diff options
Diffstat (limited to 'drivers/net/wireless')
437 files changed, 149442 insertions, 20092 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f354bd4e121e..abd3b71cd4ab 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -271,6 +271,7 @@ config MWL8K source "drivers/net/wireless/ath/Kconfig" source "drivers/net/wireless/b43/Kconfig" source "drivers/net/wireless/b43legacy/Kconfig" +source "drivers/net/wireless/brcm80211/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 7bba6a82b875..0a304b060b6c 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -41,7 +41,7 @@ obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_MWL8K) += mwl8k.o -obj-$(CONFIG_IWLAGN) += iwlwifi/ +obj-$(CONFIG_IWLWIFI) += iwlwifi/ obj-$(CONFIG_IWLWIFI_LEGACY) += iwlegacy/ obj-$(CONFIG_RT2X00) += rt2x00/ @@ -58,3 +58,6 @@ obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/ obj-$(CONFIG_IWM) += iwmc3200wifi/ obj-$(CONFIG_MWIFIEX) += mwifiex/ +obj-$(CONFIG_BRCMFMAC) += brcm80211/ +obj-$(CONFIG_BRCMUMAC) += brcm80211/ +obj-$(CONFIG_BRCMSMAC) += brcm80211/ diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 43ebc44fc82c..3b752d9fb3cd 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -1249,7 +1249,8 @@ static int adm8211_hw_reset(struct ieee80211_hw *dev) return 0; } -static u64 adm8211_get_tsft(struct ieee80211_hw *dev) +static u64 adm8211_get_tsft(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { struct adm8211_priv *priv = dev->priv; u32 tsftl; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index e1b3e3c134fd..ac1176a4f465 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -2754,7 +2754,7 @@ static const struct net_device_ops airo_netdev_ops = { .ndo_stop = airo_close, .ndo_start_xmit = airo_start_xmit, .ndo_get_stats = airo_get_stats, - .ndo_set_multicast_list = airo_set_multicast_list, + .ndo_set_rx_mode = airo_set_multicast_list, .ndo_set_mac_address = airo_set_mac_address, .ndo_do_ioctl = airo_ioctl, .ndo_change_mtu = airo_change_mtu, @@ -2766,7 +2766,7 @@ static const struct net_device_ops mpi_netdev_ops = { .ndo_stop = airo_close, .ndo_start_xmit = mpi_start_xmit, .ndo_get_stats = airo_get_stats, - .ndo_set_multicast_list = airo_set_multicast_list, + .ndo_set_rx_mode = airo_set_multicast_list, .ndo_set_mac_address = airo_set_mac_address, .ndo_do_ioctl = airo_ioctl, .ndo_change_mtu = airo_change_mtu, diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 298601436ee2..39322d4121b7 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -500,10 +500,9 @@ exit: #define HEX2STR_BUFFERS 4 #define HEX2STR_MAX_LEN 64 -#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10) /* Convert binary data into hex string */ -static char *hex2str(void *buf, int len) +static char *hex2str(void *buf, size_t len) { static atomic_t a = ATOMIC_INIT(0); static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1]; @@ -514,18 +513,17 @@ static char *hex2str(void *buf, int len) if (len > HEX2STR_MAX_LEN) len = HEX2STR_MAX_LEN; - if (len <= 0) { - ret[0] = '\0'; - return ret; - } + if (len == 0) + goto exit; while (len--) { - *obuf++ = BIN2HEX(*ibuf >> 4); - *obuf++ = BIN2HEX(*ibuf & 0xf); + obuf = pack_hex_byte(obuf, *ibuf++); *obuf++ = '-'; - ibuf++; } - *(--obuf) = '\0'; + obuf--; + +exit: + *obuf = '\0'; return ret; } diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig index d1b23067619f..073548836413 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -25,5 +25,6 @@ config ATH_DEBUG source "drivers/net/wireless/ath/ath5k/Kconfig" source "drivers/net/wireless/ath/ath9k/Kconfig" source "drivers/net/wireless/ath/carl9170/Kconfig" +source "drivers/net/wireless/ath/ath6kl/Kconfig" endif diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 0e8f528c81c0..d1214696a35b 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_ATH5K) += ath5k/ obj-$(CONFIG_ATH9K_HW) += ath9k/ obj-$(CONFIG_CARL9170) += carl9170/ +obj-$(CONFIG_ATH6KL) += ath6kl/ obj-$(CONFIG_ATH_COMMON) += ath.o diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 17c4b56c3874..908fdbc3e0ee 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -71,9 +71,7 @@ struct ath_regulatory { char alpha2[2]; u16 country_code; u16 max_power_level; - u32 tp_scale; u16 current_rd; - u16 current_rd_ext; int16_t power_limit; struct reg_dmn_pair_mapping *regpair; }; @@ -140,9 +138,6 @@ struct ath_common { u8 curbssid[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; - u8 tx_chainmask; - u8 rx_chainmask; - u32 rx_bufsize; u32 keymax; @@ -178,23 +173,29 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry); void ath_hw_cycle_counters_update(struct ath_common *common); int32_t ath_hw_get_listen_time(struct ath_common *common); -extern __attribute__ ((format (printf, 3, 4))) int -ath_printk(const char *level, struct ath_common *common, const char *fmt, ...); +extern __attribute__((format (printf, 2, 3))) +void ath_printk(const char *level, const char *fmt, ...); + +#define _ath_printk(level, common, fmt, ...) \ +do { \ + __always_unused struct ath_common *unused = common; \ + ath_printk(level, fmt, ##__VA_ARGS__); \ +} while (0) #define ath_emerg(common, fmt, ...) \ - ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__) + _ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__) #define ath_alert(common, fmt, ...) \ - ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__) + _ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__) #define ath_crit(common, fmt, ...) \ - ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__) + _ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__) #define ath_err(common, fmt, ...) \ - ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__) + _ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__) #define ath_warn(common, fmt, ...) \ - ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__) + _ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__) #define ath_notice(common, fmt, ...) \ - ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__) + _ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__) #define ath_info(common, fmt, ...) \ - ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__) + _ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__) /** * enum ath_debug_level - atheros wireless debug level @@ -246,27 +247,21 @@ enum ATH_DEBUG { #ifdef CONFIG_ATH_DEBUG -#define ath_dbg(common, dbg_mask, fmt, ...) \ -({ \ - int rtn; \ - if ((common)->debug_mask & dbg_mask) \ - rtn = ath_printk(KERN_DEBUG, common, fmt, \ - ##__VA_ARGS__); \ - else \ - rtn = 0; \ - \ - rtn; \ -}) +#define ath_dbg(common, dbg_mask, fmt, ...) \ +do { \ + if ((common)->debug_mask & dbg_mask) \ + _ath_printk(KERN_DEBUG, common, fmt, ##__VA_ARGS__); \ +} while (0) + #define ATH_DBG_WARN(foo, arg...) WARN(foo, arg) #define ATH_DBG_WARN_ON_ONCE(foo) WARN_ON_ONCE(foo) #else -static inline __attribute__ ((format (printf, 3, 4))) int -ath_dbg(struct ath_common *common, enum ATH_DEBUG dbg_mask, - const char *fmt, ...) +static inline __attribute__((format (printf, 3, 4))) +void ath_dbg(struct ath_common *common, enum ATH_DEBUG dbg_mask, + const char *fmt, ...) { - return 0; } #define ATH_DBG_WARN(foo, arg...) do {} while (0) #define ATH_DBG_WARN_ON_ONCE(foo) ({ \ diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c index a2a167363dbf..e5be7e701816 100644 --- a/drivers/net/wireless/ath/ath5k/ahb.c +++ b/drivers/net/wireless/ath/ath5k/ahb.c @@ -169,7 +169,7 @@ static int ath_ahb_probe(struct platform_device *pdev) __set_bit(ATH_STAT_2G_DISABLED, ah->status); } - ret = ath5k_init_softc(ah, &ath_ahb_bus_ops); + ret = ath5k_init_ah(ah, &ath_ahb_bus_ops); if (ret != 0) { dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret); ret = -ENODEV; @@ -214,7 +214,7 @@ static int ath_ahb_remove(struct platform_device *pdev) __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE); } - ath5k_deinit_softc(ah); + ath5k_deinit_ah(ah); platform_set_drvdata(pdev, NULL); ieee80211_free_hw(hw); diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c index 603ae15f139b..bea90e6be70e 100644 --- a/drivers/net/wireless/ath/ath5k/ani.c +++ b/drivers/net/wireless/ath/ath5k/ani.c @@ -15,7 +15,6 @@ */ #include "ath5k.h" -#include "base.h" #include "reg.h" #include "debug.h" #include "ani.h" diff --git a/drivers/net/wireless/ath/ath5k/ani.h b/drivers/net/wireless/ath/ath5k/ani.h index 034015397093..7358b6c83c6c 100644 --- a/drivers/net/wireless/ath/ath5k/ani.h +++ b/drivers/net/wireless/ath/ath5k/ani.h @@ -16,6 +16,10 @@ #ifndef ANI_H #define ANI_H +#include "../ath.h" + +enum ath5k_phy_error_code; + /* these thresholds are relative to the ATH5K_ANI_LISTEN_PERIOD */ #define ATH5K_ANI_LISTEN_PERIOD 100 #define ATH5K_ANI_OFDM_TRIG_HIGH 500 diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h index 277d5cbe0068..fecbcd9a4259 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -131,13 +131,6 @@ #define AR5K_REG_DISABLE_BITS(ah, _reg, _flags) \ ath5k_hw_reg_write(ah, ath5k_hw_reg_read(ah, _reg) & ~(_flags), _reg) -/* Access to PHY registers */ -#define AR5K_PHY_READ(ah, _reg) \ - ath5k_hw_reg_read(ah, (ah)->ah_phy + ((_reg) << 2)) - -#define AR5K_PHY_WRITE(ah, _reg, _val) \ - ath5k_hw_reg_write(ah, _val, (ah)->ah_phy + ((_reg) << 2)) - /* Access QCU registers per queue */ #define AR5K_REG_READ_Q(ah, _reg, _queue) \ (ath5k_hw_reg_read(ah, _reg) & (1 << _queue)) \ @@ -166,7 +159,6 @@ #define AR5K_TUNE_DMA_BEACON_RESP 2 #define AR5K_TUNE_SW_BEACON_RESP 10 #define AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF 0 -#define AR5K_TUNE_RADAR_ALERT false #define AR5K_TUNE_MIN_TX_FIFO_THRES 1 #define AR5K_TUNE_MAX_TX_FIFO_THRES ((IEEE80211_MAX_FRAME_LEN / 64) + 1) #define AR5K_TUNE_REGISTER_TIMEOUT 20000 @@ -295,17 +287,6 @@ enum ath5k_radio { * Common silicon revision/version values */ -enum ath5k_srev_type { - AR5K_VERSION_MAC, - AR5K_VERSION_RAD, -}; - -struct ath5k_srev_name { - const char *sr_name; - enum ath5k_srev_type sr_type; - u_int sr_val; -}; - #define AR5K_SREV_UNKNOWN 0xffff #define AR5K_SREV_AR5210 0x00 /* Crete */ @@ -424,7 +405,6 @@ enum ath5k_driver_mode { AR5K_MODE_11A = 0, AR5K_MODE_11B = 1, AR5K_MODE_11G = 2, - AR5K_MODE_XR = 0, AR5K_MODE_MAX = 3 }; @@ -694,33 +674,6 @@ struct ath5k_gain { #define AR5K_SLOT_TIME_20 880 #define AR5K_SLOT_TIME_MAX 0xffff -/* channel_flags */ -#define CHANNEL_CW_INT 0x0008 /* Contention Window interference detected */ -#define CHANNEL_CCK 0x0020 /* CCK channel */ -#define CHANNEL_OFDM 0x0040 /* OFDM channel */ -#define CHANNEL_2GHZ 0x0080 /* 2GHz channel. */ -#define CHANNEL_5GHZ 0x0100 /* 5GHz channel */ -#define CHANNEL_PASSIVE 0x0200 /* Only passive scan allowed */ -#define CHANNEL_DYN 0x0400 /* Dynamic CCK-OFDM channel (for g operation) */ -#define CHANNEL_XR 0x0800 /* XR channel */ - -#define CHANNEL_A (CHANNEL_5GHZ | CHANNEL_OFDM) -#define CHANNEL_B (CHANNEL_2GHZ | CHANNEL_CCK) -#define CHANNEL_G (CHANNEL_2GHZ | CHANNEL_OFDM) -#define CHANNEL_X (CHANNEL_5GHZ | CHANNEL_OFDM | CHANNEL_XR) - -#define CHANNEL_ALL (CHANNEL_OFDM | CHANNEL_CCK | \ - CHANNEL_2GHZ | CHANNEL_5GHZ) - -#define CHANNEL_MODES CHANNEL_ALL - -/* - * Used internally for ath5k_hw_reset_tx_queue(). - * Also see struct struct ieee80211_channel. - */ -#define IS_CHAN_XR(_c) ((_c->hw_value & CHANNEL_XR) != 0) -#define IS_CHAN_B(_c) ((_c->hw_value & CHANNEL_B) != 0) - /* * The following structure is used to map 2GHz channels to * 5GHz Atheros channels. @@ -977,7 +930,7 @@ enum ath5k_power_mode { struct ath5k_capabilities { /* * Supported PHY modes - * (ie. CHANNEL_A, CHANNEL_B, ...) + * (ie. AR5K_MODE_11A, AR5K_MODE_11B, ...) */ DECLARE_BITMAP(cap_mode, AR5K_MODE_MAX); @@ -1013,16 +966,6 @@ struct ath5k_nfcal_hist { s16 nfval[ATH5K_NF_CAL_HIST_MAX]; /* last few noise floors */ }; -/** - * struct avg_val - Helper structure for average calculation - * @avg: contains the actual average value - * @avg_weight: is used internally during calculation to prevent rounding errors - */ -struct ath5k_avg_val { - int avg; - int avg_weight; -}; - #define ATH5K_LED_MAX_NAME_LEN 31 /* @@ -1148,7 +1091,6 @@ struct ath5k_hw { bool rx_pending; /* rx tasklet pending */ bool tx_pending; /* tx tasklet pending */ - u8 lladdr[ETH_ALEN]; u8 bssidmask[ETH_ALEN]; unsigned int led_pin, /* GPIO pin for driving LED */ @@ -1156,7 +1098,6 @@ struct ath5k_hw { struct work_struct reset_work; /* deferred chip reset */ - unsigned int rxbufsize; /* rx size based on mtu */ struct list_head rxbuf; /* receive buffer */ spinlock_t rxbuflock; u32 *rxlink; /* link ptr in last RX desc */ @@ -1208,10 +1149,8 @@ struct ath5k_hw { enum ath5k_version ah_version; enum ath5k_radio ah_radio; - u32 ah_phy; u32 ah_mac_srev; u16 ah_mac_version; - u16 ah_mac_revision; u16 ah_phy_revision; u16 ah_radio_5ghz_revision; u16 ah_radio_2ghz_revision; @@ -1279,12 +1218,6 @@ struct ath5k_hw { bool txp_setup; } ah_txpower; - struct { - bool r_enabled; - int r_last_alert; - struct ieee80211_channel r_last_channel; - } ah_radar; - struct ath5k_nfcal_hist ah_nfcal_hist; /* average beacon RSSI in our BSS (used by ANI) */ @@ -1327,36 +1260,13 @@ struct ath_bus_ops { extern const struct ieee80211_ops ath5k_hw_ops; /* Initialization and detach functions */ -int ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops); -void ath5k_deinit_softc(struct ath5k_hw *ah); int ath5k_hw_init(struct ath5k_hw *ah); void ath5k_hw_deinit(struct ath5k_hw *ah); int ath5k_sysfs_register(struct ath5k_hw *ah); void ath5k_sysfs_unregister(struct ath5k_hw *ah); -/* base.c */ -struct ath5k_buf; -struct ath5k_txq; - -void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable); -bool ath5k_any_vif_assoc(struct ath5k_hw *ah); -void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ath5k_txq *txq); -int ath5k_start(struct ieee80211_hw *hw); -void ath5k_stop(struct ieee80211_hw *hw); -void ath5k_mode_setup(struct ath5k_hw *ah, struct ieee80211_vif *vif); -void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, - struct ieee80211_vif *vif); -int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan); -void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf); -int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void ath5k_beacon_config(struct ath5k_hw *ah); -void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); -void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); - /*Chip id helper functions */ -const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val); int ath5k_hw_read_srev(struct ath5k_hw *ah); /* LED functions */ @@ -1367,7 +1277,7 @@ void ath5k_unregister_leds(struct ath5k_hw *ah); /* Reset Functions */ -int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial); +int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel); int ath5k_hw_on_hold(struct ath5k_hw *ah); int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool fast, bool skip_pcu); @@ -1487,13 +1397,13 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel); /* PHY functions */ /* Misc PHY functions */ -u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan); +u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band); int ath5k_hw_phy_disable(struct ath5k_hw *ah); /* Gain_F optimization */ enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah); int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah); /* PHY/RF channel functions */ -bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags); +bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel); /* PHY calibration */ void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah); int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index f8a6b380d96d..91627dd2c26a 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -25,7 +25,6 @@ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" /** * ath5k_hw_post - Power On Self Test helper function @@ -95,7 +94,7 @@ static int ath5k_hw_post(struct ath5k_hw *ah) /** * ath5k_hw_init - Check if hw is supported and init the needed structs * - * @ah: The &struct ath5k_hw we got from the driver's init_softc function + * @ah: The &struct ath5k_hw associated with the device * * Check if the device is supported, perform a POST and initialize the needed * structs. Returns -ENOMEM if we don't have memory for the needed structs, @@ -114,7 +113,6 @@ int ath5k_hw_init(struct ath5k_hw *ah) /* * HW information */ - ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT; ah->ah_bwmode = AR5K_BWMODE_DEFAULT; ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER; ah->ah_imr = 0; @@ -137,9 +135,8 @@ int ath5k_hw_init(struct ath5k_hw *ah) else ah->ah_version = AR5K_AR5212; - /* Get the MAC revision */ + /* Get the MAC version */ ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER); - ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV); /* Fill the ath5k_hw struct with the needed functions */ ret = ath5k_hw_init_desc_functions(ah); @@ -147,7 +144,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) goto err; /* Bring device out of sleep and reset its units */ - ret = ath5k_hw_nic_wakeup(ah, 0, true); + ret = ath5k_hw_nic_wakeup(ah, NULL); if (ret) goto err; @@ -155,8 +152,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) & 0xffffffff; ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_5GHZ); - ah->ah_phy = AR5K_PHY(0); + IEEE80211_BAND_5GHZ); /* Try to identify radio chip based on its srev */ switch (ah->ah_radio_5ghz_revision & 0xf0) { @@ -164,14 +160,14 @@ int ath5k_hw_init(struct ath5k_hw *ah) ah->ah_radio = AR5K_RF5111; ah->ah_single_chip = false; ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_2GHZ); + IEEE80211_BAND_2GHZ); break; case AR5K_SREV_RAD_5112: case AR5K_SREV_RAD_2112: ah->ah_radio = AR5K_RF5112; ah->ah_single_chip = false; ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_2GHZ); + IEEE80211_BAND_2GHZ); break; case AR5K_SREV_RAD_2413: ah->ah_radio = AR5K_RF2413; @@ -208,7 +204,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) ah->ah_radio = AR5K_RF5111; ah->ah_single_chip = false; ah->ah_radio_2ghz_revision = ath5k_hw_radio_revision(ah, - CHANNEL_2GHZ); + IEEE80211_BAND_2GHZ); } else if (ah->ah_mac_version == (AR5K_SREV_AR2425 >> 4) || ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4) || ah->ah_phy_revision == AR5K_SREV_PHY_2425) { diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index c3119a6caace..b346d0492001 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -52,6 +52,7 @@ #include <linux/uaccess.h> #include <linux/slab.h> #include <linux/etherdevice.h> +#include <linux/nl80211.h> #include <net/ieee80211_radiotap.h> @@ -61,6 +62,8 @@ #include "reg.h" #include "debug.h" #include "ani.h" +#include "ath5k.h" +#include "../regd.h" #define CREATE_TRACE_POINTS #include "trace.h" @@ -272,20 +275,18 @@ static unsigned int ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, unsigned int mode, unsigned int max) { - unsigned int count, size, chfreq, freq, ch; + unsigned int count, size, freq, ch; enum ieee80211_band band; switch (mode) { case AR5K_MODE_11A: /* 1..220, but 2GHz frequencies are filtered by check_channel */ size = 220; - chfreq = CHANNEL_5GHZ; band = IEEE80211_BAND_5GHZ; break; case AR5K_MODE_11B: case AR5K_MODE_11G: size = 26; - chfreq = CHANNEL_2GHZ; band = IEEE80211_BAND_2GHZ; break; default: @@ -300,26 +301,19 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, if (freq == 0) /* mapping failed - not a standard channel */ continue; + /* Write channel info, needed for ath5k_channel_ok() */ + channels[count].center_freq = freq; + channels[count].band = band; + channels[count].hw_value = mode; + /* Check if channel is supported by the chipset */ - if (!ath5k_channel_ok(ah, freq, chfreq)) + if (!ath5k_channel_ok(ah, &channels[count])) continue; if (!modparam_all_channels && !ath5k_is_standard_channel(ch, band)) continue; - /* Write channel info and increment counter */ - channels[count].center_freq = freq; - channels[count].band = band; - switch (mode) { - case AR5K_MODE_11A: - case AR5K_MODE_11G: - channels[count].hw_value = chfreq | CHANNEL_OFDM; - break; - case AR5K_MODE_11B: - channels[count].hw_value = CHANNEL_B; - } - count++; } @@ -927,12 +921,6 @@ ath5k_txq_setup(struct ath5k_hw *ah, */ return ERR_PTR(qnum); } - if (qnum >= ARRAY_SIZE(ah->txqs)) { - ATH5K_ERR(ah, "hw qnum %u out of range, max %tu!\n", - qnum, ARRAY_SIZE(ah->txqs)); - ath5k_hw_release_tx_queue(ah, qnum); - return ERR_PTR(-EINVAL); - } txq = &ah->txqs[qnum]; if (!txq->setup) { txq->qnum = qnum; @@ -2349,7 +2337,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work) \*************************/ int __devinit -ath5k_init_softc(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) +ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = ah->hw; struct ath_common *common; @@ -2867,7 +2855,6 @@ ath5k_init(struct ieee80211_hw *hw) } SET_IEEE80211_PERM_ADDR(hw, mac); - memcpy(&ah->lladdr, mac, ETH_ALEN); /* All MAC address bits matter for ACKs */ ath5k_update_bssid_mask_and_opmode(ah, NULL); @@ -2903,7 +2890,7 @@ err: } void -ath5k_deinit_softc(struct ath5k_hw *ah) +ath5k_deinit_ah(struct ath5k_hw *ah) { struct ieee80211_hw *hw = ah->hw; diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h index a81f28d5bddc..6c94c7ff2350 100644 --- a/drivers/net/wireless/ath/ath5k/base.h +++ b/drivers/net/wireless/ath/ath5k/base.h @@ -38,19 +38,27 @@ /* * Definitions for the Atheros Wireless LAN controller driver. */ -#ifndef _DEV_ATH_ATHVAR_H -#define _DEV_ATH_ATHVAR_H +#ifndef _DEV_ATH5K_BASE_H +#define _DEV_ATH5K_BASE_H -#include <linux/interrupt.h> -#include <linux/list.h> -#include <linux/wireless.h> -#include <linux/if_ether.h> -#include <linux/rfkill.h> -#include <linux/workqueue.h> +struct ieee80211_vif; +struct ieee80211_hw; +struct ath5k_hw; +struct ath5k_txq; +struct ieee80211_channel; +struct ath_bus_ops; +enum nl80211_iftype; -#include "ath5k.h" -#include "../regd.h" -#include "../ath.h" +enum ath5k_srev_type { + AR5K_VERSION_MAC, + AR5K_VERSION_RAD, +}; + +struct ath5k_srev_name { + const char *sr_name; + enum ath5k_srev_type sr_type; + u_int sr_val; +}; struct ath5k_buf { struct list_head list; @@ -65,7 +73,6 @@ struct ath5k_vif { enum nl80211_iftype opmode; int bslot; struct ath5k_buf *bbuf; /* beacon buffer */ - u8 lladdr[ETH_ALEN]; }; struct ath5k_vif_iter_data { @@ -78,8 +85,30 @@ struct ath5k_vif_iter_data { enum nl80211_iftype opmode; int n_stas; }; + void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif); +bool ath5k_any_vif_assoc(struct ath5k_hw *ah); + +int ath5k_start(struct ieee80211_hw *hw); +void ath5k_stop(struct ieee80211_hw *hw); + +void ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf); +int ath5k_beacon_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void ath5k_beacon_config(struct ath5k_hw *ah); +void ath5k_set_beacon_filter(struct ieee80211_hw *hw, bool enable); + +void ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah, + struct ieee80211_vif *vif); +int ath5k_chan_set(struct ath5k_hw *ah, struct ieee80211_channel *chan); +void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); +void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf); +void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ath5k_txq *txq); + +const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val); +int ath5k_init_ah(struct ath5k_hw *ah, const struct ath_bus_ops *bus_ops); +void ath5k_deinit_ah(struct ath5k_hw *ah); /* Check whether BSSID mask is supported */ #define ath5k_hw_hasbssidmask(_ah) (ah->ah_version == AR5K_AR5212) @@ -87,4 +116,4 @@ void ath5k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif); /* Check whether virtual EOL is supported */ #define ath5k_hw_hasveol(_ah) (ah->ah_version != AR5K_AR5210) -#endif +#endif /* _DEV_ATH5K_BASE_H */ diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c index eefe670e28a7..810fba96702b 100644 --- a/drivers/net/wireless/ath/ath5k/caps.c +++ b/drivers/net/wireless/ath/ath5k/caps.c @@ -24,7 +24,7 @@ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" +#include "../regd.h" /* * Fill the capabilities struct diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index ccca724de173..fce8c904eea9 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -58,19 +58,18 @@ * THE POSSIBILITY OF SUCH DAMAGES. */ -#include "base.h" +#include <linux/module.h> +#include <linux/seq_file.h> +#include <linux/list.h> #include "debug.h" +#include "ath5k.h" +#include "reg.h" +#include "base.h" static unsigned int ath5k_debug; module_param_named(debug, ath5k_debug, uint, 0); -#ifdef CONFIG_ATH5K_DEBUG - -#include <linux/seq_file.h> -#include "reg.h" -#include "ani.h" - static int ath5k_debugfs_open(struct inode *inode, struct file *file) { file->private_data = inode->i_private; @@ -1031,5 +1030,3 @@ ath5k_debug_printtxbuf(struct ath5k_hw *ah, struct ath5k_buf *bf) td->tx_stat.tx_status_0, td->tx_stat.tx_status_1, done ? ' ' : (ts.ts_status == 0) ? '*' : '!'); } - -#endif /* ifdef CONFIG_ATH5K_DEBUG */ diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c index 846535f59efc..7e88dda82221 100644 --- a/drivers/net/wireless/ath/ath5k/desc.c +++ b/drivers/net/wireless/ath/ath5k/desc.c @@ -24,7 +24,6 @@ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" /************************\ diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c index 0d5d4033f12a..2481f9c7f4b6 100644 --- a/drivers/net/wireless/ath/ath5k/dma.c +++ b/drivers/net/wireless/ath/ath5k/dma.c @@ -35,7 +35,6 @@ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" /*********\ diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c index 9068b9165265..cd708c15b774 100644 --- a/drivers/net/wireless/ath/ath5k/eeprom.c +++ b/drivers/net/wireless/ath/ath5k/eeprom.c @@ -26,7 +26,6 @@ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" /******************\ @@ -1780,13 +1779,12 @@ ath5k_eeprom_detach(struct ath5k_hw *ah) int ath5k_eeprom_mode_from_channel(struct ieee80211_channel *channel) { - switch (channel->hw_value & CHANNEL_MODES) { - case CHANNEL_A: - case CHANNEL_XR: + switch (channel->hw_value) { + case AR5K_MODE_11A: return AR5K_EEPROM_MODE_11A; - case CHANNEL_G: + case AR5K_MODE_11G: return AR5K_EEPROM_MODE_11G; - case CHANNEL_B: + case AR5K_MODE_11B: return AR5K_EEPROM_MODE_11B; default: return -1; diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c index bc90503f4b7a..859297811914 100644 --- a/drivers/net/wireless/ath/ath5k/gpio.c +++ b/drivers/net/wireless/ath/ath5k/gpio.c @@ -23,7 +23,6 @@ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" /* * Set led state diff --git a/drivers/net/wireless/ath/ath5k/initvals.c b/drivers/net/wireless/ath/ath5k/initvals.c index 5ab607f40e0e..1ffecc0fd3ed 100644 --- a/drivers/net/wireless/ath/ath5k/initvals.c +++ b/drivers/net/wireless/ath/ath5k/initvals.c @@ -22,7 +22,6 @@ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" /* * Mode-independent initial register writes diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c index 8c17a00f7dad..c1151c723711 100644 --- a/drivers/net/wireless/ath/ath5k/led.c +++ b/drivers/net/wireless/ath/ath5k/led.c @@ -41,7 +41,6 @@ #include <linux/pci.h> #include "ath5k.h" -#include "base.h" #define ATH_SDEVICE(subv, subd) \ .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 2a715ca0c5e4..6ed4c0717e3e 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -41,8 +41,10 @@ * */ +#include <net/mac80211.h> #include <asm/unaligned.h> +#include "ath5k.h" #include "base.h" #include "reg.h" @@ -137,11 +139,8 @@ ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) /* Any MAC address is fine, all others are included through the * filter. */ - memcpy(&ah->lladdr, vif->addr, ETH_ALEN); ath5k_hw_set_lladdr(ah, vif->addr); - memcpy(&avf->lladdr, vif->addr, ETH_ALEN); - ath5k_update_bssid_mask_and_opmode(ah, vif); ret = 0; end: @@ -564,7 +563,7 @@ ath5k_get_stats(struct ieee80211_hw *hw, static int -ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, +ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath5k_hw *ah = hw->priv; @@ -603,7 +602,7 @@ ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue, static u64 -ath5k_get_tsf(struct ieee80211_hw *hw) +ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_hw *ah = hw->priv; @@ -612,7 +611,7 @@ ath5k_get_tsf(struct ieee80211_hw *hw) static void -ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf) { struct ath5k_hw *ah = hw->priv; @@ -621,7 +620,7 @@ ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf) static void -ath5k_reset_tsf(struct ieee80211_hw *hw) +ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c index eaf79b49341e..c1dff2ced044 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -261,7 +261,7 @@ ath5k_pci_probe(struct pci_dev *pdev, ah->iobase = mem; /* So we can unmap it on detach */ /* Initialize */ - ret = ath5k_init_softc(ah, &ath_pci_bus_ops); + ret = ath5k_init_ah(ah, &ath_pci_bus_ops); if (ret) goto err_free; @@ -287,7 +287,7 @@ ath5k_pci_remove(struct pci_dev *pdev) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath5k_hw *ah = hw->priv; - ath5k_deinit_softc(ah); + ath5k_deinit_ah(ah); pci_iounmap(pdev, ah->iobase); pci_release_region(pdev, 0); pci_disable_device(pdev); diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c index 067313845060..a7eafa3edc21 100644 --- a/drivers/net/wireless/ath/ath5k/pcu.c +++ b/drivers/net/wireless/ath/ath5k/pcu.c @@ -29,7 +29,6 @@ #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" /* * AR5212+ can use higher rates for ack transmission @@ -152,7 +151,7 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah) case AR5K_BWMODE_DEFAULT: default: slot_time = AR5K_INIT_SLOT_TIME_DEFAULT; - if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot) + if ((channel->hw_value == AR5K_MODE_11B) && !ah->ah_short_slot) slot_time = AR5K_INIT_SLOT_TIME_B; break; } @@ -183,7 +182,7 @@ unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah) case AR5K_BWMODE_DEFAULT: sifs = AR5K_INIT_SIFS_DEFAULT_BG; default: - if (channel->hw_value & CHANNEL_5GHZ) + if (channel->band == IEEE80211_BAND_5GHZ) sifs = AR5K_INIT_SIFS_DEFAULT_A; break; } diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 81e465e70175..01cb72de44cb 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -26,9 +26,9 @@ #include "ath5k.h" #include "reg.h" -#include "base.h" #include "rfbuffer.h" #include "rfgain.h" +#include "../regd.h" /******************\ @@ -38,7 +38,7 @@ /* * Get the PHY Chip revision */ -u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) +u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, enum ieee80211_band band) { unsigned int i; u32 srev; @@ -47,11 +47,11 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) /* * Set the radio chip access register */ - switch (chan) { - case CHANNEL_2GHZ: + switch (band) { + case IEEE80211_BAND_2GHZ: ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0)); break; - case CHANNEL_5GHZ: + case IEEE80211_BAND_5GHZ: ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0)); break; default: @@ -84,14 +84,16 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan) /* * Check if a channel is supported */ -bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags) +bool ath5k_channel_ok(struct ath5k_hw *ah, struct ieee80211_channel *channel) { + u16 freq = channel->center_freq; + /* Check if the channel is in our supported range */ - if (flags & CHANNEL_2GHZ) { + if (channel->band == IEEE80211_BAND_2GHZ) { if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) && (freq <= ah->ah_capabilities.cap_range.range_2ghz_max)) return true; - } else if (flags & CHANNEL_5GHZ) + } else if (channel->band == IEEE80211_BAND_5GHZ) if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) && (freq <= ah->ah_capabilities.cap_range.range_5ghz_max)) return true; @@ -224,7 +226,7 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, ds_coef_exp, ds_coef_man, clock; BUG_ON(!(ah->ah_version == AR5K_AR5212) || - !(channel->hw_value & CHANNEL_OFDM)); + (channel->hw_value == AR5K_MODE_11B)); /* Get coefficient * ALGO: coef = (5 * clock / carrier_freq) / 2 @@ -298,7 +300,7 @@ static void ath5k_hw_wait_for_synth(struct ath5k_hw *ah, u32 delay; delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) & AR5K_PHY_RX_DELAY_M; - delay = (channel->hw_value & CHANNEL_CCK) ? + delay = (channel->hw_value == AR5K_MODE_11B) ? ((delay << 2) / 22) : (delay / 10); if (ah->ah_bwmode == AR5K_BWMODE_10MHZ) delay = delay << 1; @@ -798,9 +800,9 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, } /* Set Output and Driver bias current (OB/DB) */ - if (channel->hw_value & CHANNEL_2GHZ) { + if (channel->band == IEEE80211_BAND_2GHZ) { - if (channel->hw_value & CHANNEL_CCK) + if (channel->hw_value == AR5K_MODE_11B) ee_mode = AR5K_EEPROM_MODE_11B; else ee_mode = AR5K_EEPROM_MODE_11G; @@ -825,7 +827,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, AR5K_RF_DB_2GHZ, true); /* RF5111 always needs OB/DB for 5GHz, even if we use 2GHz */ - } else if ((channel->hw_value & CHANNEL_5GHZ) || + } else if ((channel->band == IEEE80211_BAND_5GHZ) || (ah->ah_radio == AR5K_RF5111)) { /* For 11a, Turbo and XR we need to choose @@ -857,7 +859,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, if (ah->ah_radio == AR5K_RF5111) { /* Set gain_F settings according to current step */ - if (channel->hw_value & CHANNEL_OFDM) { + if (channel->hw_value != AR5K_MODE_11B) { AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL, AR5K_PHY_FRAME_CTL_TX_CLIP, @@ -914,7 +916,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, if (ah->ah_radio == AR5K_RF5112) { /* Set gain_F settings according to current step */ - if (channel->hw_value & CHANNEL_OFDM) { + if (channel->hw_value != AR5K_MODE_11B) { ath5k_hw_rfb_op(ah, rf_regs, g_step->gos_param[0], AR5K_RF_MIXGAIN_OVR, true); @@ -1026,7 +1028,7 @@ static int ath5k_hw_rfregs_init(struct ath5k_hw *ah, } if (ah->ah_radio == AR5K_RF5413 && - channel->hw_value & CHANNEL_2GHZ) { + channel->band == IEEE80211_BAND_2GHZ) { ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_DERBY_CHAN_SEL_MODE, true); @@ -1138,7 +1140,7 @@ static int ath5k_hw_rf5111_channel(struct ath5k_hw *ah, */ data0 = data1 = 0; - if (channel->hw_value & CHANNEL_2GHZ) { + if (channel->band == IEEE80211_BAND_2GHZ) { /* Map 2GHz channel to 5GHz Atheros channel ID */ ret = ath5k_hw_rf5111_chan2athchan( ieee80211_frequency_to_channel(channel->center_freq), @@ -1265,10 +1267,9 @@ static int ath5k_hw_channel(struct ath5k_hw *ah, int ret; /* * Check bounds supported by the PHY (we don't care about regulatory - * restrictions at this point). Note: hw_value already has the band - * (CHANNEL_2GHZ, or CHANNEL_5GHZ) so we inform ath5k_channel_ok() - * of the band by that */ - if (!ath5k_channel_ok(ah, channel->center_freq, channel->hw_value)) { + * restrictions at this point). + */ + if (!ath5k_channel_ok(ah, channel)) { ATH5K_ERR(ah, "channel frequency (%u MHz) out of supported " "band range\n", @@ -1614,7 +1615,7 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah, ret = ath5k_hw_rf511x_iq_calibrate(ah); if ((ah->ah_radio == AR5K_RF5111 || ah->ah_radio == AR5K_RF5112) && - (channel->hw_value & CHANNEL_OFDM)) + (channel->hw_value != AR5K_MODE_11B)) ath5k_hw_request_rfgain_probe(ah); return ret; @@ -1641,7 +1642,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, /* Convert current frequency to fbin value (the same way channels * are stored on EEPROM, check out ath5k_eeprom_bin2freq) and scale * up by 2 so we can compare it later */ - if (channel->hw_value & CHANNEL_2GHZ) { + if (channel->band == IEEE80211_BAND_2GHZ) { chan_fbin = (channel->center_freq - 2300) * 10; freq_band = AR5K_EEPROM_BAND_2GHZ; } else { @@ -1703,7 +1704,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah, spur_freq_sigma_delta = (spur_delta_phase >> 10); symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4; default: - if (channel->hw_value == CHANNEL_A) { + if (channel->band == IEEE80211_BAND_5GHZ) { /* Both sample_freq and chip_freq are 40MHz */ spur_delta_phase = (spur_offset << 17) / 25; spur_freq_sigma_delta = @@ -2226,15 +2227,20 @@ ath5k_get_chan_pcal_surrounding_piers(struct ath5k_hw *ah, idx_l = 0; idx_r = 0; - if (!(channel->hw_value & CHANNEL_OFDM)) { + switch (channel->hw_value) { + case AR5K_EEPROM_MODE_11A: + pcinfo = ee->ee_pwr_cal_a; + mode = AR5K_EEPROM_MODE_11A; + break; + case AR5K_EEPROM_MODE_11B: pcinfo = ee->ee_pwr_cal_b; mode = AR5K_EEPROM_MODE_11B; - } else if (channel->hw_value & CHANNEL_2GHZ) { + break; + case AR5K_EEPROM_MODE_11G: + default: pcinfo = ee->ee_pwr_cal_g; mode = AR5K_EEPROM_MODE_11G; - } else { - pcinfo = ee->ee_pwr_cal_a; - mode = AR5K_EEPROM_MODE_11A; + break; } max = ee->ee_n_piers[mode] - 1; @@ -2303,15 +2309,20 @@ ath5k_get_rate_pcal_data(struct ath5k_hw *ah, idx_l = 0; idx_r = 0; - if (!(channel->hw_value & CHANNEL_OFDM)) { + switch (channel->hw_value) { + case AR5K_MODE_11A: + rpinfo = ee->ee_rate_tpwr_a; + mode = AR5K_EEPROM_MODE_11A; + break; + case AR5K_MODE_11B: rpinfo = ee->ee_rate_tpwr_b; mode = AR5K_EEPROM_MODE_11B; - } else if (channel->hw_value & CHANNEL_2GHZ) { + break; + case AR5K_MODE_11G: + default: rpinfo = ee->ee_rate_tpwr_g; mode = AR5K_EEPROM_MODE_11G; - } else { - rpinfo = ee->ee_rate_tpwr_a; - mode = AR5K_EEPROM_MODE_11A; + break; } max = ee->ee_rate_target_pwr_num[mode] - 1; @@ -2392,24 +2403,22 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah, ctl_mode = ath_regd_get_band_ctl(regulatory, channel->band); - switch (channel->hw_value & CHANNEL_MODES) { - case CHANNEL_A: + switch (channel->hw_value) { + case AR5K_MODE_11A: if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) ctl_mode |= AR5K_CTL_TURBO; else ctl_mode |= AR5K_CTL_11A; break; - case CHANNEL_G: + case AR5K_MODE_11G: if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) ctl_mode |= AR5K_CTL_TURBOG; else ctl_mode |= AR5K_CTL_11G; break; - case CHANNEL_B: + case AR5K_MODE_11B: ctl_mode |= AR5K_CTL_11B; break; - case CHANNEL_XR: - /* Fall through */ default: return; } @@ -3292,7 +3301,7 @@ int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel, /* Write OFDM timings on 5212*/ if (ah->ah_version == AR5K_AR5212 && - channel->hw_value & CHANNEL_OFDM) { + channel->hw_value != AR5K_MODE_11B) { ret = ath5k_hw_write_ofdm_timings(ah, channel); if (ret) diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index 65f10398999e..776654228eaa 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -23,7 +23,6 @@ Queue Control Unit, DFS Control Unit Functions #include "ath5k.h" #include "reg.h" #include "debug.h" -#include "base.h" /******************\ @@ -185,13 +184,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type, case AR5K_TX_QUEUE_CAB: queue = AR5K_TX_QUEUE_ID_CAB; break; - case AR5K_TX_QUEUE_XR_DATA: - if (ah->ah_version != AR5K_AR5212) - ATH5K_ERR(ah, - "XR data queues only supported in" - " 5212!\n"); - queue = AR5K_TX_QUEUE_ID_XR_DATA; - break; default: return -EINVAL; } @@ -544,7 +536,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time) * * Also we have different lowest rate for 802.11a */ - if (channel->hw_value & CHANNEL_5GHZ) + if (channel->band == IEEE80211_BAND_5GHZ) rate = &ah->sbands[IEEE80211_BAND_5GHZ].bitrates[0]; else rate = &ah->sbands[IEEE80211_BAND_2GHZ].bitrates[0]; diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c index 0686c5d8d56e..2abac257b4b4 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -30,7 +30,6 @@ #include <linux/platform_device.h> #include "ath5k.h" #include "reg.h" -#include "base.h" #include "debug.h" @@ -102,12 +101,18 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah) /* * Set core clock frequency */ - if (channel->hw_value & CHANNEL_5GHZ) - clock = 40; /* 802.11a */ - else if (channel->hw_value & CHANNEL_CCK) - clock = 22; /* 802.11b */ - else - clock = 44; /* 802.11g */ + switch (channel->hw_value) { + case AR5K_MODE_11A: + clock = 40; + break; + case AR5K_MODE_11B: + clock = 22; + break; + case AR5K_MODE_11G: + default: + clock = 44; + break; + } /* Use clock multiplier for non-default * bwmode */ @@ -581,8 +586,9 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah) /* * Bring up MAC + PHY Chips and program PLL + * Channel is NULL for the initial wakeup. */ -int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) +int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel) { struct pci_dev *pdev = ah->pdev; u32 turbo, mode, clock, bus_flags; @@ -592,7 +598,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) mode = 0; clock = 0; - if ((ath5k_get_bus_type(ah) != ATH_AHB) || !initial) { + if ((ath5k_get_bus_type(ah) != ATH_AHB) || channel) { /* Wakeup the device */ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0); if (ret) { @@ -652,7 +658,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) /* On initialization skip PLL programming since we don't have * a channel / mode set yet */ - if (initial) + if (!channel) return 0; if (ah->ah_version != AR5K_AR5210) { @@ -668,13 +674,13 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) clock = AR5K_PHY_PLL_RF5111; /*Zero*/ } - if (flags & CHANNEL_2GHZ) { + if (channel->band == IEEE80211_BAND_2GHZ) { mode |= AR5K_PHY_MODE_FREQ_2GHZ; clock |= AR5K_PHY_PLL_44MHZ; - if (flags & CHANNEL_CCK) { + if (channel->hw_value == AR5K_MODE_11B) { mode |= AR5K_PHY_MODE_MOD_CCK; - } else if (flags & CHANNEL_OFDM) { + } else { /* XXX Dynamic OFDM/CCK is not supported by the * AR5211 so we set MOD_OFDM for plain g (no * CCK headers) operation. We need to test @@ -686,27 +692,16 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) mode |= AR5K_PHY_MODE_MOD_OFDM; else mode |= AR5K_PHY_MODE_MOD_DYN; - } else { - ATH5K_ERR(ah, - "invalid radio modulation mode\n"); - return -EINVAL; } - } else if (flags & CHANNEL_5GHZ) { - mode |= AR5K_PHY_MODE_FREQ_5GHZ; + } else if (channel->band == IEEE80211_BAND_5GHZ) { + mode |= (AR5K_PHY_MODE_FREQ_5GHZ | + AR5K_PHY_MODE_MOD_OFDM); /* Different PLL setting for 5413 */ if (ah->ah_radio == AR5K_RF5413) clock = AR5K_PHY_PLL_40MHZ_5413; else clock |= AR5K_PHY_PLL_40MHZ; - - if (flags & CHANNEL_OFDM) - mode |= AR5K_PHY_MODE_MOD_OFDM; - else { - ATH5K_ERR(ah, - "invalid radio modulation mode\n"); - return -EINVAL; - } } else { ATH5K_ERR(ah, "invalid radio frequency mode\n"); return -EINVAL; @@ -822,7 +817,7 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah, u32 data; ath5k_hw_reg_write(ah, AR5K_PHY_CCKTXCTL_WORLD, AR5K_PHY_CCKTXCTL); - if (channel->hw_value & CHANNEL_5GHZ) + if (channel->band == IEEE80211_BAND_5GHZ) data = 0xffb81020; else data = 0xffb80d20; @@ -905,7 +900,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah, /* Set CCK to OFDM power delta on tx power * adjustment register */ if (ah->ah_phy_revision >= AR5K_SREV_PHY_5212A) { - if (channel->hw_value == CHANNEL_G) + if (channel->hw_value == AR5K_MODE_11G) ath5k_hw_reg_write(ah, AR5K_REG_SM((ee->ee_cck_ofdm_gain_delta * -1), AR5K_PHY_TX_PWR_ADJ_CCK_GAIN_DELTA) | @@ -1084,37 +1079,23 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, ret = 0; } - switch (channel->hw_value & CHANNEL_MODES) { - case CHANNEL_A: - mode = AR5K_MODE_11A; + mode = channel->hw_value; + switch (mode) { + case AR5K_MODE_11A: break; - case CHANNEL_G: - + case AR5K_MODE_11G: if (ah->ah_version <= AR5K_AR5211) { ATH5K_ERR(ah, "G mode not available on 5210/5211"); return -EINVAL; } - - mode = AR5K_MODE_11G; break; - case CHANNEL_B: - + case AR5K_MODE_11B: if (ah->ah_version < AR5K_AR5211) { ATH5K_ERR(ah, "B mode not available on 5210"); return -EINVAL; } - - mode = AR5K_MODE_11B; - break; - case CHANNEL_XR: - if (ah->ah_version == AR5K_AR5211) { - ATH5K_ERR(ah, - "XR mode not available on 5211"); - return -EINVAL; - } - mode = AR5K_MODE_XR; break; default: ATH5K_ERR(ah, @@ -1200,7 +1181,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, } /* Wakeup the device */ - ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false); + ret = ath5k_hw_nic_wakeup(ah, channel); if (ret) return ret; diff --git a/drivers/net/wireless/ath/ath5k/rfkill.c b/drivers/net/wireless/ath/ath5k/rfkill.c index 945fc9f21e76..270a319f3aeb 100644 --- a/drivers/net/wireless/ath/ath5k/rfkill.c +++ b/drivers/net/wireless/ath/ath5k/rfkill.c @@ -33,7 +33,7 @@ * THE POSSIBILITY OF SUCH DAMAGES. */ -#include "base.h" +#include "ath5k.h" static inline void ath5k_rfkill_disable(struct ath5k_hw *ah) diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c index 0244a36ba958..9364da7bd131 100644 --- a/drivers/net/wireless/ath/ath5k/sysfs.c +++ b/drivers/net/wireless/ath/ath5k/sysfs.c @@ -1,7 +1,6 @@ #include <linux/device.h> #include <linux/pci.h> -#include "base.h" #include "ath5k.h" #include "reg.h" diff --git a/drivers/net/wireless/ath/ath5k/trace.h b/drivers/net/wireless/ath/ath5k/trace.h index c741c871f4e9..39f002ed4a88 100644 --- a/drivers/net/wireless/ath/ath5k/trace.h +++ b/drivers/net/wireless/ath/ath5k/trace.h @@ -2,7 +2,6 @@ #define __TRACE_ATH5K_H #include <linux/tracepoint.h> -#include "base.h" #ifndef CONFIG_ATH5K_TRACER #undef TRACE_EVENT @@ -11,6 +10,8 @@ static inline void trace_ ## name(proto) {} #endif struct sk_buff; +struct ath5k_txq; +struct ath5k_tx_status; #undef TRACE_SYSTEM #define TRACE_SYSTEM ath5k diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig new file mode 100644 index 000000000000..3d5f8be20eac --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -0,0 +1,15 @@ +config ATH6KL + tristate "Atheros ath6kl support" + depends on MMC + depends on CFG80211 + ---help--- + This module adds support for wireless adapters based on + Atheros AR6003 chipset running over SDIO. If you choose to + build it as a module, it will be called ath6kl. Pls note + that AR6002 and AR6001 are not supported by this driver. + +config ATH6KL_DEBUG + bool "Atheros ath6kl debugging" + depends on ATH6KL + ---help--- + Enables debug support diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile new file mode 100644 index 000000000000..8f7a0d1c290c --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/Makefile @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------------ +# Copyright (c) 2004-2010 Atheros Communications Inc. +# All rights reserved. +# +# +# +# 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. +# +# +# +# Author(s): ="Atheros" +#------------------------------------------------------------------------------ + +obj-$(CONFIG_ATH6KL) := ath6kl.o +ath6kl-y += debug.o +ath6kl-y += htc_hif.o +ath6kl-y += htc.o +ath6kl-y += bmi.o +ath6kl-y += cfg80211.o +ath6kl-y += init.o +ath6kl-y += main.o +ath6kl-y += txrx.o +ath6kl-y += wmi.o +ath6kl-y += sdio.o +ath6kl-$(CONFIG_NL80211_TESTMODE) += testmode.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/ath/ath6kl/bmi.c b/drivers/net/wireless/ath/ath6kl/bmi.c new file mode 100644 index 000000000000..c5d11cc536e0 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/bmi.c @@ -0,0 +1,689 @@ +/* + * 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 "core.h" +#include "hif-ops.h" +#include "target.h" +#include "debug.h" + +static int ath6kl_get_bmi_cmd_credits(struct ath6kl *ar) +{ + u32 addr; + unsigned long timeout; + int ret; + + ar->bmi.cmd_credits = 0; + + /* Read the counter register to get the command credits */ + addr = COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; + + timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); + while (time_before(jiffies, timeout) && !ar->bmi.cmd_credits) { + + /* + * Hit the credit counter with a 4-byte access, the first byte + * read will hit the counter and cause a decrement, while the + * remaining 3 bytes has no effect. The rationale behind this + * is to make all HIF accesses 4-byte aligned. + */ + ret = hif_read_write_sync(ar, addr, + (u8 *)&ar->bmi.cmd_credits, 4, + HIF_RD_SYNC_BYTE_INC); + if (ret) { + ath6kl_err("Unable to decrement the command credit count register: %d\n", + ret); + return ret; + } + + /* The counter is only 8 bits. + * Ignore anything in the upper 3 bytes + */ + ar->bmi.cmd_credits &= 0xFF; + } + + if (!ar->bmi.cmd_credits) { + ath6kl_err("bmi communication timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int ath6kl_bmi_get_rx_lkahd(struct ath6kl *ar) +{ + unsigned long timeout; + u32 rx_word = 0; + int ret = 0; + + timeout = jiffies + msecs_to_jiffies(BMI_COMMUNICATION_TIMEOUT); + while (time_before(jiffies, timeout) && !rx_word) { + ret = hif_read_write_sync(ar, RX_LOOKAHEAD_VALID_ADDRESS, + (u8 *)&rx_word, sizeof(rx_word), + HIF_RD_SYNC_BYTE_INC); + if (ret) { + ath6kl_err("unable to read RX_LOOKAHEAD_VALID\n"); + return ret; + } + + /* all we really want is one bit */ + rx_word &= (1 << ENDPOINT1); + } + + if (!rx_word) { + ath6kl_err("bmi_recv_buf FIFO empty\n"); + return -EINVAL; + } + + return ret; +} + +static int ath6kl_bmi_send_buf(struct ath6kl *ar, u8 *buf, u32 len) +{ + int ret; + u32 addr; + + ret = ath6kl_get_bmi_cmd_credits(ar); + if (ret) + return ret; + + addr = ar->mbox_info.htc_addr; + + ret = hif_read_write_sync(ar, addr, buf, len, + HIF_WR_SYNC_BYTE_INC); + if (ret) + ath6kl_err("unable to send the bmi data to the device\n"); + + return ret; +} + +static int ath6kl_bmi_recv_buf(struct ath6kl *ar, u8 *buf, u32 len) +{ + int ret; + u32 addr; + + /* + * During normal bootup, small reads may be required. + * Rather than issue an HIF Read and then wait as the Target + * adds successive bytes to the FIFO, we wait here until + * we know that response data is available. + * + * This allows us to cleanly timeout on an unexpected + * Target failure rather than risk problems at the HIF level. + * In particular, this avoids SDIO timeouts and possibly garbage + * data on some host controllers. And on an interconnect + * such as Compact Flash (as well as some SDIO masters) which + * does not provide any indication on data timeout, it avoids + * a potential hang or garbage response. + * + * Synchronization is more difficult for reads larger than the + * size of the MBOX FIFO (128B), because the Target is unable + * to push the 129th byte of data until AFTER the Host posts an + * HIF Read and removes some FIFO data. So for large reads the + * Host proceeds to post an HIF Read BEFORE all the data is + * actually available to read. Fortunately, large BMI reads do + * not occur in practice -- they're supported for debug/development. + * + * So Host/Target BMI synchronization is divided into these cases: + * CASE 1: length < 4 + * Should not happen + * + * CASE 2: 4 <= length <= 128 + * Wait for first 4 bytes to be in FIFO + * If CONSERVATIVE_BMI_READ is enabled, also wait for + * a BMI command credit, which indicates that the ENTIRE + * response is available in the the FIFO + * + * CASE 3: length > 128 + * Wait for the first 4 bytes to be in FIFO + * + * For most uses, a small timeout should be sufficient and we will + * usually see a response quickly; but there may be some unusual + * (debug) cases of BMI_EXECUTE where we want an larger timeout. + * For now, we use an unbounded busy loop while waiting for + * BMI_EXECUTE. + * + * If BMI_EXECUTE ever needs to support longer-latency execution, + * especially in production, this code needs to be enhanced to sleep + * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently + * a function of Host processor speed. + */ + if (len >= 4) { /* NB: Currently, always true */ + ret = ath6kl_bmi_get_rx_lkahd(ar); + if (ret) + return ret; + } + + addr = ar->mbox_info.htc_addr; + ret = hif_read_write_sync(ar, addr, buf, len, + HIF_RD_SYNC_BYTE_INC); + if (ret) { + ath6kl_err("Unable to read the bmi data from the device: %d\n", + ret); + return ret; + } + + return 0; +} + +int ath6kl_bmi_done(struct ath6kl *ar) +{ + int ret; + u32 cid = BMI_DONE; + + if (ar->bmi.done_sent) { + ath6kl_dbg(ATH6KL_DBG_BMI, "bmi done skipped\n"); + return 0; + } + + ar->bmi.done_sent = true; + + ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid)); + if (ret) { + ath6kl_err("Unable to send bmi done: %d\n", ret); + return ret; + } + + ath6kl_bmi_cleanup(ar); + + return 0; +} + +int ath6kl_bmi_get_target_info(struct ath6kl *ar, + struct ath6kl_bmi_target_info *targ_info) +{ + int ret; + u32 cid = BMI_GET_TARGET_INFO; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + ret = ath6kl_bmi_send_buf(ar, (u8 *)&cid, sizeof(cid)); + if (ret) { + ath6kl_err("Unable to send get target info: %d\n", ret); + return ret; + } + + ret = ath6kl_bmi_recv_buf(ar, (u8 *)&targ_info->version, + sizeof(targ_info->version)); + if (ret) { + ath6kl_err("Unable to recv target info: %d\n", ret); + return ret; + } + + if (le32_to_cpu(targ_info->version) == TARGET_VERSION_SENTINAL) { + /* Determine how many bytes are in the Target's targ_info */ + ret = ath6kl_bmi_recv_buf(ar, + (u8 *)&targ_info->byte_count, + sizeof(targ_info->byte_count)); + if (ret) { + ath6kl_err("unable to read target info byte count: %d\n", + ret); + return ret; + } + + /* + * The target's targ_info doesn't match the host's targ_info. + * We need to do some backwards compatibility to make this work. + */ + if (le32_to_cpu(targ_info->byte_count) != sizeof(*targ_info)) { + WARN_ON(1); + return -EINVAL; + } + + /* Read the remainder of the targ_info */ + ret = ath6kl_bmi_recv_buf(ar, + ((u8 *)targ_info) + + sizeof(targ_info->byte_count), + sizeof(*targ_info) - + sizeof(targ_info->byte_count)); + + if (ret) { + ath6kl_err("Unable to read target info (%d bytes): %d\n", + targ_info->byte_count, ret); + return ret; + } + } + + ath6kl_dbg(ATH6KL_DBG_BMI, "target info (ver: 0x%x type: 0x%x)\n", + targ_info->version, targ_info->type); + + return 0; +} + +int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) +{ + u32 cid = BMI_READ_MEMORY; + int ret; + u32 offset; + u32 len_remain, rx_len; + u16 size; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + size = BMI_DATASZ_MAX + sizeof(cid) + sizeof(addr) + sizeof(len); + if (size > MAX_BMI_CMDBUF_SZ) { + WARN_ON(1); + return -EINVAL; + } + memset(ar->bmi.cmd_buf, 0, size); + + ath6kl_dbg(ATH6KL_DBG_BMI, + "bmi read memory: device: addr: 0x%x, len: %d\n", + addr, len); + + len_remain = len; + + while (len_remain) { + rx_len = (len_remain < BMI_DATASZ_MAX) ? + len_remain : BMI_DATASZ_MAX; + offset = 0; + memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); + offset += sizeof(addr); + memcpy(&(ar->bmi.cmd_buf[offset]), &rx_len, sizeof(rx_len)); + offset += sizeof(len); + + ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); + if (ret) { + ath6kl_err("Unable to write to the device: %d\n", + ret); + return ret; + } + ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, rx_len); + if (ret) { + ath6kl_err("Unable to read from the device: %d\n", + ret); + return ret; + } + memcpy(&buf[len - len_remain], ar->bmi.cmd_buf, rx_len); + len_remain -= rx_len; addr += rx_len; + } + + return 0; +} + +int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) +{ + u32 cid = BMI_WRITE_MEMORY; + int ret; + u32 offset; + u32 len_remain, tx_len; + const u32 header = sizeof(cid) + sizeof(addr) + sizeof(len); + u8 aligned_buf[BMI_DATASZ_MAX]; + u8 *src; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + if ((BMI_DATASZ_MAX + header) > MAX_BMI_CMDBUF_SZ) { + WARN_ON(1); + return -EINVAL; + } + + memset(ar->bmi.cmd_buf, 0, BMI_DATASZ_MAX + header); + + ath6kl_dbg(ATH6KL_DBG_BMI, + "bmi write memory: addr: 0x%x, len: %d\n", addr, len); + + len_remain = len; + while (len_remain) { + src = &buf[len - len_remain]; + + if (len_remain < (BMI_DATASZ_MAX - header)) { + if (len_remain & 3) { + /* align it with 4 bytes */ + len_remain = len_remain + + (4 - (len_remain & 3)); + memcpy(aligned_buf, src, len_remain); + src = aligned_buf; + } + tx_len = len_remain; + } else { + tx_len = (BMI_DATASZ_MAX - header); + } + + offset = 0; + memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); + offset += sizeof(addr); + memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); + offset += sizeof(tx_len); + memcpy(&(ar->bmi.cmd_buf[offset]), src, tx_len); + offset += tx_len; + + ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); + if (ret) { + ath6kl_err("Unable to write to the device: %d\n", + ret); + return ret; + } + len_remain -= tx_len; addr += tx_len; + } + + return 0; +} + +int ath6kl_bmi_execute(struct ath6kl *ar, u32 addr, u32 *param) +{ + u32 cid = BMI_EXECUTE; + int ret; + u32 offset; + u16 size; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + size = sizeof(cid) + sizeof(addr) + sizeof(param); + if (size > MAX_BMI_CMDBUF_SZ) { + WARN_ON(1); + return -EINVAL; + } + memset(ar->bmi.cmd_buf, 0, size); + + ath6kl_dbg(ATH6KL_DBG_BMI, "bmi execute: addr: 0x%x, param: %d)\n", + addr, *param); + + offset = 0; + memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); + offset += sizeof(addr); + memcpy(&(ar->bmi.cmd_buf[offset]), param, sizeof(*param)); + offset += sizeof(*param); + + ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); + if (ret) { + ath6kl_err("Unable to write to the device: %d\n", ret); + return ret; + } + + ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param)); + if (ret) { + ath6kl_err("Unable to read from the device: %d\n", ret); + return ret; + } + + memcpy(param, ar->bmi.cmd_buf, sizeof(*param)); + + return 0; +} + +int ath6kl_bmi_set_app_start(struct ath6kl *ar, u32 addr) +{ + u32 cid = BMI_SET_APP_START; + int ret; + u32 offset; + u16 size; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + size = sizeof(cid) + sizeof(addr); + if (size > MAX_BMI_CMDBUF_SZ) { + WARN_ON(1); + return -EINVAL; + } + memset(ar->bmi.cmd_buf, 0, size); + + ath6kl_dbg(ATH6KL_DBG_BMI, "bmi set app start: addr: 0x%x\n", addr); + + offset = 0; + memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); + offset += sizeof(addr); + + ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); + if (ret) { + ath6kl_err("Unable to write to the device: %d\n", ret); + return ret; + } + + return 0; +} + +int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param) +{ + u32 cid = BMI_READ_SOC_REGISTER; + int ret; + u32 offset; + u16 size; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + size = sizeof(cid) + sizeof(addr); + if (size > MAX_BMI_CMDBUF_SZ) { + WARN_ON(1); + return -EINVAL; + } + memset(ar->bmi.cmd_buf, 0, size); + + ath6kl_dbg(ATH6KL_DBG_BMI, "bmi read SOC reg: addr: 0x%x\n", addr); + + offset = 0; + memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); + offset += sizeof(addr); + + ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); + if (ret) { + ath6kl_err("Unable to write to the device: %d\n", ret); + return ret; + } + + ret = ath6kl_bmi_recv_buf(ar, ar->bmi.cmd_buf, sizeof(*param)); + if (ret) { + ath6kl_err("Unable to read from the device: %d\n", ret); + return ret; + } + memcpy(param, ar->bmi.cmd_buf, sizeof(*param)); + + return 0; +} + +int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param) +{ + u32 cid = BMI_WRITE_SOC_REGISTER; + int ret; + u32 offset; + u16 size; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + size = sizeof(cid) + sizeof(addr) + sizeof(param); + if (size > MAX_BMI_CMDBUF_SZ) { + WARN_ON(1); + return -EINVAL; + } + memset(ar->bmi.cmd_buf, 0, size); + + ath6kl_dbg(ATH6KL_DBG_BMI, + "bmi write SOC reg: addr: 0x%x, param: %d\n", + addr, param); + + offset = 0; + memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); + offset += sizeof(addr); + memcpy(&(ar->bmi.cmd_buf[offset]), ¶m, sizeof(param)); + offset += sizeof(param); + + ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); + if (ret) { + ath6kl_err("Unable to write to the device: %d\n", ret); + return ret; + } + + return 0; +} + +int ath6kl_bmi_lz_data(struct ath6kl *ar, u8 *buf, u32 len) +{ + u32 cid = BMI_LZ_DATA; + int ret; + u32 offset; + u32 len_remain, tx_len; + const u32 header = sizeof(cid) + sizeof(len); + u16 size; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + size = BMI_DATASZ_MAX + header; + if (size > MAX_BMI_CMDBUF_SZ) { + WARN_ON(1); + return -EINVAL; + } + memset(ar->bmi.cmd_buf, 0, size); + + ath6kl_dbg(ATH6KL_DBG_BMI, "bmi send LZ data: len: %d)\n", + len); + + len_remain = len; + while (len_remain) { + tx_len = (len_remain < (BMI_DATASZ_MAX - header)) ? + len_remain : (BMI_DATASZ_MAX - header); + + offset = 0; + memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + memcpy(&(ar->bmi.cmd_buf[offset]), &tx_len, sizeof(tx_len)); + offset += sizeof(tx_len); + memcpy(&(ar->bmi.cmd_buf[offset]), &buf[len - len_remain], + tx_len); + offset += tx_len; + + ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); + if (ret) { + ath6kl_err("Unable to write to the device: %d\n", + ret); + return ret; + } + + len_remain -= tx_len; + } + + return 0; +} + +int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, u32 addr) +{ + u32 cid = BMI_LZ_STREAM_START; + int ret; + u32 offset; + u16 size; + + if (ar->bmi.done_sent) { + ath6kl_err("bmi done sent already, cmd %d disallowed\n", cid); + return -EACCES; + } + + size = sizeof(cid) + sizeof(addr); + if (size > MAX_BMI_CMDBUF_SZ) { + WARN_ON(1); + return -EINVAL; + } + memset(ar->bmi.cmd_buf, 0, size); + + ath6kl_dbg(ATH6KL_DBG_BMI, + "bmi LZ stream start: addr: 0x%x)\n", + addr); + + offset = 0; + memcpy(&(ar->bmi.cmd_buf[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + memcpy(&(ar->bmi.cmd_buf[offset]), &addr, sizeof(addr)); + offset += sizeof(addr); + + ret = ath6kl_bmi_send_buf(ar, ar->bmi.cmd_buf, offset); + if (ret) { + ath6kl_err("Unable to start LZ stream to the device: %d\n", + ret); + return ret; + } + + return 0; +} + +int ath6kl_bmi_fast_download(struct ath6kl *ar, u32 addr, u8 *buf, u32 len) +{ + int ret; + u32 last_word = 0; + u32 last_word_offset = len & ~0x3; + u32 unaligned_bytes = len & 0x3; + + ret = ath6kl_bmi_lz_stream_start(ar, addr); + if (ret) + return ret; + + if (unaligned_bytes) { + /* copy the last word into a zero padded buffer */ + memcpy(&last_word, &buf[last_word_offset], unaligned_bytes); + } + + ret = ath6kl_bmi_lz_data(ar, buf, last_word_offset); + if (ret) + return ret; + + if (unaligned_bytes) + ret = ath6kl_bmi_lz_data(ar, (u8 *)&last_word, 4); + + if (!ret) { + /* Close compressed stream and open a new (fake) one. + * This serves mainly to flush Target caches. */ + ret = ath6kl_bmi_lz_stream_start(ar, 0x00); + } + return ret; +} + +int ath6kl_bmi_init(struct ath6kl *ar) +{ + ar->bmi.cmd_buf = kzalloc(MAX_BMI_CMDBUF_SZ, GFP_ATOMIC); + + if (!ar->bmi.cmd_buf) + return -ENOMEM; + + return 0; +} + +void ath6kl_bmi_cleanup(struct ath6kl *ar) +{ + kfree(ar->bmi.cmd_buf); + ar->bmi.cmd_buf = NULL; +} diff --git a/drivers/net/wireless/ath/ath6kl/bmi.h b/drivers/net/wireless/ath/ath6kl/bmi.h new file mode 100644 index 000000000000..96851d5df24b --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/bmi.h @@ -0,0 +1,250 @@ +/* + * 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. + */ + +#ifndef BMI_H +#define BMI_H + +/* + * Bootloader Messaging Interface (BMI) + * + * BMI is a very simple messaging interface used during initialization + * to read memory, write memory, execute code, and to define an + * application entry PC. + * + * It is used to download an application to ATH6KL, to provide + * patches to code that is already resident on ATH6KL, and generally + * to examine and modify state. The Host has an opportunity to use + * BMI only once during bootup. Once the Host issues a BMI_DONE + * command, this opportunity ends. + * + * The Host writes BMI requests to mailbox0, and reads BMI responses + * from mailbox0. BMI requests all begin with a command + * (see below for specific commands), and are followed by + * command-specific data. + * + * Flow control: + * The Host can only issue a command once the Target gives it a + * "BMI Command Credit", using ATH6KL Counter #4. As soon as the + * Target has completed a command, it issues another BMI Command + * Credit (so the Host can issue the next command). + * + * BMI handles all required Target-side cache flushing. + */ + +#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \ + (sizeof(u32) * 3 /* cmd + addr + len */)) + +/* Maximum data size used for BMI transfers */ +#define BMI_DATASZ_MAX 256 + +/* BMI Commands */ + +#define BMI_NO_COMMAND 0 + +#define BMI_DONE 1 +/* + * Semantics: Host is done using BMI + * Request format: + * u32 command (BMI_DONE) + * Response format: none + */ + +#define BMI_READ_MEMORY 2 +/* + * Semantics: Host reads ATH6KL memory + * Request format: + * u32 command (BMI_READ_MEMORY) + * u32 address + * u32 length, at most BMI_DATASZ_MAX + * Response format: + * u8 data[length] + */ + +#define BMI_WRITE_MEMORY 3 +/* + * Semantics: Host writes ATH6KL memory + * Request format: + * u32 command (BMI_WRITE_MEMORY) + * u32 address + * u32 length, at most BMI_DATASZ_MAX + * u8 data[length] + * Response format: none + */ + +#define BMI_EXECUTE 4 +/* + * Semantics: Causes ATH6KL to execute code + * Request format: + * u32 command (BMI_EXECUTE) + * u32 address + * u32 parameter + * Response format: + * u32 return value + */ + +#define BMI_SET_APP_START 5 +/* + * Semantics: Set Target application starting address + * Request format: + * u32 command (BMI_SET_APP_START) + * u32 address + * Response format: none + */ + +#define BMI_READ_SOC_REGISTER 6 +/* + * Semantics: Read a 32-bit Target SOC register. + * Request format: + * u32 command (BMI_READ_REGISTER) + * u32 address + * Response format: + * u32 value + */ + +#define BMI_WRITE_SOC_REGISTER 7 +/* + * Semantics: Write a 32-bit Target SOC register. + * Request format: + * u32 command (BMI_WRITE_REGISTER) + * u32 address + * u32 value + * + * Response format: none + */ + +#define BMI_GET_TARGET_ID 8 +#define BMI_GET_TARGET_INFO 8 +/* + * Semantics: Fetch the 4-byte Target information + * Request format: + * u32 command (BMI_GET_TARGET_ID/INFO) + * Response format1 (old firmware): + * u32 TargetVersionID + * Response format2 (newer firmware): + * u32 TARGET_VERSION_SENTINAL + * struct bmi_target_info; + */ + +#define TARGET_VERSION_SENTINAL 0xffffffff +#define TARGET_TYPE_AR6003 3 +#define TARGET_TYPE_AR6004 5 +#define BMI_ROMPATCH_INSTALL 9 +/* + * Semantics: Install a ROM Patch. + * Request format: + * u32 command (BMI_ROMPATCH_INSTALL) + * u32 Target ROM Address + * u32 Target RAM Address or Value (depending on Target Type) + * u32 Size, in bytes + * u32 Activate? 1-->activate; + * 0-->install but do not activate + * Response format: + * u32 PatchID + */ + +#define BMI_ROMPATCH_UNINSTALL 10 +/* + * Semantics: Uninstall a previously-installed ROM Patch, + * automatically deactivating, if necessary. + * Request format: + * u32 command (BMI_ROMPATCH_UNINSTALL) + * u32 PatchID + * + * Response format: none + */ + +#define BMI_ROMPATCH_ACTIVATE 11 +/* + * Semantics: Activate a list of previously-installed ROM Patches. + * Request format: + * u32 command (BMI_ROMPATCH_ACTIVATE) + * u32 rompatch_count + * u32 PatchID[rompatch_count] + * + * Response format: none + */ + +#define BMI_ROMPATCH_DEACTIVATE 12 +/* + * Semantics: Deactivate a list of active ROM Patches. + * Request format: + * u32 command (BMI_ROMPATCH_DEACTIVATE) + * u32 rompatch_count + * u32 PatchID[rompatch_count] + * + * Response format: none + */ + + +#define BMI_LZ_STREAM_START 13 +/* + * Semantics: Begin an LZ-compressed stream of input + * which is to be uncompressed by the Target to an + * output buffer at address. The output buffer must + * be sufficiently large to hold the uncompressed + * output from the compressed input stream. This BMI + * command should be followed by a series of 1 or more + * BMI_LZ_DATA commands. + * u32 command (BMI_LZ_STREAM_START) + * u32 address + * Note: Not supported on all versions of ROM firmware. + */ + +#define BMI_LZ_DATA 14 +/* + * Semantics: Host writes ATH6KL memory with LZ-compressed + * data which is uncompressed by the Target. This command + * must be preceded by a BMI_LZ_STREAM_START command. A series + * of BMI_LZ_DATA commands are considered part of a single + * input stream until another BMI_LZ_STREAM_START is issued. + * Request format: + * u32 command (BMI_LZ_DATA) + * u32 length (of compressed data), + * at most BMI_DATASZ_MAX + * u8 CompressedData[length] + * Response format: none + * Note: Not supported on all versions of ROM firmware. + */ + +#define BMI_COMMUNICATION_TIMEOUT 1000 /* in msec */ + +struct ath6kl; +struct ath6kl_bmi_target_info { + __le32 byte_count; /* size of this structure */ + __le32 version; /* target version id */ + __le32 type; /* target type */ +} __packed; + +int ath6kl_bmi_init(struct ath6kl *ar); +void ath6kl_bmi_cleanup(struct ath6kl *ar); +int ath6kl_bmi_done(struct ath6kl *ar); +int ath6kl_bmi_get_target_info(struct ath6kl *ar, + struct ath6kl_bmi_target_info *targ_info); +int ath6kl_bmi_read(struct ath6kl *ar, u32 addr, u8 *buf, u32 len); +int ath6kl_bmi_write(struct ath6kl *ar, u32 addr, u8 *buf, u32 len); +int ath6kl_bmi_execute(struct ath6kl *ar, + u32 addr, u32 *param); +int ath6kl_bmi_set_app_start(struct ath6kl *ar, + u32 addr); +int ath6kl_bmi_reg_read(struct ath6kl *ar, u32 addr, u32 *param); +int ath6kl_bmi_reg_write(struct ath6kl *ar, u32 addr, u32 param); +int ath6kl_bmi_lz_data(struct ath6kl *ar, + u8 *buf, u32 len); +int ath6kl_bmi_lz_stream_start(struct ath6kl *ar, + u32 addr); +int ath6kl_bmi_fast_download(struct ath6kl *ar, + u32 addr, u8 *buf, u32 len); +#endif diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c new file mode 100644 index 000000000000..3aff36bad5d3 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -0,0 +1,1914 @@ +/* + * 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 "core.h" +#include "cfg80211.h" +#include "debug.h" +#include "hif-ops.h" +#include "testmode.h" + +static unsigned int ath6kl_p2p; + +module_param(ath6kl_p2p, uint, 0644); + +#define RATETAB_ENT(_rate, _rateid, _flags) { \ + .bitrate = (_rate), \ + .flags = (_flags), \ + .hw_value = (_rateid), \ +} + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .hw_value = (_channel), \ + .center_freq = (_freq), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define CHAN5G(_channel, _flags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .hw_value = (_channel), \ + .center_freq = 5000 + (5 * (_channel)), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_rate ath6kl_rates[] = { + RATETAB_ENT(10, 0x1, 0), + RATETAB_ENT(20, 0x2, 0), + RATETAB_ENT(55, 0x4, 0), + RATETAB_ENT(110, 0x8, 0), + RATETAB_ENT(60, 0x10, 0), + RATETAB_ENT(90, 0x20, 0), + RATETAB_ENT(120, 0x40, 0), + RATETAB_ENT(180, 0x80, 0), + RATETAB_ENT(240, 0x100, 0), + RATETAB_ENT(360, 0x200, 0), + RATETAB_ENT(480, 0x400, 0), + RATETAB_ENT(540, 0x800, 0), +}; + +#define ath6kl_a_rates (ath6kl_rates + 4) +#define ath6kl_a_rates_size 8 +#define ath6kl_g_rates (ath6kl_rates + 0) +#define ath6kl_g_rates_size 12 + +static struct ieee80211_channel ath6kl_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static struct ieee80211_channel ath6kl_5ghz_a_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +static struct ieee80211_supported_band ath6kl_band_2ghz = { + .n_channels = ARRAY_SIZE(ath6kl_2ghz_channels), + .channels = ath6kl_2ghz_channels, + .n_bitrates = ath6kl_g_rates_size, + .bitrates = ath6kl_g_rates, +}; + +static struct ieee80211_supported_band ath6kl_band_5ghz = { + .n_channels = ARRAY_SIZE(ath6kl_5ghz_a_channels), + .channels = ath6kl_5ghz_a_channels, + .n_bitrates = ath6kl_a_rates_size, + .bitrates = ath6kl_a_rates, +}; + +static int ath6kl_set_wpa_version(struct ath6kl *ar, + enum nl80211_wpa_versions wpa_version) +{ + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: %u\n", __func__, wpa_version); + + if (!wpa_version) { + ar->auth_mode = NONE_AUTH; + } else if (wpa_version & NL80211_WPA_VERSION_2) { + ar->auth_mode = WPA2_AUTH; + } else if (wpa_version & NL80211_WPA_VERSION_1) { + ar->auth_mode = WPA_AUTH; + } else { + ath6kl_err("%s: %u not supported\n", __func__, wpa_version); + return -ENOTSUPP; + } + + return 0; +} + +static int ath6kl_set_auth_type(struct ath6kl *ar, + enum nl80211_auth_type auth_type) +{ + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, auth_type); + + switch (auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + ar->dot11_auth_mode = OPEN_AUTH; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + ar->dot11_auth_mode = SHARED_AUTH; + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + ar->dot11_auth_mode = LEAP_AUTH; + break; + + case NL80211_AUTHTYPE_AUTOMATIC: + ar->dot11_auth_mode = OPEN_AUTH | SHARED_AUTH; + break; + + default: + ath6kl_err("%s: 0x%x not spported\n", __func__, auth_type); + return -ENOTSUPP; + } + + return 0; +} + +static int ath6kl_set_cipher(struct ath6kl *ar, u32 cipher, bool ucast) +{ + u8 *ar_cipher = ucast ? &ar->prwise_crypto : &ar->grp_crypto; + u8 *ar_cipher_len = ucast ? &ar->prwise_crypto_len : + &ar->grp_crypto_len; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: cipher 0x%x, ucast %u\n", + __func__, cipher, ucast); + + switch (cipher) { + case 0: + /* our own hack to use value 0 as no crypto used */ + *ar_cipher = NONE_CRYPT; + *ar_cipher_len = 0; + break; + case WLAN_CIPHER_SUITE_WEP40: + *ar_cipher = WEP_CRYPT; + *ar_cipher_len = 5; + break; + case WLAN_CIPHER_SUITE_WEP104: + *ar_cipher = WEP_CRYPT; + *ar_cipher_len = 13; + break; + case WLAN_CIPHER_SUITE_TKIP: + *ar_cipher = TKIP_CRYPT; + *ar_cipher_len = 0; + break; + case WLAN_CIPHER_SUITE_CCMP: + *ar_cipher = AES_CRYPT; + *ar_cipher_len = 0; + break; + default: + ath6kl_err("cipher 0x%x not supported\n", cipher); + return -ENOTSUPP; + } + + return 0; +} + +static void ath6kl_set_key_mgmt(struct ath6kl *ar, u32 key_mgmt) +{ + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: 0x%x\n", __func__, key_mgmt); + + if (key_mgmt == WLAN_AKM_SUITE_PSK) { + if (ar->auth_mode == WPA_AUTH) + ar->auth_mode = WPA_PSK_AUTH; + else if (ar->auth_mode == WPA2_AUTH) + ar->auth_mode = WPA2_PSK_AUTH; + } else if (key_mgmt != WLAN_AKM_SUITE_8021X) { + ar->auth_mode = NONE_AUTH; + } +} + +static bool ath6kl_cfg80211_ready(struct ath6kl *ar) +{ + if (!test_bit(WMI_READY, &ar->flag)) { + ath6kl_err("wmi is not ready\n"); + return false; + } + + if (!test_bit(WLAN_ENABLED, &ar->flag)) { + ath6kl_err("wlan disabled\n"); + return false; + } + + return true; +} + +static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct ath6kl *ar = ath6kl_priv(dev); + int status; + + ar->sme_state = SME_CONNECTING; + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { + ath6kl_err("destroy in progress\n"); + return -EBUSY; + } + + if (test_bit(SKIP_SCAN, &ar->flag) && + ((sme->channel && sme->channel->center_freq == 0) || + (sme->bssid && is_zero_ether_addr(sme->bssid)))) { + ath6kl_err("SkipScan: channel or bssid invalid\n"); + return -EINVAL; + } + + if (down_interruptible(&ar->sem)) { + ath6kl_err("busy, couldn't get access\n"); + return -ERESTARTSYS; + } + + if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { + ath6kl_err("busy, destroy in progress\n"); + up(&ar->sem); + return -EBUSY; + } + + if (ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)]) { + /* + * sleep until the command queue drains + */ + wait_event_interruptible_timeout(ar->event_wq, + ar->tx_pending[ath6kl_wmi_get_control_ep(ar->wmi)] == 0, + WMI_TIMEOUT); + if (signal_pending(current)) { + ath6kl_err("cmd queue drain timeout\n"); + up(&ar->sem); + return -EINTR; + } + } + + if (test_bit(CONNECTED, &ar->flag) && + ar->ssid_len == sme->ssid_len && + !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) { + ar->reconnect_flag = true; + status = ath6kl_wmi_reconnect_cmd(ar->wmi, ar->req_bssid, + ar->ch_hint); + + up(&ar->sem); + if (status) { + ath6kl_err("wmi_reconnect_cmd failed\n"); + return -EIO; + } + return 0; + } else if (ar->ssid_len == sme->ssid_len && + !memcmp(ar->ssid, sme->ssid, ar->ssid_len)) { + ath6kl_disconnect(ar); + } + + memset(ar->ssid, 0, sizeof(ar->ssid)); + ar->ssid_len = sme->ssid_len; + memcpy(ar->ssid, sme->ssid, sme->ssid_len); + + if (sme->channel) + ar->ch_hint = sme->channel->center_freq; + + memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); + if (sme->bssid && !is_broadcast_ether_addr(sme->bssid)) + memcpy(ar->req_bssid, sme->bssid, sizeof(ar->req_bssid)); + + ath6kl_set_wpa_version(ar, sme->crypto.wpa_versions); + + status = ath6kl_set_auth_type(ar, sme->auth_type); + if (status) { + up(&ar->sem); + return status; + } + + if (sme->crypto.n_ciphers_pairwise) + ath6kl_set_cipher(ar, sme->crypto.ciphers_pairwise[0], true); + else + ath6kl_set_cipher(ar, 0, true); + + ath6kl_set_cipher(ar, sme->crypto.cipher_group, false); + + if (sme->crypto.n_akm_suites) + ath6kl_set_key_mgmt(ar, sme->crypto.akm_suites[0]); + + if ((sme->key_len) && + (ar->auth_mode == NONE_AUTH) && (ar->prwise_crypto == WEP_CRYPT)) { + struct ath6kl_key *key = NULL; + + if (sme->key_idx < WMI_MIN_KEY_INDEX || + sme->key_idx > WMI_MAX_KEY_INDEX) { + ath6kl_err("key index %d out of bounds\n", + sme->key_idx); + up(&ar->sem); + return -ENOENT; + } + + key = &ar->keys[sme->key_idx]; + key->key_len = sme->key_len; + memcpy(key->key, sme->key, key->key_len); + key->cipher = ar->prwise_crypto; + ar->def_txkey_index = sme->key_idx; + + ath6kl_wmi_addkey_cmd(ar->wmi, sme->key_idx, + ar->prwise_crypto, + GROUP_USAGE | TX_USAGE, + key->key_len, + NULL, + key->key, KEY_OP_INIT_VAL, NULL, + NO_SYNC_WMIFLAG); + } + + if (!ar->usr_bss_filter) { + clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); + if (ath6kl_wmi_bssfilter_cmd(ar->wmi, ALL_BSS_FILTER, 0) != 0) { + ath6kl_err("couldn't set bss filtering\n"); + up(&ar->sem); + return -EIO; + } + } + + ar->nw_type = ar->next_mode; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: connect called with authmode %d dot11 auth %d" + " PW crypto %d PW crypto len %d GRP crypto %d" + " GRP crypto len %d channel hint %u\n", + __func__, + ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, + ar->prwise_crypto_len, ar->grp_crypto, + ar->grp_crypto_len, ar->ch_hint); + + ar->reconnect_flag = 0; + status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, + ar->dot11_auth_mode, ar->auth_mode, + ar->prwise_crypto, + ar->prwise_crypto_len, + ar->grp_crypto, ar->grp_crypto_len, + ar->ssid_len, ar->ssid, + ar->req_bssid, ar->ch_hint, + ar->connect_ctrl_flags); + + up(&ar->sem); + + if (status == -EINVAL) { + memset(ar->ssid, 0, sizeof(ar->ssid)); + ar->ssid_len = 0; + ath6kl_err("invalid request\n"); + return -ENOENT; + } else if (status) { + ath6kl_err("ath6kl_wmi_connect_cmd failed\n"); + return -EIO; + } + + if ((!(ar->connect_ctrl_flags & CONNECT_DO_WPA_OFFLOAD)) && + ((ar->auth_mode == WPA_PSK_AUTH) + || (ar->auth_mode == WPA2_PSK_AUTH))) { + mod_timer(&ar->disconnect_timer, + jiffies + msecs_to_jiffies(DISCON_TIMER_INTVAL)); + } + + ar->connect_ctrl_flags &= ~CONNECT_DO_WPA_OFFLOAD; + set_bit(CONNECT_PEND, &ar->flag); + + return 0; +} + +static int ath6kl_add_bss_if_needed(struct ath6kl *ar, const u8 *bssid, + struct ieee80211_channel *chan, + const u8 *beacon_ie, size_t beacon_ie_len) +{ + struct cfg80211_bss *bss; + u8 *ie; + + bss = cfg80211_get_bss(ar->wdev->wiphy, chan, bssid, + ar->ssid, ar->ssid_len, WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + if (bss == NULL) { + /* + * Since cfg80211 may not yet know about the BSS, + * generate a partial entry until the first BSS info + * event becomes available. + * + * Prepend SSID element since it is not included in the Beacon + * IEs from the target. + */ + ie = kmalloc(2 + ar->ssid_len + beacon_ie_len, GFP_KERNEL); + if (ie == NULL) + return -ENOMEM; + ie[0] = WLAN_EID_SSID; + ie[1] = ar->ssid_len; + memcpy(ie + 2, ar->ssid, ar->ssid_len); + memcpy(ie + 2 + ar->ssid_len, beacon_ie, beacon_ie_len); + bss = cfg80211_inform_bss(ar->wdev->wiphy, chan, + bssid, 0, WLAN_CAPABILITY_ESS, 100, + ie, 2 + ar->ssid_len + beacon_ie_len, + 0, GFP_KERNEL); + if (bss) + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added dummy bss for " + "%pM prior to indicating connect/roamed " + "event\n", bssid); + kfree(ie); + } else + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss " + "entry\n"); + + if (bss == NULL) + return -ENOMEM; + + cfg80211_put_bss(bss); + + return 0; +} + +void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, + u8 *bssid, u16 listen_intvl, + u16 beacon_intvl, + enum network_type nw_type, + u8 beacon_ie_len, u8 assoc_req_len, + u8 assoc_resp_len, u8 *assoc_info) +{ + struct ieee80211_channel *chan; + + /* capinfo + listen interval */ + u8 assoc_req_ie_offset = sizeof(u16) + sizeof(u16); + + /* capinfo + status code + associd */ + u8 assoc_resp_ie_offset = sizeof(u16) + sizeof(u16) + sizeof(u16); + + u8 *assoc_req_ie = assoc_info + beacon_ie_len + assoc_req_ie_offset; + u8 *assoc_resp_ie = assoc_info + beacon_ie_len + assoc_req_len + + assoc_resp_ie_offset; + + assoc_req_len -= assoc_req_ie_offset; + assoc_resp_len -= assoc_resp_ie_offset; + + /* + * Store Beacon interval here; DTIM period will be available only once + * a Beacon frame from the AP is seen. + */ + ar->assoc_bss_beacon_int = beacon_intvl; + clear_bit(DTIM_PERIOD_AVAIL, &ar->flag); + + if (nw_type & ADHOC_NETWORK) { + if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: ath6k not in ibss mode\n", __func__); + return; + } + } + + if (nw_type & INFRA_NETWORK) { + if (ar->wdev->iftype != NL80211_IFTYPE_STATION && + ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: ath6k not in station mode\n", __func__); + return; + } + } + + chan = ieee80211_get_channel(ar->wdev->wiphy, (int) channel); + + + if (nw_type & ADHOC_NETWORK) { + cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); + return; + } + + if (ath6kl_add_bss_if_needed(ar, bssid, chan, assoc_info, + beacon_ie_len) < 0) { + ath6kl_err("could not add cfg80211 bss entry for " + "connect/roamed notification\n"); + return; + } + + if (ar->sme_state == SME_CONNECTING) { + /* inform connect result to cfg80211 */ + ar->sme_state = SME_CONNECTED; + cfg80211_connect_result(ar->net_dev, bssid, + assoc_req_ie, assoc_req_len, + assoc_resp_ie, assoc_resp_len, + WLAN_STATUS_SUCCESS, GFP_KERNEL); + } else if (ar->sme_state == SME_CONNECTED) { + /* inform roam event to cfg80211 */ + cfg80211_roamed(ar->net_dev, chan, bssid, + assoc_req_ie, assoc_req_len, + assoc_resp_ie, assoc_resp_len, GFP_KERNEL); + } +} + +static int ath6kl_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason_code) +{ + struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev); + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: reason=%u\n", __func__, + reason_code); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { + ath6kl_err("busy, destroy in progress\n"); + return -EBUSY; + } + + if (down_interruptible(&ar->sem)) { + ath6kl_err("busy, couldn't get access\n"); + return -ERESTARTSYS; + } + + ar->reconnect_flag = 0; + ath6kl_disconnect(ar); + memset(ar->ssid, 0, sizeof(ar->ssid)); + ar->ssid_len = 0; + + if (!test_bit(SKIP_SCAN, &ar->flag)) + memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); + + up(&ar->sem); + + ar->sme_state = SME_DISCONNECTED; + + return 0; +} + +void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, + u8 *bssid, u8 assoc_resp_len, + u8 *assoc_info, u16 proto_reason) +{ + if (ar->scan_req) { + cfg80211_scan_done(ar->scan_req, true); + ar->scan_req = NULL; + } + + if (ar->nw_type & ADHOC_NETWORK) { + if (ar->wdev->iftype != NL80211_IFTYPE_ADHOC) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: ath6k not in ibss mode\n", __func__); + return; + } + memset(bssid, 0, ETH_ALEN); + cfg80211_ibss_joined(ar->net_dev, bssid, GFP_KERNEL); + return; + } + + if (ar->nw_type & INFRA_NETWORK) { + if (ar->wdev->iftype != NL80211_IFTYPE_STATION && + ar->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: ath6k not in station mode\n", __func__); + return; + } + } + + /* + * Send a disconnect command to target when a disconnect event is + * received with reason code other than 3 (DISCONNECT_CMD - disconnect + * request from host) to make the firmware stop trying to connect even + * after giving disconnect event. There will be one more disconnect + * event for this disconnect command with reason code DISCONNECT_CMD + * which will be notified to cfg80211. + */ + + if (reason != DISCONNECT_CMD) { + ath6kl_wmi_disconnect_cmd(ar->wmi); + return; + } + + clear_bit(CONNECT_PEND, &ar->flag); + + if (ar->sme_state == SME_CONNECTING) { + cfg80211_connect_result(ar->net_dev, + bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + } else if (ar->sme_state == SME_CONNECTED) { + cfg80211_disconnected(ar->net_dev, reason, + NULL, 0, GFP_KERNEL); + } + + ar->sme_state = SME_DISCONNECTED; +} + +static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +{ + struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); + s8 n_channels = 0; + u16 *channels = NULL; + int ret = 0; + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (!ar->usr_bss_filter) { + clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); + ret = ath6kl_wmi_bssfilter_cmd( + ar->wmi, + (test_bit(CONNECTED, &ar->flag) ? + ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0); + if (ret) { + ath6kl_err("couldn't set bss filtering\n"); + return ret; + } + } + + if (request->n_ssids && request->ssids[0].ssid_len) { + u8 i; + + if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1)) + request->n_ssids = MAX_PROBED_SSID_INDEX - 1; + + for (i = 0; i < request->n_ssids; i++) + ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1, + SPECIFIC_SSID_FLAG, + request->ssids[i].ssid_len, + request->ssids[i].ssid); + } + + if (request->ie) { + ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_REQ, + request->ie, request->ie_len); + if (ret) { + ath6kl_err("failed to set Probe Request appie for " + "scan"); + return ret; + } + } + + /* + * Scan only the requested channels if the request specifies a set of + * channels. If the list is longer than the target supports, do not + * configure the list and instead, scan all available channels. + */ + if (request->n_channels > 0 && + request->n_channels <= WMI_MAX_CHANNELS) { + u8 i; + + n_channels = request->n_channels; + + channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL); + if (channels == NULL) { + ath6kl_warn("failed to set scan channels, " + "scan all channels"); + n_channels = 0; + } + + for (i = 0; i < n_channels; i++) + channels[i] = request->channels[i]->center_freq; + } + + ret = ath6kl_wmi_startscan_cmd(ar->wmi, WMI_LONG_SCAN, 0, + false, 0, 0, n_channels, channels); + if (ret) + ath6kl_err("wmi_startscan_cmd failed\n"); + else + ar->scan_req = request; + + kfree(channels); + + return ret; +} + +void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status) +{ + int i; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: status %d\n", __func__, status); + + if (!ar->scan_req) + return; + + if ((status == -ECANCELED) || (status == -EBUSY)) { + cfg80211_scan_done(ar->scan_req, true); + goto out; + } + + cfg80211_scan_done(ar->scan_req, false); + + if (ar->scan_req->n_ssids && ar->scan_req->ssids[0].ssid_len) { + for (i = 0; i < ar->scan_req->n_ssids; i++) { + ath6kl_wmi_probedssid_cmd(ar->wmi, i + 1, + DISABLE_SSID_FLAG, + 0, NULL); + } + } + +out: + ar->scan_req = NULL; +} + +static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params) +{ + struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); + struct ath6kl_key *key = NULL; + u8 key_usage; + u8 key_type; + int status = 0; + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: key index %d out of bounds\n", __func__, + key_index); + return -ENOENT; + } + + key = &ar->keys[key_index]; + memset(key, 0, sizeof(struct ath6kl_key)); + + if (pairwise) + key_usage = PAIRWISE_USAGE; + else + key_usage = GROUP_USAGE; + + if (params) { + if (params->key_len > WLAN_MAX_KEY_LEN || + params->seq_len > sizeof(key->seq)) + return -EINVAL; + + key->key_len = params->key_len; + memcpy(key->key, params->key, key->key_len); + key->seq_len = params->seq_len; + memcpy(key->seq, params->seq, key->seq_len); + key->cipher = params->cipher; + } + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + key_type = WEP_CRYPT; + break; + + case WLAN_CIPHER_SUITE_TKIP: + key_type = TKIP_CRYPT; + break; + + case WLAN_CIPHER_SUITE_CCMP: + key_type = AES_CRYPT; + break; + + default: + return -ENOTSUPP; + } + + if (((ar->auth_mode == WPA_PSK_AUTH) + || (ar->auth_mode == WPA2_PSK_AUTH)) + && (key_usage & GROUP_USAGE)) + del_timer(&ar->disconnect_timer); + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: index %d, key_len %d, key_type 0x%x, key_usage 0x%x, seq_len %d\n", + __func__, key_index, key->key_len, key_type, + key_usage, key->seq_len); + + ar->def_txkey_index = key_index; + + if (ar->nw_type == AP_NETWORK && !pairwise && + (key_type == TKIP_CRYPT || key_type == AES_CRYPT) && params) { + ar->ap_mode_bkey.valid = true; + ar->ap_mode_bkey.key_index = key_index; + ar->ap_mode_bkey.key_type = key_type; + ar->ap_mode_bkey.key_len = key->key_len; + memcpy(ar->ap_mode_bkey.key, key->key, key->key_len); + if (!test_bit(CONNECTED, &ar->flag)) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group " + "key configuration until AP mode has been " + "started\n"); + /* + * The key will be set in ath6kl_connect_ap_mode() once + * the connected event is received from the target. + */ + return 0; + } + } + + if (ar->next_mode == AP_NETWORK && key_type == WEP_CRYPT && + !test_bit(CONNECTED, &ar->flag)) { + /* + * Store the key locally so that it can be re-configured after + * the AP mode has properly started + * (ath6kl_install_statioc_wep_keys). + */ + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration " + "until AP mode has been started\n"); + ar->wep_key_list[key_index].key_len = key->key_len; + memcpy(ar->wep_key_list[key_index].key, key->key, key->key_len); + return 0; + } + + status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, + key_type, key_usage, key->key_len, + key->seq, key->key, KEY_OP_INIT_VAL, + (u8 *) mac_addr, SYNC_BOTH_WMIFLAG); + + if (status) + return -EIO; + + return 0; +} + +static int ath6kl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr) +{ + struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: key index %d out of bounds\n", __func__, + key_index); + return -ENOENT; + } + + if (!ar->keys[key_index].key_len) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: index %d is empty\n", __func__, key_index); + return 0; + } + + ar->keys[key_index].key_len = 0; + + return ath6kl_wmi_deletekey_cmd(ar->wmi, key_index); +} + +static int ath6kl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback) (void *cookie, + struct key_params *)) +{ + struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); + struct ath6kl_key *key = NULL; + struct key_params params; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: key index %d out of bounds\n", __func__, + key_index); + return -ENOENT; + } + + key = &ar->keys[key_index]; + memset(¶ms, 0, sizeof(params)); + params.cipher = key->cipher; + params.key_len = key->key_len; + params.seq_len = key->seq_len; + params.seq = key->seq; + params.key = key->key; + + callback(cookie, ¶ms); + + return key->key_len ? 0 : -ENOENT; +} + +static int ath6kl_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool unicast, + bool multicast) +{ + struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(ndev); + struct ath6kl_key *key = NULL; + int status = 0; + u8 key_usage; + enum crypto_type key_type = NONE_CRYPT; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: index %d\n", __func__, key_index); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (key_index < WMI_MIN_KEY_INDEX || key_index > WMI_MAX_KEY_INDEX) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: key index %d out of bounds\n", + __func__, key_index); + return -ENOENT; + } + + if (!ar->keys[key_index].key_len) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: invalid key index %d\n", + __func__, key_index); + return -EINVAL; + } + + ar->def_txkey_index = key_index; + key = &ar->keys[ar->def_txkey_index]; + key_usage = GROUP_USAGE; + if (ar->prwise_crypto == WEP_CRYPT) + key_usage |= TX_USAGE; + if (unicast) + key_type = ar->prwise_crypto; + if (multicast) + key_type = ar->grp_crypto; + + if (ar->next_mode == AP_NETWORK && !test_bit(CONNECTED, &ar->flag)) + return 0; /* Delay until AP mode has been started */ + + status = ath6kl_wmi_addkey_cmd(ar->wmi, ar->def_txkey_index, + key_type, key_usage, + key->key_len, key->seq, key->key, + KEY_OP_INIT_VAL, NULL, + SYNC_BOTH_WMIFLAG); + if (status) + return -EIO; + + return 0; +} + +void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid, + bool ismcast) +{ + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: keyid %d, ismcast %d\n", __func__, keyid, ismcast); + + cfg80211_michael_mic_failure(ar->net_dev, ar->bssid, + (ismcast ? NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE), keyid, NULL, + GFP_KERNEL); +} + +static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); + int ret; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: changed 0x%x\n", __func__, + changed); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + ret = ath6kl_wmi_set_rts_cmd(ar->wmi, wiphy->rts_threshold); + if (ret != 0) { + ath6kl_err("ath6kl_wmi_set_rts_cmd failed\n"); + return -EIO; + } + } + + return 0; +} + +/* + * The type nl80211_tx_power_setting replaces the following + * data type from 2.6.36 onwards +*/ +static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, + int dbm) +{ + struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); + u8 ath6kl_dbm; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x, dbm %d\n", __func__, + type, dbm); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + return 0; + case NL80211_TX_POWER_LIMITED: + ar->tx_pwr = ath6kl_dbm = dbm; + break; + default: + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type 0x%x not supported\n", + __func__, type); + return -EOPNOTSUPP; + } + + ath6kl_wmi_set_tx_pwr_cmd(ar->wmi, ath6kl_dbm); + + return 0; +} + +static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) +{ + struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (test_bit(CONNECTED, &ar->flag)) { + ar->tx_pwr = 0; + + if (ath6kl_wmi_get_tx_pwr_cmd(ar->wmi) != 0) { + ath6kl_err("ath6kl_wmi_get_tx_pwr_cmd failed\n"); + return -EIO; + } + + wait_event_interruptible_timeout(ar->event_wq, ar->tx_pwr != 0, + 5 * HZ); + + if (signal_pending(current)) { + ath6kl_err("target did not respond\n"); + return -EINTR; + } + } + + *dbm = ar->tx_pwr; + return 0; +} + +static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool pmgmt, int timeout) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct wmi_power_mode_cmd mode; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: pmgmt %d, timeout %d\n", + __func__, pmgmt, timeout); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (pmgmt) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: max perf\n", __func__); + mode.pwr_mode = REC_POWER; + } else { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: rec power\n", __func__); + mode.pwr_mode = MAX_PERF_POWER; + } + + if (ath6kl_wmi_powermode_cmd(ar->wmi, mode.pwr_mode) != 0) { + ath6kl_err("wmi_powermode_cmd failed\n"); + return -EIO; + } + + return 0; +} + +static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct ath6kl *ar = ath6kl_priv(ndev); + struct wireless_dev *wdev = ar->wdev; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: type %u\n", __func__, type); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + switch (type) { + case NL80211_IFTYPE_STATION: + ar->next_mode = INFRA_NETWORK; + break; + case NL80211_IFTYPE_ADHOC: + ar->next_mode = ADHOC_NETWORK; + break; + case NL80211_IFTYPE_AP: + ar->next_mode = AP_NETWORK; + break; + case NL80211_IFTYPE_P2P_CLIENT: + ar->next_mode = INFRA_NETWORK; + break; + case NL80211_IFTYPE_P2P_GO: + ar->next_mode = AP_NETWORK; + break; + default: + ath6kl_err("invalid interface type %u\n", type); + return -EOPNOTSUPP; + } + + wdev->iftype = type; + + return 0; +} + +static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *ibss_param) +{ + struct ath6kl *ar = ath6kl_priv(dev); + int status; + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + ar->ssid_len = ibss_param->ssid_len; + memcpy(ar->ssid, ibss_param->ssid, ar->ssid_len); + + if (ibss_param->channel) + ar->ch_hint = ibss_param->channel->center_freq; + + if (ibss_param->channel_fixed) { + /* + * TODO: channel_fixed: The channel should be fixed, do not + * search for IBSSs to join on other channels. Target + * firmware does not support this feature, needs to be + * updated. + */ + return -EOPNOTSUPP; + } + + memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); + if (ibss_param->bssid && !is_broadcast_ether_addr(ibss_param->bssid)) + memcpy(ar->req_bssid, ibss_param->bssid, sizeof(ar->req_bssid)); + + ath6kl_set_wpa_version(ar, 0); + + status = ath6kl_set_auth_type(ar, NL80211_AUTHTYPE_OPEN_SYSTEM); + if (status) + return status; + + if (ibss_param->privacy) { + ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, true); + ath6kl_set_cipher(ar, WLAN_CIPHER_SUITE_WEP40, false); + } else { + ath6kl_set_cipher(ar, 0, true); + ath6kl_set_cipher(ar, 0, false); + } + + ar->nw_type = ar->next_mode; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "%s: connect called with authmode %d dot11 auth %d" + " PW crypto %d PW crypto len %d GRP crypto %d" + " GRP crypto len %d channel hint %u\n", + __func__, + ar->auth_mode, ar->dot11_auth_mode, ar->prwise_crypto, + ar->prwise_crypto_len, ar->grp_crypto, + ar->grp_crypto_len, ar->ch_hint); + + status = ath6kl_wmi_connect_cmd(ar->wmi, ar->nw_type, + ar->dot11_auth_mode, ar->auth_mode, + ar->prwise_crypto, + ar->prwise_crypto_len, + ar->grp_crypto, ar->grp_crypto_len, + ar->ssid_len, ar->ssid, + ar->req_bssid, ar->ch_hint, + ar->connect_ctrl_flags); + set_bit(CONNECT_PEND, &ar->flag); + + return 0; +} + +static int ath6kl_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev) +{ + struct ath6kl *ar = (struct ath6kl *)ath6kl_priv(dev); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + ath6kl_disconnect(ar); + memset(ar->ssid, 0, sizeof(ar->ssid)); + ar->ssid_len = 0; + + return 0; +} + +static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, +}; + +static bool is_rate_legacy(s32 rate) +{ + static const s32 legacy[] = { 1000, 2000, 5500, 11000, + 6000, 9000, 12000, 18000, 24000, + 36000, 48000, 54000 + }; + u8 i; + + for (i = 0; i < ARRAY_SIZE(legacy); i++) + if (rate == legacy[i]) + return true; + + return false; +} + +static bool is_rate_ht20(s32 rate, u8 *mcs, bool *sgi) +{ + static const s32 ht20[] = { 6500, 13000, 19500, 26000, 39000, + 52000, 58500, 65000, 72200 + }; + u8 i; + + for (i = 0; i < ARRAY_SIZE(ht20); i++) { + if (rate == ht20[i]) { + if (i == ARRAY_SIZE(ht20) - 1) + /* last rate uses sgi */ + *sgi = true; + else + *sgi = false; + + *mcs = i; + return true; + } + } + return false; +} + +static bool is_rate_ht40(s32 rate, u8 *mcs, bool *sgi) +{ + static const s32 ht40[] = { 13500, 27000, 40500, 54000, + 81000, 108000, 121500, 135000, + 150000 + }; + u8 i; + + for (i = 0; i < ARRAY_SIZE(ht40); i++) { + if (rate == ht40[i]) { + if (i == ARRAY_SIZE(ht40) - 1) + /* last rate uses sgi */ + *sgi = true; + else + *sgi = false; + + *mcs = i; + return true; + } + } + + return false; +} + +static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_info *sinfo) +{ + struct ath6kl *ar = ath6kl_priv(dev); + long left; + bool sgi; + s32 rate; + int ret; + u8 mcs; + + if (memcmp(mac, ar->bssid, ETH_ALEN) != 0) + return -ENOENT; + + if (down_interruptible(&ar->sem)) + return -EBUSY; + + set_bit(STATS_UPDATE_PEND, &ar->flag); + + ret = ath6kl_wmi_get_stats_cmd(ar->wmi); + + if (ret != 0) { + up(&ar->sem); + return -EIO; + } + + left = wait_event_interruptible_timeout(ar->event_wq, + !test_bit(STATS_UPDATE_PEND, + &ar->flag), + WMI_TIMEOUT); + + up(&ar->sem); + + if (left == 0) + return -ETIMEDOUT; + else if (left < 0) + return left; + + if (ar->target_stats.rx_byte) { + sinfo->rx_bytes = ar->target_stats.rx_byte; + sinfo->filled |= STATION_INFO_RX_BYTES; + sinfo->rx_packets = ar->target_stats.rx_pkt; + sinfo->filled |= STATION_INFO_RX_PACKETS; + } + + if (ar->target_stats.tx_byte) { + sinfo->tx_bytes = ar->target_stats.tx_byte; + sinfo->filled |= STATION_INFO_TX_BYTES; + sinfo->tx_packets = ar->target_stats.tx_pkt; + sinfo->filled |= STATION_INFO_TX_PACKETS; + } + + sinfo->signal = ar->target_stats.cs_rssi; + sinfo->filled |= STATION_INFO_SIGNAL; + + rate = ar->target_stats.tx_ucast_rate; + + if (is_rate_legacy(rate)) { + sinfo->txrate.legacy = rate / 100; + } else if (is_rate_ht20(rate, &mcs, &sgi)) { + if (sgi) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + sinfo->txrate.mcs = mcs - 1; + } else { + sinfo->txrate.mcs = mcs; + } + + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + } else if (is_rate_ht40(rate, &mcs, &sgi)) { + if (sgi) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + sinfo->txrate.mcs = mcs - 1; + } else { + sinfo->txrate.mcs = mcs; + } + + sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + } else { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "invalid rate from stats: %d\n", rate); + ath6kl_debug_war(ar, ATH6KL_WAR_INVALID_RATE); + return 0; + } + + sinfo->filled |= STATION_INFO_TX_BITRATE; + + if (test_bit(CONNECTED, &ar->flag) && + test_bit(DTIM_PERIOD_AVAIL, &ar->flag) && + ar->nw_type == INFRA_NETWORK) { + sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->bss_param.flags = 0; + sinfo->bss_param.dtim_period = ar->assoc_bss_dtim_period; + sinfo->bss_param.beacon_interval = ar->assoc_bss_beacon_int; + } + + return 0; +} + +static int ath6kl_set_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + struct ath6kl *ar = ath6kl_priv(netdev); + return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid, + pmksa->pmkid, true); +} + +static int ath6kl_del_pmksa(struct wiphy *wiphy, struct net_device *netdev, + struct cfg80211_pmksa *pmksa) +{ + struct ath6kl *ar = ath6kl_priv(netdev); + return ath6kl_wmi_setpmkid_cmd(ar->wmi, pmksa->bssid, + pmksa->pmkid, false); +} + +static int ath6kl_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) +{ + struct ath6kl *ar = ath6kl_priv(netdev); + if (test_bit(CONNECTED, &ar->flag)) + return ath6kl_wmi_setpmkid_cmd(ar->wmi, ar->bssid, NULL, false); + return 0; +} + +#ifdef CONFIG_PM +static int ar6k_cfg80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + struct ath6kl *ar = wiphy_priv(wiphy); + + return ath6kl_hif_suspend(ar); +} +#endif + +static int ath6kl_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: center_freq=%u hw_value=%u\n", + __func__, chan->center_freq, chan->hw_value); + ar->next_chan = chan->center_freq; + + return 0; +} + +static bool ath6kl_is_p2p_ie(const u8 *pos) +{ + return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && + pos[2] == 0x50 && pos[3] == 0x6f && + pos[4] == 0x9a && pos[5] == 0x09; +} + +static int ath6kl_set_ap_probe_resp_ies(struct ath6kl *ar, const u8 *ies, + size_t ies_len) +{ + const u8 *pos; + u8 *buf = NULL; + size_t len = 0; + int ret; + + /* + * Filter out P2P IE(s) since they will be included depending on + * the Probe Request frame in ath6kl_send_go_probe_resp(). + */ + + if (ies && ies_len) { + buf = kmalloc(ies_len, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + pos = ies; + while (pos + 1 < ies + ies_len) { + if (pos + 2 + pos[1] > ies + ies_len) + break; + if (!ath6kl_is_p2p_ie(pos)) { + memcpy(buf + len, pos, 2 + pos[1]); + len += 2 + pos[1]; + } + pos += 2 + pos[1]; + } + } + + ret = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_PROBE_RESP, + buf, len); + kfree(buf); + return ret; +} + +static int ath6kl_ap_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info, bool add) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ieee80211_mgmt *mgmt; + u8 *ies; + int ies_len; + struct wmi_connect_cmd p; + int res; + int i; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: add=%d\n", __func__, add); + + if (!ath6kl_cfg80211_ready(ar)) + return -EIO; + + if (ar->next_mode != AP_NETWORK) + return -EOPNOTSUPP; + + if (info->beacon_ies) { + res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_BEACON, + info->beacon_ies, + info->beacon_ies_len); + if (res) + return res; + } + if (info->proberesp_ies) { + res = ath6kl_set_ap_probe_resp_ies(ar, info->proberesp_ies, + info->proberesp_ies_len); + if (res) + return res; + } + if (info->assocresp_ies) { + res = ath6kl_wmi_set_appie_cmd(ar->wmi, WMI_FRAME_ASSOC_RESP, + info->assocresp_ies, + info->assocresp_ies_len); + if (res) + return res; + } + + if (!add) + return 0; + + ar->ap_mode_bkey.valid = false; + + /* TODO: + * info->interval + * info->dtim_period + */ + + if (info->head == NULL) + return -EINVAL; + mgmt = (struct ieee80211_mgmt *) info->head; + ies = mgmt->u.beacon.variable; + if (ies > info->head + info->head_len) + return -EINVAL; + ies_len = info->head + info->head_len - ies; + + if (info->ssid == NULL) + return -EINVAL; + memcpy(ar->ssid, info->ssid, info->ssid_len); + ar->ssid_len = info->ssid_len; + if (info->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE) + return -EOPNOTSUPP; /* TODO */ + + ar->dot11_auth_mode = OPEN_AUTH; + + memset(&p, 0, sizeof(p)); + + for (i = 0; i < info->crypto.n_akm_suites; i++) { + switch (info->crypto.akm_suites[i]) { + case WLAN_AKM_SUITE_8021X: + if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1) + p.auth_mode |= WPA_AUTH; + if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2) + p.auth_mode |= WPA2_AUTH; + break; + case WLAN_AKM_SUITE_PSK: + if (info->crypto.wpa_versions & NL80211_WPA_VERSION_1) + p.auth_mode |= WPA_PSK_AUTH; + if (info->crypto.wpa_versions & NL80211_WPA_VERSION_2) + p.auth_mode |= WPA2_PSK_AUTH; + break; + } + } + if (p.auth_mode == 0) + p.auth_mode = NONE_AUTH; + ar->auth_mode = p.auth_mode; + + for (i = 0; i < info->crypto.n_ciphers_pairwise; i++) { + switch (info->crypto.ciphers_pairwise[i]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + p.prwise_crypto_type |= WEP_CRYPT; + break; + case WLAN_CIPHER_SUITE_TKIP: + p.prwise_crypto_type |= TKIP_CRYPT; + break; + case WLAN_CIPHER_SUITE_CCMP: + p.prwise_crypto_type |= AES_CRYPT; + break; + } + } + if (p.prwise_crypto_type == 0) { + p.prwise_crypto_type = NONE_CRYPT; + ath6kl_set_cipher(ar, 0, true); + } else if (info->crypto.n_ciphers_pairwise == 1) + ath6kl_set_cipher(ar, info->crypto.ciphers_pairwise[0], true); + + switch (info->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + p.grp_crypto_type = WEP_CRYPT; + break; + case WLAN_CIPHER_SUITE_TKIP: + p.grp_crypto_type = TKIP_CRYPT; + break; + case WLAN_CIPHER_SUITE_CCMP: + p.grp_crypto_type = AES_CRYPT; + break; + default: + p.grp_crypto_type = NONE_CRYPT; + break; + } + ath6kl_set_cipher(ar, info->crypto.cipher_group, false); + + p.nw_type = AP_NETWORK; + ar->nw_type = ar->next_mode; + + p.ssid_len = ar->ssid_len; + memcpy(p.ssid, ar->ssid, ar->ssid_len); + p.dot11_auth_mode = ar->dot11_auth_mode; + p.ch = cpu_to_le16(ar->next_chan); + + res = ath6kl_wmi_ap_profile_commit(ar->wmi, &p); + if (res < 0) + return res; + + return 0; +} + +static int ath6kl_add_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + return ath6kl_ap_beacon(wiphy, dev, info, true); +} + +static int ath6kl_set_beacon(struct wiphy *wiphy, struct net_device *dev, + struct beacon_parameters *info) +{ + return ath6kl_ap_beacon(wiphy, dev, info, false); +} + +static int ath6kl_del_beacon(struct wiphy *wiphy, struct net_device *dev) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + if (ar->nw_type != AP_NETWORK) + return -EOPNOTSUPP; + if (!test_bit(CONNECTED, &ar->flag)) + return -ENOTCONN; + + ath6kl_wmi_disconnect_cmd(ar->wmi); + clear_bit(CONNECTED, &ar->flag); + + return 0; +} + +static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, + u8 *mac, struct station_parameters *params) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + if (ar->nw_type != AP_NETWORK) + return -EOPNOTSUPP; + + /* Use this only for authorizing/unauthorizing a station */ + if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) + return -EOPNOTSUPP; + + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) + return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_AUTHORIZE, + mac, 0); + return ath6kl_wmi_ap_set_mlme(ar->wmi, WMI_AP_MLME_UNAUTHORIZE, mac, + 0); +} + +static int ath6kl_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, + u64 *cookie) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + /* TODO: if already pending or ongoing remain-on-channel, + * return -EBUSY */ + *cookie = 1; /* only a single pending request is supported */ + + return ath6kl_wmi_remain_on_chnl_cmd(ar->wmi, chan->center_freq, + duration); +} + +static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + u64 cookie) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + if (cookie != 1) + return -ENOENT; + + return ath6kl_wmi_cancel_remain_on_chnl_cmd(ar->wmi); +} + +static int ath6kl_send_go_probe_resp(struct ath6kl *ar, const u8 *buf, + size_t len, unsigned int freq) +{ + const u8 *pos; + u8 *p2p; + int p2p_len; + int ret; + const struct ieee80211_mgmt *mgmt; + + mgmt = (const struct ieee80211_mgmt *) buf; + + /* Include P2P IE(s) from the frame generated in user space. */ + + p2p = kmalloc(len, GFP_KERNEL); + if (p2p == NULL) + return -ENOMEM; + p2p_len = 0; + + pos = mgmt->u.probe_resp.variable; + while (pos + 1 < buf + len) { + if (pos + 2 + pos[1] > buf + len) + break; + if (ath6kl_is_p2p_ie(pos)) { + memcpy(p2p + p2p_len, pos, 2 + pos[1]); + p2p_len += 2 + pos[1]; + } + pos += 2 + pos[1]; + } + + ret = ath6kl_wmi_send_probe_response_cmd(ar->wmi, freq, mgmt->da, + p2p, p2p_len); + kfree(p2p); + return ret; +} + +static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 *buf, size_t len, bool no_cck, u64 *cookie) +{ + struct ath6kl *ar = ath6kl_priv(dev); + u32 id; + const struct ieee80211_mgmt *mgmt; + + mgmt = (const struct ieee80211_mgmt *) buf; + if (buf + len >= mgmt->u.probe_resp.variable && + ar->nw_type == AP_NETWORK && test_bit(CONNECTED, &ar->flag) && + ieee80211_is_probe_resp(mgmt->frame_control)) { + /* + * Send Probe Response frame in AP mode using a separate WMI + * command to allow the target to fill in the generic IEs. + */ + *cookie = 0; /* TX status not supported */ + return ath6kl_send_go_probe_resp(ar, buf, len, + chan->center_freq); + } + + id = ar->send_action_id++; + if (id == 0) { + /* + * 0 is a reserved value in the WMI command and shall not be + * used for the command. + */ + id = ar->send_action_id++; + } + + *cookie = id; + return ath6kl_wmi_send_action_cmd(ar->wmi, id, chan->center_freq, wait, + buf, len); +} + +static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, + struct net_device *dev, + u16 frame_type, bool reg) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n", + __func__, frame_type, reg); + if (frame_type == IEEE80211_STYPE_PROBE_REQ) { + /* + * Note: This notification callback is not allowed to sleep, so + * we cannot send WMI_PROBE_REQ_REPORT_CMD here. Instead, we + * hardcode target to report Probe Request frames all the time. + */ + ar->probe_req_report = reg; + } +} + +static const struct ieee80211_txrx_stypes +ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) + }, +}; + +static struct cfg80211_ops ath6kl_cfg80211_ops = { + .change_virtual_intf = ath6kl_cfg80211_change_iface, + .scan = ath6kl_cfg80211_scan, + .connect = ath6kl_cfg80211_connect, + .disconnect = ath6kl_cfg80211_disconnect, + .add_key = ath6kl_cfg80211_add_key, + .get_key = ath6kl_cfg80211_get_key, + .del_key = ath6kl_cfg80211_del_key, + .set_default_key = ath6kl_cfg80211_set_default_key, + .set_wiphy_params = ath6kl_cfg80211_set_wiphy_params, + .set_tx_power = ath6kl_cfg80211_set_txpower, + .get_tx_power = ath6kl_cfg80211_get_txpower, + .set_power_mgmt = ath6kl_cfg80211_set_power_mgmt, + .join_ibss = ath6kl_cfg80211_join_ibss, + .leave_ibss = ath6kl_cfg80211_leave_ibss, + .get_station = ath6kl_get_station, + .set_pmksa = ath6kl_set_pmksa, + .del_pmksa = ath6kl_del_pmksa, + .flush_pmksa = ath6kl_flush_pmksa, + CFG80211_TESTMODE_CMD(ath6kl_tm_cmd) +#ifdef CONFIG_PM + .suspend = ar6k_cfg80211_suspend, +#endif + .set_channel = ath6kl_set_channel, + .add_beacon = ath6kl_add_beacon, + .set_beacon = ath6kl_set_beacon, + .del_beacon = ath6kl_del_beacon, + .change_station = ath6kl_change_station, + .remain_on_channel = ath6kl_remain_on_channel, + .cancel_remain_on_channel = ath6kl_cancel_remain_on_channel, + .mgmt_tx = ath6kl_mgmt_tx, + .mgmt_frame_register = ath6kl_mgmt_frame_register, +}; + +struct wireless_dev *ath6kl_cfg80211_init(struct device *dev) +{ + int ret = 0; + struct wireless_dev *wdev; + struct ath6kl *ar; + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + ath6kl_err("couldn't allocate wireless device\n"); + return NULL; + } + + /* create a new wiphy for use with cfg80211 */ + wdev->wiphy = wiphy_new(&ath6kl_cfg80211_ops, sizeof(struct ath6kl)); + if (!wdev->wiphy) { + ath6kl_err("couldn't allocate wiphy device\n"); + kfree(wdev); + return NULL; + } + + ar = wiphy_priv(wdev->wiphy); + ar->p2p = !!ath6kl_p2p; + + wdev->wiphy->mgmt_stypes = ath6kl_mgmt_stypes; + + wdev->wiphy->max_remain_on_channel_duration = 5000; + + /* set device pointer for wiphy */ + set_wiphy_dev(wdev->wiphy, dev); + + wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); + if (ar->p2p) { + wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT); + } + /* max num of ssids that can be probed during scanning */ + wdev->wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; + wdev->wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + wdev->wiphy->cipher_suites = cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + + ret = wiphy_register(wdev->wiphy); + if (ret < 0) { + ath6kl_err("couldn't register wiphy device\n"); + wiphy_free(wdev->wiphy); + kfree(wdev); + return NULL; + } + + return wdev; +} + +void ath6kl_cfg80211_deinit(struct ath6kl *ar) +{ + struct wireless_dev *wdev = ar->wdev; + + if (ar->scan_req) { + cfg80211_scan_done(ar->scan_req, true); + ar->scan_req = NULL; + } + + if (!wdev) + return; + + wiphy_unregister(wdev->wiphy); + wiphy_free(wdev->wiphy); + kfree(wdev); +} diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h new file mode 100644 index 000000000000..a84adc249c61 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ATH6KL_CFG80211_H +#define ATH6KL_CFG80211_H + +struct wireless_dev *ath6kl_cfg80211_init(struct device *dev); +void ath6kl_cfg80211_deinit(struct ath6kl *ar); + +void ath6kl_cfg80211_scan_complete_event(struct ath6kl *ar, int status); + +void ath6kl_cfg80211_connect_event(struct ath6kl *ar, u16 channel, + u8 *bssid, u16 listen_intvl, + u16 beacon_intvl, + enum network_type nw_type, + u8 beacon_ie_len, u8 assoc_req_len, + u8 assoc_resp_len, u8 *assoc_info); + +void ath6kl_cfg80211_disconnect_event(struct ath6kl *ar, u8 reason, + u8 *bssid, u8 assoc_resp_len, + u8 *assoc_info, u16 proto_reason); + +void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl *ar, u8 keyid, + bool ismcast); + +#endif /* ATH6KL_CFG80211_H */ diff --git a/drivers/net/wireless/ath/ath6kl/common.h b/drivers/net/wireless/ath/ath6kl/common.h new file mode 100644 index 000000000000..b92f0e5d2336 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/common.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include <linux/netdevice.h> + +#define ATH6KL_MAX_IE 256 + +extern int ath6kl_printk(const char *level, const char *fmt, ...); + +#define A_CACHE_LINE_PAD 128 + +/* + * Reflects the version of binary interface exposed by ATH6KL target + * firmware. Needs to be incremented by 1 for any change in the firmware + * that requires upgrade of the driver on the host side for the change to + * work correctly + */ +#define ATH6KL_ABI_VERSION 1 + +#define SIGNAL_QUALITY_METRICS_NUM_MAX 2 + +enum { + SIGNAL_QUALITY_METRICS_SNR = 0, + SIGNAL_QUALITY_METRICS_RSSI, + SIGNAL_QUALITY_METRICS_ALL, +}; + +/* + * Data Path + */ + +#define WMI_MAX_TX_DATA_FRAME_LENGTH \ + (1500 + sizeof(struct wmi_data_hdr) + \ + sizeof(struct ethhdr) + \ + sizeof(struct ath6kl_llc_snap_hdr)) + +/* An AMSDU frame */ /* The MAX AMSDU length of AR6003 is 3839 */ +#define WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH \ + (3840 + sizeof(struct wmi_data_hdr) + \ + sizeof(struct ethhdr) + \ + sizeof(struct ath6kl_llc_snap_hdr)) + +#define EPPING_ALIGNMENT_PAD \ + (((sizeof(struct htc_frame_hdr) + 3) & (~0x3)) \ + - sizeof(struct htc_frame_hdr)) + +struct ath6kl_llc_snap_hdr { + u8 dsap; + u8 ssap; + u8 cntl; + u8 org_code[3]; + __be16 eth_type; +} __packed; + +enum crypto_type { + NONE_CRYPT = 0x01, + WEP_CRYPT = 0x02, + TKIP_CRYPT = 0x04, + AES_CRYPT = 0x08, +}; + +struct htc_endpoint_credit_dist; +struct ath6kl; +enum htc_credit_dist_reason; +struct htc_credit_state_info; + +int ath6k_setup_credit_dist(void *htc_handle, + struct htc_credit_state_info *cred_info); +void ath6k_credit_distribute(struct htc_credit_state_info *cred_inf, + struct list_head *epdist_list, + enum htc_credit_dist_reason reason); +void ath6k_credit_init(struct htc_credit_state_info *cred_inf, + struct list_head *ep_list, + int tot_credits); +void ath6k_seek_credits(struct htc_credit_state_info *cred_inf, + struct htc_endpoint_credit_dist *ep_dist); +struct ath6kl *ath6kl_core_alloc(struct device *sdev); +int ath6kl_core_init(struct ath6kl *ar); +int ath6kl_unavail_ev(struct ath6kl *ar); +struct sk_buff *ath6kl_buf_alloc(int size); +#endif /* COMMON_H */ diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h new file mode 100644 index 000000000000..6d8a4845baaf --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -0,0 +1,637 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CORE_H +#define CORE_H + +#include <linux/etherdevice.h> +#include <linux/rtnetlink.h> +#include <linux/firmware.h> +#include <linux/sched.h> +#include <linux/circ_buf.h> +#include <net/cfg80211.h> +#include "htc.h" +#include "wmi.h" +#include "bmi.h" +#include "target.h" + +#define MAX_ATH6KL 1 +#define ATH6KL_MAX_RX_BUFFERS 16 +#define ATH6KL_BUFFER_SIZE 1664 +#define ATH6KL_MAX_AMSDU_RX_BUFFERS 4 +#define ATH6KL_AMSDU_REFILL_THRESHOLD 3 +#define ATH6KL_AMSDU_BUFFER_SIZE (WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH + 128) +#define MAX_MSDU_SUBFRAME_PAYLOAD_LEN 1508 +#define MIN_MSDU_SUBFRAME_PAYLOAD_LEN 46 + +#define USER_SAVEDKEYS_STAT_INIT 0 +#define USER_SAVEDKEYS_STAT_RUN 1 + +#define ATH6KL_TX_TIMEOUT 10 +#define ATH6KL_MAX_ENDPOINTS 4 +#define MAX_NODE_NUM 15 + +/* Extra bytes for htc header alignment */ +#define ATH6KL_HTC_ALIGN_BYTES 3 + +/* MAX_HI_COOKIE_NUM are reserved for high priority traffic */ +#define MAX_DEF_COOKIE_NUM 180 +#define MAX_HI_COOKIE_NUM 18 /* 10% of MAX_COOKIE_NUM */ +#define MAX_COOKIE_NUM (MAX_DEF_COOKIE_NUM + MAX_HI_COOKIE_NUM) + +#define MAX_DEFAULT_SEND_QUEUE_DEPTH (MAX_DEF_COOKIE_NUM / WMM_NUM_AC) + +#define DISCON_TIMER_INTVAL 10000 /* in msec */ +#define A_DEFAULT_LISTEN_INTERVAL 100 +#define A_MAX_WOW_LISTEN_INTERVAL 1000 + +/* includes also the null byte */ +#define ATH6KL_FIRMWARE_MAGIC "QCA-ATH6KL" + +enum ath6kl_fw_ie_type { + ATH6KL_FW_IE_FW_VERSION = 0, + ATH6KL_FW_IE_TIMESTAMP = 1, + ATH6KL_FW_IE_OTP_IMAGE = 2, + ATH6KL_FW_IE_FW_IMAGE = 3, + ATH6KL_FW_IE_PATCH_IMAGE = 4, + ATH6KL_FW_IE_RESERVED_RAM_SIZE = 5, + ATH6KL_FW_IE_CAPABILITIES = 6, + ATH6KL_FW_IE_PATCH_ADDR = 7, +}; + +enum ath6kl_fw_capability { + ATH6KL_FW_CAPABILITY_HOST_P2P = 0, + + /* this needs to be last */ + ATH6KL_FW_CAPABILITY_MAX, +}; + +#define ATH6KL_CAPABILITY_LEN (ALIGN(ATH6KL_FW_CAPABILITY_MAX, 32) / 32) + +struct ath6kl_fw_ie { + __le32 id; + __le32 len; + u8 data[0]; +}; + +/* AR6003 1.0 definitions */ +#define AR6003_REV1_VERSION 0x300002ba + +/* AR6003 2.0 definitions */ +#define AR6003_REV2_VERSION 0x30000384 +#define AR6003_REV2_PATCH_DOWNLOAD_ADDRESS 0x57e910 +#define AR6003_REV2_OTP_FILE "ath6k/AR6003/hw2.0/otp.bin.z77" +#define AR6003_REV2_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athwlan.bin.z77" +#define AR6003_REV2_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.0/athtcmd_ram.bin" +#define AR6003_REV2_PATCH_FILE "ath6k/AR6003/hw2.0/data.patch.bin" +#define AR6003_REV2_FIRMWARE_2_FILE "ath6k/AR6003/hw2.0/fw-2.bin" +#define AR6003_REV2_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" +#define AR6003_REV2_DEFAULT_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.SD31.bin" + +/* AR6003 3.0 definitions */ +#define AR6003_REV3_VERSION 0x30000582 +#define AR6003_REV3_OTP_FILE "ath6k/AR6003/hw2.1.1/otp.bin" +#define AR6003_REV3_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athwlan.bin" +#define AR6003_REV3_TCMD_FIRMWARE_FILE "ath6k/AR6003/hw2.1.1/athtcmd_ram.bin" +#define AR6003_REV3_PATCH_FILE "ath6k/AR6003/hw2.1.1/data.patch.bin" +#define AR6003_REV3_FIRMWARE_2_FILE "ath6k/AR6003/hw2.1.1/fw-2.bin" +#define AR6003_REV3_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" +#define AR6003_REV3_DEFAULT_BOARD_DATA_FILE \ + "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" + +/* AR6004 1.0 definitions */ +#define AR6004_REV1_VERSION 0x30000623 +#define AR6004_REV1_FIRMWARE_FILE "ath6k/AR6004/hw6.1/fw.ram.bin" +#define AR6004_REV1_FIRMWARE_2_FILE "ath6k/AR6004/hw6.1/fw-2.bin" +#define AR6004_REV1_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.bin" +#define AR6004_REV1_DEFAULT_BOARD_DATA_FILE "ath6k/AR6004/hw6.1/bdata.DB132.bin" +#define AR6004_REV1_EPPING_FIRMWARE_FILE "ath6k/AR6004/hw6.1/endpointping.bin" + +/* Per STA data, used in AP mode */ +#define STA_PS_AWAKE BIT(0) +#define STA_PS_SLEEP BIT(1) +#define STA_PS_POLLED BIT(2) + +/* HTC TX packet tagging definitions */ +#define ATH6KL_CONTROL_PKT_TAG HTC_TX_PACKET_TAG_USER_DEFINED +#define ATH6KL_DATA_PKT_TAG (ATH6KL_CONTROL_PKT_TAG + 1) + +#define AR6003_CUST_DATA_SIZE 16 + +#define AGGR_WIN_IDX(x, y) ((x) % (y)) +#define AGGR_INCR_IDX(x, y) AGGR_WIN_IDX(((x) + 1), (y)) +#define AGGR_DCRM_IDX(x, y) AGGR_WIN_IDX(((x) - 1), (y)) +#define ATH6KL_MAX_SEQ_NO 0xFFF +#define ATH6KL_NEXT_SEQ_NO(x) (((x) + 1) & ATH6KL_MAX_SEQ_NO) + +#define NUM_OF_TIDS 8 +#define AGGR_SZ_DEFAULT 8 + +#define AGGR_WIN_SZ_MIN 2 +#define AGGR_WIN_SZ_MAX 8 + +#define TID_WINDOW_SZ(_x) ((_x) << 1) + +#define AGGR_NUM_OF_FREE_NETBUFS 16 + +#define AGGR_RX_TIMEOUT 400 /* in ms */ + +#define WMI_TIMEOUT (2 * HZ) + +#define MBOX_YIELD_LIMIT 99 + +/* configuration lags */ +/* + * ATH6KL_CONF_IGNORE_ERP_BARKER: Ignore the barker premable in + * ERP IE of beacon to determine the short premable support when + * sending (Re)Assoc req. + * ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN: Don't send the power + * module state transition failure events which happen during + * scan, to the host. + */ +#define ATH6KL_CONF_IGNORE_ERP_BARKER BIT(0) +#define ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN BIT(1) +#define ATH6KL_CONF_ENABLE_11N BIT(2) +#define ATH6KL_CONF_ENABLE_TX_BURST BIT(3) + +enum wlan_low_pwr_state { + WLAN_POWER_STATE_ON, + WLAN_POWER_STATE_CUT_PWR, + WLAN_POWER_STATE_DEEP_SLEEP, + WLAN_POWER_STATE_WOW +}; + +enum sme_state { + SME_DISCONNECTED, + SME_CONNECTING, + SME_CONNECTED +}; + +struct skb_hold_q { + struct sk_buff *skb; + bool is_amsdu; + u16 seq_no; +}; + +struct rxtid { + bool aggr; + bool progress; + bool timer_mon; + u16 win_sz; + u16 seq_next; + u32 hold_q_sz; + struct skb_hold_q *hold_q; + struct sk_buff_head q; + spinlock_t lock; +}; + +struct rxtid_stats { + u32 num_into_aggr; + u32 num_dups; + u32 num_oow; + u32 num_mpdu; + u32 num_amsdu; + u32 num_delivered; + u32 num_timeouts; + u32 num_hole; + u32 num_bar; +}; + +struct aggr_info { + u8 aggr_sz; + u8 timer_scheduled; + struct timer_list timer; + struct net_device *dev; + struct rxtid rx_tid[NUM_OF_TIDS]; + struct sk_buff_head free_q; + struct rxtid_stats stat[NUM_OF_TIDS]; +}; + +struct ath6kl_wep_key { + u8 key_index; + u8 key_len; + u8 key[64]; +}; + +#define ATH6KL_KEY_SEQ_LEN 8 + +struct ath6kl_key { + u8 key[WLAN_MAX_KEY_LEN]; + u8 key_len; + u8 seq[ATH6KL_KEY_SEQ_LEN]; + u8 seq_len; + u32 cipher; +}; + +struct ath6kl_node_mapping { + u8 mac_addr[ETH_ALEN]; + u8 ep_id; + u8 tx_pend; +}; + +struct ath6kl_cookie { + struct sk_buff *skb; + u32 map_no; + struct htc_packet htc_pkt; + struct ath6kl_cookie *arc_list_next; +}; + +struct ath6kl_sta { + u16 sta_flags; + u8 mac[ETH_ALEN]; + u8 aid; + u8 keymgmt; + u8 ucipher; + u8 auth; + u8 wpa_ie[ATH6KL_MAX_IE]; + struct sk_buff_head psq; + spinlock_t psq_lock; +}; + +struct ath6kl_version { + u32 target_ver; + u32 wlan_ver; + u32 abi_ver; +}; + +struct ath6kl_bmi { + u32 cmd_credits; + bool done_sent; + u8 *cmd_buf; +}; + +struct target_stats { + u64 tx_pkt; + u64 tx_byte; + u64 tx_ucast_pkt; + u64 tx_ucast_byte; + u64 tx_mcast_pkt; + u64 tx_mcast_byte; + u64 tx_bcast_pkt; + u64 tx_bcast_byte; + u64 tx_rts_success_cnt; + u64 tx_pkt_per_ac[4]; + + u64 tx_err; + u64 tx_fail_cnt; + u64 tx_retry_cnt; + u64 tx_mult_retry_cnt; + u64 tx_rts_fail_cnt; + + u64 rx_pkt; + u64 rx_byte; + u64 rx_ucast_pkt; + u64 rx_ucast_byte; + u64 rx_mcast_pkt; + u64 rx_mcast_byte; + u64 rx_bcast_pkt; + u64 rx_bcast_byte; + u64 rx_frgment_pkt; + + u64 rx_err; + u64 rx_crc_err; + u64 rx_key_cache_miss; + u64 rx_decrypt_err; + u64 rx_dupl_frame; + + u64 tkip_local_mic_fail; + u64 tkip_cnter_measures_invoked; + u64 tkip_replays; + u64 tkip_fmt_err; + u64 ccmp_fmt_err; + u64 ccmp_replays; + + u64 pwr_save_fail_cnt; + + u64 cs_bmiss_cnt; + u64 cs_low_rssi_cnt; + u64 cs_connect_cnt; + u64 cs_discon_cnt; + + s32 tx_ucast_rate; + s32 rx_ucast_rate; + + u32 lq_val; + + u32 wow_pkt_dropped; + u16 wow_evt_discarded; + + s16 noise_floor_calib; + s16 cs_rssi; + s16 cs_ave_beacon_rssi; + u8 cs_ave_beacon_snr; + u8 cs_last_roam_msec; + u8 cs_snr; + + u8 wow_host_pkt_wakeups; + u8 wow_host_evt_wakeups; + + u32 arp_received; + u32 arp_matched; + u32 arp_replied; +}; + +struct ath6kl_mbox_info { + u32 htc_addr; + u32 htc_ext_addr; + u32 htc_ext_sz; + + u32 block_size; + + u32 gmbox_addr; + + u32 gmbox_sz; +}; + +/* + * 802.11i defines an extended IV for use with non-WEP ciphers. + * When the EXTIV bit is set in the key id byte an additional + * 4 bytes immediately follow the IV for TKIP. For CCMP the + * EXTIV bit is likewise set but the 8 bytes represent the + * CCMP header rather than IV+extended-IV. + */ + +#define ATH6KL_KEYBUF_SIZE 16 +#define ATH6KL_MICBUF_SIZE (8+8) /* space for both tx and rx */ + +#define ATH6KL_KEY_XMIT 0x01 +#define ATH6KL_KEY_RECV 0x02 +#define ATH6KL_KEY_DEFAULT 0x80 /* default xmit key */ + +/* Initial group key for AP mode */ +struct ath6kl_req_key { + bool valid; + u8 key_index; + int key_type; + u8 key[WLAN_MAX_KEY_LEN]; + u8 key_len; +}; + +/* Flag info */ +#define WMI_ENABLED 0 +#define WMI_READY 1 +#define CONNECTED 2 +#define STATS_UPDATE_PEND 3 +#define CONNECT_PEND 4 +#define WMM_ENABLED 5 +#define NETQ_STOPPED 6 +#define WMI_CTRL_EP_FULL 7 +#define DTIM_EXPIRED 8 +#define DESTROY_IN_PROGRESS 9 +#define NETDEV_REGISTERED 10 +#define SKIP_SCAN 11 +#define WLAN_ENABLED 12 +#define TESTMODE 13 +#define CLEAR_BSSFILTER_ON_BEACON 14 +#define DTIM_PERIOD_AVAIL 15 + +struct ath6kl { + struct device *dev; + struct net_device *net_dev; + struct ath6kl_bmi bmi; + const struct ath6kl_hif_ops *hif_ops; + struct wmi *wmi; + int tx_pending[ENDPOINT_MAX]; + int total_tx_data_pend; + struct htc_target *htc_target; + void *hif_priv; + spinlock_t lock; + struct semaphore sem; + int ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 next_mode; + u8 nw_type; + u8 dot11_auth_mode; + u8 auth_mode; + u8 prwise_crypto; + u8 prwise_crypto_len; + u8 grp_crypto; + u8 grp_crypto_len; + u8 def_txkey_index; + struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; + u8 bssid[ETH_ALEN]; + u8 req_bssid[ETH_ALEN]; + u16 ch_hint; + u16 bss_ch; + u16 listen_intvl_b; + u16 listen_intvl_t; + u8 lrssi_roam_threshold; + struct ath6kl_version version; + u32 target_type; + u8 tx_pwr; + struct net_device_stats net_stats; + struct target_stats target_stats; + struct ath6kl_node_mapping node_map[MAX_NODE_NUM]; + u8 ibss_ps_enable; + u8 node_num; + u8 next_ep_id; + struct ath6kl_cookie *cookie_list; + u32 cookie_count; + enum htc_endpoint_id ac2ep_map[WMM_NUM_AC]; + bool ac_stream_active[WMM_NUM_AC]; + u8 ac_stream_pri_map[WMM_NUM_AC]; + u8 hiac_stream_active_pri; + u8 ep2ac_map[ENDPOINT_MAX]; + enum htc_endpoint_id ctrl_ep; + struct htc_credit_state_info credit_state_info; + u32 connect_ctrl_flags; + u32 user_key_ctrl; + u8 usr_bss_filter; + struct ath6kl_sta sta_list[AP_MAX_NUM_STA]; + u8 sta_list_index; + struct ath6kl_req_key ap_mode_bkey; + struct sk_buff_head mcastpsq; + spinlock_t mcastpsq_lock; + u8 intra_bss; + struct aggr_info *aggr_cntxt; + struct wmi_ap_mode_stat ap_stats; + u8 ap_country_code[3]; + struct list_head amsdu_rx_buffer_queue; + struct timer_list disconnect_timer; + u8 rx_meta_ver; + struct wireless_dev *wdev; + struct cfg80211_scan_request *scan_req; + struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; + enum sme_state sme_state; + enum wlan_low_pwr_state wlan_pwr_state; + struct wmi_scan_params_cmd sc_params; +#define AR_MCAST_FILTER_MAC_ADDR_SIZE 4 + struct { + void *rx_report; + size_t rx_report_len; + } tm; + + struct { + u32 dataset_patch_addr; + u32 app_load_addr; + u32 app_start_override_addr; + u32 board_ext_data_addr; + u32 reserved_ram_size; + } hw; + + u16 conf_flags; + wait_queue_head_t event_wq; + struct ath6kl_mbox_info mbox_info; + + struct ath6kl_cookie cookie_mem[MAX_COOKIE_NUM]; + int reconnect_flag; + unsigned long flag; + + u8 *fw_board; + size_t fw_board_len; + + u8 *fw_otp; + size_t fw_otp_len; + + u8 *fw; + size_t fw_len; + + u8 *fw_patch; + size_t fw_patch_len; + + unsigned long fw_capabilities[ATH6KL_CAPABILITY_LEN]; + + struct workqueue_struct *ath6kl_wq; + + struct dentry *debugfs_phy; + + u32 send_action_id; + bool probe_req_report; + u16 next_chan; + + bool p2p; + u16 assoc_bss_beacon_int; + u8 assoc_bss_dtim_period; + +#ifdef CONFIG_ATH6KL_DEBUG + struct { + struct circ_buf fwlog_buf; + spinlock_t fwlog_lock; + void *fwlog_tmp; + u32 fwlog_mask; + unsigned int dbgfs_diag_reg; + u32 diag_reg_addr_wr; + u32 diag_reg_val_wr; + + struct { + unsigned int invalid_rate; + } war_stats; + } debug; +#endif /* CONFIG_ATH6KL_DEBUG */ +}; + +static inline void *ath6kl_priv(struct net_device *dev) +{ + return wdev_priv(dev->ieee80211_ptr); +} + +static inline void ath6kl_deposit_credit_to_ep(struct htc_credit_state_info + *cred_info, + struct htc_endpoint_credit_dist + *ep_dist, int credits) +{ + ep_dist->credits += credits; + ep_dist->cred_assngd += credits; + cred_info->cur_free_credits -= credits; +} + +static inline u32 ath6kl_get_hi_item_addr(struct ath6kl *ar, + u32 item_offset) +{ + u32 addr = 0; + + if (ar->target_type == TARGET_TYPE_AR6003) + addr = ATH6KL_AR6003_HI_START_ADDR + item_offset; + else if (ar->target_type == TARGET_TYPE_AR6004) + addr = ATH6KL_AR6004_HI_START_ADDR + item_offset; + + return addr; +} + +void ath6kl_destroy(struct net_device *dev, unsigned int unregister); +int ath6kl_configure_target(struct ath6kl *ar); +void ath6kl_detect_error(unsigned long ptr); +void disconnect_timer_handler(unsigned long ptr); +void init_netdev(struct net_device *dev); +void ath6kl_cookie_init(struct ath6kl *ar); +void ath6kl_cookie_cleanup(struct ath6kl *ar); +void ath6kl_rx(struct htc_target *target, struct htc_packet *packet); +void ath6kl_tx_complete(void *context, struct list_head *packet_queue); +enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, + struct htc_packet *packet); +void ath6kl_stop_txrx(struct ath6kl *ar); +void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar); +int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value); +int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length); +int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value); +int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length); +int ath6kl_read_fwlogs(struct ath6kl *ar); +void ath6kl_init_profile_info(struct ath6kl *ar); +void ath6kl_tx_data_cleanup(struct ath6kl *ar); +void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile, + bool get_dbglogs); + +struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar); +void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie); +int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev); + +struct aggr_info *aggr_init(struct net_device *dev); +void ath6kl_rx_refill(struct htc_target *target, + enum htc_endpoint_id endpoint); +void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count); +struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, + enum htc_endpoint_id endpoint, + int len); +void aggr_module_destroy(struct aggr_info *aggr_info); +void aggr_reset_state(struct aggr_info *aggr_info); + +struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 * node_addr); +struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); + +void ath6kl_ready_event(void *devt, u8 * datap, u32 sw_ver, u32 abi_ver); +int ath6kl_control_tx(void *devt, struct sk_buff *skb, + enum htc_endpoint_id eid); +void ath6kl_connect_event(struct ath6kl *ar, u16 channel, + u8 *bssid, u16 listen_int, + u16 beacon_int, enum network_type net_type, + u8 beacon_ie_len, u8 assoc_req_len, + u8 assoc_resp_len, u8 *assoc_info); +void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel); +void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr, + u8 keymgmt, u8 ucipher, u8 auth, + u8 assoc_req_len, u8 *assoc_info); +void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, + u8 *bssid, u8 assoc_resp_len, + u8 *assoc_info, u16 prot_reason_status); +void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast); +void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr); +void ath6kl_scan_complete_evt(struct ath6kl *ar, int status); +void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len); +void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active); +enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac); + +void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid); + +void ath6kl_dtimexpiry_event(struct ath6kl *ar); +void ath6kl_disconnect(struct ath6kl *ar); +void ath6kl_deep_sleep_enable(struct ath6kl *ar); +void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid); +void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, + u8 win_sz); +void ath6kl_wakeup_event(void *dev); +void ath6kl_target_failure(struct ath6kl *ar); + +#endif /* CORE_H */ diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c new file mode 100644 index 000000000000..ba3f23d71150 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -0,0 +1,934 @@ +/* + * 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 "core.h" + +#include <linux/circ_buf.h> +#include <linux/fs.h> +#include <linux/vmalloc.h> + +#include "debug.h" +#include "target.h" + +struct ath6kl_fwlog_slot { + __le32 timestamp; + __le32 length; + + /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ + u8 payload[0]; +}; + +#define ATH6KL_FWLOG_SIZE 32768 +#define ATH6KL_FWLOG_SLOT_SIZE (sizeof(struct ath6kl_fwlog_slot) + \ + ATH6KL_FWLOG_PAYLOAD_SIZE) +#define ATH6KL_FWLOG_VALID_MASK 0x1ffff + +int ath6kl_printk(const char *level, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + int rtn; + + va_start(args, fmt); + + vaf.fmt = fmt; + vaf.va = &args; + + rtn = printk("%sath6kl: %pV", level, &vaf); + + va_end(args); + + return rtn; +} + +#ifdef CONFIG_ATH6KL_DEBUG + +#define REG_OUTPUT_LEN_PER_LINE 25 +#define REGTYPE_STR_LEN 100 + +struct ath6kl_diag_reg_info { + u32 reg_start; + u32 reg_end; + const char *reg_info; +}; + +static const struct ath6kl_diag_reg_info diag_reg[] = { + { 0x20000, 0x200fc, "General DMA and Rx registers" }, + { 0x28000, 0x28900, "MAC PCU register & keycache" }, + { 0x20800, 0x20a40, "QCU" }, + { 0x21000, 0x212f0, "DCU" }, + { 0x4000, 0x42e4, "RTC" }, + { 0x540000, 0x540000 + (256 * 1024), "RAM" }, + { 0x29800, 0x2B210, "Base Band" }, + { 0x1C000, 0x1C748, "Analog" }, +}; + +void ath6kl_dump_registers(struct ath6kl_device *dev, + struct ath6kl_irq_proc_registers *irq_proc_reg, + struct ath6kl_irq_enable_reg *irq_enable_reg) +{ + + ath6kl_dbg(ATH6KL_DBG_ANY, ("<------- Register Table -------->\n")); + + if (irq_proc_reg != NULL) { + ath6kl_dbg(ATH6KL_DBG_ANY, + "Host Int status: 0x%x\n", + irq_proc_reg->host_int_status); + ath6kl_dbg(ATH6KL_DBG_ANY, + "CPU Int status: 0x%x\n", + irq_proc_reg->cpu_int_status); + ath6kl_dbg(ATH6KL_DBG_ANY, + "Error Int status: 0x%x\n", + irq_proc_reg->error_int_status); + ath6kl_dbg(ATH6KL_DBG_ANY, + "Counter Int status: 0x%x\n", + irq_proc_reg->counter_int_status); + ath6kl_dbg(ATH6KL_DBG_ANY, + "Mbox Frame: 0x%x\n", + irq_proc_reg->mbox_frame); + ath6kl_dbg(ATH6KL_DBG_ANY, + "Rx Lookahead Valid: 0x%x\n", + irq_proc_reg->rx_lkahd_valid); + ath6kl_dbg(ATH6KL_DBG_ANY, + "Rx Lookahead 0: 0x%x\n", + irq_proc_reg->rx_lkahd[0]); + ath6kl_dbg(ATH6KL_DBG_ANY, + "Rx Lookahead 1: 0x%x\n", + irq_proc_reg->rx_lkahd[1]); + + if (dev->ar->mbox_info.gmbox_addr != 0) { + /* + * If the target supports GMBOX hardware, dump some + * additional state. + */ + ath6kl_dbg(ATH6KL_DBG_ANY, + "GMBOX Host Int status 2: 0x%x\n", + irq_proc_reg->host_int_status2); + ath6kl_dbg(ATH6KL_DBG_ANY, + "GMBOX RX Avail: 0x%x\n", + irq_proc_reg->gmbox_rx_avail); + ath6kl_dbg(ATH6KL_DBG_ANY, + "GMBOX lookahead alias 0: 0x%x\n", + irq_proc_reg->rx_gmbox_lkahd_alias[0]); + ath6kl_dbg(ATH6KL_DBG_ANY, + "GMBOX lookahead alias 1: 0x%x\n", + irq_proc_reg->rx_gmbox_lkahd_alias[1]); + } + + } + + if (irq_enable_reg != NULL) { + ath6kl_dbg(ATH6KL_DBG_ANY, + "Int status Enable: 0x%x\n", + irq_enable_reg->int_status_en); + ath6kl_dbg(ATH6KL_DBG_ANY, "Counter Int status Enable: 0x%x\n", + irq_enable_reg->cntr_int_status_en); + } + ath6kl_dbg(ATH6KL_DBG_ANY, "<------------------------------->\n"); +} + +static void dump_cred_dist(struct htc_endpoint_credit_dist *ep_dist) +{ + ath6kl_dbg(ATH6KL_DBG_ANY, + "--- endpoint: %d svc_id: 0x%X ---\n", + ep_dist->endpoint, ep_dist->svc_id); + ath6kl_dbg(ATH6KL_DBG_ANY, " dist_flags : 0x%X\n", + ep_dist->dist_flags); + ath6kl_dbg(ATH6KL_DBG_ANY, " cred_norm : %d\n", + ep_dist->cred_norm); + ath6kl_dbg(ATH6KL_DBG_ANY, " cred_min : %d\n", + ep_dist->cred_min); + ath6kl_dbg(ATH6KL_DBG_ANY, " credits : %d\n", + ep_dist->credits); + ath6kl_dbg(ATH6KL_DBG_ANY, " cred_assngd : %d\n", + ep_dist->cred_assngd); + ath6kl_dbg(ATH6KL_DBG_ANY, " seek_cred : %d\n", + ep_dist->seek_cred); + ath6kl_dbg(ATH6KL_DBG_ANY, " cred_sz : %d\n", + ep_dist->cred_sz); + ath6kl_dbg(ATH6KL_DBG_ANY, " cred_per_msg : %d\n", + ep_dist->cred_per_msg); + ath6kl_dbg(ATH6KL_DBG_ANY, " cred_to_dist : %d\n", + ep_dist->cred_to_dist); + ath6kl_dbg(ATH6KL_DBG_ANY, " txq_depth : %d\n", + get_queue_depth(&((struct htc_endpoint *) + ep_dist->htc_rsvd)->txq)); + ath6kl_dbg(ATH6KL_DBG_ANY, + "----------------------------------\n"); +} + +void dump_cred_dist_stats(struct htc_target *target) +{ + struct htc_endpoint_credit_dist *ep_list; + + if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_TRC)) + return; + + list_for_each_entry(ep_list, &target->cred_dist_list, list) + dump_cred_dist(ep_list); + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:%p dist:%p\n", + target->cred_dist_cntxt, NULL); + ath6kl_dbg(ATH6KL_DBG_TRC, "credit distribution, total : %d, free : %d\n", + target->cred_dist_cntxt->total_avail_credits, + target->cred_dist_cntxt->cur_free_credits); +} + +static int ath6kl_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war) +{ + switch (war) { + case ATH6KL_WAR_INVALID_RATE: + ar->debug.war_stats.invalid_rate++; + break; + } +} + +static ssize_t read_file_war_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + char *buf; + unsigned int len = 0, buf_len = 1500; + ssize_t ret_cnt; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, buf_len - len, "\n"); + len += scnprintf(buf + len, buf_len - len, "%25s\n", + "Workaround stats"); + len += scnprintf(buf + len, buf_len - len, "%25s\n\n", + "================="); + len += scnprintf(buf + len, buf_len - len, "%20s %10u\n", + "Invalid rates", ar->debug.war_stats.invalid_rate); + + if (WARN_ON(len > buf_len)) + len = buf_len; + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + + kfree(buf); + return ret_cnt; +} + +static const struct file_operations fops_war_stats = { + .read = read_file_war_stats, + .open = ath6kl_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static void ath6kl_debug_fwlog_add(struct ath6kl *ar, const void *buf, + size_t buf_len) +{ + struct circ_buf *fwlog = &ar->debug.fwlog_buf; + size_t space; + int i; + + /* entries must all be equal size */ + if (WARN_ON(buf_len != ATH6KL_FWLOG_SLOT_SIZE)) + return; + + space = CIRC_SPACE(fwlog->head, fwlog->tail, ATH6KL_FWLOG_SIZE); + if (space < buf_len) + /* discard oldest slot */ + fwlog->tail = (fwlog->tail + ATH6KL_FWLOG_SLOT_SIZE) & + (ATH6KL_FWLOG_SIZE - 1); + + for (i = 0; i < buf_len; i += space) { + space = CIRC_SPACE_TO_END(fwlog->head, fwlog->tail, + ATH6KL_FWLOG_SIZE); + + if ((size_t) space > buf_len - i) + space = buf_len - i; + + memcpy(&fwlog->buf[fwlog->head], buf, space); + fwlog->head = (fwlog->head + space) & (ATH6KL_FWLOG_SIZE - 1); + } + +} + +void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len) +{ + struct ath6kl_fwlog_slot *slot = ar->debug.fwlog_tmp; + size_t slot_len; + + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return; + + spin_lock_bh(&ar->debug.fwlog_lock); + + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(len); + memcpy(slot->payload, buf, len); + + slot_len = sizeof(*slot) + len; + + if (slot_len < ATH6KL_FWLOG_SLOT_SIZE) + memset(slot->payload + len, 0, + ATH6KL_FWLOG_SLOT_SIZE - slot_len); + + ath6kl_debug_fwlog_add(ar, slot, ATH6KL_FWLOG_SLOT_SIZE); + + spin_unlock_bh(&ar->debug.fwlog_lock); +} + +static bool ath6kl_debug_fwlog_empty(struct ath6kl *ar) +{ + return CIRC_CNT(ar->debug.fwlog_buf.head, + ar->debug.fwlog_buf.tail, + ATH6KL_FWLOG_SLOT_SIZE) == 0; +} + +static ssize_t ath6kl_fwlog_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + struct circ_buf *fwlog = &ar->debug.fwlog_buf; + size_t len = 0, buf_len = count; + ssize_t ret_cnt; + char *buf; + int ccnt; + + buf = vmalloc(buf_len); + if (!buf) + return -ENOMEM; + + /* read undelivered logs from firmware */ + ath6kl_read_fwlogs(ar); + + spin_lock_bh(&ar->debug.fwlog_lock); + + while (len < buf_len && !ath6kl_debug_fwlog_empty(ar)) { + ccnt = CIRC_CNT_TO_END(fwlog->head, fwlog->tail, + ATH6KL_FWLOG_SIZE); + + if ((size_t) ccnt > buf_len - len) + ccnt = buf_len - len; + + memcpy(buf + len, &fwlog->buf[fwlog->tail], ccnt); + len += ccnt; + + fwlog->tail = (fwlog->tail + ccnt) & + (ATH6KL_FWLOG_SIZE - 1); + } + + spin_unlock_bh(&ar->debug.fwlog_lock); + + if (WARN_ON(len > buf_len)) + len = buf_len; + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + + vfree(buf); + + return ret_cnt; +} + +static const struct file_operations fops_fwlog = { + .open = ath6kl_debugfs_open, + .read = ath6kl_fwlog_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath6kl_fwlog_mask_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + char buf[16]; + int len; + + len = snprintf(buf, sizeof(buf), "0x%x\n", ar->debug.fwlog_mask); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath6kl_fwlog_mask_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + int ret; + + ret = kstrtou32_from_user(user_buf, count, 0, &ar->debug.fwlog_mask); + if (ret) + return ret; + + ret = ath6kl_wmi_config_debug_module_cmd(ar->wmi, + ATH6KL_FWLOG_VALID_MASK, + ar->debug.fwlog_mask); + if (ret) + return ret; + + return count; +} + +static const struct file_operations fops_fwlog_mask = { + .open = ath6kl_debugfs_open, + .read = ath6kl_fwlog_mask_read, + .write = ath6kl_fwlog_mask_write, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_tgt_stats(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + struct target_stats *tgt_stats = &ar->target_stats; + char *buf; + unsigned int len = 0, buf_len = 1500; + int i; + long left; + ssize_t ret_cnt; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + if (down_interruptible(&ar->sem)) { + kfree(buf); + return -EBUSY; + } + + set_bit(STATS_UPDATE_PEND, &ar->flag); + + if (ath6kl_wmi_get_stats_cmd(ar->wmi)) { + up(&ar->sem); + kfree(buf); + return -EIO; + } + + left = wait_event_interruptible_timeout(ar->event_wq, + !test_bit(STATS_UPDATE_PEND, + &ar->flag), WMI_TIMEOUT); + + up(&ar->sem); + + if (left <= 0) { + kfree(buf); + return -ETIMEDOUT; + } + + len += scnprintf(buf + len, buf_len - len, "\n"); + len += scnprintf(buf + len, buf_len - len, "%25s\n", + "Target Tx stats"); + len += scnprintf(buf + len, buf_len - len, "%25s\n\n", + "================="); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Ucast packets", tgt_stats->tx_ucast_pkt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Bcast packets", tgt_stats->tx_bcast_pkt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Ucast byte", tgt_stats->tx_ucast_byte); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Bcast byte", tgt_stats->tx_bcast_byte); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Rts success cnt", tgt_stats->tx_rts_success_cnt); + for (i = 0; i < 4; i++) + len += scnprintf(buf + len, buf_len - len, + "%18s %d %10llu\n", "PER on ac", + i, tgt_stats->tx_pkt_per_ac[i]); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Error", tgt_stats->tx_err); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Fail count", tgt_stats->tx_fail_cnt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Retry count", tgt_stats->tx_retry_cnt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Multi retry cnt", tgt_stats->tx_mult_retry_cnt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Rts fail cnt", tgt_stats->tx_rts_fail_cnt); + len += scnprintf(buf + len, buf_len - len, "%25s %10llu\n\n", + "TKIP counter measure used", + tgt_stats->tkip_cnter_measures_invoked); + + len += scnprintf(buf + len, buf_len - len, "%25s\n", + "Target Rx stats"); + len += scnprintf(buf + len, buf_len - len, "%25s\n", + "================="); + + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Ucast packets", tgt_stats->rx_ucast_pkt); + len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", + "Ucast Rate", tgt_stats->rx_ucast_rate); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Bcast packets", tgt_stats->rx_bcast_pkt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Ucast byte", tgt_stats->rx_ucast_byte); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Bcast byte", tgt_stats->rx_bcast_byte); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Fragmented pkt", tgt_stats->rx_frgment_pkt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Error", tgt_stats->rx_err); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "CRC Err", tgt_stats->rx_crc_err); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Key chache miss", tgt_stats->rx_key_cache_miss); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Decrypt Err", tgt_stats->rx_decrypt_err); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Duplicate frame", tgt_stats->rx_dupl_frame); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Tkip Mic failure", tgt_stats->tkip_local_mic_fail); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "TKIP format err", tgt_stats->tkip_fmt_err); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "CCMP format Err", tgt_stats->ccmp_fmt_err); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n\n", + "CCMP Replay Err", tgt_stats->ccmp_replays); + + len += scnprintf(buf + len, buf_len - len, "%25s\n", + "Misc Target stats"); + len += scnprintf(buf + len, buf_len - len, "%25s\n", + "================="); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Beacon Miss count", tgt_stats->cs_bmiss_cnt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Num Connects", tgt_stats->cs_connect_cnt); + len += scnprintf(buf + len, buf_len - len, "%20s %10llu\n", + "Num disconnects", tgt_stats->cs_discon_cnt); + len += scnprintf(buf + len, buf_len - len, "%20s %10d\n", + "Beacon avg rssi", tgt_stats->cs_ave_beacon_rssi); + + if (len > buf_len) + len = buf_len; + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + + kfree(buf); + return ret_cnt; +} + +static const struct file_operations fops_tgt_stats = { + .read = read_file_tgt_stats, + .open = ath6kl_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +#define print_credit_info(fmt_str, ep_list_field) \ + (len += scnprintf(buf + len, buf_len - len, fmt_str, \ + ep_list->ep_list_field)) +#define CREDIT_INFO_DISPLAY_STRING_LEN 200 +#define CREDIT_INFO_LEN 128 + +static ssize_t read_file_credit_dist_stats(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + struct htc_target *target = ar->htc_target; + struct htc_endpoint_credit_dist *ep_list; + char *buf; + unsigned int buf_len, len = 0; + ssize_t ret_cnt; + + buf_len = CREDIT_INFO_DISPLAY_STRING_LEN + + get_queue_depth(&target->cred_dist_list) * CREDIT_INFO_LEN; + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", + "Total Avail Credits: ", + target->cred_dist_cntxt->total_avail_credits); + len += scnprintf(buf + len, buf_len - len, "%25s%5d\n", + "Free credits :", + target->cred_dist_cntxt->cur_free_credits); + + len += scnprintf(buf + len, buf_len - len, + " Epid Flags Cred_norm Cred_min Credits Cred_assngd" + " Seek_cred Cred_sz Cred_per_msg Cred_to_dist" + " qdepth\n"); + + list_for_each_entry(ep_list, &target->cred_dist_list, list) { + print_credit_info(" %2d", endpoint); + print_credit_info("%10x", dist_flags); + print_credit_info("%8d", cred_norm); + print_credit_info("%9d", cred_min); + print_credit_info("%9d", credits); + print_credit_info("%10d", cred_assngd); + print_credit_info("%13d", seek_cred); + print_credit_info("%12d", cred_sz); + print_credit_info("%9d", cred_per_msg); + print_credit_info("%14d", cred_to_dist); + len += scnprintf(buf + len, buf_len - len, "%12d\n", + get_queue_depth(&((struct htc_endpoint *) + ep_list->htc_rsvd)->txq)); + } + + if (len > buf_len) + len = buf_len; + + ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + return ret_cnt; +} + +static const struct file_operations fops_credit_dist_stats = { + .read = read_file_credit_dist_stats, + .open = ath6kl_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static unsigned long ath6kl_get_num_reg(void) +{ + int i; + unsigned long n_reg = 0; + + for (i = 0; i < ARRAY_SIZE(diag_reg); i++) + n_reg = n_reg + + (diag_reg[i].reg_end - diag_reg[i].reg_start) / 4 + 1; + + return n_reg; +} + +static bool ath6kl_dbg_is_diag_reg_valid(u32 reg_addr) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { + if (reg_addr >= diag_reg[i].reg_start && + reg_addr <= diag_reg[i].reg_end) + return true; + } + + return false; +} + +static ssize_t ath6kl_regread_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + u8 buf[50]; + unsigned int len = 0; + + if (ar->debug.dbgfs_diag_reg) + len += scnprintf(buf + len, sizeof(buf) - len, "0x%x\n", + ar->debug.dbgfs_diag_reg); + else + len += scnprintf(buf + len, sizeof(buf) - len, + "All diag registers\n"); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath6kl_regread_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + u8 buf[50]; + unsigned int len; + unsigned long reg_addr; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + + if (strict_strtoul(buf, 0, ®_addr)) + return -EINVAL; + + if ((reg_addr % 4) != 0) + return -EINVAL; + + if (reg_addr && !ath6kl_dbg_is_diag_reg_valid(reg_addr)) + return -EINVAL; + + ar->debug.dbgfs_diag_reg = reg_addr; + + return count; +} + +static const struct file_operations fops_diag_reg_read = { + .read = ath6kl_regread_read, + .write = ath6kl_regread_write, + .open = ath6kl_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static int ath6kl_regdump_open(struct inode *inode, struct file *file) +{ + struct ath6kl *ar = inode->i_private; + u8 *buf; + unsigned long int reg_len; + unsigned int len = 0, n_reg; + u32 addr; + __le32 reg_val; + int i, status; + + /* Dump all the registers if no register is specified */ + if (!ar->debug.dbgfs_diag_reg) + n_reg = ath6kl_get_num_reg(); + else + n_reg = 1; + + reg_len = n_reg * REG_OUTPUT_LEN_PER_LINE; + if (n_reg > 1) + reg_len += REGTYPE_STR_LEN; + + buf = vmalloc(reg_len); + if (!buf) + return -ENOMEM; + + if (n_reg == 1) { + addr = ar->debug.dbgfs_diag_reg; + + status = ath6kl_diag_read32(ar, + TARG_VTOP(ar->target_type, addr), + (u32 *)®_val); + if (status) + goto fail_reg_read; + + len += scnprintf(buf + len, reg_len - len, + "0x%06x 0x%08x\n", addr, le32_to_cpu(reg_val)); + goto done; + } + + for (i = 0; i < ARRAY_SIZE(diag_reg); i++) { + len += scnprintf(buf + len, reg_len - len, + "%s\n", diag_reg[i].reg_info); + for (addr = diag_reg[i].reg_start; + addr <= diag_reg[i].reg_end; addr += 4) { + status = ath6kl_diag_read32(ar, + TARG_VTOP(ar->target_type, addr), + (u32 *)®_val); + if (status) + goto fail_reg_read; + + len += scnprintf(buf + len, reg_len - len, + "0x%06x 0x%08x\n", + addr, le32_to_cpu(reg_val)); + } + } + +done: + file->private_data = buf; + return 0; + +fail_reg_read: + ath6kl_warn("Unable to read memory:%u\n", addr); + vfree(buf); + return -EIO; +} + +static ssize_t ath6kl_regdump_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + u8 *buf = file->private_data; + return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); +} + +static int ath6kl_regdump_release(struct inode *inode, struct file *file) +{ + vfree(file->private_data); + return 0; +} + +static const struct file_operations fops_reg_dump = { + .open = ath6kl_regdump_open, + .read = ath6kl_regdump_read, + .release = ath6kl_regdump_release, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath6kl_lrssi_roam_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + unsigned long lrssi_roam_threshold; + 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 (strict_strtoul(buf, 0, &lrssi_roam_threshold)) + return -EINVAL; + + ar->lrssi_roam_threshold = lrssi_roam_threshold; + + ath6kl_wmi_set_roam_lrssi_cmd(ar->wmi, ar->lrssi_roam_threshold); + + return count; +} + +static ssize_t ath6kl_lrssi_roam_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + char buf[32]; + unsigned int len; + + len = snprintf(buf, sizeof(buf), "%u\n", ar->lrssi_roam_threshold); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_lrssi_roam_threshold = { + .read = ath6kl_lrssi_roam_read, + .write = ath6kl_lrssi_roam_write, + .open = ath6kl_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t ath6kl_regwrite_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + u8 buf[32]; + unsigned int len = 0; + + len = scnprintf(buf, sizeof(buf), "Addr: 0x%x Val: 0x%x\n", + ar->debug.diag_reg_addr_wr, ar->debug.diag_reg_val_wr); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath6kl_regwrite_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath6kl *ar = file->private_data; + char buf[32]; + char *sptr, *token; + unsigned int len = 0; + u32 reg_addr, reg_val; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + sptr = buf; + + token = strsep(&sptr, "="); + if (!token) + return -EINVAL; + + if (kstrtou32(token, 0, ®_addr)) + return -EINVAL; + + if (!ath6kl_dbg_is_diag_reg_valid(reg_addr)) + return -EINVAL; + + if (kstrtou32(sptr, 0, ®_val)) + return -EINVAL; + + ar->debug.diag_reg_addr_wr = reg_addr; + ar->debug.diag_reg_val_wr = reg_val; + + if (ath6kl_diag_write32(ar, ar->debug.diag_reg_addr_wr, + cpu_to_le32(ar->debug.diag_reg_val_wr))) + return -EIO; + + return count; +} + +static const struct file_operations fops_diag_reg_write = { + .read = ath6kl_regwrite_read, + .write = ath6kl_regwrite_write, + .open = ath6kl_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int ath6kl_debug_init(struct ath6kl *ar) +{ + ar->debug.fwlog_buf.buf = vmalloc(ATH6KL_FWLOG_SIZE); + if (ar->debug.fwlog_buf.buf == NULL) + return -ENOMEM; + + ar->debug.fwlog_tmp = kmalloc(ATH6KL_FWLOG_SLOT_SIZE, GFP_KERNEL); + if (ar->debug.fwlog_tmp == NULL) { + vfree(ar->debug.fwlog_buf.buf); + return -ENOMEM; + } + + spin_lock_init(&ar->debug.fwlog_lock); + + /* + * Actually we are lying here but don't know how to read the mask + * value from the firmware. + */ + ar->debug.fwlog_mask = 0; + + ar->debugfs_phy = debugfs_create_dir("ath6kl", + ar->wdev->wiphy->debugfsdir); + if (!ar->debugfs_phy) { + vfree(ar->debug.fwlog_buf.buf); + kfree(ar->debug.fwlog_tmp); + return -ENOMEM; + } + + debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, + &fops_tgt_stats); + + debugfs_create_file("credit_dist_stats", S_IRUSR, ar->debugfs_phy, ar, + &fops_credit_dist_stats); + + debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, + &fops_fwlog); + + debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, + ar, &fops_fwlog_mask); + + debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, + &fops_diag_reg_read); + + debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar, + &fops_reg_dump); + + debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR, + ar->debugfs_phy, ar, &fops_lrssi_roam_threshold); + + debugfs_create_file("reg_write", S_IRUSR | S_IWUSR, + ar->debugfs_phy, ar, &fops_diag_reg_write); + + debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar, + &fops_war_stats); + + return 0; +} + +void ath6kl_debug_cleanup(struct ath6kl *ar) +{ + vfree(ar->debug.fwlog_buf.buf); + kfree(ar->debug.fwlog_tmp); +} + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h new file mode 100644 index 000000000000..9288a3ce1e39 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/debug.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DEBUG_H +#define DEBUG_H + +#include "htc_hif.h" + +enum ATH6K_DEBUG_MASK { + ATH6KL_DBG_WLAN_CONNECT = BIT(0), /* wlan connect */ + ATH6KL_DBG_WLAN_SCAN = BIT(1), /* wlan scan */ + ATH6KL_DBG_WLAN_TX = BIT(2), /* wlan tx */ + ATH6KL_DBG_WLAN_RX = BIT(3), /* wlan rx */ + ATH6KL_DBG_BMI = BIT(4), /* bmi tracing */ + ATH6KL_DBG_HTC_SEND = BIT(5), /* htc send */ + ATH6KL_DBG_HTC_RECV = BIT(6), /* htc recv */ + ATH6KL_DBG_IRQ = BIT(7), /* interrupt processing */ + ATH6KL_DBG_PM = BIT(8), /* power management */ + ATH6KL_DBG_WLAN_NODE = BIT(9), /* general wlan node tracing */ + ATH6KL_DBG_WMI = BIT(10), /* wmi tracing */ + ATH6KL_DBG_TRC = BIT(11), /* generic func tracing */ + ATH6KL_DBG_SCATTER = BIT(12), /* hif scatter tracing */ + ATH6KL_DBG_WLAN_CFG = BIT(13), /* cfg80211 i/f file tracing */ + ATH6KL_DBG_RAW_BYTES = BIT(14), /* dump tx/rx frames */ + ATH6KL_DBG_AGGR = BIT(15), /* aggregation */ + ATH6KL_DBG_SDIO = BIT(16), + ATH6KL_DBG_SDIO_DUMP = BIT(17), + ATH6KL_DBG_BOOT = BIT(18), /* driver init and fw boot */ + ATH6KL_DBG_WMI_DUMP = BIT(19), + ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ +}; + +extern unsigned int debug_mask; +extern int ath6kl_printk(const char *level, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +#define ath6kl_info(fmt, ...) \ + ath6kl_printk(KERN_INFO, fmt, ##__VA_ARGS__) +#define ath6kl_err(fmt, ...) \ + ath6kl_printk(KERN_ERR, fmt, ##__VA_ARGS__) +#define ath6kl_warn(fmt, ...) \ + ath6kl_printk(KERN_WARNING, fmt, ##__VA_ARGS__) + +#define AR_DBG_LVL_CHECK(mask) (debug_mask & mask) + +enum ath6kl_war { + ATH6KL_WAR_INVALID_RATE, +}; + +#ifdef CONFIG_ATH6KL_DEBUG +#define ath6kl_dbg(mask, fmt, ...) \ + ({ \ + int rtn; \ + if (debug_mask & mask) \ + rtn = ath6kl_printk(KERN_DEBUG, fmt, ##__VA_ARGS__); \ + else \ + rtn = 0; \ + \ + rtn; \ + }) + +static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, + const char *msg, const char *prefix, + const void *buf, size_t len) +{ + if (debug_mask & mask) { + if (msg) + ath6kl_dbg(mask, "%s\n", msg); + + print_hex_dump_bytes(prefix, DUMP_PREFIX_OFFSET, buf, len); + } +} + +void ath6kl_dump_registers(struct ath6kl_device *dev, + struct ath6kl_irq_proc_registers *irq_proc_reg, + struct ath6kl_irq_enable_reg *irq_en_reg); +void dump_cred_dist_stats(struct htc_target *target); +void ath6kl_debug_fwlog_event(struct ath6kl *ar, const void *buf, size_t len); +void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war); +int ath6kl_debug_init(struct ath6kl *ar); +void ath6kl_debug_cleanup(struct ath6kl *ar); + +#else +static inline int ath6kl_dbg(enum ATH6K_DEBUG_MASK dbg_mask, + const char *fmt, ...) +{ + return 0; +} + +static inline void ath6kl_dbg_dump(enum ATH6K_DEBUG_MASK mask, + const char *msg, const char *prefix, + const void *buf, size_t len) +{ +} + +static inline void ath6kl_dump_registers(struct ath6kl_device *dev, + struct ath6kl_irq_proc_registers *irq_proc_reg, + struct ath6kl_irq_enable_reg *irq_en_reg) +{ + +} +static inline void dump_cred_dist_stats(struct htc_target *target) +{ +} + +static inline void ath6kl_debug_fwlog_event(struct ath6kl *ar, + const void *buf, size_t len) +{ +} + +static inline void ath6kl_debug_war(struct ath6kl *ar, enum ath6kl_war war) +{ +} + +static inline int ath6kl_debug_init(struct ath6kl *ar) +{ + return 0; +} + +static inline void ath6kl_debug_cleanup(struct ath6kl *ar) +{ +} + +#endif +#endif diff --git a/drivers/net/wireless/ath/ath6kl/hif-ops.h b/drivers/net/wireless/ath/ath6kl/hif-ops.h new file mode 100644 index 000000000000..d6c898f3d0b3 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/hif-ops.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +#ifndef HIF_OPS_H +#define HIF_OPS_H + +#include "hif.h" + +static inline int hif_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, + u32 len, u32 request) +{ + return ar->hif_ops->read_write_sync(ar, addr, buf, len, request); +} + +static inline int hif_write_async(struct ath6kl *ar, u32 address, u8 *buffer, + u32 length, u32 request, + struct htc_packet *packet) +{ + return ar->hif_ops->write_async(ar, address, buffer, length, + request, packet); +} +static inline void ath6kl_hif_irq_enable(struct ath6kl *ar) +{ + return ar->hif_ops->irq_enable(ar); +} + +static inline void ath6kl_hif_irq_disable(struct ath6kl *ar) +{ + return ar->hif_ops->irq_disable(ar); +} + +static inline struct hif_scatter_req *hif_scatter_req_get(struct ath6kl *ar) +{ + return ar->hif_ops->scatter_req_get(ar); +} + +static inline void hif_scatter_req_add(struct ath6kl *ar, + struct hif_scatter_req *s_req) +{ + return ar->hif_ops->scatter_req_add(ar, s_req); +} + +static inline int ath6kl_hif_enable_scatter(struct ath6kl *ar) +{ + return ar->hif_ops->enable_scatter(ar); +} + +static inline int ath6kl_hif_scat_req_rw(struct ath6kl *ar, + struct hif_scatter_req *scat_req) +{ + return ar->hif_ops->scat_req_rw(ar, scat_req); +} + +static inline void ath6kl_hif_cleanup_scatter(struct ath6kl *ar) +{ + return ar->hif_ops->cleanup_scatter(ar); +} + +static inline int ath6kl_hif_suspend(struct ath6kl *ar) +{ + return ar->hif_ops->suspend(ar); +} + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/hif.h b/drivers/net/wireless/ath/ath6kl/hif.h new file mode 100644 index 000000000000..797e2d1d9bf9 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/hif.h @@ -0,0 +1,208 @@ +/* + * 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. + */ + +#ifndef HIF_H +#define HIF_H + +#include "common.h" +#include "core.h" + +#include <linux/scatterlist.h> + +#define BUS_REQUEST_MAX_NUM 64 +#define HIF_MBOX_BLOCK_SIZE 128 +#define HIF_MBOX0_BLOCK_SIZE 1 + +#define HIF_DMA_BUFFER_SIZE (32 * 1024) +#define CMD53_FIXED_ADDRESS 1 +#define CMD53_INCR_ADDRESS 2 + +#define MAX_SCATTER_REQUESTS 4 +#define MAX_SCATTER_ENTRIES_PER_REQ 16 +#define MAX_SCATTER_REQ_TRANSFER_SIZE (32 * 1024) + +#define MANUFACTURER_ID_AR6003_BASE 0x300 + /* SDIO manufacturer ID and Codes */ +#define MANUFACTURER_ID_ATH6KL_BASE_MASK 0xFF00 +#define MANUFACTURER_CODE 0x271 /* Atheros */ + +/* Mailbox address in SDIO address space */ +#define HIF_MBOX_BASE_ADDR 0x800 +#define HIF_MBOX_WIDTH 0x800 + +#define HIF_MBOX_END_ADDR (HTC_MAILBOX_NUM_MAX * HIF_MBOX_WIDTH - 1) + +/* version 1 of the chip has only a 12K extended mbox range */ +#define HIF_MBOX0_EXT_BASE_ADDR 0x4000 +#define HIF_MBOX0_EXT_WIDTH (12*1024) + +/* GMBOX addresses */ +#define HIF_GMBOX_BASE_ADDR 0x7000 +#define HIF_GMBOX_WIDTH 0x4000 + +/* interrupt mode register */ +#define CCCR_SDIO_IRQ_MODE_REG 0xF0 + +/* mode to enable special 4-bit interrupt assertion without clock */ +#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ (1 << 0) + +struct bus_request { + struct list_head list; + + /* request data */ + u32 address; + + u8 *buffer; + u32 length; + u32 request; + struct htc_packet *packet; + int status; + + /* this is a scatter request */ + struct hif_scatter_req *scat_req; +}; + +/* direction of transfer (read/write) */ +#define HIF_READ 0x00000001 +#define HIF_WRITE 0x00000002 +#define HIF_DIR_MASK (HIF_READ | HIF_WRITE) + +/* + * emode - This indicates the whether the command is to be executed in a + * blocking or non-blocking fashion (HIF_SYNCHRONOUS/ + * HIF_ASYNCHRONOUS). The read/write data paths in HTC have been + * implemented using the asynchronous mode allowing the the bus + * driver to indicate the completion of operation through the + * registered callback routine. The requirement primarily comes + * from the contexts these operations get called from (a driver's + * transmit context or the ISR context in case of receive). + * Support for both of these modes is essential. + */ +#define HIF_SYNCHRONOUS 0x00000010 +#define HIF_ASYNCHRONOUS 0x00000020 +#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS) + +/* + * dmode - An interface may support different kinds of commands based on + * the tradeoff between the amount of data it can carry and the + * setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/ + * HIF_BLOCK_BASIS). In case of latter, the data is rounded off + * to the nearest block size by padding. The size of the block is + * configurable at compile time using the HIF_BLOCK_SIZE and is + * negotiated with the target during initialization after the + * ATH6KL interrupts are enabled. + */ +#define HIF_BYTE_BASIS 0x00000040 +#define HIF_BLOCK_BASIS 0x00000080 +#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS) + +/* + * amode - This indicates if the address has to be incremented on ATH6KL + * after every read/write operation (HIF?FIXED_ADDRESS/ + * HIF_INCREMENTAL_ADDRESS). + */ +#define HIF_FIXED_ADDRESS 0x00000100 +#define HIF_INCREMENTAL_ADDRESS 0x00000200 +#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS) + +#define HIF_WR_ASYNC_BYTE_INC \ + (HIF_WRITE | HIF_ASYNCHRONOUS | \ + HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) + +#define HIF_WR_ASYNC_BLOCK_INC \ + (HIF_WRITE | HIF_ASYNCHRONOUS | \ + HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS) + +#define HIF_WR_SYNC_BYTE_FIX \ + (HIF_WRITE | HIF_SYNCHRONOUS | \ + HIF_BYTE_BASIS | HIF_FIXED_ADDRESS) + +#define HIF_WR_SYNC_BYTE_INC \ + (HIF_WRITE | HIF_SYNCHRONOUS | \ + HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) + +#define HIF_WR_SYNC_BLOCK_INC \ + (HIF_WRITE | HIF_SYNCHRONOUS | \ + HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS) + +#define HIF_RD_SYNC_BYTE_INC \ + (HIF_READ | HIF_SYNCHRONOUS | \ + HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) + +#define HIF_RD_SYNC_BYTE_FIX \ + (HIF_READ | HIF_SYNCHRONOUS | \ + HIF_BYTE_BASIS | HIF_FIXED_ADDRESS) + +#define HIF_RD_ASYNC_BLOCK_FIX \ + (HIF_READ | HIF_ASYNCHRONOUS | \ + HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS) + +#define HIF_RD_SYNC_BLOCK_FIX \ + (HIF_READ | HIF_SYNCHRONOUS | \ + HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS) + +struct hif_scatter_item { + u8 *buf; + int len; + struct htc_packet *packet; +}; + +struct hif_scatter_req { + struct list_head list; + /* address for the read/write operation */ + u32 addr; + + /* request flags */ + u32 req; + + /* total length of entire transfer */ + u32 len; + + bool virt_scat; + + void (*complete) (struct htc_target *, struct hif_scatter_req *); + int status; + int scat_entries; + + struct bus_request *busrequest; + struct scatterlist *sgentries; + + /* bounce buffer for upper layers to copy to/from */ + u8 *virt_dma_buf; + + struct hif_scatter_item scat_list[1]; +}; + +struct ath6kl_hif_ops { + int (*read_write_sync)(struct ath6kl *ar, u32 addr, u8 *buf, + u32 len, u32 request); + int (*write_async)(struct ath6kl *ar, u32 address, u8 *buffer, + u32 length, u32 request, struct htc_packet *packet); + + void (*irq_enable)(struct ath6kl *ar); + void (*irq_disable)(struct ath6kl *ar); + + struct hif_scatter_req *(*scatter_req_get)(struct ath6kl *ar); + void (*scatter_req_add)(struct ath6kl *ar, + struct hif_scatter_req *s_req); + int (*enable_scatter)(struct ath6kl *ar); + int (*scat_req_rw) (struct ath6kl *ar, + struct hif_scatter_req *scat_req); + void (*cleanup_scatter)(struct ath6kl *ar); + int (*suspend)(struct ath6kl *ar); +}; + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/htc.c b/drivers/net/wireless/ath/ath6kl/htc.c new file mode 100644 index 000000000000..f88a7c9e4148 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/htc.c @@ -0,0 +1,2478 @@ +/* + * Copyright (c) 2007-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 "core.h" +#include "htc_hif.h" +#include "debug.h" +#include "hif-ops.h" +#include <asm/unaligned.h> + +#define CALC_TXRX_PADDED_LEN(dev, len) (__ALIGN_MASK((len), (dev)->block_mask)) + +static void ath6kl_htc_tx_buf_align(u8 **buf, unsigned long len) +{ + u8 *align_addr; + + if (!IS_ALIGNED((unsigned long) *buf, 4)) { + align_addr = PTR_ALIGN(*buf - 4, 4); + memmove(align_addr, *buf, len); + *buf = align_addr; + } +} + +static void ath6kl_htc_tx_prep_pkt(struct htc_packet *packet, u8 flags, + int ctrl0, int ctrl1) +{ + struct htc_frame_hdr *hdr; + + packet->buf -= HTC_HDR_LENGTH; + hdr = (struct htc_frame_hdr *)packet->buf; + + /* Endianess? */ + put_unaligned((u16)packet->act_len, &hdr->payld_len); + hdr->flags = flags; + hdr->eid = packet->endpoint; + hdr->ctrl[0] = ctrl0; + hdr->ctrl[1] = ctrl1; +} + +static void htc_reclaim_txctrl_buf(struct htc_target *target, + struct htc_packet *pkt) +{ + spin_lock_bh(&target->htc_lock); + list_add_tail(&pkt->list, &target->free_ctrl_txbuf); + spin_unlock_bh(&target->htc_lock); +} + +static struct htc_packet *htc_get_control_buf(struct htc_target *target, + bool tx) +{ + struct htc_packet *packet = NULL; + struct list_head *buf_list; + + buf_list = tx ? &target->free_ctrl_txbuf : &target->free_ctrl_rxbuf; + + spin_lock_bh(&target->htc_lock); + + if (list_empty(buf_list)) { + spin_unlock_bh(&target->htc_lock); + return NULL; + } + + packet = list_first_entry(buf_list, struct htc_packet, list); + list_del(&packet->list); + spin_unlock_bh(&target->htc_lock); + + if (tx) + packet->buf = packet->buf_start + HTC_HDR_LENGTH; + + return packet; +} + +static void htc_tx_comp_update(struct htc_target *target, + struct htc_endpoint *endpoint, + struct htc_packet *packet) +{ + packet->completion = NULL; + packet->buf += HTC_HDR_LENGTH; + + if (!packet->status) + return; + + ath6kl_err("req failed (status:%d, ep:%d, len:%d creds:%d)\n", + packet->status, packet->endpoint, packet->act_len, + packet->info.tx.cred_used); + + /* on failure to submit, reclaim credits for this packet */ + spin_lock_bh(&target->tx_lock); + endpoint->cred_dist.cred_to_dist += + packet->info.tx.cred_used; + endpoint->cred_dist.txq_depth = get_queue_depth(&endpoint->txq); + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", + target->cred_dist_cntxt, &target->cred_dist_list); + + ath6k_credit_distribute(target->cred_dist_cntxt, + &target->cred_dist_list, + HTC_CREDIT_DIST_SEND_COMPLETE); + + spin_unlock_bh(&target->tx_lock); +} + +static void htc_tx_complete(struct htc_endpoint *endpoint, + struct list_head *txq) +{ + if (list_empty(txq)) + return; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "send complete ep %d, (%d pkts)\n", + endpoint->eid, get_queue_depth(txq)); + + ath6kl_tx_complete(endpoint->target->dev->ar, txq); +} + +static void htc_tx_comp_handler(struct htc_target *target, + struct htc_packet *packet) +{ + struct htc_endpoint *endpoint = &target->endpoint[packet->endpoint]; + struct list_head container; + + htc_tx_comp_update(target, endpoint, packet); + INIT_LIST_HEAD(&container); + list_add_tail(&packet->list, &container); + /* do completion */ + htc_tx_complete(endpoint, &container); +} + +static void htc_async_tx_scat_complete(struct htc_target *target, + struct hif_scatter_req *scat_req) +{ + struct htc_endpoint *endpoint; + struct htc_packet *packet; + struct list_head tx_compq; + int i; + + INIT_LIST_HEAD(&tx_compq); + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "htc_async_tx_scat_complete total len: %d entries: %d\n", + scat_req->len, scat_req->scat_entries); + + if (scat_req->status) + ath6kl_err("send scatter req failed: %d\n", scat_req->status); + + packet = scat_req->scat_list[0].packet; + endpoint = &target->endpoint[packet->endpoint]; + + /* walk through the scatter list and process */ + for (i = 0; i < scat_req->scat_entries; i++) { + packet = scat_req->scat_list[i].packet; + if (!packet) { + WARN_ON(1); + return; + } + + packet->status = scat_req->status; + htc_tx_comp_update(target, endpoint, packet); + list_add_tail(&packet->list, &tx_compq); + } + + /* free scatter request */ + hif_scatter_req_add(target->dev->ar, scat_req); + + /* complete all packets */ + htc_tx_complete(endpoint, &tx_compq); +} + +static int ath6kl_htc_tx_issue(struct htc_target *target, + struct htc_packet *packet) +{ + int status; + bool sync = false; + u32 padded_len, send_len; + + if (!packet->completion) + sync = true; + + send_len = packet->act_len + HTC_HDR_LENGTH; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s: transmit len : %d (%s)\n", + __func__, send_len, sync ? "sync" : "async"); + + padded_len = CALC_TXRX_PADDED_LEN(target, send_len); + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "DevSendPacket, padded len: %d mbox:0x%X (mode:%s)\n", + padded_len, + target->dev->ar->mbox_info.htc_addr, + sync ? "sync" : "async"); + + if (sync) { + status = hif_read_write_sync(target->dev->ar, + target->dev->ar->mbox_info.htc_addr, + packet->buf, padded_len, + HIF_WR_SYNC_BLOCK_INC); + + packet->status = status; + packet->buf += HTC_HDR_LENGTH; + } else + status = hif_write_async(target->dev->ar, + target->dev->ar->mbox_info.htc_addr, + packet->buf, padded_len, + HIF_WR_ASYNC_BLOCK_INC, packet); + + return status; +} + +static int htc_check_credits(struct htc_target *target, + struct htc_endpoint *ep, u8 *flags, + enum htc_endpoint_id eid, unsigned int len, + int *req_cred) +{ + + *req_cred = (len > target->tgt_cred_sz) ? + DIV_ROUND_UP(len, target->tgt_cred_sz) : 1; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "creds required:%d got:%d\n", + *req_cred, ep->cred_dist.credits); + + if (ep->cred_dist.credits < *req_cred) { + if (eid == ENDPOINT_0) + return -EINVAL; + + /* Seek more credits */ + ep->cred_dist.seek_cred = *req_cred - ep->cred_dist.credits; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", + target->cred_dist_cntxt, &ep->cred_dist); + + ath6k_seek_credits(target->cred_dist_cntxt, &ep->cred_dist); + + ep->cred_dist.seek_cred = 0; + + if (ep->cred_dist.credits < *req_cred) { + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "not enough credits for ep %d - leaving packet in queue\n", + eid); + return -EINVAL; + } + } + + ep->cred_dist.credits -= *req_cred; + ep->ep_st.cred_cosumd += *req_cred; + + /* When we are getting low on credits, ask for more */ + if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) { + ep->cred_dist.seek_cred = + ep->cred_dist.cred_per_msg - ep->cred_dist.credits; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", + target->cred_dist_cntxt, &ep->cred_dist); + + ath6k_seek_credits(target->cred_dist_cntxt, &ep->cred_dist); + + /* see if we were successful in getting more */ + if (ep->cred_dist.credits < ep->cred_dist.cred_per_msg) { + /* tell the target we need credits ASAP! */ + *flags |= HTC_FLAGS_NEED_CREDIT_UPDATE; + ep->ep_st.cred_low_indicate += 1; + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "host needs credits\n"); + } + } + + return 0; +} + +static void ath6kl_htc_tx_pkts_get(struct htc_target *target, + struct htc_endpoint *endpoint, + struct list_head *queue) +{ + int req_cred; + u8 flags; + struct htc_packet *packet; + unsigned int len; + + while (true) { + + flags = 0; + + if (list_empty(&endpoint->txq)) + break; + packet = list_first_entry(&endpoint->txq, struct htc_packet, + list); + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "got head pkt:0x%p , queue depth: %d\n", + packet, get_queue_depth(&endpoint->txq)); + + len = CALC_TXRX_PADDED_LEN(target, + packet->act_len + HTC_HDR_LENGTH); + + if (htc_check_credits(target, endpoint, &flags, + packet->endpoint, len, &req_cred)) + break; + + /* now we can fully move onto caller's queue */ + packet = list_first_entry(&endpoint->txq, struct htc_packet, + list); + list_move_tail(&packet->list, queue); + + /* save the number of credits this packet consumed */ + packet->info.tx.cred_used = req_cred; + + /* all TX packets are handled asynchronously */ + packet->completion = htc_tx_comp_handler; + packet->context = target; + endpoint->ep_st.tx_issued += 1; + + /* save send flags */ + packet->info.tx.flags = flags; + packet->info.tx.seqno = endpoint->seqno; + endpoint->seqno++; + } +} + +/* See if the padded tx length falls on a credit boundary */ +static int htc_get_credit_padding(unsigned int cred_sz, int *len, + struct htc_endpoint *ep) +{ + int rem_cred, cred_pad; + + rem_cred = *len % cred_sz; + + /* No padding needed */ + if (!rem_cred) + return 0; + + if (!(ep->conn_flags & HTC_FLGS_TX_BNDL_PAD_EN)) + return -1; + + /* + * The transfer consumes a "partial" credit, this + * packet cannot be bundled unless we add + * additional "dummy" padding (max 255 bytes) to + * consume the entire credit. + */ + cred_pad = *len < cred_sz ? (cred_sz - *len) : rem_cred; + + if ((cred_pad > 0) && (cred_pad <= 255)) + *len += cred_pad; + else + /* The amount of padding is too large, send as non-bundled */ + return -1; + + return cred_pad; +} + +static int ath6kl_htc_tx_setup_scat_list(struct htc_target *target, + struct htc_endpoint *endpoint, + struct hif_scatter_req *scat_req, + int n_scat, + struct list_head *queue) +{ + struct htc_packet *packet; + int i, len, rem_scat, cred_pad; + int status = 0; + + rem_scat = target->max_tx_bndl_sz; + + for (i = 0; i < n_scat; i++) { + scat_req->scat_list[i].packet = NULL; + + if (list_empty(queue)) + break; + + packet = list_first_entry(queue, struct htc_packet, list); + len = CALC_TXRX_PADDED_LEN(target, + packet->act_len + HTC_HDR_LENGTH); + + cred_pad = htc_get_credit_padding(target->tgt_cred_sz, + &len, endpoint); + if (cred_pad < 0 || rem_scat < len) { + status = -ENOSPC; + break; + } + + rem_scat -= len; + /* now remove it from the queue */ + list_del(&packet->list); + + scat_req->scat_list[i].packet = packet; + /* prepare packet and flag message as part of a send bundle */ + ath6kl_htc_tx_prep_pkt(packet, + packet->info.tx.flags | HTC_FLAGS_SEND_BUNDLE, + cred_pad, packet->info.tx.seqno); + /* Make sure the buffer is 4-byte aligned */ + ath6kl_htc_tx_buf_align(&packet->buf, + packet->act_len + HTC_HDR_LENGTH); + scat_req->scat_list[i].buf = packet->buf; + scat_req->scat_list[i].len = len; + + scat_req->len += len; + scat_req->scat_entries++; + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "%d, adding pkt : 0x%p len:%d (remaining space:%d)\n", + i, packet, len, rem_scat); + } + + /* Roll back scatter setup in case of any failure */ + if (scat_req->scat_entries < HTC_MIN_HTC_MSGS_TO_BUNDLE) { + for (i = scat_req->scat_entries - 1; i >= 0; i--) { + packet = scat_req->scat_list[i].packet; + if (packet) { + packet->buf += HTC_HDR_LENGTH; + list_add(&packet->list, queue); + } + } + return -EAGAIN; + } + + return status; +} + +/* + * Drain a queue and send as bundles this function may return without fully + * draining the queue when + * + * 1. scatter resources are exhausted + * 2. a message that will consume a partial credit will stop the + * bundling process early + * 3. we drop below the minimum number of messages for a bundle + */ +static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, + struct list_head *queue, + int *sent_bundle, int *n_bundle_pkts) +{ + struct htc_target *target = endpoint->target; + struct hif_scatter_req *scat_req = NULL; + int n_scat, n_sent_bundle = 0, tot_pkts_bundle = 0; + int status; + + while (true) { + status = 0; + n_scat = get_queue_depth(queue); + n_scat = min(n_scat, target->msg_per_bndl_max); + + if (n_scat < HTC_MIN_HTC_MSGS_TO_BUNDLE) + /* not enough to bundle */ + break; + + scat_req = hif_scatter_req_get(target->dev->ar); + + if (!scat_req) { + /* no scatter resources */ + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "no more scatter resources\n"); + break; + } + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "pkts to scatter: %d\n", + n_scat); + + scat_req->len = 0; + scat_req->scat_entries = 0; + + status = ath6kl_htc_tx_setup_scat_list(target, endpoint, + scat_req, n_scat, + queue); + if (status == -EAGAIN) { + hif_scatter_req_add(target->dev->ar, scat_req); + break; + } + + /* send path is always asynchronous */ + scat_req->complete = htc_async_tx_scat_complete; + n_sent_bundle++; + tot_pkts_bundle += scat_req->scat_entries; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "send scatter total bytes: %d , entries: %d\n", + scat_req->len, scat_req->scat_entries); + ath6kldev_submit_scat_req(target->dev, scat_req, false); + + if (status) + break; + } + + *sent_bundle = n_sent_bundle; + *n_bundle_pkts = tot_pkts_bundle; + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "%s (sent:%d)\n", + __func__, n_sent_bundle); + + return; +} + +static void ath6kl_htc_tx_from_queue(struct htc_target *target, + struct htc_endpoint *endpoint) +{ + struct list_head txq; + struct htc_packet *packet; + int bundle_sent; + int n_pkts_bundle; + + spin_lock_bh(&target->tx_lock); + + endpoint->tx_proc_cnt++; + if (endpoint->tx_proc_cnt > 1) { + endpoint->tx_proc_cnt--; + spin_unlock_bh(&target->tx_lock); + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "htc_try_send (busy)\n"); + return; + } + + /* + * drain the endpoint TX queue for transmission as long + * as we have enough credits. + */ + INIT_LIST_HEAD(&txq); + + while (true) { + + if (list_empty(&endpoint->txq)) + break; + + ath6kl_htc_tx_pkts_get(target, endpoint, &txq); + + if (list_empty(&txq)) + break; + + spin_unlock_bh(&target->tx_lock); + + bundle_sent = 0; + n_pkts_bundle = 0; + + while (true) { + /* try to send a bundle on each pass */ + if ((target->tx_bndl_enable) && + (get_queue_depth(&txq) >= + HTC_MIN_HTC_MSGS_TO_BUNDLE)) { + int temp1 = 0, temp2 = 0; + + ath6kl_htc_tx_bundle(endpoint, &txq, + &temp1, &temp2); + bundle_sent += temp1; + n_pkts_bundle += temp2; + } + + if (list_empty(&txq)) + break; + + packet = list_first_entry(&txq, struct htc_packet, + list); + list_del(&packet->list); + + ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags, + 0, packet->info.tx.seqno); + ath6kl_htc_tx_issue(target, packet); + } + + spin_lock_bh(&target->tx_lock); + + endpoint->ep_st.tx_bundles += bundle_sent; + endpoint->ep_st.tx_pkt_bundled += n_pkts_bundle; + } + + endpoint->tx_proc_cnt = 0; + spin_unlock_bh(&target->tx_lock); +} + +static bool ath6kl_htc_tx_try(struct htc_target *target, + struct htc_endpoint *endpoint, + struct htc_packet *tx_pkt) +{ + struct htc_ep_callbacks ep_cb; + int txq_depth; + bool overflow = false; + + ep_cb = endpoint->ep_cb; + + spin_lock_bh(&target->tx_lock); + txq_depth = get_queue_depth(&endpoint->txq); + spin_unlock_bh(&target->tx_lock); + + if (txq_depth >= endpoint->max_txq_depth) + overflow = true; + + if (overflow) + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "ep %d, tx queue will overflow :%d , tx depth:%d, max:%d\n", + endpoint->eid, overflow, txq_depth, + endpoint->max_txq_depth); + + if (overflow && ep_cb.tx_full) { + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "indicating overflowed tx packet: 0x%p\n", tx_pkt); + + if (ep_cb.tx_full(endpoint->target, tx_pkt) == + HTC_SEND_FULL_DROP) { + endpoint->ep_st.tx_dropped += 1; + return false; + } + } + + spin_lock_bh(&target->tx_lock); + list_add_tail(&tx_pkt->list, &endpoint->txq); + spin_unlock_bh(&target->tx_lock); + + ath6kl_htc_tx_from_queue(target, endpoint); + + return true; +} + +static void htc_chk_ep_txq(struct htc_target *target) +{ + struct htc_endpoint *endpoint; + struct htc_endpoint_credit_dist *cred_dist; + + /* + * Run through the credit distribution list to see if there are + * packets queued. NOTE: no locks need to be taken since the + * distribution list is not dynamic (cannot be re-ordered) and we + * are not modifying any state. + */ + list_for_each_entry(cred_dist, &target->cred_dist_list, list) { + endpoint = (struct htc_endpoint *)cred_dist->htc_rsvd; + + spin_lock_bh(&target->tx_lock); + if (!list_empty(&endpoint->txq)) { + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "ep %d has %d credits and %d packets in tx queue\n", + cred_dist->endpoint, + endpoint->cred_dist.credits, + get_queue_depth(&endpoint->txq)); + spin_unlock_bh(&target->tx_lock); + /* + * Try to start the stalled queue, this list is + * ordered by priority. If there are credits + * available the highest priority queue will get a + * chance to reclaim credits from lower priority + * ones. + */ + ath6kl_htc_tx_from_queue(target, endpoint); + spin_lock_bh(&target->tx_lock); + } + spin_unlock_bh(&target->tx_lock); + } +} + +static int htc_setup_tx_complete(struct htc_target *target) +{ + struct htc_packet *send_pkt = NULL; + int status; + + send_pkt = htc_get_control_buf(target, true); + + if (!send_pkt) + return -ENOMEM; + + if (target->htc_tgt_ver >= HTC_VERSION_2P1) { + struct htc_setup_comp_ext_msg *setup_comp_ext; + u32 flags = 0; + + setup_comp_ext = + (struct htc_setup_comp_ext_msg *)send_pkt->buf; + memset(setup_comp_ext, 0, sizeof(*setup_comp_ext)); + setup_comp_ext->msg_id = + cpu_to_le16(HTC_MSG_SETUP_COMPLETE_EX_ID); + + if (target->msg_per_bndl_max > 0) { + /* Indicate HTC bundling to the target */ + flags |= HTC_SETUP_COMP_FLG_RX_BNDL_EN; + setup_comp_ext->msg_per_rxbndl = + target->msg_per_bndl_max; + } + + memcpy(&setup_comp_ext->flags, &flags, + sizeof(setup_comp_ext->flags)); + set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp_ext, + sizeof(struct htc_setup_comp_ext_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + + } else { + struct htc_setup_comp_msg *setup_comp; + setup_comp = (struct htc_setup_comp_msg *)send_pkt->buf; + memset(setup_comp, 0, sizeof(struct htc_setup_comp_msg)); + setup_comp->msg_id = cpu_to_le16(HTC_MSG_SETUP_COMPLETE_ID); + set_htc_pkt_info(send_pkt, NULL, (u8 *) setup_comp, + sizeof(struct htc_setup_comp_msg), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + } + + /* we want synchronous operation */ + send_pkt->completion = NULL; + ath6kl_htc_tx_prep_pkt(send_pkt, 0, 0, 0); + status = ath6kl_htc_tx_issue(target, send_pkt); + + if (send_pkt != NULL) + htc_reclaim_txctrl_buf(target, send_pkt); + + return status; +} + +void ath6kl_htc_set_credit_dist(struct htc_target *target, + struct htc_credit_state_info *cred_dist_cntxt, + u16 srvc_pri_order[], int list_len) +{ + struct htc_endpoint *endpoint; + int i, ep; + + target->cred_dist_cntxt = cred_dist_cntxt; + + list_add_tail(&target->endpoint[ENDPOINT_0].cred_dist.list, + &target->cred_dist_list); + + for (i = 0; i < list_len; i++) { + for (ep = ENDPOINT_1; ep < ENDPOINT_MAX; ep++) { + endpoint = &target->endpoint[ep]; + if (endpoint->svc_id == srvc_pri_order[i]) { + list_add_tail(&endpoint->cred_dist.list, + &target->cred_dist_list); + break; + } + } + if (ep >= ENDPOINT_MAX) { + WARN_ON(1); + return; + } + } +} + +int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet) +{ + struct htc_endpoint *endpoint; + struct list_head queue; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "htc_tx: ep id: %d, buf: 0x%p, len: %d\n", + packet->endpoint, packet->buf, packet->act_len); + + if (packet->endpoint >= ENDPOINT_MAX) { + WARN_ON(1); + return -EINVAL; + } + + endpoint = &target->endpoint[packet->endpoint]; + + if (!ath6kl_htc_tx_try(target, endpoint, packet)) { + packet->status = (target->htc_flags & HTC_OP_STATE_STOPPING) ? + -ECANCELED : -ENOSPC; + INIT_LIST_HEAD(&queue); + list_add(&packet->list, &queue); + htc_tx_complete(endpoint, &queue); + } + + return 0; +} + +/* flush endpoint TX queue */ +void ath6kl_htc_flush_txep(struct htc_target *target, + enum htc_endpoint_id eid, u16 tag) +{ + struct htc_packet *packet, *tmp_pkt; + struct list_head discard_q, container; + struct htc_endpoint *endpoint = &target->endpoint[eid]; + + if (!endpoint->svc_id) { + WARN_ON(1); + return; + } + + /* initialize the discard queue */ + INIT_LIST_HEAD(&discard_q); + + spin_lock_bh(&target->tx_lock); + + list_for_each_entry_safe(packet, tmp_pkt, &endpoint->txq, list) { + if ((tag == HTC_TX_PACKET_TAG_ALL) || + (tag == packet->info.tx.tag)) + list_move_tail(&packet->list, &discard_q); + } + + spin_unlock_bh(&target->tx_lock); + + list_for_each_entry_safe(packet, tmp_pkt, &discard_q, list) { + packet->status = -ECANCELED; + list_del(&packet->list); + ath6kl_dbg(ATH6KL_DBG_TRC, + "flushing tx pkt:0x%p, len:%d, ep:%d tag:0x%X\n", + packet, packet->act_len, + packet->endpoint, packet->info.tx.tag); + + INIT_LIST_HEAD(&container); + list_add_tail(&packet->list, &container); + htc_tx_complete(endpoint, &container); + } + +} + +static void ath6kl_htc_flush_txep_all(struct htc_target *target) +{ + struct htc_endpoint *endpoint; + int i; + + dump_cred_dist_stats(target); + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + if (endpoint->svc_id == 0) + /* not in use.. */ + continue; + ath6kl_htc_flush_txep(target, i, HTC_TX_PACKET_TAG_ALL); + } +} + +void ath6kl_htc_indicate_activity_change(struct htc_target *target, + enum htc_endpoint_id eid, bool active) +{ + struct htc_endpoint *endpoint = &target->endpoint[eid]; + bool dist = false; + + if (endpoint->svc_id == 0) { + WARN_ON(1); + return; + } + + spin_lock_bh(&target->tx_lock); + + if (active) { + if (!(endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE)) { + endpoint->cred_dist.dist_flags |= HTC_EP_ACTIVE; + dist = true; + } + } else { + if (endpoint->cred_dist.dist_flags & HTC_EP_ACTIVE) { + endpoint->cred_dist.dist_flags &= ~HTC_EP_ACTIVE; + dist = true; + } + } + + if (dist) { + endpoint->cred_dist.txq_depth = + get_queue_depth(&endpoint->txq); + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", + target->cred_dist_cntxt, &target->cred_dist_list); + + ath6k_credit_distribute(target->cred_dist_cntxt, + &target->cred_dist_list, + HTC_CREDIT_DIST_ACTIVITY_CHANGE); + } + + spin_unlock_bh(&target->tx_lock); + + if (dist && !active) + htc_chk_ep_txq(target); +} + +/* HTC Rx */ + +static inline void ath6kl_htc_rx_update_stats(struct htc_endpoint *endpoint, + int n_look_ahds) +{ + endpoint->ep_st.rx_pkts++; + if (n_look_ahds == 1) + endpoint->ep_st.rx_lkahds++; + else if (n_look_ahds > 1) + endpoint->ep_st.rx_bundle_lkahd++; +} + +static inline bool htc_valid_rx_frame_len(struct htc_target *target, + enum htc_endpoint_id eid, int len) +{ + return (eid == target->dev->ar->ctrl_ep) ? + len <= ATH6KL_BUFFER_SIZE : len <= ATH6KL_AMSDU_BUFFER_SIZE; +} + +static int htc_add_rxbuf(struct htc_target *target, struct htc_packet *packet) +{ + struct list_head queue; + + INIT_LIST_HEAD(&queue); + list_add_tail(&packet->list, &queue); + return ath6kl_htc_add_rxbuf_multiple(target, &queue); +} + +static void htc_reclaim_rxbuf(struct htc_target *target, + struct htc_packet *packet, + struct htc_endpoint *ep) +{ + if (packet->info.rx.rx_flags & HTC_RX_PKT_NO_RECYCLE) { + htc_rxpkt_reset(packet); + packet->status = -ECANCELED; + ep->ep_cb.rx(ep->target, packet); + } else { + htc_rxpkt_reset(packet); + htc_add_rxbuf((void *)(target), packet); + } +} + +static void reclaim_rx_ctrl_buf(struct htc_target *target, + struct htc_packet *packet) +{ + spin_lock_bh(&target->htc_lock); + list_add_tail(&packet->list, &target->free_ctrl_rxbuf); + spin_unlock_bh(&target->htc_lock); +} + +static int ath6kl_htc_rx_packet(struct htc_target *target, + struct htc_packet *packet, + u32 rx_len) +{ + struct ath6kl_device *dev = target->dev; + u32 padded_len; + int status; + + padded_len = CALC_TXRX_PADDED_LEN(target, rx_len); + + if (padded_len > packet->buf_len) { + ath6kl_err("not enough receive space for packet - padlen:%d recvlen:%d bufferlen:%d\n", + padded_len, rx_len, packet->buf_len); + return -ENOMEM; + } + + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "dev_rx_pkt (0x%p : hdr:0x%X) padded len: %d mbox:0x%X (mode:%s)\n", + packet, packet->info.rx.exp_hdr, + padded_len, dev->ar->mbox_info.htc_addr, "sync"); + + status = hif_read_write_sync(dev->ar, + dev->ar->mbox_info.htc_addr, + packet->buf, padded_len, + HIF_RD_SYNC_BLOCK_FIX); + + packet->status = status; + + return status; +} + +/* + * optimization for recv packets, we can indicate a + * "hint" that there are more single-packets to fetch + * on this endpoint. + */ +static void ath6kl_htc_rx_set_indicate(u32 lk_ahd, + struct htc_endpoint *endpoint, + struct htc_packet *packet) +{ + struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)&lk_ahd; + + if (htc_hdr->eid == packet->endpoint) { + if (!list_empty(&endpoint->rx_bufq)) + packet->info.rx.indicat_flags |= + HTC_RX_FLAGS_INDICATE_MORE_PKTS; + } +} + +static void ath6kl_htc_rx_chk_water_mark(struct htc_endpoint *endpoint) +{ + struct htc_ep_callbacks ep_cb = endpoint->ep_cb; + + if (ep_cb.rx_refill_thresh > 0) { + spin_lock_bh(&endpoint->target->rx_lock); + if (get_queue_depth(&endpoint->rx_bufq) + < ep_cb.rx_refill_thresh) { + spin_unlock_bh(&endpoint->target->rx_lock); + ep_cb.rx_refill(endpoint->target, endpoint->eid); + return; + } + spin_unlock_bh(&endpoint->target->rx_lock); + } +} + +/* This function is called with rx_lock held */ +static int ath6kl_htc_rx_setup(struct htc_target *target, + struct htc_endpoint *ep, + u32 *lk_ahds, struct list_head *queue, int n_msg) +{ + struct htc_packet *packet; + /* FIXME: type of lk_ahds can't be right */ + struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)lk_ahds; + struct htc_ep_callbacks ep_cb; + int status = 0, j, full_len; + bool no_recycle; + + full_len = CALC_TXRX_PADDED_LEN(target, + le16_to_cpu(htc_hdr->payld_len) + + sizeof(*htc_hdr)); + + if (!htc_valid_rx_frame_len(target, ep->eid, full_len)) { + ath6kl_warn("Rx buffer requested with invalid length\n"); + return -EINVAL; + } + + ep_cb = ep->ep_cb; + for (j = 0; j < n_msg; j++) { + + /* + * Reset flag, any packets allocated using the + * rx_alloc() API cannot be recycled on + * cleanup,they must be explicitly returned. + */ + no_recycle = false; + + if (ep_cb.rx_allocthresh && + (full_len > ep_cb.rx_alloc_thresh)) { + ep->ep_st.rx_alloc_thresh_hit += 1; + ep->ep_st.rxalloc_thresh_byte += + le16_to_cpu(htc_hdr->payld_len); + + spin_unlock_bh(&target->rx_lock); + no_recycle = true; + + packet = ep_cb.rx_allocthresh(ep->target, ep->eid, + full_len); + spin_lock_bh(&target->rx_lock); + } else { + /* refill handler is being used */ + if (list_empty(&ep->rx_bufq)) { + if (ep_cb.rx_refill) { + spin_unlock_bh(&target->rx_lock); + ep_cb.rx_refill(ep->target, ep->eid); + spin_lock_bh(&target->rx_lock); + } + } + + if (list_empty(&ep->rx_bufq)) + packet = NULL; + else { + packet = list_first_entry(&ep->rx_bufq, + struct htc_packet, list); + list_del(&packet->list); + } + } + + if (!packet) { + target->rx_st_flags |= HTC_RECV_WAIT_BUFFERS; + target->ep_waiting = ep->eid; + return -ENOSPC; + } + + /* clear flags */ + packet->info.rx.rx_flags = 0; + packet->info.rx.indicat_flags = 0; + packet->status = 0; + + if (no_recycle) + /* + * flag that these packets cannot be + * recycled, they have to be returned to + * the user + */ + packet->info.rx.rx_flags |= HTC_RX_PKT_NO_RECYCLE; + + /* Caller needs to free this upon any failure */ + list_add_tail(&packet->list, queue); + + if (target->htc_flags & HTC_OP_STATE_STOPPING) { + status = -ECANCELED; + break; + } + + if (j) { + packet->info.rx.rx_flags |= HTC_RX_PKT_REFRESH_HDR; + packet->info.rx.exp_hdr = 0xFFFFFFFF; + } else + /* set expected look ahead */ + packet->info.rx.exp_hdr = *lk_ahds; + + packet->act_len = le16_to_cpu(htc_hdr->payld_len) + + HTC_HDR_LENGTH; + } + + return status; +} + +static int ath6kl_htc_rx_alloc(struct htc_target *target, + u32 lk_ahds[], int msg, + struct htc_endpoint *endpoint, + struct list_head *queue) +{ + int status = 0; + struct htc_packet *packet, *tmp_pkt; + struct htc_frame_hdr *htc_hdr; + int i, n_msg; + + spin_lock_bh(&target->rx_lock); + + for (i = 0; i < msg; i++) { + + htc_hdr = (struct htc_frame_hdr *)&lk_ahds[i]; + + if (htc_hdr->eid >= ENDPOINT_MAX) { + ath6kl_err("invalid ep in look-ahead: %d\n", + htc_hdr->eid); + status = -ENOMEM; + break; + } + + if (htc_hdr->eid != endpoint->eid) { + ath6kl_err("invalid ep in look-ahead: %d should be : %d (index:%d)\n", + htc_hdr->eid, endpoint->eid, i); + status = -ENOMEM; + break; + } + + if (le16_to_cpu(htc_hdr->payld_len) > HTC_MAX_PAYLOAD_LENGTH) { + ath6kl_err("payload len %d exceeds max htc : %d !\n", + htc_hdr->payld_len, + (u32) HTC_MAX_PAYLOAD_LENGTH); + status = -ENOMEM; + break; + } + + if (endpoint->svc_id == 0) { + ath6kl_err("ep %d is not connected !\n", htc_hdr->eid); + status = -ENOMEM; + break; + } + + if (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) { + /* + * HTC header indicates that every packet to follow + * has the same padded length so that it can be + * optimally fetched as a full bundle. + */ + n_msg = (htc_hdr->flags & HTC_FLG_RX_BNDL_CNT) >> + HTC_FLG_RX_BNDL_CNT_S; + + /* the count doesn't include the starter frame */ + n_msg++; + if (n_msg > target->msg_per_bndl_max) { + status = -ENOMEM; + break; + } + + endpoint->ep_st.rx_bundle_from_hdr += 1; + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "htc hdr indicates :%d msg can be fetched as a bundle\n", + n_msg); + } else + /* HTC header only indicates 1 message to fetch */ + n_msg = 1; + + /* Setup packet buffers for each message */ + status = ath6kl_htc_rx_setup(target, endpoint, &lk_ahds[i], + queue, n_msg); + + /* + * This is due to unavailabilty of buffers to rx entire data. + * Return no error so that free buffers from queue can be used + * to receive partial data. + */ + if (status == -ENOSPC) { + spin_unlock_bh(&target->rx_lock); + return 0; + } + + if (status) + break; + } + + spin_unlock_bh(&target->rx_lock); + + if (status) { + list_for_each_entry_safe(packet, tmp_pkt, queue, list) { + list_del(&packet->list); + htc_reclaim_rxbuf(target, packet, + &target->endpoint[packet->endpoint]); + } + } + + return status; +} + +static void htc_ctrl_rx(struct htc_target *context, struct htc_packet *packets) +{ + if (packets->endpoint != ENDPOINT_0) { + WARN_ON(1); + return; + } + + if (packets->status == -ECANCELED) { + reclaim_rx_ctrl_buf(context, packets); + return; + } + + if (packets->act_len > 0) { + ath6kl_err("htc_ctrl_rx, got message with len:%zu\n", + packets->act_len + HTC_HDR_LENGTH); + + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, + "Unexpected ENDPOINT 0 Message", "", + packets->buf - HTC_HDR_LENGTH, + packets->act_len + HTC_HDR_LENGTH); + } + + htc_reclaim_rxbuf(context, packets, &context->endpoint[0]); +} + +static void htc_proc_cred_rpt(struct htc_target *target, + struct htc_credit_report *rpt, + int n_entries, + enum htc_endpoint_id from_ep) +{ + struct htc_endpoint *endpoint; + int tot_credits = 0, i; + bool dist = false; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "htc_proc_cred_rpt, credit report entries:%d\n", n_entries); + + spin_lock_bh(&target->tx_lock); + + for (i = 0; i < n_entries; i++, rpt++) { + if (rpt->eid >= ENDPOINT_MAX) { + WARN_ON(1); + spin_unlock_bh(&target->tx_lock); + return; + } + + endpoint = &target->endpoint[rpt->eid]; + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, " ep %d got %d credits\n", + rpt->eid, rpt->credits); + + endpoint->ep_st.tx_cred_rpt += 1; + endpoint->ep_st.cred_retnd += rpt->credits; + + if (from_ep == rpt->eid) { + /* + * This credit report arrived on the same endpoint + * indicating it arrived in an RX packet. + */ + endpoint->ep_st.cred_from_rx += rpt->credits; + endpoint->ep_st.cred_rpt_from_rx += 1; + } else if (from_ep == ENDPOINT_0) { + /* credit arrived on endpoint 0 as a NULL message */ + endpoint->ep_st.cred_from_ep0 += rpt->credits; + endpoint->ep_st.cred_rpt_ep0 += 1; + } else { + endpoint->ep_st.cred_from_other += rpt->credits; + endpoint->ep_st.cred_rpt_from_other += 1; + } + + if (rpt->eid == ENDPOINT_0) + /* always give endpoint 0 credits back */ + endpoint->cred_dist.credits += rpt->credits; + else { + endpoint->cred_dist.cred_to_dist += rpt->credits; + dist = true; + } + + /* + * Refresh tx depth for distribution function that will + * recover these credits NOTE: this is only valid when + * there are credits to recover! + */ + endpoint->cred_dist.txq_depth = + get_queue_depth(&endpoint->txq); + + tot_credits += rpt->credits; + } + + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, + "report indicated %d credits to distribute\n", + tot_credits); + + if (dist) { + /* + * This was a credit return based on a completed send + * operations note, this is done with the lock held + */ + ath6kl_dbg(ATH6KL_DBG_HTC_SEND, "ctxt:0x%p dist:0x%p\n", + target->cred_dist_cntxt, &target->cred_dist_list); + + ath6k_credit_distribute(target->cred_dist_cntxt, + &target->cred_dist_list, + HTC_CREDIT_DIST_SEND_COMPLETE); + } + + spin_unlock_bh(&target->tx_lock); + + if (tot_credits) + htc_chk_ep_txq(target); +} + +static int htc_parse_trailer(struct htc_target *target, + struct htc_record_hdr *record, + u8 *record_buf, u32 *next_lk_ahds, + enum htc_endpoint_id endpoint, + int *n_lk_ahds) +{ + struct htc_bundle_lkahd_rpt *bundle_lkahd_rpt; + struct htc_lookahead_report *lk_ahd; + int len; + + switch (record->rec_id) { + case HTC_RECORD_CREDITS: + len = record->len / sizeof(struct htc_credit_report); + if (!len) { + WARN_ON(1); + return -EINVAL; + } + + htc_proc_cred_rpt(target, + (struct htc_credit_report *) record_buf, + len, endpoint); + break; + case HTC_RECORD_LOOKAHEAD: + len = record->len / sizeof(*lk_ahd); + if (!len) { + WARN_ON(1); + return -EINVAL; + } + + lk_ahd = (struct htc_lookahead_report *) record_buf; + if ((lk_ahd->pre_valid == ((~lk_ahd->post_valid) & 0xFF)) + && next_lk_ahds) { + + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "lk_ahd report found (pre valid:0x%X, post valid:0x%X)\n", + lk_ahd->pre_valid, lk_ahd->post_valid); + + /* look ahead bytes are valid, copy them over */ + memcpy((u8 *)&next_lk_ahds[0], lk_ahd->lk_ahd, 4); + + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Next Look Ahead", + "", next_lk_ahds, 4); + + *n_lk_ahds = 1; + } + break; + case HTC_RECORD_LOOKAHEAD_BUNDLE: + len = record->len / sizeof(*bundle_lkahd_rpt); + if (!len || (len > HTC_HOST_MAX_MSG_PER_BUNDLE)) { + WARN_ON(1); + return -EINVAL; + } + + if (next_lk_ahds) { + int i; + + bundle_lkahd_rpt = + (struct htc_bundle_lkahd_rpt *) record_buf; + + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Bundle lk_ahd", + "", record_buf, record->len); + + for (i = 0; i < len; i++) { + memcpy((u8 *)&next_lk_ahds[i], + bundle_lkahd_rpt->lk_ahd, 4); + bundle_lkahd_rpt++; + } + + *n_lk_ahds = i; + } + break; + default: + ath6kl_err("unhandled record: id:%d len:%d\n", + record->rec_id, record->len); + break; + } + + return 0; + +} + +static int htc_proc_trailer(struct htc_target *target, + u8 *buf, int len, u32 *next_lk_ahds, + int *n_lk_ahds, enum htc_endpoint_id endpoint) +{ + struct htc_record_hdr *record; + int orig_len; + int status; + u8 *record_buf; + u8 *orig_buf; + + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "+htc_proc_trailer (len:%d)\n", len); + + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Recv Trailer", "", + buf, len); + + orig_buf = buf; + orig_len = len; + status = 0; + + while (len > 0) { + + if (len < sizeof(struct htc_record_hdr)) { + status = -ENOMEM; + break; + } + /* these are byte aligned structs */ + record = (struct htc_record_hdr *) buf; + len -= sizeof(struct htc_record_hdr); + buf += sizeof(struct htc_record_hdr); + + if (record->len > len) { + ath6kl_err("invalid record len: %d (id:%d) buf has: %d bytes left\n", + record->len, record->rec_id, len); + status = -ENOMEM; + break; + } + record_buf = buf; + + status = htc_parse_trailer(target, record, record_buf, + next_lk_ahds, endpoint, n_lk_ahds); + + if (status) + break; + + /* advance buffer past this record for next time around */ + buf += record->len; + len -= record->len; + } + + if (status) + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD Recv Trailer", + "", orig_buf, orig_len); + + return status; +} + +static int ath6kl_htc_rx_process_hdr(struct htc_target *target, + struct htc_packet *packet, + u32 *next_lkahds, int *n_lkahds) +{ + int status = 0; + u16 payload_len; + u32 lk_ahd; + struct htc_frame_hdr *htc_hdr = (struct htc_frame_hdr *)packet->buf; + + if (n_lkahds != NULL) + *n_lkahds = 0; + + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "HTC Recv PKT", "htc ", + packet->buf, packet->act_len); + + /* + * NOTE: we cannot assume the alignment of buf, so we use the safe + * macros to retrieve 16 bit fields. + */ + payload_len = le16_to_cpu(get_unaligned(&htc_hdr->payld_len)); + + memcpy((u8 *)&lk_ahd, packet->buf, sizeof(lk_ahd)); + + if (packet->info.rx.rx_flags & HTC_RX_PKT_REFRESH_HDR) { + /* + * Refresh the expected header and the actual length as it + * was unknown when this packet was grabbed as part of the + * bundle. + */ + packet->info.rx.exp_hdr = lk_ahd; + packet->act_len = payload_len + HTC_HDR_LENGTH; + + /* validate the actual header that was refreshed */ + if (packet->act_len > packet->buf_len) { + ath6kl_err("refreshed hdr payload len (%d) in bundled recv is invalid (hdr: 0x%X)\n", + payload_len, lk_ahd); + /* + * Limit this to max buffer just to print out some + * of the buffer. + */ + packet->act_len = min(packet->act_len, packet->buf_len); + status = -ENOMEM; + goto fail_rx; + } + + if (packet->endpoint != htc_hdr->eid) { + ath6kl_err("refreshed hdr ep (%d) does not match expected ep (%d)\n", + htc_hdr->eid, packet->endpoint); + status = -ENOMEM; + goto fail_rx; + } + } + + if (lk_ahd != packet->info.rx.exp_hdr) { + ath6kl_err("%s(): lk_ahd mismatch! (pPkt:0x%p flags:0x%X)\n", + __func__, packet, packet->info.rx.rx_flags); + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Expected Message lk_ahd", + "", &packet->info.rx.exp_hdr, 4); + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "Current Frame Header", + "", (u8 *)&lk_ahd, sizeof(lk_ahd)); + status = -ENOMEM; + goto fail_rx; + } + + if (htc_hdr->flags & HTC_FLG_RX_TRAILER) { + if (htc_hdr->ctrl[0] < sizeof(struct htc_record_hdr) || + htc_hdr->ctrl[0] > payload_len) { + ath6kl_err("%s(): invalid hdr (payload len should be :%d, CB[0] is:%d)\n", + __func__, payload_len, htc_hdr->ctrl[0]); + status = -ENOMEM; + goto fail_rx; + } + + if (packet->info.rx.rx_flags & HTC_RX_PKT_IGNORE_LOOKAHEAD) { + next_lkahds = NULL; + n_lkahds = NULL; + } + + status = htc_proc_trailer(target, packet->buf + HTC_HDR_LENGTH + + payload_len - htc_hdr->ctrl[0], + htc_hdr->ctrl[0], next_lkahds, + n_lkahds, packet->endpoint); + + if (status) + goto fail_rx; + + packet->act_len -= htc_hdr->ctrl[0]; + } + + packet->buf += HTC_HDR_LENGTH; + packet->act_len -= HTC_HDR_LENGTH; + +fail_rx: + if (status) + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, "BAD HTC Recv PKT", + "", packet->buf, + packet->act_len < 256 ? packet->act_len : 256); + else { + if (packet->act_len > 0) + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, + "HTC - Application Msg", "", + packet->buf, packet->act_len); + } + + return status; +} + +static void ath6kl_htc_rx_complete(struct htc_endpoint *endpoint, + struct htc_packet *packet) +{ + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "htc calling ep %d recv callback on packet 0x%p\n", + endpoint->eid, packet); + endpoint->ep_cb.rx(endpoint->target, packet); +} + +static int ath6kl_htc_rx_bundle(struct htc_target *target, + struct list_head *rxq, + struct list_head *sync_compq, + int *n_pkt_fetched, bool part_bundle) +{ + struct hif_scatter_req *scat_req; + struct htc_packet *packet; + int rem_space = target->max_rx_bndl_sz; + int n_scat_pkt, status = 0, i, len; + + n_scat_pkt = get_queue_depth(rxq); + n_scat_pkt = min(n_scat_pkt, target->msg_per_bndl_max); + + if ((get_queue_depth(rxq) - n_scat_pkt) > 0) { + /* + * We were forced to split this bundle receive operation + * all packets in this partial bundle must have their + * lookaheads ignored. + */ + part_bundle = true; + + /* + * This would only happen if the target ignored our max + * bundle limit. + */ + ath6kl_warn("%s(): partial bundle detected num:%d , %d\n", + __func__, get_queue_depth(rxq), n_scat_pkt); + } + + len = 0; + + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "%s(): (numpackets: %d , actual : %d)\n", + __func__, get_queue_depth(rxq), n_scat_pkt); + + scat_req = hif_scatter_req_get(target->dev->ar); + + if (scat_req == NULL) + goto fail_rx_pkt; + + for (i = 0; i < n_scat_pkt; i++) { + int pad_len; + + packet = list_first_entry(rxq, struct htc_packet, list); + list_del(&packet->list); + + pad_len = CALC_TXRX_PADDED_LEN(target, + packet->act_len); + + if ((rem_space - pad_len) < 0) { + list_add(&packet->list, rxq); + break; + } + + rem_space -= pad_len; + + if (part_bundle || (i < (n_scat_pkt - 1))) + /* + * Packet 0..n-1 cannot be checked for look-aheads + * since we are fetching a bundle the last packet + * however can have it's lookahead used + */ + packet->info.rx.rx_flags |= + HTC_RX_PKT_IGNORE_LOOKAHEAD; + + /* NOTE: 1 HTC packet per scatter entry */ + scat_req->scat_list[i].buf = packet->buf; + scat_req->scat_list[i].len = pad_len; + + packet->info.rx.rx_flags |= HTC_RX_PKT_PART_OF_BUNDLE; + + list_add_tail(&packet->list, sync_compq); + + WARN_ON(!scat_req->scat_list[i].len); + len += scat_req->scat_list[i].len; + } + + scat_req->len = len; + scat_req->scat_entries = i; + + status = ath6kldev_submit_scat_req(target->dev, scat_req, true); + + if (!status) + *n_pkt_fetched = i; + + /* free scatter request */ + hif_scatter_req_add(target->dev->ar, scat_req); + +fail_rx_pkt: + + return status; +} + +static int ath6kl_htc_rx_process_packets(struct htc_target *target, + struct list_head *comp_pktq, + u32 lk_ahds[], + int *n_lk_ahd) +{ + struct htc_packet *packet, *tmp_pkt; + struct htc_endpoint *ep; + int status = 0; + + list_for_each_entry_safe(packet, tmp_pkt, comp_pktq, list) { + list_del(&packet->list); + ep = &target->endpoint[packet->endpoint]; + + /* process header for each of the recv packet */ + status = ath6kl_htc_rx_process_hdr(target, packet, lk_ahds, + n_lk_ahd); + if (status) + return status; + + if (list_empty(comp_pktq)) { + /* + * Last packet's more packet flag is set + * based on the lookahead. + */ + if (*n_lk_ahd > 0) + ath6kl_htc_rx_set_indicate(lk_ahds[0], + ep, packet); + } else + /* + * Packets in a bundle automatically have + * this flag set. + */ + packet->info.rx.indicat_flags |= + HTC_RX_FLAGS_INDICATE_MORE_PKTS; + + ath6kl_htc_rx_update_stats(ep, *n_lk_ahd); + + if (packet->info.rx.rx_flags & HTC_RX_PKT_PART_OF_BUNDLE) + ep->ep_st.rx_bundl += 1; + + ath6kl_htc_rx_complete(ep, packet); + } + + return status; +} + +static int ath6kl_htc_rx_fetch(struct htc_target *target, + struct list_head *rx_pktq, + struct list_head *comp_pktq) +{ + int fetched_pkts; + bool part_bundle = false; + int status = 0; + + /* now go fetch the list of HTC packets */ + while (!list_empty(rx_pktq)) { + fetched_pkts = 0; + + if (target->rx_bndl_enable && (get_queue_depth(rx_pktq) > 1)) { + /* + * There are enough packets to attempt a + * bundle transfer and recv bundling is + * allowed. + */ + status = ath6kl_htc_rx_bundle(target, rx_pktq, + comp_pktq, + &fetched_pkts, + part_bundle); + if (status) + return status; + + if (!list_empty(rx_pktq)) + part_bundle = true; + } + + if (!fetched_pkts) { + struct htc_packet *packet; + + packet = list_first_entry(rx_pktq, struct htc_packet, + list); + + list_del(&packet->list); + + /* fully synchronous */ + packet->completion = NULL; + + if (!list_empty(rx_pktq)) + /* + * look_aheads in all packet + * except the last one in the + * bundle must be ignored + */ + packet->info.rx.rx_flags |= + HTC_RX_PKT_IGNORE_LOOKAHEAD; + + /* go fetch the packet */ + status = ath6kl_htc_rx_packet(target, packet, + packet->act_len); + if (status) + return status; + + list_add_tail(&packet->list, comp_pktq); + } + } + + return status; +} + +int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, + u32 msg_look_ahead[], int *num_pkts) +{ + struct htc_packet *packets, *tmp_pkt; + struct htc_endpoint *endpoint; + struct list_head rx_pktq, comp_pktq; + int status = 0; + u32 look_aheads[HTC_HOST_MAX_MSG_PER_BUNDLE]; + int num_look_ahead = 1; + enum htc_endpoint_id id; + int n_fetched = 0; + + *num_pkts = 0; + + /* + * On first entry copy the look_aheads into our temp array for + * processing + */ + memcpy(look_aheads, msg_look_ahead, sizeof(look_aheads)); + + while (true) { + + /* + * First lookahead sets the expected endpoint IDs for all + * packets in a bundle. + */ + id = ((struct htc_frame_hdr *)&look_aheads[0])->eid; + endpoint = &target->endpoint[id]; + + if (id >= ENDPOINT_MAX) { + ath6kl_err("MsgPend, invalid endpoint in look-ahead: %d\n", + id); + status = -ENOMEM; + break; + } + + INIT_LIST_HEAD(&rx_pktq); + INIT_LIST_HEAD(&comp_pktq); + + /* + * Try to allocate as many HTC RX packets indicated by the + * look_aheads. + */ + status = ath6kl_htc_rx_alloc(target, look_aheads, + num_look_ahead, endpoint, + &rx_pktq); + if (status) + break; + + if (get_queue_depth(&rx_pktq) >= 2) + /* + * A recv bundle was detected, force IRQ status + * re-check again + */ + target->chk_irq_status_cnt = 1; + + n_fetched += get_queue_depth(&rx_pktq); + + num_look_ahead = 0; + + status = ath6kl_htc_rx_fetch(target, &rx_pktq, &comp_pktq); + + if (!status) + ath6kl_htc_rx_chk_water_mark(endpoint); + + /* Process fetched packets */ + status = ath6kl_htc_rx_process_packets(target, &comp_pktq, + look_aheads, + &num_look_ahead); + + if (!num_look_ahead || status) + break; + + /* + * For SYNCH processing, if we get here, we are running + * through the loop again due to a detected lookahead. Set + * flag that we should re-check IRQ status registers again + * before leaving IRQ processing, this can net better + * performance in high throughput situations. + */ + target->chk_irq_status_cnt = 1; + } + + if (status) { + ath6kl_err("failed to get pending recv messages: %d\n", + status); + /* + * Cleanup any packets we allocated but didn't use to + * actually fetch any packets. + */ + list_for_each_entry_safe(packets, tmp_pkt, &rx_pktq, list) { + list_del(&packets->list); + htc_reclaim_rxbuf(target, packets, + &target->endpoint[packets->endpoint]); + } + + /* cleanup any packets in sync completion queue */ + list_for_each_entry_safe(packets, tmp_pkt, &comp_pktq, list) { + list_del(&packets->list); + htc_reclaim_rxbuf(target, packets, + &target->endpoint[packets->endpoint]); + } + + if (target->htc_flags & HTC_OP_STATE_STOPPING) { + ath6kl_warn("host is going to stop blocking receiver for htc_stop\n"); + ath6kldev_rx_control(target->dev, false); + } + } + + /* + * Before leaving, check to see if host ran out of buffers and + * needs to stop the receiver. + */ + if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { + ath6kl_warn("host has no rx buffers blocking receiver to prevent overrun\n"); + ath6kldev_rx_control(target->dev, false); + } + *num_pkts = n_fetched; + + return status; +} + +/* + * Synchronously wait for a control message from the target, + * This function is used at initialization time ONLY. At init messages + * on ENDPOINT 0 are expected. + */ +static struct htc_packet *htc_wait_for_ctrl_msg(struct htc_target *target) +{ + struct htc_packet *packet = NULL; + struct htc_frame_hdr *htc_hdr; + u32 look_ahead; + + if (ath6kldev_poll_mboxmsg_rx(target->dev, &look_ahead, + HTC_TARGET_RESPONSE_TIMEOUT)) + return NULL; + + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "htc_wait_for_ctrl_msg: look_ahead : 0x%X\n", look_ahead); + + htc_hdr = (struct htc_frame_hdr *)&look_ahead; + + if (htc_hdr->eid != ENDPOINT_0) + return NULL; + + packet = htc_get_control_buf(target, false); + + if (!packet) + return NULL; + + packet->info.rx.rx_flags = 0; + packet->info.rx.exp_hdr = look_ahead; + packet->act_len = le16_to_cpu(htc_hdr->payld_len) + HTC_HDR_LENGTH; + + if (packet->act_len > packet->buf_len) + goto fail_ctrl_rx; + + /* we want synchronous operation */ + packet->completion = NULL; + + /* get the message from the device, this will block */ + if (ath6kl_htc_rx_packet(target, packet, packet->act_len)) + goto fail_ctrl_rx; + + /* process receive header */ + packet->status = ath6kl_htc_rx_process_hdr(target, packet, NULL, NULL); + + if (packet->status) { + ath6kl_err("htc_wait_for_ctrl_msg, ath6kl_htc_rx_process_hdr failed (status = %d)\n", + packet->status); + goto fail_ctrl_rx; + } + + return packet; + +fail_ctrl_rx: + if (packet != NULL) { + htc_rxpkt_reset(packet); + reclaim_rx_ctrl_buf(target, packet); + } + + return NULL; +} + +int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, + struct list_head *pkt_queue) +{ + struct htc_endpoint *endpoint; + struct htc_packet *first_pkt; + bool rx_unblock = false; + int status = 0, depth; + + if (list_empty(pkt_queue)) + return -ENOMEM; + + first_pkt = list_first_entry(pkt_queue, struct htc_packet, list); + + if (first_pkt->endpoint >= ENDPOINT_MAX) + return status; + + depth = get_queue_depth(pkt_queue); + + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "htc_add_rxbuf_multiple: ep id: %d, cnt:%d, len: %d\n", + first_pkt->endpoint, depth, first_pkt->buf_len); + + endpoint = &target->endpoint[first_pkt->endpoint]; + + if (target->htc_flags & HTC_OP_STATE_STOPPING) { + struct htc_packet *packet, *tmp_pkt; + + /* walk through queue and mark each one canceled */ + list_for_each_entry_safe(packet, tmp_pkt, pkt_queue, list) { + packet->status = -ECANCELED; + list_del(&packet->list); + ath6kl_htc_rx_complete(endpoint, packet); + } + + return status; + } + + spin_lock_bh(&target->rx_lock); + + list_splice_tail_init(pkt_queue, &endpoint->rx_bufq); + + /* check if we are blocked waiting for a new buffer */ + if (target->rx_st_flags & HTC_RECV_WAIT_BUFFERS) { + if (target->ep_waiting == first_pkt->endpoint) { + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "receiver was blocked on ep:%d, unblocking.\n", + target->ep_waiting); + target->rx_st_flags &= ~HTC_RECV_WAIT_BUFFERS; + target->ep_waiting = ENDPOINT_MAX; + rx_unblock = true; + } + } + + spin_unlock_bh(&target->rx_lock); + + if (rx_unblock && !(target->htc_flags & HTC_OP_STATE_STOPPING)) + /* TODO : implement a buffer threshold count? */ + ath6kldev_rx_control(target->dev, true); + + return status; +} + +void ath6kl_htc_flush_rx_buf(struct htc_target *target) +{ + struct htc_endpoint *endpoint; + struct htc_packet *packet, *tmp_pkt; + int i; + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + if (!endpoint->svc_id) + /* not in use.. */ + continue; + + spin_lock_bh(&target->rx_lock); + list_for_each_entry_safe(packet, tmp_pkt, + &endpoint->rx_bufq, list) { + list_del(&packet->list); + spin_unlock_bh(&target->rx_lock); + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "flushing rx pkt:0x%p, len:%d, ep:%d\n", + packet, packet->buf_len, + packet->endpoint); + dev_kfree_skb(packet->pkt_cntxt); + spin_lock_bh(&target->rx_lock); + } + spin_unlock_bh(&target->rx_lock); + } +} + +int ath6kl_htc_conn_service(struct htc_target *target, + struct htc_service_connect_req *conn_req, + struct htc_service_connect_resp *conn_resp) +{ + struct htc_packet *rx_pkt = NULL; + struct htc_packet *tx_pkt = NULL; + struct htc_conn_service_resp *resp_msg; + struct htc_conn_service_msg *conn_msg; + struct htc_endpoint *endpoint; + enum htc_endpoint_id assigned_ep = ENDPOINT_MAX; + unsigned int max_msg_sz = 0; + int status = 0; + + ath6kl_dbg(ATH6KL_DBG_TRC, + "htc_conn_service, target:0x%p service id:0x%X\n", + target, conn_req->svc_id); + + if (conn_req->svc_id == HTC_CTRL_RSVD_SVC) { + /* special case for pseudo control service */ + assigned_ep = ENDPOINT_0; + max_msg_sz = HTC_MAX_CTRL_MSG_LEN; + } else { + /* allocate a packet to send to the target */ + tx_pkt = htc_get_control_buf(target, true); + + if (!tx_pkt) + return -ENOMEM; + + conn_msg = (struct htc_conn_service_msg *)tx_pkt->buf; + memset(conn_msg, 0, sizeof(*conn_msg)); + conn_msg->msg_id = cpu_to_le16(HTC_MSG_CONN_SVC_ID); + conn_msg->svc_id = cpu_to_le16(conn_req->svc_id); + conn_msg->conn_flags = cpu_to_le16(conn_req->conn_flags); + + set_htc_pkt_info(tx_pkt, NULL, (u8 *) conn_msg, + sizeof(*conn_msg) + conn_msg->svc_meta_len, + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + + /* we want synchronous operation */ + tx_pkt->completion = NULL; + ath6kl_htc_tx_prep_pkt(tx_pkt, 0, 0, 0); + status = ath6kl_htc_tx_issue(target, tx_pkt); + + if (status) + goto fail_tx; + + /* wait for response */ + rx_pkt = htc_wait_for_ctrl_msg(target); + + if (!rx_pkt) { + status = -ENOMEM; + goto fail_tx; + } + + resp_msg = (struct htc_conn_service_resp *)rx_pkt->buf; + + if ((le16_to_cpu(resp_msg->msg_id) != HTC_MSG_CONN_SVC_RESP_ID) + || (rx_pkt->act_len < sizeof(*resp_msg))) { + status = -ENOMEM; + goto fail_tx; + } + + conn_resp->resp_code = resp_msg->status; + /* check response status */ + if (resp_msg->status != HTC_SERVICE_SUCCESS) { + ath6kl_err("target failed service 0x%X connect request (status:%d)\n", + resp_msg->svc_id, resp_msg->status); + status = -ENOMEM; + goto fail_tx; + } + + assigned_ep = (enum htc_endpoint_id)resp_msg->eid; + max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz); + } + + if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) { + status = -ENOMEM; + goto fail_tx; + } + + endpoint = &target->endpoint[assigned_ep]; + endpoint->eid = assigned_ep; + if (endpoint->svc_id) { + status = -ENOMEM; + goto fail_tx; + } + + /* return assigned endpoint to caller */ + conn_resp->endpoint = assigned_ep; + conn_resp->len_max = max_msg_sz; + + /* setup the endpoint */ + + /* this marks the endpoint in use */ + endpoint->svc_id = conn_req->svc_id; + + endpoint->max_txq_depth = conn_req->max_txq_depth; + endpoint->len_max = max_msg_sz; + endpoint->ep_cb = conn_req->ep_cb; + endpoint->cred_dist.svc_id = conn_req->svc_id; + endpoint->cred_dist.htc_rsvd = endpoint; + endpoint->cred_dist.endpoint = assigned_ep; + endpoint->cred_dist.cred_sz = target->tgt_cred_sz; + + if (conn_req->max_rxmsg_sz) { + /* + * Override cred_per_msg calculation, this optimizes + * the credit-low indications since the host will actually + * issue smaller messages in the Send path. + */ + if (conn_req->max_rxmsg_sz > max_msg_sz) { + status = -ENOMEM; + goto fail_tx; + } + endpoint->cred_dist.cred_per_msg = + conn_req->max_rxmsg_sz / target->tgt_cred_sz; + } else + endpoint->cred_dist.cred_per_msg = + max_msg_sz / target->tgt_cred_sz; + + if (!endpoint->cred_dist.cred_per_msg) + endpoint->cred_dist.cred_per_msg = 1; + + /* save local connection flags */ + endpoint->conn_flags = conn_req->flags; + +fail_tx: + if (tx_pkt) + htc_reclaim_txctrl_buf(target, tx_pkt); + + if (rx_pkt) { + htc_rxpkt_reset(rx_pkt); + reclaim_rx_ctrl_buf(target, rx_pkt); + } + + return status; +} + +static void reset_ep_state(struct htc_target *target) +{ + struct htc_endpoint *endpoint; + int i; + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + memset(&endpoint->cred_dist, 0, sizeof(endpoint->cred_dist)); + endpoint->svc_id = 0; + endpoint->len_max = 0; + endpoint->max_txq_depth = 0; + memset(&endpoint->ep_st, 0, + sizeof(endpoint->ep_st)); + INIT_LIST_HEAD(&endpoint->rx_bufq); + INIT_LIST_HEAD(&endpoint->txq); + endpoint->target = target; + } + + /* reset distribution list */ + INIT_LIST_HEAD(&target->cred_dist_list); +} + +int ath6kl_htc_get_rxbuf_num(struct htc_target *target, + enum htc_endpoint_id endpoint) +{ + int num; + + spin_lock_bh(&target->rx_lock); + num = get_queue_depth(&(target->endpoint[endpoint].rx_bufq)); + spin_unlock_bh(&target->rx_lock); + return num; +} + +static void htc_setup_msg_bndl(struct htc_target *target) +{ + /* limit what HTC can handle */ + target->msg_per_bndl_max = min(HTC_HOST_MAX_MSG_PER_BUNDLE, + target->msg_per_bndl_max); + + if (ath6kl_hif_enable_scatter(target->dev->ar)) { + target->msg_per_bndl_max = 0; + return; + } + + /* limit bundle what the device layer can handle */ + target->msg_per_bndl_max = min(target->max_scat_entries, + target->msg_per_bndl_max); + + ath6kl_dbg(ATH6KL_DBG_TRC, + "htc bundling allowed. max msg per htc bundle: %d\n", + target->msg_per_bndl_max); + + /* Max rx bundle size is limited by the max tx bundle size */ + target->max_rx_bndl_sz = target->max_xfer_szper_scatreq; + /* Max tx bundle size if limited by the extended mbox address range */ + target->max_tx_bndl_sz = min(HIF_MBOX0_EXT_WIDTH, + target->max_xfer_szper_scatreq); + + ath6kl_dbg(ATH6KL_DBG_ANY, "max recv: %d max send: %d\n", + target->max_rx_bndl_sz, target->max_tx_bndl_sz); + + if (target->max_tx_bndl_sz) + target->tx_bndl_enable = true; + + if (target->max_rx_bndl_sz) + target->rx_bndl_enable = true; + + if ((target->tgt_cred_sz % target->block_sz) != 0) { + ath6kl_warn("credit size: %d is not block aligned! Disabling send bundling\n", + target->tgt_cred_sz); + + /* + * Disallow send bundling since the credit size is + * not aligned to a block size the I/O block + * padding will spill into the next credit buffer + * which is fatal. + */ + target->tx_bndl_enable = false; + } +} + +int ath6kl_htc_wait_target(struct htc_target *target) +{ + struct htc_packet *packet = NULL; + struct htc_ready_ext_msg *rdy_msg; + struct htc_service_connect_req connect; + struct htc_service_connect_resp resp; + int status; + + /* we should be getting 1 control message that the target is ready */ + packet = htc_wait_for_ctrl_msg(target); + + if (!packet) + return -ENOMEM; + + /* we controlled the buffer creation so it's properly aligned */ + rdy_msg = (struct htc_ready_ext_msg *)packet->buf; + + if ((le16_to_cpu(rdy_msg->ver2_0_info.msg_id) != HTC_MSG_READY_ID) || + (packet->act_len < sizeof(struct htc_ready_msg))) { + status = -ENOMEM; + goto fail_wait_target; + } + + if (!rdy_msg->ver2_0_info.cred_cnt || !rdy_msg->ver2_0_info.cred_sz) { + status = -ENOMEM; + goto fail_wait_target; + } + + target->tgt_creds = le16_to_cpu(rdy_msg->ver2_0_info.cred_cnt); + target->tgt_cred_sz = le16_to_cpu(rdy_msg->ver2_0_info.cred_sz); + + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "target ready: credits: %d credit size: %d\n", + target->tgt_creds, target->tgt_cred_sz); + + /* check if this is an extended ready message */ + if (packet->act_len >= sizeof(struct htc_ready_ext_msg)) { + /* this is an extended message */ + target->htc_tgt_ver = rdy_msg->htc_ver; + target->msg_per_bndl_max = rdy_msg->msg_per_htc_bndl; + } else { + /* legacy */ + target->htc_tgt_ver = HTC_VERSION_2P0; + target->msg_per_bndl_max = 0; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "using htc protocol version : %s (%d)\n", + (target->htc_tgt_ver == HTC_VERSION_2P0) ? "2.0" : ">= 2.1", + target->htc_tgt_ver); + + if (target->msg_per_bndl_max > 0) + htc_setup_msg_bndl(target); + + /* setup our pseudo HTC control endpoint connection */ + memset(&connect, 0, sizeof(connect)); + memset(&resp, 0, sizeof(resp)); + connect.ep_cb.rx = htc_ctrl_rx; + connect.ep_cb.rx_refill = NULL; + connect.ep_cb.tx_full = NULL; + connect.max_txq_depth = NUM_CONTROL_BUFFERS; + connect.svc_id = HTC_CTRL_RSVD_SVC; + + /* connect fake service */ + status = ath6kl_htc_conn_service((void *)target, &connect, &resp); + + if (status) + ath6kl_hif_cleanup_scatter(target->dev->ar); + +fail_wait_target: + if (packet) { + htc_rxpkt_reset(packet); + reclaim_rx_ctrl_buf(target, packet); + } + + return status; +} + +/* + * Start HTC, enable interrupts and let the target know + * host has finished setup. + */ +int ath6kl_htc_start(struct htc_target *target) +{ + struct htc_packet *packet; + int status; + + /* Disable interrupts at the chip level */ + ath6kldev_disable_intrs(target->dev); + + target->htc_flags = 0; + target->rx_st_flags = 0; + + /* Push control receive buffers into htc control endpoint */ + while ((packet = htc_get_control_buf(target, false)) != NULL) { + status = htc_add_rxbuf(target, packet); + if (status) + return status; + } + + /* NOTE: the first entry in the distribution list is ENDPOINT_0 */ + ath6k_credit_init(target->cred_dist_cntxt, &target->cred_dist_list, + target->tgt_creds); + + dump_cred_dist_stats(target); + + /* Indicate to the target of the setup completion */ + status = htc_setup_tx_complete(target); + + if (status) + return status; + + /* unmask interrupts */ + status = ath6kldev_unmask_intrs(target->dev); + + if (status) + ath6kl_htc_stop(target); + + return status; +} + +/* htc_stop: stop interrupt reception, and flush all queued buffers */ +void ath6kl_htc_stop(struct htc_target *target) +{ + spin_lock_bh(&target->htc_lock); + target->htc_flags |= HTC_OP_STATE_STOPPING; + spin_unlock_bh(&target->htc_lock); + + /* + * Masking interrupts is a synchronous operation, when this + * function returns all pending HIF I/O has completed, we can + * safely flush the queues. + */ + ath6kldev_mask_intrs(target->dev); + + ath6kl_htc_flush_txep_all(target); + + ath6kl_htc_flush_rx_buf(target); + + reset_ep_state(target); +} + +void *ath6kl_htc_create(struct ath6kl *ar) +{ + struct htc_target *target = NULL; + struct htc_packet *packet; + int status = 0, i = 0; + u32 block_size, ctrl_bufsz; + + target = kzalloc(sizeof(*target), GFP_KERNEL); + if (!target) { + ath6kl_err("unable to allocate memory\n"); + return NULL; + } + + target->dev = kzalloc(sizeof(*target->dev), GFP_KERNEL); + if (!target->dev) { + ath6kl_err("unable to allocate memory\n"); + status = -ENOMEM; + goto fail_create_htc; + } + + spin_lock_init(&target->htc_lock); + spin_lock_init(&target->rx_lock); + spin_lock_init(&target->tx_lock); + + INIT_LIST_HEAD(&target->free_ctrl_txbuf); + INIT_LIST_HEAD(&target->free_ctrl_rxbuf); + INIT_LIST_HEAD(&target->cred_dist_list); + + target->dev->ar = ar; + target->dev->htc_cnxt = target; + target->ep_waiting = ENDPOINT_MAX; + + reset_ep_state(target); + + status = ath6kldev_setup(target->dev); + + if (status) + goto fail_create_htc; + + block_size = ar->mbox_info.block_size; + + ctrl_bufsz = (block_size > HTC_MAX_CTRL_MSG_LEN) ? + (block_size + HTC_HDR_LENGTH) : + (HTC_MAX_CTRL_MSG_LEN + HTC_HDR_LENGTH); + + for (i = 0; i < NUM_CONTROL_BUFFERS; i++) { + packet = kzalloc(sizeof(*packet), GFP_KERNEL); + if (!packet) + break; + + packet->buf_start = kzalloc(ctrl_bufsz, GFP_KERNEL); + if (!packet->buf_start) { + kfree(packet); + break; + } + + packet->buf_len = ctrl_bufsz; + if (i < NUM_CONTROL_RX_BUFFERS) { + packet->act_len = 0; + packet->buf = packet->buf_start; + packet->endpoint = ENDPOINT_0; + list_add_tail(&packet->list, &target->free_ctrl_rxbuf); + } else + list_add_tail(&packet->list, &target->free_ctrl_txbuf); + } + +fail_create_htc: + if (i != NUM_CONTROL_BUFFERS || status) { + if (target) { + ath6kl_htc_cleanup(target); + target = NULL; + } + } + + return target; +} + +/* cleanup the HTC instance */ +void ath6kl_htc_cleanup(struct htc_target *target) +{ + struct htc_packet *packet, *tmp_packet; + + ath6kl_hif_cleanup_scatter(target->dev->ar); + + list_for_each_entry_safe(packet, tmp_packet, + &target->free_ctrl_txbuf, list) { + list_del(&packet->list); + kfree(packet->buf_start); + kfree(packet); + } + + list_for_each_entry_safe(packet, tmp_packet, + &target->free_ctrl_rxbuf, list) { + list_del(&packet->list); + kfree(packet->buf_start); + kfree(packet); + } + + kfree(target->dev); + kfree(target); +} diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h new file mode 100644 index 000000000000..8ce0c2c07ded --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -0,0 +1,607 @@ +/* + * 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. + */ + +#ifndef HTC_H +#define HTC_H + +#include "common.h" + +/* frame header flags */ + +/* send direction */ +#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0) +#define HTC_FLAGS_SEND_BUNDLE (1 << 1) + +/* receive direction */ +#define HTC_FLG_RX_UNUSED (1 << 0) +#define HTC_FLG_RX_TRAILER (1 << 1) +/* Bundle count maske and shift */ +#define HTC_FLG_RX_BNDL_CNT (0xF0) +#define HTC_FLG_RX_BNDL_CNT_S 4 + +#define HTC_HDR_LENGTH (sizeof(struct htc_frame_hdr)) +#define HTC_MAX_PAYLOAD_LENGTH (4096 - sizeof(struct htc_frame_hdr)) + +/* HTC control message IDs */ + +#define HTC_MSG_READY_ID 1 +#define HTC_MSG_CONN_SVC_ID 2 +#define HTC_MSG_CONN_SVC_RESP_ID 3 +#define HTC_MSG_SETUP_COMPLETE_ID 4 +#define HTC_MSG_SETUP_COMPLETE_EX_ID 5 + +#define HTC_MAX_CTRL_MSG_LEN 256 + +#define HTC_VERSION_2P0 0x00 +#define HTC_VERSION_2P1 0x01 + +#define HTC_SERVICE_META_DATA_MAX_LENGTH 128 + +#define HTC_CONN_FLGS_THRESH_LVL_QUAT 0x0 +#define HTC_CONN_FLGS_THRESH_LVL_HALF 0x1 +#define HTC_CONN_FLGS_THRESH_LVL_THREE_QUAT 0x2 +#define HTC_CONN_FLGS_REDUCE_CRED_DRIB 0x4 +#define HTC_CONN_FLGS_THRESH_MASK 0x3 + +/* connect response status codes */ +#define HTC_SERVICE_SUCCESS 0 +#define HTC_SERVICE_NOT_FOUND 1 +#define HTC_SERVICE_FAILED 2 + +/* no resources (i.e. no more endpoints) */ +#define HTC_SERVICE_NO_RESOURCES 3 + +/* specific service is not allowing any more endpoints */ +#define HTC_SERVICE_NO_MORE_EP 4 + +/* report record IDs */ +#define HTC_RECORD_NULL 0 +#define HTC_RECORD_CREDITS 1 +#define HTC_RECORD_LOOKAHEAD 2 +#define HTC_RECORD_LOOKAHEAD_BUNDLE 3 + +#define HTC_SETUP_COMP_FLG_RX_BNDL_EN (1 << 0) + +#define MAKE_SERVICE_ID(group, index) \ + (int)(((int)group << 8) | (int)(index)) + +/* NOTE: service ID of 0x0000 is reserved and should never be used */ +#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP, 1) +#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 0) +#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 1) +#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 2) +#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 3) +#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP, 4) +#define WMI_MAX_SERVICES 5 + +/* reserved and used to flush ALL packets */ +#define HTC_TX_PACKET_TAG_ALL 0 +#define HTC_SERVICE_TX_PACKET_TAG 1 +#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_SERVICE_TX_PACKET_TAG + 9) + +/* more packets on this endpoint are being fetched */ +#define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0) + +/* TODO.. for BMI */ +#define ENDPOINT1 0 +/* TODO -remove me, but we have to fix BMI first */ +#define HTC_MAILBOX_NUM_MAX 4 + +/* enable send bundle padding for this endpoint */ +#define HTC_FLGS_TX_BNDL_PAD_EN (1 << 0) +#define HTC_EP_ACTIVE ((u32) (1u << 31)) + +/* HTC operational parameters */ +#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ +#define HTC_TARGET_DEBUG_INTR_MASK 0x01 +#define HTC_TARGET_CREDIT_INTR_MASK 0xF0 + +#define HTC_HOST_MAX_MSG_PER_BUNDLE 8 +#define HTC_MIN_HTC_MSGS_TO_BUNDLE 2 + +/* packet flags */ + +#define HTC_RX_PKT_IGNORE_LOOKAHEAD (1 << 0) +#define HTC_RX_PKT_REFRESH_HDR (1 << 1) +#define HTC_RX_PKT_PART_OF_BUNDLE (1 << 2) +#define HTC_RX_PKT_NO_RECYCLE (1 << 3) + +#define NUM_CONTROL_BUFFERS 8 +#define NUM_CONTROL_TX_BUFFERS 2 +#define NUM_CONTROL_RX_BUFFERS (NUM_CONTROL_BUFFERS - NUM_CONTROL_TX_BUFFERS) + +#define HTC_RECV_WAIT_BUFFERS (1 << 0) +#define HTC_OP_STATE_STOPPING (1 << 0) + +/* + * The frame header length and message formats defined herein were selected + * to accommodate optimal alignment for target processing. This reduces + * code size and improves performance. Any changes to the header length may + * alter the alignment and cause exceptions on the target. When adding to + * the messagestructures insure that fields are properly aligned. + */ + +/* HTC frame header + * + * NOTE: do not remove or re-arrange the fields, these are minimally + * required to take advantage of 4-byte lookaheads in some hardware + * implementations. + */ +struct htc_frame_hdr { + u8 eid; + u8 flags; + + /* length of data (including trailer) that follows the header */ + __le16 payld_len; + + /* end of 4-byte lookahead */ + + u8 ctrl[2]; +} __packed; + +/* HTC ready message */ +struct htc_ready_msg { + __le16 msg_id; + __le16 cred_cnt; + __le16 cred_sz; + u8 max_ep; + u8 pad; +} __packed; + +/* extended HTC ready message */ +struct htc_ready_ext_msg { + struct htc_ready_msg ver2_0_info; + u8 htc_ver; + u8 msg_per_htc_bndl; +} __packed; + +/* connect service */ +struct htc_conn_service_msg { + __le16 msg_id; + __le16 svc_id; + __le16 conn_flags; + u8 svc_meta_len; + u8 pad; +} __packed; + +/* connect response */ +struct htc_conn_service_resp { + __le16 msg_id; + __le16 svc_id; + u8 status; + u8 eid; + __le16 max_msg_sz; + u8 svc_meta_len; + u8 pad; +} __packed; + +struct htc_setup_comp_msg { + __le16 msg_id; +} __packed; + +/* extended setup completion message */ +struct htc_setup_comp_ext_msg { + __le16 msg_id; + __le32 flags; + u8 msg_per_rxbndl; + u8 Rsvd[3]; +} __packed; + +struct htc_record_hdr { + u8 rec_id; + u8 len; +} __packed; + +struct htc_credit_report { + u8 eid; + u8 credits; +} __packed; + +/* + * NOTE: The lk_ahd array is guarded by a pre_valid + * and Post Valid guard bytes. The pre_valid bytes must + * equal the inverse of the post_valid byte. + */ +struct htc_lookahead_report { + u8 pre_valid; + u8 lk_ahd[4]; + u8 post_valid; +} __packed; + +struct htc_bundle_lkahd_rpt { + u8 lk_ahd[4]; +} __packed; + +/* Current service IDs */ + +enum htc_service_grp_ids { + RSVD_SERVICE_GROUP = 0, + WMI_SERVICE_GROUP = 1, + + HTC_TEST_GROUP = 254, + HTC_SERVICE_GROUP_LAST = 255 +}; + +/* ------ endpoint IDS ------ */ + +enum htc_endpoint_id { + ENDPOINT_UNUSED = -1, + ENDPOINT_0 = 0, + ENDPOINT_1 = 1, + ENDPOINT_2 = 2, + ENDPOINT_3, + ENDPOINT_4, + ENDPOINT_5, + ENDPOINT_6, + ENDPOINT_7, + ENDPOINT_8, + ENDPOINT_MAX, +}; + +struct htc_tx_packet_info { + u16 tag; + int cred_used; + u8 flags; + int seqno; +}; + +struct htc_rx_packet_info { + u32 exp_hdr; + u32 rx_flags; + u32 indicat_flags; +}; + +struct htc_target; + +/* wrapper around endpoint-specific packets */ +struct htc_packet { + struct list_head list; + + /* caller's per packet specific context */ + void *pkt_cntxt; + + /* + * the true buffer start , the caller can store the real + * buffer start here. In receive callbacks, the HTC layer + * sets buf to the start of the payload past the header. + * This field allows the caller to reset buf when it recycles + * receive packets back to HTC. + */ + u8 *buf_start; + + /* + * Pointer to the start of the buffer. In the transmit + * direction this points to the start of the payload. In the + * receive direction, however, the buffer when queued up + * points to the start of the HTC header but when returned + * to the caller points to the start of the payload + */ + u8 *buf; + u32 buf_len; + + /* actual length of payload */ + u32 act_len; + + /* endpoint that this packet was sent/recv'd from */ + enum htc_endpoint_id endpoint; + + /* completion status */ + + int status; + union { + struct htc_tx_packet_info tx; + struct htc_rx_packet_info rx; + } info; + + void (*completion) (struct htc_target *, struct htc_packet *); + struct htc_target *context; +}; + +enum htc_send_full_action { + HTC_SEND_FULL_KEEP = 0, + HTC_SEND_FULL_DROP = 1, +}; + +struct htc_ep_callbacks { + void (*rx) (struct htc_target *, struct htc_packet *); + void (*rx_refill) (struct htc_target *, enum htc_endpoint_id endpoint); + enum htc_send_full_action (*tx_full) (struct htc_target *, + struct htc_packet *); + struct htc_packet *(*rx_allocthresh) (struct htc_target *, + enum htc_endpoint_id, int); + int rx_alloc_thresh; + int rx_refill_thresh; +}; + +/* service connection information */ +struct htc_service_connect_req { + u16 svc_id; + u16 conn_flags; + struct htc_ep_callbacks ep_cb; + int max_txq_depth; + u32 flags; + unsigned int max_rxmsg_sz; +}; + +/* service connection response information */ +struct htc_service_connect_resp { + u8 buf_len; + u8 act_len; + enum htc_endpoint_id endpoint; + unsigned int len_max; + u8 resp_code; +}; + +/* endpoint distributionstructure */ +struct htc_endpoint_credit_dist { + struct list_head list; + + /* Service ID (set by HTC) */ + u16 svc_id; + + /* endpoint for this distributionstruct (set by HTC) */ + enum htc_endpoint_id endpoint; + + u32 dist_flags; + + /* + * credits for normal operation, anything above this + * indicates the endpoint is over-subscribed. + */ + int cred_norm; + + /* floor for credit distribution */ + int cred_min; + + int cred_assngd; + + /* current credits available */ + int credits; + + /* + * pending credits to distribute on this endpoint, this + * is set by HTC when credit reports arrive. The credit + * distribution functions sets this to zero when it distributes + * the credits. + */ + int cred_to_dist; + + /* + * the number of credits that the current pending TX packet needs + * to transmit. This is set by HTC when endpoint needs credits in + * order to transmit. + */ + int seek_cred; + + /* size in bytes of each credit */ + int cred_sz; + + /* credits required for a maximum sized messages */ + int cred_per_msg; + + /* reserved for HTC use */ + void *htc_rsvd; + + /* + * current depth of TX queue , i.e. messages waiting for credits + * This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE + * or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint + * that has non-zero credits to recover. + */ + int txq_depth; +}; + +/* + * credit distibution code that is passed into the distrbution function, + * there are mandatory and optional codes that must be handled + */ +enum htc_credit_dist_reason { + HTC_CREDIT_DIST_SEND_COMPLETE = 0, + HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, + HTC_CREDIT_DIST_SEEK_CREDITS, +}; + +struct htc_credit_state_info { + int total_avail_credits; + int cur_free_credits; + struct list_head lowestpri_ep_dist; +}; + +/* endpoint statistics */ +struct htc_endpoint_stats { + /* + * number of times the host set the credit-low flag in a send + * message on this endpoint + */ + u32 cred_low_indicate; + + u32 tx_issued; + u32 tx_pkt_bundled; + u32 tx_bundles; + u32 tx_dropped; + + /* running count of total credit reports received for this endpoint */ + u32 tx_cred_rpt; + + /* credit reports received from this endpoint's RX packets */ + u32 cred_rpt_from_rx; + + /* credit reports received from RX packets of other endpoints */ + u32 cred_rpt_from_other; + + /* credit reports received from endpoint 0 RX packets */ + u32 cred_rpt_ep0; + + /* count of credits received via Rx packets on this endpoint */ + u32 cred_from_rx; + + /* count of credits received via another endpoint */ + u32 cred_from_other; + + /* count of credits received via another endpoint */ + u32 cred_from_ep0; + + /* count of consummed credits */ + u32 cred_cosumd; + + /* count of credits returned */ + u32 cred_retnd; + + u32 rx_pkts; + + /* count of lookahead records found in Rx msg */ + u32 rx_lkahds; + + /* count of recv packets received in a bundle */ + u32 rx_bundl; + + /* count of number of bundled lookaheads */ + u32 rx_bundle_lkahd; + + /* count of the number of bundle indications from the HTC header */ + u32 rx_bundle_from_hdr; + + /* the number of times the recv allocation threshold was hit */ + u32 rx_alloc_thresh_hit; + + /* total number of bytes */ + u32 rxalloc_thresh_byte; +}; + +struct htc_endpoint { + enum htc_endpoint_id eid; + u16 svc_id; + struct list_head txq; + struct list_head rx_bufq; + struct htc_endpoint_credit_dist cred_dist; + struct htc_ep_callbacks ep_cb; + int max_txq_depth; + int len_max; + int tx_proc_cnt; + int rx_proc_cnt; + struct htc_target *target; + u8 seqno; + u32 conn_flags; + struct htc_endpoint_stats ep_st; +}; + +struct htc_control_buffer { + struct htc_packet packet; + u8 *buf; +}; + +struct ath6kl_device; + +/* our HTC target state */ +struct htc_target { + struct htc_endpoint endpoint[ENDPOINT_MAX]; + struct list_head cred_dist_list; + struct list_head free_ctrl_txbuf; + struct list_head free_ctrl_rxbuf; + struct htc_credit_state_info *cred_dist_cntxt; + int tgt_creds; + unsigned int tgt_cred_sz; + spinlock_t htc_lock; + spinlock_t rx_lock; + spinlock_t tx_lock; + struct ath6kl_device *dev; + u32 htc_flags; + u32 rx_st_flags; + enum htc_endpoint_id ep_waiting; + u8 htc_tgt_ver; + + /* max messages per bundle for HTC */ + int msg_per_bndl_max; + + bool tx_bndl_enable; + int rx_bndl_enable; + int max_rx_bndl_sz; + int max_tx_bndl_sz; + + u32 block_sz; + u32 block_mask; + + int max_scat_entries; + int max_xfer_szper_scatreq; + + int chk_irq_status_cnt; +}; + +void *ath6kl_htc_create(struct ath6kl *ar); +void ath6kl_htc_set_credit_dist(struct htc_target *target, + struct htc_credit_state_info *cred_info, + u16 svc_pri_order[], int len); +int ath6kl_htc_wait_target(struct htc_target *target); +int ath6kl_htc_start(struct htc_target *target); +int ath6kl_htc_conn_service(struct htc_target *target, + struct htc_service_connect_req *req, + struct htc_service_connect_resp *resp); +int ath6kl_htc_tx(struct htc_target *target, struct htc_packet *packet); +void ath6kl_htc_stop(struct htc_target *target); +void ath6kl_htc_cleanup(struct htc_target *target); +void ath6kl_htc_flush_txep(struct htc_target *target, + enum htc_endpoint_id endpoint, u16 tag); +void ath6kl_htc_flush_rx_buf(struct htc_target *target); +void ath6kl_htc_indicate_activity_change(struct htc_target *target, + enum htc_endpoint_id endpoint, + bool active); +int ath6kl_htc_get_rxbuf_num(struct htc_target *target, + enum htc_endpoint_id endpoint); +int ath6kl_htc_add_rxbuf_multiple(struct htc_target *target, + struct list_head *pktq); +int ath6kl_htc_rxmsg_pending_handler(struct htc_target *target, + u32 msg_look_ahead[], int *n_pkts); + +static inline void set_htc_pkt_info(struct htc_packet *packet, void *context, + u8 *buf, unsigned int len, + enum htc_endpoint_id eid, u16 tag) +{ + packet->pkt_cntxt = context; + packet->buf = buf; + packet->act_len = len; + packet->endpoint = eid; + packet->info.tx.tag = tag; +} + +static inline void htc_rxpkt_reset(struct htc_packet *packet) +{ + packet->buf = packet->buf_start; + packet->act_len = 0; +} + +static inline void set_htc_rxpkt_info(struct htc_packet *packet, void *context, + u8 *buf, unsigned long len, + enum htc_endpoint_id eid) +{ + packet->pkt_cntxt = context; + packet->buf = buf; + packet->buf_start = buf; + packet->buf_len = len; + packet->endpoint = eid; +} + +static inline int get_queue_depth(struct list_head *queue) +{ + struct list_head *tmp_list; + int depth = 0; + + list_for_each(tmp_list, queue) + depth++; + + return depth; +} + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/htc_hif.c b/drivers/net/wireless/ath/ath6kl/htc_hif.c new file mode 100644 index 000000000000..86b1cc7409c2 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/htc_hif.c @@ -0,0 +1,641 @@ +/* + * Copyright (c) 2007-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 "core.h" +#include "target.h" +#include "hif-ops.h" +#include "htc_hif.h" +#include "debug.h" + +#define MAILBOX_FOR_BLOCK_SIZE 1 + +#define ATH6KL_TIME_QUANTUM 10 /* in ms */ + +static int ath6kldev_cp_scat_dma_buf(struct hif_scatter_req *req, bool from_dma) +{ + u8 *buf; + int i; + + buf = req->virt_dma_buf; + + for (i = 0; i < req->scat_entries; i++) { + + if (from_dma) + memcpy(req->scat_list[i].buf, buf, + req->scat_list[i].len); + else + memcpy(buf, req->scat_list[i].buf, + req->scat_list[i].len); + + buf += req->scat_list[i].len; + } + + return 0; +} + +int ath6kldev_rw_comp_handler(void *context, int status) +{ + struct htc_packet *packet = context; + + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, + "ath6kldev_rw_comp_handler (pkt:0x%p , status: %d\n", + packet, status); + + packet->status = status; + packet->completion(packet->context, packet); + + return 0; +} + +static int ath6kldev_proc_dbg_intr(struct ath6kl_device *dev) +{ + u32 dummy; + int status; + + ath6kl_err("target debug interrupt\n"); + + ath6kl_target_failure(dev->ar); + + /* + * read counter to clear the interrupt, the debug error interrupt is + * counter 0. + */ + status = hif_read_write_sync(dev->ar, COUNT_DEC_ADDRESS, + (u8 *)&dummy, 4, HIF_RD_SYNC_BYTE_INC); + if (status) + WARN_ON(1); + + return status; +} + +/* mailbox recv message polling */ +int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, u32 *lk_ahd, + int timeout) +{ + struct ath6kl_irq_proc_registers *rg; + int status = 0, i; + u8 htc_mbox = 1 << HTC_MAILBOX; + + for (i = timeout / ATH6KL_TIME_QUANTUM; i > 0; i--) { + /* this is the standard HIF way, load the reg table */ + status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS, + (u8 *) &dev->irq_proc_reg, + sizeof(dev->irq_proc_reg), + HIF_RD_SYNC_BYTE_INC); + + if (status) { + ath6kl_err("failed to read reg table\n"); + return status; + } + + /* check for MBOX data and valid lookahead */ + if (dev->irq_proc_reg.host_int_status & htc_mbox) { + if (dev->irq_proc_reg.rx_lkahd_valid & + htc_mbox) { + /* + * Mailbox has a message and the look ahead + * is valid. + */ + rg = &dev->irq_proc_reg; + *lk_ahd = + le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]); + break; + } + } + + /* delay a little */ + mdelay(ATH6KL_TIME_QUANTUM); + ath6kl_dbg(ATH6KL_DBG_HTC_RECV, "retry mbox poll : %d\n", i); + } + + if (i == 0) { + ath6kl_err("timeout waiting for recv message\n"); + status = -ETIME; + /* check if the target asserted */ + if (dev->irq_proc_reg.counter_int_status & + ATH6KL_TARGET_DEBUG_INTR_MASK) + /* + * Target failure handler will be called in case of + * an assert. + */ + ath6kldev_proc_dbg_intr(dev); + } + + return status; +} + +/* + * Disable packet reception (used in case the host runs out of buffers) + * using the interrupt enable registers through the host I/F + */ +int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx) +{ + struct ath6kl_irq_enable_reg regs; + int status = 0; + + /* take the lock to protect interrupt enable shadows */ + spin_lock_bh(&dev->lock); + + if (enable_rx) + dev->irq_en_reg.int_status_en |= + SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); + else + dev->irq_en_reg.int_status_en &= + ~SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); + + memcpy(®s, &dev->irq_en_reg, sizeof(regs)); + + spin_unlock_bh(&dev->lock); + + status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, + ®s.int_status_en, + sizeof(struct ath6kl_irq_enable_reg), + HIF_WR_SYNC_BYTE_INC); + + return status; +} + +int ath6kldev_submit_scat_req(struct ath6kl_device *dev, + struct hif_scatter_req *scat_req, bool read) +{ + int status = 0; + + if (read) { + scat_req->req = HIF_RD_SYNC_BLOCK_FIX; + scat_req->addr = dev->ar->mbox_info.htc_addr; + } else { + scat_req->req = HIF_WR_ASYNC_BLOCK_INC; + + scat_req->addr = + (scat_req->len > HIF_MBOX_WIDTH) ? + dev->ar->mbox_info.htc_ext_addr : + dev->ar->mbox_info.htc_addr; + } + + ath6kl_dbg((ATH6KL_DBG_HTC_RECV | ATH6KL_DBG_HTC_SEND), + "ath6kldev_submit_scat_req, entries: %d, total len: %d mbox:0x%X (mode: %s : %s)\n", + scat_req->scat_entries, scat_req->len, + scat_req->addr, !read ? "async" : "sync", + (read) ? "rd" : "wr"); + + if (!read && scat_req->virt_scat) { + status = ath6kldev_cp_scat_dma_buf(scat_req, false); + if (status) { + scat_req->status = status; + scat_req->complete(dev->ar->htc_target, scat_req); + return 0; + } + } + + status = ath6kl_hif_scat_req_rw(dev->ar, scat_req); + + if (read) { + /* in sync mode, we can touch the scatter request */ + scat_req->status = status; + if (!status && scat_req->virt_scat) + scat_req->status = + ath6kldev_cp_scat_dma_buf(scat_req, true); + } + + return status; +} + +static int ath6kldev_proc_counter_intr(struct ath6kl_device *dev) +{ + u8 counter_int_status; + + ath6kl_dbg(ATH6KL_DBG_IRQ, "counter interrupt\n"); + + counter_int_status = dev->irq_proc_reg.counter_int_status & + dev->irq_en_reg.cntr_int_status_en; + + ath6kl_dbg(ATH6KL_DBG_IRQ, + "valid interrupt source(s) in COUNTER_INT_STATUS: 0x%x\n", + counter_int_status); + + /* + * NOTE: other modules like GMBOX may use the counter interrupt for + * credit flow control on other counters, we only need to check for + * the debug assertion counter interrupt. + */ + if (counter_int_status & ATH6KL_TARGET_DEBUG_INTR_MASK) + return ath6kldev_proc_dbg_intr(dev); + + return 0; +} + +static int ath6kldev_proc_err_intr(struct ath6kl_device *dev) +{ + int status; + u8 error_int_status; + u8 reg_buf[4]; + + ath6kl_dbg(ATH6KL_DBG_IRQ, "error interrupt\n"); + + error_int_status = dev->irq_proc_reg.error_int_status & 0x0F; + if (!error_int_status) { + WARN_ON(1); + return -EIO; + } + + ath6kl_dbg(ATH6KL_DBG_IRQ, + "valid interrupt source(s) in ERROR_INT_STATUS: 0x%x\n", + error_int_status); + + if (MS(ERROR_INT_STATUS_WAKEUP, error_int_status)) + ath6kl_dbg(ATH6KL_DBG_IRQ, "error : wakeup\n"); + + if (MS(ERROR_INT_STATUS_RX_UNDERFLOW, error_int_status)) + ath6kl_err("rx underflow\n"); + + if (MS(ERROR_INT_STATUS_TX_OVERFLOW, error_int_status)) + ath6kl_err("tx overflow\n"); + + /* Clear the interrupt */ + dev->irq_proc_reg.error_int_status &= ~error_int_status; + + /* set W1C value to clear the interrupt, this hits the register first */ + reg_buf[0] = error_int_status; + reg_buf[1] = 0; + reg_buf[2] = 0; + reg_buf[3] = 0; + + status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS, + reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); + + if (status) + WARN_ON(1); + + return status; +} + +static int ath6kldev_proc_cpu_intr(struct ath6kl_device *dev) +{ + int status; + u8 cpu_int_status; + u8 reg_buf[4]; + + ath6kl_dbg(ATH6KL_DBG_IRQ, "cpu interrupt\n"); + + cpu_int_status = dev->irq_proc_reg.cpu_int_status & + dev->irq_en_reg.cpu_int_status_en; + if (!cpu_int_status) { + WARN_ON(1); + return -EIO; + } + + ath6kl_dbg(ATH6KL_DBG_IRQ, + "valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", + cpu_int_status); + + /* Clear the interrupt */ + dev->irq_proc_reg.cpu_int_status &= ~cpu_int_status; + + /* + * Set up the register transfer buffer to hit the register 4 times , + * this is done to make the access 4-byte aligned to mitigate issues + * with host bus interconnects that restrict bus transfer lengths to + * be a multiple of 4-bytes. + */ + + /* set W1C value to clear the interrupt, this hits the register first */ + reg_buf[0] = cpu_int_status; + /* the remaining are set to zero which have no-effect */ + reg_buf[1] = 0; + reg_buf[2] = 0; + reg_buf[3] = 0; + + status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS, + reg_buf, 4, HIF_WR_SYNC_BYTE_FIX); + + if (status) + WARN_ON(1); + + return status; +} + +/* process pending interrupts synchronously */ +static int proc_pending_irqs(struct ath6kl_device *dev, bool *done) +{ + struct ath6kl_irq_proc_registers *rg; + int status = 0; + u8 host_int_status = 0; + u32 lk_ahd = 0; + u8 htc_mbox = 1 << HTC_MAILBOX; + + ath6kl_dbg(ATH6KL_DBG_IRQ, "proc_pending_irqs: (dev: 0x%p)\n", dev); + + /* + * NOTE: HIF implementation guarantees that the context of this + * call allows us to perform SYNCHRONOUS I/O, that is we can block, + * sleep or call any API that can block or switch thread/task + * contexts. This is a fully schedulable context. + */ + + /* + * Process pending intr only when int_status_en is clear, it may + * result in unnecessary bus transaction otherwise. Target may be + * unresponsive at the time. + */ + if (dev->irq_en_reg.int_status_en) { + /* + * Read the first 28 bytes of the HTC register table. This + * will yield us the value of different int status + * registers and the lookahead registers. + * + * length = sizeof(int_status) + sizeof(cpu_int_status) + * + sizeof(error_int_status) + + * sizeof(counter_int_status) + + * sizeof(mbox_frame) + sizeof(rx_lkahd_valid) + * + sizeof(hole) + sizeof(rx_lkahd) + + * sizeof(int_status_en) + + * sizeof(cpu_int_status_en) + + * sizeof(err_int_status_en) + + * sizeof(cntr_int_status_en); + */ + status = hif_read_write_sync(dev->ar, HOST_INT_STATUS_ADDRESS, + (u8 *) &dev->irq_proc_reg, + sizeof(dev->irq_proc_reg), + HIF_RD_SYNC_BYTE_INC); + if (status) + goto out; + + if (AR_DBG_LVL_CHECK(ATH6KL_DBG_IRQ)) + ath6kl_dump_registers(dev, &dev->irq_proc_reg, + &dev->irq_en_reg); + + /* Update only those registers that are enabled */ + host_int_status = dev->irq_proc_reg.host_int_status & + dev->irq_en_reg.int_status_en; + + /* Look at mbox status */ + if (host_int_status & htc_mbox) { + /* + * Mask out pending mbox value, we use "lookAhead as + * the real flag for mbox processing. + */ + host_int_status &= ~htc_mbox; + if (dev->irq_proc_reg.rx_lkahd_valid & + htc_mbox) { + rg = &dev->irq_proc_reg; + lk_ahd = le32_to_cpu(rg->rx_lkahd[HTC_MAILBOX]); + if (!lk_ahd) + ath6kl_err("lookAhead is zero!\n"); + } + } + } + + if (!host_int_status && !lk_ahd) { + *done = true; + goto out; + } + + if (lk_ahd) { + int fetched = 0; + + ath6kl_dbg(ATH6KL_DBG_IRQ, + "pending mailbox msg, lk_ahd: 0x%X\n", lk_ahd); + /* + * Mailbox Interrupt, the HTC layer may issue async + * requests to empty the mailbox. When emptying the recv + * mailbox we use the async handler above called from the + * completion routine of the callers read request. This can + * improve performance by reducing context switching when + * we rapidly pull packets. + */ + status = ath6kl_htc_rxmsg_pending_handler(dev->htc_cnxt, + &lk_ahd, &fetched); + if (status) + goto out; + + if (!fetched) + /* + * HTC could not pull any messages out due to lack + * of resources. + */ + dev->htc_cnxt->chk_irq_status_cnt = 0; + } + + /* now handle the rest of them */ + ath6kl_dbg(ATH6KL_DBG_IRQ, + "valid interrupt source(s) for other interrupts: 0x%x\n", + host_int_status); + + if (MS(HOST_INT_STATUS_CPU, host_int_status)) { + /* CPU Interrupt */ + status = ath6kldev_proc_cpu_intr(dev); + if (status) + goto out; + } + + if (MS(HOST_INT_STATUS_ERROR, host_int_status)) { + /* Error Interrupt */ + status = ath6kldev_proc_err_intr(dev); + if (status) + goto out; + } + + if (MS(HOST_INT_STATUS_COUNTER, host_int_status)) + /* Counter Interrupt */ + status = ath6kldev_proc_counter_intr(dev); + +out: + /* + * An optimization to bypass reading the IRQ status registers + * unecessarily which can re-wake the target, if upper layers + * determine that we are in a low-throughput mode, we can rely on + * taking another interrupt rather than re-checking the status + * registers which can re-wake the target. + * + * NOTE : for host interfaces that makes use of detecting pending + * mbox messages at hif can not use this optimization due to + * possible side effects, SPI requires the host to drain all + * messages from the mailbox before exiting the ISR routine. + */ + + ath6kl_dbg(ATH6KL_DBG_IRQ, + "bypassing irq status re-check, forcing done\n"); + + if (!dev->htc_cnxt->chk_irq_status_cnt) + *done = true; + + ath6kl_dbg(ATH6KL_DBG_IRQ, + "proc_pending_irqs: (done:%d, status=%d\n", *done, status); + + return status; +} + +/* interrupt handler, kicks off all interrupt processing */ +int ath6kldev_intr_bh_handler(struct ath6kl *ar) +{ + struct ath6kl_device *dev = ar->htc_target->dev; + int status = 0; + bool done = false; + + /* + * Reset counter used to flag a re-scan of IRQ status registers on + * the target. + */ + dev->htc_cnxt->chk_irq_status_cnt = 0; + + /* + * IRQ processing is synchronous, interrupt status registers can be + * re-read. + */ + while (!done) { + status = proc_pending_irqs(dev, &done); + if (status) + break; + } + + return status; +} + +static int ath6kldev_enable_intrs(struct ath6kl_device *dev) +{ + struct ath6kl_irq_enable_reg regs; + int status; + + spin_lock_bh(&dev->lock); + + /* Enable all but ATH6KL CPU interrupts */ + dev->irq_en_reg.int_status_en = + SM(INT_STATUS_ENABLE_ERROR, 0x01) | + SM(INT_STATUS_ENABLE_CPU, 0x01) | + SM(INT_STATUS_ENABLE_COUNTER, 0x01); + + /* + * NOTE: There are some cases where HIF can do detection of + * pending mbox messages which is disabled now. + */ + dev->irq_en_reg.int_status_en |= SM(INT_STATUS_ENABLE_MBOX_DATA, 0x01); + + /* Set up the CPU Interrupt status Register */ + dev->irq_en_reg.cpu_int_status_en = 0; + + /* Set up the Error Interrupt status Register */ + dev->irq_en_reg.err_int_status_en = + SM(ERROR_STATUS_ENABLE_RX_UNDERFLOW, 0x01) | + SM(ERROR_STATUS_ENABLE_TX_OVERFLOW, 0x1); + + /* + * Enable Counter interrupt status register to get fatal errors for + * debugging. + */ + dev->irq_en_reg.cntr_int_status_en = SM(COUNTER_INT_STATUS_ENABLE_BIT, + ATH6KL_TARGET_DEBUG_INTR_MASK); + memcpy(®s, &dev->irq_en_reg, sizeof(regs)); + + spin_unlock_bh(&dev->lock); + + status = hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, + ®s.int_status_en, sizeof(regs), + HIF_WR_SYNC_BYTE_INC); + + if (status) + ath6kl_err("failed to update interrupt ctl reg err: %d\n", + status); + + return status; +} + +int ath6kldev_disable_intrs(struct ath6kl_device *dev) +{ + struct ath6kl_irq_enable_reg regs; + + spin_lock_bh(&dev->lock); + /* Disable all interrupts */ + dev->irq_en_reg.int_status_en = 0; + dev->irq_en_reg.cpu_int_status_en = 0; + dev->irq_en_reg.err_int_status_en = 0; + dev->irq_en_reg.cntr_int_status_en = 0; + memcpy(®s, &dev->irq_en_reg, sizeof(regs)); + spin_unlock_bh(&dev->lock); + + return hif_read_write_sync(dev->ar, INT_STATUS_ENABLE_ADDRESS, + ®s.int_status_en, sizeof(regs), + HIF_WR_SYNC_BYTE_INC); +} + +/* enable device interrupts */ +int ath6kldev_unmask_intrs(struct ath6kl_device *dev) +{ + int status = 0; + + /* + * Make sure interrupt are disabled before unmasking at the HIF + * layer. The rationale here is that between device insertion + * (where we clear the interrupts the first time) and when HTC + * is finally ready to handle interrupts, other software can perform + * target "soft" resets. The ATH6KL interrupt enables reset back to an + * "enabled" state when this happens. + */ + ath6kldev_disable_intrs(dev); + + /* unmask the host controller interrupts */ + ath6kl_hif_irq_enable(dev->ar); + status = ath6kldev_enable_intrs(dev); + + return status; +} + +/* disable all device interrupts */ +int ath6kldev_mask_intrs(struct ath6kl_device *dev) +{ + /* + * Mask the interrupt at the HIF layer to avoid any stray interrupt + * taken while we zero out our shadow registers in + * ath6kldev_disable_intrs(). + */ + ath6kl_hif_irq_disable(dev->ar); + + return ath6kldev_disable_intrs(dev); +} + +int ath6kldev_setup(struct ath6kl_device *dev) +{ + int status = 0; + + spin_lock_init(&dev->lock); + + /* + * NOTE: we actually get the block size of a mailbox other than 0, + * for SDIO the block size on mailbox 0 is artificially set to 1. + * So we use the block size that is set for the other 3 mailboxes. + */ + dev->htc_cnxt->block_sz = dev->ar->mbox_info.block_size; + + /* must be a power of 2 */ + if ((dev->htc_cnxt->block_sz & (dev->htc_cnxt->block_sz - 1)) != 0) { + WARN_ON(1); + goto fail_setup; + } + + /* assemble mask, used for padding to a block */ + dev->htc_cnxt->block_mask = dev->htc_cnxt->block_sz - 1; + + ath6kl_dbg(ATH6KL_DBG_TRC, "block size: %d, mbox addr:0x%X\n", + dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr); + + ath6kl_dbg(ATH6KL_DBG_TRC, + "hif interrupt processing is sync only\n"); + + status = ath6kldev_disable_intrs(dev); + +fail_setup: + return status; + +} diff --git a/drivers/net/wireless/ath/ath6kl/htc_hif.h b/drivers/net/wireless/ath/ath6kl/htc_hif.h new file mode 100644 index 000000000000..171ad63d89b0 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/htc_hif.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007-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 HTC_HIF_H +#define HTC_HIF_H + +#include "htc.h" +#include "hif.h" + +#define ATH6KL_MAILBOXES 4 + +/* HTC runs over mailbox 0 */ +#define HTC_MAILBOX 0 + +#define ATH6KL_TARGET_DEBUG_INTR_MASK 0x01 + +#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \ + INT_STATUS_ENABLE_CPU_MASK | \ + INT_STATUS_ENABLE_COUNTER_MASK) + +#define ATH6KL_REG_IO_BUFFER_SIZE 32 +#define ATH6KL_MAX_REG_IO_BUFFERS 8 +#define ATH6KL_SCATTER_ENTRIES_PER_REQ 16 +#define ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER (16 * 1024) +#define ATH6KL_SCATTER_REQS 4 + +#ifndef A_CACHE_LINE_PAD +#define A_CACHE_LINE_PAD 128 +#endif +#define ATH6KL_MIN_SCATTER_ENTRIES_PER_REQ 2 +#define ATH6KL_MIN_TRANSFER_SIZE_PER_SCATTER (4 * 1024) + +struct ath6kl_irq_proc_registers { + u8 host_int_status; + u8 cpu_int_status; + u8 error_int_status; + u8 counter_int_status; + u8 mbox_frame; + u8 rx_lkahd_valid; + u8 host_int_status2; + u8 gmbox_rx_avail; + __le32 rx_lkahd[2]; + __le32 rx_gmbox_lkahd_alias[2]; +} __packed; + +struct ath6kl_irq_enable_reg { + u8 int_status_en; + u8 cpu_int_status_en; + u8 err_int_status_en; + u8 cntr_int_status_en; +} __packed; + +struct ath6kl_device { + spinlock_t lock; + u8 pad1[A_CACHE_LINE_PAD]; + struct ath6kl_irq_proc_registers irq_proc_reg; + u8 pad2[A_CACHE_LINE_PAD]; + struct ath6kl_irq_enable_reg irq_en_reg; + u8 pad3[A_CACHE_LINE_PAD]; + struct htc_target *htc_cnxt; + struct ath6kl *ar; +}; + +int ath6kldev_setup(struct ath6kl_device *dev); +int ath6kldev_unmask_intrs(struct ath6kl_device *dev); +int ath6kldev_mask_intrs(struct ath6kl_device *dev); +int ath6kldev_poll_mboxmsg_rx(struct ath6kl_device *dev, + u32 *lk_ahd, int timeout); +int ath6kldev_rx_control(struct ath6kl_device *dev, bool enable_rx); +int ath6kldev_disable_intrs(struct ath6kl_device *dev); + +int ath6kldev_rw_comp_handler(void *context, int status); +int ath6kldev_intr_bh_handler(struct ath6kl *ar); + +/* Scatter Function and Definitions */ +int ath6kldev_submit_scat_req(struct ath6kl_device *dev, + struct hif_scatter_req *scat_req, bool read); + +#endif /*ATH6KL_H_ */ diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c new file mode 100644 index 000000000000..c1d2366704b5 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -0,0 +1,1727 @@ + +/* + * Copyright (c) 2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/moduleparam.h> +#include <linux/of.h> +#include <linux/mmc/sdio_func.h> +#include "core.h" +#include "cfg80211.h" +#include "target.h" +#include "debug.h" +#include "hif-ops.h" + +unsigned int debug_mask; +static unsigned int testmode; + +module_param(debug_mask, uint, 0644); +module_param(testmode, uint, 0644); + +/* + * Include definitions here that can be used to tune the WLAN module + * behavior. Different customers can tune the behavior as per their needs, + * here. + */ + +/* + * This configuration item enable/disable keepalive support. + * Keepalive support: In the absence of any data traffic to AP, null + * frames will be sent to the AP at periodic interval, to keep the association + * active. This configuration item defines the periodic interval. + * Use value of zero to disable keepalive support + * Default: 60 seconds + */ +#define WLAN_CONFIG_KEEP_ALIVE_INTERVAL 60 + +/* + * This configuration item sets the value of disconnect timeout + * Firmware delays sending the disconnec event to the host for this + * timeout after is gets disconnected from the current AP. + * If the firmware successly roams within the disconnect timeout + * it sends a new connect event + */ +#define WLAN_CONFIG_DISCONNECT_TIMEOUT 10 + +#define CONFIG_AR600x_DEBUG_UART_TX_PIN 8 + +#define ATH6KL_DATA_OFFSET 64 +struct sk_buff *ath6kl_buf_alloc(int size) +{ + struct sk_buff *skb; + u16 reserved; + + /* Add chacheline space at front and back of buffer */ + reserved = (2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + + sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES; + skb = dev_alloc_skb(size + reserved); + + if (skb) + skb_reserve(skb, reserved - L1_CACHE_BYTES); + return skb; +} + +void ath6kl_init_profile_info(struct ath6kl *ar) +{ + ar->ssid_len = 0; + memset(ar->ssid, 0, sizeof(ar->ssid)); + + ar->dot11_auth_mode = OPEN_AUTH; + ar->auth_mode = NONE_AUTH; + ar->prwise_crypto = NONE_CRYPT; + ar->prwise_crypto_len = 0; + ar->grp_crypto = NONE_CRYPT; + ar->grp_crypto_len = 0; + memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); + memset(ar->req_bssid, 0, sizeof(ar->req_bssid)); + memset(ar->bssid, 0, sizeof(ar->bssid)); + ar->bss_ch = 0; + ar->nw_type = ar->next_mode = INFRA_NETWORK; +} + +static u8 ath6kl_get_fw_iftype(struct ath6kl *ar) +{ + switch (ar->nw_type) { + case INFRA_NETWORK: + return HI_OPTION_FW_MODE_BSS_STA; + case ADHOC_NETWORK: + return HI_OPTION_FW_MODE_IBSS; + case AP_NETWORK: + return HI_OPTION_FW_MODE_AP; + default: + ath6kl_err("Unsupported interface type :%d\n", ar->nw_type); + return 0xff; + } +} + +static int ath6kl_set_host_app_area(struct ath6kl *ar) +{ + u32 address, data; + struct host_app_area host_app_area; + + /* Fetch the address of the host_app_area_s + * instance in the host interest area */ + address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_app_host_interest)); + address = TARG_VTOP(ar->target_type, address); + + if (ath6kl_diag_read32(ar, address, &data)) + return -EIO; + + address = TARG_VTOP(ar->target_type, data); + host_app_area.wmi_protocol_ver = WMI_PROTOCOL_VERSION; + if (ath6kl_diag_write(ar, address, (u8 *) &host_app_area, + sizeof(struct host_app_area))) + return -EIO; + + return 0; +} + +static inline void set_ac2_ep_map(struct ath6kl *ar, + u8 ac, + enum htc_endpoint_id ep) +{ + ar->ac2ep_map[ac] = ep; + ar->ep2ac_map[ep] = ac; +} + +/* connect to a service */ +static int ath6kl_connectservice(struct ath6kl *ar, + struct htc_service_connect_req *con_req, + char *desc) +{ + int status; + struct htc_service_connect_resp response; + + memset(&response, 0, sizeof(response)); + + status = ath6kl_htc_conn_service(ar->htc_target, con_req, &response); + if (status) { + ath6kl_err("failed to connect to %s service status:%d\n", + desc, status); + return status; + } + + switch (con_req->svc_id) { + case WMI_CONTROL_SVC: + if (test_bit(WMI_ENABLED, &ar->flag)) + ath6kl_wmi_set_control_ep(ar->wmi, response.endpoint); + ar->ctrl_ep = response.endpoint; + break; + case WMI_DATA_BE_SVC: + set_ac2_ep_map(ar, WMM_AC_BE, response.endpoint); + break; + case WMI_DATA_BK_SVC: + set_ac2_ep_map(ar, WMM_AC_BK, response.endpoint); + break; + case WMI_DATA_VI_SVC: + set_ac2_ep_map(ar, WMM_AC_VI, response.endpoint); + break; + case WMI_DATA_VO_SVC: + set_ac2_ep_map(ar, WMM_AC_VO, response.endpoint); + break; + default: + ath6kl_err("service id is not mapped %d\n", con_req->svc_id); + return -EINVAL; + } + + return 0; +} + +static int ath6kl_init_service_ep(struct ath6kl *ar) +{ + struct htc_service_connect_req connect; + + memset(&connect, 0, sizeof(connect)); + + /* these fields are the same for all service endpoints */ + connect.ep_cb.rx = ath6kl_rx; + connect.ep_cb.rx_refill = ath6kl_rx_refill; + connect.ep_cb.tx_full = ath6kl_tx_queue_full; + + /* + * Set the max queue depth so that our ath6kl_tx_queue_full handler + * gets called. + */ + connect.max_txq_depth = MAX_DEFAULT_SEND_QUEUE_DEPTH; + connect.ep_cb.rx_refill_thresh = ATH6KL_MAX_RX_BUFFERS / 4; + if (!connect.ep_cb.rx_refill_thresh) + connect.ep_cb.rx_refill_thresh++; + + /* connect to control service */ + connect.svc_id = WMI_CONTROL_SVC; + if (ath6kl_connectservice(ar, &connect, "WMI CONTROL")) + return -EIO; + + connect.flags |= HTC_FLGS_TX_BNDL_PAD_EN; + + /* + * Limit the HTC message size on the send path, although e can + * receive A-MSDU frames of 4K, we will only send ethernet-sized + * (802.3) frames on the send path. + */ + connect.max_rxmsg_sz = WMI_MAX_TX_DATA_FRAME_LENGTH; + + /* + * To reduce the amount of committed memory for larger A_MSDU + * frames, use the recv-alloc threshold mechanism for larger + * packets. + */ + connect.ep_cb.rx_alloc_thresh = ATH6KL_BUFFER_SIZE; + connect.ep_cb.rx_allocthresh = ath6kl_alloc_amsdu_rxbuf; + + /* + * For the remaining data services set the connection flag to + * reduce dribbling, if configured to do so. + */ + connect.conn_flags |= HTC_CONN_FLGS_REDUCE_CRED_DRIB; + connect.conn_flags &= ~HTC_CONN_FLGS_THRESH_MASK; + connect.conn_flags |= HTC_CONN_FLGS_THRESH_LVL_HALF; + + connect.svc_id = WMI_DATA_BE_SVC; + + if (ath6kl_connectservice(ar, &connect, "WMI DATA BE")) + return -EIO; + + /* connect to back-ground map this to WMI LOW_PRI */ + connect.svc_id = WMI_DATA_BK_SVC; + if (ath6kl_connectservice(ar, &connect, "WMI DATA BK")) + return -EIO; + + /* connect to Video service, map this to to HI PRI */ + connect.svc_id = WMI_DATA_VI_SVC; + if (ath6kl_connectservice(ar, &connect, "WMI DATA VI")) + return -EIO; + + /* + * Connect to VO service, this is currently not mapped to a WMI + * priority stream due to historical reasons. WMI originally + * defined 3 priorities over 3 mailboxes We can change this when + * WMI is reworked so that priorities are not dependent on + * mailboxes. + */ + connect.svc_id = WMI_DATA_VO_SVC; + if (ath6kl_connectservice(ar, &connect, "WMI DATA VO")) + return -EIO; + + return 0; +} + +static void ath6kl_init_control_info(struct ath6kl *ar) +{ + u8 ctr; + + clear_bit(WMI_ENABLED, &ar->flag); + ath6kl_init_profile_info(ar); + ar->def_txkey_index = 0; + memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); + ar->ch_hint = 0; + ar->listen_intvl_t = A_DEFAULT_LISTEN_INTERVAL; + ar->listen_intvl_b = 0; + ar->tx_pwr = 0; + clear_bit(SKIP_SCAN, &ar->flag); + set_bit(WMM_ENABLED, &ar->flag); + ar->intra_bss = 1; + memset(&ar->sc_params, 0, sizeof(ar->sc_params)); + ar->sc_params.short_scan_ratio = WMI_SHORTSCANRATIO_DEFAULT; + ar->sc_params.scan_ctrl_flags = DEFAULT_SCAN_CTRL_FLAGS; + ar->lrssi_roam_threshold = DEF_LRSSI_ROAM_THRESHOLD; + + memset((u8 *)ar->sta_list, 0, + AP_MAX_NUM_STA * sizeof(struct ath6kl_sta)); + + spin_lock_init(&ar->mcastpsq_lock); + + /* Init the PS queues */ + for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { + spin_lock_init(&ar->sta_list[ctr].psq_lock); + skb_queue_head_init(&ar->sta_list[ctr].psq); + } + + skb_queue_head_init(&ar->mcastpsq); + + memcpy(ar->ap_country_code, DEF_AP_COUNTRY_CODE, 3); +} + +/* + * Set HTC/Mbox operational parameters, this can only be called when the + * target is in the BMI phase. + */ +static int ath6kl_set_htc_params(struct ath6kl *ar, u32 mbox_isr_yield_val, + u8 htc_ctrl_buf) +{ + int status; + u32 blk_size; + + blk_size = ar->mbox_info.block_size; + + if (htc_ctrl_buf) + blk_size |= ((u32)htc_ctrl_buf) << 16; + + /* set the host interest area for the block size */ + status = ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_mbox_io_block_sz)), + (u8 *)&blk_size, + 4); + if (status) { + ath6kl_err("bmi_write_memory for IO block size failed\n"); + goto out; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "block size set: %d (target addr:0x%X)\n", + blk_size, + ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_mbox_io_block_sz))); + + if (mbox_isr_yield_val) { + /* set the host interest area for the mbox ISR yield limit */ + status = ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_mbox_isr_yield_limit)), + (u8 *)&mbox_isr_yield_val, + 4); + if (status) { + ath6kl_err("bmi_write_memory for yield limit failed\n"); + goto out; + } + } + +out: + return status; +} + +#define REG_DUMP_COUNT_AR6003 60 +#define REGISTER_DUMP_LEN_MAX 60 + +static void ath6kl_dump_target_assert_info(struct ath6kl *ar) +{ + u32 address; + u32 regdump_loc = 0; + int status; + u32 regdump_val[REGISTER_DUMP_LEN_MAX]; + u32 i; + + if (ar->target_type != TARGET_TYPE_AR6003) + return; + + /* the reg dump pointer is copied to the host interest area */ + address = ath6kl_get_hi_item_addr(ar, HI_ITEM(hi_failure_state)); + address = TARG_VTOP(ar->target_type, address); + + /* read RAM location through diagnostic window */ + status = ath6kl_diag_read32(ar, address, ®dump_loc); + + if (status || !regdump_loc) { + ath6kl_err("failed to get ptr to register dump area\n"); + return; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "location of register dump data: 0x%X\n", + regdump_loc); + regdump_loc = TARG_VTOP(ar->target_type, regdump_loc); + + /* fetch register dump data */ + status = ath6kl_diag_read(ar, regdump_loc, (u8 *)®dump_val[0], + REG_DUMP_COUNT_AR6003 * (sizeof(u32))); + + if (status) { + ath6kl_err("failed to get register dump\n"); + return; + } + ath6kl_dbg(ATH6KL_DBG_TRC, "Register Dump:\n"); + + for (i = 0; i < REG_DUMP_COUNT_AR6003; i++) + ath6kl_dbg(ATH6KL_DBG_TRC, " %d : 0x%8.8X\n", + i, regdump_val[i]); + +} + +void ath6kl_target_failure(struct ath6kl *ar) +{ + ath6kl_err("target asserted\n"); + + /* try dumping target assertion information (if any) */ + ath6kl_dump_target_assert_info(ar); + +} + +static int ath6kl_target_config_wlan_params(struct ath6kl *ar) +{ + int status = 0; + int ret; + + /* + * Configure the device for rx dot11 header rules. "0,0" are the + * default values. Required if checksum offload is needed. Set + * RxMetaVersion to 2. + */ + if (ath6kl_wmi_set_rx_frame_format_cmd(ar->wmi, + ar->rx_meta_ver, 0, 0)) { + ath6kl_err("unable to set the rx frame format\n"); + status = -EIO; + } + + if (ar->conf_flags & ATH6KL_CONF_IGNORE_PS_FAIL_EVT_IN_SCAN) + if ((ath6kl_wmi_pmparams_cmd(ar->wmi, 0, 1, 0, 0, 1, + IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN)) != 0) { + ath6kl_err("unable to set power save fail event policy\n"); + status = -EIO; + } + + if (!(ar->conf_flags & ATH6KL_CONF_IGNORE_ERP_BARKER)) + if ((ath6kl_wmi_set_lpreamble_cmd(ar->wmi, 0, + WMI_DONOT_IGNORE_BARKER_IN_ERP)) != 0) { + ath6kl_err("unable to set barker preamble policy\n"); + status = -EIO; + } + + if (ath6kl_wmi_set_keepalive_cmd(ar->wmi, + WLAN_CONFIG_KEEP_ALIVE_INTERVAL)) { + ath6kl_err("unable to set keep alive interval\n"); + status = -EIO; + } + + if (ath6kl_wmi_disctimeout_cmd(ar->wmi, + WLAN_CONFIG_DISCONNECT_TIMEOUT)) { + ath6kl_err("unable to set disconnect timeout\n"); + status = -EIO; + } + + if (!(ar->conf_flags & ATH6KL_CONF_ENABLE_TX_BURST)) + if (ath6kl_wmi_set_wmm_txop(ar->wmi, WMI_TXOP_DISABLED)) { + ath6kl_err("unable to set txop bursting\n"); + status = -EIO; + } + + if (ar->p2p) { + ret = ath6kl_wmi_info_req_cmd(ar->wmi, + P2P_FLAG_CAPABILITIES_REQ | + P2P_FLAG_MACADDR_REQ | + P2P_FLAG_HMODEL_REQ); + if (ret) { + ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P " + "capabilities (%d) - assuming P2P not " + "supported\n", ret); + ar->p2p = 0; + } + } + + if (ar->p2p) { + /* Enable Probe Request reporting for P2P */ + ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, true); + if (ret) { + ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe " + "Request reporting (%d)\n", ret); + } + } + + return status; +} + +int ath6kl_configure_target(struct ath6kl *ar) +{ + u32 param, ram_reserved_size; + u8 fw_iftype; + + fw_iftype = ath6kl_get_fw_iftype(ar); + if (fw_iftype == 0xff) + return -EINVAL; + + /* Tell target which HTC version it is used*/ + param = HTC_PROTOCOL_VERSION; + if (ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_app_host_interest)), + (u8 *)¶m, 4) != 0) { + ath6kl_err("bmi_write_memory for htc version failed\n"); + return -EIO; + } + + /* set the firmware mode to STA/IBSS/AP */ + param = 0; + + if (ath6kl_bmi_read(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_option_flag)), + (u8 *)¶m, 4) != 0) { + ath6kl_err("bmi_read_memory for setting fwmode failed\n"); + return -EIO; + } + + param |= (1 << HI_OPTION_NUM_DEV_SHIFT); + param |= (fw_iftype << HI_OPTION_FW_MODE_SHIFT); + if (ar->p2p && fw_iftype == HI_OPTION_FW_MODE_BSS_STA) { + param |= HI_OPTION_FW_SUBMODE_P2PDEV << + HI_OPTION_FW_SUBMODE_SHIFT; + } + param |= (0 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); + param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); + + if (ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_option_flag)), + (u8 *)¶m, + 4) != 0) { + ath6kl_err("bmi_write_memory for setting fwmode failed\n"); + return -EIO; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "firmware mode set\n"); + + /* + * Hardcode the address use for the extended board data + * Ideally this should be pre-allocate by the OS at boot time + * But since it is a new feature and board data is loaded + * at init time, we have to workaround this from host. + * It is difficult to patch the firmware boot code, + * but possible in theory. + */ + + param = ar->hw.board_ext_data_addr; + ram_reserved_size = ar->hw.reserved_ram_size; + + if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_ext_data)), + (u8 *)¶m, 4) != 0) { + ath6kl_err("bmi_write_memory for hi_board_ext_data failed\n"); + return -EIO; + } + + if (ath6kl_bmi_write(ar, ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_end_ram_reserve_sz)), + (u8 *)&ram_reserved_size, 4) != 0) { + ath6kl_err("bmi_write_memory for hi_end_ram_reserve_sz failed\n"); + return -EIO; + } + + /* set the block size for the target */ + if (ath6kl_set_htc_params(ar, MBOX_YIELD_LIMIT, 0)) + /* use default number of control buffers */ + return -EIO; + + return 0; +} + +struct ath6kl *ath6kl_core_alloc(struct device *sdev) +{ + struct net_device *dev; + struct ath6kl *ar; + struct wireless_dev *wdev; + + wdev = ath6kl_cfg80211_init(sdev); + if (!wdev) { + ath6kl_err("ath6kl_cfg80211_init failed\n"); + return NULL; + } + + ar = wdev_priv(wdev); + ar->dev = sdev; + ar->wdev = wdev; + wdev->iftype = NL80211_IFTYPE_STATION; + + if (ath6kl_debug_init(ar)) { + ath6kl_err("Failed to initialize debugfs\n"); + ath6kl_cfg80211_deinit(ar); + return NULL; + } + + dev = alloc_netdev(0, "wlan%d", ether_setup); + if (!dev) { + ath6kl_err("no memory for network device instance\n"); + ath6kl_cfg80211_deinit(ar); + return NULL; + } + + dev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); + wdev->netdev = dev; + ar->sme_state = SME_DISCONNECTED; + + init_netdev(dev); + + ar->net_dev = dev; + set_bit(WLAN_ENABLED, &ar->flag); + + ar->wlan_pwr_state = WLAN_POWER_STATE_ON; + + spin_lock_init(&ar->lock); + + ath6kl_init_control_info(ar); + init_waitqueue_head(&ar->event_wq); + sema_init(&ar->sem, 1); + clear_bit(DESTROY_IN_PROGRESS, &ar->flag); + + INIT_LIST_HEAD(&ar->amsdu_rx_buffer_queue); + + setup_timer(&ar->disconnect_timer, disconnect_timer_handler, + (unsigned long) dev); + + return ar; +} + +int ath6kl_unavail_ev(struct ath6kl *ar) +{ + ath6kl_destroy(ar->net_dev, 1); + + return 0; +} + +/* firmware upload */ +static int ath6kl_get_fw(struct ath6kl *ar, const char *filename, + u8 **fw, size_t *fw_len) +{ + const struct firmware *fw_entry; + int ret; + + ret = request_firmware(&fw_entry, filename, ar->dev); + if (ret) + return ret; + + *fw_len = fw_entry->size; + *fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); + + if (*fw == NULL) + ret = -ENOMEM; + + release_firmware(fw_entry); + + return ret; +} + +#ifdef CONFIG_OF +static const char *get_target_ver_dir(const struct ath6kl *ar) +{ + switch (ar->version.target_ver) { + case AR6003_REV1_VERSION: + return "ath6k/AR6003/hw1.0"; + case AR6003_REV2_VERSION: + return "ath6k/AR6003/hw2.0"; + case AR6003_REV3_VERSION: + return "ath6k/AR6003/hw2.1.1"; + } + ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__, + ar->version.target_ver); + return NULL; +} + +/* + * Check the device tree for a board-id and use it to construct + * the pathname to the firmware file. Used (for now) to find a + * fallback to the "bdata.bin" file--typically a symlink to the + * appropriate board-specific file. + */ +static bool check_device_tree(struct ath6kl *ar) +{ + static const char *board_id_prop = "atheros,board-id"; + struct device_node *node; + char board_filename[64]; + const char *board_id; + int ret; + + for_each_compatible_node(node, NULL, "atheros,ath6kl") { + board_id = of_get_property(node, board_id_prop, NULL); + if (board_id == NULL) { + ath6kl_warn("No \"%s\" property on %s node.\n", + board_id_prop, node->name); + continue; + } + snprintf(board_filename, sizeof(board_filename), + "%s/bdata.%s.bin", get_target_ver_dir(ar), board_id); + + ret = ath6kl_get_fw(ar, board_filename, &ar->fw_board, + &ar->fw_board_len); + if (ret) { + ath6kl_err("Failed to get DT board file %s: %d\n", + board_filename, ret); + continue; + } + return true; + } + return false; +} +#else +static bool check_device_tree(struct ath6kl *ar) +{ + return false; +} +#endif /* CONFIG_OF */ + +static int ath6kl_fetch_board_file(struct ath6kl *ar) +{ + const char *filename; + int ret; + + if (ar->fw_board != NULL) + return 0; + + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + filename = AR6003_REV2_BOARD_DATA_FILE; + break; + case AR6004_REV1_VERSION: + filename = AR6004_REV1_BOARD_DATA_FILE; + break; + default: + filename = AR6003_REV3_BOARD_DATA_FILE; + break; + } + + ret = ath6kl_get_fw(ar, filename, &ar->fw_board, + &ar->fw_board_len); + if (ret == 0) { + /* managed to get proper board file */ + return 0; + } + + if (check_device_tree(ar)) { + /* got board file from device tree */ + return 0; + } + + /* there was no proper board file, try to use default instead */ + ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", + filename, ret); + + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE; + break; + case AR6004_REV1_VERSION: + filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE; + break; + default: + filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE; + break; + } + + ret = ath6kl_get_fw(ar, filename, &ar->fw_board, + &ar->fw_board_len); + if (ret) { + ath6kl_err("Failed to get default board file %s: %d\n", + filename, ret); + return ret; + } + + ath6kl_warn("WARNING! No proper board file was not found, instead using a default board file.\n"); + ath6kl_warn("Most likely your hardware won't work as specified. Install correct board file!\n"); + + return 0; +} + +static int ath6kl_fetch_otp_file(struct ath6kl *ar) +{ + const char *filename; + int ret; + + if (ar->fw_otp != NULL) + return 0; + + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + filename = AR6003_REV2_OTP_FILE; + break; + case AR6004_REV1_VERSION: + ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n"); + return 0; + break; + default: + filename = AR6003_REV3_OTP_FILE; + break; + } + + ret = ath6kl_get_fw(ar, filename, &ar->fw_otp, + &ar->fw_otp_len); + if (ret) { + ath6kl_err("Failed to get OTP file %s: %d\n", + filename, ret); + return ret; + } + + return 0; +} + +static int ath6kl_fetch_fw_file(struct ath6kl *ar) +{ + const char *filename; + int ret; + + if (ar->fw != NULL) + return 0; + + if (testmode) { + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + filename = AR6003_REV2_TCMD_FIRMWARE_FILE; + break; + case AR6003_REV3_VERSION: + filename = AR6003_REV3_TCMD_FIRMWARE_FILE; + break; + case AR6004_REV1_VERSION: + ath6kl_warn("testmode not supported with ar6004\n"); + return -EOPNOTSUPP; + default: + ath6kl_warn("unknown target version: 0x%x\n", + ar->version.target_ver); + return -EINVAL; + } + + set_bit(TESTMODE, &ar->flag); + + goto get_fw; + } + + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + filename = AR6003_REV2_FIRMWARE_FILE; + break; + case AR6004_REV1_VERSION: + filename = AR6004_REV1_FIRMWARE_FILE; + break; + default: + filename = AR6003_REV3_FIRMWARE_FILE; + break; + } + +get_fw: + ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len); + if (ret) { + ath6kl_err("Failed to get firmware file %s: %d\n", + filename, ret); + return ret; + } + + return 0; +} + +static int ath6kl_fetch_patch_file(struct ath6kl *ar) +{ + const char *filename; + int ret; + + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + filename = AR6003_REV2_PATCH_FILE; + break; + case AR6004_REV1_VERSION: + /* FIXME: implement for AR6004 */ + return 0; + break; + default: + filename = AR6003_REV3_PATCH_FILE; + break; + } + + if (ar->fw_patch == NULL) { + ret = ath6kl_get_fw(ar, filename, &ar->fw_patch, + &ar->fw_patch_len); + if (ret) { + ath6kl_err("Failed to get patch file %s: %d\n", + filename, ret); + return ret; + } + } + + return 0; +} + +static int ath6kl_fetch_fw_api1(struct ath6kl *ar) +{ + int ret; + + ret = ath6kl_fetch_otp_file(ar); + if (ret) + return ret; + + ret = ath6kl_fetch_fw_file(ar); + if (ret) + return ret; + + ret = ath6kl_fetch_patch_file(ar); + if (ret) + return ret; + + return 0; +} + +static int ath6kl_fetch_fw_api2(struct ath6kl *ar) +{ + size_t magic_len, len, ie_len; + const struct firmware *fw; + struct ath6kl_fw_ie *hdr; + const char *filename; + const u8 *data; + int ret, ie_id, i, index, bit; + __le32 *val; + + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + filename = AR6003_REV2_FIRMWARE_2_FILE; + break; + case AR6003_REV3_VERSION: + filename = AR6003_REV3_FIRMWARE_2_FILE; + break; + case AR6004_REV1_VERSION: + filename = AR6004_REV1_FIRMWARE_2_FILE; + break; + default: + return -EOPNOTSUPP; + } + + ret = request_firmware(&fw, filename, ar->dev); + if (ret) + return ret; + + data = fw->data; + len = fw->size; + + /* magic also includes the null byte, check that as well */ + magic_len = strlen(ATH6KL_FIRMWARE_MAGIC) + 1; + + if (len < magic_len) { + ret = -EINVAL; + goto out; + } + + if (memcmp(data, ATH6KL_FIRMWARE_MAGIC, magic_len) != 0) { + ret = -EINVAL; + goto out; + } + + len -= magic_len; + data += magic_len; + + /* loop elements */ + while (len > sizeof(struct ath6kl_fw_ie)) { + /* hdr is unaligned! */ + hdr = (struct ath6kl_fw_ie *) data; + + ie_id = le32_to_cpup(&hdr->id); + ie_len = le32_to_cpup(&hdr->len); + + len -= sizeof(*hdr); + data += sizeof(*hdr); + + if (len < ie_len) { + ret = -EINVAL; + goto out; + } + + switch (ie_id) { + case ATH6KL_FW_IE_OTP_IMAGE: + ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", + ie_len); + + ar->fw_otp = kmemdup(data, ie_len, GFP_KERNEL); + + if (ar->fw_otp == NULL) { + ret = -ENOMEM; + goto out; + } + + ar->fw_otp_len = ie_len; + break; + case ATH6KL_FW_IE_FW_IMAGE: + ath6kl_dbg(ATH6KL_DBG_BOOT, "found fw image ie (%zd B)\n", + ie_len); + + ar->fw = kmemdup(data, ie_len, GFP_KERNEL); + + if (ar->fw == NULL) { + ret = -ENOMEM; + goto out; + } + + ar->fw_len = ie_len; + break; + case ATH6KL_FW_IE_PATCH_IMAGE: + ath6kl_dbg(ATH6KL_DBG_BOOT, "found patch image ie (%zd B)\n", + ie_len); + + ar->fw_patch = kmemdup(data, ie_len, GFP_KERNEL); + + if (ar->fw_patch == NULL) { + ret = -ENOMEM; + goto out; + } + + ar->fw_patch_len = ie_len; + break; + case ATH6KL_FW_IE_RESERVED_RAM_SIZE: + val = (__le32 *) data; + ar->hw.reserved_ram_size = le32_to_cpup(val); + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "found reserved ram size ie 0x%d\n", + ar->hw.reserved_ram_size); + break; + case ATH6KL_FW_IE_CAPABILITIES: + ath6kl_dbg(ATH6KL_DBG_BOOT, + "found firmware capabilities ie (%zd B)\n", + ie_len); + + for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) { + index = ALIGN(i, 8) / 8; + bit = i % 8; + + if (data[index] & (1 << bit)) + __set_bit(i, ar->fw_capabilities); + } + + ath6kl_dbg_dump(ATH6KL_DBG_BOOT, "capabilities", "", + ar->fw_capabilities, + sizeof(ar->fw_capabilities)); + break; + case ATH6KL_FW_IE_PATCH_ADDR: + if (ie_len != sizeof(*val)) + break; + + val = (__le32 *) data; + ar->hw.dataset_patch_addr = le32_to_cpup(val); + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "found patch address ie 0x%d\n", + ar->hw.dataset_patch_addr); + break; + default: + ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n", + le32_to_cpup(&hdr->id)); + break; + } + + len -= ie_len; + data += ie_len; + }; + + ret = 0; +out: + release_firmware(fw); + + return ret; +} + +static int ath6kl_fetch_firmwares(struct ath6kl *ar) +{ + int ret; + + ret = ath6kl_fetch_board_file(ar); + if (ret) + return ret; + + ret = ath6kl_fetch_fw_api2(ar); + if (ret == 0) { + ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 2\n"); + return 0; + } + + ret = ath6kl_fetch_fw_api1(ar); + if (ret) + return ret; + + ath6kl_dbg(ATH6KL_DBG_BOOT, "using fw api 1\n"); + + return 0; +} + +static int ath6kl_upload_board_file(struct ath6kl *ar) +{ + u32 board_address, board_ext_address, param; + u32 board_data_size, board_ext_data_size; + int ret; + + if (WARN_ON(ar->fw_board == NULL)) + return -ENOENT; + + /* + * Determine where in Target RAM to write Board Data. + * For AR6004, host determine Target RAM address for + * writing board data. + */ + if (ar->target_type == TARGET_TYPE_AR6004) { + board_address = AR6004_REV1_BOARD_DATA_ADDRESS; + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_data)), + (u8 *) &board_address, 4); + } else { + ath6kl_bmi_read(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_data)), + (u8 *) &board_address, 4); + } + + /* determine where in target ram to write extended board data */ + ath6kl_bmi_read(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_ext_data)), + (u8 *) &board_ext_address, 4); + + if (board_ext_address == 0) { + ath6kl_err("Failed to get board file target address.\n"); + return -EINVAL; + } + + switch (ar->target_type) { + case TARGET_TYPE_AR6003: + board_data_size = AR6003_BOARD_DATA_SZ; + board_ext_data_size = AR6003_BOARD_EXT_DATA_SZ; + break; + case TARGET_TYPE_AR6004: + board_data_size = AR6004_BOARD_DATA_SZ; + board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ; + break; + default: + WARN_ON(1); + return -EINVAL; + break; + } + + if (ar->fw_board_len == (board_data_size + + board_ext_data_size)) { + + /* write extended board data */ + ath6kl_dbg(ATH6KL_DBG_BOOT, + "writing extended board data to 0x%x (%d B)\n", + board_ext_address, board_ext_data_size); + + ret = ath6kl_bmi_write(ar, board_ext_address, + ar->fw_board + board_data_size, + board_ext_data_size); + if (ret) { + ath6kl_err("Failed to write extended board data: %d\n", + ret); + return ret; + } + + /* record that extended board data is initialized */ + param = (board_ext_data_size << 16) | 1; + + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_ext_data_config)), + (unsigned char *) ¶m, 4); + } + + if (ar->fw_board_len < board_data_size) { + ath6kl_err("Too small board file: %zu\n", ar->fw_board_len); + ret = -EINVAL; + return ret; + } + + ath6kl_dbg(ATH6KL_DBG_BOOT, "writing board file to 0x%x (%d B)\n", + board_address, board_data_size); + + ret = ath6kl_bmi_write(ar, board_address, ar->fw_board, + board_data_size); + + if (ret) { + ath6kl_err("Board file bmi write failed: %d\n", ret); + return ret; + } + + /* record the fact that Board Data IS initialized */ + param = 1; + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_board_data_initialized)), + (u8 *)¶m, 4); + + return ret; +} + +static int ath6kl_upload_otp(struct ath6kl *ar) +{ + u32 address, param; + int ret; + + if (WARN_ON(ar->fw_otp == NULL)) + return -ENOENT; + + address = ar->hw.app_load_addr; + + ath6kl_dbg(ATH6KL_DBG_BOOT, "writing otp to 0x%x (%zd B)\n", address, + ar->fw_otp_len); + + ret = ath6kl_bmi_fast_download(ar, address, ar->fw_otp, + ar->fw_otp_len); + if (ret) { + ath6kl_err("Failed to upload OTP file: %d\n", ret); + return ret; + } + + /* read firmware start address */ + ret = ath6kl_bmi_read(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_app_start)), + (u8 *) &address, sizeof(address)); + + if (ret) { + ath6kl_err("Failed to read hi_app_start: %d\n", ret); + return ret; + } + + ar->hw.app_start_override_addr = address; + + ath6kl_dbg(ATH6KL_DBG_BOOT, "app_start_override_addr 0x%x\n", + ar->hw.app_start_override_addr); + + /* execute the OTP code */ + ath6kl_dbg(ATH6KL_DBG_BOOT, "executing OTP at 0x%x\n", address); + param = 0; + ath6kl_bmi_execute(ar, address, ¶m); + + return ret; +} + +static int ath6kl_upload_firmware(struct ath6kl *ar) +{ + u32 address; + int ret; + + if (WARN_ON(ar->fw == NULL)) + return -ENOENT; + + address = ar->hw.app_load_addr; + + ath6kl_dbg(ATH6KL_DBG_BOOT, "writing firmware to 0x%x (%zd B)\n", + address, ar->fw_len); + + ret = ath6kl_bmi_fast_download(ar, address, ar->fw, ar->fw_len); + + if (ret) { + ath6kl_err("Failed to write firmware: %d\n", ret); + return ret; + } + + /* + * Set starting address for firmware + * Don't need to setup app_start override addr on AR6004 + */ + if (ar->target_type != TARGET_TYPE_AR6004) { + address = ar->hw.app_start_override_addr; + ath6kl_bmi_set_app_start(ar, address); + } + return ret; +} + +static int ath6kl_upload_patch(struct ath6kl *ar) +{ + u32 address, param; + int ret; + + if (WARN_ON(ar->fw_patch == NULL)) + return -ENOENT; + + address = ar->hw.dataset_patch_addr; + + ath6kl_dbg(ATH6KL_DBG_BOOT, "writing patch to 0x%x (%zd B)\n", + address, ar->fw_patch_len); + + ret = ath6kl_bmi_write(ar, address, ar->fw_patch, ar->fw_patch_len); + if (ret) { + ath6kl_err("Failed to write patch file: %d\n", ret); + return ret; + } + + param = address; + ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_dset_list_head)), + (unsigned char *) ¶m, 4); + + return 0; +} + +static int ath6kl_init_upload(struct ath6kl *ar) +{ + u32 param, options, sleep, address; + int status = 0; + + if (ar->target_type != TARGET_TYPE_AR6003 && + ar->target_type != TARGET_TYPE_AR6004) + return -EINVAL; + + /* temporarily disable system sleep */ + address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS; + status = ath6kl_bmi_reg_read(ar, address, ¶m); + if (status) + return status; + + options = param; + + param |= ATH6KL_OPTION_SLEEP_DISABLE; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + + address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; + status = ath6kl_bmi_reg_read(ar, address, ¶m); + if (status) + return status; + + sleep = param; + + param |= SM(SYSTEM_SLEEP_DISABLE, 1); + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + + ath6kl_dbg(ATH6KL_DBG_TRC, "old options: %d, old sleep: %d\n", + options, sleep); + + /* program analog PLL register */ + /* no need to control 40/44MHz clock on AR6004 */ + if (ar->target_type != TARGET_TYPE_AR6004) { + status = ath6kl_bmi_reg_write(ar, ATH6KL_ANALOG_PLL_REGISTER, + 0xF9104001); + + if (status) + return status; + + /* Run at 80/88MHz by default */ + param = SM(CPU_CLOCK_STANDARD, 1); + + address = RTC_BASE_ADDRESS + CPU_CLOCK_ADDRESS; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + } + + param = 0; + address = RTC_BASE_ADDRESS + LPO_CAL_ADDRESS; + param = SM(LPO_CAL_ENABLE, 1); + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + + /* WAR to avoid SDIO CRC err */ + if (ar->version.target_ver == AR6003_REV2_VERSION) { + ath6kl_err("temporary war to avoid sdio crc error\n"); + + param = 0x20; + + address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + + address = GPIO_BASE_ADDRESS + GPIO_PIN11_ADDRESS; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + + address = GPIO_BASE_ADDRESS + GPIO_PIN12_ADDRESS; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + + address = GPIO_BASE_ADDRESS + GPIO_PIN13_ADDRESS; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + } + + /* write EEPROM data to Target RAM */ + status = ath6kl_upload_board_file(ar); + if (status) + return status; + + /* transfer One time Programmable data */ + status = ath6kl_upload_otp(ar); + if (status) + return status; + + /* Download Target firmware */ + status = ath6kl_upload_firmware(ar); + if (status) + return status; + + status = ath6kl_upload_patch(ar); + if (status) + return status; + + /* Restore system sleep */ + address = RTC_BASE_ADDRESS + SYSTEM_SLEEP_ADDRESS; + status = ath6kl_bmi_reg_write(ar, address, sleep); + if (status) + return status; + + address = MBOX_BASE_ADDRESS + LOCAL_SCRATCH_ADDRESS; + param = options | 0x20; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + + /* Configure GPIO AR6003 UART */ + param = CONFIG_AR600x_DEBUG_UART_TX_PIN; + status = ath6kl_bmi_write(ar, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_dbg_uart_txpin)), + (u8 *)¶m, 4); + + return status; +} + +static int ath6kl_init_hw_params(struct ath6kl *ar) +{ + switch (ar->version.target_ver) { + case AR6003_REV2_VERSION: + ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS; + ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS; + ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS; + ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE; + break; + case AR6003_REV3_VERSION: + ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS; + ar->hw.app_load_addr = 0x1234; + ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS; + ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE; + break; + case AR6004_REV1_VERSION: + ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS; + ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS; + ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS; + ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE; + break; + default: + ath6kl_err("Unsupported hardware version: 0x%x\n", + ar->version.target_ver); + return -EINVAL; + } + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n", + ar->version.target_ver, ar->target_type, + ar->hw.dataset_patch_addr, ar->hw.app_load_addr); + ath6kl_dbg(ATH6KL_DBG_BOOT, + "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x", + ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr, + ar->hw.reserved_ram_size); + + return 0; +} + +static int ath6kl_init(struct net_device *dev) +{ + struct ath6kl *ar = ath6kl_priv(dev); + int status = 0; + s32 timeleft; + + if (!ar) + return -EIO; + + /* Do we need to finish the BMI phase */ + if (ath6kl_bmi_done(ar)) { + status = -EIO; + goto ath6kl_init_done; + } + + /* Indicate that WMI is enabled (although not ready yet) */ + set_bit(WMI_ENABLED, &ar->flag); + ar->wmi = ath6kl_wmi_init(ar); + if (!ar->wmi) { + ath6kl_err("failed to initialize wmi\n"); + status = -EIO; + goto ath6kl_init_done; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: got wmi @ 0x%p.\n", __func__, ar->wmi); + + /* + * The reason we have to wait for the target here is that the + * driver layer has to init BMI in order to set the host block + * size. + */ + if (ath6kl_htc_wait_target(ar->htc_target)) { + status = -EIO; + goto err_node_cleanup; + } + + if (ath6kl_init_service_ep(ar)) { + status = -EIO; + goto err_cleanup_scatter; + } + + /* setup access class priority mappings */ + ar->ac_stream_pri_map[WMM_AC_BK] = 0; /* lowest */ + ar->ac_stream_pri_map[WMM_AC_BE] = 1; + ar->ac_stream_pri_map[WMM_AC_VI] = 2; + ar->ac_stream_pri_map[WMM_AC_VO] = 3; /* highest */ + + /* give our connected endpoints some buffers */ + ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); + ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); + + /* allocate some buffers that handle larger AMSDU frames */ + ath6kl_refill_amsdu_rxbufs(ar, ATH6KL_MAX_AMSDU_RX_BUFFERS); + + /* setup credit distribution */ + ath6k_setup_credit_dist(ar->htc_target, &ar->credit_state_info); + + ath6kl_cookie_init(ar); + + /* start HTC */ + status = ath6kl_htc_start(ar->htc_target); + + if (status) { + ath6kl_cookie_cleanup(ar); + goto err_rxbuf_cleanup; + } + + /* Wait for Wmi event to be ready */ + timeleft = wait_event_interruptible_timeout(ar->event_wq, + test_bit(WMI_READY, + &ar->flag), + WMI_TIMEOUT); + + ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n"); + + if (ar->version.abi_ver != ATH6KL_ABI_VERSION) { + ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n", + ATH6KL_ABI_VERSION, ar->version.abi_ver); + status = -EIO; + goto err_htc_stop; + } + + if (!timeleft || signal_pending(current)) { + ath6kl_err("wmi is not ready or wait was interrupted\n"); + status = -EIO; + goto err_htc_stop; + } + + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: wmi is ready\n", __func__); + + /* communicate the wmi protocol verision to the target */ + if ((ath6kl_set_host_app_area(ar)) != 0) + ath6kl_err("unable to set the host app area\n"); + + ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER | + ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST; + + ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + + status = ath6kl_target_config_wlan_params(ar); + if (!status) + goto ath6kl_init_done; + +err_htc_stop: + ath6kl_htc_stop(ar->htc_target); +err_rxbuf_cleanup: + ath6kl_htc_flush_rx_buf(ar->htc_target); + ath6kl_cleanup_amsdu_rxbufs(ar); +err_cleanup_scatter: + ath6kl_hif_cleanup_scatter(ar); +err_node_cleanup: + ath6kl_wmi_shutdown(ar->wmi); + clear_bit(WMI_ENABLED, &ar->flag); + ar->wmi = NULL; + +ath6kl_init_done: + return status; +} + +int ath6kl_core_init(struct ath6kl *ar) +{ + int ret = 0; + struct ath6kl_bmi_target_info targ_info; + + ar->ath6kl_wq = create_singlethread_workqueue("ath6kl"); + if (!ar->ath6kl_wq) + return -ENOMEM; + + ret = ath6kl_bmi_init(ar); + if (ret) + goto err_wq; + + ret = ath6kl_bmi_get_target_info(ar, &targ_info); + if (ret) + goto err_bmi_cleanup; + + ar->version.target_ver = le32_to_cpu(targ_info.version); + ar->target_type = le32_to_cpu(targ_info.type); + ar->wdev->wiphy->hw_version = le32_to_cpu(targ_info.version); + + ret = ath6kl_init_hw_params(ar); + if (ret) + goto err_bmi_cleanup; + + ret = ath6kl_configure_target(ar); + if (ret) + goto err_bmi_cleanup; + + ar->htc_target = ath6kl_htc_create(ar); + + if (!ar->htc_target) { + ret = -ENOMEM; + goto err_bmi_cleanup; + } + + ar->aggr_cntxt = aggr_init(ar->net_dev); + if (!ar->aggr_cntxt) { + ath6kl_err("failed to initialize aggr\n"); + ret = -ENOMEM; + goto err_htc_cleanup; + } + + ret = ath6kl_fetch_firmwares(ar); + if (ret) + goto err_htc_cleanup; + + ret = ath6kl_init_upload(ar); + if (ret) + goto err_htc_cleanup; + + ret = ath6kl_init(ar->net_dev); + if (ret) + goto err_htc_cleanup; + + /* This runs the init function if registered */ + ret = register_netdev(ar->net_dev); + if (ret) { + ath6kl_err("register_netdev failed\n"); + ath6kl_destroy(ar->net_dev, 0); + return ret; + } + + set_bit(NETDEV_REGISTERED, &ar->flag); + + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", + __func__, ar->net_dev->name, ar->net_dev, ar); + + return ret; + +err_htc_cleanup: + ath6kl_htc_cleanup(ar->htc_target); +err_bmi_cleanup: + ath6kl_bmi_cleanup(ar); +err_wq: + destroy_workqueue(ar->ath6kl_wq); + return ret; +} + +void ath6kl_stop_txrx(struct ath6kl *ar) +{ + struct net_device *ndev = ar->net_dev; + + if (!ndev) + return; + + set_bit(DESTROY_IN_PROGRESS, &ar->flag); + + if (down_interruptible(&ar->sem)) { + ath6kl_err("down_interruptible failed\n"); + return; + } + + if (ar->wlan_pwr_state != WLAN_POWER_STATE_CUT_PWR) + ath6kl_stop_endpoint(ndev, false, true); + + clear_bit(WLAN_ENABLED, &ar->flag); +} + +/* + * We need to differentiate between the surprise and planned removal of the + * device because of the following consideration: + * + * - In case of surprise removal, the hcd already frees up the pending + * for the device and hence there is no need to unregister the function + * driver inorder to get these requests. For planned removal, the function + * driver has to explicitly unregister itself to have the hcd return all the + * pending requests before the data structures for the devices are freed up. + * Note that as per the current implementation, the function driver will + * end up releasing all the devices since there is no API to selectively + * release a particular device. + * + * - Certain commands issued to the target can be skipped for surprise + * removal since they will anyway not go through. + */ +void ath6kl_destroy(struct net_device *dev, unsigned int unregister) +{ + struct ath6kl *ar; + + if (!dev || !ath6kl_priv(dev)) { + ath6kl_err("failed to get device structure\n"); + return; + } + + ar = ath6kl_priv(dev); + + destroy_workqueue(ar->ath6kl_wq); + + if (ar->htc_target) + ath6kl_htc_cleanup(ar->htc_target); + + aggr_module_destroy(ar->aggr_cntxt); + + ath6kl_cookie_cleanup(ar); + + ath6kl_cleanup_amsdu_rxbufs(ar); + + ath6kl_bmi_cleanup(ar); + + ath6kl_debug_cleanup(ar); + + if (unregister && test_bit(NETDEV_REGISTERED, &ar->flag)) { + unregister_netdev(dev); + clear_bit(NETDEV_REGISTERED, &ar->flag); + } + + free_netdev(dev); + + kfree(ar->fw_board); + kfree(ar->fw_otp); + kfree(ar->fw); + kfree(ar->fw_patch); + + ath6kl_cfg80211_deinit(ar); +} diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c new file mode 100644 index 000000000000..30b5a53db9ed --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -0,0 +1,1477 @@ +/* + * 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 "core.h" +#include "hif-ops.h" +#include "cfg80211.h" +#include "target.h" +#include "debug.h" + +struct ath6kl_sta *ath6kl_find_sta(struct ath6kl *ar, u8 *node_addr) +{ + struct ath6kl_sta *conn = NULL; + u8 i, max_conn; + + max_conn = (ar->nw_type == AP_NETWORK) ? AP_MAX_NUM_STA : 0; + + for (i = 0; i < max_conn; i++) { + if (memcmp(node_addr, ar->sta_list[i].mac, ETH_ALEN) == 0) { + conn = &ar->sta_list[i]; + break; + } + } + + return conn; +} + +struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid) +{ + struct ath6kl_sta *conn = NULL; + u8 ctr; + + for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { + if (ar->sta_list[ctr].aid == aid) { + conn = &ar->sta_list[ctr]; + break; + } + } + return conn; +} + +static void ath6kl_add_new_sta(struct ath6kl *ar, u8 *mac, u16 aid, u8 *wpaie, + u8 ielen, u8 keymgmt, u8 ucipher, u8 auth) +{ + struct ath6kl_sta *sta; + u8 free_slot; + + free_slot = aid - 1; + + sta = &ar->sta_list[free_slot]; + memcpy(sta->mac, mac, ETH_ALEN); + if (ielen <= ATH6KL_MAX_IE) + memcpy(sta->wpa_ie, wpaie, ielen); + sta->aid = aid; + sta->keymgmt = keymgmt; + sta->ucipher = ucipher; + sta->auth = auth; + + ar->sta_list_index = ar->sta_list_index | (1 << free_slot); + ar->ap_stats.sta[free_slot].aid = cpu_to_le32(aid); +} + +static void ath6kl_sta_cleanup(struct ath6kl *ar, u8 i) +{ + struct ath6kl_sta *sta = &ar->sta_list[i]; + + /* empty the queued pkts in the PS queue if any */ + spin_lock_bh(&sta->psq_lock); + skb_queue_purge(&sta->psq); + spin_unlock_bh(&sta->psq_lock); + + memset(&ar->ap_stats.sta[sta->aid - 1], 0, + sizeof(struct wmi_per_sta_stat)); + memset(sta->mac, 0, ETH_ALEN); + memset(sta->wpa_ie, 0, ATH6KL_MAX_IE); + sta->aid = 0; + sta->sta_flags = 0; + + ar->sta_list_index = ar->sta_list_index & ~(1 << i); + +} + +static u8 ath6kl_remove_sta(struct ath6kl *ar, u8 *mac, u16 reason) +{ + u8 i, removed = 0; + + if (is_zero_ether_addr(mac)) + return removed; + + if (is_broadcast_ether_addr(mac)) { + ath6kl_dbg(ATH6KL_DBG_TRC, "deleting all station\n"); + + for (i = 0; i < AP_MAX_NUM_STA; i++) { + if (!is_zero_ether_addr(ar->sta_list[i].mac)) { + ath6kl_sta_cleanup(ar, i); + removed = 1; + } + } + } else { + for (i = 0; i < AP_MAX_NUM_STA; i++) { + if (memcmp(ar->sta_list[i].mac, mac, ETH_ALEN) == 0) { + ath6kl_dbg(ATH6KL_DBG_TRC, + "deleting station %pM aid=%d reason=%d\n", + mac, ar->sta_list[i].aid, reason); + ath6kl_sta_cleanup(ar, i); + removed = 1; + break; + } + } + } + + return removed; +} + +enum htc_endpoint_id ath6kl_ac2_endpoint_id(void *devt, u8 ac) +{ + struct ath6kl *ar = devt; + return ar->ac2ep_map[ac]; +} + +struct ath6kl_cookie *ath6kl_alloc_cookie(struct ath6kl *ar) +{ + struct ath6kl_cookie *cookie; + + cookie = ar->cookie_list; + if (cookie != NULL) { + ar->cookie_list = cookie->arc_list_next; + ar->cookie_count--; + } + + return cookie; +} + +void ath6kl_cookie_init(struct ath6kl *ar) +{ + u32 i; + + ar->cookie_list = NULL; + ar->cookie_count = 0; + + memset(ar->cookie_mem, 0, sizeof(ar->cookie_mem)); + + for (i = 0; i < MAX_COOKIE_NUM; i++) + ath6kl_free_cookie(ar, &ar->cookie_mem[i]); +} + +void ath6kl_cookie_cleanup(struct ath6kl *ar) +{ + ar->cookie_list = NULL; + ar->cookie_count = 0; +} + +void ath6kl_free_cookie(struct ath6kl *ar, struct ath6kl_cookie *cookie) +{ + /* Insert first */ + + if (!ar || !cookie) + return; + + cookie->arc_list_next = ar->cookie_list; + ar->cookie_list = cookie; + ar->cookie_count++; +} + +/* set the window address register (using 4-byte register access ). */ +static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) +{ + int status; + s32 i; + __le32 addr_val; + + /* + * Write bytes 1,2,3 of the register to set the upper address bytes, + * the LSB is written last to initiate the access cycle + */ + + for (i = 1; i <= 3; i++) { + /* + * Fill the buffer with the address byte value we want to + * hit 4 times. No need to worry about endianness as the + * same byte is copied to all four bytes of addr_val at + * any time. + */ + memset((u8 *)&addr_val, ((u8 *)&addr)[i], 4); + + /* + * Hit each byte of the register address with a 4-byte + * write operation to the same address, this is a harmless + * operation. + */ + status = hif_read_write_sync(ar, reg_addr + i, (u8 *)&addr_val, + 4, HIF_WR_SYNC_BYTE_FIX); + if (status) + break; + } + + if (status) { + ath6kl_err("failed to write initial bytes of 0x%x to window reg: 0x%X\n", + addr, reg_addr); + return status; + } + + /* + * Write the address register again, this time write the whole + * 4-byte value. The effect here is that the LSB write causes the + * cycle to start, the extra 3 byte write to bytes 1,2,3 has no + * effect since we are writing the same values again + */ + addr_val = cpu_to_le32(addr); + status = hif_read_write_sync(ar, reg_addr, + (u8 *)&(addr_val), + 4, HIF_WR_SYNC_BYTE_INC); + + if (status) { + ath6kl_err("failed to write 0x%x to window reg: 0x%X\n", + addr, reg_addr); + return status; + } + + return 0; +} + +/* + * Read from the hardware through its diagnostic window. No cooperation + * from the firmware is required for this. + */ +int ath6kl_diag_read32(struct ath6kl *ar, u32 address, u32 *value) +{ + int ret; + + /* set window register to start read cycle */ + ret = ath6kl_set_addrwin_reg(ar, WINDOW_READ_ADDR_ADDRESS, address); + if (ret) + return ret; + + /* read the data */ + ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) value, + sizeof(*value), HIF_RD_SYNC_BYTE_INC); + if (ret) { + ath6kl_warn("failed to read32 through diagnose window: %d\n", + ret); + return ret; + } + + return 0; +} + +/* + * Write to the ATH6KL through its diagnostic window. No cooperation from + * the Target is required for this. + */ +int ath6kl_diag_write32(struct ath6kl *ar, u32 address, __le32 value) +{ + int ret; + + /* set write data */ + ret = hif_read_write_sync(ar, WINDOW_DATA_ADDRESS, (u8 *) &value, + sizeof(value), HIF_WR_SYNC_BYTE_INC); + if (ret) { + ath6kl_err("failed to write 0x%x during diagnose window to 0x%d\n", + address, value); + return ret; + } + + /* set window register, which starts the write cycle */ + return ath6kl_set_addrwin_reg(ar, WINDOW_WRITE_ADDR_ADDRESS, + address); +} + +int ath6kl_diag_read(struct ath6kl *ar, u32 address, void *data, u32 length) +{ + u32 count, *buf = data; + int ret; + + if (WARN_ON(length % 4)) + return -EINVAL; + + for (count = 0; count < length / 4; count++, address += 4) { + ret = ath6kl_diag_read32(ar, address, &buf[count]); + if (ret) + return ret; + } + + return 0; +} + +int ath6kl_diag_write(struct ath6kl *ar, u32 address, void *data, u32 length) +{ + u32 count; + __le32 *buf = data; + int ret; + + if (WARN_ON(length % 4)) + return -EINVAL; + + for (count = 0; count < length / 4; count++, address += 4) { + ret = ath6kl_diag_write32(ar, address, buf[count]); + if (ret) + return ret; + } + + return 0; +} + +int ath6kl_read_fwlogs(struct ath6kl *ar) +{ + struct ath6kl_dbglog_hdr debug_hdr; + struct ath6kl_dbglog_buf debug_buf; + u32 address, length, dropped, firstbuf, debug_hdr_addr; + int ret = 0, loop; + u8 *buf; + + buf = kmalloc(ATH6KL_FWLOG_PAYLOAD_SIZE, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + address = TARG_VTOP(ar->target_type, + ath6kl_get_hi_item_addr(ar, + HI_ITEM(hi_dbglog_hdr))); + + ret = ath6kl_diag_read32(ar, address, &debug_hdr_addr); + if (ret) + goto out; + + /* Get the contents of the ring buffer */ + if (debug_hdr_addr == 0) { + ath6kl_warn("Invalid address for debug_hdr_addr\n"); + ret = -EINVAL; + goto out; + } + + address = TARG_VTOP(ar->target_type, debug_hdr_addr); + ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr)); + + address = TARG_VTOP(ar->target_type, + le32_to_cpu(debug_hdr.dbuf_addr)); + firstbuf = address; + dropped = le32_to_cpu(debug_hdr.dropped); + ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); + + loop = 100; + + do { + address = TARG_VTOP(ar->target_type, + le32_to_cpu(debug_buf.buffer_addr)); + length = le32_to_cpu(debug_buf.length); + + if (length != 0 && (le32_to_cpu(debug_buf.length) <= + le32_to_cpu(debug_buf.bufsize))) { + length = ALIGN(length, 4); + + ret = ath6kl_diag_read(ar, address, + buf, length); + if (ret) + goto out; + + ath6kl_debug_fwlog_event(ar, buf, length); + } + + address = TARG_VTOP(ar->target_type, + le32_to_cpu(debug_buf.next)); + ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf)); + if (ret) + goto out; + + loop--; + + if (WARN_ON(loop == 0)) { + ret = -ETIMEDOUT; + goto out; + } + } while (address != firstbuf); + +out: + kfree(buf); + + return ret; +} + +/* FIXME: move to a better place, target.h? */ +#define AR6003_RESET_CONTROL_ADDRESS 0x00004000 +#define AR6004_RESET_CONTROL_ADDRESS 0x00004000 + +static void ath6kl_reset_device(struct ath6kl *ar, u32 target_type, + bool wait_fot_compltn, bool cold_reset) +{ + int status = 0; + u32 address; + __le32 data; + + if (target_type != TARGET_TYPE_AR6003 && + target_type != TARGET_TYPE_AR6004) + return; + + data = cold_reset ? cpu_to_le32(RESET_CONTROL_COLD_RST) : + cpu_to_le32(RESET_CONTROL_MBOX_RST); + + switch (target_type) { + case TARGET_TYPE_AR6003: + address = AR6003_RESET_CONTROL_ADDRESS; + break; + case TARGET_TYPE_AR6004: + address = AR6004_RESET_CONTROL_ADDRESS; + break; + default: + address = AR6003_RESET_CONTROL_ADDRESS; + break; + } + + status = ath6kl_diag_write32(ar, address, data); + + if (status) + ath6kl_err("failed to reset target\n"); +} + +void ath6kl_stop_endpoint(struct net_device *dev, bool keep_profile, + bool get_dbglogs) +{ + struct ath6kl *ar = ath6kl_priv(dev); + static u8 bcast_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + bool discon_issued; + + netif_stop_queue(dev); + + /* disable the target and the interrupts associated with it */ + if (test_bit(WMI_READY, &ar->flag)) { + discon_issued = (test_bit(CONNECTED, &ar->flag) || + test_bit(CONNECT_PEND, &ar->flag)); + ath6kl_disconnect(ar); + if (!keep_profile) + ath6kl_init_profile_info(ar); + + del_timer(&ar->disconnect_timer); + + clear_bit(WMI_READY, &ar->flag); + ath6kl_wmi_shutdown(ar->wmi); + clear_bit(WMI_ENABLED, &ar->flag); + ar->wmi = NULL; + + /* + * After wmi_shudown all WMI events will be dropped. We + * need to cleanup the buffers allocated in AP mode and + * give disconnect notification to stack, which usually + * happens in the disconnect_event. Simulate the disconnect + * event by calling the function directly. Sometimes + * disconnect_event will be received when the debug logs + * are collected. + */ + if (discon_issued) + ath6kl_disconnect_event(ar, DISCONNECT_CMD, + (ar->nw_type & AP_NETWORK) ? + bcast_mac : ar->bssid, + 0, NULL, 0); + + ar->user_key_ctrl = 0; + + } else { + ath6kl_dbg(ATH6KL_DBG_TRC, + "%s: wmi is not ready 0x%p 0x%p\n", + __func__, ar, ar->wmi); + + /* Shut down WMI if we have started it */ + if (test_bit(WMI_ENABLED, &ar->flag)) { + ath6kl_dbg(ATH6KL_DBG_TRC, + "%s: shut down wmi\n", __func__); + ath6kl_wmi_shutdown(ar->wmi); + clear_bit(WMI_ENABLED, &ar->flag); + ar->wmi = NULL; + } + } + + if (ar->htc_target) { + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: shut down htc\n", __func__); + ath6kl_htc_stop(ar->htc_target); + } + + /* + * Try to reset the device if we can. The driver may have been + * configure NOT to reset the target during a debug session. + */ + ath6kl_dbg(ATH6KL_DBG_TRC, + "attempting to reset target on instance destroy\n"); + ath6kl_reset_device(ar, ar->target_type, true, true); +} + +static void ath6kl_install_static_wep_keys(struct ath6kl *ar) +{ + u8 index; + u8 keyusage; + + for (index = WMI_MIN_KEY_INDEX; index <= WMI_MAX_KEY_INDEX; index++) { + if (ar->wep_key_list[index].key_len) { + keyusage = GROUP_USAGE; + if (index == ar->def_txkey_index) + keyusage |= TX_USAGE; + + ath6kl_wmi_addkey_cmd(ar->wmi, + index, + WEP_CRYPT, + keyusage, + ar->wep_key_list[index].key_len, + NULL, + ar->wep_key_list[index].key, + KEY_OP_INIT_VAL, NULL, + NO_SYNC_WMIFLAG); + } + } +} + +void ath6kl_connect_ap_mode_bss(struct ath6kl *ar, u16 channel) +{ + struct ath6kl_req_key *ik; + int res; + u8 key_rsc[ATH6KL_KEY_SEQ_LEN]; + + ik = &ar->ap_mode_bkey; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "AP mode started on %u MHz\n", channel); + + switch (ar->auth_mode) { + case NONE_AUTH: + if (ar->prwise_crypto == WEP_CRYPT) + ath6kl_install_static_wep_keys(ar); + break; + case WPA_PSK_AUTH: + case WPA2_PSK_AUTH: + case (WPA_PSK_AUTH | WPA2_PSK_AUTH): + if (!ik->valid) + break; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for " + "the initial group key for AP mode\n"); + memset(key_rsc, 0, sizeof(key_rsc)); + res = ath6kl_wmi_addkey_cmd( + ar->wmi, ik->key_index, ik->key_type, + GROUP_USAGE, ik->key_len, key_rsc, ik->key, + KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); + if (res) { + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed " + "addkey failed: %d\n", res); + } + break; + } + + ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); + set_bit(CONNECTED, &ar->flag); + netif_carrier_on(ar->net_dev); +} + +void ath6kl_connect_ap_mode_sta(struct ath6kl *ar, u16 aid, u8 *mac_addr, + u8 keymgmt, u8 ucipher, u8 auth, + u8 assoc_req_len, u8 *assoc_info) +{ + u8 *ies = NULL, *wpa_ie = NULL, *pos; + size_t ies_len = 0; + struct station_info sinfo; + + ath6kl_dbg(ATH6KL_DBG_TRC, "new station %pM aid=%d\n", mac_addr, aid); + + if (assoc_req_len > sizeof(struct ieee80211_hdr_3addr)) { + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *) assoc_info; + if (ieee80211_is_assoc_req(mgmt->frame_control) && + assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) + + sizeof(mgmt->u.assoc_req)) { + ies = mgmt->u.assoc_req.variable; + ies_len = assoc_info + assoc_req_len - ies; + } else if (ieee80211_is_reassoc_req(mgmt->frame_control) && + assoc_req_len >= sizeof(struct ieee80211_hdr_3addr) + + sizeof(mgmt->u.reassoc_req)) { + ies = mgmt->u.reassoc_req.variable; + ies_len = assoc_info + assoc_req_len - ies; + } + } + + pos = ies; + while (pos && pos + 1 < ies + ies_len) { + if (pos + 2 + pos[1] > ies + ies_len) + break; + if (pos[0] == WLAN_EID_RSN) + wpa_ie = pos; /* RSN IE */ + else if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && + pos[1] >= 4 && + pos[2] == 0x00 && pos[3] == 0x50 && pos[4] == 0xf2) { + if (pos[5] == 0x01) + wpa_ie = pos; /* WPA IE */ + else if (pos[5] == 0x04) { + wpa_ie = pos; /* WPS IE */ + break; /* overrides WPA/RSN IE */ + } + } + pos += 2 + pos[1]; + } + + ath6kl_add_new_sta(ar, mac_addr, aid, wpa_ie, + wpa_ie ? 2 + wpa_ie[1] : 0, + keymgmt, ucipher, auth); + + /* send event to application */ + memset(&sinfo, 0, sizeof(sinfo)); + + /* TODO: sinfo.generation */ + + sinfo.assoc_req_ies = ies; + sinfo.assoc_req_ies_len = ies_len; + sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; + + cfg80211_new_sta(ar->net_dev, mac_addr, &sinfo, GFP_KERNEL); + + netif_wake_queue(ar->net_dev); +} + +/* Functions for Tx credit handling */ +void ath6k_credit_init(struct htc_credit_state_info *cred_info, + struct list_head *ep_list, + int tot_credits) +{ + struct htc_endpoint_credit_dist *cur_ep_dist; + int count; + + cred_info->cur_free_credits = tot_credits; + cred_info->total_avail_credits = tot_credits; + + list_for_each_entry(cur_ep_dist, ep_list, list) { + if (cur_ep_dist->endpoint == ENDPOINT_0) + continue; + + cur_ep_dist->cred_min = cur_ep_dist->cred_per_msg; + + if (tot_credits > 4) + if ((cur_ep_dist->svc_id == WMI_DATA_BK_SVC) || + (cur_ep_dist->svc_id == WMI_DATA_BE_SVC)) { + ath6kl_deposit_credit_to_ep(cred_info, + cur_ep_dist, + cur_ep_dist->cred_min); + cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; + } + + if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) { + ath6kl_deposit_credit_to_ep(cred_info, cur_ep_dist, + cur_ep_dist->cred_min); + /* + * Control service is always marked active, it + * never goes inactive EVER. + */ + cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; + } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC) + /* this is the lowest priority data endpoint */ + cred_info->lowestpri_ep_dist = cur_ep_dist->list; + + /* + * Streams have to be created (explicit | implicit) for all + * kinds of traffic. BE endpoints are also inactive in the + * beginning. When BE traffic starts it creates implicit + * streams that redistributes credits. + * + * Note: all other endpoints have minimums set but are + * initially given NO credits. credits will be distributed + * as traffic activity demands + */ + } + + WARN_ON(cred_info->cur_free_credits <= 0); + + list_for_each_entry(cur_ep_dist, ep_list, list) { + if (cur_ep_dist->endpoint == ENDPOINT_0) + continue; + + if (cur_ep_dist->svc_id == WMI_CONTROL_SVC) + cur_ep_dist->cred_norm = cur_ep_dist->cred_per_msg; + else { + /* + * For the remaining data endpoints, we assume that + * each cred_per_msg are the same. We use a simple + * calculation here, we take the remaining credits + * and determine how many max messages this can + * cover and then set each endpoint's normal value + * equal to 3/4 this amount. + */ + count = (cred_info->cur_free_credits / + cur_ep_dist->cred_per_msg) + * cur_ep_dist->cred_per_msg; + count = (count * 3) >> 2; + count = max(count, cur_ep_dist->cred_per_msg); + cur_ep_dist->cred_norm = count; + + } + } +} + +/* initialize and setup credit distribution */ +int ath6k_setup_credit_dist(void *htc_handle, + struct htc_credit_state_info *cred_info) +{ + u16 servicepriority[5]; + + memset(cred_info, 0, sizeof(struct htc_credit_state_info)); + + servicepriority[0] = WMI_CONTROL_SVC; /* highest */ + servicepriority[1] = WMI_DATA_VO_SVC; + servicepriority[2] = WMI_DATA_VI_SVC; + servicepriority[3] = WMI_DATA_BE_SVC; + servicepriority[4] = WMI_DATA_BK_SVC; /* lowest */ + + /* set priority list */ + ath6kl_htc_set_credit_dist(htc_handle, cred_info, servicepriority, 5); + + return 0; +} + +/* reduce an ep's credits back to a set limit */ +static void ath6k_reduce_credits(struct htc_credit_state_info *cred_info, + struct htc_endpoint_credit_dist *ep_dist, + int limit) +{ + int credits; + + ep_dist->cred_assngd = limit; + + if (ep_dist->credits <= limit) + return; + + credits = ep_dist->credits - limit; + ep_dist->credits -= credits; + cred_info->cur_free_credits += credits; +} + +static void ath6k_credit_update(struct htc_credit_state_info *cred_info, + struct list_head *epdist_list) +{ + struct htc_endpoint_credit_dist *cur_dist_list; + + list_for_each_entry(cur_dist_list, epdist_list, list) { + if (cur_dist_list->endpoint == ENDPOINT_0) + continue; + + if (cur_dist_list->cred_to_dist > 0) { + cur_dist_list->credits += + cur_dist_list->cred_to_dist; + cur_dist_list->cred_to_dist = 0; + if (cur_dist_list->credits > + cur_dist_list->cred_assngd) + ath6k_reduce_credits(cred_info, + cur_dist_list, + cur_dist_list->cred_assngd); + + if (cur_dist_list->credits > + cur_dist_list->cred_norm) + ath6k_reduce_credits(cred_info, cur_dist_list, + cur_dist_list->cred_norm); + + if (!(cur_dist_list->dist_flags & HTC_EP_ACTIVE)) { + if (cur_dist_list->txq_depth == 0) + ath6k_reduce_credits(cred_info, + cur_dist_list, 0); + } + } + } +} + +/* + * HTC has an endpoint that needs credits, ep_dist is the endpoint in + * question. + */ +void ath6k_seek_credits(struct htc_credit_state_info *cred_info, + struct htc_endpoint_credit_dist *ep_dist) +{ + struct htc_endpoint_credit_dist *curdist_list; + int credits = 0; + int need; + + if (ep_dist->svc_id == WMI_CONTROL_SVC) + goto out; + + if ((ep_dist->svc_id == WMI_DATA_VI_SVC) || + (ep_dist->svc_id == WMI_DATA_VO_SVC)) + if ((ep_dist->cred_assngd >= ep_dist->cred_norm)) + goto out; + + /* + * For all other services, we follow a simple algorithm of: + * + * 1. checking the free pool for credits + * 2. checking lower priority endpoints for credits to take + */ + + credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); + + if (credits >= ep_dist->seek_cred) + goto out; + + /* + * We don't have enough in the free pool, try taking away from + * lower priority services The rule for taking away credits: + * + * 1. Only take from lower priority endpoints + * 2. Only take what is allocated above the minimum (never + * starve an endpoint completely) + * 3. Only take what you need. + */ + + list_for_each_entry_reverse(curdist_list, + &cred_info->lowestpri_ep_dist, + list) { + if (curdist_list == ep_dist) + break; + + need = ep_dist->seek_cred - cred_info->cur_free_credits; + + if ((curdist_list->cred_assngd - need) >= + curdist_list->cred_min) { + /* + * The current one has been allocated more than + * it's minimum and it has enough credits assigned + * above it's minimum to fulfill our need try to + * take away just enough to fulfill our need. + */ + ath6k_reduce_credits(cred_info, curdist_list, + curdist_list->cred_assngd - need); + + if (cred_info->cur_free_credits >= + ep_dist->seek_cred) + break; + } + + if (curdist_list->endpoint == ENDPOINT_0) + break; + } + + credits = min(cred_info->cur_free_credits, ep_dist->seek_cred); + +out: + /* did we find some credits? */ + if (credits) + ath6kl_deposit_credit_to_ep(cred_info, ep_dist, credits); + + ep_dist->seek_cred = 0; +} + +/* redistribute credits based on activity change */ +static void ath6k_redistribute_credits(struct htc_credit_state_info *info, + struct list_head *ep_dist_list) +{ + struct htc_endpoint_credit_dist *curdist_list; + + list_for_each_entry(curdist_list, ep_dist_list, list) { + if (curdist_list->endpoint == ENDPOINT_0) + continue; + + if ((curdist_list->svc_id == WMI_DATA_BK_SVC) || + (curdist_list->svc_id == WMI_DATA_BE_SVC)) + curdist_list->dist_flags |= HTC_EP_ACTIVE; + + if ((curdist_list->svc_id != WMI_CONTROL_SVC) && + !(curdist_list->dist_flags & HTC_EP_ACTIVE)) { + if (curdist_list->txq_depth == 0) + ath6k_reduce_credits(info, + curdist_list, 0); + else + ath6k_reduce_credits(info, + curdist_list, + curdist_list->cred_min); + } + } +} + +/* + * + * This function is invoked whenever endpoints require credit + * distributions. A lock is held while this function is invoked, this + * function shall NOT block. The ep_dist_list is a list of distribution + * structures in prioritized order as defined by the call to the + * htc_set_credit_dist() api. + */ +void ath6k_credit_distribute(struct htc_credit_state_info *cred_info, + struct list_head *ep_dist_list, + enum htc_credit_dist_reason reason) +{ + switch (reason) { + case HTC_CREDIT_DIST_SEND_COMPLETE: + ath6k_credit_update(cred_info, ep_dist_list); + break; + case HTC_CREDIT_DIST_ACTIVITY_CHANGE: + ath6k_redistribute_credits(cred_info, ep_dist_list); + break; + default: + break; + } + + WARN_ON(cred_info->cur_free_credits > cred_info->total_avail_credits); + WARN_ON(cred_info->cur_free_credits < 0); +} + +void disconnect_timer_handler(unsigned long ptr) +{ + struct net_device *dev = (struct net_device *)ptr; + struct ath6kl *ar = ath6kl_priv(dev); + + ath6kl_init_profile_info(ar); + ath6kl_disconnect(ar); +} + +void ath6kl_disconnect(struct ath6kl *ar) +{ + if (test_bit(CONNECTED, &ar->flag) || + test_bit(CONNECT_PEND, &ar->flag)) { + ath6kl_wmi_disconnect_cmd(ar->wmi); + /* + * Disconnect command is issued, clear the connect pending + * flag. The connected flag will be cleared in + * disconnect event notification. + */ + clear_bit(CONNECT_PEND, &ar->flag); + } +} + +void ath6kl_deep_sleep_enable(struct ath6kl *ar) +{ + switch (ar->sme_state) { + case SME_CONNECTING: + cfg80211_connect_result(ar->net_dev, ar->bssid, NULL, 0, + NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + break; + case SME_CONNECTED: + default: + /* + * FIXME: oddly enough smeState is in DISCONNECTED during + * suspend, why? Need to send disconnected event in that + * state. + */ + cfg80211_disconnected(ar->net_dev, 0, NULL, 0, GFP_KERNEL); + break; + } + + if (test_bit(CONNECTED, &ar->flag) || + test_bit(CONNECT_PEND, &ar->flag)) + ath6kl_wmi_disconnect_cmd(ar->wmi); + + ar->sme_state = SME_DISCONNECTED; + + /* disable scanning */ + if (ath6kl_wmi_scanparams_cmd(ar->wmi, 0xFFFF, 0, 0, 0, 0, 0, 0, 0, + 0, 0) != 0) + printk(KERN_WARNING "ath6kl: failed to disable scan " + "during suspend\n"); + + ath6kl_cfg80211_scan_complete_event(ar, -ECANCELED); +} + +/* WMI Event handlers */ + +static const char *get_hw_id_string(u32 id) +{ + switch (id) { + case AR6003_REV1_VERSION: + return "1.0"; + case AR6003_REV2_VERSION: + return "2.0"; + case AR6003_REV3_VERSION: + return "2.1.1"; + default: + return "unknown"; + } +} + +void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) +{ + struct ath6kl *ar = devt; + struct net_device *dev = ar->net_dev; + + memcpy(dev->dev_addr, datap, ETH_ALEN); + ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n", + __func__, dev->dev_addr); + + ar->version.wlan_ver = sw_ver; + ar->version.abi_ver = abi_ver; + + snprintf(ar->wdev->wiphy->fw_version, + sizeof(ar->wdev->wiphy->fw_version), + "%u.%u.%u.%u", + (ar->version.wlan_ver & 0xf0000000) >> 28, + (ar->version.wlan_ver & 0x0f000000) >> 24, + (ar->version.wlan_ver & 0x00ff0000) >> 16, + (ar->version.wlan_ver & 0x0000ffff)); + + /* indicate to the waiting thread that the ready event was received */ + set_bit(WMI_READY, &ar->flag); + wake_up(&ar->event_wq); + + ath6kl_info("hw %s fw %s%s\n", + get_hw_id_string(ar->wdev->wiphy->hw_version), + ar->wdev->wiphy->fw_version, + test_bit(TESTMODE, &ar->flag) ? " testmode" : ""); +} + +void ath6kl_scan_complete_evt(struct ath6kl *ar, int status) +{ + ath6kl_cfg80211_scan_complete_event(ar, status); + + if (!ar->usr_bss_filter) { + clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); + ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); + } + + ath6kl_dbg(ATH6KL_DBG_WLAN_SCAN, "scan complete: %d\n", status); +} + +void ath6kl_connect_event(struct ath6kl *ar, u16 channel, u8 *bssid, + u16 listen_int, u16 beacon_int, + enum network_type net_type, u8 beacon_ie_len, + u8 assoc_req_len, u8 assoc_resp_len, + u8 *assoc_info) +{ + unsigned long flags; + + ath6kl_cfg80211_connect_event(ar, channel, bssid, + listen_int, beacon_int, + net_type, beacon_ie_len, + assoc_req_len, assoc_resp_len, + assoc_info); + + memcpy(ar->bssid, bssid, sizeof(ar->bssid)); + ar->bss_ch = channel; + + if ((ar->nw_type == INFRA_NETWORK)) + ath6kl_wmi_listeninterval_cmd(ar->wmi, ar->listen_intvl_t, + ar->listen_intvl_b); + + netif_wake_queue(ar->net_dev); + + /* Update connect & link status atomically */ + spin_lock_irqsave(&ar->lock, flags); + set_bit(CONNECTED, &ar->flag); + clear_bit(CONNECT_PEND, &ar->flag); + netif_carrier_on(ar->net_dev); + spin_unlock_irqrestore(&ar->lock, flags); + + aggr_reset_state(ar->aggr_cntxt); + ar->reconnect_flag = 0; + + if ((ar->nw_type == ADHOC_NETWORK) && ar->ibss_ps_enable) { + memset(ar->node_map, 0, sizeof(ar->node_map)); + ar->node_num = 0; + ar->next_ep_id = ENDPOINT_2; + } + + if (!ar->usr_bss_filter) { + set_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); + ath6kl_wmi_bssfilter_cmd(ar->wmi, CURRENT_BSS_FILTER, 0); + } +} + +void ath6kl_tkip_micerr_event(struct ath6kl *ar, u8 keyid, bool ismcast) +{ + struct ath6kl_sta *sta; + u8 tsc[6]; + /* + * For AP case, keyid will have aid of STA which sent pkt with + * MIC error. Use this aid to get MAC & send it to hostapd. + */ + if (ar->nw_type == AP_NETWORK) { + sta = ath6kl_find_sta_by_aid(ar, (keyid >> 2)); + if (!sta) + return; + + ath6kl_dbg(ATH6KL_DBG_TRC, + "ap tkip mic error received from aid=%d\n", keyid); + + memset(tsc, 0, sizeof(tsc)); /* FIX: get correct TSC */ + cfg80211_michael_mic_failure(ar->net_dev, sta->mac, + NL80211_KEYTYPE_PAIRWISE, keyid, + tsc, GFP_KERNEL); + } else + ath6kl_cfg80211_tkip_micerr_event(ar, keyid, ismcast); + +} + +static void ath6kl_update_target_stats(struct ath6kl *ar, u8 *ptr, u32 len) +{ + struct wmi_target_stats *tgt_stats = + (struct wmi_target_stats *) ptr; + struct target_stats *stats = &ar->target_stats; + struct tkip_ccmp_stats *ccmp_stats; + u8 ac; + + if (len < sizeof(*tgt_stats)) + return; + + ath6kl_dbg(ATH6KL_DBG_TRC, "updating target stats\n"); + + stats->tx_pkt += le32_to_cpu(tgt_stats->stats.tx.pkt); + stats->tx_byte += le32_to_cpu(tgt_stats->stats.tx.byte); + stats->tx_ucast_pkt += le32_to_cpu(tgt_stats->stats.tx.ucast_pkt); + stats->tx_ucast_byte += le32_to_cpu(tgt_stats->stats.tx.ucast_byte); + stats->tx_mcast_pkt += le32_to_cpu(tgt_stats->stats.tx.mcast_pkt); + stats->tx_mcast_byte += le32_to_cpu(tgt_stats->stats.tx.mcast_byte); + stats->tx_bcast_pkt += le32_to_cpu(tgt_stats->stats.tx.bcast_pkt); + stats->tx_bcast_byte += le32_to_cpu(tgt_stats->stats.tx.bcast_byte); + stats->tx_rts_success_cnt += + le32_to_cpu(tgt_stats->stats.tx.rts_success_cnt); + + for (ac = 0; ac < WMM_NUM_AC; ac++) + stats->tx_pkt_per_ac[ac] += + le32_to_cpu(tgt_stats->stats.tx.pkt_per_ac[ac]); + + stats->tx_err += le32_to_cpu(tgt_stats->stats.tx.err); + stats->tx_fail_cnt += le32_to_cpu(tgt_stats->stats.tx.fail_cnt); + stats->tx_retry_cnt += le32_to_cpu(tgt_stats->stats.tx.retry_cnt); + stats->tx_mult_retry_cnt += + le32_to_cpu(tgt_stats->stats.tx.mult_retry_cnt); + stats->tx_rts_fail_cnt += + le32_to_cpu(tgt_stats->stats.tx.rts_fail_cnt); + stats->tx_ucast_rate = + ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.tx.ucast_rate)); + + stats->rx_pkt += le32_to_cpu(tgt_stats->stats.rx.pkt); + stats->rx_byte += le32_to_cpu(tgt_stats->stats.rx.byte); + stats->rx_ucast_pkt += le32_to_cpu(tgt_stats->stats.rx.ucast_pkt); + stats->rx_ucast_byte += le32_to_cpu(tgt_stats->stats.rx.ucast_byte); + stats->rx_mcast_pkt += le32_to_cpu(tgt_stats->stats.rx.mcast_pkt); + stats->rx_mcast_byte += le32_to_cpu(tgt_stats->stats.rx.mcast_byte); + stats->rx_bcast_pkt += le32_to_cpu(tgt_stats->stats.rx.bcast_pkt); + stats->rx_bcast_byte += le32_to_cpu(tgt_stats->stats.rx.bcast_byte); + stats->rx_frgment_pkt += le32_to_cpu(tgt_stats->stats.rx.frgment_pkt); + stats->rx_err += le32_to_cpu(tgt_stats->stats.rx.err); + stats->rx_crc_err += le32_to_cpu(tgt_stats->stats.rx.crc_err); + stats->rx_key_cache_miss += + le32_to_cpu(tgt_stats->stats.rx.key_cache_miss); + stats->rx_decrypt_err += le32_to_cpu(tgt_stats->stats.rx.decrypt_err); + stats->rx_dupl_frame += le32_to_cpu(tgt_stats->stats.rx.dupl_frame); + stats->rx_ucast_rate = + ath6kl_wmi_get_rate(a_sle32_to_cpu(tgt_stats->stats.rx.ucast_rate)); + + ccmp_stats = &tgt_stats->stats.tkip_ccmp_stats; + + stats->tkip_local_mic_fail += + le32_to_cpu(ccmp_stats->tkip_local_mic_fail); + stats->tkip_cnter_measures_invoked += + le32_to_cpu(ccmp_stats->tkip_cnter_measures_invoked); + stats->tkip_fmt_err += le32_to_cpu(ccmp_stats->tkip_fmt_err); + + stats->ccmp_fmt_err += le32_to_cpu(ccmp_stats->ccmp_fmt_err); + stats->ccmp_replays += le32_to_cpu(ccmp_stats->ccmp_replays); + + stats->pwr_save_fail_cnt += + le32_to_cpu(tgt_stats->pm_stats.pwr_save_failure_cnt); + stats->noise_floor_calib = + a_sle32_to_cpu(tgt_stats->noise_floor_calib); + + stats->cs_bmiss_cnt += + le32_to_cpu(tgt_stats->cserv_stats.cs_bmiss_cnt); + stats->cs_low_rssi_cnt += + le32_to_cpu(tgt_stats->cserv_stats.cs_low_rssi_cnt); + stats->cs_connect_cnt += + le16_to_cpu(tgt_stats->cserv_stats.cs_connect_cnt); + stats->cs_discon_cnt += + le16_to_cpu(tgt_stats->cserv_stats.cs_discon_cnt); + + stats->cs_ave_beacon_rssi = + a_sle16_to_cpu(tgt_stats->cserv_stats.cs_ave_beacon_rssi); + + stats->cs_last_roam_msec = + tgt_stats->cserv_stats.cs_last_roam_msec; + stats->cs_snr = tgt_stats->cserv_stats.cs_snr; + stats->cs_rssi = a_sle16_to_cpu(tgt_stats->cserv_stats.cs_rssi); + + stats->lq_val = le32_to_cpu(tgt_stats->lq_val); + + stats->wow_pkt_dropped += + le32_to_cpu(tgt_stats->wow_stats.wow_pkt_dropped); + stats->wow_host_pkt_wakeups += + tgt_stats->wow_stats.wow_host_pkt_wakeups; + stats->wow_host_evt_wakeups += + tgt_stats->wow_stats.wow_host_evt_wakeups; + stats->wow_evt_discarded += + le16_to_cpu(tgt_stats->wow_stats.wow_evt_discarded); + + if (test_bit(STATS_UPDATE_PEND, &ar->flag)) { + clear_bit(STATS_UPDATE_PEND, &ar->flag); + wake_up(&ar->event_wq); + } +} + +static void ath6kl_add_le32(__le32 *var, __le32 val) +{ + *var = cpu_to_le32(le32_to_cpu(*var) + le32_to_cpu(val)); +} + +void ath6kl_tgt_stats_event(struct ath6kl *ar, u8 *ptr, u32 len) +{ + struct wmi_ap_mode_stat *p = (struct wmi_ap_mode_stat *) ptr; + struct wmi_ap_mode_stat *ap = &ar->ap_stats; + struct wmi_per_sta_stat *st_ap, *st_p; + u8 ac; + + if (ar->nw_type == AP_NETWORK) { + if (len < sizeof(*p)) + return; + + for (ac = 0; ac < AP_MAX_NUM_STA; ac++) { + st_ap = &ap->sta[ac]; + st_p = &p->sta[ac]; + + ath6kl_add_le32(&st_ap->tx_bytes, st_p->tx_bytes); + ath6kl_add_le32(&st_ap->tx_pkts, st_p->tx_pkts); + ath6kl_add_le32(&st_ap->tx_error, st_p->tx_error); + ath6kl_add_le32(&st_ap->tx_discard, st_p->tx_discard); + ath6kl_add_le32(&st_ap->rx_bytes, st_p->rx_bytes); + ath6kl_add_le32(&st_ap->rx_pkts, st_p->rx_pkts); + ath6kl_add_le32(&st_ap->rx_error, st_p->rx_error); + ath6kl_add_le32(&st_ap->rx_discard, st_p->rx_discard); + } + + } else { + ath6kl_update_target_stats(ar, ptr, len); + } +} + +void ath6kl_wakeup_event(void *dev) +{ + struct ath6kl *ar = (struct ath6kl *) dev; + + wake_up(&ar->event_wq); +} + +void ath6kl_txpwr_rx_evt(void *devt, u8 tx_pwr) +{ + struct ath6kl *ar = (struct ath6kl *) devt; + + ar->tx_pwr = tx_pwr; + wake_up(&ar->event_wq); +} + +void ath6kl_pspoll_event(struct ath6kl *ar, u8 aid) +{ + struct ath6kl_sta *conn; + struct sk_buff *skb; + bool psq_empty = false; + + conn = ath6kl_find_sta_by_aid(ar, aid); + + if (!conn) + return; + /* + * Send out a packet queued on ps queue. When the ps queue + * becomes empty update the PVB for this station. + */ + spin_lock_bh(&conn->psq_lock); + psq_empty = skb_queue_empty(&conn->psq); + spin_unlock_bh(&conn->psq_lock); + + if (psq_empty) + /* TODO: Send out a NULL data frame */ + return; + + spin_lock_bh(&conn->psq_lock); + skb = skb_dequeue(&conn->psq); + spin_unlock_bh(&conn->psq_lock); + + conn->sta_flags |= STA_PS_POLLED; + ath6kl_data_tx(skb, ar->net_dev); + conn->sta_flags &= ~STA_PS_POLLED; + + spin_lock_bh(&conn->psq_lock); + psq_empty = skb_queue_empty(&conn->psq); + spin_unlock_bh(&conn->psq_lock); + + if (psq_empty) + ath6kl_wmi_set_pvb_cmd(ar->wmi, conn->aid, 0); +} + +void ath6kl_dtimexpiry_event(struct ath6kl *ar) +{ + bool mcastq_empty = false; + struct sk_buff *skb; + + /* + * If there are no associated STAs, ignore the DTIM expiry event. + * There can be potential race conditions where the last associated + * STA may disconnect & before the host could clear the 'Indicate + * DTIM' request to the firmware, the firmware would have just + * indicated a DTIM expiry event. The race is between 'clear DTIM + * expiry cmd' going from the host to the firmware & the DTIM + * expiry event happening from the firmware to the host. + */ + if (!ar->sta_list_index) + return; + + spin_lock_bh(&ar->mcastpsq_lock); + mcastq_empty = skb_queue_empty(&ar->mcastpsq); + spin_unlock_bh(&ar->mcastpsq_lock); + + if (mcastq_empty) + return; + + /* set the STA flag to dtim_expired for the frame to go out */ + set_bit(DTIM_EXPIRED, &ar->flag); + + spin_lock_bh(&ar->mcastpsq_lock); + while ((skb = skb_dequeue(&ar->mcastpsq)) != NULL) { + spin_unlock_bh(&ar->mcastpsq_lock); + + ath6kl_data_tx(skb, ar->net_dev); + + spin_lock_bh(&ar->mcastpsq_lock); + } + spin_unlock_bh(&ar->mcastpsq_lock); + + clear_bit(DTIM_EXPIRED, &ar->flag); + + /* clear the LSB of the BitMapCtl field of the TIM IE */ + ath6kl_wmi_set_pvb_cmd(ar->wmi, MCAST_AID, 0); +} + +void ath6kl_disconnect_event(struct ath6kl *ar, u8 reason, u8 *bssid, + u8 assoc_resp_len, u8 *assoc_info, + u16 prot_reason_status) +{ + unsigned long flags; + + if (ar->nw_type == AP_NETWORK) { + if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) + return; + + /* if no more associated STAs, empty the mcast PS q */ + if (ar->sta_list_index == 0) { + spin_lock_bh(&ar->mcastpsq_lock); + skb_queue_purge(&ar->mcastpsq); + spin_unlock_bh(&ar->mcastpsq_lock); + + /* clear the LSB of the TIM IE's BitMapCtl field */ + if (test_bit(WMI_READY, &ar->flag)) + ath6kl_wmi_set_pvb_cmd(ar->wmi, MCAST_AID, 0); + } + + if (!is_broadcast_ether_addr(bssid)) { + /* send event to application */ + cfg80211_del_sta(ar->net_dev, bssid, GFP_KERNEL); + } + + if (memcmp(ar->net_dev->dev_addr, bssid, ETH_ALEN) == 0) { + memset(ar->wep_key_list, 0, sizeof(ar->wep_key_list)); + clear_bit(CONNECTED, &ar->flag); + } + return; + } + + ath6kl_cfg80211_disconnect_event(ar, reason, bssid, + assoc_resp_len, assoc_info, + prot_reason_status); + + aggr_reset_state(ar->aggr_cntxt); + + del_timer(&ar->disconnect_timer); + + ath6kl_dbg(ATH6KL_DBG_WLAN_CONNECT, + "disconnect reason is %d\n", reason); + + /* + * If the event is due to disconnect cmd from the host, only they + * the target would stop trying to connect. Under any other + * condition, target would keep trying to connect. + */ + if (reason == DISCONNECT_CMD) { + if (!ar->usr_bss_filter && test_bit(WMI_READY, &ar->flag)) + ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); + } else { + set_bit(CONNECT_PEND, &ar->flag); + if (((reason == ASSOC_FAILED) && + (prot_reason_status == 0x11)) || + ((reason == ASSOC_FAILED) && (prot_reason_status == 0x0) + && (ar->reconnect_flag == 1))) { + set_bit(CONNECTED, &ar->flag); + return; + } + } + + /* update connect & link status atomically */ + spin_lock_irqsave(&ar->lock, flags); + clear_bit(CONNECTED, &ar->flag); + netif_carrier_off(ar->net_dev); + spin_unlock_irqrestore(&ar->lock, flags); + + if ((reason != CSERV_DISCONNECT) || (ar->reconnect_flag != 1)) + ar->reconnect_flag = 0; + + if (reason != CSERV_DISCONNECT) + ar->user_key_ctrl = 0; + + netif_stop_queue(ar->net_dev); + memset(ar->bssid, 0, sizeof(ar->bssid)); + ar->bss_ch = 0; + + ath6kl_tx_data_cleanup(ar); +} + +static int ath6kl_open(struct net_device *dev) +{ + struct ath6kl *ar = ath6kl_priv(dev); + unsigned long flags; + + spin_lock_irqsave(&ar->lock, flags); + + set_bit(WLAN_ENABLED, &ar->flag); + + if (test_bit(CONNECTED, &ar->flag)) { + netif_carrier_on(dev); + netif_wake_queue(dev); + } else + netif_carrier_off(dev); + + spin_unlock_irqrestore(&ar->lock, flags); + + return 0; +} + +static int ath6kl_close(struct net_device *dev) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + netif_stop_queue(dev); + + ath6kl_disconnect(ar); + + if (test_bit(WMI_READY, &ar->flag)) { + if (ath6kl_wmi_scanparams_cmd(ar->wmi, 0xFFFF, 0, 0, 0, 0, 0, 0, + 0, 0, 0)) + return -EIO; + + clear_bit(WLAN_ENABLED, &ar->flag); + } + + ath6kl_cfg80211_scan_complete_event(ar, -ECANCELED); + + return 0; +} + +static struct net_device_stats *ath6kl_get_stats(struct net_device *dev) +{ + struct ath6kl *ar = ath6kl_priv(dev); + + return &ar->net_stats; +} + +static struct net_device_ops ath6kl_netdev_ops = { + .ndo_open = ath6kl_open, + .ndo_stop = ath6kl_close, + .ndo_start_xmit = ath6kl_data_tx, + .ndo_get_stats = ath6kl_get_stats, +}; + +void init_netdev(struct net_device *dev) +{ + dev->netdev_ops = &ath6kl_netdev_ops; + dev->watchdog_timeo = ATH6KL_TX_TIMEOUT; + + dev->needed_headroom = ETH_HLEN; + dev->needed_headroom += sizeof(struct ath6kl_llc_snap_hdr) + + sizeof(struct wmi_data_hdr) + HTC_HDR_LENGTH + + WMI_MAX_TX_META_SZ + ATH6KL_HTC_ALIGN_BYTES; + + return; +} diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c new file mode 100644 index 000000000000..f1dc311ee0c7 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -0,0 +1,949 @@ +/* + * 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/mmc/card.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/sd.h> +#include "htc_hif.h" +#include "hif-ops.h" +#include "target.h" +#include "debug.h" +#include "cfg80211.h" + +struct ath6kl_sdio { + struct sdio_func *func; + + spinlock_t lock; + + /* free list */ + struct list_head bus_req_freeq; + + /* available bus requests */ + struct bus_request bus_req[BUS_REQUEST_MAX_NUM]; + + struct ath6kl *ar; + u8 *dma_buffer; + + /* scatter request list head */ + struct list_head scat_req; + + spinlock_t scat_lock; + bool is_disabled; + atomic_t irq_handling; + const struct sdio_device_id *id; + struct work_struct wr_async_work; + struct list_head wr_asyncq; + spinlock_t wr_async_lock; +}; + +#define CMD53_ARG_READ 0 +#define CMD53_ARG_WRITE 1 +#define CMD53_ARG_BLOCK_BASIS 1 +#define CMD53_ARG_FIXED_ADDRESS 0 +#define CMD53_ARG_INCR_ADDRESS 1 + +static inline struct ath6kl_sdio *ath6kl_sdio_priv(struct ath6kl *ar) +{ + return ar->hif_priv; +} + +/* + * Macro to check if DMA buffer is WORD-aligned and DMA-able. + * Most host controllers assume the buffer is DMA'able and will + * bug-check otherwise (i.e. buffers on the stack). virt_addr_valid + * check fails on stack memory. + */ +static inline bool buf_needs_bounce(u8 *buf) +{ + return ((unsigned long) buf & 0x3) || !virt_addr_valid(buf); +} + +static void ath6kl_sdio_set_mbox_info(struct ath6kl *ar) +{ + struct ath6kl_mbox_info *mbox_info = &ar->mbox_info; + + /* EP1 has an extended range */ + mbox_info->htc_addr = HIF_MBOX_BASE_ADDR; + mbox_info->htc_ext_addr = HIF_MBOX0_EXT_BASE_ADDR; + mbox_info->htc_ext_sz = HIF_MBOX0_EXT_WIDTH; + mbox_info->block_size = HIF_MBOX_BLOCK_SIZE; + mbox_info->gmbox_addr = HIF_GMBOX_BASE_ADDR; + mbox_info->gmbox_sz = HIF_GMBOX_WIDTH; +} + +static inline void ath6kl_sdio_set_cmd53_arg(u32 *arg, u8 rw, u8 func, + u8 mode, u8 opcode, u32 addr, + u16 blksz) +{ + *arg = (((rw & 1) << 31) | + ((func & 0x7) << 28) | + ((mode & 1) << 27) | + ((opcode & 1) << 26) | + ((addr & 0x1FFFF) << 9) | + (blksz & 0x1FF)); +} + +static inline void ath6kl_sdio_set_cmd52_arg(u32 *arg, u8 write, u8 raw, + unsigned int address, + unsigned char val) +{ + const u8 func = 0; + + *arg = ((write & 1) << 31) | + ((func & 0x7) << 28) | + ((raw & 1) << 27) | + (1 << 26) | + ((address & 0x1FFFF) << 9) | + (1 << 8) | + (val & 0xFF); +} + +static int ath6kl_sdio_func0_cmd52_wr_byte(struct mmc_card *card, + unsigned int address, + unsigned char byte) +{ + struct mmc_command io_cmd; + + memset(&io_cmd, 0, sizeof(io_cmd)); + ath6kl_sdio_set_cmd52_arg(&io_cmd.arg, 1, 0, address, byte); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + return mmc_wait_for_cmd(card->host, &io_cmd, 0); +} + +static int ath6kl_sdio_io(struct sdio_func *func, u32 request, u32 addr, + u8 *buf, u32 len) +{ + int ret = 0; + + if (request & HIF_WRITE) { + /* FIXME: looks like ugly workaround for something */ + if (addr >= HIF_MBOX_BASE_ADDR && + addr <= HIF_MBOX_END_ADDR) + addr += (HIF_MBOX_WIDTH - len); + + /* FIXME: this also looks like ugly workaround */ + if (addr == HIF_MBOX0_EXT_BASE_ADDR) + addr += HIF_MBOX0_EXT_WIDTH - len; + + if (request & HIF_FIXED_ADDRESS) + ret = sdio_writesb(func, addr, buf, len); + else + ret = sdio_memcpy_toio(func, addr, buf, len); + } else { + if (request & HIF_FIXED_ADDRESS) + ret = sdio_readsb(func, buf, addr, len); + else + ret = sdio_memcpy_fromio(func, buf, addr, len); + } + + ath6kl_dbg(ATH6KL_DBG_SDIO, "%s addr 0x%x%s buf 0x%p len %d\n", + request & HIF_WRITE ? "wr" : "rd", addr, + request & HIF_FIXED_ADDRESS ? " (fixed)" : "", buf, len); + ath6kl_dbg_dump(ATH6KL_DBG_SDIO_DUMP, NULL, "sdio ", buf, len); + + return ret; +} + +static struct bus_request *ath6kl_sdio_alloc_busreq(struct ath6kl_sdio *ar_sdio) +{ + struct bus_request *bus_req; + unsigned long flag; + + spin_lock_irqsave(&ar_sdio->lock, flag); + + if (list_empty(&ar_sdio->bus_req_freeq)) { + spin_unlock_irqrestore(&ar_sdio->lock, flag); + return NULL; + } + + bus_req = list_first_entry(&ar_sdio->bus_req_freeq, + struct bus_request, list); + list_del(&bus_req->list); + + spin_unlock_irqrestore(&ar_sdio->lock, flag); + ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n", + __func__, bus_req); + + return bus_req; +} + +static void ath6kl_sdio_free_bus_req(struct ath6kl_sdio *ar_sdio, + struct bus_request *bus_req) +{ + unsigned long flag; + + ath6kl_dbg(ATH6KL_DBG_SCATTER, "%s: bus request 0x%p\n", + __func__, bus_req); + + spin_lock_irqsave(&ar_sdio->lock, flag); + list_add_tail(&bus_req->list, &ar_sdio->bus_req_freeq); + spin_unlock_irqrestore(&ar_sdio->lock, flag); +} + +static void ath6kl_sdio_setup_scat_data(struct hif_scatter_req *scat_req, + struct mmc_data *data) +{ + struct scatterlist *sg; + int i; + + data->blksz = HIF_MBOX_BLOCK_SIZE; + data->blocks = scat_req->len / HIF_MBOX_BLOCK_SIZE; + + ath6kl_dbg(ATH6KL_DBG_SCATTER, + "hif-scatter: (%s) addr: 0x%X, (block len: %d, block count: %d) , (tot:%d,sg:%d)\n", + (scat_req->req & HIF_WRITE) ? "WR" : "RD", scat_req->addr, + data->blksz, data->blocks, scat_req->len, + scat_req->scat_entries); + + data->flags = (scat_req->req & HIF_WRITE) ? MMC_DATA_WRITE : + MMC_DATA_READ; + + /* fill SG entries */ + sg = scat_req->sgentries; + sg_init_table(sg, scat_req->scat_entries); + + /* assemble SG list */ + for (i = 0; i < scat_req->scat_entries; i++, sg++) { + ath6kl_dbg(ATH6KL_DBG_SCATTER, "%d: addr:0x%p, len:%d\n", + i, scat_req->scat_list[i].buf, + scat_req->scat_list[i].len); + + sg_set_buf(sg, scat_req->scat_list[i].buf, + scat_req->scat_list[i].len); + } + + /* set scatter-gather table for request */ + data->sg = scat_req->sgentries; + data->sg_len = scat_req->scat_entries; +} + +static int ath6kl_sdio_scat_rw(struct ath6kl_sdio *ar_sdio, + struct bus_request *req) +{ + struct mmc_request mmc_req; + struct mmc_command cmd; + struct mmc_data data; + struct hif_scatter_req *scat_req; + u8 opcode, rw; + int status, len; + + scat_req = req->scat_req; + + if (scat_req->virt_scat) { + len = scat_req->len; + if (scat_req->req & HIF_BLOCK_BASIS) + len = round_down(len, HIF_MBOX_BLOCK_SIZE); + + status = ath6kl_sdio_io(ar_sdio->func, scat_req->req, + scat_req->addr, scat_req->virt_dma_buf, + len); + goto scat_complete; + } + + memset(&mmc_req, 0, sizeof(struct mmc_request)); + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + ath6kl_sdio_setup_scat_data(scat_req, &data); + + opcode = (scat_req->req & HIF_FIXED_ADDRESS) ? + CMD53_ARG_FIXED_ADDRESS : CMD53_ARG_INCR_ADDRESS; + + rw = (scat_req->req & HIF_WRITE) ? CMD53_ARG_WRITE : CMD53_ARG_READ; + + /* Fixup the address so that the last byte will fall on MBOX EOM */ + if (scat_req->req & HIF_WRITE) { + if (scat_req->addr == HIF_MBOX_BASE_ADDR) + scat_req->addr += HIF_MBOX_WIDTH - scat_req->len; + else + /* Uses extended address range */ + scat_req->addr += HIF_MBOX0_EXT_WIDTH - scat_req->len; + } + + /* set command argument */ + ath6kl_sdio_set_cmd53_arg(&cmd.arg, rw, ar_sdio->func->num, + CMD53_ARG_BLOCK_BASIS, opcode, scat_req->addr, + data.blocks); + + cmd.opcode = SD_IO_RW_EXTENDED; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; + + mmc_req.cmd = &cmd; + mmc_req.data = &data; + + mmc_set_data_timeout(&data, ar_sdio->func->card); + /* synchronous call to process request */ + mmc_wait_for_req(ar_sdio->func->card->host, &mmc_req); + + status = cmd.error ? cmd.error : data.error; + +scat_complete: + scat_req->status = status; + + if (scat_req->status) + ath6kl_err("Scatter write request failed:%d\n", + scat_req->status); + + if (scat_req->req & HIF_ASYNCHRONOUS) + scat_req->complete(ar_sdio->ar->htc_target, scat_req); + + return status; +} + +static int ath6kl_sdio_alloc_prep_scat_req(struct ath6kl_sdio *ar_sdio, + int n_scat_entry, int n_scat_req, + bool virt_scat) +{ + struct hif_scatter_req *s_req; + struct bus_request *bus_req; + int i, scat_req_sz, scat_list_sz, sg_sz, buf_sz; + u8 *virt_buf; + + scat_list_sz = (n_scat_entry - 1) * sizeof(struct hif_scatter_item); + scat_req_sz = sizeof(*s_req) + scat_list_sz; + + if (!virt_scat) + sg_sz = sizeof(struct scatterlist) * n_scat_entry; + else + buf_sz = 2 * L1_CACHE_BYTES + + ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER; + + for (i = 0; i < n_scat_req; i++) { + /* allocate the scatter request */ + s_req = kzalloc(scat_req_sz, GFP_KERNEL); + if (!s_req) + return -ENOMEM; + + if (virt_scat) { + virt_buf = kzalloc(buf_sz, GFP_KERNEL); + if (!virt_buf) { + kfree(s_req); + return -ENOMEM; + } + + s_req->virt_dma_buf = + (u8 *)L1_CACHE_ALIGN((unsigned long)virt_buf); + } else { + /* allocate sglist */ + s_req->sgentries = kzalloc(sg_sz, GFP_KERNEL); + + if (!s_req->sgentries) { + kfree(s_req); + return -ENOMEM; + } + } + + /* allocate a bus request for this scatter request */ + bus_req = ath6kl_sdio_alloc_busreq(ar_sdio); + if (!bus_req) { + kfree(s_req->sgentries); + kfree(s_req->virt_dma_buf); + kfree(s_req); + return -ENOMEM; + } + + /* assign the scatter request to this bus request */ + bus_req->scat_req = s_req; + s_req->busrequest = bus_req; + + s_req->virt_scat = virt_scat; + + /* add it to the scatter pool */ + hif_scatter_req_add(ar_sdio->ar, s_req); + } + + return 0; +} + +static int ath6kl_sdio_read_write_sync(struct ath6kl *ar, u32 addr, u8 *buf, + u32 len, u32 request) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + u8 *tbuf = NULL; + int ret; + bool bounced = false; + + if (request & HIF_BLOCK_BASIS) + len = round_down(len, HIF_MBOX_BLOCK_SIZE); + + if (buf_needs_bounce(buf)) { + if (!ar_sdio->dma_buffer) + return -ENOMEM; + tbuf = ar_sdio->dma_buffer; + memcpy(tbuf, buf, len); + bounced = true; + } else + tbuf = buf; + + sdio_claim_host(ar_sdio->func); + ret = ath6kl_sdio_io(ar_sdio->func, request, addr, tbuf, len); + if ((request & HIF_READ) && bounced) + memcpy(buf, tbuf, len); + sdio_release_host(ar_sdio->func); + + return ret; +} + +static void __ath6kl_sdio_write_async(struct ath6kl_sdio *ar_sdio, + struct bus_request *req) +{ + if (req->scat_req) + ath6kl_sdio_scat_rw(ar_sdio, req); + else { + void *context; + int status; + + status = ath6kl_sdio_read_write_sync(ar_sdio->ar, req->address, + req->buffer, req->length, + req->request); + context = req->packet; + ath6kl_sdio_free_bus_req(ar_sdio, req); + ath6kldev_rw_comp_handler(context, status); + } +} + +static void ath6kl_sdio_write_async_work(struct work_struct *work) +{ + struct ath6kl_sdio *ar_sdio; + unsigned long flags; + struct bus_request *req, *tmp_req; + + ar_sdio = container_of(work, struct ath6kl_sdio, wr_async_work); + sdio_claim_host(ar_sdio->func); + + spin_lock_irqsave(&ar_sdio->wr_async_lock, flags); + list_for_each_entry_safe(req, tmp_req, &ar_sdio->wr_asyncq, list) { + list_del(&req->list); + spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags); + __ath6kl_sdio_write_async(ar_sdio, req); + spin_lock_irqsave(&ar_sdio->wr_async_lock, flags); + } + spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags); + + sdio_release_host(ar_sdio->func); +} + +static void ath6kl_sdio_irq_handler(struct sdio_func *func) +{ + int status; + struct ath6kl_sdio *ar_sdio; + + ath6kl_dbg(ATH6KL_DBG_SDIO, "irq\n"); + + ar_sdio = sdio_get_drvdata(func); + atomic_set(&ar_sdio->irq_handling, 1); + + /* + * Release the host during interrups so we can pick it back up when + * we process commands. + */ + sdio_release_host(ar_sdio->func); + + status = ath6kldev_intr_bh_handler(ar_sdio->ar); + sdio_claim_host(ar_sdio->func); + atomic_set(&ar_sdio->irq_handling, 0); + WARN_ON(status && status != -ECANCELED); +} + +static int ath6kl_sdio_power_on(struct ath6kl_sdio *ar_sdio) +{ + struct sdio_func *func = ar_sdio->func; + int ret = 0; + + if (!ar_sdio->is_disabled) + return 0; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) { + ath6kl_err("Unable to enable sdio func: %d)\n", ret); + sdio_release_host(func); + return ret; + } + + sdio_release_host(func); + + /* + * Wait for hardware to initialise. It should take a lot less than + * 10 ms but let's be conservative here. + */ + msleep(10); + + ar_sdio->is_disabled = false; + + return ret; +} + +static int ath6kl_sdio_power_off(struct ath6kl_sdio *ar_sdio) +{ + int ret; + + if (ar_sdio->is_disabled) + return 0; + + /* Disable the card */ + sdio_claim_host(ar_sdio->func); + ret = sdio_disable_func(ar_sdio->func); + sdio_release_host(ar_sdio->func); + + if (ret) + return ret; + + ar_sdio->is_disabled = true; + + return ret; +} + +static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer, + u32 length, u32 request, + struct htc_packet *packet) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + struct bus_request *bus_req; + unsigned long flags; + + bus_req = ath6kl_sdio_alloc_busreq(ar_sdio); + + if (!bus_req) + return -ENOMEM; + + bus_req->address = address; + bus_req->buffer = buffer; + bus_req->length = length; + bus_req->request = request; + bus_req->packet = packet; + + spin_lock_irqsave(&ar_sdio->wr_async_lock, flags); + list_add_tail(&bus_req->list, &ar_sdio->wr_asyncq); + spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags); + queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work); + + return 0; +} + +static void ath6kl_sdio_irq_enable(struct ath6kl *ar) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + int ret; + + sdio_claim_host(ar_sdio->func); + + /* Register the isr */ + ret = sdio_claim_irq(ar_sdio->func, ath6kl_sdio_irq_handler); + if (ret) + ath6kl_err("Failed to claim sdio irq: %d\n", ret); + + sdio_release_host(ar_sdio->func); +} + +static void ath6kl_sdio_irq_disable(struct ath6kl *ar) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + int ret; + + sdio_claim_host(ar_sdio->func); + + /* Mask our function IRQ */ + while (atomic_read(&ar_sdio->irq_handling)) { + sdio_release_host(ar_sdio->func); + schedule_timeout(HZ / 10); + sdio_claim_host(ar_sdio->func); + } + + ret = sdio_release_irq(ar_sdio->func); + if (ret) + ath6kl_err("Failed to release sdio irq: %d\n", ret); + + sdio_release_host(ar_sdio->func); +} + +static struct hif_scatter_req *ath6kl_sdio_scatter_req_get(struct ath6kl *ar) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + struct hif_scatter_req *node = NULL; + unsigned long flag; + + spin_lock_irqsave(&ar_sdio->scat_lock, flag); + + if (!list_empty(&ar_sdio->scat_req)) { + node = list_first_entry(&ar_sdio->scat_req, + struct hif_scatter_req, list); + list_del(&node->list); + } + + spin_unlock_irqrestore(&ar_sdio->scat_lock, flag); + + return node; +} + +static void ath6kl_sdio_scatter_req_add(struct ath6kl *ar, + struct hif_scatter_req *s_req) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + unsigned long flag; + + spin_lock_irqsave(&ar_sdio->scat_lock, flag); + + list_add_tail(&s_req->list, &ar_sdio->scat_req); + + spin_unlock_irqrestore(&ar_sdio->scat_lock, flag); + +} + +/* scatter gather read write request */ +static int ath6kl_sdio_async_rw_scatter(struct ath6kl *ar, + struct hif_scatter_req *scat_req) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + u32 request = scat_req->req; + int status = 0; + unsigned long flags; + + if (!scat_req->len) + return -EINVAL; + + ath6kl_dbg(ATH6KL_DBG_SCATTER, + "hif-scatter: total len: %d scatter entries: %d\n", + scat_req->len, scat_req->scat_entries); + + if (request & HIF_SYNCHRONOUS) { + sdio_claim_host(ar_sdio->func); + status = ath6kl_sdio_scat_rw(ar_sdio, scat_req->busrequest); + sdio_release_host(ar_sdio->func); + } else { + spin_lock_irqsave(&ar_sdio->wr_async_lock, flags); + list_add_tail(&scat_req->busrequest->list, &ar_sdio->wr_asyncq); + spin_unlock_irqrestore(&ar_sdio->wr_async_lock, flags); + queue_work(ar->ath6kl_wq, &ar_sdio->wr_async_work); + } + + return status; +} + +/* clean up scatter support */ +static void ath6kl_sdio_cleanup_scatter(struct ath6kl *ar) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + struct hif_scatter_req *s_req, *tmp_req; + unsigned long flag; + + /* empty the free list */ + spin_lock_irqsave(&ar_sdio->scat_lock, flag); + list_for_each_entry_safe(s_req, tmp_req, &ar_sdio->scat_req, list) { + list_del(&s_req->list); + spin_unlock_irqrestore(&ar_sdio->scat_lock, flag); + + if (s_req->busrequest) + ath6kl_sdio_free_bus_req(ar_sdio, s_req->busrequest); + kfree(s_req->virt_dma_buf); + kfree(s_req->sgentries); + kfree(s_req); + + spin_lock_irqsave(&ar_sdio->scat_lock, flag); + } + spin_unlock_irqrestore(&ar_sdio->scat_lock, flag); +} + +/* setup of HIF scatter resources */ +static int ath6kl_sdio_enable_scatter(struct ath6kl *ar) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + struct htc_target *target = ar->htc_target; + int ret; + bool virt_scat = false; + + /* check if host supports scatter and it meets our requirements */ + if (ar_sdio->func->card->host->max_segs < MAX_SCATTER_ENTRIES_PER_REQ) { + ath6kl_err("host only supports scatter of :%d entries, need: %d\n", + ar_sdio->func->card->host->max_segs, + MAX_SCATTER_ENTRIES_PER_REQ); + virt_scat = true; + } + + if (!virt_scat) { + ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio, + MAX_SCATTER_ENTRIES_PER_REQ, + MAX_SCATTER_REQUESTS, virt_scat); + + if (!ret) { + ath6kl_dbg(ATH6KL_DBG_SCATTER, + "hif-scatter enabled: max scatter req : %d entries: %d\n", + MAX_SCATTER_REQUESTS, + MAX_SCATTER_ENTRIES_PER_REQ); + + target->max_scat_entries = MAX_SCATTER_ENTRIES_PER_REQ; + target->max_xfer_szper_scatreq = + MAX_SCATTER_REQ_TRANSFER_SIZE; + } else { + ath6kl_sdio_cleanup_scatter(ar); + ath6kl_warn("hif scatter resource setup failed, trying virtual scatter method\n"); + } + } + + if (virt_scat || ret) { + ret = ath6kl_sdio_alloc_prep_scat_req(ar_sdio, + ATH6KL_SCATTER_ENTRIES_PER_REQ, + ATH6KL_SCATTER_REQS, virt_scat); + + if (ret) { + ath6kl_err("failed to alloc virtual scatter resources !\n"); + ath6kl_sdio_cleanup_scatter(ar); + return ret; + } + + ath6kl_dbg(ATH6KL_DBG_SCATTER, + "Vitual scatter enabled, max_scat_req:%d, entries:%d\n", + ATH6KL_SCATTER_REQS, ATH6KL_SCATTER_ENTRIES_PER_REQ); + + target->max_scat_entries = ATH6KL_SCATTER_ENTRIES_PER_REQ; + target->max_xfer_szper_scatreq = + ATH6KL_MAX_TRANSFER_SIZE_PER_SCATTER; + } + + return 0; +} + +static int ath6kl_sdio_suspend(struct ath6kl *ar) +{ + struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar); + struct sdio_func *func = ar_sdio->func; + mmc_pm_flag_t flags; + int ret; + + flags = sdio_get_host_pm_caps(func); + + if (!(flags & MMC_PM_KEEP_POWER)) + /* as host doesn't support keep power we need to bail out */ + ath6kl_dbg(ATH6KL_DBG_SDIO, + "func %d doesn't support MMC_PM_KEEP_POWER\n", + func->num); + return -EINVAL; + + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) { + printk(KERN_ERR "ath6kl: set sdio pm flags failed: %d\n", + ret); + return ret; + } + + ath6kl_deep_sleep_enable(ar); + + return 0; +} + +static const struct ath6kl_hif_ops ath6kl_sdio_ops = { + .read_write_sync = ath6kl_sdio_read_write_sync, + .write_async = ath6kl_sdio_write_async, + .irq_enable = ath6kl_sdio_irq_enable, + .irq_disable = ath6kl_sdio_irq_disable, + .scatter_req_get = ath6kl_sdio_scatter_req_get, + .scatter_req_add = ath6kl_sdio_scatter_req_add, + .enable_scatter = ath6kl_sdio_enable_scatter, + .scat_req_rw = ath6kl_sdio_async_rw_scatter, + .cleanup_scatter = ath6kl_sdio_cleanup_scatter, + .suspend = ath6kl_sdio_suspend, +}; + +static int ath6kl_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret; + struct ath6kl_sdio *ar_sdio; + struct ath6kl *ar; + int count; + + ath6kl_dbg(ATH6KL_DBG_SDIO, + "new func %d vendor 0x%x device 0x%x block 0x%x/0x%x\n", + func->num, func->vendor, func->device, + func->max_blksize, func->cur_blksize); + + ar_sdio = kzalloc(sizeof(struct ath6kl_sdio), GFP_KERNEL); + if (!ar_sdio) + return -ENOMEM; + + ar_sdio->dma_buffer = kzalloc(HIF_DMA_BUFFER_SIZE, GFP_KERNEL); + if (!ar_sdio->dma_buffer) { + ret = -ENOMEM; + goto err_hif; + } + + ar_sdio->func = func; + sdio_set_drvdata(func, ar_sdio); + + ar_sdio->id = id; + ar_sdio->is_disabled = true; + + spin_lock_init(&ar_sdio->lock); + spin_lock_init(&ar_sdio->scat_lock); + spin_lock_init(&ar_sdio->wr_async_lock); + + INIT_LIST_HEAD(&ar_sdio->scat_req); + INIT_LIST_HEAD(&ar_sdio->bus_req_freeq); + INIT_LIST_HEAD(&ar_sdio->wr_asyncq); + + INIT_WORK(&ar_sdio->wr_async_work, ath6kl_sdio_write_async_work); + + for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) + ath6kl_sdio_free_bus_req(ar_sdio, &ar_sdio->bus_req[count]); + + ar = ath6kl_core_alloc(&ar_sdio->func->dev); + if (!ar) { + ath6kl_err("Failed to alloc ath6kl core\n"); + ret = -ENOMEM; + goto err_dma; + } + + ar_sdio->ar = ar; + ar->hif_priv = ar_sdio; + ar->hif_ops = &ath6kl_sdio_ops; + + ath6kl_sdio_set_mbox_info(ar); + + sdio_claim_host(func); + + if ((ar_sdio->id->device & MANUFACTURER_ID_ATH6KL_BASE_MASK) >= + MANUFACTURER_ID_AR6003_BASE) { + /* enable 4-bit ASYNC interrupt on AR6003 or later */ + ret = ath6kl_sdio_func0_cmd52_wr_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG, + SDIO_IRQ_MODE_ASYNC_4BIT_IRQ); + if (ret) { + ath6kl_err("Failed to enable 4-bit async irq mode %d\n", + ret); + sdio_release_host(func); + goto err_cfg80211; + } + + ath6kl_dbg(ATH6KL_DBG_SDIO, "4-bit async irq mode enabled\n"); + } + + /* give us some time to enable, in ms */ + func->enable_timeout = 100; + + sdio_release_host(func); + + ret = ath6kl_sdio_power_on(ar_sdio); + if (ret) + goto err_cfg80211; + + sdio_claim_host(func); + + ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); + if (ret) { + ath6kl_err("Set sdio block size %d failed: %d)\n", + HIF_MBOX_BLOCK_SIZE, ret); + sdio_release_host(func); + goto err_off; + } + + sdio_release_host(func); + + ret = ath6kl_core_init(ar); + if (ret) { + ath6kl_err("Failed to init ath6kl core\n"); + goto err_off; + } + + return ret; + +err_off: + ath6kl_sdio_power_off(ar_sdio); +err_cfg80211: + ath6kl_cfg80211_deinit(ar_sdio->ar); +err_dma: + kfree(ar_sdio->dma_buffer); +err_hif: + kfree(ar_sdio); + + return ret; +} + +static void ath6kl_sdio_remove(struct sdio_func *func) +{ + struct ath6kl_sdio *ar_sdio; + + ath6kl_dbg(ATH6KL_DBG_SDIO, + "removed func %d vendor 0x%x device 0x%x\n", + func->num, func->vendor, func->device); + + ar_sdio = sdio_get_drvdata(func); + + ath6kl_stop_txrx(ar_sdio->ar); + cancel_work_sync(&ar_sdio->wr_async_work); + + ath6kl_unavail_ev(ar_sdio->ar); + + ath6kl_sdio_power_off(ar_sdio); + + kfree(ar_sdio->dma_buffer); + kfree(ar_sdio); +} + +static const struct sdio_device_id ath6kl_sdio_devices[] = { + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))}, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, ath6kl_sdio_devices); + +static struct sdio_driver ath6kl_sdio_driver = { + .name = "ath6kl_sdio", + .id_table = ath6kl_sdio_devices, + .probe = ath6kl_sdio_probe, + .remove = ath6kl_sdio_remove, +}; + +static int __init ath6kl_sdio_init(void) +{ + int ret; + + ret = sdio_register_driver(&ath6kl_sdio_driver); + if (ret) + ath6kl_err("sdio driver registration failed: %d\n", ret); + + return ret; +} + +static void __exit ath6kl_sdio_exit(void) +{ + sdio_unregister_driver(&ath6kl_sdio_driver); +} + +module_init(ath6kl_sdio_init); +module_exit(ath6kl_sdio_exit); + +MODULE_AUTHOR("Atheros Communications, Inc."); +MODULE_DESCRIPTION("Driver support for Atheros AR600x SDIO devices"); +MODULE_LICENSE("Dual BSD/GPL"); + +MODULE_FIRMWARE(AR6003_REV2_OTP_FILE); +MODULE_FIRMWARE(AR6003_REV2_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6003_REV2_PATCH_FILE); +MODULE_FIRMWARE(AR6003_REV2_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6003_REV2_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6003_REV3_OTP_FILE); +MODULE_FIRMWARE(AR6003_REV3_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6003_REV3_PATCH_FILE); +MODULE_FIRMWARE(AR6003_REV3_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6003_REV3_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h new file mode 100644 index 000000000000..c9a76051f042 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2004-2010 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef TARGET_H +#define TARGET_H + +#define AR6003_BOARD_DATA_SZ 1024 +#define AR6003_BOARD_EXT_DATA_SZ 768 + +#define AR6004_BOARD_DATA_SZ 7168 +#define AR6004_BOARD_EXT_DATA_SZ 0 + +#define RESET_CONTROL_ADDRESS 0x00000000 +#define RESET_CONTROL_COLD_RST 0x00000100 +#define RESET_CONTROL_MBOX_RST 0x00000004 + +#define CPU_CLOCK_STANDARD_S 0 +#define CPU_CLOCK_STANDARD 0x00000003 +#define CPU_CLOCK_ADDRESS 0x00000020 + +#define CLOCK_CONTROL_ADDRESS 0x00000028 +#define CLOCK_CONTROL_LF_CLK32_S 2 +#define CLOCK_CONTROL_LF_CLK32 0x00000004 + +#define SYSTEM_SLEEP_ADDRESS 0x000000c4 +#define SYSTEM_SLEEP_DISABLE_S 0 +#define SYSTEM_SLEEP_DISABLE 0x00000001 + +#define LPO_CAL_ADDRESS 0x000000e0 +#define LPO_CAL_ENABLE_S 20 +#define LPO_CAL_ENABLE 0x00100000 + +#define GPIO_PIN10_ADDRESS 0x00000050 +#define GPIO_PIN11_ADDRESS 0x00000054 +#define GPIO_PIN12_ADDRESS 0x00000058 +#define GPIO_PIN13_ADDRESS 0x0000005c + +#define HOST_INT_STATUS_ADDRESS 0x00000400 +#define HOST_INT_STATUS_ERROR_S 7 +#define HOST_INT_STATUS_ERROR 0x00000080 + +#define HOST_INT_STATUS_CPU_S 6 +#define HOST_INT_STATUS_CPU 0x00000040 + +#define HOST_INT_STATUS_COUNTER_S 4 +#define HOST_INT_STATUS_COUNTER 0x00000010 + +#define CPU_INT_STATUS_ADDRESS 0x00000401 + +#define ERROR_INT_STATUS_ADDRESS 0x00000402 +#define ERROR_INT_STATUS_WAKEUP_S 2 +#define ERROR_INT_STATUS_WAKEUP 0x00000004 + +#define ERROR_INT_STATUS_RX_UNDERFLOW_S 1 +#define ERROR_INT_STATUS_RX_UNDERFLOW 0x00000002 + +#define ERROR_INT_STATUS_TX_OVERFLOW_S 0 +#define ERROR_INT_STATUS_TX_OVERFLOW 0x00000001 + +#define COUNTER_INT_STATUS_ADDRESS 0x00000403 +#define COUNTER_INT_STATUS_COUNTER_S 0 +#define COUNTER_INT_STATUS_COUNTER 0x000000ff + +#define RX_LOOKAHEAD_VALID_ADDRESS 0x00000405 + +#define INT_STATUS_ENABLE_ADDRESS 0x00000418 +#define INT_STATUS_ENABLE_ERROR_S 7 +#define INT_STATUS_ENABLE_ERROR 0x00000080 + +#define INT_STATUS_ENABLE_CPU_S 6 +#define INT_STATUS_ENABLE_CPU 0x00000040 + +#define INT_STATUS_ENABLE_INT_S 5 +#define INT_STATUS_ENABLE_INT 0x00000020 +#define INT_STATUS_ENABLE_COUNTER_S 4 +#define INT_STATUS_ENABLE_COUNTER 0x00000010 + +#define INT_STATUS_ENABLE_MBOX_DATA_S 0 +#define INT_STATUS_ENABLE_MBOX_DATA 0x0000000f + +#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419 +#define CPU_INT_STATUS_ENABLE_BIT_S 0 +#define CPU_INT_STATUS_ENABLE_BIT 0x000000ff + +#define ERROR_STATUS_ENABLE_ADDRESS 0x0000041a +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_S 1 +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW 0x00000002 + +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_S 0 +#define ERROR_STATUS_ENABLE_TX_OVERFLOW 0x00000001 + +#define COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000041b +#define COUNTER_INT_STATUS_ENABLE_BIT_S 0 +#define COUNTER_INT_STATUS_ENABLE_BIT 0x000000ff + +#define COUNT_ADDRESS 0x00000420 + +#define COUNT_DEC_ADDRESS 0x00000440 + +#define WINDOW_DATA_ADDRESS 0x00000474 +#define WINDOW_WRITE_ADDR_ADDRESS 0x00000478 +#define WINDOW_READ_ADDR_ADDRESS 0x0000047c +#define CPU_DBG_SEL_ADDRESS 0x00000483 +#define CPU_DBG_ADDRESS 0x00000484 + +#define LOCAL_SCRATCH_ADDRESS 0x000000c0 +#define ATH6KL_OPTION_SLEEP_DISABLE 0x08 + +#define RTC_BASE_ADDRESS 0x00004000 +#define GPIO_BASE_ADDRESS 0x00014000 +#define MBOX_BASE_ADDRESS 0x00018000 +#define ANALOG_INTF_BASE_ADDRESS 0x0001c000 + +/* real name of the register is unknown */ +#define ATH6KL_ANALOG_PLL_REGISTER (ANALOG_INTF_BASE_ADDRESS + 0x284) + +#define SM(f, v) (((v) << f##_S) & f) +#define MS(f, v) (((v) & f) >> f##_S) + +/* + * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the + * host_interest structure. + * + * Host Interest is shared between Host and Target in order to coordinate + * between the two, and is intended to remain constant (with additions only + * at the end). + */ +#define ATH6KL_AR6003_HI_START_ADDR 0x00540600 +#define ATH6KL_AR6004_HI_START_ADDR 0x00400800 + +/* + * These are items that the Host may need to access + * via BMI or via the Diagnostic Window. The position + * of items in this structure must remain constant. + * across firmware revisions! + * + * Types for each item must be fixed size across target and host platforms. + * The structure is used only to calculate offset for each register with + * HI_ITEM() macro, no values are stored to it. + * + * More items may be added at the end. + */ +struct host_interest { + /* + * Pointer to application-defined area, if any. + * Set by Target application during startup. + */ + u32 hi_app_host_interest; /* 0x00 */ + + /* Pointer to register dump area, valid after Target crash. */ + u32 hi_failure_state; /* 0x04 */ + + /* Pointer to debug logging header */ + u32 hi_dbglog_hdr; /* 0x08 */ + + u32 hi_unused1; /* 0x0c */ + + /* + * General-purpose flag bits, similar to ATH6KL_OPTION_* flags. + * Can be used by application rather than by OS. + */ + u32 hi_option_flag; /* 0x10 */ + + /* + * Boolean that determines whether or not to + * display messages on the serial port. + */ + u32 hi_serial_enable; /* 0x14 */ + + /* Start address of DataSet index, if any */ + u32 hi_dset_list_head; /* 0x18 */ + + /* Override Target application start address */ + u32 hi_app_start; /* 0x1c */ + + /* Clock and voltage tuning */ + u32 hi_skip_clock_init; /* 0x20 */ + u32 hi_core_clock_setting; /* 0x24 */ + u32 hi_cpu_clock_setting; /* 0x28 */ + u32 hi_system_sleep_setting; /* 0x2c */ + u32 hi_xtal_control_setting; /* 0x30 */ + u32 hi_pll_ctrl_setting_24ghz; /* 0x34 */ + u32 hi_pll_ctrl_setting_5ghz; /* 0x38 */ + u32 hi_ref_voltage_trim_setting; /* 0x3c */ + u32 hi_clock_info; /* 0x40 */ + + /* + * Flash configuration overrides, used only + * when firmware is not executing from flash. + * (When using flash, modify the global variables + * with equivalent names.) + */ + u32 hi_bank0_addr_value; /* 0x44 */ + u32 hi_bank0_read_value; /* 0x48 */ + u32 hi_bank0_write_value; /* 0x4c */ + u32 hi_bank0_config_value; /* 0x50 */ + + /* Pointer to Board Data */ + u32 hi_board_data; /* 0x54 */ + u32 hi_board_data_initialized; /* 0x58 */ + + u32 hi_dset_ram_index_tbl; /* 0x5c */ + + u32 hi_desired_baud_rate; /* 0x60 */ + u32 hi_dbglog_config; /* 0x64 */ + u32 hi_end_ram_reserve_sz; /* 0x68 */ + u32 hi_mbox_io_block_sz; /* 0x6c */ + + u32 hi_num_bpatch_streams; /* 0x70 -- unused */ + u32 hi_mbox_isr_yield_limit; /* 0x74 */ + + u32 hi_refclk_hz; /* 0x78 */ + u32 hi_ext_clk_detected; /* 0x7c */ + u32 hi_dbg_uart_txpin; /* 0x80 */ + u32 hi_dbg_uart_rxpin; /* 0x84 */ + u32 hi_hci_uart_baud; /* 0x88 */ + u32 hi_hci_uart_pin_assignments; /* 0x8C */ + /* + * NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts + * pin + */ + u32 hi_hci_uart_baud_scale_val; /* 0x90 */ + u32 hi_hci_uart_baud_step_val; /* 0x94 */ + + u32 hi_allocram_start; /* 0x98 */ + u32 hi_allocram_sz; /* 0x9c */ + u32 hi_hci_bridge_flags; /* 0xa0 */ + u32 hi_hci_uart_support_pins; /* 0xa4 */ + /* + * NOTE: byte [0] = RESET pin (bit 7 is polarity), + * bytes[1]..bytes[3] are for future use + */ + u32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */ + /* + * 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high + * [31:16]: wakeup timeout in ms + */ + + /* Pointer to extended board data */ + u32 hi_board_ext_data; /* 0xac */ + u32 hi_board_ext_data_config; /* 0xb0 */ + + /* + * Bit [0] : valid + * Bit[31:16: size + */ + /* + * hi_reset_flag is used to do some stuff when target reset. + * such as restore app_start after warm reset or + * preserve host Interest area, or preserve ROM data, literals etc. + */ + u32 hi_reset_flag; /* 0xb4 */ + /* indicate hi_reset_flag is valid */ + u32 hi_reset_flag_valid; /* 0xb8 */ + u32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */ + /* + * 0xbc - [31:0]: idle timeout in ms + */ + /* ACS flags */ + u32 hi_acs_flags; /* 0xc0 */ + u32 hi_console_flags; /* 0xc4 */ + u32 hi_nvram_state; /* 0xc8 */ + u32 hi_option_flag2; /* 0xcc */ + + /* If non-zero, override values sent to Host in WMI_READY event. */ + u32 hi_sw_version_override; /* 0xd0 */ + u32 hi_abi_version_override; /* 0xd4 */ + + /* + * Percentage of high priority RX traffic to total expected RX traffic - + * applicable only to ar6004 + */ + u32 hi_hp_rx_traffic_ratio; /* 0xd8 */ + + /* test applications flags */ + u32 hi_test_apps_related ; /* 0xdc */ + /* location of test script */ + u32 hi_ota_testscript; /* 0xe0 */ + /* location of CAL data */ + u32 hi_cal_data; /* 0xe4 */ + /* Number of packet log buffers */ + u32 hi_pktlog_num_buffers; /* 0xe8 */ + +} __packed; + +#define HI_ITEM(item) offsetof(struct host_interest, item) + +#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3 + +#define HI_OPTION_FW_MODE_IBSS 0x0 +#define HI_OPTION_FW_MODE_BSS_STA 0x1 +#define HI_OPTION_FW_MODE_AP 0x2 + +#define HI_OPTION_FW_SUBMODE_NONE 0x0 +#define HI_OPTION_FW_SUBMODE_P2PDEV 0x1 +#define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2 +#define HI_OPTION_FW_SUBMODE_P2PGO 0x3 + +#define HI_OPTION_NUM_DEV_SHIFT 0x9 + +#define HI_OPTION_FW_BRIDGE_SHIFT 0x04 + +/* Fw Mode/SubMode Mask +|------------------------------------------------------------------------------| +| SUB | SUB | SUB | SUB | | | | +| MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0| +| (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2) +|------------------------------------------------------------------------------| +*/ +#define HI_OPTION_FW_MODE_SHIFT 0xC +#define HI_OPTION_FW_SUBMODE_SHIFT 0x14 + +/* Convert a Target virtual address into a Target physical address */ +#define AR6003_VTOP(vaddr) ((vaddr) & 0x001fffff) +#define AR6004_VTOP(vaddr) (vaddr) + +#define TARG_VTOP(target_type, vaddr) \ + (((target_type) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \ + (((target_type) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : 0)) + +#define AR6003_REV2_APP_LOAD_ADDRESS 0x543180 +#define AR6003_REV2_BOARD_EXT_DATA_ADDRESS 0x57E500 +#define AR6003_REV2_DATASET_PATCH_ADDRESS 0x57e884 +#define AR6003_REV2_RAM_RESERVE_SIZE 6912 + +#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000 +#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330 +#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74 +#define AR6003_REV3_RAM_RESERVE_SIZE 512 + +#define AR6004_REV1_BOARD_DATA_ADDRESS 0x435400 +#define AR6004_REV1_BOARD_EXT_DATA_ADDRESS 0x437000 +#define AR6004_REV1_RAM_RESERVE_SIZE 11264 + +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + +struct ath6kl_dbglog_buf { + __le32 next; + __le32 buffer_addr; + __le32 bufsize; + __le32 length; + __le32 count; + __le32 free; +} __packed; + +struct ath6kl_dbglog_hdr { + __le32 dbuf_addr; + __le32 dropped; +} __packed; + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/testmode.c b/drivers/net/wireless/ath/ath6kl/testmode.c new file mode 100644 index 000000000000..381eb66a605f --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/testmode.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "testmode.h" + +#include <net/netlink.h> + +enum ath6kl_tm_attr { + __ATH6KL_TM_ATTR_INVALID = 0, + ATH6KL_TM_ATTR_CMD = 1, + ATH6KL_TM_ATTR_DATA = 2, + + /* keep last */ + __ATH6KL_TM_ATTR_AFTER_LAST, + ATH6KL_TM_ATTR_MAX = __ATH6KL_TM_ATTR_AFTER_LAST - 1, +}; + +enum ath6kl_tm_cmd { + ATH6KL_TM_CMD_TCMD = 0, + ATH6KL_TM_CMD_RX_REPORT = 1, +}; + +#define ATH6KL_TM_DATA_MAX_LEN 5000 + +static const struct nla_policy ath6kl_tm_policy[ATH6KL_TM_ATTR_MAX + 1] = { + [ATH6KL_TM_ATTR_CMD] = { .type = NLA_U32 }, + [ATH6KL_TM_ATTR_DATA] = { .type = NLA_BINARY, + .len = ATH6KL_TM_DATA_MAX_LEN }, +}; + +void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len) +{ + if (down_interruptible(&ar->sem)) + return; + + kfree(ar->tm.rx_report); + + ar->tm.rx_report = kmemdup(buf, buf_len, GFP_KERNEL); + ar->tm.rx_report_len = buf_len; + + up(&ar->sem); + + wake_up(&ar->event_wq); +} + +static int ath6kl_tm_rx_report(struct ath6kl *ar, void *buf, size_t buf_len, + struct sk_buff *skb) +{ + int ret = 0; + long left; + + if (down_interruptible(&ar->sem)) + return -ERESTARTSYS; + + if (!test_bit(WMI_READY, &ar->flag)) { + ret = -EIO; + goto out; + } + + if (test_bit(DESTROY_IN_PROGRESS, &ar->flag)) { + ret = -EBUSY; + goto out; + } + + if (ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len) < 0) { + up(&ar->sem); + return -EIO; + } + + left = wait_event_interruptible_timeout(ar->event_wq, + ar->tm.rx_report != NULL, + WMI_TIMEOUT); + + if (left == 0) { + ret = -ETIMEDOUT; + goto out; + } else if (left < 0) { + ret = left; + goto out; + } + + if (ar->tm.rx_report == NULL || ar->tm.rx_report_len == 0) { + ret = -EINVAL; + goto out; + } + + NLA_PUT(skb, ATH6KL_TM_ATTR_DATA, ar->tm.rx_report_len, + ar->tm.rx_report); + + kfree(ar->tm.rx_report); + ar->tm.rx_report = NULL; + +out: + up(&ar->sem); + + return ret; + +nla_put_failure: + ret = -ENOBUFS; + goto out; +} + +int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) +{ + struct ath6kl *ar = wiphy_priv(wiphy); + struct nlattr *tb[ATH6KL_TM_ATTR_MAX + 1]; + int err, buf_len, reply_len; + struct sk_buff *skb; + void *buf; + + err = nla_parse(tb, ATH6KL_TM_ATTR_MAX, data, len, + ath6kl_tm_policy); + if (err) + return err; + + if (!tb[ATH6KL_TM_ATTR_CMD]) + return -EINVAL; + + switch (nla_get_u32(tb[ATH6KL_TM_ATTR_CMD])) { + case ATH6KL_TM_CMD_TCMD: + if (!tb[ATH6KL_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); + buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); + + ath6kl_wmi_test_cmd(ar->wmi, buf, buf_len); + + return 0; + + break; + case ATH6KL_TM_CMD_RX_REPORT: + if (!tb[ATH6KL_TM_ATTR_DATA]) + return -EINVAL; + + buf = nla_data(tb[ATH6KL_TM_ATTR_DATA]); + buf_len = nla_len(tb[ATH6KL_TM_ATTR_DATA]); + + reply_len = nla_total_size(ATH6KL_TM_DATA_MAX_LEN); + skb = cfg80211_testmode_alloc_reply_skb(wiphy, reply_len); + if (!skb) + return -ENOMEM; + + err = ath6kl_tm_rx_report(ar, buf, buf_len, skb); + if (err < 0) { + kfree_skb(skb); + return err; + } + + return cfg80211_testmode_reply(skb); + default: + return -EOPNOTSUPP; + } +} diff --git a/drivers/net/wireless/ath/ath6kl/testmode.h b/drivers/net/wireless/ath/ath6kl/testmode.h new file mode 100644 index 000000000000..43dffcc11fb1 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/testmode.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" + +#ifdef CONFIG_NL80211_TESTMODE + +void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, size_t buf_len); +int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len); + +#else + +static inline void ath6kl_tm_rx_report_event(struct ath6kl *ar, void *buf, + size_t buf_len) +{ +} + +static inline int ath6kl_tm_cmd(struct wiphy *wiphy, void *data, int len) +{ + return 0; +} + +#endif diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c new file mode 100644 index 000000000000..a7117074f81c --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -0,0 +1,1478 @@ +/* + * 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 "core.h" +#include "debug.h" + +static u8 ath6kl_ibss_map_epid(struct sk_buff *skb, struct net_device *dev, + u32 *map_no) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ethhdr *eth_hdr; + u32 i, ep_map = -1; + u8 *datap; + + *map_no = 0; + datap = skb->data; + eth_hdr = (struct ethhdr *) (datap + sizeof(struct wmi_data_hdr)); + + if (is_multicast_ether_addr(eth_hdr->h_dest)) + return ENDPOINT_2; + + for (i = 0; i < ar->node_num; i++) { + if (memcmp(eth_hdr->h_dest, ar->node_map[i].mac_addr, + ETH_ALEN) == 0) { + *map_no = i + 1; + ar->node_map[i].tx_pend++; + return ar->node_map[i].ep_id; + } + + if ((ep_map == -1) && !ar->node_map[i].tx_pend) + ep_map = i; + } + + if (ep_map == -1) { + ep_map = ar->node_num; + ar->node_num++; + if (ar->node_num > MAX_NODE_NUM) + return ENDPOINT_UNUSED; + } + + memcpy(ar->node_map[ep_map].mac_addr, eth_hdr->h_dest, ETH_ALEN); + + for (i = ENDPOINT_2; i <= ENDPOINT_5; i++) { + if (!ar->tx_pending[i]) { + ar->node_map[ep_map].ep_id = i; + break; + } + + /* + * No free endpoint is available, start redistribution on + * the inuse endpoints. + */ + if (i == ENDPOINT_5) { + ar->node_map[ep_map].ep_id = ar->next_ep_id; + ar->next_ep_id++; + if (ar->next_ep_id > ENDPOINT_5) + ar->next_ep_id = ENDPOINT_2; + } + } + + *map_no = ep_map + 1; + ar->node_map[ep_map].tx_pend++; + + return ar->node_map[ep_map].ep_id; +} + +static bool ath6kl_powersave_ap(struct ath6kl *ar, struct sk_buff *skb, + bool *more_data) +{ + struct ethhdr *datap = (struct ethhdr *) skb->data; + struct ath6kl_sta *conn = NULL; + bool ps_queued = false, is_psq_empty = false; + + if (is_multicast_ether_addr(datap->h_dest)) { + u8 ctr = 0; + bool q_mcast = false; + + for (ctr = 0; ctr < AP_MAX_NUM_STA; ctr++) { + if (ar->sta_list[ctr].sta_flags & STA_PS_SLEEP) { + q_mcast = true; + break; + } + } + + if (q_mcast) { + /* + * If this transmit is not because of a Dtim Expiry + * q it. + */ + if (!test_bit(DTIM_EXPIRED, &ar->flag)) { + bool is_mcastq_empty = false; + + spin_lock_bh(&ar->mcastpsq_lock); + is_mcastq_empty = + skb_queue_empty(&ar->mcastpsq); + skb_queue_tail(&ar->mcastpsq, skb); + spin_unlock_bh(&ar->mcastpsq_lock); + + /* + * If this is the first Mcast pkt getting + * queued indicate to the target to set the + * BitmapControl LSB of the TIM IE. + */ + if (is_mcastq_empty) + ath6kl_wmi_set_pvb_cmd(ar->wmi, + MCAST_AID, 1); + + ps_queued = true; + } else { + /* + * This transmit is because of Dtim expiry. + * Determine if MoreData bit has to be set. + */ + spin_lock_bh(&ar->mcastpsq_lock); + if (!skb_queue_empty(&ar->mcastpsq)) + *more_data = true; + spin_unlock_bh(&ar->mcastpsq_lock); + } + } + } else { + conn = ath6kl_find_sta(ar, datap->h_dest); + if (!conn) { + dev_kfree_skb(skb); + + /* Inform the caller that the skb is consumed */ + return true; + } + + if (conn->sta_flags & STA_PS_SLEEP) { + if (!(conn->sta_flags & STA_PS_POLLED)) { + /* Queue the frames if the STA is sleeping */ + spin_lock_bh(&conn->psq_lock); + is_psq_empty = skb_queue_empty(&conn->psq); + skb_queue_tail(&conn->psq, skb); + spin_unlock_bh(&conn->psq_lock); + + /* + * If this is the first pkt getting queued + * for this STA, update the PVB for this + * STA. + */ + if (is_psq_empty) + ath6kl_wmi_set_pvb_cmd(ar->wmi, + conn->aid, 1); + + ps_queued = true; + } else { + /* + * This tx is because of a PsPoll. + * Determine if MoreData bit has to be set. + */ + spin_lock_bh(&conn->psq_lock); + if (!skb_queue_empty(&conn->psq)) + *more_data = true; + spin_unlock_bh(&conn->psq_lock); + } + } + } + + return ps_queued; +} + +/* Tx functions */ + +int ath6kl_control_tx(void *devt, struct sk_buff *skb, + enum htc_endpoint_id eid) +{ + struct ath6kl *ar = devt; + int status = 0; + struct ath6kl_cookie *cookie = NULL; + + spin_lock_bh(&ar->lock); + + ath6kl_dbg(ATH6KL_DBG_WLAN_TX, + "%s: skb=0x%p, len=0x%x eid =%d\n", __func__, + skb, skb->len, eid); + + if (test_bit(WMI_CTRL_EP_FULL, &ar->flag) && (eid == ar->ctrl_ep)) { + /* + * Control endpoint is full, don't allocate resources, we + * are just going to drop this packet. + */ + cookie = NULL; + ath6kl_err("wmi ctrl ep full, dropping pkt : 0x%p, len:%d\n", + skb, skb->len); + } else + cookie = ath6kl_alloc_cookie(ar); + + if (cookie == NULL) { + spin_unlock_bh(&ar->lock); + status = -ENOMEM; + goto fail_ctrl_tx; + } + + ar->tx_pending[eid]++; + + if (eid != ar->ctrl_ep) + ar->total_tx_data_pend++; + + spin_unlock_bh(&ar->lock); + + cookie->skb = skb; + cookie->map_no = 0; + set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, + eid, ATH6KL_CONTROL_PKT_TAG); + + /* + * This interface is asynchronous, if there is an error, cleanup + * will happen in the TX completion callback. + */ + ath6kl_htc_tx(ar->htc_target, &cookie->htc_pkt); + + return 0; + +fail_ctrl_tx: + dev_kfree_skb(skb); + return status; +} + +int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_cookie *cookie = NULL; + enum htc_endpoint_id eid = ENDPOINT_UNUSED; + u32 map_no = 0; + u16 htc_tag = ATH6KL_DATA_PKT_TAG; + u8 ac = 99 ; /* initialize to unmapped ac */ + bool chk_adhoc_ps_mapping = false, more_data = false; + int ret; + + ath6kl_dbg(ATH6KL_DBG_WLAN_TX, + "%s: skb=0x%p, data=0x%p, len=0x%x\n", __func__, + skb, skb->data, skb->len); + + /* If target is not associated */ + if (!test_bit(CONNECTED, &ar->flag)) { + dev_kfree_skb(skb); + return 0; + } + + if (!test_bit(WMI_READY, &ar->flag)) + goto fail_tx; + + /* AP mode Power saving processing */ + if (ar->nw_type == AP_NETWORK) { + if (ath6kl_powersave_ap(ar, skb, &more_data)) + return 0; + } + + if (test_bit(WMI_ENABLED, &ar->flag)) { + if (skb_headroom(skb) < dev->needed_headroom) { + WARN_ON(1); + goto fail_tx; + } + + if (ath6kl_wmi_dix_2_dot3(ar->wmi, skb)) { + ath6kl_err("ath6kl_wmi_dix_2_dot3 failed\n"); + goto fail_tx; + } + + if (ath6kl_wmi_data_hdr_add(ar->wmi, skb, DATA_MSGTYPE, + more_data, 0, 0, NULL)) { + ath6kl_err("wmi_data_hdr_add failed\n"); + goto fail_tx; + } + + if ((ar->nw_type == ADHOC_NETWORK) && + ar->ibss_ps_enable && test_bit(CONNECTED, &ar->flag)) + chk_adhoc_ps_mapping = true; + else { + /* get the stream mapping */ + ret = ath6kl_wmi_implicit_create_pstream(ar->wmi, skb, + 0, test_bit(WMM_ENABLED, &ar->flag), &ac); + if (ret) + goto fail_tx; + } + } else + goto fail_tx; + + spin_lock_bh(&ar->lock); + + if (chk_adhoc_ps_mapping) + eid = ath6kl_ibss_map_epid(skb, dev, &map_no); + else + eid = ar->ac2ep_map[ac]; + + if (eid == 0 || eid == ENDPOINT_UNUSED) { + ath6kl_err("eid %d is not mapped!\n", eid); + spin_unlock_bh(&ar->lock); + goto fail_tx; + } + + /* allocate resource for this packet */ + cookie = ath6kl_alloc_cookie(ar); + + if (!cookie) { + spin_unlock_bh(&ar->lock); + goto fail_tx; + } + + /* update counts while the lock is held */ + ar->tx_pending[eid]++; + ar->total_tx_data_pend++; + + spin_unlock_bh(&ar->lock); + + if (!IS_ALIGNED((unsigned long) skb->data - HTC_HDR_LENGTH, 4) && + skb_cloned(skb)) { + /* + * We will touch (move the buffer data to align it. Since the + * skb buffer is cloned and not only the header is changed, we + * have to copy it to allow the changes. Since we are copying + * the data here, we may as well align it by reserving suitable + * headroom to avoid the memmove in ath6kl_htc_tx_buf_align(). + */ + struct sk_buff *nskb; + + nskb = skb_copy_expand(skb, HTC_HDR_LENGTH, 0, GFP_ATOMIC); + if (nskb == NULL) + goto fail_tx; + kfree_skb(skb); + skb = nskb; + } + + cookie->skb = skb; + cookie->map_no = map_no; + set_htc_pkt_info(&cookie->htc_pkt, cookie, skb->data, skb->len, + eid, htc_tag); + + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "tx ", + skb->data, skb->len); + + /* + * HTC interface is asynchronous, if this fails, cleanup will + * happen in the ath6kl_tx_complete callback. + */ + ath6kl_htc_tx(ar->htc_target, &cookie->htc_pkt); + + return 0; + +fail_tx: + dev_kfree_skb(skb); + + ar->net_stats.tx_dropped++; + ar->net_stats.tx_aborted_errors++; + + return 0; +} + +/* indicate tx activity or inactivity on a WMI stream */ +void ath6kl_indicate_tx_activity(void *devt, u8 traffic_class, bool active) +{ + struct ath6kl *ar = devt; + enum htc_endpoint_id eid; + int i; + + eid = ar->ac2ep_map[traffic_class]; + + if (!test_bit(WMI_ENABLED, &ar->flag)) + goto notify_htc; + + spin_lock_bh(&ar->lock); + + ar->ac_stream_active[traffic_class] = active; + + if (active) { + /* + * Keep track of the active stream with the highest + * priority. + */ + if (ar->ac_stream_pri_map[traffic_class] > + ar->hiac_stream_active_pri) + /* set the new highest active priority */ + ar->hiac_stream_active_pri = + ar->ac_stream_pri_map[traffic_class]; + + } else { + /* + * We may have to search for the next active stream + * that is the highest priority. + */ + if (ar->hiac_stream_active_pri == + ar->ac_stream_pri_map[traffic_class]) { + /* + * The highest priority stream just went inactive + * reset and search for the "next" highest "active" + * priority stream. + */ + ar->hiac_stream_active_pri = 0; + + for (i = 0; i < WMM_NUM_AC; i++) { + if (ar->ac_stream_active[i] && + (ar->ac_stream_pri_map[i] > + ar->hiac_stream_active_pri)) + /* + * Set the new highest active + * priority. + */ + ar->hiac_stream_active_pri = + ar->ac_stream_pri_map[i]; + } + } + } + + spin_unlock_bh(&ar->lock); + +notify_htc: + /* notify HTC, this may cause credit distribution changes */ + ath6kl_htc_indicate_activity_change(ar->htc_target, eid, active); +} + +enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target, + struct htc_packet *packet) +{ + struct ath6kl *ar = target->dev->ar; + enum htc_endpoint_id endpoint = packet->endpoint; + + if (endpoint == ar->ctrl_ep) { + /* + * Under normal WMI if this is getting full, then something + * is running rampant the host should not be exhausting the + * WMI queue with too many commands the only exception to + * this is during testing using endpointping. + */ + spin_lock_bh(&ar->lock); + set_bit(WMI_CTRL_EP_FULL, &ar->flag); + spin_unlock_bh(&ar->lock); + ath6kl_err("wmi ctrl ep is full\n"); + return HTC_SEND_FULL_KEEP; + } + + if (packet->info.tx.tag == ATH6KL_CONTROL_PKT_TAG) + return HTC_SEND_FULL_KEEP; + + if (ar->nw_type == ADHOC_NETWORK) + /* + * In adhoc mode, we cannot differentiate traffic + * priorities so there is no need to continue, however we + * should stop the network. + */ + goto stop_net_queues; + + /* + * The last MAX_HI_COOKIE_NUM "batch" of cookies are reserved for + * the highest active stream. + */ + if (ar->ac_stream_pri_map[ar->ep2ac_map[endpoint]] < + ar->hiac_stream_active_pri && + ar->cookie_count <= MAX_HI_COOKIE_NUM) + /* + * Give preference to the highest priority stream by + * dropping the packets which overflowed. + */ + return HTC_SEND_FULL_DROP; + +stop_net_queues: + spin_lock_bh(&ar->lock); + set_bit(NETQ_STOPPED, &ar->flag); + spin_unlock_bh(&ar->lock); + netif_stop_queue(ar->net_dev); + + return HTC_SEND_FULL_KEEP; +} + +/* TODO this needs to be looked at */ +static void ath6kl_tx_clear_node_map(struct ath6kl *ar, + enum htc_endpoint_id eid, u32 map_no) +{ + u32 i; + + if (ar->nw_type != ADHOC_NETWORK) + return; + + if (!ar->ibss_ps_enable) + return; + + if (eid == ar->ctrl_ep) + return; + + if (map_no == 0) + return; + + map_no--; + ar->node_map[map_no].tx_pend--; + + if (ar->node_map[map_no].tx_pend) + return; + + if (map_no != (ar->node_num - 1)) + return; + + for (i = ar->node_num; i > 0; i--) { + if (ar->node_map[i - 1].tx_pend) + break; + + memset(&ar->node_map[i - 1], 0, + sizeof(struct ath6kl_node_mapping)); + ar->node_num--; + } +} + +void ath6kl_tx_complete(void *context, struct list_head *packet_queue) +{ + struct ath6kl *ar = context; + struct sk_buff_head skb_queue; + struct htc_packet *packet; + struct sk_buff *skb; + struct ath6kl_cookie *ath6kl_cookie; + u32 map_no = 0; + int status; + enum htc_endpoint_id eid; + bool wake_event = false; + bool flushing = false; + + skb_queue_head_init(&skb_queue); + + /* lock the driver as we update internal state */ + spin_lock_bh(&ar->lock); + + /* reap completed packets */ + while (!list_empty(packet_queue)) { + + packet = list_first_entry(packet_queue, struct htc_packet, + list); + list_del(&packet->list); + + ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt; + if (!ath6kl_cookie) + goto fatal; + + status = packet->status; + skb = ath6kl_cookie->skb; + eid = packet->endpoint; + map_no = ath6kl_cookie->map_no; + + if (!skb || !skb->data) + goto fatal; + + packet->buf = skb->data; + + __skb_queue_tail(&skb_queue, skb); + + if (!status && (packet->act_len != skb->len)) + goto fatal; + + ar->tx_pending[eid]--; + + if (eid != ar->ctrl_ep) + ar->total_tx_data_pend--; + + if (eid == ar->ctrl_ep) { + if (test_bit(WMI_CTRL_EP_FULL, &ar->flag)) + clear_bit(WMI_CTRL_EP_FULL, &ar->flag); + + if (ar->tx_pending[eid] == 0) + wake_event = true; + } + + if (status) { + if (status == -ECANCELED) + /* a packet was flushed */ + flushing = true; + + ar->net_stats.tx_errors++; + + if (status != -ENOSPC) + ath6kl_err("tx error, status: 0x%x\n", status); + ath6kl_dbg(ATH6KL_DBG_WLAN_TX, + "%s: skb=0x%p data=0x%p len=0x%x eid=%d %s\n", + __func__, skb, packet->buf, packet->act_len, + eid, "error!"); + } else { + ath6kl_dbg(ATH6KL_DBG_WLAN_TX, + "%s: skb=0x%p data=0x%p len=0x%x eid=%d %s\n", + __func__, skb, packet->buf, packet->act_len, + eid, "OK"); + + flushing = false; + ar->net_stats.tx_packets++; + ar->net_stats.tx_bytes += skb->len; + } + + ath6kl_tx_clear_node_map(ar, eid, map_no); + + ath6kl_free_cookie(ar, ath6kl_cookie); + + if (test_bit(NETQ_STOPPED, &ar->flag)) + clear_bit(NETQ_STOPPED, &ar->flag); + } + + spin_unlock_bh(&ar->lock); + + __skb_queue_purge(&skb_queue); + + if (test_bit(CONNECTED, &ar->flag)) { + if (!flushing) + netif_wake_queue(ar->net_dev); + } + + if (wake_event) + wake_up(&ar->event_wq); + + return; + +fatal: + WARN_ON(1); + spin_unlock_bh(&ar->lock); + return; +} + +void ath6kl_tx_data_cleanup(struct ath6kl *ar) +{ + int i; + + /* flush all the data (non-control) streams */ + for (i = 0; i < WMM_NUM_AC; i++) + ath6kl_htc_flush_txep(ar->htc_target, ar->ac2ep_map[i], + ATH6KL_DATA_PKT_TAG); +} + +/* Rx functions */ + +static void ath6kl_deliver_frames_to_nw_stack(struct net_device *dev, + struct sk_buff *skb) +{ + if (!skb) + return; + + skb->dev = dev; + + if (!(skb->dev->flags & IFF_UP)) { + dev_kfree_skb(skb); + return; + } + + skb->protocol = eth_type_trans(skb, skb->dev); + + netif_rx_ni(skb); +} + +static void ath6kl_alloc_netbufs(struct sk_buff_head *q, u16 num) +{ + struct sk_buff *skb; + + while (num) { + skb = ath6kl_buf_alloc(ATH6KL_BUFFER_SIZE); + if (!skb) { + ath6kl_err("netbuf allocation failed\n"); + return; + } + skb_queue_tail(q, skb); + num--; + } +} + +static struct sk_buff *aggr_get_free_skb(struct aggr_info *p_aggr) +{ + struct sk_buff *skb = NULL; + + if (skb_queue_len(&p_aggr->free_q) < (AGGR_NUM_OF_FREE_NETBUFS >> 2)) + ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS); + + skb = skb_dequeue(&p_aggr->free_q); + + return skb; +} + +void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint) +{ + struct ath6kl *ar = target->dev->ar; + struct sk_buff *skb; + int rx_buf; + int n_buf_refill; + struct htc_packet *packet; + struct list_head queue; + + n_buf_refill = ATH6KL_MAX_RX_BUFFERS - + ath6kl_htc_get_rxbuf_num(ar->htc_target, endpoint); + + if (n_buf_refill <= 0) + return; + + INIT_LIST_HEAD(&queue); + + ath6kl_dbg(ATH6KL_DBG_WLAN_RX, + "%s: providing htc with %d buffers at eid=%d\n", + __func__, n_buf_refill, endpoint); + + for (rx_buf = 0; rx_buf < n_buf_refill; rx_buf++) { + skb = ath6kl_buf_alloc(ATH6KL_BUFFER_SIZE); + if (!skb) + break; + + packet = (struct htc_packet *) skb->head; + if (!IS_ALIGNED((unsigned long) skb->data, 4)) + skb->data = PTR_ALIGN(skb->data - 4, 4); + set_htc_rxpkt_info(packet, skb, skb->data, + ATH6KL_BUFFER_SIZE, endpoint); + list_add_tail(&packet->list, &queue); + } + + if (!list_empty(&queue)) + ath6kl_htc_add_rxbuf_multiple(ar->htc_target, &queue); +} + +void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count) +{ + struct htc_packet *packet; + struct sk_buff *skb; + + while (count) { + skb = ath6kl_buf_alloc(ATH6KL_AMSDU_BUFFER_SIZE); + if (!skb) + return; + + packet = (struct htc_packet *) skb->head; + if (!IS_ALIGNED((unsigned long) skb->data, 4)) + skb->data = PTR_ALIGN(skb->data - 4, 4); + set_htc_rxpkt_info(packet, skb, skb->data, + ATH6KL_AMSDU_BUFFER_SIZE, 0); + spin_lock_bh(&ar->lock); + list_add_tail(&packet->list, &ar->amsdu_rx_buffer_queue); + spin_unlock_bh(&ar->lock); + count--; + } +} + +/* + * Callback to allocate a receive buffer for a pending packet. We use a + * pre-allocated list of buffers of maximum AMSDU size (4K). + */ +struct htc_packet *ath6kl_alloc_amsdu_rxbuf(struct htc_target *target, + enum htc_endpoint_id endpoint, + int len) +{ + struct ath6kl *ar = target->dev->ar; + struct htc_packet *packet = NULL; + struct list_head *pkt_pos; + int refill_cnt = 0, depth = 0; + + ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: eid=%d, len:%d\n", + __func__, endpoint, len); + + if ((len <= ATH6KL_BUFFER_SIZE) || + (len > ATH6KL_AMSDU_BUFFER_SIZE)) + return NULL; + + spin_lock_bh(&ar->lock); + + if (list_empty(&ar->amsdu_rx_buffer_queue)) { + spin_unlock_bh(&ar->lock); + refill_cnt = ATH6KL_MAX_AMSDU_RX_BUFFERS; + goto refill_buf; + } + + packet = list_first_entry(&ar->amsdu_rx_buffer_queue, + struct htc_packet, list); + list_del(&packet->list); + list_for_each(pkt_pos, &ar->amsdu_rx_buffer_queue) + depth++; + + refill_cnt = ATH6KL_MAX_AMSDU_RX_BUFFERS - depth; + spin_unlock_bh(&ar->lock); + + /* set actual endpoint ID */ + packet->endpoint = endpoint; + +refill_buf: + if (refill_cnt >= ATH6KL_AMSDU_REFILL_THRESHOLD) + ath6kl_refill_amsdu_rxbufs(ar, refill_cnt); + + return packet; +} + +static void aggr_slice_amsdu(struct aggr_info *p_aggr, + struct rxtid *rxtid, struct sk_buff *skb) +{ + struct sk_buff *new_skb; + struct ethhdr *hdr; + u16 frame_8023_len, payload_8023_len, mac_hdr_len, amsdu_len; + u8 *framep; + + mac_hdr_len = sizeof(struct ethhdr); + framep = skb->data + mac_hdr_len; + amsdu_len = skb->len - mac_hdr_len; + + while (amsdu_len > mac_hdr_len) { + hdr = (struct ethhdr *) framep; + payload_8023_len = ntohs(hdr->h_proto); + + if (payload_8023_len < MIN_MSDU_SUBFRAME_PAYLOAD_LEN || + payload_8023_len > MAX_MSDU_SUBFRAME_PAYLOAD_LEN) { + ath6kl_err("802.3 AMSDU frame bound check failed. len %d\n", + payload_8023_len); + break; + } + + frame_8023_len = payload_8023_len + mac_hdr_len; + new_skb = aggr_get_free_skb(p_aggr); + if (!new_skb) { + ath6kl_err("no buffer available\n"); + break; + } + + memcpy(new_skb->data, framep, frame_8023_len); + skb_put(new_skb, frame_8023_len); + if (ath6kl_wmi_dot3_2_dix(new_skb)) { + ath6kl_err("dot3_2_dix error\n"); + dev_kfree_skb(new_skb); + break; + } + + skb_queue_tail(&rxtid->q, new_skb); + + /* Is this the last subframe within this aggregate ? */ + if ((amsdu_len - frame_8023_len) == 0) + break; + + /* Add the length of A-MSDU subframe padding bytes - + * Round to nearest word. + */ + frame_8023_len = ALIGN(frame_8023_len, 4); + + framep += frame_8023_len; + amsdu_len -= frame_8023_len; + } + + dev_kfree_skb(skb); +} + +static void aggr_deque_frms(struct aggr_info *p_aggr, u8 tid, + u16 seq_no, u8 order) +{ + struct sk_buff *skb; + struct rxtid *rxtid; + struct skb_hold_q *node; + u16 idx, idx_end, seq_end; + struct rxtid_stats *stats; + + if (!p_aggr) + return; + + rxtid = &p_aggr->rx_tid[tid]; + stats = &p_aggr->stat[tid]; + + idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); + + /* + * idx_end is typically the last possible frame in the window, + * but changes to 'the' seq_no, when BAR comes. If seq_no + * is non-zero, we will go up to that and stop. + * Note: last seq no in current window will occupy the same + * index position as index that is just previous to start. + * An imp point : if win_sz is 7, for seq_no space of 4095, + * then, there would be holes when sequence wrap around occurs. + * Target should judiciously choose the win_sz, based on + * this condition. For 4095, (TID_WINDOW_SZ = 2 x win_sz + * 2, 4, 8, 16 win_sz works fine). + * We must deque from "idx" to "idx_end", including both. + */ + seq_end = seq_no ? seq_no : rxtid->seq_next; + idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz); + + spin_lock_bh(&rxtid->lock); + + do { + node = &rxtid->hold_q[idx]; + if ((order == 1) && (!node->skb)) + break; + + if (node->skb) { + if (node->is_amsdu) + aggr_slice_amsdu(p_aggr, rxtid, node->skb); + else + skb_queue_tail(&rxtid->q, node->skb); + node->skb = NULL; + } else + stats->num_hole++; + + rxtid->seq_next = ATH6KL_NEXT_SEQ_NO(rxtid->seq_next); + idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); + } while (idx != idx_end); + + spin_unlock_bh(&rxtid->lock); + + stats->num_delivered += skb_queue_len(&rxtid->q); + + while ((skb = skb_dequeue(&rxtid->q))) + ath6kl_deliver_frames_to_nw_stack(p_aggr->dev, skb); +} + +static bool aggr_process_recv_frm(struct aggr_info *agg_info, u8 tid, + u16 seq_no, + bool is_amsdu, struct sk_buff *frame) +{ + struct rxtid *rxtid; + struct rxtid_stats *stats; + struct sk_buff *skb; + struct skb_hold_q *node; + u16 idx, st, cur, end; + bool is_queued = false; + u16 extended_end; + + rxtid = &agg_info->rx_tid[tid]; + stats = &agg_info->stat[tid]; + + stats->num_into_aggr++; + + if (!rxtid->aggr) { + if (is_amsdu) { + aggr_slice_amsdu(agg_info, rxtid, frame); + is_queued = true; + stats->num_amsdu++; + while ((skb = skb_dequeue(&rxtid->q))) + ath6kl_deliver_frames_to_nw_stack(agg_info->dev, + skb); + } + return is_queued; + } + + /* Check the incoming sequence no, if it's in the window */ + st = rxtid->seq_next; + cur = seq_no; + end = (st + rxtid->hold_q_sz-1) & ATH6KL_MAX_SEQ_NO; + + if (((st < end) && (cur < st || cur > end)) || + ((st > end) && (cur > end) && (cur < st))) { + extended_end = (end + rxtid->hold_q_sz - 1) & + ATH6KL_MAX_SEQ_NO; + + if (((end < extended_end) && + (cur < end || cur > extended_end)) || + ((end > extended_end) && (cur > extended_end) && + (cur < end))) { + aggr_deque_frms(agg_info, tid, 0, 0); + if (cur >= rxtid->hold_q_sz - 1) + rxtid->seq_next = cur - (rxtid->hold_q_sz - 1); + else + rxtid->seq_next = ATH6KL_MAX_SEQ_NO - + (rxtid->hold_q_sz - 2 - cur); + } else { + /* + * Dequeue only those frames that are outside the + * new shifted window. + */ + if (cur >= rxtid->hold_q_sz - 1) + st = cur - (rxtid->hold_q_sz - 1); + else + st = ATH6KL_MAX_SEQ_NO - + (rxtid->hold_q_sz - 2 - cur); + + aggr_deque_frms(agg_info, tid, st, 0); + } + + stats->num_oow++; + } + + idx = AGGR_WIN_IDX(seq_no, rxtid->hold_q_sz); + + node = &rxtid->hold_q[idx]; + + spin_lock_bh(&rxtid->lock); + + /* + * Is the cur frame duplicate or something beyond our window(hold_q + * -> which is 2x, already)? + * + * 1. Duplicate is easy - drop incoming frame. + * 2. Not falling in current sliding window. + * 2a. is the frame_seq_no preceding current tid_seq_no? + * -> drop the frame. perhaps sender did not get our ACK. + * this is taken care of above. + * 2b. is the frame_seq_no beyond window(st, TID_WINDOW_SZ); + * -> Taken care of it above, by moving window forward. + */ + dev_kfree_skb(node->skb); + stats->num_dups++; + + node->skb = frame; + is_queued = true; + node->is_amsdu = is_amsdu; + node->seq_no = seq_no; + + if (node->is_amsdu) + stats->num_amsdu++; + else + stats->num_mpdu++; + + spin_unlock_bh(&rxtid->lock); + + aggr_deque_frms(agg_info, tid, 0, 1); + + if (agg_info->timer_scheduled) + rxtid->progress = true; + else + for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { + if (rxtid->hold_q[idx].skb) { + /* + * There is a frame in the queue and no + * timer so start a timer to ensure that + * the frame doesn't remain stuck + * forever. + */ + agg_info->timer_scheduled = true; + mod_timer(&agg_info->timer, + (jiffies + + HZ * (AGGR_RX_TIMEOUT) / 1000)); + rxtid->progress = false; + rxtid->timer_mon = true; + break; + } + } + + return is_queued; +} + +void ath6kl_rx(struct htc_target *target, struct htc_packet *packet) +{ + struct ath6kl *ar = target->dev->ar; + struct sk_buff *skb = packet->pkt_cntxt; + struct wmi_rx_meta_v2 *meta; + struct wmi_data_hdr *dhdr; + int min_hdr_len; + u8 meta_type, dot11_hdr = 0; + int status = packet->status; + enum htc_endpoint_id ept = packet->endpoint; + bool is_amsdu, prev_ps, ps_state = false; + struct ath6kl_sta *conn = NULL; + struct sk_buff *skb1 = NULL; + struct ethhdr *datap = NULL; + u16 seq_no, offset; + u8 tid; + + ath6kl_dbg(ATH6KL_DBG_WLAN_RX, + "%s: ar=0x%p eid=%d, skb=0x%p, data=0x%p, len=0x%x status:%d", + __func__, ar, ept, skb, packet->buf, + packet->act_len, status); + + if (status || !(skb->data + HTC_HDR_LENGTH)) { + ar->net_stats.rx_errors++; + dev_kfree_skb(skb); + return; + } + + /* + * Take lock to protect buffer counts and adaptive power throughput + * state. + */ + spin_lock_bh(&ar->lock); + + ar->net_stats.rx_packets++; + ar->net_stats.rx_bytes += packet->act_len; + + spin_unlock_bh(&ar->lock); + + skb_put(skb, packet->act_len + HTC_HDR_LENGTH); + skb_pull(skb, HTC_HDR_LENGTH); + + ath6kl_dbg_dump(ATH6KL_DBG_RAW_BYTES, __func__, "rx ", + skb->data, skb->len); + + skb->dev = ar->net_dev; + + if (!test_bit(WMI_ENABLED, &ar->flag)) { + if (EPPING_ALIGNMENT_PAD > 0) + skb_pull(skb, EPPING_ALIGNMENT_PAD); + ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb); + return; + } + + if (ept == ar->ctrl_ep) { + ath6kl_wmi_control_rx(ar->wmi, skb); + return; + } + + min_hdr_len = sizeof(struct ethhdr) + sizeof(struct wmi_data_hdr) + + sizeof(struct ath6kl_llc_snap_hdr); + + dhdr = (struct wmi_data_hdr *) skb->data; + + /* + * In the case of AP mode we may receive NULL data frames + * that do not have LLC hdr. They are 16 bytes in size. + * Allow these frames in the AP mode. + */ + if (ar->nw_type != AP_NETWORK && + ((packet->act_len < min_hdr_len) || + (packet->act_len > WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH))) { + ath6kl_info("frame len is too short or too long\n"); + ar->net_stats.rx_errors++; + ar->net_stats.rx_length_errors++; + dev_kfree_skb(skb); + return; + } + + /* Get the Power save state of the STA */ + if (ar->nw_type == AP_NETWORK) { + meta_type = wmi_data_hdr_get_meta(dhdr); + + ps_state = !!((dhdr->info >> WMI_DATA_HDR_PS_SHIFT) & + WMI_DATA_HDR_PS_MASK); + + offset = sizeof(struct wmi_data_hdr); + + switch (meta_type) { + case 0: + break; + case WMI_META_VERSION_1: + offset += sizeof(struct wmi_rx_meta_v1); + break; + case WMI_META_VERSION_2: + offset += sizeof(struct wmi_rx_meta_v2); + break; + default: + break; + } + + datap = (struct ethhdr *) (skb->data + offset); + conn = ath6kl_find_sta(ar, datap->h_source); + + if (!conn) { + dev_kfree_skb(skb); + return; + } + + /* + * If there is a change in PS state of the STA, + * take appropriate steps: + * + * 1. If Sleep-->Awake, flush the psq for the STA + * Clear the PVB for the STA. + * 2. If Awake-->Sleep, Starting queueing frames + * the STA. + */ + prev_ps = !!(conn->sta_flags & STA_PS_SLEEP); + + if (ps_state) + conn->sta_flags |= STA_PS_SLEEP; + else + conn->sta_flags &= ~STA_PS_SLEEP; + + if (prev_ps ^ !!(conn->sta_flags & STA_PS_SLEEP)) { + if (!(conn->sta_flags & STA_PS_SLEEP)) { + struct sk_buff *skbuff = NULL; + + spin_lock_bh(&conn->psq_lock); + while ((skbuff = skb_dequeue(&conn->psq)) + != NULL) { + spin_unlock_bh(&conn->psq_lock); + ath6kl_data_tx(skbuff, ar->net_dev); + spin_lock_bh(&conn->psq_lock); + } + spin_unlock_bh(&conn->psq_lock); + /* Clear the PVB for this STA */ + ath6kl_wmi_set_pvb_cmd(ar->wmi, conn->aid, 0); + } + } + + /* drop NULL data frames here */ + if ((packet->act_len < min_hdr_len) || + (packet->act_len > + WMI_MAX_AMSDU_RX_DATA_FRAME_LENGTH)) { + dev_kfree_skb(skb); + return; + } + } + + is_amsdu = wmi_data_hdr_is_amsdu(dhdr) ? true : false; + tid = wmi_data_hdr_get_up(dhdr); + seq_no = wmi_data_hdr_get_seqno(dhdr); + meta_type = wmi_data_hdr_get_meta(dhdr); + dot11_hdr = wmi_data_hdr_get_dot11(dhdr); + skb_pull(skb, sizeof(struct wmi_data_hdr)); + + switch (meta_type) { + case WMI_META_VERSION_1: + skb_pull(skb, sizeof(struct wmi_rx_meta_v1)); + break; + case WMI_META_VERSION_2: + meta = (struct wmi_rx_meta_v2 *) skb->data; + if (meta->csum_flags & 0x1) { + skb->ip_summed = CHECKSUM_COMPLETE; + skb->csum = (__force __wsum) meta->csum; + } + skb_pull(skb, sizeof(struct wmi_rx_meta_v2)); + break; + default: + break; + } + + if (dot11_hdr) + status = ath6kl_wmi_dot11_hdr_remove(ar->wmi, skb); + else if (!is_amsdu) + status = ath6kl_wmi_dot3_2_dix(skb); + + if (status) { + /* + * Drop frames that could not be processed (lack of + * memory, etc.) + */ + dev_kfree_skb(skb); + return; + } + + if (!(ar->net_dev->flags & IFF_UP)) { + dev_kfree_skb(skb); + return; + } + + if (ar->nw_type == AP_NETWORK) { + datap = (struct ethhdr *) skb->data; + if (is_multicast_ether_addr(datap->h_dest)) + /* + * Bcast/Mcast frames should be sent to the + * OS stack as well as on the air. + */ + skb1 = skb_copy(skb, GFP_ATOMIC); + else { + /* + * Search for a connected STA with dstMac + * as the Mac address. If found send the + * frame to it on the air else send the + * frame up the stack. + */ + struct ath6kl_sta *conn = NULL; + conn = ath6kl_find_sta(ar, datap->h_dest); + + if (conn && ar->intra_bss) { + skb1 = skb; + skb = NULL; + } else if (conn && !ar->intra_bss) { + dev_kfree_skb(skb); + skb = NULL; + } + } + if (skb1) + ath6kl_data_tx(skb1, ar->net_dev); + } + + datap = (struct ethhdr *) skb->data; + + if (is_unicast_ether_addr(datap->h_dest) && + aggr_process_recv_frm(ar->aggr_cntxt, tid, seq_no, + is_amsdu, skb)) + /* aggregation code will handle the skb */ + return; + + ath6kl_deliver_frames_to_nw_stack(ar->net_dev, skb); +} + +static void aggr_timeout(unsigned long arg) +{ + u8 i, j; + struct aggr_info *p_aggr = (struct aggr_info *) arg; + struct rxtid *rxtid; + struct rxtid_stats *stats; + + for (i = 0; i < NUM_OF_TIDS; i++) { + rxtid = &p_aggr->rx_tid[i]; + stats = &p_aggr->stat[i]; + + if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) + continue; + + stats->num_timeouts++; + ath6kl_dbg(ATH6KL_DBG_AGGR, + "aggr timeout (st %d end %d)\n", + rxtid->seq_next, + ((rxtid->seq_next + rxtid->hold_q_sz-1) & + ATH6KL_MAX_SEQ_NO)); + aggr_deque_frms(p_aggr, i, 0, 0); + } + + p_aggr->timer_scheduled = false; + + for (i = 0; i < NUM_OF_TIDS; i++) { + rxtid = &p_aggr->rx_tid[i]; + + if (rxtid->aggr && rxtid->hold_q) { + for (j = 0; j < rxtid->hold_q_sz; j++) { + if (rxtid->hold_q[j].skb) { + p_aggr->timer_scheduled = true; + rxtid->timer_mon = true; + rxtid->progress = false; + break; + } + } + + if (j >= rxtid->hold_q_sz) + rxtid->timer_mon = false; + } + } + + if (p_aggr->timer_scheduled) + mod_timer(&p_aggr->timer, + jiffies + msecs_to_jiffies(AGGR_RX_TIMEOUT)); +} + +static void aggr_delete_tid_state(struct aggr_info *p_aggr, u8 tid) +{ + struct rxtid *rxtid; + struct rxtid_stats *stats; + + if (!p_aggr || tid >= NUM_OF_TIDS) + return; + + rxtid = &p_aggr->rx_tid[tid]; + stats = &p_aggr->stat[tid]; + + if (rxtid->aggr) + aggr_deque_frms(p_aggr, tid, 0, 0); + + rxtid->aggr = false; + rxtid->progress = false; + rxtid->timer_mon = false; + rxtid->win_sz = 0; + rxtid->seq_next = 0; + rxtid->hold_q_sz = 0; + + kfree(rxtid->hold_q); + rxtid->hold_q = NULL; + + memset(stats, 0, sizeof(struct rxtid_stats)); +} + +void aggr_recv_addba_req_evt(struct ath6kl *ar, u8 tid, u16 seq_no, u8 win_sz) +{ + struct aggr_info *p_aggr = ar->aggr_cntxt; + struct rxtid *rxtid; + struct rxtid_stats *stats; + u16 hold_q_size; + + if (!p_aggr) + return; + + rxtid = &p_aggr->rx_tid[tid]; + stats = &p_aggr->stat[tid]; + + if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) + ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n", + __func__, win_sz, tid); + + if (rxtid->aggr) + aggr_delete_tid_state(p_aggr, tid); + + rxtid->seq_next = seq_no; + hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q); + rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL); + if (!rxtid->hold_q) + return; + + rxtid->win_sz = win_sz; + rxtid->hold_q_sz = TID_WINDOW_SZ(win_sz); + if (!skb_queue_empty(&rxtid->q)) + return; + + rxtid->aggr = true; +} + +struct aggr_info *aggr_init(struct net_device *dev) +{ + struct aggr_info *p_aggr = NULL; + struct rxtid *rxtid; + u8 i; + + p_aggr = kzalloc(sizeof(struct aggr_info), GFP_KERNEL); + if (!p_aggr) { + ath6kl_err("failed to alloc memory for aggr_node\n"); + return NULL; + } + + p_aggr->aggr_sz = AGGR_SZ_DEFAULT; + p_aggr->dev = dev; + init_timer(&p_aggr->timer); + p_aggr->timer.function = aggr_timeout; + p_aggr->timer.data = (unsigned long) p_aggr; + + p_aggr->timer_scheduled = false; + skb_queue_head_init(&p_aggr->free_q); + + ath6kl_alloc_netbufs(&p_aggr->free_q, AGGR_NUM_OF_FREE_NETBUFS); + + for (i = 0; i < NUM_OF_TIDS; i++) { + rxtid = &p_aggr->rx_tid[i]; + rxtid->aggr = false; + rxtid->progress = false; + rxtid->timer_mon = false; + skb_queue_head_init(&rxtid->q); + spin_lock_init(&rxtid->lock); + } + + return p_aggr; +} + +void aggr_recv_delba_req_evt(struct ath6kl *ar, u8 tid) +{ + struct aggr_info *p_aggr = ar->aggr_cntxt; + struct rxtid *rxtid; + + if (!p_aggr) + return; + + rxtid = &p_aggr->rx_tid[tid]; + + if (rxtid->aggr) + aggr_delete_tid_state(p_aggr, tid); +} + +void aggr_reset_state(struct aggr_info *aggr_info) +{ + u8 tid; + + for (tid = 0; tid < NUM_OF_TIDS; tid++) + aggr_delete_tid_state(aggr_info, tid); +} + +/* clean up our amsdu buffer list */ +void ath6kl_cleanup_amsdu_rxbufs(struct ath6kl *ar) +{ + struct htc_packet *packet, *tmp_pkt; + + spin_lock_bh(&ar->lock); + if (list_empty(&ar->amsdu_rx_buffer_queue)) { + spin_unlock_bh(&ar->lock); + return; + } + + list_for_each_entry_safe(packet, tmp_pkt, &ar->amsdu_rx_buffer_queue, + list) { + list_del(&packet->list); + spin_unlock_bh(&ar->lock); + dev_kfree_skb(packet->pkt_cntxt); + spin_lock_bh(&ar->lock); + } + + spin_unlock_bh(&ar->lock); +} + +void aggr_module_destroy(struct aggr_info *aggr_info) +{ + struct rxtid *rxtid; + u8 i, k; + + if (!aggr_info) + return; + + if (aggr_info->timer_scheduled) { + del_timer(&aggr_info->timer); + aggr_info->timer_scheduled = false; + } + + for (i = 0; i < NUM_OF_TIDS; i++) { + rxtid = &aggr_info->rx_tid[i]; + if (rxtid->hold_q) { + for (k = 0; k < rxtid->hold_q_sz; k++) + dev_kfree_skb(rxtid->hold_q[k].skb); + kfree(rxtid->hold_q); + } + + skb_queue_purge(&rxtid->q); + } + + skb_queue_purge(&aggr_info->free_q); + kfree(aggr_info); +} diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c new file mode 100644 index 000000000000..a7de23cbd2c7 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -0,0 +1,3127 @@ +/* + * 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/ip.h> +#include "core.h" +#include "debug.h" +#include "testmode.h" +#include "../regd.h" +#include "../regd_common.h" + +static int ath6kl_wmi_sync_point(struct wmi *wmi); + +static const s32 wmi_rate_tbl[][2] = { + /* {W/O SGI, with SGI} */ + {1000, 1000}, + {2000, 2000}, + {5500, 5500}, + {11000, 11000}, + {6000, 6000}, + {9000, 9000}, + {12000, 12000}, + {18000, 18000}, + {24000, 24000}, + {36000, 36000}, + {48000, 48000}, + {54000, 54000}, + {6500, 7200}, + {13000, 14400}, + {19500, 21700}, + {26000, 28900}, + {39000, 43300}, + {52000, 57800}, + {58500, 65000}, + {65000, 72200}, + {13500, 15000}, + {27000, 30000}, + {40500, 45000}, + {54000, 60000}, + {81000, 90000}, + {108000, 120000}, + {121500, 135000}, + {135000, 150000}, + {0, 0} +}; + +/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */ +static const u8 up_to_ac[] = { + WMM_AC_BE, + WMM_AC_BK, + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VI, + WMM_AC_VO, + WMM_AC_VO, +}; + +void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id) +{ + if (WARN_ON(ep_id == ENDPOINT_UNUSED || ep_id >= ENDPOINT_MAX)) + return; + + wmi->ep_id = ep_id; +} + +enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi) +{ + return wmi->ep_id; +} + +/* Performs DIX to 802.3 encapsulation for transmit packets. + * Assumes the entire DIX header is contigous and that there is + * enough room in the buffer for a 802.3 mac header and LLC+SNAP headers. + */ +int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb) +{ + struct ath6kl_llc_snap_hdr *llc_hdr; + struct ethhdr *eth_hdr; + size_t new_len; + __be16 type; + u8 *datap; + u16 size; + + if (WARN_ON(skb == NULL)) + return -EINVAL; + + size = sizeof(struct ath6kl_llc_snap_hdr) + sizeof(struct wmi_data_hdr); + if (skb_headroom(skb) < size) + return -ENOMEM; + + eth_hdr = (struct ethhdr *) skb->data; + type = eth_hdr->h_proto; + + if (!is_ethertype(be16_to_cpu(type))) { + ath6kl_dbg(ATH6KL_DBG_WMI, + "%s: pkt is already in 802.3 format\n", __func__); + return 0; + } + + new_len = skb->len - sizeof(*eth_hdr) + sizeof(*llc_hdr); + + skb_push(skb, sizeof(struct ath6kl_llc_snap_hdr)); + datap = skb->data; + + eth_hdr->h_proto = cpu_to_be16(new_len); + + memcpy(datap, eth_hdr, sizeof(*eth_hdr)); + + llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + sizeof(*eth_hdr)); + llc_hdr->dsap = 0xAA; + llc_hdr->ssap = 0xAA; + llc_hdr->cntl = 0x03; + llc_hdr->org_code[0] = 0x0; + llc_hdr->org_code[1] = 0x0; + llc_hdr->org_code[2] = 0x0; + llc_hdr->eth_type = type; + + return 0; +} + +static int ath6kl_wmi_meta_add(struct wmi *wmi, struct sk_buff *skb, + u8 *version, void *tx_meta_info) +{ + struct wmi_tx_meta_v1 *v1; + struct wmi_tx_meta_v2 *v2; + + if (WARN_ON(skb == NULL || version == NULL)) + return -EINVAL; + + switch (*version) { + case WMI_META_VERSION_1: + skb_push(skb, WMI_MAX_TX_META_SZ); + v1 = (struct wmi_tx_meta_v1 *) skb->data; + v1->pkt_id = 0; + v1->rate_plcy_id = 0; + *version = WMI_META_VERSION_1; + break; + case WMI_META_VERSION_2: + skb_push(skb, WMI_MAX_TX_META_SZ); + v2 = (struct wmi_tx_meta_v2 *) skb->data; + memcpy(v2, (struct wmi_tx_meta_v2 *) tx_meta_info, + sizeof(struct wmi_tx_meta_v2)); + break; + } + + return 0; +} + +int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, + u8 msg_type, bool more_data, + enum wmi_data_hdr_data_type data_type, + u8 meta_ver, void *tx_meta_info) +{ + struct wmi_data_hdr *data_hdr; + int ret; + + if (WARN_ON(skb == NULL)) + return -EINVAL; + + if (tx_meta_info) { + ret = ath6kl_wmi_meta_add(wmi, skb, &meta_ver, tx_meta_info); + if (ret) + return ret; + } + + skb_push(skb, sizeof(struct wmi_data_hdr)); + + data_hdr = (struct wmi_data_hdr *)skb->data; + memset(data_hdr, 0, sizeof(struct wmi_data_hdr)); + + data_hdr->info = msg_type << WMI_DATA_HDR_MSG_TYPE_SHIFT; + data_hdr->info |= data_type << WMI_DATA_HDR_DATA_TYPE_SHIFT; + + if (more_data) + data_hdr->info |= + WMI_DATA_HDR_MORE_MASK << WMI_DATA_HDR_MORE_SHIFT; + + data_hdr->info2 = cpu_to_le16(meta_ver << WMI_DATA_HDR_META_SHIFT); + data_hdr->info3 = 0; + + return 0; +} + +static u8 ath6kl_wmi_determine_user_priority(u8 *pkt, u32 layer2_pri) +{ + struct iphdr *ip_hdr = (struct iphdr *) pkt; + u8 ip_pri; + + /* + * Determine IPTOS priority + * + * IP-TOS - 8bits + * : DSCP(6-bits) ECN(2-bits) + * : DSCP - P2 P1 P0 X X X + * where (P2 P1 P0) form 802.1D + */ + ip_pri = ip_hdr->tos >> 5; + ip_pri &= 0x7; + + if ((layer2_pri & 0x7) > ip_pri) + return (u8) layer2_pri & 0x7; + else + return ip_pri; +} + +int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb, + u32 layer2_priority, bool wmm_enabled, + u8 *ac) +{ + struct wmi_data_hdr *data_hdr; + struct ath6kl_llc_snap_hdr *llc_hdr; + struct wmi_create_pstream_cmd cmd; + u32 meta_size, hdr_size; + u16 ip_type = IP_ETHERTYPE; + u8 stream_exist, usr_pri; + u8 traffic_class = WMM_AC_BE; + u8 *datap; + + if (WARN_ON(skb == NULL)) + return -EINVAL; + + datap = skb->data; + data_hdr = (struct wmi_data_hdr *) datap; + + meta_size = ((le16_to_cpu(data_hdr->info2) >> WMI_DATA_HDR_META_SHIFT) & + WMI_DATA_HDR_META_MASK) ? WMI_MAX_TX_META_SZ : 0; + + if (!wmm_enabled) { + /* If WMM is disabled all traffic goes as BE traffic */ + usr_pri = 0; + } else { + hdr_size = sizeof(struct ethhdr); + + llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap + + sizeof(struct + wmi_data_hdr) + + meta_size + hdr_size); + + if (llc_hdr->eth_type == htons(ip_type)) { + /* + * Extract the endpoint info from the TOS field + * in the IP header. + */ + usr_pri = + ath6kl_wmi_determine_user_priority(((u8 *) llc_hdr) + + sizeof(struct ath6kl_llc_snap_hdr), + layer2_priority); + } else + usr_pri = layer2_priority & 0x7; + } + + /* workaround for WMM S5 */ + if ((wmi->traffic_class == WMM_AC_VI) && + ((usr_pri == 5) || (usr_pri == 4))) + usr_pri = 1; + + /* Convert user priority to traffic class */ + traffic_class = up_to_ac[usr_pri & 0x7]; + + wmi_data_hdr_set_up(data_hdr, usr_pri); + + spin_lock_bh(&wmi->lock); + stream_exist = wmi->fat_pipe_exist; + spin_unlock_bh(&wmi->lock); + + if (!(stream_exist & (1 << traffic_class))) { + memset(&cmd, 0, sizeof(cmd)); + cmd.traffic_class = traffic_class; + cmd.user_pri = usr_pri; + cmd.inactivity_int = + cpu_to_le32(WMI_IMPLICIT_PSTREAM_INACTIVITY_INT); + /* Implicit streams are created with TSID 0xFF */ + cmd.tsid = WMI_IMPLICIT_PSTREAM; + ath6kl_wmi_create_pstream_cmd(wmi, &cmd); + } + + *ac = traffic_class; + + return 0; +} + +int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb) +{ + struct ieee80211_hdr_3addr *pwh, wh; + struct ath6kl_llc_snap_hdr *llc_hdr; + struct ethhdr eth_hdr; + u32 hdr_size; + u8 *datap; + __le16 sub_type; + + if (WARN_ON(skb == NULL)) + return -EINVAL; + + datap = skb->data; + pwh = (struct ieee80211_hdr_3addr *) datap; + + sub_type = pwh->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE); + + memcpy((u8 *) &wh, datap, sizeof(struct ieee80211_hdr_3addr)); + + /* Strip off the 802.11 header */ + if (sub_type == cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { + hdr_size = roundup(sizeof(struct ieee80211_qos_hdr), + sizeof(u32)); + skb_pull(skb, hdr_size); + } else if (sub_type == cpu_to_le16(IEEE80211_STYPE_DATA)) + skb_pull(skb, sizeof(struct ieee80211_hdr_3addr)); + + datap = skb->data; + llc_hdr = (struct ath6kl_llc_snap_hdr *)(datap); + + memset(ð_hdr, 0, sizeof(eth_hdr)); + eth_hdr.h_proto = llc_hdr->eth_type; + + switch ((le16_to_cpu(wh.frame_control)) & + (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { + case 0: + memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN); + memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN); + break; + case IEEE80211_FCTL_TODS: + memcpy(eth_hdr.h_dest, wh.addr3, ETH_ALEN); + memcpy(eth_hdr.h_source, wh.addr2, ETH_ALEN); + break; + case IEEE80211_FCTL_FROMDS: + memcpy(eth_hdr.h_dest, wh.addr1, ETH_ALEN); + memcpy(eth_hdr.h_source, wh.addr3, ETH_ALEN); + break; + case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: + break; + } + + skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr)); + skb_push(skb, sizeof(eth_hdr)); + + datap = skb->data; + + memcpy(datap, ð_hdr, sizeof(eth_hdr)); + + return 0; +} + +/* + * Performs 802.3 to DIX encapsulation for received packets. + * Assumes the entire 802.3 header is contigous. + */ +int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb) +{ + struct ath6kl_llc_snap_hdr *llc_hdr; + struct ethhdr eth_hdr; + u8 *datap; + + if (WARN_ON(skb == NULL)) + return -EINVAL; + + datap = skb->data; + + memcpy(ð_hdr, datap, sizeof(eth_hdr)); + + llc_hdr = (struct ath6kl_llc_snap_hdr *) (datap + sizeof(eth_hdr)); + eth_hdr.h_proto = llc_hdr->eth_type; + + skb_pull(skb, sizeof(struct ath6kl_llc_snap_hdr)); + datap = skb->data; + + memcpy(datap, ð_hdr, sizeof(eth_hdr)); + + return 0; +} + +static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len) +{ + struct tx_complete_msg_v1 *msg_v1; + struct wmi_tx_complete_event *evt; + int index; + u16 size; + + evt = (struct wmi_tx_complete_event *) datap; + + ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n", + evt->num_msg, evt->msg_len, evt->msg_type); + + if (!AR_DBG_LVL_CHECK(ATH6KL_DBG_WMI)) + return 0; + + for (index = 0; index < evt->num_msg; index++) { + size = sizeof(struct wmi_tx_complete_event) + + (index * sizeof(struct tx_complete_msg_v1)); + msg_v1 = (struct tx_complete_msg_v1 *)(datap + size); + + ath6kl_dbg(ATH6KL_DBG_WMI, "msg: %d %d %d %d\n", + msg_v1->status, msg_v1->pkt_id, + msg_v1->rate_idx, msg_v1->ack_failures); + } + + return 0; +} + +static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmi_remain_on_chnl_event *ev; + u32 freq; + u32 dur; + struct ieee80211_channel *chan; + struct ath6kl *ar = wmi->parent_dev; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_remain_on_chnl_event *) datap; + freq = le32_to_cpu(ev->freq); + dur = le32_to_cpu(ev->duration); + ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: freq=%u dur=%u\n", + freq, dur); + chan = ieee80211_get_channel(ar->wdev->wiphy, freq); + if (!chan) { + ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel " + "(freq=%u)\n", freq); + return -EINVAL; + } + cfg80211_ready_on_channel(ar->net_dev, 1, chan, NL80211_CHAN_NO_HT, + dur, GFP_ATOMIC); + + return 0; +} + +static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, + u8 *datap, int len) +{ + struct wmi_cancel_remain_on_chnl_event *ev; + u32 freq; + u32 dur; + struct ieee80211_channel *chan; + struct ath6kl *ar = wmi->parent_dev; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_cancel_remain_on_chnl_event *) datap; + freq = le32_to_cpu(ev->freq); + dur = le32_to_cpu(ev->duration); + ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u " + "status=%u\n", freq, dur, ev->status); + chan = ieee80211_get_channel(ar->wdev->wiphy, freq); + if (!chan) { + ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown " + "channel (freq=%u)\n", freq); + return -EINVAL; + } + cfg80211_remain_on_channel_expired(ar->net_dev, 1, chan, + NL80211_CHAN_NO_HT, GFP_ATOMIC); + + return 0; +} + +static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_tx_status_event *ev; + u32 id; + struct ath6kl *ar = wmi->parent_dev; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_tx_status_event *) datap; + id = le32_to_cpu(ev->id); + ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n", + id, ev->ack_status); + if (wmi->last_mgmt_tx_frame) { + cfg80211_mgmt_tx_status(ar->net_dev, id, + wmi->last_mgmt_tx_frame, + wmi->last_mgmt_tx_frame_len, + !!ev->ack_status, GFP_ATOMIC); + kfree(wmi->last_mgmt_tx_frame); + wmi->last_mgmt_tx_frame = NULL; + wmi->last_mgmt_tx_frame_len = 0; + } + + return 0; +} + +static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_p2p_rx_probe_req_event *ev; + u32 freq; + u16 dlen; + struct ath6kl *ar = wmi->parent_dev; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_p2p_rx_probe_req_event *) datap; + freq = le32_to_cpu(ev->freq); + dlen = le16_to_cpu(ev->len); + if (datap + len < ev->data + dlen) { + ath6kl_err("invalid wmi_p2p_rx_probe_req_event: " + "len=%d dlen=%u\n", len, dlen); + return -EINVAL; + } + ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u " + "probe_req_report=%d\n", + dlen, freq, ar->probe_req_report); + + if (ar->probe_req_report || ar->nw_type == AP_NETWORK) + cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC); + + return 0; +} + +static int ath6kl_wmi_p2p_capabilities_event_rx(u8 *datap, int len) +{ + struct wmi_p2p_capabilities_event *ev; + u16 dlen; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_p2p_capabilities_event *) datap; + dlen = le16_to_cpu(ev->len); + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_capab: len=%u\n", dlen); + + return 0; +} + +static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_rx_action_event *ev; + u32 freq; + u16 dlen; + struct ath6kl *ar = wmi->parent_dev; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_rx_action_event *) datap; + freq = le32_to_cpu(ev->freq); + dlen = le16_to_cpu(ev->len); + if (datap + len < ev->data + dlen) { + ath6kl_err("invalid wmi_rx_action_event: " + "len=%d dlen=%u\n", len, dlen); + return -EINVAL; + } + ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); + cfg80211_rx_mgmt(ar->net_dev, freq, ev->data, dlen, GFP_ATOMIC); + + return 0; +} + +static int ath6kl_wmi_p2p_info_event_rx(u8 *datap, int len) +{ + struct wmi_p2p_info_event *ev; + u32 flags; + u16 dlen; + + if (len < sizeof(*ev)) + return -EINVAL; + + ev = (struct wmi_p2p_info_event *) datap; + flags = le32_to_cpu(ev->info_req_flags); + dlen = le16_to_cpu(ev->len); + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: flags=%x len=%d\n", flags, dlen); + + if (flags & P2P_FLAG_CAPABILITIES_REQ) { + struct wmi_p2p_capabilities *cap; + if (dlen < sizeof(*cap)) + return -EINVAL; + cap = (struct wmi_p2p_capabilities *) ev->data; + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: GO Power Save = %d\n", + cap->go_power_save); + } + + if (flags & P2P_FLAG_MACADDR_REQ) { + struct wmi_p2p_macaddr *mac; + if (dlen < sizeof(*mac)) + return -EINVAL; + mac = (struct wmi_p2p_macaddr *) ev->data; + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: MAC Address = %pM\n", + mac->mac_addr); + } + + if (flags & P2P_FLAG_HMODEL_REQ) { + struct wmi_p2p_hmodel *mod; + if (dlen < sizeof(*mod)) + return -EINVAL; + mod = (struct wmi_p2p_hmodel *) ev->data; + ath6kl_dbg(ATH6KL_DBG_WMI, "p2p_info: P2P Model = %d (%s)\n", + mod->p2p_model, + mod->p2p_model ? "host" : "firmware"); + } + return 0; +} + +static inline struct sk_buff *ath6kl_wmi_get_new_buf(u32 size) +{ + struct sk_buff *skb; + + skb = ath6kl_buf_alloc(size); + if (!skb) + return NULL; + + skb_put(skb, size); + if (size) + memset(skb->data, 0, size); + + return skb; +} + +/* Send a "simple" wmi command -- one with no arguments */ +static int ath6kl_wmi_simple_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id) +{ + struct sk_buff *skb; + int ret; + + skb = ath6kl_wmi_get_new_buf(0); + if (!skb) + return -ENOMEM; + + ret = ath6kl_wmi_cmd_send(wmi, skb, cmd_id, NO_SYNC_WMIFLAG); + + return ret; +} + +static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_ready_event_2 *ev = (struct wmi_ready_event_2 *) datap; + + if (len < sizeof(struct wmi_ready_event_2)) + return -EINVAL; + + wmi->ready = true; + ath6kl_ready_event(wmi->parent_dev, ev->mac_addr, + le32_to_cpu(ev->sw_version), + le32_to_cpu(ev->abi_version)); + + return 0; +} + +/* + * Mechanism to modify the roaming behavior in the firmware. The lower rssi + * at which the station has to roam can be passed with + * WMI_SET_LRSSI_SCAN_PARAMS. Subtract 96 from RSSI to get the signal level + * in dBm. + */ +int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi) +{ + struct sk_buff *skb; + struct roam_ctrl_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct roam_ctrl_cmd *) skb->data; + + cmd->info.params.lrssi_scan_period = cpu_to_le16(DEF_LRSSI_SCAN_PERIOD); + cmd->info.params.lrssi_scan_threshold = a_cpu_to_sle16(lrssi + + DEF_SCAN_FOR_ROAM_INTVL); + cmd->info.params.lrssi_roam_threshold = a_cpu_to_sle16(lrssi); + cmd->info.params.roam_rssi_floor = DEF_LRSSI_ROAM_FLOOR; + cmd->roam_ctrl = WMI_SET_LRSSI_SCAN_PARAMS; + + ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_ROAM_CTRL_CMDID, NO_SYNC_WMIFLAG); + + return 0; +} + +static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_connect_event *ev; + u8 *pie, *peie; + struct ath6kl *ar = wmi->parent_dev; + + if (len < sizeof(struct wmi_connect_event)) + return -EINVAL; + + ev = (struct wmi_connect_event *) datap; + + if (ar->nw_type == AP_NETWORK) { + /* AP mode start/STA connected event */ + struct net_device *dev = ar->net_dev; + if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) { + ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM " + "(AP started)\n", + __func__, le16_to_cpu(ev->u.ap_bss.ch), + ev->u.ap_bss.bssid); + ath6kl_connect_ap_mode_bss( + ar, le16_to_cpu(ev->u.ap_bss.ch)); + } else { + ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM " + "auth=%u keymgmt=%u cipher=%u apsd_info=%u " + "(STA connected)\n", + __func__, ev->u.ap_sta.aid, + ev->u.ap_sta.mac_addr, + ev->u.ap_sta.auth, + ev->u.ap_sta.keymgmt, + le16_to_cpu(ev->u.ap_sta.cipher), + ev->u.ap_sta.apsd_info); + ath6kl_connect_ap_mode_sta( + ar, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr, + ev->u.ap_sta.keymgmt, + le16_to_cpu(ev->u.ap_sta.cipher), + ev->u.ap_sta.auth, ev->assoc_req_len, + ev->assoc_info + ev->beacon_ie_len); + } + return 0; + } + + /* STA/IBSS mode connection event */ + + ath6kl_dbg(ATH6KL_DBG_WMI, + "wmi event connect freq %d bssid %pM listen_intvl %d beacon_intvl %d type %d\n", + le16_to_cpu(ev->u.sta.ch), ev->u.sta.bssid, + le16_to_cpu(ev->u.sta.listen_intvl), + le16_to_cpu(ev->u.sta.beacon_intvl), + le32_to_cpu(ev->u.sta.nw_type)); + + /* Start of assoc rsp IEs */ + pie = ev->assoc_info + ev->beacon_ie_len + + ev->assoc_req_len + (sizeof(u16) * 3); /* capinfo, status, aid */ + + /* End of assoc rsp IEs */ + peie = ev->assoc_info + ev->beacon_ie_len + ev->assoc_req_len + + ev->assoc_resp_len; + + while (pie < peie) { + switch (*pie) { + case WLAN_EID_VENDOR_SPECIFIC: + if (pie[1] > 3 && pie[2] == 0x00 && pie[3] == 0x50 && + pie[4] == 0xf2 && pie[5] == WMM_OUI_TYPE) { + /* WMM OUT (00:50:F2) */ + if (pie[1] > 5 + && pie[6] == WMM_PARAM_OUI_SUBTYPE) + wmi->is_wmm_enabled = true; + } + break; + } + + if (wmi->is_wmm_enabled) + break; + + pie += pie[1] + 2; + } + + ath6kl_connect_event(wmi->parent_dev, le16_to_cpu(ev->u.sta.ch), + ev->u.sta.bssid, + le16_to_cpu(ev->u.sta.listen_intvl), + le16_to_cpu(ev->u.sta.beacon_intvl), + le32_to_cpu(ev->u.sta.nw_type), + ev->beacon_ie_len, ev->assoc_req_len, + ev->assoc_resp_len, ev->assoc_info); + + return 0; +} + +static struct country_code_to_enum_rd * +ath6kl_regd_find_country(u16 countryCode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].countryCode == countryCode) + return &allCountries[i]; + } + + return NULL; +} + +static struct reg_dmn_pair_mapping * +ath6kl_get_regpair(u16 regdmn) +{ + int i; + + if (regdmn == NO_ENUMRD) + return NULL; + + for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { + if (regDomainPairs[i].regDmnEnum == regdmn) + return ®DomainPairs[i]; + } + + return NULL; +} + +static struct country_code_to_enum_rd * +ath6kl_regd_find_country_by_rd(u16 regdmn) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(allCountries); i++) { + if (allCountries[i].regDmnEnum == regdmn) + return &allCountries[i]; + } + + return NULL; +} + +static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len) +{ + + struct ath6kl_wmi_regdomain *ev; + struct country_code_to_enum_rd *country = NULL; + struct reg_dmn_pair_mapping *regpair = NULL; + char alpha2[2]; + u32 reg_code; + + ev = (struct ath6kl_wmi_regdomain *) datap; + reg_code = le32_to_cpu(ev->reg_code); + + if ((reg_code >> ATH6KL_COUNTRY_RD_SHIFT) & COUNTRY_ERD_FLAG) + country = ath6kl_regd_find_country((u16) reg_code); + else if (!(((u16) reg_code & WORLD_SKU_MASK) == WORLD_SKU_PREFIX)) { + + regpair = ath6kl_get_regpair((u16) reg_code); + country = ath6kl_regd_find_country_by_rd((u16) reg_code); + ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n", + regpair->regDmnEnum); + } + + if (country) { + alpha2[0] = country->isoName[0]; + alpha2[1] = country->isoName[1]; + + regulatory_hint(wmi->parent_dev->wdev->wiphy, alpha2); + + ath6kl_dbg(ATH6KL_DBG_WMI, "Country alpha2 being used: %c%c\n", + alpha2[0], alpha2[1]); + } +} + +static int ath6kl_wmi_disconnect_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_disconnect_event *ev; + wmi->traffic_class = 100; + + if (len < sizeof(struct wmi_disconnect_event)) + return -EINVAL; + + ev = (struct wmi_disconnect_event *) datap; + + ath6kl_dbg(ATH6KL_DBG_WMI, + "wmi event disconnect proto_reason %d bssid %pM wmi_reason %d assoc_resp_len %d\n", + le16_to_cpu(ev->proto_reason_status), ev->bssid, + ev->disconn_reason, ev->assoc_resp_len); + + wmi->is_wmm_enabled = false; + wmi->pair_crypto_type = NONE_CRYPT; + wmi->grp_crypto_type = NONE_CRYPT; + + ath6kl_disconnect_event(wmi->parent_dev, ev->disconn_reason, + ev->bssid, ev->assoc_resp_len, ev->assoc_info, + le16_to_cpu(ev->proto_reason_status)); + + return 0; +} + +static int ath6kl_wmi_peer_node_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_peer_node_event *ev; + + if (len < sizeof(struct wmi_peer_node_event)) + return -EINVAL; + + ev = (struct wmi_peer_node_event *) datap; + + if (ev->event_code == PEER_NODE_JOIN_EVENT) + ath6kl_dbg(ATH6KL_DBG_WMI, "joined node with mac addr: %pM\n", + ev->peer_mac_addr); + else if (ev->event_code == PEER_NODE_LEAVE_EVENT) + ath6kl_dbg(ATH6KL_DBG_WMI, "left node with mac addr: %pM\n", + ev->peer_mac_addr); + + return 0; +} + +static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_tkip_micerr_event *ev; + + if (len < sizeof(struct wmi_tkip_micerr_event)) + return -EINVAL; + + ev = (struct wmi_tkip_micerr_event *) datap; + + ath6kl_tkip_micerr_event(wmi->parent_dev, ev->key_id, ev->is_mcast); + + return 0; +} + +static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_bss_info_hdr2 *bih; + u8 *buf; + struct ieee80211_channel *channel; + struct ath6kl *ar = wmi->parent_dev; + struct ieee80211_mgmt *mgmt; + struct cfg80211_bss *bss; + + if (len <= sizeof(struct wmi_bss_info_hdr2)) + return -EINVAL; + + bih = (struct wmi_bss_info_hdr2 *) datap; + buf = datap + sizeof(struct wmi_bss_info_hdr2); + len -= sizeof(struct wmi_bss_info_hdr2); + + ath6kl_dbg(ATH6KL_DBG_WMI, + "bss info evt - ch %u, snr %d, rssi %d, bssid \"%pM\" " + "frame_type=%d\n", + bih->ch, bih->snr, bih->snr - 95, bih->bssid, + bih->frame_type); + + if (bih->frame_type != BEACON_FTYPE && + bih->frame_type != PROBERESP_FTYPE) + return 0; /* Only update BSS table for now */ + + if (bih->frame_type == BEACON_FTYPE && + test_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag)) { + clear_bit(CLEAR_BSSFILTER_ON_BEACON, &ar->flag); + ath6kl_wmi_bssfilter_cmd(ar->wmi, NONE_BSS_FILTER, 0); + } + + channel = ieee80211_get_channel(ar->wdev->wiphy, le16_to_cpu(bih->ch)); + if (channel == NULL) + return -EINVAL; + + if (len < 8 + 2 + 2) + return -EINVAL; + + if (bih->frame_type == BEACON_FTYPE && test_bit(CONNECTED, &ar->flag) && + memcmp(bih->bssid, ar->bssid, ETH_ALEN) == 0) { + const u8 *tim; + tim = cfg80211_find_ie(WLAN_EID_TIM, buf + 8 + 2 + 2, + len - 8 - 2 - 2); + if (tim && tim[1] >= 2) { + ar->assoc_bss_dtim_period = tim[3]; + set_bit(DTIM_PERIOD_AVAIL, &ar->flag); + } + } + + /* + * In theory, use of cfg80211_inform_bss() would be more natural here + * since we do not have the full frame. However, at least for now, + * cfg80211 can only distinguish Beacon and Probe Response frames from + * each other when using cfg80211_inform_bss_frame(), so let's build a + * fake IEEE 802.11 header to be able to take benefit of this. + */ + mgmt = kmalloc(24 + len, GFP_ATOMIC); + if (mgmt == NULL) + return -EINVAL; + + if (bih->frame_type == BEACON_FTYPE) { + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_BEACON); + memset(mgmt->da, 0xff, ETH_ALEN); + } else { + struct net_device *dev = ar->net_dev; + + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + memcpy(mgmt->da, dev->dev_addr, ETH_ALEN); + } + mgmt->duration = cpu_to_le16(0); + memcpy(mgmt->sa, bih->bssid, ETH_ALEN); + memcpy(mgmt->bssid, bih->bssid, ETH_ALEN); + mgmt->seq_ctrl = cpu_to_le16(0); + + memcpy(&mgmt->u.beacon, buf, len); + + bss = cfg80211_inform_bss_frame(ar->wdev->wiphy, channel, mgmt, + 24 + len, (bih->snr - 95) * 100, + GFP_ATOMIC); + kfree(mgmt); + if (bss == NULL) + return -ENOMEM; + cfg80211_put_bss(bss); + + return 0; +} + +/* Inactivity timeout of a fatpipe(pstream) at the target */ +static int ath6kl_wmi_pstream_timeout_event_rx(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmi_pstream_timeout_event *ev; + + if (len < sizeof(struct wmi_pstream_timeout_event)) + return -EINVAL; + + ev = (struct wmi_pstream_timeout_event *) datap; + + /* + * When the pstream (fat pipe == AC) timesout, it means there were + * no thinStreams within this pstream & it got implicitly created + * due to data flow on this AC. We start the inactivity timer only + * for implicitly created pstream. Just reset the host state. + */ + spin_lock_bh(&wmi->lock); + wmi->stream_exist_for_ac[ev->traffic_class] = 0; + wmi->fat_pipe_exist &= ~(1 << ev->traffic_class); + spin_unlock_bh(&wmi->lock); + + /* Indicate inactivity to driver layer for this fatpipe (pstream) */ + ath6kl_indicate_tx_activity(wmi->parent_dev, ev->traffic_class, false); + + return 0; +} + +static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_bit_rate_reply *reply; + s32 rate; + u32 sgi, index; + + if (len < sizeof(struct wmi_bit_rate_reply)) + return -EINVAL; + + reply = (struct wmi_bit_rate_reply *) datap; + + ath6kl_dbg(ATH6KL_DBG_WMI, "rateindex %d\n", reply->rate_index); + + if (reply->rate_index == (s8) RATE_AUTO) { + rate = RATE_AUTO; + } else { + index = reply->rate_index & 0x7f; + sgi = (reply->rate_index & 0x80) ? 1 : 0; + rate = wmi_rate_tbl[index][sgi]; + } + + ath6kl_wakeup_event(wmi->parent_dev); + + return 0; +} + +static int ath6kl_wmi_tcmd_test_report_rx(struct wmi *wmi, u8 *datap, int len) +{ + ath6kl_tm_rx_report_event(wmi->parent_dev, datap, len); + + return 0; +} + +static int ath6kl_wmi_ratemask_reply_rx(struct wmi *wmi, u8 *datap, int len) +{ + if (len < sizeof(struct wmi_fix_rates_reply)) + return -EINVAL; + + ath6kl_wakeup_event(wmi->parent_dev); + + return 0; +} + +static int ath6kl_wmi_ch_list_reply_rx(struct wmi *wmi, u8 *datap, int len) +{ + if (len < sizeof(struct wmi_channel_list_reply)) + return -EINVAL; + + ath6kl_wakeup_event(wmi->parent_dev); + + return 0; +} + +static int ath6kl_wmi_tx_pwr_reply_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_tx_pwr_reply *reply; + + if (len < sizeof(struct wmi_tx_pwr_reply)) + return -EINVAL; + + reply = (struct wmi_tx_pwr_reply *) datap; + ath6kl_txpwr_rx_evt(wmi->parent_dev, reply->dbM); + + return 0; +} + +static int ath6kl_wmi_keepalive_reply_rx(struct wmi *wmi, u8 *datap, int len) +{ + if (len < sizeof(struct wmi_get_keepalive_cmd)) + return -EINVAL; + + ath6kl_wakeup_event(wmi->parent_dev); + + return 0; +} + +static int ath6kl_wmi_scan_complete_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_scan_complete_event *ev; + + ev = (struct wmi_scan_complete_event *) datap; + + ath6kl_scan_complete_evt(wmi->parent_dev, a_sle32_to_cpu(ev->status)); + wmi->is_probe_ssid = false; + + return 0; +} + +static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmi_neighbor_report_event *ev; + u8 i; + + if (len < sizeof(*ev)) + return -EINVAL; + ev = (struct wmi_neighbor_report_event *) datap; + if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info) + > len) { + ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event " + "(num=%d len=%d)\n", ev->num_neighbors, len); + return -EINVAL; + } + for (i = 0; i < ev->num_neighbors; i++) { + ath6kl_dbg(ATH6KL_DBG_WMI, "neighbor %d/%d - %pM 0x%x\n", + i + 1, ev->num_neighbors, ev->neighbor[i].bssid, + ev->neighbor[i].bss_flags); + cfg80211_pmksa_candidate_notify(wmi->parent_dev->net_dev, i, + ev->neighbor[i].bssid, + !!(ev->neighbor[i].bss_flags & + WMI_PREAUTH_CAPABLE_BSS), + GFP_ATOMIC); + } + + return 0; +} + +/* + * Target is reporting a programming error. This is for + * developer aid only. Target only checks a few common violations + * and it is responsibility of host to do all error checking. + * Behavior of target after wmi error event is undefined. + * A reset is recommended. + */ +static int ath6kl_wmi_error_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + const char *type = "unknown error"; + struct wmi_cmd_error_event *ev; + ev = (struct wmi_cmd_error_event *) datap; + + switch (ev->err_code) { + case INVALID_PARAM: + type = "invalid parameter"; + break; + case ILLEGAL_STATE: + type = "invalid state"; + break; + case INTERNAL_ERROR: + type = "internal error"; + break; + } + + ath6kl_dbg(ATH6KL_DBG_WMI, "programming error, cmd=%d %s\n", + ev->cmd_id, type); + + return 0; +} + +static int ath6kl_wmi_stats_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + ath6kl_tgt_stats_event(wmi->parent_dev, datap, len); + + return 0; +} + +static u8 ath6kl_wmi_get_upper_threshold(s16 rssi, + struct sq_threshold_params *sq_thresh, + u32 size) +{ + u32 index; + u8 threshold = (u8) sq_thresh->upper_threshold[size - 1]; + + /* The list is already in sorted order. Get the next lower value */ + for (index = 0; index < size; index++) { + if (rssi < sq_thresh->upper_threshold[index]) { + threshold = (u8) sq_thresh->upper_threshold[index]; + break; + } + } + + return threshold; +} + +static u8 ath6kl_wmi_get_lower_threshold(s16 rssi, + struct sq_threshold_params *sq_thresh, + u32 size) +{ + u32 index; + u8 threshold = (u8) sq_thresh->lower_threshold[size - 1]; + + /* The list is already in sorted order. Get the next lower value */ + for (index = 0; index < size; index++) { + if (rssi > sq_thresh->lower_threshold[index]) { + threshold = (u8) sq_thresh->lower_threshold[index]; + break; + } + } + + return threshold; +} + +static int ath6kl_wmi_send_rssi_threshold_params(struct wmi *wmi, + struct wmi_rssi_threshold_params_cmd *rssi_cmd) +{ + struct sk_buff *skb; + struct wmi_rssi_threshold_params_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_rssi_threshold_params_cmd *) skb->data; + memcpy(cmd, rssi_cmd, sizeof(struct wmi_rssi_threshold_params_cmd)); + + return ath6kl_wmi_cmd_send(wmi, skb, WMI_RSSI_THRESHOLD_PARAMS_CMDID, + NO_SYNC_WMIFLAG); +} + +static int ath6kl_wmi_rssi_threshold_event_rx(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmi_rssi_threshold_event *reply; + struct wmi_rssi_threshold_params_cmd cmd; + struct sq_threshold_params *sq_thresh; + enum wmi_rssi_threshold_val new_threshold; + u8 upper_rssi_threshold, lower_rssi_threshold; + s16 rssi; + int ret; + + if (len < sizeof(struct wmi_rssi_threshold_event)) + return -EINVAL; + + reply = (struct wmi_rssi_threshold_event *) datap; + new_threshold = (enum wmi_rssi_threshold_val) reply->range; + rssi = a_sle16_to_cpu(reply->rssi); + + sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_RSSI]; + + /* + * Identify the threshold breached and communicate that to the app. + * After that install a new set of thresholds based on the signal + * quality reported by the target + */ + if (new_threshold) { + /* Upper threshold breached */ + if (rssi < sq_thresh->upper_threshold[0]) { + ath6kl_dbg(ATH6KL_DBG_WMI, + "spurious upper rssi threshold event: %d\n", + rssi); + } else if ((rssi < sq_thresh->upper_threshold[1]) && + (rssi >= sq_thresh->upper_threshold[0])) { + new_threshold = WMI_RSSI_THRESHOLD1_ABOVE; + } else if ((rssi < sq_thresh->upper_threshold[2]) && + (rssi >= sq_thresh->upper_threshold[1])) { + new_threshold = WMI_RSSI_THRESHOLD2_ABOVE; + } else if ((rssi < sq_thresh->upper_threshold[3]) && + (rssi >= sq_thresh->upper_threshold[2])) { + new_threshold = WMI_RSSI_THRESHOLD3_ABOVE; + } else if ((rssi < sq_thresh->upper_threshold[4]) && + (rssi >= sq_thresh->upper_threshold[3])) { + new_threshold = WMI_RSSI_THRESHOLD4_ABOVE; + } else if ((rssi < sq_thresh->upper_threshold[5]) && + (rssi >= sq_thresh->upper_threshold[4])) { + new_threshold = WMI_RSSI_THRESHOLD5_ABOVE; + } else if (rssi >= sq_thresh->upper_threshold[5]) { + new_threshold = WMI_RSSI_THRESHOLD6_ABOVE; + } + } else { + /* Lower threshold breached */ + if (rssi > sq_thresh->lower_threshold[0]) { + ath6kl_dbg(ATH6KL_DBG_WMI, + "spurious lower rssi threshold event: %d %d\n", + rssi, sq_thresh->lower_threshold[0]); + } else if ((rssi > sq_thresh->lower_threshold[1]) && + (rssi <= sq_thresh->lower_threshold[0])) { + new_threshold = WMI_RSSI_THRESHOLD6_BELOW; + } else if ((rssi > sq_thresh->lower_threshold[2]) && + (rssi <= sq_thresh->lower_threshold[1])) { + new_threshold = WMI_RSSI_THRESHOLD5_BELOW; + } else if ((rssi > sq_thresh->lower_threshold[3]) && + (rssi <= sq_thresh->lower_threshold[2])) { + new_threshold = WMI_RSSI_THRESHOLD4_BELOW; + } else if ((rssi > sq_thresh->lower_threshold[4]) && + (rssi <= sq_thresh->lower_threshold[3])) { + new_threshold = WMI_RSSI_THRESHOLD3_BELOW; + } else if ((rssi > sq_thresh->lower_threshold[5]) && + (rssi <= sq_thresh->lower_threshold[4])) { + new_threshold = WMI_RSSI_THRESHOLD2_BELOW; + } else if (rssi <= sq_thresh->lower_threshold[5]) { + new_threshold = WMI_RSSI_THRESHOLD1_BELOW; + } + } + + /* Calculate and install the next set of thresholds */ + lower_rssi_threshold = ath6kl_wmi_get_lower_threshold(rssi, sq_thresh, + sq_thresh->lower_threshold_valid_count); + upper_rssi_threshold = ath6kl_wmi_get_upper_threshold(rssi, sq_thresh, + sq_thresh->upper_threshold_valid_count); + + /* Issue a wmi command to install the thresholds */ + cmd.thresh_above1_val = a_cpu_to_sle16(upper_rssi_threshold); + cmd.thresh_below1_val = a_cpu_to_sle16(lower_rssi_threshold); + cmd.weight = sq_thresh->weight; + cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval); + + ret = ath6kl_wmi_send_rssi_threshold_params(wmi, &cmd); + if (ret) { + ath6kl_err("unable to configure rssi thresholds\n"); + return -EIO; + } + + return 0; +} + +static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_cac_event *reply; + struct ieee80211_tspec_ie *ts; + u16 active_tsids, tsinfo; + u8 tsid, index; + u8 ts_id; + + if (len < sizeof(struct wmi_cac_event)) + return -EINVAL; + + reply = (struct wmi_cac_event *) datap; + + if ((reply->cac_indication == CAC_INDICATION_ADMISSION_RESP) && + (reply->status_code != IEEE80211_TSPEC_STATUS_ADMISS_ACCEPTED)) { + + ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion); + tsinfo = le16_to_cpu(ts->tsinfo); + tsid = (tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & + IEEE80211_WMM_IE_TSPEC_TID_MASK; + + ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, tsid); + } else if (reply->cac_indication == CAC_INDICATION_NO_RESP) { + /* + * Following assumes that there is only one outstanding + * ADDTS request when this event is received + */ + spin_lock_bh(&wmi->lock); + active_tsids = wmi->stream_exist_for_ac[reply->ac]; + spin_unlock_bh(&wmi->lock); + + for (index = 0; index < sizeof(active_tsids) * 8; index++) { + if ((active_tsids >> index) & 1) + break; + } + if (index < (sizeof(active_tsids) * 8)) + ath6kl_wmi_delete_pstream_cmd(wmi, reply->ac, index); + } + + /* + * Clear active tsids and Add missing handling + * for delete qos stream from AP + */ + else if (reply->cac_indication == CAC_INDICATION_DELETE) { + + ts = (struct ieee80211_tspec_ie *) &(reply->tspec_suggestion); + tsinfo = le16_to_cpu(ts->tsinfo); + ts_id = ((tsinfo >> IEEE80211_WMM_IE_TSPEC_TID_SHIFT) & + IEEE80211_WMM_IE_TSPEC_TID_MASK); + + spin_lock_bh(&wmi->lock); + wmi->stream_exist_for_ac[reply->ac] &= ~(1 << ts_id); + active_tsids = wmi->stream_exist_for_ac[reply->ac]; + spin_unlock_bh(&wmi->lock); + + /* Indicate stream inactivity to driver layer only if all tsids + * within this AC are deleted. + */ + if (!active_tsids) { + ath6kl_indicate_tx_activity(wmi->parent_dev, reply->ac, + false); + wmi->fat_pipe_exist &= ~(1 << reply->ac); + } + } + + return 0; +} + +static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi, + struct wmi_snr_threshold_params_cmd *snr_cmd) +{ + struct sk_buff *skb; + struct wmi_snr_threshold_params_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_snr_threshold_params_cmd *) skb->data; + memcpy(cmd, snr_cmd, sizeof(struct wmi_snr_threshold_params_cmd)); + + return ath6kl_wmi_cmd_send(wmi, skb, WMI_SNR_THRESHOLD_PARAMS_CMDID, + NO_SYNC_WMIFLAG); +} + +static int ath6kl_wmi_snr_threshold_event_rx(struct wmi *wmi, u8 *datap, + int len) +{ + struct wmi_snr_threshold_event *reply; + struct sq_threshold_params *sq_thresh; + struct wmi_snr_threshold_params_cmd cmd; + enum wmi_snr_threshold_val new_threshold; + u8 upper_snr_threshold, lower_snr_threshold; + s16 snr; + int ret; + + if (len < sizeof(struct wmi_snr_threshold_event)) + return -EINVAL; + + reply = (struct wmi_snr_threshold_event *) datap; + + new_threshold = (enum wmi_snr_threshold_val) reply->range; + snr = reply->snr; + + sq_thresh = &wmi->sq_threshld[SIGNAL_QUALITY_METRICS_SNR]; + + /* + * Identify the threshold breached and communicate that to the app. + * After that install a new set of thresholds based on the signal + * quality reported by the target. + */ + if (new_threshold) { + /* Upper threshold breached */ + if (snr < sq_thresh->upper_threshold[0]) { + ath6kl_dbg(ATH6KL_DBG_WMI, + "spurious upper snr threshold event: %d\n", + snr); + } else if ((snr < sq_thresh->upper_threshold[1]) && + (snr >= sq_thresh->upper_threshold[0])) { + new_threshold = WMI_SNR_THRESHOLD1_ABOVE; + } else if ((snr < sq_thresh->upper_threshold[2]) && + (snr >= sq_thresh->upper_threshold[1])) { + new_threshold = WMI_SNR_THRESHOLD2_ABOVE; + } else if ((snr < sq_thresh->upper_threshold[3]) && + (snr >= sq_thresh->upper_threshold[2])) { + new_threshold = WMI_SNR_THRESHOLD3_ABOVE; + } else if (snr >= sq_thresh->upper_threshold[3]) { + new_threshold = WMI_SNR_THRESHOLD4_ABOVE; + } + } else { + /* Lower threshold breached */ + if (snr > sq_thresh->lower_threshold[0]) { + ath6kl_dbg(ATH6KL_DBG_WMI, + "spurious lower snr threshold event: %d\n", + sq_thresh->lower_threshold[0]); + } else if ((snr > sq_thresh->lower_threshold[1]) && + (snr <= sq_thresh->lower_threshold[0])) { + new_threshold = WMI_SNR_THRESHOLD4_BELOW; + } else if ((snr > sq_thresh->lower_threshold[2]) && + (snr <= sq_thresh->lower_threshold[1])) { + new_threshold = WMI_SNR_THRESHOLD3_BELOW; + } else if ((snr > sq_thresh->lower_threshold[3]) && + (snr <= sq_thresh->lower_threshold[2])) { + new_threshold = WMI_SNR_THRESHOLD2_BELOW; + } else if (snr <= sq_thresh->lower_threshold[3]) { + new_threshold = WMI_SNR_THRESHOLD1_BELOW; + } + } + + /* Calculate and install the next set of thresholds */ + lower_snr_threshold = ath6kl_wmi_get_lower_threshold(snr, sq_thresh, + sq_thresh->lower_threshold_valid_count); + upper_snr_threshold = ath6kl_wmi_get_upper_threshold(snr, sq_thresh, + sq_thresh->upper_threshold_valid_count); + + /* Issue a wmi command to install the thresholds */ + cmd.thresh_above1_val = upper_snr_threshold; + cmd.thresh_below1_val = lower_snr_threshold; + cmd.weight = sq_thresh->weight; + cmd.poll_time = cpu_to_le32(sq_thresh->polling_interval); + + ath6kl_dbg(ATH6KL_DBG_WMI, + "snr: %d, threshold: %d, lower: %d, upper: %d\n", + snr, new_threshold, + lower_snr_threshold, upper_snr_threshold); + + ret = ath6kl_wmi_send_snr_threshold_params(wmi, &cmd); + if (ret) { + ath6kl_err("unable to configure snr threshold\n"); + return -EIO; + } + + return 0; +} + +static int ath6kl_wmi_aplist_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + u16 ap_info_entry_size; + struct wmi_aplist_event *ev = (struct wmi_aplist_event *) datap; + struct wmi_ap_info_v1 *ap_info_v1; + u8 index; + + if (len < sizeof(struct wmi_aplist_event) || + ev->ap_list_ver != APLIST_VER1) + return -EINVAL; + + ap_info_entry_size = sizeof(struct wmi_ap_info_v1); + ap_info_v1 = (struct wmi_ap_info_v1 *) ev->ap_list; + + ath6kl_dbg(ATH6KL_DBG_WMI, + "number of APs in aplist event: %d\n", ev->num_ap); + + if (len < (int) (sizeof(struct wmi_aplist_event) + + (ev->num_ap - 1) * ap_info_entry_size)) + return -EINVAL; + + /* AP list version 1 contents */ + for (index = 0; index < ev->num_ap; index++) { + ath6kl_dbg(ATH6KL_DBG_WMI, "AP#%d BSSID %pM Channel %d\n", + index, ap_info_v1->bssid, ap_info_v1->channel); + ap_info_v1++; + } + + return 0; +} + +int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, + enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag) +{ + struct wmi_cmd_hdr *cmd_hdr; + enum htc_endpoint_id ep_id = wmi->ep_id; + int ret; + + if (WARN_ON(skb == NULL)) + return -EINVAL; + + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", + cmd_id, skb->len, sync_flag); + ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi tx ", + skb->data, skb->len); + + if (sync_flag >= END_WMIFLAG) { + dev_kfree_skb(skb); + return -EINVAL; + } + + if ((sync_flag == SYNC_BEFORE_WMIFLAG) || + (sync_flag == SYNC_BOTH_WMIFLAG)) { + /* + * Make sure all data currently queued is transmitted before + * the cmd execution. Establish a new sync point. + */ + ath6kl_wmi_sync_point(wmi); + } + + skb_push(skb, sizeof(struct wmi_cmd_hdr)); + + cmd_hdr = (struct wmi_cmd_hdr *) skb->data; + cmd_hdr->cmd_id = cpu_to_le16(cmd_id); + cmd_hdr->info1 = 0; /* added for virtual interface */ + + /* Only for OPT_TX_CMD, use BE endpoint. */ + if (cmd_id == WMI_OPT_TX_FRAME_CMDID) { + ret = ath6kl_wmi_data_hdr_add(wmi, skb, OPT_MSGTYPE, + false, false, 0, NULL); + if (ret) { + dev_kfree_skb(skb); + return ret; + } + ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, WMM_AC_BE); + } + + ath6kl_control_tx(wmi->parent_dev, skb, ep_id); + + if ((sync_flag == SYNC_AFTER_WMIFLAG) || + (sync_flag == SYNC_BOTH_WMIFLAG)) { + /* + * Make sure all new data queued waits for the command to + * execute. Establish a new sync point. + */ + ath6kl_wmi_sync_point(wmi); + } + + return 0; +} + +int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type, + enum dot11_auth_mode dot11_auth_mode, + enum auth_mode auth_mode, + enum crypto_type pairwise_crypto, + u8 pairwise_crypto_len, + enum crypto_type group_crypto, + u8 group_crypto_len, int ssid_len, u8 *ssid, + u8 *bssid, u16 channel, u32 ctrl_flags) +{ + struct sk_buff *skb; + struct wmi_connect_cmd *cc; + int ret; + + ath6kl_dbg(ATH6KL_DBG_WMI, + "wmi connect bssid %pM freq %d flags 0x%x ssid_len %d " + "type %d dot11_auth %d auth %d pairwise %d group %d\n", + bssid, channel, ctrl_flags, ssid_len, nw_type, + dot11_auth_mode, auth_mode, pairwise_crypto, group_crypto); + ath6kl_dbg_dump(ATH6KL_DBG_WMI, NULL, "ssid ", ssid, ssid_len); + + wmi->traffic_class = 100; + + if ((pairwise_crypto == NONE_CRYPT) && (group_crypto != NONE_CRYPT)) + return -EINVAL; + + if ((pairwise_crypto != NONE_CRYPT) && (group_crypto == NONE_CRYPT)) + return -EINVAL; + + skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_connect_cmd)); + if (!skb) + return -ENOMEM; + + cc = (struct wmi_connect_cmd *) skb->data; + + if (ssid_len) + memcpy(cc->ssid, ssid, ssid_len); + + cc->ssid_len = ssid_len; + cc->nw_type = nw_type; + cc->dot11_auth_mode = dot11_auth_mode; + cc->auth_mode = auth_mode; + cc->prwise_crypto_type = pairwise_crypto; + cc->prwise_crypto_len = pairwise_crypto_len; + cc->grp_crypto_type = group_crypto; + cc->grp_crypto_len = group_crypto_len; + cc->ch = cpu_to_le16(channel); + cc->ctrl_flags = cpu_to_le32(ctrl_flags); + + if (bssid != NULL) + memcpy(cc->bssid, bssid, ETH_ALEN); + + wmi->pair_crypto_type = pairwise_crypto; + wmi->grp_crypto_type = group_crypto; + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CONNECT_CMDID, NO_SYNC_WMIFLAG); + + return ret; +} + +int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel) +{ + struct sk_buff *skb; + struct wmi_reconnect_cmd *cc; + int ret; + + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi reconnect bssid %pM freq %d\n", + bssid, channel); + + wmi->traffic_class = 100; + + skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_reconnect_cmd)); + if (!skb) + return -ENOMEM; + + cc = (struct wmi_reconnect_cmd *) skb->data; + cc->channel = cpu_to_le16(channel); + + if (bssid != NULL) + memcpy(cc->bssid, bssid, ETH_ALEN); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RECONNECT_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} + +int ath6kl_wmi_disconnect_cmd(struct wmi *wmi) +{ + int ret; + + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi disconnect\n"); + + wmi->traffic_class = 100; + + /* Disconnect command does not need to do a SYNC before. */ + ret = ath6kl_wmi_simple_cmd(wmi, WMI_DISCONNECT_CMDID); + + return ret; +} + +int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type, + u32 force_fgscan, u32 is_legacy, + u32 home_dwell_time, u32 force_scan_interval, + s8 num_chan, u16 *ch_list) +{ + struct sk_buff *skb; + struct wmi_start_scan_cmd *sc; + s8 size; + int i, ret; + + size = sizeof(struct wmi_start_scan_cmd); + + if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN)) + return -EINVAL; + + if (num_chan > WMI_MAX_CHANNELS) + return -EINVAL; + + if (num_chan) + size += sizeof(u16) * (num_chan - 1); + + skb = ath6kl_wmi_get_new_buf(size); + if (!skb) + return -ENOMEM; + + sc = (struct wmi_start_scan_cmd *) skb->data; + sc->scan_type = scan_type; + sc->force_fg_scan = cpu_to_le32(force_fgscan); + sc->is_legacy = cpu_to_le32(is_legacy); + sc->home_dwell_time = cpu_to_le32(home_dwell_time); + sc->force_scan_intvl = cpu_to_le32(force_scan_interval); + sc->num_ch = num_chan; + + for (i = 0; i < num_chan; i++) + sc->ch_list[i] = cpu_to_le16(ch_list[i]); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_START_SCAN_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} + +int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec, + u16 fg_end_sec, u16 bg_sec, + u16 minact_chdw_msec, u16 maxact_chdw_msec, + u16 pas_chdw_msec, u8 short_scan_ratio, + u8 scan_ctrl_flag, u32 max_dfsch_act_time, + u16 maxact_scan_per_ssid) +{ + struct sk_buff *skb; + struct wmi_scan_params_cmd *sc; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*sc)); + if (!skb) + return -ENOMEM; + + sc = (struct wmi_scan_params_cmd *) skb->data; + sc->fg_start_period = cpu_to_le16(fg_start_sec); + sc->fg_end_period = cpu_to_le16(fg_end_sec); + sc->bg_period = cpu_to_le16(bg_sec); + sc->minact_chdwell_time = cpu_to_le16(minact_chdw_msec); + sc->maxact_chdwell_time = cpu_to_le16(maxact_chdw_msec); + sc->pas_chdwell_time = cpu_to_le16(pas_chdw_msec); + sc->short_scan_ratio = short_scan_ratio; + sc->scan_ctrl_flags = scan_ctrl_flag; + sc->max_dfsch_act_time = cpu_to_le32(max_dfsch_act_time); + sc->maxact_scan_per_ssid = cpu_to_le16(maxact_scan_per_ssid); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_SCAN_PARAMS_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask) +{ + struct sk_buff *skb; + struct wmi_bss_filter_cmd *cmd; + int ret; + + if (filter >= LAST_BSS_FILTER) + return -EINVAL; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_bss_filter_cmd *) skb->data; + cmd->bss_filter = filter; + cmd->ie_mask = cpu_to_le32(ie_mask); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_BSS_FILTER_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag, + u8 ssid_len, u8 *ssid) +{ + struct sk_buff *skb; + struct wmi_probed_ssid_cmd *cmd; + int ret; + + if (index > MAX_PROBED_SSID_INDEX) + return -EINVAL; + + if (ssid_len > sizeof(cmd->ssid)) + return -EINVAL; + + if ((flag & (DISABLE_SSID_FLAG | ANY_SSID_FLAG)) && (ssid_len > 0)) + return -EINVAL; + + if ((flag & SPECIFIC_SSID_FLAG) && !ssid_len) + return -EINVAL; + + if (flag & SPECIFIC_SSID_FLAG) + wmi->is_probe_ssid = true; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_probed_ssid_cmd *) skb->data; + cmd->entry_index = index; + cmd->flag = flag; + cmd->ssid_len = ssid_len; + memcpy(cmd->ssid, ssid, ssid_len); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PROBED_SSID_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval, + u16 listen_beacons) +{ + struct sk_buff *skb; + struct wmi_listen_int_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_listen_int_cmd *) skb->data; + cmd->listen_intvl = cpu_to_le16(listen_interval); + cmd->num_beacons = cpu_to_le16(listen_beacons); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LISTEN_INT_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode) +{ + struct sk_buff *skb; + struct wmi_power_mode_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_power_mode_cmd *) skb->data; + cmd->pwr_mode = pwr_mode; + wmi->pwr_mode = pwr_mode; + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_MODE_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period, + u16 ps_poll_num, u16 dtim_policy, + u16 tx_wakeup_policy, u16 num_tx_to_wakeup, + u16 ps_fail_event_policy) +{ + struct sk_buff *skb; + struct wmi_power_params_cmd *pm; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*pm)); + if (!skb) + return -ENOMEM; + + pm = (struct wmi_power_params_cmd *)skb->data; + pm->idle_period = cpu_to_le16(idle_period); + pm->pspoll_number = cpu_to_le16(ps_poll_num); + pm->dtim_policy = cpu_to_le16(dtim_policy); + pm->tx_wakeup_policy = cpu_to_le16(tx_wakeup_policy); + pm->num_tx_to_wakeup = cpu_to_le16(num_tx_to_wakeup); + pm->ps_fail_event_policy = cpu_to_le16(ps_fail_event_policy); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_POWER_PARAMS_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout) +{ + struct sk_buff *skb; + struct wmi_disc_timeout_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_disc_timeout_cmd *) skb->data; + cmd->discon_timeout = timeout; + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_DISC_TIMEOUT_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, + enum crypto_type key_type, + u8 key_usage, u8 key_len, + u8 *key_rsc, u8 *key_material, + u8 key_op_ctrl, u8 *mac_addr, + enum wmi_sync_flag sync_flag) +{ + struct sk_buff *skb; + struct wmi_add_cipher_key_cmd *cmd; + int ret; + + ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d " + "key_usage=%d key_len=%d key_op_ctrl=%d\n", + key_index, key_type, key_usage, key_len, key_op_ctrl); + + if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) || + (key_material == NULL)) + return -EINVAL; + + if ((WEP_CRYPT != key_type) && (NULL == key_rsc)) + return -EINVAL; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_add_cipher_key_cmd *) skb->data; + cmd->key_index = key_index; + cmd->key_type = key_type; + cmd->key_usage = key_usage; + cmd->key_len = key_len; + memcpy(cmd->key, key_material, key_len); + + if (key_rsc != NULL) + memcpy(cmd->key_rsc, key_rsc, sizeof(cmd->key_rsc)); + + cmd->key_op_ctrl = key_op_ctrl; + + if (mac_addr) + memcpy(cmd->key_mac_addr, mac_addr, ETH_ALEN); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_CIPHER_KEY_CMDID, + sync_flag); + + return ret; +} + +int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk) +{ + struct sk_buff *skb; + struct wmi_add_krk_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_add_krk_cmd *) skb->data; + memcpy(cmd->krk, krk, WMI_KRK_LEN); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_ADD_KRK_CMDID, NO_SYNC_WMIFLAG); + + return ret; +} + +int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index) +{ + struct sk_buff *skb; + struct wmi_delete_cipher_key_cmd *cmd; + int ret; + + if (key_index > WMI_MAX_KEY_INDEX) + return -EINVAL; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_delete_cipher_key_cmd *) skb->data; + cmd->key_index = key_index; + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_CIPHER_KEY_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} + +int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid, + const u8 *pmkid, bool set) +{ + struct sk_buff *skb; + struct wmi_setpmkid_cmd *cmd; + int ret; + + if (bssid == NULL) + return -EINVAL; + + if (set && pmkid == NULL) + return -EINVAL; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_setpmkid_cmd *) skb->data; + memcpy(cmd->bssid, bssid, ETH_ALEN); + if (set) { + memcpy(cmd->pmkid, pmkid, sizeof(cmd->pmkid)); + cmd->enable = PMKID_ENABLE; + } else { + memset(cmd->pmkid, 0, sizeof(cmd->pmkid)); + cmd->enable = PMKID_DISABLE; + } + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_PMKID_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} + +static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb, + enum htc_endpoint_id ep_id) +{ + struct wmi_data_hdr *data_hdr; + int ret; + + if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) + return -EINVAL; + + skb_push(skb, sizeof(struct wmi_data_hdr)); + + data_hdr = (struct wmi_data_hdr *) skb->data; + data_hdr->info = SYNC_MSGTYPE << WMI_DATA_HDR_MSG_TYPE_SHIFT; + data_hdr->info3 = 0; + + ret = ath6kl_control_tx(wmi->parent_dev, skb, ep_id); + + return ret; +} + +static int ath6kl_wmi_sync_point(struct wmi *wmi) +{ + struct sk_buff *skb; + struct wmi_sync_cmd *cmd; + struct wmi_data_sync_bufs data_sync_bufs[WMM_NUM_AC]; + enum htc_endpoint_id ep_id; + u8 index, num_pri_streams = 0; + int ret = 0; + + memset(data_sync_bufs, 0, sizeof(data_sync_bufs)); + + spin_lock_bh(&wmi->lock); + + for (index = 0; index < WMM_NUM_AC; index++) { + if (wmi->fat_pipe_exist & (1 << index)) { + num_pri_streams++; + data_sync_bufs[num_pri_streams - 1].traffic_class = + index; + } + } + + spin_unlock_bh(&wmi->lock); + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) { + ret = -ENOMEM; + goto free_skb; + } + + cmd = (struct wmi_sync_cmd *) skb->data; + + /* + * In the SYNC cmd sent on the control Ep, send a bitmap + * of the data eps on which the Data Sync will be sent + */ + cmd->data_sync_map = wmi->fat_pipe_exist; + + for (index = 0; index < num_pri_streams; index++) { + data_sync_bufs[index].skb = ath6kl_buf_alloc(0); + if (data_sync_bufs[index].skb == NULL) { + ret = -ENOMEM; + break; + } + } + + /* + * If buffer allocation for any of the dataSync fails, + * then do not send the Synchronize cmd on the control ep + */ + if (ret) + goto free_skb; + + /* + * Send sync cmd followed by sync data messages on all + * endpoints being used + */ + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SYNCHRONIZE_CMDID, + NO_SYNC_WMIFLAG); + + if (ret) + goto free_skb; + + /* cmd buffer sent, we no longer own it */ + skb = NULL; + + for (index = 0; index < num_pri_streams; index++) { + + if (WARN_ON(!data_sync_bufs[index].skb)) + break; + + ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev, + data_sync_bufs[index]. + traffic_class); + ret = + ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb, + ep_id); + + if (ret) + break; + + data_sync_bufs[index].skb = NULL; + } + +free_skb: + /* free up any resources left over (possibly due to an error) */ + if (skb) + dev_kfree_skb(skb); + + for (index = 0; index < num_pri_streams; index++) { + if (data_sync_bufs[index].skb != NULL) { + dev_kfree_skb((struct sk_buff *)data_sync_bufs[index]. + skb); + } + } + + return ret; +} + +int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, + struct wmi_create_pstream_cmd *params) +{ + struct sk_buff *skb; + struct wmi_create_pstream_cmd *cmd; + u8 fatpipe_exist_for_ac = 0; + s32 min_phy = 0; + s32 nominal_phy = 0; + int ret; + + if (!((params->user_pri < 8) && + (params->user_pri <= 0x7) && + (up_to_ac[params->user_pri & 0x7] == params->traffic_class) && + (params->traffic_direc == UPLINK_TRAFFIC || + params->traffic_direc == DNLINK_TRAFFIC || + params->traffic_direc == BIDIR_TRAFFIC) && + (params->traffic_type == TRAFFIC_TYPE_APERIODIC || + params->traffic_type == TRAFFIC_TYPE_PERIODIC) && + (params->voice_psc_cap == DISABLE_FOR_THIS_AC || + params->voice_psc_cap == ENABLE_FOR_THIS_AC || + params->voice_psc_cap == ENABLE_FOR_ALL_AC) && + (params->tsid == WMI_IMPLICIT_PSTREAM || + params->tsid <= WMI_MAX_THINSTREAM))) { + return -EINVAL; + } + + /* + * Check nominal PHY rate is >= minimalPHY, + * so that DUT can allow TSRS IE + */ + + /* Get the physical rate (units of bps) */ + min_phy = ((le32_to_cpu(params->min_phy_rate) / 1000) / 1000); + + /* Check minimal phy < nominal phy rate */ + if (params->nominal_phy >= min_phy) { + /* unit of 500 kbps */ + nominal_phy = (params->nominal_phy * 1000) / 500; + ath6kl_dbg(ATH6KL_DBG_WMI, + "TSRS IE enabled::MinPhy %x->NominalPhy ===> %x\n", + min_phy, nominal_phy); + + params->nominal_phy = nominal_phy; + } else { + params->nominal_phy = 0; + } + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, + "sending create_pstream_cmd: ac=%d tsid:%d\n", + params->traffic_class, params->tsid); + + cmd = (struct wmi_create_pstream_cmd *) skb->data; + memcpy(cmd, params, sizeof(*cmd)); + + /* This is an implicitly created Fat pipe */ + if ((u32) params->tsid == (u32) WMI_IMPLICIT_PSTREAM) { + spin_lock_bh(&wmi->lock); + fatpipe_exist_for_ac = (wmi->fat_pipe_exist & + (1 << params->traffic_class)); + wmi->fat_pipe_exist |= (1 << params->traffic_class); + spin_unlock_bh(&wmi->lock); + } else { + /* explicitly created thin stream within a fat pipe */ + spin_lock_bh(&wmi->lock); + fatpipe_exist_for_ac = (wmi->fat_pipe_exist & + (1 << params->traffic_class)); + wmi->stream_exist_for_ac[params->traffic_class] |= + (1 << params->tsid); + /* + * If a thinstream becomes active, the fat pipe automatically + * becomes active + */ + wmi->fat_pipe_exist |= (1 << params->traffic_class); + spin_unlock_bh(&wmi->lock); + } + + /* + * Indicate activty change to driver layer only if this is the + * first TSID to get created in this AC explicitly or an implicit + * fat pipe is getting created. + */ + if (!fatpipe_exist_for_ac) + ath6kl_indicate_tx_activity(wmi->parent_dev, + params->traffic_class, true); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_CREATE_PSTREAM_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid) +{ + struct sk_buff *skb; + struct wmi_delete_pstream_cmd *cmd; + u16 active_tsids = 0; + int ret; + + if (traffic_class > 3) { + ath6kl_err("invalid traffic class: %d\n", traffic_class); + return -EINVAL; + } + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_delete_pstream_cmd *) skb->data; + cmd->traffic_class = traffic_class; + cmd->tsid = tsid; + + spin_lock_bh(&wmi->lock); + active_tsids = wmi->stream_exist_for_ac[traffic_class]; + spin_unlock_bh(&wmi->lock); + + if (!(active_tsids & (1 << tsid))) { + dev_kfree_skb(skb); + ath6kl_dbg(ATH6KL_DBG_WMI, + "TSID %d doesn't exist for traffic class: %d\n", + tsid, traffic_class); + return -ENODATA; + } + + ath6kl_dbg(ATH6KL_DBG_WMI, + "sending delete_pstream_cmd: traffic class: %d tsid=%d\n", + traffic_class, tsid); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_DELETE_PSTREAM_CMDID, + SYNC_BEFORE_WMIFLAG); + + spin_lock_bh(&wmi->lock); + wmi->stream_exist_for_ac[traffic_class] &= ~(1 << tsid); + active_tsids = wmi->stream_exist_for_ac[traffic_class]; + spin_unlock_bh(&wmi->lock); + + /* + * Indicate stream inactivity to driver layer only if all tsids + * within this AC are deleted. + */ + if (!active_tsids) { + ath6kl_indicate_tx_activity(wmi->parent_dev, + traffic_class, false); + wmi->fat_pipe_exist &= ~(1 << traffic_class); + } + + return ret; +} + +int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd) +{ + struct sk_buff *skb; + struct wmi_set_ip_cmd *cmd; + int ret; + + /* Multicast address are not valid */ + if ((*((u8 *) &ip_cmd->ips[0]) >= 0xE0) || + (*((u8 *) &ip_cmd->ips[1]) >= 0xE0)) + return -EINVAL; + + skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_ip_cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_ip_cmd *) skb->data; + memcpy(cmd, ip_cmd, sizeof(struct wmi_set_ip_cmd)); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_IP_CMDID, NO_SYNC_WMIFLAG); + return ret; +} + +static int ath6kl_wmi_get_wow_list_event_rx(struct wmi *wmi, u8 * datap, + int len) +{ + if (len < sizeof(struct wmi_get_wow_list_reply)) + return -EINVAL; + + return 0; +} + +static int ath6kl_wmi_cmd_send_xtnd(struct wmi *wmi, struct sk_buff *skb, + enum wmix_command_id cmd_id, + enum wmi_sync_flag sync_flag) +{ + struct wmix_cmd_hdr *cmd_hdr; + int ret; + + skb_push(skb, sizeof(struct wmix_cmd_hdr)); + + cmd_hdr = (struct wmix_cmd_hdr *) skb->data; + cmd_hdr->cmd_id = cpu_to_le32(cmd_id); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_EXTENSION_CMDID, sync_flag); + + return ret; +} + +int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source) +{ + struct sk_buff *skb; + struct wmix_hb_challenge_resp_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmix_hb_challenge_resp_cmd *) skb->data; + cmd->cookie = cpu_to_le32(cookie); + cmd->source = cpu_to_le32(source); + + ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_HB_CHALLENGE_RESP_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config) +{ + struct ath6kl_wmix_dbglog_cfg_module_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct ath6kl_wmix_dbglog_cfg_module_cmd *) skb->data; + cmd->valid = cpu_to_le32(valid); + cmd->config = cpu_to_le32(config); + + ret = ath6kl_wmi_cmd_send_xtnd(wmi, skb, WMIX_DBGLOG_CFG_MODULE_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_get_stats_cmd(struct wmi *wmi) +{ + return ath6kl_wmi_simple_cmd(wmi, WMI_GET_STATISTICS_CMDID); +} + +int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM) +{ + struct sk_buff *skb; + struct wmi_set_tx_pwr_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_tx_pwr_cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_tx_pwr_cmd *) skb->data; + cmd->dbM = dbM; + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_TX_PWR_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} + +int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi) +{ + return ath6kl_wmi_simple_cmd(wmi, WMI_GET_TX_PWR_CMDID); +} + +int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, u8 preamble_policy) +{ + struct sk_buff *skb; + struct wmi_set_lpreamble_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_lpreamble_cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_lpreamble_cmd *) skb->data; + cmd->status = status; + cmd->preamble_policy = preamble_policy; + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_LPREAMBLE_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold) +{ + struct sk_buff *skb; + struct wmi_set_rts_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_rts_cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_rts_cmd *) skb->data; + cmd->threshold = cpu_to_le16(threshold); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_RTS_CMDID, NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg) +{ + struct sk_buff *skb; + struct wmi_set_wmm_txop_cmd *cmd; + int ret; + + if (!((cfg == WMI_TXOP_DISABLED) || (cfg == WMI_TXOP_ENABLED))) + return -EINVAL; + + skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_set_wmm_txop_cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_wmm_txop_cmd *) skb->data; + cmd->txop_enable = cfg; + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_WMM_TXOP_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl) +{ + struct sk_buff *skb; + struct wmi_set_keepalive_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_keepalive_cmd *) skb->data; + cmd->keep_alive_intvl = keep_alive_intvl; + wmi->keep_alive_intvl = keep_alive_intvl; + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_KEEPALIVE_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len) +{ + struct sk_buff *skb; + int ret; + + skb = ath6kl_wmi_get_new_buf(len); + if (!skb) + return -ENOMEM; + + memcpy(skb->data, buf, len); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_TEST_CMDID, NO_SYNC_WMIFLAG); + + return ret; +} + + +s32 ath6kl_wmi_get_rate(s8 rate_index) +{ + if (rate_index == RATE_AUTO) + return 0; + + return wmi_rate_tbl[(u32) rate_index][0]; +} + +static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap, + u32 len) +{ + struct wmi_pmkid_list_reply *reply; + u32 expected_len; + + if (len < sizeof(struct wmi_pmkid_list_reply)) + return -EINVAL; + + reply = (struct wmi_pmkid_list_reply *)datap; + expected_len = sizeof(reply->num_pmkid) + + le32_to_cpu(reply->num_pmkid) * WMI_PMKID_LEN; + + if (len < expected_len) + return -EINVAL; + + return 0; +} + +static int ath6kl_wmi_addba_req_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_addba_req_event *cmd = (struct wmi_addba_req_event *) datap; + + aggr_recv_addba_req_evt(wmi->parent_dev, cmd->tid, + le16_to_cpu(cmd->st_seq_no), cmd->win_sz); + + return 0; +} + +static int ath6kl_wmi_delba_req_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_delba_event *cmd = (struct wmi_delba_event *) datap; + + aggr_recv_delba_req_evt(wmi->parent_dev, cmd->tid); + + return 0; +} + +/* AP mode functions */ + +int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p) +{ + struct sk_buff *skb; + struct wmi_connect_cmd *cm; + int res; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cm)); + if (!skb) + return -ENOMEM; + + cm = (struct wmi_connect_cmd *) skb->data; + memcpy(cm, p, sizeof(*cm)); + + res = ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_CONFIG_COMMIT_CMDID, + NO_SYNC_WMIFLAG); + ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u " + "ctrl_flags=0x%x-> res=%d\n", + __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch), + le32_to_cpu(p->ctrl_flags), res); + return res; +} + +int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason) +{ + struct sk_buff *skb; + struct wmi_ap_set_mlme_cmd *cm; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cm)); + if (!skb) + return -ENOMEM; + + cm = (struct wmi_ap_set_mlme_cmd *) skb->data; + memcpy(cm->mac, mac, ETH_ALEN); + cm->reason = cpu_to_le16(reason); + cm->cmd = cmd; + + return ath6kl_wmi_cmd_send(wmip, skb, WMI_AP_SET_MLME_CMDID, + NO_SYNC_WMIFLAG); +} + +static int ath6kl_wmi_pspoll_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + struct wmi_pspoll_event *ev; + + if (len < sizeof(struct wmi_pspoll_event)) + return -EINVAL; + + ev = (struct wmi_pspoll_event *) datap; + + ath6kl_pspoll_event(wmi->parent_dev, le16_to_cpu(ev->aid)); + + return 0; +} + +static int ath6kl_wmi_dtimexpiry_event_rx(struct wmi *wmi, u8 *datap, int len) +{ + ath6kl_dtimexpiry_event(wmi->parent_dev); + + return 0; +} + +int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag) +{ + struct sk_buff *skb; + struct wmi_ap_set_pvb_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(struct wmi_ap_set_pvb_cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_ap_set_pvb_cmd *) skb->data; + cmd->aid = cpu_to_le16(aid); + cmd->rsvd = cpu_to_le16(0); + cmd->flag = cpu_to_le32(flag); + + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_AP_SET_PVB_CMDID, + NO_SYNC_WMIFLAG); + + return 0; +} + +int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_ver, + bool rx_dot11_hdr, bool defrag_on_host) +{ + struct sk_buff *skb; + struct wmi_rx_frame_format_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_rx_frame_format_cmd *) skb->data; + cmd->dot11_hdr = rx_dot11_hdr ? 1 : 0; + cmd->defrag_on_host = defrag_on_host ? 1 : 0; + cmd->meta_ver = rx_meta_ver; + + /* Delete the local aggr state, on host */ + ret = ath6kl_wmi_cmd_send(wmi, skb, WMI_RX_FRAME_FORMAT_CMDID, + NO_SYNC_WMIFLAG); + + return ret; +} + +int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, + u8 ie_len) +{ + struct sk_buff *skb; + struct wmi_set_appie_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + ie_len); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u " + "ie_len=%u\n", mgmt_frm_type, ie_len); + p = (struct wmi_set_appie_cmd *) skb->data; + p->mgmt_frm_type = mgmt_frm_type; + p->ie_len = ie_len; + memcpy(p->ie_info, ie, ie_len); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_SET_APPIE_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable) +{ + struct sk_buff *skb; + struct wmi_disable_11b_rates_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "disable_11b_rates_cmd: disable=%u\n", + disable); + cmd = (struct wmi_disable_11b_rates_cmd *) skb->data; + cmd->disable = disable ? 1 : 0; + + return ath6kl_wmi_cmd_send(wmi, skb, WMI_DISABLE_11B_RATES_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur) +{ + struct sk_buff *skb; + struct wmi_remain_on_chnl_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl_cmd: freq=%u dur=%u\n", + freq, dur); + p = (struct wmi_remain_on_chnl_cmd *) skb->data; + p->freq = cpu_to_le32(freq); + p->duration = cpu_to_le32(dur); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_REMAIN_ON_CHNL_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait, + const u8 *data, u16 data_len) +{ + struct sk_buff *skb; + struct wmi_send_action_cmd *p; + u8 *buf; + + if (wait) + return -EINVAL; /* Offload for wait not supported */ + + buf = kmalloc(data_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len); + if (!skb) { + kfree(buf); + return -ENOMEM; + } + + kfree(wmi->last_mgmt_tx_frame); + wmi->last_mgmt_tx_frame = buf; + wmi->last_mgmt_tx_frame_len = data_len; + + ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u " + "len=%u\n", id, freq, wait, data_len); + p = (struct wmi_send_action_cmd *) skb->data; + p->id = cpu_to_le32(id); + p->freq = cpu_to_le32(freq); + p->wait = cpu_to_le32(wait); + p->len = cpu_to_le16(data_len); + memcpy(p->data, data, data_len); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_ACTION_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq, + const u8 *dst, + const u8 *data, u16 data_len) +{ + struct sk_buff *skb; + struct wmi_p2p_probe_response_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM " + "len=%u\n", freq, dst, data_len); + p = (struct wmi_p2p_probe_response_cmd *) skb->data; + p->freq = cpu_to_le32(freq); + memcpy(p->destination_addr, dst, ETH_ALEN); + p->len = cpu_to_le16(data_len); + memcpy(p->data, data, data_len); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_SEND_PROBE_RESPONSE_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable) +{ + struct sk_buff *skb; + struct wmi_probe_req_report_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "probe_report_req_cmd: enable=%u\n", + enable); + p = (struct wmi_probe_req_report_cmd *) skb->data; + p->enable = enable ? 1 : 0; + return ath6kl_wmi_cmd_send(wmi, skb, WMI_PROBE_REQ_REPORT_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags) +{ + struct sk_buff *skb; + struct wmi_get_p2p_info *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p)); + if (!skb) + return -ENOMEM; + + ath6kl_dbg(ATH6KL_DBG_WMI, "info_req_cmd: flags=%x\n", + info_req_flags); + p = (struct wmi_get_p2p_info *) skb->data; + p->info_req_flags = cpu_to_le32(info_req_flags); + return ath6kl_wmi_cmd_send(wmi, skb, WMI_GET_P2P_INFO_CMDID, + NO_SYNC_WMIFLAG); +} + +int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi) +{ + ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl_cmd\n"); + return ath6kl_wmi_simple_cmd(wmi, WMI_CANCEL_REMAIN_ON_CHNL_CMDID); +} + +static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb) +{ + struct wmix_cmd_hdr *cmd; + u32 len; + u16 id; + u8 *datap; + int ret = 0; + + if (skb->len < sizeof(struct wmix_cmd_hdr)) { + ath6kl_err("bad packet 1\n"); + wmi->stat.cmd_len_err++; + return -EINVAL; + } + + cmd = (struct wmix_cmd_hdr *) skb->data; + id = le32_to_cpu(cmd->cmd_id); + + skb_pull(skb, sizeof(struct wmix_cmd_hdr)); + + datap = skb->data; + len = skb->len; + + switch (id) { + case WMIX_HB_CHALLENGE_RESP_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n"); + break; + case WMIX_DBGLOG_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len); + ath6kl_debug_fwlog_event(wmi->parent_dev, datap, len); + break; + default: + ath6kl_warn("unknown cmd id 0x%x\n", id); + wmi->stat.cmd_id_err++; + ret = -EINVAL; + break; + } + + return ret; +} + +/* Control Path */ +int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb) +{ + struct wmi_cmd_hdr *cmd; + u32 len; + u16 id; + u8 *datap; + int ret = 0; + + if (WARN_ON(skb == NULL)) + return -EINVAL; + + if (skb->len < sizeof(struct wmi_cmd_hdr)) { + ath6kl_err("bad packet 1\n"); + dev_kfree_skb(skb); + wmi->stat.cmd_len_err++; + return -EINVAL; + } + + cmd = (struct wmi_cmd_hdr *) skb->data; + id = le16_to_cpu(cmd->cmd_id); + + skb_pull(skb, sizeof(struct wmi_cmd_hdr)); + + datap = skb->data; + len = skb->len; + + ath6kl_dbg(ATH6KL_DBG_WMI, "wmi rx id %d len %d\n", id, len); + ath6kl_dbg_dump(ATH6KL_DBG_WMI_DUMP, NULL, "wmi rx ", + datap, len); + + switch (id) { + case WMI_GET_BITRATE_CMDID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_BITRATE_CMDID\n"); + ret = ath6kl_wmi_bitrate_reply_rx(wmi, datap, len); + break; + case WMI_GET_CHANNEL_LIST_CMDID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_CHANNEL_LIST_CMDID\n"); + ret = ath6kl_wmi_ch_list_reply_rx(wmi, datap, len); + break; + case WMI_GET_TX_PWR_CMDID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_TX_PWR_CMDID\n"); + ret = ath6kl_wmi_tx_pwr_reply_rx(wmi, datap, len); + break; + case WMI_READY_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_READY_EVENTID\n"); + ret = ath6kl_wmi_ready_event_rx(wmi, datap, len); + break; + case WMI_CONNECT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CONNECT_EVENTID\n"); + ret = ath6kl_wmi_connect_event_rx(wmi, datap, len); + break; + case WMI_DISCONNECT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DISCONNECT_EVENTID\n"); + ret = ath6kl_wmi_disconnect_event_rx(wmi, datap, len); + break; + case WMI_PEER_NODE_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PEER_NODE_EVENTID\n"); + ret = ath6kl_wmi_peer_node_event_rx(wmi, datap, len); + break; + case WMI_TKIP_MICERR_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TKIP_MICERR_EVENTID\n"); + ret = ath6kl_wmi_tkip_micerr_event_rx(wmi, datap, len); + break; + case WMI_BSSINFO_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_BSSINFO_EVENTID\n"); + ret = ath6kl_wmi_bssinfo_event_rx(wmi, datap, len); + break; + case WMI_REGDOMAIN_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REGDOMAIN_EVENTID\n"); + ath6kl_wmi_regdomain_event(wmi, datap, len); + break; + case WMI_PSTREAM_TIMEOUT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSTREAM_TIMEOUT_EVENTID\n"); + ret = ath6kl_wmi_pstream_timeout_event_rx(wmi, datap, len); + break; + case WMI_NEIGHBOR_REPORT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_NEIGHBOR_REPORT_EVENTID\n"); + ret = ath6kl_wmi_neighbor_report_event_rx(wmi, datap, len); + break; + case WMI_SCAN_COMPLETE_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SCAN_COMPLETE_EVENTID\n"); + ret = ath6kl_wmi_scan_complete_rx(wmi, datap, len); + break; + case WMI_CMDERROR_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CMDERROR_EVENTID\n"); + ret = ath6kl_wmi_error_event_rx(wmi, datap, len); + break; + case WMI_REPORT_STATISTICS_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_STATISTICS_EVENTID\n"); + ret = ath6kl_wmi_stats_event_rx(wmi, datap, len); + break; + case WMI_RSSI_THRESHOLD_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RSSI_THRESHOLD_EVENTID\n"); + ret = ath6kl_wmi_rssi_threshold_event_rx(wmi, datap, len); + break; + case WMI_ERROR_REPORT_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ERROR_REPORT_EVENTID\n"); + break; + case WMI_OPT_RX_FRAME_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_OPT_RX_FRAME_EVENTID\n"); + /* this event has been deprecated */ + break; + case WMI_REPORT_ROAM_TBL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_TBL_EVENTID\n"); + break; + case WMI_EXTENSION_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_EXTENSION_EVENTID\n"); + ret = ath6kl_wmi_control_rx_xtnd(wmi, skb); + break; + case WMI_CAC_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CAC_EVENTID\n"); + ret = ath6kl_wmi_cac_event_rx(wmi, datap, len); + break; + case WMI_CHANNEL_CHANGE_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_CHANNEL_CHANGE_EVENTID\n"); + break; + case WMI_REPORT_ROAM_DATA_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REPORT_ROAM_DATA_EVENTID\n"); + break; + case WMI_TEST_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TEST_EVENTID\n"); + ret = ath6kl_wmi_tcmd_test_report_rx(wmi, datap, len); + break; + case WMI_GET_FIXRATES_CMDID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_FIXRATES_CMDID\n"); + ret = ath6kl_wmi_ratemask_reply_rx(wmi, datap, len); + break; + case WMI_TX_RETRY_ERR_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_RETRY_ERR_EVENTID\n"); + break; + case WMI_SNR_THRESHOLD_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SNR_THRESHOLD_EVENTID\n"); + ret = ath6kl_wmi_snr_threshold_event_rx(wmi, datap, len); + break; + case WMI_LQ_THRESHOLD_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_LQ_THRESHOLD_EVENTID\n"); + break; + case WMI_APLIST_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_APLIST_EVENTID\n"); + ret = ath6kl_wmi_aplist_event_rx(wmi, datap, len); + break; + case WMI_GET_KEEPALIVE_CMDID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_KEEPALIVE_CMDID\n"); + ret = ath6kl_wmi_keepalive_reply_rx(wmi, datap, len); + break; + case WMI_GET_WOW_LIST_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_WOW_LIST_EVENTID\n"); + ret = ath6kl_wmi_get_wow_list_event_rx(wmi, datap, len); + break; + case WMI_GET_PMKID_LIST_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_GET_PMKID_LIST_EVENTID\n"); + ret = ath6kl_wmi_get_pmkid_list_event_rx(wmi, datap, len); + break; + case WMI_PSPOLL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_PSPOLL_EVENTID\n"); + ret = ath6kl_wmi_pspoll_event_rx(wmi, datap, len); + break; + case WMI_DTIMEXPIRY_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DTIMEXPIRY_EVENTID\n"); + ret = ath6kl_wmi_dtimexpiry_event_rx(wmi, datap, len); + break; + case WMI_SET_PARAMS_REPLY_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_SET_PARAMS_REPLY_EVENTID\n"); + break; + case WMI_ADDBA_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_REQ_EVENTID\n"); + ret = ath6kl_wmi_addba_req_event_rx(wmi, datap, len); + break; + case WMI_ADDBA_RESP_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_ADDBA_RESP_EVENTID\n"); + break; + case WMI_DELBA_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_DELBA_REQ_EVENTID\n"); + ret = ath6kl_wmi_delba_req_event_rx(wmi, datap, len); + break; + case WMI_REPORT_BTCOEX_CONFIG_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, + "WMI_REPORT_BTCOEX_CONFIG_EVENTID\n"); + break; + case WMI_REPORT_BTCOEX_STATS_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, + "WMI_REPORT_BTCOEX_STATS_EVENTID\n"); + break; + case WMI_TX_COMPLETE_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_COMPLETE_EVENTID\n"); + ret = ath6kl_wmi_tx_complete_event_rx(datap, len); + break; + case WMI_REMAIN_ON_CHNL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_REMAIN_ON_CHNL_EVENTID\n"); + ret = ath6kl_wmi_remain_on_chnl_event_rx(wmi, datap, len); + break; + case WMI_CANCEL_REMAIN_ON_CHNL_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, + "WMI_CANCEL_REMAIN_ON_CHNL_EVENTID\n"); + ret = ath6kl_wmi_cancel_remain_on_chnl_event_rx(wmi, datap, + len); + break; + case WMI_TX_STATUS_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TX_STATUS_EVENTID\n"); + ret = ath6kl_wmi_tx_status_event_rx(wmi, datap, len); + break; + case WMI_RX_PROBE_REQ_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_PROBE_REQ_EVENTID\n"); + ret = ath6kl_wmi_rx_probe_req_event_rx(wmi, datap, len); + break; + case WMI_P2P_CAPABILITIES_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_CAPABILITIES_EVENTID\n"); + ret = ath6kl_wmi_p2p_capabilities_event_rx(datap, len); + break; + case WMI_RX_ACTION_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n"); + ret = ath6kl_wmi_rx_action_event_rx(wmi, datap, len); + break; + case WMI_P2P_INFO_EVENTID: + ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_P2P_INFO_EVENTID\n"); + ret = ath6kl_wmi_p2p_info_event_rx(datap, len); + break; + default: + ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", id); + wmi->stat.cmd_id_err++; + ret = -EINVAL; + break; + } + + dev_kfree_skb(skb); + + return ret; +} + +static void ath6kl_wmi_qos_state_init(struct wmi *wmi) +{ + if (!wmi) + return; + + spin_lock_bh(&wmi->lock); + + wmi->fat_pipe_exist = 0; + memset(wmi->stream_exist_for_ac, 0, sizeof(wmi->stream_exist_for_ac)); + + spin_unlock_bh(&wmi->lock); +} + +void *ath6kl_wmi_init(struct ath6kl *dev) +{ + struct wmi *wmi; + + wmi = kzalloc(sizeof(struct wmi), GFP_KERNEL); + if (!wmi) + return NULL; + + spin_lock_init(&wmi->lock); + + wmi->parent_dev = dev; + + ath6kl_wmi_qos_state_init(wmi); + + wmi->pwr_mode = REC_POWER; + wmi->phy_mode = WMI_11G_MODE; + + wmi->pair_crypto_type = NONE_CRYPT; + wmi->grp_crypto_type = NONE_CRYPT; + + wmi->ht_allowed[A_BAND_24GHZ] = 1; + wmi->ht_allowed[A_BAND_5GHZ] = 1; + + return wmi; +} + +void ath6kl_wmi_shutdown(struct wmi *wmi) +{ + if (!wmi) + return; + + kfree(wmi->last_mgmt_tx_frame); + kfree(wmi); +} diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h new file mode 100644 index 000000000000..f8e644d54aa7 --- /dev/null +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -0,0 +1,2282 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file contains the definitions of the WMI protocol specified in the + * Wireless Module Interface (WMI). It includes definitions of all the + * commands and events. Commands are messages from the host to the WM. + * Events and Replies are messages from the WM to the host. + */ + +#ifndef WMI_H +#define WMI_H + +#include <linux/ieee80211.h> + +#include "htc.h" + +#define HTC_PROTOCOL_VERSION 0x0002 +#define WMI_PROTOCOL_VERSION 0x0002 +#define WMI_CONTROL_MSG_MAX_LEN 256 +#define is_ethertype(type_or_len) ((type_or_len) >= 0x0600) + +#define IP_ETHERTYPE 0x0800 + +#define WMI_IMPLICIT_PSTREAM 0xFF +#define WMI_MAX_THINSTREAM 15 + +#define SSID_IE_LEN_INDEX 13 + +/* Host side link management data structures */ +#define SIG_QUALITY_THRESH_LVLS 6 +#define SIG_QUALITY_UPPER_THRESH_LVLS SIG_QUALITY_THRESH_LVLS +#define SIG_QUALITY_LOWER_THRESH_LVLS SIG_QUALITY_THRESH_LVLS + +#define A_BAND_24GHZ 0 +#define A_BAND_5GHZ 1 +#define A_NUM_BANDS 2 + +/* in ms */ +#define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000 + +/* + * There are no signed versions of __le16 and __le32, so for a temporary + * solution come up with our own version. The idea is from fs/ntfs/types.h. + * + * Use a_ prefix so that it doesn't conflict if we get proper support to + * linux/types.h. + */ +typedef __s16 __bitwise a_sle16; +typedef __s32 __bitwise a_sle32; + +static inline a_sle32 a_cpu_to_sle32(s32 val) +{ + return (__force a_sle32) cpu_to_le32(val); +} + +static inline s32 a_sle32_to_cpu(a_sle32 val) +{ + return le32_to_cpu((__force __le32) val); +} + +static inline a_sle16 a_cpu_to_sle16(s16 val) +{ + return (__force a_sle16) cpu_to_le16(val); +} + +static inline s16 a_sle16_to_cpu(a_sle16 val) +{ + return le16_to_cpu((__force __le16) val); +} + +struct sq_threshold_params { + s16 upper_threshold[SIG_QUALITY_UPPER_THRESH_LVLS]; + s16 lower_threshold[SIG_QUALITY_LOWER_THRESH_LVLS]; + u32 upper_threshold_valid_count; + u32 lower_threshold_valid_count; + u32 polling_interval; + u8 weight; + u8 last_rssi; + u8 last_rssi_poll_event; +}; + +struct wmi_stats { + u32 cmd_len_err; + u32 cmd_id_err; +}; + +struct wmi_data_sync_bufs { + u8 traffic_class; + struct sk_buff *skb; +}; + +/* WMM stream classes */ +#define WMM_NUM_AC 4 +#define WMM_AC_BE 0 /* best effort */ +#define WMM_AC_BK 1 /* background */ +#define WMM_AC_VI 2 /* video */ +#define WMM_AC_VO 3 /* voice */ + +struct wmi { + bool ready; + u16 stream_exist_for_ac[WMM_NUM_AC]; + u8 fat_pipe_exist; + struct ath6kl *parent_dev; + struct wmi_stats stat; + u8 pwr_mode; + u8 phy_mode; + u8 keep_alive_intvl; + spinlock_t lock; + enum htc_endpoint_id ep_id; + struct sq_threshold_params + sq_threshld[SIGNAL_QUALITY_METRICS_NUM_MAX]; + enum crypto_type pair_crypto_type; + enum crypto_type grp_crypto_type; + bool is_wmm_enabled; + u8 ht_allowed[A_NUM_BANDS]; + u8 traffic_class; + bool is_probe_ssid; + + u8 *last_mgmt_tx_frame; + size_t last_mgmt_tx_frame_len; +}; + +struct host_app_area { + u32 wmi_protocol_ver; +}; + +enum wmi_msg_type { + DATA_MSGTYPE = 0x0, + CNTL_MSGTYPE, + SYNC_MSGTYPE, + OPT_MSGTYPE, +}; + +/* + * Macros for operating on WMI_DATA_HDR (info) field + */ + +#define WMI_DATA_HDR_MSG_TYPE_MASK 0x03 +#define WMI_DATA_HDR_MSG_TYPE_SHIFT 0 +#define WMI_DATA_HDR_UP_MASK 0x07 +#define WMI_DATA_HDR_UP_SHIFT 2 + +/* In AP mode, the same bit (b5) is used to indicate Power save state in + * the Rx dir and More data bit state in the tx direction. + */ +#define WMI_DATA_HDR_PS_MASK 0x1 +#define WMI_DATA_HDR_PS_SHIFT 5 + +#define WMI_DATA_HDR_MORE_MASK 0x1 +#define WMI_DATA_HDR_MORE_SHIFT 5 + +enum wmi_data_hdr_data_type { + WMI_DATA_HDR_DATA_TYPE_802_3 = 0, + WMI_DATA_HDR_DATA_TYPE_802_11, + + /* used to be used for the PAL */ + WMI_DATA_HDR_DATA_TYPE_ACL, +}; + +#define WMI_DATA_HDR_DATA_TYPE_MASK 0x3 +#define WMI_DATA_HDR_DATA_TYPE_SHIFT 6 + +/* Macros for operating on WMI_DATA_HDR (info2) field */ +#define WMI_DATA_HDR_SEQNO_MASK 0xFFF +#define WMI_DATA_HDR_SEQNO_SHIFT 0 + +#define WMI_DATA_HDR_AMSDU_MASK 0x1 +#define WMI_DATA_HDR_AMSDU_SHIFT 12 + +#define WMI_DATA_HDR_META_MASK 0x7 +#define WMI_DATA_HDR_META_SHIFT 13 + +struct wmi_data_hdr { + s8 rssi; + + /* + * usage of 'info' field(8-bit): + * + * b1:b0 - WMI_MSG_TYPE + * b4:b3:b2 - UP(tid) + * b5 - Used in AP mode. + * More-data in tx dir, PS in rx. + * b7:b6 - Dot3 header(0), + * Dot11 Header(1), + * ACL data(2) + */ + u8 info; + + /* + * usage of 'info2' field(16-bit): + * + * b11:b0 - seq_no + * b12 - A-MSDU? + * b15:b13 - META_DATA_VERSION 0 - 7 + */ + __le16 info2; + __le16 info3; +} __packed; + +static inline u8 wmi_data_hdr_get_up(struct wmi_data_hdr *dhdr) +{ + return (dhdr->info >> WMI_DATA_HDR_UP_SHIFT) & WMI_DATA_HDR_UP_MASK; +} + +static inline void wmi_data_hdr_set_up(struct wmi_data_hdr *dhdr, + u8 usr_pri) +{ + dhdr->info &= ~(WMI_DATA_HDR_UP_MASK << WMI_DATA_HDR_UP_SHIFT); + dhdr->info |= usr_pri << WMI_DATA_HDR_UP_SHIFT; +} + +static inline u8 wmi_data_hdr_get_dot11(struct wmi_data_hdr *dhdr) +{ + u8 data_type; + + data_type = (dhdr->info >> WMI_DATA_HDR_DATA_TYPE_SHIFT) & + WMI_DATA_HDR_DATA_TYPE_MASK; + return (data_type == WMI_DATA_HDR_DATA_TYPE_802_11); +} + +static inline u16 wmi_data_hdr_get_seqno(struct wmi_data_hdr *dhdr) +{ + return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_SEQNO_SHIFT) & + WMI_DATA_HDR_SEQNO_MASK; +} + +static inline u8 wmi_data_hdr_is_amsdu(struct wmi_data_hdr *dhdr) +{ + return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_AMSDU_SHIFT) & + WMI_DATA_HDR_AMSDU_MASK; +} + +static inline u8 wmi_data_hdr_get_meta(struct wmi_data_hdr *dhdr) +{ + return (le16_to_cpu(dhdr->info2) >> WMI_DATA_HDR_META_SHIFT) & + WMI_DATA_HDR_META_MASK; +} + +/* Tx meta version definitions */ +#define WMI_MAX_TX_META_SZ 12 +#define WMI_META_VERSION_1 0x01 +#define WMI_META_VERSION_2 0x02 + +struct wmi_tx_meta_v1 { + /* packet ID to identify the tx request */ + u8 pkt_id; + + /* rate policy to be used for the tx of this frame */ + u8 rate_plcy_id; +} __packed; + +struct wmi_tx_meta_v2 { + /* + * Offset from start of the WMI header for csum calculation to + * begin. + */ + u8 csum_start; + + /* offset from start of WMI header where final csum goes */ + u8 csum_dest; + + /* no of bytes over which csum is calculated */ + u8 csum_flags; +} __packed; + +struct wmi_rx_meta_v1 { + u8 status; + + /* rate index mapped to rate at which this packet was received. */ + u8 rix; + + /* rssi of packet */ + u8 rssi; + + /* rf channel during packet reception */ + u8 channel; + + __le16 flags; +} __packed; + +struct wmi_rx_meta_v2 { + __le16 csum; + + /* bit 0 set -partial csum valid bit 1 set -test mode */ + u8 csum_flags; +} __packed; + +/* Control Path */ +struct wmi_cmd_hdr { + __le16 cmd_id; + + /* info1 - 16 bits + * b03:b00 - id + * b15:b04 - unused */ + __le16 info1; + + /* for alignment */ + __le16 reserved; +} __packed; + +/* List of WMI commands */ +enum wmi_cmd_id { + WMI_CONNECT_CMDID = 0x0001, + WMI_RECONNECT_CMDID, + WMI_DISCONNECT_CMDID, + WMI_SYNCHRONIZE_CMDID, + WMI_CREATE_PSTREAM_CMDID, + WMI_DELETE_PSTREAM_CMDID, + WMI_START_SCAN_CMDID, + WMI_SET_SCAN_PARAMS_CMDID, + WMI_SET_BSS_FILTER_CMDID, + WMI_SET_PROBED_SSID_CMDID, /* 10 */ + WMI_SET_LISTEN_INT_CMDID, + WMI_SET_BMISS_TIME_CMDID, + WMI_SET_DISC_TIMEOUT_CMDID, + WMI_GET_CHANNEL_LIST_CMDID, + WMI_SET_BEACON_INT_CMDID, + WMI_GET_STATISTICS_CMDID, + WMI_SET_CHANNEL_PARAMS_CMDID, + WMI_SET_POWER_MODE_CMDID, + WMI_SET_IBSS_PM_CAPS_CMDID, + WMI_SET_POWER_PARAMS_CMDID, /* 20 */ + WMI_SET_POWERSAVE_TIMERS_POLICY_CMDID, + WMI_ADD_CIPHER_KEY_CMDID, + WMI_DELETE_CIPHER_KEY_CMDID, + WMI_ADD_KRK_CMDID, + WMI_DELETE_KRK_CMDID, + WMI_SET_PMKID_CMDID, + WMI_SET_TX_PWR_CMDID, + WMI_GET_TX_PWR_CMDID, + WMI_SET_ASSOC_INFO_CMDID, + WMI_ADD_BAD_AP_CMDID, /* 30 */ + WMI_DELETE_BAD_AP_CMDID, + WMI_SET_TKIP_COUNTERMEASURES_CMDID, + WMI_RSSI_THRESHOLD_PARAMS_CMDID, + WMI_TARGET_ERROR_REPORT_BITMASK_CMDID, + WMI_SET_ACCESS_PARAMS_CMDID, + WMI_SET_RETRY_LIMITS_CMDID, + WMI_SET_OPT_MODE_CMDID, + WMI_OPT_TX_FRAME_CMDID, + WMI_SET_VOICE_PKT_SIZE_CMDID, + WMI_SET_MAX_SP_LEN_CMDID, /* 40 */ + WMI_SET_ROAM_CTRL_CMDID, + WMI_GET_ROAM_TBL_CMDID, + WMI_GET_ROAM_DATA_CMDID, + WMI_ENABLE_RM_CMDID, + WMI_SET_MAX_OFFHOME_DURATION_CMDID, + WMI_EXTENSION_CMDID, /* Non-wireless extensions */ + WMI_SNR_THRESHOLD_PARAMS_CMDID, + WMI_LQ_THRESHOLD_PARAMS_CMDID, + WMI_SET_LPREAMBLE_CMDID, + WMI_SET_RTS_CMDID, /* 50 */ + WMI_CLR_RSSI_SNR_CMDID, + WMI_SET_FIXRATES_CMDID, + WMI_GET_FIXRATES_CMDID, + WMI_SET_AUTH_MODE_CMDID, + WMI_SET_REASSOC_MODE_CMDID, + WMI_SET_WMM_CMDID, + WMI_SET_WMM_TXOP_CMDID, + WMI_TEST_CMDID, + + /* COEX AR6002 only */ + WMI_SET_BT_STATUS_CMDID, + WMI_SET_BT_PARAMS_CMDID, /* 60 */ + + WMI_SET_KEEPALIVE_CMDID, + WMI_GET_KEEPALIVE_CMDID, + WMI_SET_APPIE_CMDID, + WMI_GET_APPIE_CMDID, + WMI_SET_WSC_STATUS_CMDID, + + /* Wake on Wireless */ + WMI_SET_HOST_SLEEP_MODE_CMDID, + WMI_SET_WOW_MODE_CMDID, + WMI_GET_WOW_LIST_CMDID, + WMI_ADD_WOW_PATTERN_CMDID, + WMI_DEL_WOW_PATTERN_CMDID, /* 70 */ + + WMI_SET_FRAMERATES_CMDID, + WMI_SET_AP_PS_CMDID, + WMI_SET_QOS_SUPP_CMDID, + + /* WMI_THIN_RESERVED_... mark the start and end + * values for WMI_THIN_RESERVED command IDs. These + * command IDs can be found in wmi_thin.h */ + WMI_THIN_RESERVED_START = 0x8000, + WMI_THIN_RESERVED_END = 0x8fff, + + /* Developer commands starts at 0xF000 */ + WMI_SET_BITRATE_CMDID = 0xF000, + WMI_GET_BITRATE_CMDID, + WMI_SET_WHALPARAM_CMDID, + WMI_SET_MAC_ADDRESS_CMDID, + WMI_SET_AKMP_PARAMS_CMDID, + WMI_SET_PMKID_LIST_CMDID, + WMI_GET_PMKID_LIST_CMDID, + WMI_ABORT_SCAN_CMDID, + WMI_SET_TARGET_EVENT_REPORT_CMDID, + + /* Unused */ + WMI_UNUSED1, + WMI_UNUSED2, + + /* AP mode commands */ + WMI_AP_HIDDEN_SSID_CMDID, + WMI_AP_SET_NUM_STA_CMDID, + WMI_AP_ACL_POLICY_CMDID, + WMI_AP_ACL_MAC_LIST_CMDID, + WMI_AP_CONFIG_COMMIT_CMDID, + WMI_AP_SET_MLME_CMDID, + WMI_AP_SET_PVB_CMDID, + WMI_AP_CONN_INACT_CMDID, + WMI_AP_PROT_SCAN_TIME_CMDID, + WMI_AP_SET_COUNTRY_CMDID, + WMI_AP_SET_DTIM_CMDID, + WMI_AP_MODE_STAT_CMDID, + + WMI_SET_IP_CMDID, + WMI_SET_PARAMS_CMDID, + WMI_SET_MCAST_FILTER_CMDID, + WMI_DEL_MCAST_FILTER_CMDID, + + WMI_ALLOW_AGGR_CMDID, + WMI_ADDBA_REQ_CMDID, + WMI_DELBA_REQ_CMDID, + WMI_SET_HT_CAP_CMDID, + WMI_SET_HT_OP_CMDID, + WMI_SET_TX_SELECT_RATES_CMDID, + WMI_SET_TX_SGI_PARAM_CMDID, + WMI_SET_RATE_POLICY_CMDID, + + WMI_HCI_CMD_CMDID, + WMI_RX_FRAME_FORMAT_CMDID, + WMI_SET_THIN_MODE_CMDID, + WMI_SET_BT_WLAN_CONN_PRECEDENCE_CMDID, + + WMI_AP_SET_11BG_RATESET_CMDID, + WMI_SET_PMK_CMDID, + WMI_MCAST_FILTER_CMDID, + + /* COEX CMDID AR6003 */ + WMI_SET_BTCOEX_FE_ANT_CMDID, + WMI_SET_BTCOEX_COLOCATED_BT_DEV_CMDID, + WMI_SET_BTCOEX_SCO_CONFIG_CMDID, + WMI_SET_BTCOEX_A2DP_CONFIG_CMDID, + WMI_SET_BTCOEX_ACLCOEX_CONFIG_CMDID, + WMI_SET_BTCOEX_BTINQUIRY_PAGE_CONFIG_CMDID, + WMI_SET_BTCOEX_DEBUG_CMDID, + WMI_SET_BTCOEX_BT_OPERATING_STATUS_CMDID, + WMI_GET_BTCOEX_STATS_CMDID, + WMI_GET_BTCOEX_CONFIG_CMDID, + + WMI_SET_DFS_ENABLE_CMDID, /* F034 */ + WMI_SET_DFS_MINRSSITHRESH_CMDID, + WMI_SET_DFS_MAXPULSEDUR_CMDID, + WMI_DFS_RADAR_DETECTED_CMDID, + + /* P2P commands */ + WMI_P2P_SET_CONFIG_CMDID, /* F038 */ + WMI_WPS_SET_CONFIG_CMDID, + WMI_SET_REQ_DEV_ATTR_CMDID, + WMI_P2P_FIND_CMDID, + WMI_P2P_STOP_FIND_CMDID, + WMI_P2P_GO_NEG_START_CMDID, + WMI_P2P_LISTEN_CMDID, + + WMI_CONFIG_TX_MAC_RULES_CMDID, /* F040 */ + WMI_SET_PROMISCUOUS_MODE_CMDID, + WMI_RX_FRAME_FILTER_CMDID, + WMI_SET_CHANNEL_CMDID, + + /* WAC commands */ + WMI_ENABLE_WAC_CMDID, + WMI_WAC_SCAN_REPLY_CMDID, + WMI_WAC_CTRL_REQ_CMDID, + WMI_SET_DIV_PARAMS_CMDID, + + WMI_GET_PMK_CMDID, + WMI_SET_PASSPHRASE_CMDID, + WMI_SEND_ASSOC_RES_CMDID, + WMI_SET_ASSOC_REQ_RELAY_CMDID, + + /* ACS command, consists of sub-commands */ + WMI_ACS_CTRL_CMDID, + WMI_SET_EXCESS_TX_RETRY_THRES_CMDID, + WMI_SET_TBD_TIME_CMDID, /*added for wmiconfig command for TBD */ + + /* Pktlog cmds */ + WMI_PKTLOG_ENABLE_CMDID, + WMI_PKTLOG_DISABLE_CMDID, + + /* More P2P Cmds */ + WMI_P2P_GO_NEG_REQ_RSP_CMDID, + WMI_P2P_GRP_INIT_CMDID, + WMI_P2P_GRP_FORMATION_DONE_CMDID, + WMI_P2P_INVITE_CMDID, + WMI_P2P_INVITE_REQ_RSP_CMDID, + WMI_P2P_PROV_DISC_REQ_CMDID, + WMI_P2P_SET_CMDID, + + WMI_GET_RFKILL_MODE_CMDID, + WMI_SET_RFKILL_MODE_CMDID, + WMI_AP_SET_APSD_CMDID, + WMI_AP_APSD_BUFFERED_TRAFFIC_CMDID, + + WMI_P2P_SDPD_TX_CMDID, /* F05C */ + WMI_P2P_STOP_SDPD_CMDID, + WMI_P2P_CANCEL_CMDID, + /* Ultra low power store / recall commands */ + WMI_STORERECALL_CONFIGURE_CMDID, + WMI_STORERECALL_RECALL_CMDID, + WMI_STORERECALL_HOST_READY_CMDID, + WMI_FORCE_TARGET_ASSERT_CMDID, + + WMI_SET_PROBED_SSID_EX_CMDID, + WMI_SET_NETWORK_LIST_OFFLOAD_CMDID, + WMI_SET_ARP_NS_OFFLOAD_CMDID, + WMI_ADD_WOW_EXT_PATTERN_CMDID, + WMI_GTK_OFFLOAD_OP_CMDID, + WMI_REMAIN_ON_CHNL_CMDID, + WMI_CANCEL_REMAIN_ON_CHNL_CMDID, + WMI_SEND_ACTION_CMDID, + WMI_PROBE_REQ_REPORT_CMDID, + WMI_DISABLE_11B_RATES_CMDID, + WMI_SEND_PROBE_RESPONSE_CMDID, + WMI_GET_P2P_INFO_CMDID, + WMI_AP_JOIN_BSS_CMDID, +}; + +enum wmi_mgmt_frame_type { + WMI_FRAME_BEACON = 0, + WMI_FRAME_PROBE_REQ, + WMI_FRAME_PROBE_RESP, + WMI_FRAME_ASSOC_REQ, + WMI_FRAME_ASSOC_RESP, + WMI_NUM_MGMT_FRAME +}; + +/* WMI_CONNECT_CMDID */ +enum network_type { + INFRA_NETWORK = 0x01, + ADHOC_NETWORK = 0x02, + ADHOC_CREATOR = 0x04, + AP_NETWORK = 0x10, +}; + +enum dot11_auth_mode { + OPEN_AUTH = 0x01, + SHARED_AUTH = 0x02, + + /* different from IEEE_AUTH_MODE definitions */ + LEAP_AUTH = 0x04, +}; + +enum auth_mode { + NONE_AUTH = 0x01, + WPA_AUTH = 0x02, + WPA2_AUTH = 0x04, + WPA_PSK_AUTH = 0x08, + WPA2_PSK_AUTH = 0x10, + WPA_AUTH_CCKM = 0x20, + WPA2_AUTH_CCKM = 0x40, +}; + +#define WMI_MIN_CRYPTO_TYPE NONE_CRYPT +#define WMI_MAX_CRYPTO_TYPE (AES_CRYPT + 1) + +#define WMI_MIN_KEY_INDEX 0 +#define WMI_MAX_KEY_INDEX 3 + +#define WMI_MAX_KEY_LEN 32 + +/* + * NB: these values are ordered carefully; there are lots of + * of implications in any reordering. In particular beware + * that 4 is not used to avoid conflicting with IEEE80211_F_PRIVACY. + */ +#define ATH6KL_CIPHER_WEP 0 +#define ATH6KL_CIPHER_TKIP 1 +#define ATH6KL_CIPHER_AES_OCB 2 +#define ATH6KL_CIPHER_AES_CCM 3 +#define ATH6KL_CIPHER_CKIP 5 +#define ATH6KL_CIPHER_CCKM_KRK 6 +#define ATH6KL_CIPHER_NONE 7 /* pseudo value */ + +/* + * 802.11 rate set. + */ +#define ATH6KL_RATE_MAXSIZE 15 /* max rates we'll handle */ + +#define ATH_OUI_TYPE 0x01 +#define WPA_OUI_TYPE 0x01 +#define WMM_PARAM_OUI_SUBTYPE 0x01 +#define WMM_OUI_TYPE 0x02 +#define WSC_OUT_TYPE 0x04 + +enum wmi_connect_ctrl_flags_bits { + CONNECT_ASSOC_POLICY_USER = 0x0001, + CONNECT_SEND_REASSOC = 0x0002, + CONNECT_IGNORE_WPAx_GROUP_CIPHER = 0x0004, + CONNECT_PROFILE_MATCH_DONE = 0x0008, + CONNECT_IGNORE_AAC_BEACON = 0x0010, + CONNECT_CSA_FOLLOW_BSS = 0x0020, + CONNECT_DO_WPA_OFFLOAD = 0x0040, + CONNECT_DO_NOT_DEAUTH = 0x0080, +}; + +struct wmi_connect_cmd { + u8 nw_type; + u8 dot11_auth_mode; + u8 auth_mode; + u8 prwise_crypto_type; + u8 prwise_crypto_len; + u8 grp_crypto_type; + u8 grp_crypto_len; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + __le16 ch; + u8 bssid[ETH_ALEN]; + __le32 ctrl_flags; +} __packed; + +/* WMI_RECONNECT_CMDID */ +struct wmi_reconnect_cmd { + /* channel hint */ + __le16 channel; + + /* mandatory if set */ + u8 bssid[ETH_ALEN]; +} __packed; + +/* WMI_ADD_CIPHER_KEY_CMDID */ +enum key_usage { + PAIRWISE_USAGE = 0x00, + GROUP_USAGE = 0x01, + + /* default Tx Key - static WEP only */ + TX_USAGE = 0x02, +}; + +/* + * Bit Flag + * Bit 0 - Initialise TSC - default is Initialize + */ +#define KEY_OP_INIT_TSC 0x01 +#define KEY_OP_INIT_RSC 0x02 + +/* default initialise the TSC & RSC */ +#define KEY_OP_INIT_VAL 0x03 +#define KEY_OP_VALID_MASK 0x03 + +struct wmi_add_cipher_key_cmd { + u8 key_index; + u8 key_type; + + /* enum key_usage */ + u8 key_usage; + + u8 key_len; + + /* key replay sequence counter */ + u8 key_rsc[8]; + + u8 key[WLAN_MAX_KEY_LEN]; + + /* additional key control info */ + u8 key_op_ctrl; + + u8 key_mac_addr[ETH_ALEN]; +} __packed; + +/* WMI_DELETE_CIPHER_KEY_CMDID */ +struct wmi_delete_cipher_key_cmd { + u8 key_index; +} __packed; + +#define WMI_KRK_LEN 16 + +/* WMI_ADD_KRK_CMDID */ +struct wmi_add_krk_cmd { + u8 krk[WMI_KRK_LEN]; +} __packed; + +/* WMI_SETPMKID_CMDID */ + +#define WMI_PMKID_LEN 16 + +enum pmkid_enable_flg { + PMKID_DISABLE = 0, + PMKID_ENABLE = 1, +}; + +struct wmi_setpmkid_cmd { + u8 bssid[ETH_ALEN]; + + /* enum pmkid_enable_flg */ + u8 enable; + + u8 pmkid[WMI_PMKID_LEN]; +} __packed; + +/* WMI_START_SCAN_CMD */ +enum wmi_scan_type { + WMI_LONG_SCAN = 0, + WMI_SHORT_SCAN = 1, +}; + +struct wmi_start_scan_cmd { + __le32 force_fg_scan; + + /* for legacy cisco AP compatibility */ + __le32 is_legacy; + + /* max duration in the home channel(msec) */ + __le32 home_dwell_time; + + /* time interval between scans (msec) */ + __le32 force_scan_intvl; + + /* enum wmi_scan_type */ + u8 scan_type; + + /* how many channels follow */ + u8 num_ch; + + /* channels in Mhz */ + __le16 ch_list[1]; +} __packed; + +/* WMI_SET_SCAN_PARAMS_CMDID */ +#define WMI_SHORTSCANRATIO_DEFAULT 3 + +/* + * Warning: scan control flag value of 0xFF is used to disable + * all flags in WMI_SCAN_PARAMS_CMD. Do not add any more + * flags here + */ +enum wmi_scan_ctrl_flags_bits { + + /* set if can scan in the connect cmd */ + CONNECT_SCAN_CTRL_FLAGS = 0x01, + + /* set if scan for the SSID it is already connected to */ + SCAN_CONNECTED_CTRL_FLAGS = 0x02, + + /* set if enable active scan */ + ACTIVE_SCAN_CTRL_FLAGS = 0x04, + + /* set if enable roam scan when bmiss and lowrssi */ + ROAM_SCAN_CTRL_FLAGS = 0x08, + + /* set if follows customer BSSINFO reporting rule */ + REPORT_BSSINFO_CTRL_FLAGS = 0x10, + + /* if disabled, target doesn't scan after a disconnect event */ + ENABLE_AUTO_CTRL_FLAGS = 0x20, + + /* + * Scan complete event with canceled status will be generated when + * a scan is prempted before it gets completed. + */ + ENABLE_SCAN_ABORT_EVENT = 0x40 +}; + +#define DEFAULT_SCAN_CTRL_FLAGS \ + (CONNECT_SCAN_CTRL_FLAGS | \ + SCAN_CONNECTED_CTRL_FLAGS | \ + ACTIVE_SCAN_CTRL_FLAGS | \ + ROAM_SCAN_CTRL_FLAGS | \ + ENABLE_AUTO_CTRL_FLAGS) + +struct wmi_scan_params_cmd { + /* sec */ + __le16 fg_start_period; + + /* sec */ + __le16 fg_end_period; + + /* sec */ + __le16 bg_period; + + /* msec */ + __le16 maxact_chdwell_time; + + /* msec */ + __le16 pas_chdwell_time; + + /* how many shorts scan for one long */ + u8 short_scan_ratio; + + u8 scan_ctrl_flags; + + /* msec */ + __le16 minact_chdwell_time; + + /* max active scans per ssid */ + __le16 maxact_scan_per_ssid; + + /* msecs */ + __le32 max_dfsch_act_time; +} __packed; + +/* WMI_SET_BSS_FILTER_CMDID */ +enum wmi_bss_filter { + /* no beacons forwarded */ + NONE_BSS_FILTER = 0x0, + + /* all beacons forwarded */ + ALL_BSS_FILTER, + + /* only beacons matching profile */ + PROFILE_FILTER, + + /* all but beacons matching profile */ + ALL_BUT_PROFILE_FILTER, + + /* only beacons matching current BSS */ + CURRENT_BSS_FILTER, + + /* all but beacons matching BSS */ + ALL_BUT_BSS_FILTER, + + /* beacons matching probed ssid */ + PROBED_SSID_FILTER, + + /* marker only */ + LAST_BSS_FILTER, +}; + +struct wmi_bss_filter_cmd { + /* see, enum wmi_bss_filter */ + u8 bss_filter; + + /* for alignment */ + u8 reserved1; + + /* for alignment */ + __le16 reserved2; + + __le32 ie_mask; +} __packed; + +/* WMI_SET_PROBED_SSID_CMDID */ +#define MAX_PROBED_SSID_INDEX 9 + +enum wmi_ssid_flag { + /* disables entry */ + DISABLE_SSID_FLAG = 0, + + /* probes specified ssid */ + SPECIFIC_SSID_FLAG = 0x01, + + /* probes for any ssid */ + ANY_SSID_FLAG = 0x02, +}; + +struct wmi_probed_ssid_cmd { + /* 0 to MAX_PROBED_SSID_INDEX */ + u8 entry_index; + + /* see, enum wmi_ssid_flg */ + u8 flag; + + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +} __packed; + +/* + * WMI_SET_LISTEN_INT_CMDID + * The Listen interval is between 15 and 3000 TUs + */ +struct wmi_listen_int_cmd { + __le16 listen_intvl; + __le16 num_beacons; +} __packed; + +/* WMI_SET_POWER_MODE_CMDID */ +enum wmi_power_mode { + REC_POWER = 0x01, + MAX_PERF_POWER, +}; + +struct wmi_power_mode_cmd { + /* see, enum wmi_power_mode */ + u8 pwr_mode; +} __packed; + +/* + * Policy to determnine whether power save failure event should be sent to + * host during scanning + */ +enum power_save_fail_event_policy { + SEND_POWER_SAVE_FAIL_EVENT_ALWAYS = 1, + IGNORE_POWER_SAVE_FAIL_EVENT_DURING_SCAN = 2, +}; + +struct wmi_power_params_cmd { + /* msec */ + __le16 idle_period; + + __le16 pspoll_number; + __le16 dtim_policy; + __le16 tx_wakeup_policy; + __le16 num_tx_to_wakeup; + __le16 ps_fail_event_policy; +} __packed; + +/* WMI_SET_DISC_TIMEOUT_CMDID */ +struct wmi_disc_timeout_cmd { + /* seconds */ + u8 discon_timeout; +} __packed; + +enum dir_type { + UPLINK_TRAFFIC = 0, + DNLINK_TRAFFIC = 1, + BIDIR_TRAFFIC = 2, +}; + +enum voiceps_cap_type { + DISABLE_FOR_THIS_AC = 0, + ENABLE_FOR_THIS_AC = 1, + ENABLE_FOR_ALL_AC = 2, +}; + +enum traffic_type { + TRAFFIC_TYPE_APERIODIC = 0, + TRAFFIC_TYPE_PERIODIC = 1, +}; + +/* WMI_SYNCHRONIZE_CMDID */ +struct wmi_sync_cmd { + u8 data_sync_map; +} __packed; + +/* WMI_CREATE_PSTREAM_CMDID */ +struct wmi_create_pstream_cmd { + /* msec */ + __le32 min_service_int; + + /* msec */ + __le32 max_service_int; + + /* msec */ + __le32 inactivity_int; + + /* msec */ + __le32 suspension_int; + + __le32 service_start_time; + + /* in bps */ + __le32 min_data_rate; + + /* in bps */ + __le32 mean_data_rate; + + /* in bps */ + __le32 peak_data_rate; + + __le32 max_burst_size; + __le32 delay_bound; + + /* in bps */ + __le32 min_phy_rate; + + __le32 sba; + __le32 medium_time; + + /* in octects */ + __le16 nominal_msdu; + + /* in octects */ + __le16 max_msdu; + + u8 traffic_class; + + /* see, enum dir_type */ + u8 traffic_direc; + + u8 rx_queue_num; + + /* see, enum traffic_type */ + u8 traffic_type; + + /* see, enum voiceps_cap_type */ + u8 voice_psc_cap; + u8 tsid; + + /* 802.1D user priority */ + u8 user_pri; + + /* nominal phy rate */ + u8 nominal_phy; +} __packed; + +/* WMI_DELETE_PSTREAM_CMDID */ +struct wmi_delete_pstream_cmd { + u8 tx_queue_num; + u8 rx_queue_num; + u8 traffic_direc; + u8 traffic_class; + u8 tsid; +} __packed; + +/* WMI_SET_CHANNEL_PARAMS_CMDID */ +enum wmi_phy_mode { + WMI_11A_MODE = 0x1, + WMI_11G_MODE = 0x2, + WMI_11AG_MODE = 0x3, + WMI_11B_MODE = 0x4, + WMI_11GONLY_MODE = 0x5, +}; + +#define WMI_MAX_CHANNELS 32 + +/* + * WMI_RSSI_THRESHOLD_PARAMS_CMDID + * Setting the polltime to 0 would disable polling. Threshold values are + * in the ascending order, and should agree to: + * (lowThreshold_lowerVal < lowThreshold_upperVal < highThreshold_lowerVal + * < highThreshold_upperVal) + */ + +struct wmi_rssi_threshold_params_cmd { + /* polling time as a factor of LI */ + __le32 poll_time; + + /* lowest of upper */ + a_sle16 thresh_above1_val; + + a_sle16 thresh_above2_val; + a_sle16 thresh_above3_val; + a_sle16 thresh_above4_val; + a_sle16 thresh_above5_val; + + /* highest of upper */ + a_sle16 thresh_above6_val; + + /* lowest of bellow */ + a_sle16 thresh_below1_val; + + a_sle16 thresh_below2_val; + a_sle16 thresh_below3_val; + a_sle16 thresh_below4_val; + a_sle16 thresh_below5_val; + + /* highest of bellow */ + a_sle16 thresh_below6_val; + + /* "alpha" */ + u8 weight; + + u8 reserved[3]; +} __packed; + +/* + * WMI_SNR_THRESHOLD_PARAMS_CMDID + * Setting the polltime to 0 would disable polling. + */ + +struct wmi_snr_threshold_params_cmd { + /* polling time as a factor of LI */ + __le32 poll_time; + + /* "alpha" */ + u8 weight; + + /* lowest of uppper */ + u8 thresh_above1_val; + + u8 thresh_above2_val; + u8 thresh_above3_val; + + /* highest of upper */ + u8 thresh_above4_val; + + /* lowest of bellow */ + u8 thresh_below1_val; + + u8 thresh_below2_val; + u8 thresh_below3_val; + + /* highest of bellow */ + u8 thresh_below4_val; + + u8 reserved[3]; +} __packed; + +enum wmi_preamble_policy { + WMI_IGNORE_BARKER_IN_ERP = 0, + WMI_DONOT_IGNORE_BARKER_IN_ERP +}; + +struct wmi_set_lpreamble_cmd { + u8 status; + u8 preamble_policy; +} __packed; + +struct wmi_set_rts_cmd { + __le16 threshold; +} __packed; + +/* WMI_SET_TX_PWR_CMDID */ +struct wmi_set_tx_pwr_cmd { + /* in dbM units */ + u8 dbM; +} __packed; + +struct wmi_tx_pwr_reply { + /* in dbM units */ + u8 dbM; +} __packed; + +struct wmi_report_sleep_state_event { + __le32 sleep_state; +}; + +enum wmi_report_sleep_status { + WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP = 0, + WMI_REPORT_SLEEP_STATUS_IS_AWAKE +}; +enum target_event_report_config { + /* default */ + DISCONN_EVT_IN_RECONN = 0, + + NO_DISCONN_EVT_IN_RECONN +}; + +/* Command Replies */ + +/* WMI_GET_CHANNEL_LIST_CMDID reply */ +struct wmi_channel_list_reply { + u8 reserved; + + /* number of channels in reply */ + u8 num_ch; + + /* channel in Mhz */ + __le16 ch_list[1]; +} __packed; + +/* List of Events (target to host) */ +enum wmi_event_id { + WMI_READY_EVENTID = 0x1001, + WMI_CONNECT_EVENTID, + WMI_DISCONNECT_EVENTID, + WMI_BSSINFO_EVENTID, + WMI_CMDERROR_EVENTID, + WMI_REGDOMAIN_EVENTID, + WMI_PSTREAM_TIMEOUT_EVENTID, + WMI_NEIGHBOR_REPORT_EVENTID, + WMI_TKIP_MICERR_EVENTID, + WMI_SCAN_COMPLETE_EVENTID, /* 0x100a */ + WMI_REPORT_STATISTICS_EVENTID, + WMI_RSSI_THRESHOLD_EVENTID, + WMI_ERROR_REPORT_EVENTID, + WMI_OPT_RX_FRAME_EVENTID, + WMI_REPORT_ROAM_TBL_EVENTID, + WMI_EXTENSION_EVENTID, + WMI_CAC_EVENTID, + WMI_SNR_THRESHOLD_EVENTID, + WMI_LQ_THRESHOLD_EVENTID, + WMI_TX_RETRY_ERR_EVENTID, /* 0x1014 */ + WMI_REPORT_ROAM_DATA_EVENTID, + WMI_TEST_EVENTID, + WMI_APLIST_EVENTID, + WMI_GET_WOW_LIST_EVENTID, + WMI_GET_PMKID_LIST_EVENTID, + WMI_CHANNEL_CHANGE_EVENTID, + WMI_PEER_NODE_EVENTID, + WMI_PSPOLL_EVENTID, + WMI_DTIMEXPIRY_EVENTID, + WMI_WLAN_VERSION_EVENTID, + WMI_SET_PARAMS_REPLY_EVENTID, + WMI_ADDBA_REQ_EVENTID, /*0x1020 */ + WMI_ADDBA_RESP_EVENTID, + WMI_DELBA_REQ_EVENTID, + WMI_TX_COMPLETE_EVENTID, + WMI_HCI_EVENT_EVENTID, + WMI_ACL_DATA_EVENTID, + WMI_REPORT_SLEEP_STATE_EVENTID, + WMI_REPORT_BTCOEX_STATS_EVENTID, + WMI_REPORT_BTCOEX_CONFIG_EVENTID, + WMI_GET_PMK_EVENTID, + + /* DFS Events */ + WMI_DFS_HOST_ATTACH_EVENTID, + WMI_DFS_HOST_INIT_EVENTID, + WMI_DFS_RESET_DELAYLINES_EVENTID, + WMI_DFS_RESET_RADARQ_EVENTID, + WMI_DFS_RESET_AR_EVENTID, + WMI_DFS_RESET_ARQ_EVENTID, + WMI_DFS_SET_DUR_MULTIPLIER_EVENTID, + WMI_DFS_SET_BANGRADAR_EVENTID, + WMI_DFS_SET_DEBUGLEVEL_EVENTID, + WMI_DFS_PHYERR_EVENTID, + + /* CCX Evants */ + WMI_CCX_RM_STATUS_EVENTID, + + /* P2P Events */ + WMI_P2P_GO_NEG_RESULT_EVENTID, + + WMI_WAC_SCAN_DONE_EVENTID, + WMI_WAC_REPORT_BSS_EVENTID, + WMI_WAC_START_WPS_EVENTID, + WMI_WAC_CTRL_REQ_REPLY_EVENTID, + + WMI_REPORT_WMM_PARAMS_EVENTID, + WMI_WAC_REJECT_WPS_EVENTID, + + /* More P2P Events */ + WMI_P2P_GO_NEG_REQ_EVENTID, + WMI_P2P_INVITE_REQ_EVENTID, + WMI_P2P_INVITE_RCVD_RESULT_EVENTID, + WMI_P2P_INVITE_SENT_RESULT_EVENTID, + WMI_P2P_PROV_DISC_RESP_EVENTID, + WMI_P2P_PROV_DISC_REQ_EVENTID, + + /* RFKILL Events */ + WMI_RFKILL_STATE_CHANGE_EVENTID, + WMI_RFKILL_GET_MODE_CMD_EVENTID, + + WMI_P2P_START_SDPD_EVENTID, + WMI_P2P_SDPD_RX_EVENTID, + + WMI_THIN_RESERVED_START_EVENTID = 0x8000, + /* Events in this range are reserved for thinmode */ + WMI_THIN_RESERVED_END_EVENTID = 0x8fff, + + WMI_SET_CHANNEL_EVENTID, + WMI_ASSOC_REQ_EVENTID, + + /* Generic ACS event */ + WMI_ACS_EVENTID, + WMI_STORERECALL_STORE_EVENTID, + WMI_WOW_EXT_WAKE_EVENTID, + WMI_GTK_OFFLOAD_STATUS_EVENTID, + WMI_NETWORK_LIST_OFFLOAD_EVENTID, + WMI_REMAIN_ON_CHNL_EVENTID, + WMI_CANCEL_REMAIN_ON_CHNL_EVENTID, + WMI_TX_STATUS_EVENTID, + WMI_RX_PROBE_REQ_EVENTID, + WMI_P2P_CAPABILITIES_EVENTID, + WMI_RX_ACTION_EVENTID, + WMI_P2P_INFO_EVENTID, +}; + +struct wmi_ready_event_2 { + __le32 sw_version; + __le32 abi_version; + u8 mac_addr[ETH_ALEN]; + u8 phy_cap; +} __packed; + +/* Connect Event */ +struct wmi_connect_event { + union { + struct { + __le16 ch; + u8 bssid[ETH_ALEN]; + __le16 listen_intvl; + __le16 beacon_intvl; + __le32 nw_type; + } sta; + struct { + u8 phymode; + u8 aid; + u8 mac_addr[ETH_ALEN]; + u8 auth; + u8 keymgmt; + __le16 cipher; + u8 apsd_info; + u8 unused[3]; + } ap_sta; + struct { + __le16 ch; + u8 bssid[ETH_ALEN]; + u8 unused[8]; + } ap_bss; + } u; + u8 beacon_ie_len; + u8 assoc_req_len; + u8 assoc_resp_len; + u8 assoc_info[1]; +} __packed; + +/* Disconnect Event */ +enum wmi_disconnect_reason { + NO_NETWORK_AVAIL = 0x01, + + /* bmiss */ + LOST_LINK = 0x02, + + DISCONNECT_CMD = 0x03, + BSS_DISCONNECTED = 0x04, + AUTH_FAILED = 0x05, + ASSOC_FAILED = 0x06, + NO_RESOURCES_AVAIL = 0x07, + CSERV_DISCONNECT = 0x08, + INVALID_PROFILE = 0x0a, + DOT11H_CHANNEL_SWITCH = 0x0b, + PROFILE_MISMATCH = 0x0c, + CONNECTION_EVICTED = 0x0d, + IBSS_MERGE = 0xe, +}; + +#define ATH6KL_COUNTRY_RD_SHIFT 16 + +struct ath6kl_wmi_regdomain { + __le32 reg_code; +}; + +struct wmi_disconnect_event { + /* reason code, see 802.11 spec. */ + __le16 proto_reason_status; + + /* set if known */ + u8 bssid[ETH_ALEN]; + + /* see WMI_DISCONNECT_REASON */ + u8 disconn_reason; + + u8 assoc_resp_len; + u8 assoc_info[1]; +} __packed; + +/* + * BSS Info Event. + * Mechanism used to inform host of the presence and characteristic of + * wireless networks present. Consists of bss info header followed by + * the beacon or probe-response frame body. The 802.11 header is no included. + */ +enum wmi_bi_ftype { + BEACON_FTYPE = 0x1, + PROBERESP_FTYPE, + ACTION_MGMT_FTYPE, + PROBEREQ_FTYPE, +}; + +#define DEF_LRSSI_SCAN_PERIOD 5 +#define DEF_LRSSI_ROAM_THRESHOLD 20 +#define DEF_LRSSI_ROAM_FLOOR 60 +#define DEF_SCAN_FOR_ROAM_INTVL 2 + +enum wmi_roam_ctrl { + WMI_FORCE_ROAM = 1, + WMI_SET_ROAM_MODE, + WMI_SET_HOST_BIAS, + WMI_SET_LRSSI_SCAN_PARAMS, +}; + +struct bss_bias { + u8 bssid[ETH_ALEN]; + u8 bias; +} __packed; + +struct bss_bias_info { + u8 num_bss; + struct bss_bias bss_bias[1]; +} __packed; + +struct low_rssi_scan_params { + __le16 lrssi_scan_period; + a_sle16 lrssi_scan_threshold; + a_sle16 lrssi_roam_threshold; + u8 roam_rssi_floor; + u8 reserved[1]; +} __packed; + +struct roam_ctrl_cmd { + union { + u8 bssid[ETH_ALEN]; + u8 roam_mode; + struct bss_bias_info bss; + struct low_rssi_scan_params params; + } __packed info; + u8 roam_ctrl; +} __packed; + +/* BSS INFO HDR version 2.0 */ +struct wmi_bss_info_hdr2 { + __le16 ch; /* frequency in MHz */ + + /* see, enum wmi_bi_ftype */ + u8 frame_type; + + u8 snr; /* note: rssi = snr - 95 dBm */ + u8 bssid[ETH_ALEN]; + __le16 ie_mask; +} __packed; + +/* Command Error Event */ +enum wmi_error_code { + INVALID_PARAM = 0x01, + ILLEGAL_STATE = 0x02, + INTERNAL_ERROR = 0x03, +}; + +struct wmi_cmd_error_event { + __le16 cmd_id; + u8 err_code; +} __packed; + +struct wmi_pstream_timeout_event { + u8 tx_queue_num; + u8 rx_queue_num; + u8 traffic_direc; + u8 traffic_class; +} __packed; + +/* + * The WMI_NEIGHBOR_REPORT Event is generated by the target to inform + * the host of BSS's it has found that matches the current profile. + * It can be used by the host to cache PMKs and/to initiate pre-authentication + * if the BSS supports it. The first bssid is always the current associated + * BSS. + * The bssid and bssFlags information repeats according to the number + * or APs reported. + */ +enum wmi_bss_flags { + WMI_DEFAULT_BSS_FLAGS = 0x00, + WMI_PREAUTH_CAPABLE_BSS = 0x01, + WMI_PMKID_VALID_BSS = 0x02, +}; + +struct wmi_neighbor_info { + u8 bssid[ETH_ALEN]; + u8 bss_flags; /* enum wmi_bss_flags */ +} __packed; + +struct wmi_neighbor_report_event { + u8 num_neighbors; + struct wmi_neighbor_info neighbor[0]; +} __packed; + +/* TKIP MIC Error Event */ +struct wmi_tkip_micerr_event { + u8 key_id; + u8 is_mcast; +} __packed; + +/* WMI_SCAN_COMPLETE_EVENTID */ +struct wmi_scan_complete_event { + a_sle32 status; +} __packed; + +#define MAX_OPT_DATA_LEN 1400 + +/* + * Special frame receive Event. + * Mechanism used to inform host of the receiption of the special frames. + * Consists of special frame info header followed by special frame body. + * The 802.11 header is not included. + */ +struct wmi_opt_rx_info_hdr { + __le16 ch; + u8 frame_type; + s8 snr; + u8 src_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; +} __packed; + +/* Reporting statistic */ +struct tx_stats { + __le32 pkt; + __le32 byte; + __le32 ucast_pkt; + __le32 ucast_byte; + __le32 mcast_pkt; + __le32 mcast_byte; + __le32 bcast_pkt; + __le32 bcast_byte; + __le32 rts_success_cnt; + __le32 pkt_per_ac[4]; + __le32 err_per_ac[4]; + + __le32 err; + __le32 fail_cnt; + __le32 retry_cnt; + __le32 mult_retry_cnt; + __le32 rts_fail_cnt; + a_sle32 ucast_rate; +} __packed; + +struct rx_stats { + __le32 pkt; + __le32 byte; + __le32 ucast_pkt; + __le32 ucast_byte; + __le32 mcast_pkt; + __le32 mcast_byte; + __le32 bcast_pkt; + __le32 bcast_byte; + __le32 frgment_pkt; + + __le32 err; + __le32 crc_err; + __le32 key_cache_miss; + __le32 decrypt_err; + __le32 dupl_frame; + a_sle32 ucast_rate; +} __packed; + +struct tkip_ccmp_stats { + __le32 tkip_local_mic_fail; + __le32 tkip_cnter_measures_invoked; + __le32 tkip_replays; + __le32 tkip_fmt_err; + __le32 ccmp_fmt_err; + __le32 ccmp_replays; +} __packed; + +struct pm_stats { + __le32 pwr_save_failure_cnt; + __le16 stop_tx_failure_cnt; + __le16 atim_tx_failure_cnt; + __le16 atim_rx_failure_cnt; + __le16 bcn_rx_failure_cnt; +} __packed; + +struct cserv_stats { + __le32 cs_bmiss_cnt; + __le32 cs_low_rssi_cnt; + __le16 cs_connect_cnt; + __le16 cs_discon_cnt; + a_sle16 cs_ave_beacon_rssi; + __le16 cs_roam_count; + a_sle16 cs_rssi; + u8 cs_snr; + u8 cs_ave_beacon_snr; + u8 cs_last_roam_msec; +} __packed; + +struct wlan_net_stats { + struct tx_stats tx; + struct rx_stats rx; + struct tkip_ccmp_stats tkip_ccmp_stats; +} __packed; + +struct arp_stats { + __le32 arp_received; + __le32 arp_matched; + __le32 arp_replied; +} __packed; + +struct wlan_wow_stats { + __le32 wow_pkt_dropped; + __le16 wow_evt_discarded; + u8 wow_host_pkt_wakeups; + u8 wow_host_evt_wakeups; +} __packed; + +struct wmi_target_stats { + __le32 lq_val; + a_sle32 noise_floor_calib; + struct pm_stats pm_stats; + struct wlan_net_stats stats; + struct wlan_wow_stats wow_stats; + struct arp_stats arp_stats; + struct cserv_stats cserv_stats; +} __packed; + +/* + * WMI_RSSI_THRESHOLD_EVENTID. + * Indicate the RSSI events to host. Events are indicated when we breach a + * thresold value. + */ +enum wmi_rssi_threshold_val { + WMI_RSSI_THRESHOLD1_ABOVE = 0, + WMI_RSSI_THRESHOLD2_ABOVE, + WMI_RSSI_THRESHOLD3_ABOVE, + WMI_RSSI_THRESHOLD4_ABOVE, + WMI_RSSI_THRESHOLD5_ABOVE, + WMI_RSSI_THRESHOLD6_ABOVE, + WMI_RSSI_THRESHOLD1_BELOW, + WMI_RSSI_THRESHOLD2_BELOW, + WMI_RSSI_THRESHOLD3_BELOW, + WMI_RSSI_THRESHOLD4_BELOW, + WMI_RSSI_THRESHOLD5_BELOW, + WMI_RSSI_THRESHOLD6_BELOW +}; + +struct wmi_rssi_threshold_event { + a_sle16 rssi; + u8 range; +} __packed; + +enum wmi_snr_threshold_val { + WMI_SNR_THRESHOLD1_ABOVE = 1, + WMI_SNR_THRESHOLD1_BELOW, + WMI_SNR_THRESHOLD2_ABOVE, + WMI_SNR_THRESHOLD2_BELOW, + WMI_SNR_THRESHOLD3_ABOVE, + WMI_SNR_THRESHOLD3_BELOW, + WMI_SNR_THRESHOLD4_ABOVE, + WMI_SNR_THRESHOLD4_BELOW +}; + +struct wmi_snr_threshold_event { + /* see, enum wmi_snr_threshold_val */ + u8 range; + + u8 snr; +} __packed; + +/* WMI_REPORT_ROAM_TBL_EVENTID */ +#define MAX_ROAM_TBL_CAND 5 + +struct wmi_bss_roam_info { + a_sle32 roam_util; + u8 bssid[ETH_ALEN]; + s8 rssi; + s8 rssidt; + s8 last_rssi; + s8 util; + s8 bias; + + /* for alignment */ + u8 reserved; +} __packed; + +/* WMI_CAC_EVENTID */ +enum cac_indication { + CAC_INDICATION_ADMISSION = 0x00, + CAC_INDICATION_ADMISSION_RESP = 0x01, + CAC_INDICATION_DELETE = 0x02, + CAC_INDICATION_NO_RESP = 0x03, +}; + +#define WMM_TSPEC_IE_LEN 63 + +struct wmi_cac_event { + u8 ac; + u8 cac_indication; + u8 status_code; + u8 tspec_suggestion[WMM_TSPEC_IE_LEN]; +} __packed; + +/* WMI_APLIST_EVENTID */ + +enum aplist_ver { + APLIST_VER1 = 1, +}; + +struct wmi_ap_info_v1 { + u8 bssid[ETH_ALEN]; + __le16 channel; +} __packed; + +union wmi_ap_info { + struct wmi_ap_info_v1 ap_info_v1; +} __packed; + +struct wmi_aplist_event { + u8 ap_list_ver; + u8 num_ap; + union wmi_ap_info ap_list[1]; +} __packed; + +/* Developer Commands */ + +/* + * WMI_SET_BITRATE_CMDID + * + * Get bit rate cmd uses same definition as set bit rate cmd + */ +enum wmi_bit_rate { + RATE_AUTO = -1, + RATE_1Mb = 0, + RATE_2Mb = 1, + RATE_5_5Mb = 2, + RATE_11Mb = 3, + RATE_6Mb = 4, + RATE_9Mb = 5, + RATE_12Mb = 6, + RATE_18Mb = 7, + RATE_24Mb = 8, + RATE_36Mb = 9, + RATE_48Mb = 10, + RATE_54Mb = 11, + RATE_MCS_0_20 = 12, + RATE_MCS_1_20 = 13, + RATE_MCS_2_20 = 14, + RATE_MCS_3_20 = 15, + RATE_MCS_4_20 = 16, + RATE_MCS_5_20 = 17, + RATE_MCS_6_20 = 18, + RATE_MCS_7_20 = 19, + RATE_MCS_0_40 = 20, + RATE_MCS_1_40 = 21, + RATE_MCS_2_40 = 22, + RATE_MCS_3_40 = 23, + RATE_MCS_4_40 = 24, + RATE_MCS_5_40 = 25, + RATE_MCS_6_40 = 26, + RATE_MCS_7_40 = 27, +}; + +struct wmi_bit_rate_reply { + /* see, enum wmi_bit_rate */ + s8 rate_index; +} __packed; + +/* + * WMI_SET_FIXRATES_CMDID + * + * Get fix rates cmd uses same definition as set fix rates cmd + */ +struct wmi_fix_rates_reply { + /* see wmi_bit_rate */ + __le32 fix_rate_mask; +} __packed; + +enum roam_data_type { + /* get the roam time data */ + ROAM_DATA_TIME = 1, +}; + +struct wmi_target_roam_time { + __le32 disassoc_time; + __le32 no_txrx_time; + __le32 assoc_time; + __le32 allow_txrx_time; + u8 disassoc_bssid[ETH_ALEN]; + s8 disassoc_bss_rssi; + u8 assoc_bssid[ETH_ALEN]; + s8 assoc_bss_rssi; +} __packed; + +enum wmi_txop_cfg { + WMI_TXOP_DISABLED = 0, + WMI_TXOP_ENABLED +}; + +struct wmi_set_wmm_txop_cmd { + u8 txop_enable; +} __packed; + +struct wmi_set_keepalive_cmd { + u8 keep_alive_intvl; +} __packed; + +struct wmi_get_keepalive_cmd { + __le32 configured; + u8 keep_alive_intvl; +} __packed; + +struct wmi_set_appie_cmd { + u8 mgmt_frm_type; /* enum wmi_mgmt_frame_type */ + u8 ie_len; + u8 ie_info[0]; +} __packed; + +/* Notify the WSC registration status to the target */ +#define WSC_REG_ACTIVE 1 +#define WSC_REG_INACTIVE 0 + +#define WOW_MAX_FILTER_LISTS 1 +#define WOW_MAX_FILTERS_PER_LIST 4 +#define WOW_PATTERN_SIZE 64 +#define WOW_MASK_SIZE 64 + +#define MAC_MAX_FILTERS_PER_LIST 4 + +struct wow_filter { + u8 wow_valid_filter; + u8 wow_filter_id; + u8 wow_filter_size; + u8 wow_filter_offset; + u8 wow_filter_mask[WOW_MASK_SIZE]; + u8 wow_filter_pattern[WOW_PATTERN_SIZE]; +} __packed; + +#define MAX_IP_ADDRS 2 + +struct wmi_set_ip_cmd { + /* IP in network byte order */ + __le32 ips[MAX_IP_ADDRS]; +} __packed; + +/* WMI_GET_WOW_LIST_CMD reply */ +struct wmi_get_wow_list_reply { + /* number of patterns in reply */ + u8 num_filters; + + /* this is filter # x of total num_filters */ + u8 this_filter_num; + + u8 wow_mode; + u8 host_mode; + struct wow_filter wow_filters[1]; +} __packed; + +/* WMI_SET_AKMP_PARAMS_CMD */ + +struct wmi_pmkid { + u8 pmkid[WMI_PMKID_LEN]; +} __packed; + +/* WMI_GET_PMKID_LIST_CMD Reply */ +struct wmi_pmkid_list_reply { + __le32 num_pmkid; + u8 bssid_list[ETH_ALEN][1]; + struct wmi_pmkid pmkid_list[1]; +} __packed; + +/* WMI_ADDBA_REQ_EVENTID */ +struct wmi_addba_req_event { + u8 tid; + u8 win_sz; + __le16 st_seq_no; + + /* f/w response for ADDBA Req; OK (0) or failure (!=0) */ + u8 status; +} __packed; + +/* WMI_ADDBA_RESP_EVENTID */ +struct wmi_addba_resp_event { + u8 tid; + + /* OK (0), failure (!=0) */ + u8 status; + + /* three values: not supported(0), 3839, 8k */ + __le16 amsdu_sz; +} __packed; + +/* WMI_DELBA_EVENTID + * f/w received a DELBA for peer and processed it. + * Host is notified of this + */ +struct wmi_delba_event { + u8 tid; + u8 is_peer_initiator; + __le16 reason_code; +} __packed; + +#define PEER_NODE_JOIN_EVENT 0x00 +#define PEER_NODE_LEAVE_EVENT 0x01 +#define PEER_FIRST_NODE_JOIN_EVENT 0x10 +#define PEER_LAST_NODE_LEAVE_EVENT 0x11 + +struct wmi_peer_node_event { + u8 event_code; + u8 peer_mac_addr[ETH_ALEN]; +} __packed; + +/* Transmit complete event data structure(s) */ + +/* version 1 of tx complete msg */ +struct tx_complete_msg_v1 { +#define TX_COMPLETE_STATUS_SUCCESS 0 +#define TX_COMPLETE_STATUS_RETRIES 1 +#define TX_COMPLETE_STATUS_NOLINK 2 +#define TX_COMPLETE_STATUS_TIMEOUT 3 +#define TX_COMPLETE_STATUS_OTHER 4 + + u8 status; + + /* packet ID to identify parent packet */ + u8 pkt_id; + + /* rate index on successful transmission */ + u8 rate_idx; + + /* number of ACK failures in tx attempt */ + u8 ack_failures; +} __packed; + +struct wmi_tx_complete_event { + /* no of tx comp msgs following this struct */ + u8 num_msg; + + /* length in bytes for each individual msg following this struct */ + u8 msg_len; + + /* version of tx complete msg data following this struct */ + u8 msg_type; + + /* individual messages follow this header */ + u8 reserved; +} __packed; + +/* + * ------- AP Mode definitions -------------- + */ + +/* + * !!! Warning !!! + * -Changing the following values needs compilation of both driver and firmware + */ +#define AP_MAX_NUM_STA 8 + +/* Spl. AID used to set DTIM flag in the beacons */ +#define MCAST_AID 0xFF + +#define DEF_AP_COUNTRY_CODE "US " + +/* Used with WMI_AP_SET_NUM_STA_CMDID */ + +/* + * Used with WMI_AP_SET_MLME_CMDID + */ + +/* MLME Commands */ +#define WMI_AP_MLME_ASSOC 1 /* associate station */ +#define WMI_AP_DISASSOC 2 /* disassociate station */ +#define WMI_AP_DEAUTH 3 /* deauthenticate station */ +#define WMI_AP_MLME_AUTHORIZE 4 /* authorize station */ +#define WMI_AP_MLME_UNAUTHORIZE 5 /* unauthorize station */ + +struct wmi_ap_set_mlme_cmd { + u8 mac[ETH_ALEN]; + __le16 reason; /* 802.11 reason code */ + u8 cmd; /* operation to perform (WMI_AP_*) */ +} __packed; + +struct wmi_ap_set_pvb_cmd { + __le32 flag; + __le16 rsvd; + __le16 aid; +} __packed; + +struct wmi_rx_frame_format_cmd { + /* version of meta data for rx packets <0 = default> (0-7 = valid) */ + u8 meta_ver; + + /* + * 1 == leave .11 header intact, + * 0 == replace .11 header with .3 <default> + */ + u8 dot11_hdr; + + /* + * 1 == defragmentation is performed by host, + * 0 == performed by target <default> + */ + u8 defrag_on_host; + + /* for alignment */ + u8 reserved[1]; +} __packed; + +/* AP mode events */ + +/* WMI_PS_POLL_EVENT */ +struct wmi_pspoll_event { + __le16 aid; +} __packed; + +struct wmi_per_sta_stat { + __le32 tx_bytes; + __le32 tx_pkts; + __le32 tx_error; + __le32 tx_discard; + __le32 rx_bytes; + __le32 rx_pkts; + __le32 rx_error; + __le32 rx_discard; + __le32 aid; +} __packed; + +struct wmi_ap_mode_stat { + __le32 action; + struct wmi_per_sta_stat sta[AP_MAX_NUM_STA + 1]; +} __packed; + +/* End of AP mode definitions */ + +struct wmi_remain_on_chnl_cmd { + __le32 freq; + __le32 duration; +} __packed; + +struct wmi_send_action_cmd { + __le32 id; + __le32 freq; + __le32 wait; + __le16 len; + u8 data[0]; +} __packed; + +struct wmi_tx_status_event { + __le32 id; + u8 ack_status; +} __packed; + +struct wmi_probe_req_report_cmd { + u8 enable; +} __packed; + +struct wmi_disable_11b_rates_cmd { + u8 disable; +} __packed; + +struct wmi_set_appie_extended_cmd { + u8 role_id; + u8 mgmt_frm_type; + u8 ie_len; + u8 ie_info[0]; +} __packed; + +struct wmi_remain_on_chnl_event { + __le32 freq; + __le32 duration; +} __packed; + +struct wmi_cancel_remain_on_chnl_event { + __le32 freq; + __le32 duration; + u8 status; +} __packed; + +struct wmi_rx_action_event { + __le32 freq; + __le16 len; + u8 data[0]; +} __packed; + +struct wmi_p2p_capabilities_event { + __le16 len; + u8 data[0]; +} __packed; + +struct wmi_p2p_rx_probe_req_event { + __le32 freq; + __le16 len; + u8 data[0]; +} __packed; + +#define P2P_FLAG_CAPABILITIES_REQ (0x00000001) +#define P2P_FLAG_MACADDR_REQ (0x00000002) +#define P2P_FLAG_HMODEL_REQ (0x00000002) + +struct wmi_get_p2p_info { + __le32 info_req_flags; +} __packed; + +struct wmi_p2p_info_event { + __le32 info_req_flags; + __le16 len; + u8 data[0]; +} __packed; + +struct wmi_p2p_capabilities { + u8 go_power_save; +} __packed; + +struct wmi_p2p_macaddr { + u8 mac_addr[ETH_ALEN]; +} __packed; + +struct wmi_p2p_hmodel { + u8 p2p_model; +} __packed; + +struct wmi_p2p_probe_response_cmd { + __le32 freq; + u8 destination_addr[ETH_ALEN]; + __le16 len; + u8 data[0]; +} __packed; + +/* Extended WMI (WMIX) + * + * Extended WMIX commands are encapsulated in a WMI message with + * cmd=WMI_EXTENSION_CMD. + * + * Extended WMI commands are those that are needed during wireless + * operation, but which are not really wireless commands. This allows, + * for instance, platform-specific commands. Extended WMI commands are + * embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID. + * Extended WMI events are similarly embedded in a WMI event message with + * WMI_EVENT_ID=WMI_EXTENSION_EVENTID. + */ +struct wmix_cmd_hdr { + __le32 cmd_id; +} __packed; + +enum wmix_command_id { + WMIX_DSETOPEN_REPLY_CMDID = 0x2001, + WMIX_DSETDATA_REPLY_CMDID, + WMIX_GPIO_OUTPUT_SET_CMDID, + WMIX_GPIO_INPUT_GET_CMDID, + WMIX_GPIO_REGISTER_SET_CMDID, + WMIX_GPIO_REGISTER_GET_CMDID, + WMIX_GPIO_INTR_ACK_CMDID, + WMIX_HB_CHALLENGE_RESP_CMDID, + WMIX_DBGLOG_CFG_MODULE_CMDID, + WMIX_PROF_CFG_CMDID, /* 0x200a */ + WMIX_PROF_ADDR_SET_CMDID, + WMIX_PROF_START_CMDID, + WMIX_PROF_STOP_CMDID, + WMIX_PROF_COUNT_GET_CMDID, +}; + +enum wmix_event_id { + WMIX_DSETOPENREQ_EVENTID = 0x3001, + WMIX_DSETCLOSE_EVENTID, + WMIX_DSETDATAREQ_EVENTID, + WMIX_GPIO_INTR_EVENTID, + WMIX_GPIO_DATA_EVENTID, + WMIX_GPIO_ACK_EVENTID, + WMIX_HB_CHALLENGE_RESP_EVENTID, + WMIX_DBGLOG_EVENTID, + WMIX_PROF_COUNT_EVENTID, +}; + +/* + * ------Error Detection support------- + */ + +/* + * WMIX_HB_CHALLENGE_RESP_CMDID + * Heartbeat Challenge Response command + */ +struct wmix_hb_challenge_resp_cmd { + __le32 cookie; + __le32 source; +} __packed; + +struct ath6kl_wmix_dbglog_cfg_module_cmd { + __le32 valid; + __le32 config; +} __packed; + +/* End of Extended WMI (WMIX) */ + +enum wmi_sync_flag { + NO_SYNC_WMIFLAG = 0, + + /* transmit all queued data before cmd */ + SYNC_BEFORE_WMIFLAG, + + /* any new data waits until cmd execs */ + SYNC_AFTER_WMIFLAG, + + SYNC_BOTH_WMIFLAG, + + /* end marker */ + END_WMIFLAG +}; + +enum htc_endpoint_id ath6kl_wmi_get_control_ep(struct wmi *wmi); +void ath6kl_wmi_set_control_ep(struct wmi *wmi, enum htc_endpoint_id ep_id); +int ath6kl_wmi_dix_2_dot3(struct wmi *wmi, struct sk_buff *skb); +int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb, + u8 msg_type, bool more_data, + enum wmi_data_hdr_data_type data_type, + u8 meta_ver, void *tx_meta_info); + +int ath6kl_wmi_dot11_hdr_remove(struct wmi *wmi, struct sk_buff *skb); +int ath6kl_wmi_dot3_2_dix(struct sk_buff *skb); +int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, struct sk_buff *skb, + u32 layer2_priority, bool wmm_enabled, + u8 *ac); + +int ath6kl_wmi_control_rx(struct wmi *wmi, struct sk_buff *skb); + +int ath6kl_wmi_cmd_send(struct wmi *wmi, struct sk_buff *skb, + enum wmi_cmd_id cmd_id, enum wmi_sync_flag sync_flag); + +int ath6kl_wmi_connect_cmd(struct wmi *wmi, enum network_type nw_type, + enum dot11_auth_mode dot11_auth_mode, + enum auth_mode auth_mode, + enum crypto_type pairwise_crypto, + u8 pairwise_crypto_len, + enum crypto_type group_crypto, + u8 group_crypto_len, int ssid_len, u8 *ssid, + u8 *bssid, u16 channel, u32 ctrl_flags); + +int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 *bssid, u16 channel); +int ath6kl_wmi_disconnect_cmd(struct wmi *wmi); +int ath6kl_wmi_startscan_cmd(struct wmi *wmi, enum wmi_scan_type scan_type, + u32 force_fgscan, u32 is_legacy, + u32 home_dwell_time, u32 force_scan_interval, + s8 num_chan, u16 *ch_list); +int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u16 fg_start_sec, + u16 fg_end_sec, u16 bg_sec, + u16 minact_chdw_msec, u16 maxact_chdw_msec, + u16 pas_chdw_msec, u8 short_scan_ratio, + u8 scan_ctrl_flag, u32 max_dfsch_act_time, + u16 maxact_scan_per_ssid); +int ath6kl_wmi_bssfilter_cmd(struct wmi *wmi, u8 filter, u32 ie_mask); +int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 index, u8 flag, + u8 ssid_len, u8 *ssid); +int ath6kl_wmi_listeninterval_cmd(struct wmi *wmi, u16 listen_interval, + u16 listen_beacons); +int ath6kl_wmi_powermode_cmd(struct wmi *wmi, u8 pwr_mode); +int ath6kl_wmi_pmparams_cmd(struct wmi *wmi, u16 idle_period, + u16 ps_poll_num, u16 dtim_policy, + u16 tx_wakup_policy, u16 num_tx_to_wakeup, + u16 ps_fail_event_policy); +int ath6kl_wmi_disctimeout_cmd(struct wmi *wmi, u8 timeout); +int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, + struct wmi_create_pstream_cmd *pstream); +int ath6kl_wmi_delete_pstream_cmd(struct wmi *wmi, u8 traffic_class, u8 tsid); + +int ath6kl_wmi_set_rts_cmd(struct wmi *wmi, u16 threshold); +int ath6kl_wmi_set_lpreamble_cmd(struct wmi *wmi, u8 status, + u8 preamble_policy); + +int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source); +int ath6kl_wmi_config_debug_module_cmd(struct wmi *wmi, u32 valid, u32 config); + +int ath6kl_wmi_get_stats_cmd(struct wmi *wmi); +int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 key_index, + enum crypto_type key_type, + u8 key_usage, u8 key_len, + u8 *key_rsc, u8 *key_material, + u8 key_op_ctrl, u8 *mac_addr, + enum wmi_sync_flag sync_flag); +int ath6kl_wmi_add_krk_cmd(struct wmi *wmi, u8 *krk); +int ath6kl_wmi_deletekey_cmd(struct wmi *wmi, u8 key_index); +int ath6kl_wmi_setpmkid_cmd(struct wmi *wmi, const u8 *bssid, + const u8 *pmkid, bool set); +int ath6kl_wmi_set_tx_pwr_cmd(struct wmi *wmi, u8 dbM); +int ath6kl_wmi_get_tx_pwr_cmd(struct wmi *wmi); + +int ath6kl_wmi_set_wmm_txop(struct wmi *wmi, enum wmi_txop_cfg cfg); +int ath6kl_wmi_set_keepalive_cmd(struct wmi *wmi, u8 keep_alive_intvl); +int ath6kl_wmi_test_cmd(struct wmi *wmi, void *buf, size_t len); + +s32 ath6kl_wmi_get_rate(s8 rate_index); + +int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, struct wmi_set_ip_cmd *ip_cmd); +int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); + +/* AP mode */ +int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, struct wmi_connect_cmd *p); + +int ath6kl_wmi_ap_set_mlme(struct wmi *wmip, u8 cmd, const u8 *mac, u16 reason); + +int ath6kl_wmi_set_pvb_cmd(struct wmi *wmi, u16 aid, bool flag); + +int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 rx_meta_version, + bool rx_dot11_hdr, bool defrag_on_host); + +int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, + u8 ie_len); + +/* P2P */ +int ath6kl_wmi_disable_11b_rates_cmd(struct wmi *wmi, bool disable); + +int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u32 freq, u32 dur); + +int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u32 id, u32 freq, u32 wait, + const u8 *data, u16 data_len); + +int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u32 freq, + const u8 *dst, + const u8 *data, u16 data_len); + +int ath6kl_wmi_probe_report_req_cmd(struct wmi *wmi, bool enable); + +int ath6kl_wmi_info_req_cmd(struct wmi *wmi, u32 info_req_flags); + +int ath6kl_wmi_cancel_remain_on_chnl_cmd(struct wmi *wmi); + +int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 mgmt_frm_type, const u8 *ie, + u8 ie_len); + +void *ath6kl_wmi_init(struct ath6kl *devt); +void ath6kl_wmi_shutdown(struct wmi *wmi); + +#endif /* WMI_H */ diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 05a6fade7b1c..36ed3c46fec6 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -21,6 +21,7 @@ ath9k_hw-y:= \ ar5008_phy.o \ ar9002_calib.o \ ar9003_calib.o \ + ar9003_rtt.o \ calib.o \ eeprom.o \ eeprom_def.o \ diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 0b36fcf8a280..85a54cd2b083 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -133,7 +133,7 @@ static int ath_ahb_probe(struct platform_device *pdev) goto err_free_hw; } - ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops); + ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_irq; diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index bfb6481f01f9..2776c3c1f506 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -273,7 +273,8 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) immunityLevel, aniState->noiseFloor, aniState->rssiThrLow, aniState->rssiThrHigh); - aniState->ofdmNoiseImmunityLevel = immunityLevel; + if (aniState->update_ani) + aniState->ofdmNoiseImmunityLevel = immunityLevel; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; @@ -346,7 +347,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; - aniState->cckNoiseImmunityLevel = immunityLevel; + if (aniState->update_ani) + aniState->cckNoiseImmunityLevel = immunityLevel; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; @@ -502,9 +504,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, ATH9K_ANI_CCK_WEAK_SIG_THR); - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart(ah); return; } @@ -525,8 +524,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & - ~ATH9K_RX_FILTER_PHYERR); ath9k_ani_restart(ah); ENABLE_REGWRITE_BUFFER(ah); @@ -593,6 +590,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); + aniState->update_ani = false; ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL); ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL); } @@ -609,6 +607,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); + aniState->update_ani = true; ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel); ath9k_hw_set_cck_nil(ah, @@ -643,7 +642,7 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) listenTime = ath_hw_get_listen_time(common); if (listenTime <= 0) { - ah->stats.ast_ani_lneg++; + ah->stats.ast_ani_lneg_or_lzero++; ath9k_ani_restart(ah); return false; } @@ -892,6 +891,8 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ani->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; + ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; + ani->update_ani = false; } /* diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index dbab5b9ce494..83029d6c7b22 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -122,6 +122,7 @@ struct ar5416AniState { u8 firstepLevel; u8 ofdmWeakSigDetectOff; u8 cckWeakSigThreshold; + bool update_ani; u32 listenTime; int32_t rssiThrLow; int32_t rssiThrHigh; @@ -148,8 +149,7 @@ struct ar5416Stats { u32 ast_ani_ofdmerrs; u32 ast_ani_cckerrs; u32 ast_ani_reset; - u32 ast_ani_lzero; - u32 ast_ani_lneg; + u32 ast_ani_lneg_or_lzero; u32 avgbrssi; struct ath9k_mib_stats ast_mibstats; }; @@ -159,7 +159,5 @@ void ath9k_enable_mib_counters(struct ath_hw *ah); void ath9k_hw_disable_mib_counters(struct ath_hw *ah); void ath9k_hw_ani_setup(struct ath_hw *ah); void ath9k_hw_ani_init(struct ath_hw *ah); -int ath9k_hw_get_ani_channel_idx(struct ath_hw *ah, - struct ath9k_channel *chan); #endif /* ANI_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h index 234617c948a1..f81e7fc60a36 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h @@ -14,70 +14,71 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -static const u32 ar5416Modes[][6] = { - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180}, - {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0}, - {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a}, - {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303}, - {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, - {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, - {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, - {0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0, 0x137216a0}, - {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de, 0x6c48b0de}, - {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e}, - {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e}, - {0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18}, - {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, - {0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190}, - {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081}, - {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0}, - {0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134}, - {0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b}, - {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020}, - {0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80}, - {0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80}, - {0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80}, - {0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120, 0x00001120}, - {0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00}, - {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be}, - {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, - {0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c}, - {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, - {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, - {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880}, - {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788}, - {0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, - {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000}, - {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa}, - {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000}, - {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402}, - {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06}, - {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b}, - {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b}, - {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a}, - {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf}, - {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f}, - {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f}, - {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f}, - {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +static const u32 ar5416Modes[][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}, + {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300}, + {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, + {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, + {0x00009844, 0x1372161e, 0x1372161e, 0x137216a0, 0x137216a0}, + {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x00009850, 0x6c48b4e0, 0x6d48b4e0, 0x6d48b0de, 0x6c48b0de}, + {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e}, + {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18}, + {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, + {0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190}, + {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081}, + {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134}, + {0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b}, + {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020}, + {0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80}, + {0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80}, + {0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80}, + {0x00009964, 0x00000000, 0x00000000, 0x00001120, 0x00001120}, + {0x000099bc, 0x001a0a00, 0x001a0a00, 0x001a0a00, 0x001a0a00}, + {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be}, + {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, + {0x000099c8, 0x6af6532c, 0x6af6532c, 0x6af6532c, 0x6af6532c}, + {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, + {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, + {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880}, + {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788}, + {0x0000a20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120}, + {0x0000b20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120}, + {0x0000c20c, 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120}, + {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, + {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa}, + {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000}, + {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402}, + {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06}, + {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b}, + {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b}, + {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a}, + {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf}, + {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f}, + {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f}, + {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f}, + {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000}, + {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }; static const u32 ar5416Common[][2] = { @@ -668,6 +669,6 @@ static const u32 ar5416Addac[][2] = { {0x0000989c, 0x00000000}, {0x0000989c, 0x00000000}, {0x0000989c, 0x00000000}, - {0x000098cc, 0x00000000}, + {0x000098c4, 0x00000000}, }; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index fac2c6da6ca4..f199e9e25149 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -704,8 +704,10 @@ static void ar5008_hw_override_ini(struct ath_hw *ah, REG_WRITE(ah, AR_PCU_MISC_MODE2, val); } - if (!AR_SREV_5416_20_OR_LATER(ah) || - AR_SREV_9280_20_OR_LATER(ah)) + 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; /* * Disable BB clock gating @@ -761,10 +763,8 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah, static int ar5008_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); int i, regWrites = 0; - struct ieee80211_channel *channel = chan->chan; u32 modesIndex, freqIndex; switch (chan->chanmode) { @@ -802,7 +802,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, /* Write ADDAC shifts */ REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); - ah->eep_ops->set_addac(ah, chan); + if (ah->eep_ops->set_addac) + ah->eep_ops->set_addac(ah, chan); if (AR_SREV_5416_22_OR_LATER(ah)) { REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); @@ -900,14 +901,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, ar5008_hw_set_channel_regs(ah, chan); ar5008_hw_init_chain_masks(ah); ath9k_olc_init(ah); - - /* Set TX power */ - ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit), false); + ath9k_hw_apply_txpower(ah, chan); /* Write analog registers */ if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { @@ -1007,24 +1001,6 @@ static void ar5008_restore_chainmask(struct ath_hw *ah) } } -static void ar5008_set_diversity(struct ath_hw *ah, bool value) -{ - u32 v = REG_READ(ah, AR_PHY_CCK_DETECT); - if (value) - v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - else - v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - REG_WRITE(ah, AR_PHY_CCK_DETECT, v); -} - -static u32 ar9100_hw_compute_pll_control(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - if (chan && IS_CHAN_5GHZ(chan)) - return 0x1450; - return 0x1458; -} - static u32 ar9160_hw_compute_pll_control(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -1654,7 +1630,6 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->rfbus_req = ar5008_hw_rfbus_req; priv_ops->rfbus_done = ar5008_hw_rfbus_done; priv_ops->restore_chainmask = ar5008_restore_chainmask; - priv_ops->set_diversity = ar5008_set_diversity; priv_ops->do_getnf = ar5008_hw_do_getnf; priv_ops->set_radar_params = ar5008_hw_set_radar_params; @@ -1664,9 +1639,7 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) } else priv_ops->ani_control = ar5008_hw_ani_control_old; - if (AR_SREV_9100(ah)) - priv_ops->compute_pll_control = ar9100_hw_compute_pll_control; - else if (AR_SREV_9160_10_OR_LATER(ah)) + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) priv_ops->compute_pll_control = ar9160_hw_compute_pll_control; else priv_ops->compute_pll_control = ar5008_hw_compute_pll_control; diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h index 6d2e2f3303f9..e8bdc75405f1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h @@ -14,73 +14,74 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -static const u32 ar5416Modes_9100[][6] = { - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180}, - {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0}, - {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a}, - {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303}, - {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, - {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, - {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, - {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0}, - {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2}, - {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e}, - {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e}, - {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18}, - {0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, - {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0}, - {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081}, - {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0}, - {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016}, - {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d}, - {0x00009940, 0x00750604, 0x00754604, 0xfff81204, 0xfff81204, 0xfff81204}, - {0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020}, - {0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e, 0xe250a51e}, - {0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff, 0x3388ffff}, - {0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0}, - {0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0}, - {0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0}, - {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120}, - {0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00, 0x001a0c00}, - {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be}, - {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, - {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329}, - {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, - {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, - {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880}, - {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788}, - {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, - {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000}, - {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa}, - {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000}, - {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402}, - {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06}, - {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b}, - {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b}, - {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a}, - {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf}, - {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f}, - {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f}, - {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f}, - {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +static const u32 ar5416Modes_9100[][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}, + {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300}, + {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, + {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, + {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, + {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2}, + {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e}, + {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20}, + {0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, + {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0}, + {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081}, + {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d}, + {0x00009940, 0x00750604, 0x00754604, 0xfff81204, 0xfff81204}, + {0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020}, + {0x00009954, 0x5f3ca3de, 0x5f3ca3de, 0xe250a51e, 0xe250a51e}, + {0x00009958, 0x2108ecff, 0x2108ecff, 0x3388ffff, 0x3388ffff}, + {0x00009960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0}, + {0x0000a960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0}, + {0x0000b960, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0, 0x0001bfc0}, + {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120}, + {0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a1000, 0x001a0c00}, + {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be}, + {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, + {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329}, + {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, + {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, + {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880}, + {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788}, + {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120}, + {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120}, + {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120}, + {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, + {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa}, + {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000}, + {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402}, + {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06}, + {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b}, + {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b}, + {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a}, + {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf}, + {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f}, + {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f}, + {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f}, + {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000}, + {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }; static const u32 ar5416Common_9100[][2] = { @@ -666,71 +667,72 @@ static const u32 ar5416Addac_9100[][2] = { {0x000098cc, 0x00000000}, }; -static const u32 ar5416Modes_9160[][6] = { - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180}, - {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000, 0x00014008}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0}, - {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab, 0x098813cf}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a}, - {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303}, - {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, - {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, - {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, - {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0}, - {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68}, - {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2, 0x6c48b0e2}, - {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e}, - {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e}, - {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18}, - {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, - {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0}, - {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081}, - {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0}, - {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016}, - {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d}, - {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020}, - {0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40}, - {0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40}, - {0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40}, - {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120}, - {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce}, - {0x000099bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00}, - {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be}, - {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, - {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329}, - {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, - {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, - {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880, 0x00000880}, - {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, 0xd03e4788}, - {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120, 0x002ac120}, - {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, - {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000}, - {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, 0x0a1a7caa}, - {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000}, - {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, 0x2e032402}, - {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, 0x4a0a3c06}, - {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, 0x621a540b}, - {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, 0x764f6c1b}, - {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, 0x845b7a5a}, - {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, 0x950f8ccf}, - {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, 0xa5cf9b4f}, - {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, 0xbddfaf1f}, - {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, 0xd1ffc93f}, - {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +static const u32 ar5416Modes_9160[][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}, + {0x000010f0, 0x0000a000, 0x00014000, 0x00016000, 0x0000b000}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d93a7, 0x128d93cf, 0x12e013d7, 0x12e013ab}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300}, + {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, + {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, + {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, + {0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68}, + {0x00009850, 0x6c48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6c48b0e2}, + {0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e}, + {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20}, + {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, + {0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0}, + {0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081}, + {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d}, + {0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020}, + {0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40}, + {0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40}, + {0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40}, + {0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120}, + {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x000099bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00}, + {0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be}, + {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, + {0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329}, + {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, + {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, + {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a204, 0x00000880, 0x00000880, 0x00000880, 0x00000880}, + {0x0000a208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788}, + {0x0000a20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120}, + {0x0000b20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120}, + {0x0000c20c, 0x002fc160, 0x002fc160, 0x002ac120, 0x002ac120}, + {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, + {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa}, + {0x0000a300, 0x18010000, 0x18010000, 0x18010000, 0x18010000}, + {0x0000a304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402}, + {0x0000a308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06}, + {0x0000a30c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b}, + {0x0000a310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b}, + {0x0000a314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a}, + {0x0000a318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf}, + {0x0000a31c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f}, + {0x0000a320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f}, + {0x0000a324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f}, + {0x0000a328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000}, + {0x0000a32c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a330, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }; static const u32 ar5416Common_9160[][2] = { diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index 2d394af82171..e0ab0657cc3a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -869,6 +869,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) ar9002_hw_pa_cal(ah, true); /* Do NF Calibration after DC offset and other calibrations */ + ath9k_hw_loadnf(ah, chan); ath9k_hw_start_nfcal(ah, true); if (ah->caldata) diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 44d9d8d56490..626d547d2f06 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -30,7 +30,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) { if (AR_SREV_9271(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271, - ARRAY_SIZE(ar9271Modes_9271), 6); + ARRAY_SIZE(ar9271Modes_9271), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, ARRAY_SIZE(ar9271Common_9271), 2); INIT_INI_ARRAY(&ah->iniCommon_normal_cck_fir_coeff_9271, @@ -41,21 +41,21 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar9271Common_japan_2484_cck_fir_coeff_9271), 2); INIT_INI_ARRAY(&ah->iniModes_9271_1_0_only, ar9271Modes_9271_1_0_only, - ARRAY_SIZE(ar9271Modes_9271_1_0_only), 6); + ARRAY_SIZE(ar9271Modes_9271_1_0_only), 5); INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg, - ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 6); + ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 5); INIT_INI_ARRAY(&ah->iniModes_high_power_tx_gain_9271, ar9271Modes_high_power_tx_gain_9271, - ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 6); + ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5); INIT_INI_ARRAY(&ah->iniModes_normal_power_tx_gain_9271, ar9271Modes_normal_power_tx_gain_9271, - ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 6); + ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5); return; } if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, - ARRAY_SIZE(ar9287Modes_9287_1_1), 6); + ARRAY_SIZE(ar9287Modes_9287_1_1), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1, ARRAY_SIZE(ar9287Common_9287_1_1), 2); if (ah->config.pcie_clock_req) @@ -71,7 +71,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, - ARRAY_SIZE(ar9285Modes_9285_1_2), 6); + ARRAY_SIZE(ar9285Modes_9285_1_2), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, ARRAY_SIZE(ar9285Common_9285_1_2), 2); @@ -87,7 +87,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) } } else if (AR_SREV_9280_20_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, - ARRAY_SIZE(ar9280Modes_9280_2), 6); + ARRAY_SIZE(ar9280Modes_9280_2), 5); INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, ARRAY_SIZE(ar9280Common_9280_2), 2); @@ -105,7 +105,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); } else if (AR_SREV_9160_10_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160, - ARRAY_SIZE(ar5416Modes_9160), 6); + ARRAY_SIZE(ar5416Modes_9160), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, ARRAY_SIZE(ar5416Common_9160), 2); INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9160, @@ -134,7 +134,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) } } else if (AR_SREV_9100_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100, - ARRAY_SIZE(ar5416Modes_9100), 6); + ARRAY_SIZE(ar5416Modes_9100), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, ARRAY_SIZE(ar5416Common_9100), 2); INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0_9100, @@ -157,7 +157,7 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) ARRAY_SIZE(ar5416Addac_9100), 2); } else { INIT_INI_ARRAY(&ah->iniModes, ar5416Modes, - ARRAY_SIZE(ar5416Modes), 6); + ARRAY_SIZE(ar5416Modes), 5); INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, ARRAY_SIZE(ar5416Common), 2); INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, @@ -207,19 +207,19 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9280Modes_backoff_13db_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); + ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 5); else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9280Modes_backoff_23db_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); + ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 5); else INIT_INI_ARRAY(&ah->iniModesRxGain, ar9280Modes_original_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 5); } else { INIT_INI_ARRAY(&ah->iniModesRxGain, ar9280Modes_original_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 5); } } @@ -234,15 +234,15 @@ static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah) if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_high_power_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); + ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 5); else INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_original_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 5); } else { INIT_INI_ARRAY(&ah->iniModesTxGain, ar9280Modes_original_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 5); } } @@ -251,14 +251,14 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) if (AR_SREV_9287_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9287Modes_rx_gain_9287_1_1, - ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 6); + ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 5); else if (AR_SREV_9280_20(ah)) ar9280_20_hw_init_rxgain_ini(ah); if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModesTxGain, ar9287Modes_tx_gain_9287_1_1, - ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 6); + ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 5); } else if (AR_SREV_9280_20(ah)) { ar9280_20_hw_init_txgain_ini(ah); } else if (AR_SREV_9285_12_OR_LATER(ah)) { @@ -270,24 +270,24 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9285Modes_XE2_0_high_power, ARRAY_SIZE( - ar9285Modes_XE2_0_high_power), 6); + ar9285Modes_XE2_0_high_power), 5); } else { INIT_INI_ARRAY(&ah->iniModesTxGain, ar9285Modes_high_power_tx_gain_9285_1_2, ARRAY_SIZE( - ar9285Modes_high_power_tx_gain_9285_1_2), 6); + ar9285Modes_high_power_tx_gain_9285_1_2), 5); } } else { if (AR_SREV_9285E_20(ah)) { INIT_INI_ARRAY(&ah->iniModesTxGain, ar9285Modes_XE2_0_normal_power, ARRAY_SIZE( - ar9285Modes_XE2_0_normal_power), 6); + ar9285Modes_XE2_0_normal_power), 5); } else { INIT_INI_ARRAY(&ah->iniModesTxGain, ar9285Modes_original_tx_gain_9285_1_2, ARRAY_SIZE( - ar9285Modes_original_tx_gain_9285_1_2), 6); + ar9285Modes_original_tx_gain_9285_1_2), 5); } } } @@ -303,17 +303,13 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) * register as the other analog registers. Hence the 9 writes. */ static void ar9002_hw_configpcipowersave(struct ath_hw *ah, - int restore, - int power_off) + bool power_off) { u8 i; u32 val; - if (ah->is_pciexpress != true || ah->aspm_enabled != true) - return; - /* Nothing to do on restore for 11N */ - if (!restore) { + if (!power_off /* !restore */) { if (AR_SREV_9280_20_OR_LATER(ah)) { /* * AR9280 2.0 or later chips use SerDes values from the diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h index 7573257731b6..863db321070d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h @@ -14,53 +14,54 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -static const u32 ar9280Modes_9280_2[][6] = { - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180}, - {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880}, - {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303}, - {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, - {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, - {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, - {0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e}, - {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0}, - {0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2}, - {0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e}, - {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e, 0x31395d5e}, - {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18}, - {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, - {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881}, - {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0}, - {0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b, 0x00000016}, - {0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d}, - {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010}, - {0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010}, - {0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010}, - {0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210}, - {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce}, - {0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c}, - {0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00}, - {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444}, - {0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019}, - {0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019}, - {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, - {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000}, - {0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000, 0x13c88000}, - {0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000}, - {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e}, - {0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000, 0x0c000000}, - {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000}, +static const u32 ar9280Modes_9280_2[][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}, + {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {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}, + {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300}, + {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, + {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, + {0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, + {0x00009850, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x0000985c, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20}, + {0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, + {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x00009918, 0x0000000a, 0x00000014, 0x00000268, 0x0000000b}, + {0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d}, + {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010}, + {0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010}, + {0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010}, + {0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210}, + {0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c}, + {0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00}, + {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444}, + {0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019}, + {0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019}, + {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, + {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a23c, 0x13c88000, 0x13c88000, 0x13c88001, 0x13c88000}, + {0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000}, + {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e}, + {0x0000a388, 0x0c000000, 0x0c000000, 0x08000000, 0x0c000000}, + {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000}, }; static const u32 ar9280Common_9280_2[][2] = { @@ -424,471 +425,476 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = { {0x00009918, 0x0000000b, 0x00000016}, }; -static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = { - {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290}, - {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300}, - {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304}, - {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308}, - {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c}, - {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000}, - {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004}, - {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008}, - {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c}, - {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080}, - {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084}, - {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088}, - {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c}, - {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100}, - {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104}, - {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108}, - {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c}, - {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110}, - {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114}, - {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180}, - {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184}, - {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188}, - {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c}, - {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190}, - {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194}, - {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0}, - {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c}, - {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8}, - {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284}, - {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288}, - {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224}, - {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290}, - {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300}, - {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304}, - {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308}, - {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c}, - {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380}, - {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384}, - {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700}, - {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704}, - {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708}, - {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c}, - {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780}, - {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784}, - {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00}, - {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04}, - {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08}, - {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c}, - {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10}, - {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b80, 0x00008b80, 0x00008b80}, - {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b84, 0x00008b84, 0x00008b84}, - {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b88, 0x00008b88, 0x00008b88}, - {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b8c, 0x00008b8c, 0x00008b8c}, - {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b90, 0x00008b90, 0x00008b90}, - {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b94, 0x00008b94, 0x00008b94}, - {0x00009adc, 0x0000b390, 0x0000b390, 0x00008b98, 0x00008b98, 0x00008b98}, - {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008ba4, 0x00008ba4, 0x00008ba4}, - {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008ba8, 0x00008ba8, 0x00008ba8}, - {0x00009ae8, 0x0000b780, 0x0000b780, 0x00008bac, 0x00008bac, 0x00008bac}, - {0x00009aec, 0x0000b784, 0x0000b784, 0x00008bb0, 0x00008bb0, 0x00008bb0}, - {0x00009af0, 0x0000b788, 0x0000b788, 0x00008bb4, 0x00008bb4, 0x00008bb4}, - {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008ba1, 0x00008ba1, 0x00008ba1}, - {0x00009af8, 0x0000b790, 0x0000b790, 0x00008ba5, 0x00008ba5, 0x00008ba5}, - {0x00009afc, 0x0000b794, 0x0000b794, 0x00008ba9, 0x00008ba9, 0x00008ba9}, - {0x00009b00, 0x0000b798, 0x0000b798, 0x00008bad, 0x00008bad, 0x00008bad}, - {0x00009b04, 0x0000d784, 0x0000d784, 0x00008bb1, 0x00008bb1, 0x00008bb1}, - {0x00009b08, 0x0000d788, 0x0000d788, 0x00008bb5, 0x00008bb5, 0x00008bb5}, - {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008ba2, 0x00008ba2, 0x00008ba2}, - {0x00009b10, 0x0000d790, 0x0000d790, 0x00008ba6, 0x00008ba6, 0x00008ba6}, - {0x00009b14, 0x0000f780, 0x0000f780, 0x00008baa, 0x00008baa, 0x00008baa}, - {0x00009b18, 0x0000f784, 0x0000f784, 0x00008bae, 0x00008bae, 0x00008bae}, - {0x00009b1c, 0x0000f788, 0x0000f788, 0x00008bb2, 0x00008bb2, 0x00008bb2}, - {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008bb6, 0x00008bb6, 0x00008bb6}, - {0x00009b24, 0x0000f790, 0x0000f790, 0x00008ba3, 0x00008ba3, 0x00008ba3}, - {0x00009b28, 0x0000f794, 0x0000f794, 0x00008ba7, 0x00008ba7, 0x00008ba7}, - {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008bab, 0x00008bab, 0x00008bab}, - {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008baf, 0x00008baf, 0x00008baf}, - {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008bb3, 0x00008bb3, 0x00008bb3}, - {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008bb7, 0x00008bb7, 0x00008bb7}, - {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008bc3, 0x00008bc3, 0x00008bc3}, - {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008bc7, 0x00008bc7, 0x00008bc7}, - {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008bcb, 0x00008bcb, 0x00008bcb}, - {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008bcf, 0x00008bcf, 0x00008bcf}, - {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008bd3, 0x00008bd3, 0x00008bd3}, - {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008bd7, 0x00008bd7, 0x00008bd7}, - {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb, 0x00008bdb}, - {0x00009848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055}, - {0x0000a848, 0x00001066, 0x00001066, 0x00001055, 0x00001055, 0x00001055}, +static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290}, + {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300}, + {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304}, + {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308}, + {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c}, + {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000}, + {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004}, + {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008}, + {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c}, + {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080}, + {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084}, + {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088}, + {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c}, + {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100}, + {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104}, + {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108}, + {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c}, + {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110}, + {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114}, + {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180}, + {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184}, + {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188}, + {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c}, + {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190}, + {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194}, + {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0}, + {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c}, + {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8}, + {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284}, + {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288}, + {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224}, + {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290}, + {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300}, + {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304}, + {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308}, + {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c}, + {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380}, + {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384}, + {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700}, + {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704}, + {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708}, + {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c}, + {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780}, + {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784}, + {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00}, + {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04}, + {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08}, + {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c}, + {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10}, + {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b80, 0x00008b80}, + {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b84, 0x00008b84}, + {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b88, 0x00008b88}, + {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b8c, 0x00008b8c}, + {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b90, 0x00008b90}, + {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b94, 0x00008b94}, + {0x00009adc, 0x0000b390, 0x0000b390, 0x00008b98, 0x00008b98}, + {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008ba4, 0x00008ba4}, + {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008ba8, 0x00008ba8}, + {0x00009ae8, 0x0000b780, 0x0000b780, 0x00008bac, 0x00008bac}, + {0x00009aec, 0x0000b784, 0x0000b784, 0x00008bb0, 0x00008bb0}, + {0x00009af0, 0x0000b788, 0x0000b788, 0x00008bb4, 0x00008bb4}, + {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008ba1, 0x00008ba1}, + {0x00009af8, 0x0000b790, 0x0000b790, 0x00008ba5, 0x00008ba5}, + {0x00009afc, 0x0000b794, 0x0000b794, 0x00008ba9, 0x00008ba9}, + {0x00009b00, 0x0000b798, 0x0000b798, 0x00008bad, 0x00008bad}, + {0x00009b04, 0x0000d784, 0x0000d784, 0x00008bb1, 0x00008bb1}, + {0x00009b08, 0x0000d788, 0x0000d788, 0x00008bb5, 0x00008bb5}, + {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008ba2, 0x00008ba2}, + {0x00009b10, 0x0000d790, 0x0000d790, 0x00008ba6, 0x00008ba6}, + {0x00009b14, 0x0000f780, 0x0000f780, 0x00008baa, 0x00008baa}, + {0x00009b18, 0x0000f784, 0x0000f784, 0x00008bae, 0x00008bae}, + {0x00009b1c, 0x0000f788, 0x0000f788, 0x00008bb2, 0x00008bb2}, + {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008bb6, 0x00008bb6}, + {0x00009b24, 0x0000f790, 0x0000f790, 0x00008ba3, 0x00008ba3}, + {0x00009b28, 0x0000f794, 0x0000f794, 0x00008ba7, 0x00008ba7}, + {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008bab, 0x00008bab}, + {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008baf, 0x00008baf}, + {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008bb3, 0x00008bb3}, + {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008bb7, 0x00008bb7}, + {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008bc3, 0x00008bc3}, + {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008bc7, 0x00008bc7}, + {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008bcb, 0x00008bcb}, + {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008bcf, 0x00008bcf}, + {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008bd3, 0x00008bd3}, + {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008bd7, 0x00008bd7}, + {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008bdb, 0x00008bdb}, + {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008bdb, 0x00008bdb}, + {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008bdb, 0x00008bdb}, + {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008bdb, 0x00008bdb}, + {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008bdb, 0x00008bdb}, + {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008bdb, 0x00008bdb}, + {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008bdb, 0x00008bdb}, + {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008bdb, 0x00008bdb}, + {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008bdb, 0x00008bdb}, + {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008bdb, 0x00008bdb}, + {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008bdb, 0x00008bdb}, + {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008bdb, 0x00008bdb}, + {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008bdb, 0x00008bdb}, + {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008bdb, 0x00008bdb}, + {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008bdb, 0x00008bdb}, + {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008bdb, 0x00008bdb}, + {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008bdb, 0x00008bdb}, + {0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008bdb, 0x00008bdb}, + {0x00009848, 0x00001066, 0x00001066, 0x00001055, 0x00001055}, + {0x0000a848, 0x00001066, 0x00001066, 0x00001055, 0x00001055}, }; -static const u32 ar9280Modes_original_rxgain_9280_2[][6] = { - {0x00009a00, 0x00008184, 0x00008184, 0x00008000, 0x00008000, 0x00008000}, - {0x00009a04, 0x00008188, 0x00008188, 0x00008000, 0x00008000, 0x00008000}, - {0x00009a08, 0x0000818c, 0x0000818c, 0x00008000, 0x00008000, 0x00008000}, - {0x00009a0c, 0x00008190, 0x00008190, 0x00008000, 0x00008000, 0x00008000}, - {0x00009a10, 0x00008194, 0x00008194, 0x00008000, 0x00008000, 0x00008000}, - {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000}, - {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004}, - {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008}, - {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c}, - {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080}, - {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084}, - {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088}, - {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c}, - {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100}, - {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104}, - {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108}, - {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c}, - {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110}, - {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114}, - {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180}, - {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184}, - {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188}, - {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c}, - {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190}, - {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194}, - {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0}, - {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c}, - {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8}, - {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284}, - {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288}, - {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224}, - {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290}, - {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300}, - {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304}, - {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308}, - {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c}, - {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380}, - {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384}, - {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700}, - {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704}, - {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708}, - {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c}, - {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780}, - {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784}, - {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00}, - {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04}, - {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08}, - {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c}, - {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80}, - {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84}, - {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88}, - {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c}, - {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90}, - {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80}, - {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84}, - {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88}, - {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c}, - {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90}, - {0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c}, - {0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310}, - {0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384}, - {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388}, - {0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324}, - {0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704}, - {0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4}, - {0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8}, - {0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710}, - {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714}, - {0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720}, - {0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724}, - {0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728}, - {0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c}, - {0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0}, - {0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4}, - {0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8}, - {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0}, - {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4}, - {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8}, - {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5}, - {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9}, - {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad}, - {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1}, - {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5}, - {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9}, - {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5}, - {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9}, - {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1}, - {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5}, - {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9}, - {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6}, - {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca}, - {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce}, - {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2}, - {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6}, - {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3}, - {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7}, - {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb}, - {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf}, - {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7}, - {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db}, - {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db}, - {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db}, - {0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db}, - {0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063}, - {0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063}, +static const u32 ar9280Modes_original_rxgain_9280_2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009a00, 0x00008184, 0x00008184, 0x00008000, 0x00008000}, + {0x00009a04, 0x00008188, 0x00008188, 0x00008000, 0x00008000}, + {0x00009a08, 0x0000818c, 0x0000818c, 0x00008000, 0x00008000}, + {0x00009a0c, 0x00008190, 0x00008190, 0x00008000, 0x00008000}, + {0x00009a10, 0x00008194, 0x00008194, 0x00008000, 0x00008000}, + {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000}, + {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004}, + {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008}, + {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c}, + {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080}, + {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084}, + {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088}, + {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c}, + {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100}, + {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104}, + {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108}, + {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c}, + {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110}, + {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114}, + {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180}, + {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184}, + {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188}, + {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c}, + {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190}, + {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194}, + {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0}, + {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c}, + {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8}, + {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284}, + {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288}, + {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224}, + {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290}, + {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300}, + {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304}, + {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308}, + {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c}, + {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380}, + {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384}, + {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700}, + {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704}, + {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708}, + {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c}, + {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780}, + {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784}, + {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00}, + {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04}, + {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08}, + {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c}, + {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80}, + {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84}, + {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88}, + {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c}, + {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90}, + {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80}, + {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84}, + {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88}, + {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c}, + {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90}, + {0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c}, + {0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310}, + {0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384}, + {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388}, + {0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324}, + {0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704}, + {0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4}, + {0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8}, + {0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710}, + {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714}, + {0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720}, + {0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724}, + {0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728}, + {0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c}, + {0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0}, + {0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4}, + {0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8}, + {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0}, + {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4}, + {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8}, + {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5}, + {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9}, + {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad}, + {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1}, + {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5}, + {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9}, + {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5}, + {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9}, + {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1}, + {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5}, + {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9}, + {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6}, + {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca}, + {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce}, + {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2}, + {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6}, + {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3}, + {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7}, + {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb}, + {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf}, + {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7}, + {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db}, + {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db}, + {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db}, + {0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db}, + {0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063}, + {0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063}, }; -static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = { - {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290}, - {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300}, - {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304}, - {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308}, - {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c}, - {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000}, - {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004}, - {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008}, - {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c}, - {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080}, - {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084}, - {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088}, - {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c}, - {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100}, - {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104}, - {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108}, - {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c}, - {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110}, - {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114}, - {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180}, - {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184}, - {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188}, - {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c}, - {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190}, - {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194}, - {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0}, - {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c}, - {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8}, - {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284}, - {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288}, - {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224}, - {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290}, - {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300}, - {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304}, - {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308}, - {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c}, - {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380}, - {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384}, - {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700}, - {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704}, - {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708}, - {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c}, - {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780}, - {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784}, - {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00}, - {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04}, - {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08}, - {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c}, - {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80}, - {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84}, - {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88}, - {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c}, - {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90}, - {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80}, - {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84}, - {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88}, - {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c}, - {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90}, - {0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310}, - {0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314}, - {0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320}, - {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324}, - {0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328}, - {0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c}, - {0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330}, - {0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334}, - {0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321}, - {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325}, - {0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329}, - {0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d}, - {0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331}, - {0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335}, - {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322}, - {0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326}, - {0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a}, - {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e}, - {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332}, - {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336}, - {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323}, - {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327}, - {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b}, - {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f}, - {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333}, - {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337}, - {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343}, - {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347}, - {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b}, - {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f}, - {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353}, - {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357}, - {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b}, - {0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a}, - {0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a}, +static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290}, + {0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300}, + {0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304}, + {0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308}, + {0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c}, + {0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000}, + {0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004}, + {0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008}, + {0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c}, + {0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080}, + {0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084}, + {0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088}, + {0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c}, + {0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100}, + {0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104}, + {0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108}, + {0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c}, + {0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110}, + {0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114}, + {0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180}, + {0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184}, + {0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188}, + {0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c}, + {0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190}, + {0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194}, + {0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0}, + {0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c}, + {0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8}, + {0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284}, + {0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288}, + {0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224}, + {0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290}, + {0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300}, + {0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304}, + {0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308}, + {0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c}, + {0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380}, + {0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384}, + {0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700}, + {0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704}, + {0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708}, + {0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c}, + {0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780}, + {0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784}, + {0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00}, + {0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04}, + {0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08}, + {0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c}, + {0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80}, + {0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84}, + {0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88}, + {0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c}, + {0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90}, + {0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80}, + {0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84}, + {0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88}, + {0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c}, + {0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90}, + {0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310}, + {0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314}, + {0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320}, + {0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324}, + {0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328}, + {0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c}, + {0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330}, + {0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334}, + {0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321}, + {0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325}, + {0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329}, + {0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d}, + {0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331}, + {0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335}, + {0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322}, + {0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326}, + {0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a}, + {0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e}, + {0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332}, + {0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336}, + {0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323}, + {0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327}, + {0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b}, + {0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f}, + {0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333}, + {0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337}, + {0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343}, + {0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347}, + {0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b}, + {0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f}, + {0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353}, + {0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357}, + {0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b}, + {0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b}, + {0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b}, + {0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b}, + {0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b}, + {0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b}, + {0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b}, + {0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b}, + {0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b}, + {0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b}, + {0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b}, + {0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b}, + {0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b}, + {0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a}, + {0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a}, }; -static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { - {0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652}, - {0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce}, - {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002}, - {0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008}, - {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010}, - {0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012}, - {0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014}, - {0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a}, - {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211}, - {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213}, - {0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411, 0x00022411}, - {0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413, 0x00025413}, - {0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811, 0x00029811}, - {0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813, 0x0002c813}, - {0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14, 0x00030a14}, - {0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50, 0x00035a50}, - {0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c, 0x00039c4c}, - {0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a, 0x0003de8a}, - {0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92, 0x00042e92}, - {0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2, 0x00046ed2}, - {0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5, 0x0004bed5}, - {0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54, 0x0004ff54}, - {0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5, 0x00055fd5}, - {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081}, - {0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff}, - {0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff}, - {0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000}, - {0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000, 0x00172000}, - {0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480}, - {0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480}, +static const u32 ar9280Modes_high_power_tx_gain_9280_2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a274, 0x0a19e652, 0x0a19e652, 0x0a1aa652, 0x0a1aa652}, + {0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce}, + {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002}, + {0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008}, + {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010}, + {0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012}, + {0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014}, + {0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a}, + {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211}, + {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213}, + {0x0000a324, 0x00021092, 0x00021092, 0x00022411, 0x00022411}, + {0x0000a328, 0x0002510a, 0x0002510a, 0x00025413, 0x00025413}, + {0x0000a32c, 0x0002910c, 0x0002910c, 0x00029811, 0x00029811}, + {0x0000a330, 0x0002c18b, 0x0002c18b, 0x0002c813, 0x0002c813}, + {0x0000a334, 0x0002f1cc, 0x0002f1cc, 0x00030a14, 0x00030a14}, + {0x0000a338, 0x000321eb, 0x000321eb, 0x00035a50, 0x00035a50}, + {0x0000a33c, 0x000341ec, 0x000341ec, 0x00039c4c, 0x00039c4c}, + {0x0000a340, 0x000341ec, 0x000341ec, 0x0003de8a, 0x0003de8a}, + {0x0000a344, 0x000341ec, 0x000341ec, 0x00042e92, 0x00042e92}, + {0x0000a348, 0x000341ec, 0x000341ec, 0x00046ed2, 0x00046ed2}, + {0x0000a34c, 0x000341ec, 0x000341ec, 0x0004bed5, 0x0004bed5}, + {0x0000a350, 0x000341ec, 0x000341ec, 0x0004ff54, 0x0004ff54}, + {0x0000a354, 0x000341ec, 0x000341ec, 0x00055fd5, 0x00055fd5}, + {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081}, + {0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff}, + {0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff}, + {0x0000781c, 0x00172000, 0x00172000, 0x00172000, 0x00172000}, + {0x00007840, 0x00172000, 0x00172000, 0x00172000, 0x00172000}, + {0x00007820, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480}, + {0x00007844, 0xf258a480, 0xf258a480, 0xf258a480, 0xf258a480}, }; -static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { - {0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652}, - {0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce}, - {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002}, - {0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009}, - {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b}, - {0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012}, - {0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048}, - {0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a}, - {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211}, - {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213}, - {0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b}, - {0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412}, - {0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414}, - {0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a}, - {0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649}, - {0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b}, - {0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49}, - {0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48}, - {0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a}, - {0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88}, - {0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a}, - {0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9}, - {0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42}, - {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081}, - {0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff}, - {0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff}, - {0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000}, - {0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000, 0x00392000}, - {0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480}, - {0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480, 0x92592480}, +static const u32 ar9280Modes_original_tx_gain_9280_2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652}, + {0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce}, + {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002}, + {0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009}, + {0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b}, + {0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012}, + {0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048}, + {0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a}, + {0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211}, + {0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213}, + {0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b}, + {0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412}, + {0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414}, + {0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a}, + {0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649}, + {0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b}, + {0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49}, + {0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48}, + {0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a}, + {0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88}, + {0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a}, + {0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9}, + {0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42}, + {0x0000a3ec, 0x00f70081, 0x00f70081, 0x00f70081, 0x00f70081}, + {0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff}, + {0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff}, + {0x0000781c, 0x00392000, 0x00392000, 0x00392000, 0x00392000}, + {0x00007840, 0x00392000, 0x00392000, 0x00392000, 0x00392000}, + {0x00007820, 0x92592480, 0x92592480, 0x92592480, 0x92592480}, + {0x00007844, 0x92592480, 0x92592480, 0x92592480, 0x92592480}, }; static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { @@ -947,309 +953,310 @@ static const u32 ar9285PciePhy_clkreq_off_L1_9285[][2] = { {0x00004044, 0x00000000}, }; -static const u32 ar9285Modes_9285_1_2[][6] = { - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180}, - {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880}, - {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303}, - {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, - {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, - {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, - {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e}, - {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0}, - {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059}, - {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059}, - {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, - {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e}, - {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e}, - {0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18}, - {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, - {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881}, - {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0}, - {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016}, - {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d}, - {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010}, - {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c}, - {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00}, - {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, - {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f}, - {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, - {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, - {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000}, - {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000}, - {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000}, - {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000}, - {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000}, - {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000}, - {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000}, - {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000}, - {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000}, - {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000}, - {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000}, - {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000}, - {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000}, - {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000}, - {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000}, - {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000}, - {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000}, - {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000}, - {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000}, - {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000}, - {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000}, - {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000}, - {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000}, - {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000}, - {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000}, - {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000}, - {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000}, - {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000}, - {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000}, - {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000}, - {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000}, - {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000}, - {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000}, - {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000}, - {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000}, - {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000}, - {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000}, - {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000}, - {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000}, - {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000}, - {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000}, - {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000}, - {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000}, - {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000}, - {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000}, - {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000}, - {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000}, - {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000}, - {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000}, - {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000}, - {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000}, - {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000}, - {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000}, - {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000}, - {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000}, - {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000}, - {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000}, - {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000}, - {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000}, - {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000}, - {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000}, - {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000}, - {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000}, - {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000}, - {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000}, - {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000}, - {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000}, - {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000}, - {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000}, - {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000}, - {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000}, - {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000}, - {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000}, - {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000}, - {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000}, - {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000}, - {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000}, - {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000}, - {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000}, - {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000}, - {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000}, - {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000}, - {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000}, - {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000}, - {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000}, - {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000}, - {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000}, - {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000}, - {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000}, - {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000}, - {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000}, - {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000}, - {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000}, - {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000}, - {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000}, - {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000}, - {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000}, - {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000}, - {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000}, - {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000}, - {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000}, - {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000}, - {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000}, - {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000}, - {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000}, - {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000}, - {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000}, - {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000}, - {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000}, - {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000}, - {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000}, - {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000}, - {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000}, - {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000}, - {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000}, - {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000}, - {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000}, - {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000}, - {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000}, - {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000}, - {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000}, - {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000}, - {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000}, - {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000}, - {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000}, - {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000}, - {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000}, - {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000}, - {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000}, - {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000}, - {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000}, - {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000}, - {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000}, - {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000}, - {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000}, - {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000}, - {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000}, - {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000}, - {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000}, - {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000}, - {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000}, - {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000}, - {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000}, - {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000}, - {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000}, - {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000}, - {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000}, - {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000}, - {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000}, - {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000}, - {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000}, - {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000}, - {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000}, - {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000}, - {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000}, - {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000}, - {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000}, - {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000}, - {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000}, - {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000}, - {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000}, - {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000}, - {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000}, - {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000}, - {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000}, - {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000}, - {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000}, - {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000}, - {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000}, - {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000}, - {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000}, - {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000}, - {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000}, - {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000}, - {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000}, - {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000}, - {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000}, - {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000}, - {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004}, - {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000}, - {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000}, - {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, - {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000}, - {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000}, - {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e}, +static const u32 ar9285Modes_9285_1_2[][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}, + {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, + {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300}, + {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, + {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, + {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e}, + {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620}, + {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053}, + {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053}, + {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, + {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e}, + {0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20}, + {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00}, + {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d}, + {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020}, + {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c}, + {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00}, + {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, + {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f}, + {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, + {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, + {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084}, + {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088}, + {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c}, + {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100}, + {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104}, + {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108}, + {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c}, + {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110}, + {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114}, + {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180}, + {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184}, + {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188}, + {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c}, + {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190}, + {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194}, + {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0}, + {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c}, + {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8}, + {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284}, + {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288}, + {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224}, + {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290}, + {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300}, + {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304}, + {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308}, + {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c}, + {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380}, + {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384}, + {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700}, + {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704}, + {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708}, + {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c}, + {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780}, + {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784}, + {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00}, + {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04}, + {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08}, + {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c}, + {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80}, + {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84}, + {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88}, + {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c}, + {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90}, + {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80}, + {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84}, + {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88}, + {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c}, + {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90}, + {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c}, + {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310}, + {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384}, + {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388}, + {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324}, + {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704}, + {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4}, + {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8}, + {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710}, + {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714}, + {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720}, + {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724}, + {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728}, + {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c}, + {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0}, + {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4}, + {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8}, + {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0}, + {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4}, + {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8}, + {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5}, + {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9}, + {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad}, + {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1}, + {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5}, + {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9}, + {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5}, + {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9}, + {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1}, + {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5}, + {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9}, + {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6}, + {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca}, + {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce}, + {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2}, + {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6}, + {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3}, + {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7}, + {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb}, + {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf}, + {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7}, + {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084}, + {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088}, + {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c}, + {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100}, + {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104}, + {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108}, + {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c}, + {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110}, + {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114}, + {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180}, + {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184}, + {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188}, + {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c}, + {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190}, + {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194}, + {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0}, + {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c}, + {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8}, + {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284}, + {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288}, + {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224}, + {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290}, + {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300}, + {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304}, + {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308}, + {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c}, + {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380}, + {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384}, + {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700}, + {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704}, + {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708}, + {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c}, + {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780}, + {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784}, + {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00}, + {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04}, + {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08}, + {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c}, + {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80}, + {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84}, + {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88}, + {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c}, + {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90}, + {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80}, + {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84}, + {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88}, + {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c}, + {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90}, + {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c}, + {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310}, + {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384}, + {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388}, + {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324}, + {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704}, + {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4}, + {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8}, + {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710}, + {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714}, + {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720}, + {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724}, + {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728}, + {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c}, + {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0}, + {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4}, + {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8}, + {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0}, + {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4}, + {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8}, + {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5}, + {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9}, + {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad}, + {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1}, + {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5}, + {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9}, + {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5}, + {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9}, + {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1}, + {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5}, + {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9}, + {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6}, + {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca}, + {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce}, + {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2}, + {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6}, + {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3}, + {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7}, + {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb}, + {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf}, + {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7}, + {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004}, + {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000}, + {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000}, + {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, + {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000}, + {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e}, }; static const u32 ar9285Common_9285_1_2[][2] = { @@ -1572,164 +1579,168 @@ static const u32 ar9285Common_9285_1_2[][2] = { {0x00007870, 0x10142c00}, }; -static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][6] = { - {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000}, - {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000}, - {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000}, - {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000}, - {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000}, - {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000}, - {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000}, - {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000}, - {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000}, - {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000}, - {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000}, - {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000}, - {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000}, - {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8}, - {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b}, - {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e}, - {0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803}, - {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe}, - {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20}, - {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe}, - {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00}, - {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652}, - {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, - {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7}, - {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, - {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, - {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, - {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, +static const u32 ar9285Modes_high_power_tx_gain_9285_1_2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200}, + {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201}, + {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240}, + {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241}, + {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600}, + {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800}, + {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802}, + {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805}, + {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80}, + {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00}, + {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40}, + {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80}, + {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82}, + {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e}, + {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e}, + {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8}, + {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b}, + {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e}, + {0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803}, + {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe}, + {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20}, + {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe}, + {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00}, + {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652}, + {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, + {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7}, + {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, + {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, + {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, + {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, }; -static const u32 ar9285Modes_original_tx_gain_9285_1_2[][6] = { - {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000}, - {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000}, - {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000}, - {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000}, - {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000}, - {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000}, - {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000}, - {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000}, - {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000}, - {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000}, - {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000}, - {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000}, - {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000}, - {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8}, - {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b}, - {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e}, - {0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801}, - {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe}, - {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20}, - {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4}, - {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04}, - {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652}, - {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, - {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c}, - {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, - {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c}, - {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, - {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c}, +static const u32 ar9285Modes_original_tx_gain_9285_1_2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200}, + {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208}, + {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608}, + {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618}, + {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9}, + {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710}, + {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718}, + {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758}, + {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a}, + {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c}, + {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e}, + {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f}, + {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df}, + {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e}, + {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e}, + {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x00007814, 0x924934a8, 0x924934a8, 0x924934a8, 0x924934a8}, + {0x00007828, 0x26d2491b, 0x26d2491b, 0x26d2491b, 0x26d2491b}, + {0x00007830, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e, 0xedb6d96e}, + {0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801}, + {0x0000783c, 0x0001fffe, 0x0001fffe, 0x0001fffe, 0x0001fffe}, + {0x00007840, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20, 0xffeb1a20}, + {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4}, + {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04}, + {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652}, + {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, + {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c}, + {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, + {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c}, + {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, + {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c}, }; -static const u32 ar9285Modes_XE2_0_normal_power[][6] = { - {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000}, - {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000}, - {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000}, - {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000}, - {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000}, - {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000}, - {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000}, - {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000}, - {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000}, - {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000}, - {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000}, - {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000}, - {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000}, - {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8}, - {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b}, - {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6dbae}, - {0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441}, - {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe}, - {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c}, - {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4}, - {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04}, - {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652}, - {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, - {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c}, - {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, - {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c}, - {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, - {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c}, +static const u32 ar9285Modes_XE2_0_normal_power[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200}, + {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208}, + {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608}, + {0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618}, + {0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9}, + {0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710}, + {0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718}, + {0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758}, + {0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a}, + {0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c}, + {0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e}, + {0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f}, + {0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df}, + {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e}, + {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e}, + {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8}, + {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b}, + {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e}, + {0x00007838, 0xdac71441, 0xdac71441, 0xdac71441, 0xdac71441}, + {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe}, + {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c}, + {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4}, + {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04}, + {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652}, + {0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, + {0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c}, + {0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, + {0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c}, + {0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c}, + {0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c}, }; -static const u32 ar9285Modes_XE2_0_high_power[][6] = { - {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200, 0x00000000}, - {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201, 0x00000000}, - {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000}, - {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000}, - {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600, 0x00000000}, - {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800, 0x00000000}, - {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802, 0x00000000}, - {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805, 0x00000000}, - {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80, 0x00000000}, - {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80, 0x00000000}, - {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000}, - {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000}, - {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000}, - {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8}, - {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b, 0x4ad2491b}, - {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e}, - {0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443}, - {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe}, - {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c}, - {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe}, - {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00}, - {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652, 0x0a22a652}, - {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, - {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7}, - {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, - {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, - {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, - {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, +static const u32 ar9285Modes_XE2_0_high_power[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a304, 0x00000000, 0x00000000, 0x00006200, 0x00006200}, + {0x0000a308, 0x00000000, 0x00000000, 0x00008201, 0x00008201}, + {0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240}, + {0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241}, + {0x0000a314, 0x00000000, 0x00000000, 0x0000f600, 0x0000f600}, + {0x0000a318, 0x00000000, 0x00000000, 0x00012800, 0x00012800}, + {0x0000a31c, 0x00000000, 0x00000000, 0x00016802, 0x00016802}, + {0x0000a320, 0x00000000, 0x00000000, 0x0001b805, 0x0001b805}, + {0x0000a324, 0x00000000, 0x00000000, 0x00021a80, 0x00021a80}, + {0x0000a328, 0x00000000, 0x00000000, 0x00028b00, 0x00028b00}, + {0x0000a32c, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40}, + {0x0000a330, 0x00000000, 0x00000000, 0x0002cd80, 0x0002cd80}, + {0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82}, + {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e}, + {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e}, + {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x00007814, 0x92497ca8, 0x92497ca8, 0x92497ca8, 0x92497ca8}, + {0x00007828, 0x4ad2491b, 0x4ad2491b, 0x2ad2491b, 0x4ad2491b}, + {0x00007830, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e, 0xedb6da6e}, + {0x00007838, 0xdac71443, 0xdac71443, 0xdac71443, 0xdac71443}, + {0x0000783c, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe, 0x2481f6fe}, + {0x00007840, 0xba5f638c, 0xba5f638c, 0xba5f638c, 0xba5f638c}, + {0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe}, + {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00}, + {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a216652, 0x0a216652}, + {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, + {0x0000a27c, 0x050380e7, 0x050380e7, 0x050380e7, 0x050380e7}, + {0x0000a394, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, + {0x0000a398, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, + {0x0000a3dc, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, + {0x0000a3e0, 0x000000e7, 0x000000e7, 0x000000e7, 0x000000e7}, }; static const u32 ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { @@ -1760,50 +1771,51 @@ static const u32 ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { {0x00004044, 0x00000000}, }; -static const u32 ar9287Modes_9287_1_1[][6] = { - {0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160, 0x000001e0}, - {0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c, 0x000001e0}, - {0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38, 0x00001180}, - {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008}, - {0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00, 0x06e006e0}, - {0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b, 0x0988004f}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440, 0x00006880}, - {0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300, 0x00000303}, - {0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200, 0x02020200}, - {0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001, 0x3a020001}, - {0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007, 0x00000007}, - {0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e, 0x206a012e}, - {0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0, 0x037216a0}, - {0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2}, - {0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e}, - {0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e, 0x31395d5e}, - {0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20, 0x00058d18}, - {0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, - {0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881, 0x06903881}, - {0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898, 0x000007d0}, - {0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b, 0x00000016}, - {0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d}, - {0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010, 0xefbc1010}, - {0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010}, - {0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010, 0x00000010}, - {0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210, 0x00000210}, - {0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce, 0x000003ce}, - {0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c, 0x0000001c}, - {0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00, 0x00000c00}, - {0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444, 0x00000444}, - {0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a, 0x1883800a}, - {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000}, - {0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000, 0x0004a000}, - {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e}, - {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +static const u32 ar9287Modes_9287_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00001030, 0x00000000, 0x00000000, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000000, 0x00000000, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000000, 0x00000000, 0x00007c70, 0x00003e38}, + {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00008014, 0x00000000, 0x00000000, 0x10801600, 0x08400b00}, + {0x0000801c, 0x00000000, 0x00000000, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003200, 0x00003200, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00000000, 0x00000000, 0x00006880, 0x00003440}, + {0x00009804, 0x00000000, 0x00000000, 0x000003c4, 0x00000300}, + {0x00009820, 0x00000000, 0x00000000, 0x02020200, 0x02020200}, + {0x00009824, 0x00000000, 0x00000000, 0x01000e0e, 0x01000e0e}, + {0x00009828, 0x00000000, 0x00000000, 0x3a020001, 0x3a020001}, + {0x00009834, 0x00000000, 0x00000000, 0x00000e0e, 0x00000e0e}, + {0x00009838, 0x00000003, 0x00000003, 0x00000007, 0x00000007}, + {0x00009840, 0x206a002e, 0x206a002e, 0x206a012e, 0x206a012e}, + {0x00009844, 0x03720000, 0x03720000, 0x037216a0, 0x037216a0}, + {0x00009850, 0x60000000, 0x60000000, 0x6d4000e2, 0x6c4000e2}, + {0x00009858, 0x7c000d00, 0x7c000d00, 0x7ec84d2e, 0x7ec84d2e}, + {0x0000985c, 0x3100005e, 0x3100005e, 0x3139605e, 0x31395d5e}, + {0x00009860, 0x00058d00, 0x00058d00, 0x00058d20, 0x00058d20}, + {0x00009864, 0x00000e00, 0x00000e00, 0x0001ce00, 0x0001ce00}, + {0x00009868, 0x000040c0, 0x000040c0, 0x5ac640d0, 0x5ac640d0}, + {0x0000986c, 0x00000080, 0x00000080, 0x06903881, 0x06903881}, + {0x00009914, 0x00000000, 0x00000000, 0x00001130, 0x00000898}, + {0x00009918, 0x00000000, 0x00000000, 0x00000016, 0x0000000b}, + {0x00009924, 0xd00a8a01, 0xd00a8a01, 0xd00a8a0d, 0xd00a8a0d}, + {0x00009944, 0xefbc0000, 0xefbc0000, 0xefbc1010, 0xefbc1010}, + {0x00009960, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a960, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x00009964, 0x00000000, 0x00000000, 0x00000210, 0x00000210}, + {0x0000c968, 0x00000200, 0x00000200, 0x000003ce, 0x000003ce}, + {0x000099b8, 0x00000000, 0x00000000, 0x0000001c, 0x0000001c}, + {0x000099bc, 0x00000000, 0x00000000, 0x00000c00, 0x00000c00}, + {0x000099c0, 0x00000000, 0x00000000, 0x05eea6d4, 0x05eea6d4}, + {0x0000a204, 0x00000440, 0x00000440, 0x00000444, 0x00000444}, + {0x0000a20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000b20c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a21c, 0x1803800a, 0x1803800a, 0x1883800a, 0x1883800a}, + {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a250, 0x00000000, 0x00000000, 0x0004a000, 0x0004a000}, + {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e}, + {0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }; static const u32 ar9287Common_9287_1_1[][2] = { @@ -2189,313 +2201,315 @@ static const u32 ar9287Common_japan_2484_cck_fir_coeff_9287_1_1[][2] = { {0x0000a1fc, 0xca9228ee}, }; -static const u32 ar9287Modes_tx_gain_9287_1_1[][6] = { - {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002, 0x00004002}, - {0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004, 0x00008004}, - {0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a, 0x0000c00a}, - {0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c, 0x0001000c}, - {0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b, 0x0001420b}, - {0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a, 0x0001824a}, - {0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a, 0x0001c44a}, - {0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a, 0x0002064a}, - {0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a, 0x0002484a}, - {0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a, 0x00028a4a}, - {0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a}, - {0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a, 0x00030e4a}, - {0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a, 0x00034e8a}, - {0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c, 0x00038e8c}, - {0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc, 0x0003cecc}, - {0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4, 0x00040ed4}, - {0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc, 0x00044edc}, - {0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede, 0x00048ede}, - {0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e}, - {0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e, 0x00050f5e}, - {0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e, 0x00054f9e}, - {0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062, 0x00000062}, - {0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064, 0x00004064}, - {0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4, 0x000080a4}, - {0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa, 0x0000c0aa}, - {0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac, 0x000100ac}, - {0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4, 0x000140b4}, - {0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4, 0x000180f4}, - {0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134, 0x0001c134}, - {0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174, 0x00020174}, - {0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c, 0x0002417c}, - {0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e, 0x0002817e}, - {0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be, 0x0002c1be}, - {0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe, 0x000301fe}, - {0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000, 0x0a1aa000}, +static const u32 ar9287Modes_tx_gain_9287_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a304, 0x00000000, 0x00000000, 0x00004002, 0x00004002}, + {0x0000a308, 0x00000000, 0x00000000, 0x00008004, 0x00008004}, + {0x0000a30c, 0x00000000, 0x00000000, 0x0000c00a, 0x0000c00a}, + {0x0000a310, 0x00000000, 0x00000000, 0x0001000c, 0x0001000c}, + {0x0000a314, 0x00000000, 0x00000000, 0x0001420b, 0x0001420b}, + {0x0000a318, 0x00000000, 0x00000000, 0x0001824a, 0x0001824a}, + {0x0000a31c, 0x00000000, 0x00000000, 0x0001c44a, 0x0001c44a}, + {0x0000a320, 0x00000000, 0x00000000, 0x0002064a, 0x0002064a}, + {0x0000a324, 0x00000000, 0x00000000, 0x0002484a, 0x0002484a}, + {0x0000a328, 0x00000000, 0x00000000, 0x00028a4a, 0x00028a4a}, + {0x0000a32c, 0x00000000, 0x00000000, 0x0002cc4a, 0x0002cc4a}, + {0x0000a330, 0x00000000, 0x00000000, 0x00030e4a, 0x00030e4a}, + {0x0000a334, 0x00000000, 0x00000000, 0x00034e8a, 0x00034e8a}, + {0x0000a338, 0x00000000, 0x00000000, 0x00038e8c, 0x00038e8c}, + {0x0000a33c, 0x00000000, 0x00000000, 0x0003cecc, 0x0003cecc}, + {0x0000a340, 0x00000000, 0x00000000, 0x00040ed4, 0x00040ed4}, + {0x0000a344, 0x00000000, 0x00000000, 0x00044edc, 0x00044edc}, + {0x0000a348, 0x00000000, 0x00000000, 0x00048ede, 0x00048ede}, + {0x0000a34c, 0x00000000, 0x00000000, 0x0004cf1e, 0x0004cf1e}, + {0x0000a350, 0x00000000, 0x00000000, 0x00050f5e, 0x00050f5e}, + {0x0000a354, 0x00000000, 0x00000000, 0x00054f9e, 0x00054f9e}, + {0x0000a780, 0x00000000, 0x00000000, 0x00000062, 0x00000062}, + {0x0000a784, 0x00000000, 0x00000000, 0x00004064, 0x00004064}, + {0x0000a788, 0x00000000, 0x00000000, 0x000080a4, 0x000080a4}, + {0x0000a78c, 0x00000000, 0x00000000, 0x0000c0aa, 0x0000c0aa}, + {0x0000a790, 0x00000000, 0x00000000, 0x000100ac, 0x000100ac}, + {0x0000a794, 0x00000000, 0x00000000, 0x000140b4, 0x000140b4}, + {0x0000a798, 0x00000000, 0x00000000, 0x000180f4, 0x000180f4}, + {0x0000a79c, 0x00000000, 0x00000000, 0x0001c134, 0x0001c134}, + {0x0000a7a0, 0x00000000, 0x00000000, 0x00020174, 0x00020174}, + {0x0000a7a4, 0x00000000, 0x00000000, 0x0002417c, 0x0002417c}, + {0x0000a7a8, 0x00000000, 0x00000000, 0x0002817e, 0x0002817e}, + {0x0000a7ac, 0x00000000, 0x00000000, 0x0002c1be, 0x0002c1be}, + {0x0000a7b0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7b4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7b8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7bc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7c0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7c4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7c8, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7cc, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7d0, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a7d4, 0x00000000, 0x00000000, 0x000301fe, 0x000301fe}, + {0x0000a274, 0x0a180000, 0x0a180000, 0x0a1aa000, 0x0a1aa000}, }; -static const u32 ar9287Modes_rx_gain_9287_1_1[][6] = { - {0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120}, - {0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124}, - {0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128}, - {0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c}, - {0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130}, - {0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194}, - {0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198}, - {0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c}, - {0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210}, - {0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284}, - {0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288}, - {0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c}, - {0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290}, - {0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294}, - {0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0}, - {0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4}, - {0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8}, - {0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac}, - {0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0}, - {0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4}, - {0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8}, - {0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4}, - {0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708}, - {0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c}, - {0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710}, - {0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04}, - {0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08}, - {0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c}, - {0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10}, - {0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14}, - {0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18}, - {0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c}, - {0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90}, - {0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94}, - {0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98}, - {0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4}, - {0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8}, - {0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04}, - {0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08}, - {0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c}, - {0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10}, - {0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14}, - {0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18}, - {0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c}, - {0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90}, - {0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18}, - {0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24}, - {0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28}, - {0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314}, - {0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318}, - {0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c}, - {0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390}, - {0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394}, - {0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398}, - {0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4}, - {0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8}, - {0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac}, - {0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0}, - {0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380}, - {0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384}, - {0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388}, - {0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710}, - {0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714}, - {0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718}, - {0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10}, - {0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14}, - {0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18}, - {0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c}, - {0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90}, - {0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94}, - {0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c}, - {0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90}, - {0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94}, - {0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0}, - {0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4}, - {0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8}, - {0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac}, - {0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0}, - {0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4}, - {0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1}, - {0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5}, - {0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9}, - {0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad}, - {0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1}, - {0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5}, - {0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9}, - {0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5}, - {0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9}, - {0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd}, - {0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1}, - {0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5}, - {0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2}, - {0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6}, - {0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca}, - {0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce}, - {0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2}, - {0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6}, - {0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda}, - {0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7}, - {0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb}, - {0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf}, - {0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3}, - {0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7}, - {0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120, 0x0000a120}, - {0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124, 0x0000a124}, - {0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128, 0x0000a128}, - {0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c, 0x0000a12c}, - {0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130, 0x0000a130}, - {0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194, 0x0000a194}, - {0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198, 0x0000a198}, - {0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c, 0x0000a20c}, - {0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210, 0x0000a210}, - {0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284, 0x0000a284}, - {0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288, 0x0000a288}, - {0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c, 0x0000a28c}, - {0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290, 0x0000a290}, - {0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294, 0x0000a294}, - {0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0, 0x0000a2a0}, - {0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4, 0x0000a2a4}, - {0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8, 0x0000a2a8}, - {0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac, 0x0000a2ac}, - {0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0, 0x0000a2b0}, - {0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4, 0x0000a2b4}, - {0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8, 0x0000a2b8}, - {0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4, 0x0000a2c4}, - {0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708, 0x0000a708}, - {0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c, 0x0000a70c}, - {0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710, 0x0000a710}, - {0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04, 0x0000ab04}, - {0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08, 0x0000ab08}, - {0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c, 0x0000ab0c}, - {0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10, 0x0000ab10}, - {0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14, 0x0000ab14}, - {0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18, 0x0000ab18}, - {0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c, 0x0000ab8c}, - {0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90, 0x0000ab90}, - {0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94, 0x0000ab94}, - {0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98, 0x0000ab98}, - {0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4, 0x0000aba4}, - {0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8, 0x0000aba8}, - {0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04, 0x0000cb04}, - {0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08, 0x0000cb08}, - {0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c, 0x0000cb0c}, - {0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10, 0x0000cb10}, - {0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14, 0x0000cb14}, - {0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18, 0x0000cb18}, - {0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c, 0x0000cb8c}, - {0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90, 0x0000cb90}, - {0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18, 0x0000cf18}, - {0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24, 0x0000cf24}, - {0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28, 0x0000cf28}, - {0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314, 0x0000d314}, - {0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318, 0x0000d318}, - {0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c, 0x0000d38c}, - {0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390, 0x0000d390}, - {0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394, 0x0000d394}, - {0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398, 0x0000d398}, - {0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4, 0x0000d3a4}, - {0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8, 0x0000d3a8}, - {0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac, 0x0000d3ac}, - {0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0, 0x0000d3b0}, - {0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380, 0x0000f380}, - {0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384, 0x0000f384}, - {0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388, 0x0000f388}, - {0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710, 0x0000f710}, - {0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714, 0x0000f714}, - {0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718, 0x0000f718}, - {0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10, 0x0000fb10}, - {0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14, 0x0000fb14}, - {0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18, 0x0000fb18}, - {0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c, 0x0000fb8c}, - {0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90, 0x0000fb90}, - {0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94, 0x0000fb94}, - {0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c, 0x0000ff8c}, - {0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90, 0x0000ff90}, - {0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94, 0x0000ff94}, - {0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0, 0x0000ffa0}, - {0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4, 0x0000ffa4}, - {0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8, 0x0000ffa8}, - {0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac, 0x0000ffac}, - {0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0, 0x0000ffb0}, - {0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4, 0x0000ffb4}, - {0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1, 0x0000ffa1}, - {0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5, 0x0000ffa5}, - {0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9, 0x0000ffa9}, - {0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad, 0x0000ffad}, - {0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1, 0x0000ffb1}, - {0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5, 0x0000ffb5}, - {0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9, 0x0000ffb9}, - {0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5, 0x0000ffc5}, - {0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9, 0x0000ffc9}, - {0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd, 0x0000ffcd}, - {0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1, 0x0000ffd1}, - {0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5, 0x0000ffd5}, - {0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2, 0x0000ffc2}, - {0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6, 0x0000ffc6}, - {0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca, 0x0000ffca}, - {0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce, 0x0000ffce}, - {0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2, 0x0000ffd2}, - {0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6, 0x0000ffd6}, - {0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda, 0x0000ffda}, - {0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7, 0x0000ffc7}, - {0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb, 0x0000ffcb}, - {0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf, 0x0000ffcf}, - {0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3, 0x0000ffd3}, - {0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7, 0x0000ffd7}, - {0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb, 0x0000ffdb}, - {0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067}, - {0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067, 0x00001067}, +static const u32 ar9287Modes_rx_gain_9287_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009a00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120}, + {0x00009a04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124}, + {0x00009a08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128}, + {0x00009a0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c}, + {0x00009a10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130}, + {0x00009a14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194}, + {0x00009a18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198}, + {0x00009a1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c}, + {0x00009a20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210}, + {0x00009a24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284}, + {0x00009a28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288}, + {0x00009a2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c}, + {0x00009a30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290}, + {0x00009a34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294}, + {0x00009a38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0}, + {0x00009a3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4}, + {0x00009a40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8}, + {0x00009a44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac}, + {0x00009a48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0}, + {0x00009a4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4}, + {0x00009a50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8}, + {0x00009a54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4}, + {0x00009a58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708}, + {0x00009a5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c}, + {0x00009a60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710}, + {0x00009a64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04}, + {0x00009a68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08}, + {0x00009a6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c}, + {0x00009a70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10}, + {0x00009a74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14}, + {0x00009a78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18}, + {0x00009a7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c}, + {0x00009a80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90}, + {0x00009a84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94}, + {0x00009a88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98}, + {0x00009a8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4}, + {0x00009a90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8}, + {0x00009a94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04}, + {0x00009a98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08}, + {0x00009a9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c}, + {0x00009aa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10}, + {0x00009aa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14}, + {0x00009aa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18}, + {0x00009aac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c}, + {0x00009ab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90}, + {0x00009ab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18}, + {0x00009ab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24}, + {0x00009abc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28}, + {0x00009ac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314}, + {0x00009ac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318}, + {0x00009ac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c}, + {0x00009acc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390}, + {0x00009ad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394}, + {0x00009ad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398}, + {0x00009ad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4}, + {0x00009adc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8}, + {0x00009ae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac}, + {0x00009ae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0}, + {0x00009ae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380}, + {0x00009aec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384}, + {0x00009af0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388}, + {0x00009af4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710}, + {0x00009af8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714}, + {0x00009afc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718}, + {0x00009b00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10}, + {0x00009b04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14}, + {0x00009b08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18}, + {0x00009b0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c}, + {0x00009b10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90}, + {0x00009b14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94}, + {0x00009b18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c}, + {0x00009b1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90}, + {0x00009b20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94}, + {0x00009b24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0}, + {0x00009b28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4}, + {0x00009b2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8}, + {0x00009b30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac}, + {0x00009b34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0}, + {0x00009b38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4}, + {0x00009b3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1}, + {0x00009b40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5}, + {0x00009b44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9}, + {0x00009b48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad}, + {0x00009b4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1}, + {0x00009b50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5}, + {0x00009b54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9}, + {0x00009b58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5}, + {0x00009b5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9}, + {0x00009b60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd}, + {0x00009b64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1}, + {0x00009b68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5}, + {0x00009b6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2}, + {0x00009b70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6}, + {0x00009b74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca}, + {0x00009b78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce}, + {0x00009b7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2}, + {0x00009b80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6}, + {0x00009b84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda}, + {0x00009b88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7}, + {0x00009b8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb}, + {0x00009b90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf}, + {0x00009b94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3}, + {0x00009b98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7}, + {0x00009b9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009ba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009ba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009ba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009be0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009be4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009be8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009bfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000aa00, 0x00000000, 0x00000000, 0x0000a120, 0x0000a120}, + {0x0000aa04, 0x00000000, 0x00000000, 0x0000a124, 0x0000a124}, + {0x0000aa08, 0x00000000, 0x00000000, 0x0000a128, 0x0000a128}, + {0x0000aa0c, 0x00000000, 0x00000000, 0x0000a12c, 0x0000a12c}, + {0x0000aa10, 0x00000000, 0x00000000, 0x0000a130, 0x0000a130}, + {0x0000aa14, 0x00000000, 0x00000000, 0x0000a194, 0x0000a194}, + {0x0000aa18, 0x00000000, 0x00000000, 0x0000a198, 0x0000a198}, + {0x0000aa1c, 0x00000000, 0x00000000, 0x0000a20c, 0x0000a20c}, + {0x0000aa20, 0x00000000, 0x00000000, 0x0000a210, 0x0000a210}, + {0x0000aa24, 0x00000000, 0x00000000, 0x0000a284, 0x0000a284}, + {0x0000aa28, 0x00000000, 0x00000000, 0x0000a288, 0x0000a288}, + {0x0000aa2c, 0x00000000, 0x00000000, 0x0000a28c, 0x0000a28c}, + {0x0000aa30, 0x00000000, 0x00000000, 0x0000a290, 0x0000a290}, + {0x0000aa34, 0x00000000, 0x00000000, 0x0000a294, 0x0000a294}, + {0x0000aa38, 0x00000000, 0x00000000, 0x0000a2a0, 0x0000a2a0}, + {0x0000aa3c, 0x00000000, 0x00000000, 0x0000a2a4, 0x0000a2a4}, + {0x0000aa40, 0x00000000, 0x00000000, 0x0000a2a8, 0x0000a2a8}, + {0x0000aa44, 0x00000000, 0x00000000, 0x0000a2ac, 0x0000a2ac}, + {0x0000aa48, 0x00000000, 0x00000000, 0x0000a2b0, 0x0000a2b0}, + {0x0000aa4c, 0x00000000, 0x00000000, 0x0000a2b4, 0x0000a2b4}, + {0x0000aa50, 0x00000000, 0x00000000, 0x0000a2b8, 0x0000a2b8}, + {0x0000aa54, 0x00000000, 0x00000000, 0x0000a2c4, 0x0000a2c4}, + {0x0000aa58, 0x00000000, 0x00000000, 0x0000a708, 0x0000a708}, + {0x0000aa5c, 0x00000000, 0x00000000, 0x0000a70c, 0x0000a70c}, + {0x0000aa60, 0x00000000, 0x00000000, 0x0000a710, 0x0000a710}, + {0x0000aa64, 0x00000000, 0x00000000, 0x0000ab04, 0x0000ab04}, + {0x0000aa68, 0x00000000, 0x00000000, 0x0000ab08, 0x0000ab08}, + {0x0000aa6c, 0x00000000, 0x00000000, 0x0000ab0c, 0x0000ab0c}, + {0x0000aa70, 0x00000000, 0x00000000, 0x0000ab10, 0x0000ab10}, + {0x0000aa74, 0x00000000, 0x00000000, 0x0000ab14, 0x0000ab14}, + {0x0000aa78, 0x00000000, 0x00000000, 0x0000ab18, 0x0000ab18}, + {0x0000aa7c, 0x00000000, 0x00000000, 0x0000ab8c, 0x0000ab8c}, + {0x0000aa80, 0x00000000, 0x00000000, 0x0000ab90, 0x0000ab90}, + {0x0000aa84, 0x00000000, 0x00000000, 0x0000ab94, 0x0000ab94}, + {0x0000aa88, 0x00000000, 0x00000000, 0x0000ab98, 0x0000ab98}, + {0x0000aa8c, 0x00000000, 0x00000000, 0x0000aba4, 0x0000aba4}, + {0x0000aa90, 0x00000000, 0x00000000, 0x0000aba8, 0x0000aba8}, + {0x0000aa94, 0x00000000, 0x00000000, 0x0000cb04, 0x0000cb04}, + {0x0000aa98, 0x00000000, 0x00000000, 0x0000cb08, 0x0000cb08}, + {0x0000aa9c, 0x00000000, 0x00000000, 0x0000cb0c, 0x0000cb0c}, + {0x0000aaa0, 0x00000000, 0x00000000, 0x0000cb10, 0x0000cb10}, + {0x0000aaa4, 0x00000000, 0x00000000, 0x0000cb14, 0x0000cb14}, + {0x0000aaa8, 0x00000000, 0x00000000, 0x0000cb18, 0x0000cb18}, + {0x0000aaac, 0x00000000, 0x00000000, 0x0000cb8c, 0x0000cb8c}, + {0x0000aab0, 0x00000000, 0x00000000, 0x0000cb90, 0x0000cb90}, + {0x0000aab4, 0x00000000, 0x00000000, 0x0000cf18, 0x0000cf18}, + {0x0000aab8, 0x00000000, 0x00000000, 0x0000cf24, 0x0000cf24}, + {0x0000aabc, 0x00000000, 0x00000000, 0x0000cf28, 0x0000cf28}, + {0x0000aac0, 0x00000000, 0x00000000, 0x0000d314, 0x0000d314}, + {0x0000aac4, 0x00000000, 0x00000000, 0x0000d318, 0x0000d318}, + {0x0000aac8, 0x00000000, 0x00000000, 0x0000d38c, 0x0000d38c}, + {0x0000aacc, 0x00000000, 0x00000000, 0x0000d390, 0x0000d390}, + {0x0000aad0, 0x00000000, 0x00000000, 0x0000d394, 0x0000d394}, + {0x0000aad4, 0x00000000, 0x00000000, 0x0000d398, 0x0000d398}, + {0x0000aad8, 0x00000000, 0x00000000, 0x0000d3a4, 0x0000d3a4}, + {0x0000aadc, 0x00000000, 0x00000000, 0x0000d3a8, 0x0000d3a8}, + {0x0000aae0, 0x00000000, 0x00000000, 0x0000d3ac, 0x0000d3ac}, + {0x0000aae4, 0x00000000, 0x00000000, 0x0000d3b0, 0x0000d3b0}, + {0x0000aae8, 0x00000000, 0x00000000, 0x0000f380, 0x0000f380}, + {0x0000aaec, 0x00000000, 0x00000000, 0x0000f384, 0x0000f384}, + {0x0000aaf0, 0x00000000, 0x00000000, 0x0000f388, 0x0000f388}, + {0x0000aaf4, 0x00000000, 0x00000000, 0x0000f710, 0x0000f710}, + {0x0000aaf8, 0x00000000, 0x00000000, 0x0000f714, 0x0000f714}, + {0x0000aafc, 0x00000000, 0x00000000, 0x0000f718, 0x0000f718}, + {0x0000ab00, 0x00000000, 0x00000000, 0x0000fb10, 0x0000fb10}, + {0x0000ab04, 0x00000000, 0x00000000, 0x0000fb14, 0x0000fb14}, + {0x0000ab08, 0x00000000, 0x00000000, 0x0000fb18, 0x0000fb18}, + {0x0000ab0c, 0x00000000, 0x00000000, 0x0000fb8c, 0x0000fb8c}, + {0x0000ab10, 0x00000000, 0x00000000, 0x0000fb90, 0x0000fb90}, + {0x0000ab14, 0x00000000, 0x00000000, 0x0000fb94, 0x0000fb94}, + {0x0000ab18, 0x00000000, 0x00000000, 0x0000ff8c, 0x0000ff8c}, + {0x0000ab1c, 0x00000000, 0x00000000, 0x0000ff90, 0x0000ff90}, + {0x0000ab20, 0x00000000, 0x00000000, 0x0000ff94, 0x0000ff94}, + {0x0000ab24, 0x00000000, 0x00000000, 0x0000ffa0, 0x0000ffa0}, + {0x0000ab28, 0x00000000, 0x00000000, 0x0000ffa4, 0x0000ffa4}, + {0x0000ab2c, 0x00000000, 0x00000000, 0x0000ffa8, 0x0000ffa8}, + {0x0000ab30, 0x00000000, 0x00000000, 0x0000ffac, 0x0000ffac}, + {0x0000ab34, 0x00000000, 0x00000000, 0x0000ffb0, 0x0000ffb0}, + {0x0000ab38, 0x00000000, 0x00000000, 0x0000ffb4, 0x0000ffb4}, + {0x0000ab3c, 0x00000000, 0x00000000, 0x0000ffa1, 0x0000ffa1}, + {0x0000ab40, 0x00000000, 0x00000000, 0x0000ffa5, 0x0000ffa5}, + {0x0000ab44, 0x00000000, 0x00000000, 0x0000ffa9, 0x0000ffa9}, + {0x0000ab48, 0x00000000, 0x00000000, 0x0000ffad, 0x0000ffad}, + {0x0000ab4c, 0x00000000, 0x00000000, 0x0000ffb1, 0x0000ffb1}, + {0x0000ab50, 0x00000000, 0x00000000, 0x0000ffb5, 0x0000ffb5}, + {0x0000ab54, 0x00000000, 0x00000000, 0x0000ffb9, 0x0000ffb9}, + {0x0000ab58, 0x00000000, 0x00000000, 0x0000ffc5, 0x0000ffc5}, + {0x0000ab5c, 0x00000000, 0x00000000, 0x0000ffc9, 0x0000ffc9}, + {0x0000ab60, 0x00000000, 0x00000000, 0x0000ffcd, 0x0000ffcd}, + {0x0000ab64, 0x00000000, 0x00000000, 0x0000ffd1, 0x0000ffd1}, + {0x0000ab68, 0x00000000, 0x00000000, 0x0000ffd5, 0x0000ffd5}, + {0x0000ab6c, 0x00000000, 0x00000000, 0x0000ffc2, 0x0000ffc2}, + {0x0000ab70, 0x00000000, 0x00000000, 0x0000ffc6, 0x0000ffc6}, + {0x0000ab74, 0x00000000, 0x00000000, 0x0000ffca, 0x0000ffca}, + {0x0000ab78, 0x00000000, 0x00000000, 0x0000ffce, 0x0000ffce}, + {0x0000ab7c, 0x00000000, 0x00000000, 0x0000ffd2, 0x0000ffd2}, + {0x0000ab80, 0x00000000, 0x00000000, 0x0000ffd6, 0x0000ffd6}, + {0x0000ab84, 0x00000000, 0x00000000, 0x0000ffda, 0x0000ffda}, + {0x0000ab88, 0x00000000, 0x00000000, 0x0000ffc7, 0x0000ffc7}, + {0x0000ab8c, 0x00000000, 0x00000000, 0x0000ffcb, 0x0000ffcb}, + {0x0000ab90, 0x00000000, 0x00000000, 0x0000ffcf, 0x0000ffcf}, + {0x0000ab94, 0x00000000, 0x00000000, 0x0000ffd3, 0x0000ffd3}, + {0x0000ab98, 0x00000000, 0x00000000, 0x0000ffd7, 0x0000ffd7}, + {0x0000ab9c, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000aba0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000aba4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000aba8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abac, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abb0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abb4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abb8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abbc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abc0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abc4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abc8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abcc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abd0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abd4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abd8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abdc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abe0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abe4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abe8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abec, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abf0, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abf4, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abf8, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x0000abfc, 0x00000000, 0x00000000, 0x0000ffdb, 0x0000ffdb}, + {0x00009848, 0x00000000, 0x00000000, 0x00001067, 0x00001067}, + {0x0000a848, 0x00000000, 0x00000000, 0x00001067, 0x00001067}, }; static const u32 ar9287PciePhy_clkreq_always_on_L1_9287_1_1[][2] = { @@ -2526,310 +2540,311 @@ static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = { {0x00004044, 0x00000000}, }; -static const u32 ar9271Modes_9271[][6] = { - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180}, - {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880}, - {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303}, - {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, - {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001}, - {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, - {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e}, - {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620, 0x037216a0}, - {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059}, - {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053, 0x00001059}, - {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, - {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e}, - {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e}, - {0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, - {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00}, - {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881}, - {0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310, 0x30002310}, - {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0}, - {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016}, - {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d}, - {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010}, - {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c}, - {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00}, - {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, - {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f}, - {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, - {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, - {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000}, - {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000}, - {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000}, - {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000}, - {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000}, - {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000}, - {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000}, - {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000}, - {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000}, - {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000}, - {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000}, - {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000}, - {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000}, - {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000}, - {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000}, - {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000}, - {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000}, - {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000}, - {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000}, - {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000}, - {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000}, - {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000}, - {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000}, - {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000}, - {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000}, - {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000}, - {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000}, - {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000}, - {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000}, - {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000}, - {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000}, - {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000}, - {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000}, - {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000}, - {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000}, - {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000}, - {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000}, - {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000}, - {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000}, - {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000}, - {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000}, - {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000}, - {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000}, - {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000}, - {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000}, - {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000}, - {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000}, - {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000}, - {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000}, - {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000}, - {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000}, - {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000}, - {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000}, - {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000}, - {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000}, - {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000}, - {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000}, - {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000}, - {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000}, - {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000}, - {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000}, - {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000}, - {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000}, - {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000}, - {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000}, - {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000}, - {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000}, - {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000}, - {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000}, - {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000}, - {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000}, - {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000}, - {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000}, - {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000}, - {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000}, - {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000}, - {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000}, - {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000}, - {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000}, - {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000}, - {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000}, - {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000}, - {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000}, - {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000}, - {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000}, - {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000}, - {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000}, - {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000}, - {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000}, - {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084, 0x00000000}, - {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088, 0x00000000}, - {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c, 0x00000000}, - {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100, 0x00000000}, - {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104, 0x00000000}, - {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108, 0x00000000}, - {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c, 0x00000000}, - {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110, 0x00000000}, - {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114, 0x00000000}, - {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180, 0x00000000}, - {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184, 0x00000000}, - {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188, 0x00000000}, - {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c, 0x00000000}, - {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190, 0x00000000}, - {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194, 0x00000000}, - {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0, 0x00000000}, - {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c, 0x00000000}, - {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8, 0x00000000}, - {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284, 0x00000000}, - {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288, 0x00000000}, - {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224, 0x00000000}, - {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290, 0x00000000}, - {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300, 0x00000000}, - {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304, 0x00000000}, - {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308, 0x00000000}, - {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c, 0x00000000}, - {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380, 0x00000000}, - {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384, 0x00000000}, - {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000}, - {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000}, - {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000}, - {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000}, - {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000}, - {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000}, - {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00, 0x00000000}, - {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04, 0x00000000}, - {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08, 0x00000000}, - {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c, 0x00000000}, - {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80, 0x00000000}, - {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84, 0x00000000}, - {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88, 0x00000000}, - {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c, 0x00000000}, - {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90, 0x00000000}, - {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80, 0x00000000}, - {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84, 0x00000000}, - {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88, 0x00000000}, - {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c, 0x00000000}, - {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90, 0x00000000}, - {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c, 0x00000000}, - {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310, 0x00000000}, - {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384, 0x00000000}, - {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388, 0x00000000}, - {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324, 0x00000000}, - {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704, 0x00000000}, - {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4, 0x00000000}, - {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8, 0x00000000}, - {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710, 0x00000000}, - {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714, 0x00000000}, - {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720, 0x00000000}, - {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724, 0x00000000}, - {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728, 0x00000000}, - {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c, 0x00000000}, - {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0, 0x00000000}, - {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4, 0x00000000}, - {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8, 0x00000000}, - {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0, 0x00000000}, - {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4, 0x00000000}, - {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8, 0x00000000}, - {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5, 0x00000000}, - {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9, 0x00000000}, - {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad, 0x00000000}, - {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1, 0x00000000}, - {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5, 0x00000000}, - {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9, 0x00000000}, - {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5, 0x00000000}, - {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9, 0x00000000}, - {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1, 0x00000000}, - {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5, 0x00000000}, - {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9, 0x00000000}, - {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6, 0x00000000}, - {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca, 0x00000000}, - {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce, 0x00000000}, - {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2, 0x00000000}, - {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6, 0x00000000}, - {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3, 0x00000000}, - {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7, 0x00000000}, - {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb, 0x00000000}, - {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf, 0x00000000}, - {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7, 0x00000000}, - {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db, 0x00000000}, - {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004}, - {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000}, - {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000, 0x0001f000}, - {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, - {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000}, - {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000}, - {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e}, +static const u32 ar9271Modes_9271[][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}, + {0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, + {0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300}, + {0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x00009824, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x00009828, 0x3a020001, 0x3a020001, 0x3a020001, 0x3a020001}, + {0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007}, + {0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e}, + {0x00009844, 0x0372161e, 0x0372161e, 0x03721620, 0x03721620}, + {0x00009848, 0x00001066, 0x00001066, 0x00001053, 0x00001053}, + {0x0000a848, 0x00001066, 0x00001066, 0x00001053, 0x00001053}, + {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, + {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e}, + {0x00009860, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18}, + {0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00}, + {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x00009910, 0x30002310, 0x30002310, 0x30002310, 0x30002310}, + {0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d}, + {0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020}, + {0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c}, + {0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00}, + {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77}, + {0x000099c8, 0x6af6532f, 0x6af6532f, 0x6af6532f, 0x6af6532f}, + {0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8}, + {0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384}, + {0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009a00, 0x00000000, 0x00000000, 0x00058084, 0x00058084}, + {0x00009a04, 0x00000000, 0x00000000, 0x00058088, 0x00058088}, + {0x00009a08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c}, + {0x00009a0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100}, + {0x00009a10, 0x00000000, 0x00000000, 0x00058104, 0x00058104}, + {0x00009a14, 0x00000000, 0x00000000, 0x00058108, 0x00058108}, + {0x00009a18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c}, + {0x00009a1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110}, + {0x00009a20, 0x00000000, 0x00000000, 0x00058114, 0x00058114}, + {0x00009a24, 0x00000000, 0x00000000, 0x00058180, 0x00058180}, + {0x00009a28, 0x00000000, 0x00000000, 0x00058184, 0x00058184}, + {0x00009a2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188}, + {0x00009a30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c}, + {0x00009a34, 0x00000000, 0x00000000, 0x00058190, 0x00058190}, + {0x00009a38, 0x00000000, 0x00000000, 0x00058194, 0x00058194}, + {0x00009a3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0}, + {0x00009a40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c}, + {0x00009a44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8}, + {0x00009a48, 0x00000000, 0x00000000, 0x00058284, 0x00058284}, + {0x00009a4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288}, + {0x00009a50, 0x00000000, 0x00000000, 0x00058224, 0x00058224}, + {0x00009a54, 0x00000000, 0x00000000, 0x00058290, 0x00058290}, + {0x00009a58, 0x00000000, 0x00000000, 0x00058300, 0x00058300}, + {0x00009a5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304}, + {0x00009a60, 0x00000000, 0x00000000, 0x00058308, 0x00058308}, + {0x00009a64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c}, + {0x00009a68, 0x00000000, 0x00000000, 0x00058380, 0x00058380}, + {0x00009a6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384}, + {0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700}, + {0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704}, + {0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708}, + {0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c}, + {0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780}, + {0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784}, + {0x00009a88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00}, + {0x00009a8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04}, + {0x00009a90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08}, + {0x00009a94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c}, + {0x00009a98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80}, + {0x00009a9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84}, + {0x00009aa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88}, + {0x00009aa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c}, + {0x00009aa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90}, + {0x00009aac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80}, + {0x00009ab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84}, + {0x00009ab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88}, + {0x00009ab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c}, + {0x00009abc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90}, + {0x00009ac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c}, + {0x00009ac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310}, + {0x00009ac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384}, + {0x00009acc, 0x00000000, 0x00000000, 0x000db388, 0x000db388}, + {0x00009ad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324}, + {0x00009ad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704}, + {0x00009ad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4}, + {0x00009adc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8}, + {0x00009ae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710}, + {0x00009ae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714}, + {0x00009ae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720}, + {0x00009aec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724}, + {0x00009af0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728}, + {0x00009af4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c}, + {0x00009af8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0}, + {0x00009afc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4}, + {0x00009b00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8}, + {0x00009b04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0}, + {0x00009b08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4}, + {0x00009b0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8}, + {0x00009b10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5}, + {0x00009b14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9}, + {0x00009b18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad}, + {0x00009b1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1}, + {0x00009b20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5}, + {0x00009b24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9}, + {0x00009b28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5}, + {0x00009b2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9}, + {0x00009b30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1}, + {0x00009b34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5}, + {0x00009b38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9}, + {0x00009b3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6}, + {0x00009b40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca}, + {0x00009b44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce}, + {0x00009b48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2}, + {0x00009b4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6}, + {0x00009b50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3}, + {0x00009b54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7}, + {0x00009b58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb}, + {0x00009b5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf}, + {0x00009b60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7}, + {0x00009b64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009b9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009ba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009ba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009ba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009be0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009be4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009be8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x00009bfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000aa00, 0x00000000, 0x00000000, 0x00058084, 0x00058084}, + {0x0000aa04, 0x00000000, 0x00000000, 0x00058088, 0x00058088}, + {0x0000aa08, 0x00000000, 0x00000000, 0x0005808c, 0x0005808c}, + {0x0000aa0c, 0x00000000, 0x00000000, 0x00058100, 0x00058100}, + {0x0000aa10, 0x00000000, 0x00000000, 0x00058104, 0x00058104}, + {0x0000aa14, 0x00000000, 0x00000000, 0x00058108, 0x00058108}, + {0x0000aa18, 0x00000000, 0x00000000, 0x0005810c, 0x0005810c}, + {0x0000aa1c, 0x00000000, 0x00000000, 0x00058110, 0x00058110}, + {0x0000aa20, 0x00000000, 0x00000000, 0x00058114, 0x00058114}, + {0x0000aa24, 0x00000000, 0x00000000, 0x00058180, 0x00058180}, + {0x0000aa28, 0x00000000, 0x00000000, 0x00058184, 0x00058184}, + {0x0000aa2c, 0x00000000, 0x00000000, 0x00058188, 0x00058188}, + {0x0000aa30, 0x00000000, 0x00000000, 0x0005818c, 0x0005818c}, + {0x0000aa34, 0x00000000, 0x00000000, 0x00058190, 0x00058190}, + {0x0000aa38, 0x00000000, 0x00000000, 0x00058194, 0x00058194}, + {0x0000aa3c, 0x00000000, 0x00000000, 0x000581a0, 0x000581a0}, + {0x0000aa40, 0x00000000, 0x00000000, 0x0005820c, 0x0005820c}, + {0x0000aa44, 0x00000000, 0x00000000, 0x000581a8, 0x000581a8}, + {0x0000aa48, 0x00000000, 0x00000000, 0x00058284, 0x00058284}, + {0x0000aa4c, 0x00000000, 0x00000000, 0x00058288, 0x00058288}, + {0x0000aa50, 0x00000000, 0x00000000, 0x00058224, 0x00058224}, + {0x0000aa54, 0x00000000, 0x00000000, 0x00058290, 0x00058290}, + {0x0000aa58, 0x00000000, 0x00000000, 0x00058300, 0x00058300}, + {0x0000aa5c, 0x00000000, 0x00000000, 0x00058304, 0x00058304}, + {0x0000aa60, 0x00000000, 0x00000000, 0x00058308, 0x00058308}, + {0x0000aa64, 0x00000000, 0x00000000, 0x0005830c, 0x0005830c}, + {0x0000aa68, 0x00000000, 0x00000000, 0x00058380, 0x00058380}, + {0x0000aa6c, 0x00000000, 0x00000000, 0x00058384, 0x00058384}, + {0x0000aa70, 0x00000000, 0x00000000, 0x00068700, 0x00068700}, + {0x0000aa74, 0x00000000, 0x00000000, 0x00068704, 0x00068704}, + {0x0000aa78, 0x00000000, 0x00000000, 0x00068708, 0x00068708}, + {0x0000aa7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c}, + {0x0000aa80, 0x00000000, 0x00000000, 0x00068780, 0x00068780}, + {0x0000aa84, 0x00000000, 0x00000000, 0x00068784, 0x00068784}, + {0x0000aa88, 0x00000000, 0x00000000, 0x00078b00, 0x00078b00}, + {0x0000aa8c, 0x00000000, 0x00000000, 0x00078b04, 0x00078b04}, + {0x0000aa90, 0x00000000, 0x00000000, 0x00078b08, 0x00078b08}, + {0x0000aa94, 0x00000000, 0x00000000, 0x00078b0c, 0x00078b0c}, + {0x0000aa98, 0x00000000, 0x00000000, 0x00078b80, 0x00078b80}, + {0x0000aa9c, 0x00000000, 0x00000000, 0x00078b84, 0x00078b84}, + {0x0000aaa0, 0x00000000, 0x00000000, 0x00078b88, 0x00078b88}, + {0x0000aaa4, 0x00000000, 0x00000000, 0x00078b8c, 0x00078b8c}, + {0x0000aaa8, 0x00000000, 0x00000000, 0x00078b90, 0x00078b90}, + {0x0000aaac, 0x00000000, 0x00000000, 0x000caf80, 0x000caf80}, + {0x0000aab0, 0x00000000, 0x00000000, 0x000caf84, 0x000caf84}, + {0x0000aab4, 0x00000000, 0x00000000, 0x000caf88, 0x000caf88}, + {0x0000aab8, 0x00000000, 0x00000000, 0x000caf8c, 0x000caf8c}, + {0x0000aabc, 0x00000000, 0x00000000, 0x000caf90, 0x000caf90}, + {0x0000aac0, 0x00000000, 0x00000000, 0x000db30c, 0x000db30c}, + {0x0000aac4, 0x00000000, 0x00000000, 0x000db310, 0x000db310}, + {0x0000aac8, 0x00000000, 0x00000000, 0x000db384, 0x000db384}, + {0x0000aacc, 0x00000000, 0x00000000, 0x000db388, 0x000db388}, + {0x0000aad0, 0x00000000, 0x00000000, 0x000db324, 0x000db324}, + {0x0000aad4, 0x00000000, 0x00000000, 0x000eb704, 0x000eb704}, + {0x0000aad8, 0x00000000, 0x00000000, 0x000eb6a4, 0x000eb6a4}, + {0x0000aadc, 0x00000000, 0x00000000, 0x000eb6a8, 0x000eb6a8}, + {0x0000aae0, 0x00000000, 0x00000000, 0x000eb710, 0x000eb710}, + {0x0000aae4, 0x00000000, 0x00000000, 0x000eb714, 0x000eb714}, + {0x0000aae8, 0x00000000, 0x00000000, 0x000eb720, 0x000eb720}, + {0x0000aaec, 0x00000000, 0x00000000, 0x000eb724, 0x000eb724}, + {0x0000aaf0, 0x00000000, 0x00000000, 0x000eb728, 0x000eb728}, + {0x0000aaf4, 0x00000000, 0x00000000, 0x000eb72c, 0x000eb72c}, + {0x0000aaf8, 0x00000000, 0x00000000, 0x000eb7a0, 0x000eb7a0}, + {0x0000aafc, 0x00000000, 0x00000000, 0x000eb7a4, 0x000eb7a4}, + {0x0000ab00, 0x00000000, 0x00000000, 0x000eb7a8, 0x000eb7a8}, + {0x0000ab04, 0x00000000, 0x00000000, 0x000eb7b0, 0x000eb7b0}, + {0x0000ab08, 0x00000000, 0x00000000, 0x000eb7b4, 0x000eb7b4}, + {0x0000ab0c, 0x00000000, 0x00000000, 0x000eb7b8, 0x000eb7b8}, + {0x0000ab10, 0x00000000, 0x00000000, 0x000eb7a5, 0x000eb7a5}, + {0x0000ab14, 0x00000000, 0x00000000, 0x000eb7a9, 0x000eb7a9}, + {0x0000ab18, 0x00000000, 0x00000000, 0x000eb7ad, 0x000eb7ad}, + {0x0000ab1c, 0x00000000, 0x00000000, 0x000eb7b1, 0x000eb7b1}, + {0x0000ab20, 0x00000000, 0x00000000, 0x000eb7b5, 0x000eb7b5}, + {0x0000ab24, 0x00000000, 0x00000000, 0x000eb7b9, 0x000eb7b9}, + {0x0000ab28, 0x00000000, 0x00000000, 0x000eb7c5, 0x000eb7c5}, + {0x0000ab2c, 0x00000000, 0x00000000, 0x000eb7c9, 0x000eb7c9}, + {0x0000ab30, 0x00000000, 0x00000000, 0x000eb7d1, 0x000eb7d1}, + {0x0000ab34, 0x00000000, 0x00000000, 0x000eb7d5, 0x000eb7d5}, + {0x0000ab38, 0x00000000, 0x00000000, 0x000eb7d9, 0x000eb7d9}, + {0x0000ab3c, 0x00000000, 0x00000000, 0x000eb7c6, 0x000eb7c6}, + {0x0000ab40, 0x00000000, 0x00000000, 0x000eb7ca, 0x000eb7ca}, + {0x0000ab44, 0x00000000, 0x00000000, 0x000eb7ce, 0x000eb7ce}, + {0x0000ab48, 0x00000000, 0x00000000, 0x000eb7d2, 0x000eb7d2}, + {0x0000ab4c, 0x00000000, 0x00000000, 0x000eb7d6, 0x000eb7d6}, + {0x0000ab50, 0x00000000, 0x00000000, 0x000eb7c3, 0x000eb7c3}, + {0x0000ab54, 0x00000000, 0x00000000, 0x000eb7c7, 0x000eb7c7}, + {0x0000ab58, 0x00000000, 0x00000000, 0x000eb7cb, 0x000eb7cb}, + {0x0000ab5c, 0x00000000, 0x00000000, 0x000eb7cf, 0x000eb7cf}, + {0x0000ab60, 0x00000000, 0x00000000, 0x000eb7d7, 0x000eb7d7}, + {0x0000ab64, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab68, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab6c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab70, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab74, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab78, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab7c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab80, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab84, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab88, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab8c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab90, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab94, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab98, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000ab9c, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000aba0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000aba4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000aba8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abac, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abb0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abb4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abb8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abbc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abc0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abc4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abc8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abcc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abd0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abd4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abd8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abdc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abe0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abe4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abe8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abec, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abf0, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abf4, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abf8, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000abfc, 0x00000000, 0x00000000, 0x000eb7db, 0x000eb7db}, + {0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004}, + {0x0000a20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000}, + {0x0000b20c, 0x00000014, 0x00000014, 0x0001f000, 0x0001f000}, + {0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a}, + {0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000}, + {0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e}, }; static const u32 ar9271Common_9271[][2] = { @@ -3175,91 +3190,95 @@ static const u32 ar9271Common_japan_2484_cck_fir_coeff_9271[][2] = { {0x0000a1fc, 0xca9228ee}, }; -static const u32 ar9271Modes_9271_1_0_only[][6] = { - {0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311, 0x30002311}, - {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, +static const u32 ar9271Modes_9271_1_0_only[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009910, 0x30002311, 0x30002311, 0x30002311, 0x30002311}, + {0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001}, }; -static const u32 ar9271Modes_9271_ANI_reg[][6] = { - {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, - {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e, 0x3139605e}, - {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e}, - {0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881, 0x06903881}, - {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8}, - {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d}, - {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, +static const u32 ar9271Modes_9271_ANI_reg[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2}, + {0x0000985c, 0x3139605e, 0x3139605e, 0x3137605e, 0x3137605e}, + {0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x0000986c, 0x06903881, 0x06903881, 0x06903881, 0x06903881}, + {0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x0000a208, 0x803e68c8, 0x803e68c8, 0x803e68c8, 0x803e68c8}, + {0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d}, + {0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, }; -static const u32 ar9271Modes_normal_power_tx_gain_9271[][6] = { - {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000}, - {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000}, - {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000}, - {0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610, 0x00000000}, - {0x0000a314, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0, 0x00000000}, - {0x0000a318, 0x00000000, 0x00000000, 0x00039758, 0x00039758, 0x00000000}, - {0x0000a31c, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759, 0x00000000}, - {0x0000a320, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a, 0x00000000}, - {0x0000a324, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c, 0x00000000}, - {0x0000a328, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x0004979f, 0x0004979f, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x0004d7df, 0x0004d7df, 0x00000000}, - {0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000}, - {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000}, - {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000}, - {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029, 0x00000029}, - {0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff}, - {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4}, - {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04}, - {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a218652, 0x0a218652, 0x0a22a652}, - {0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd}, - {0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd}, - {0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd}, - {0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd}, - {0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd}, - {0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd}, +static const u32 ar9271Modes_normal_power_tx_gain_9271[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200}, + {0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208}, + {0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608}, + {0x0000a310, 0x00000000, 0x00000000, 0x0001e610, 0x0001e610}, + {0x0000a314, 0x00000000, 0x00000000, 0x00024650, 0x00024650}, + {0x0000a318, 0x00000000, 0x00000000, 0x0002d6d0, 0x0002d6d0}, + {0x0000a31c, 0x00000000, 0x00000000, 0x000316d2, 0x000316d2}, + {0x0000a320, 0x00000000, 0x00000000, 0x00039758, 0x00039758}, + {0x0000a324, 0x00000000, 0x00000000, 0x0003b759, 0x0003b759}, + {0x0000a328, 0x00000000, 0x00000000, 0x0003d75a, 0x0003d75a}, + {0x0000a32c, 0x00000000, 0x00000000, 0x0004175c, 0x0004175c}, + {0x0000a330, 0x00000000, 0x00000000, 0x0004575e, 0x0004575e}, + {0x0000a334, 0x000368de, 0x000368de, 0x0004979f, 0x0004979f}, + {0x0000a338, 0x0003891e, 0x0003891e, 0x0004d7df, 0x0004d7df}, + {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e}, + {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x00007838, 0x00000029, 0x00000029, 0x00000029, 0x00000029}, + {0x00007824, 0x00d8abff, 0x00d8abff, 0x00d8abff, 0x00d8abff}, + {0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4}, + {0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04}, + {0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21c652, 0x0a21c652}, + {0x0000a278, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd}, + {0x0000a27c, 0x050e83bd, 0x050e83bd, 0x050e83bd, 0x050e83bd}, + {0x0000a394, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd}, + {0x0000a398, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd}, + {0x0000a3dc, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd, 0x3bdef7bd}, + {0x0000a3e0, 0x000003bd, 0x000003bd, 0x000003bd, 0x000003bd}, }; -static const u32 ar9271Modes_high_power_tx_gain_9271[][6] = { - {0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000, 0x00000000}, - {0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200, 0x00000000}, - {0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201, 0x00000000}, - {0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240, 0x00000000}, - {0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241, 0x00000000}, - {0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600, 0x00000000}, - {0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800, 0x00000000}, - {0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802, 0x00000000}, - {0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805, 0x00000000}, - {0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41, 0x00000000}, - {0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00, 0x00000000}, - {0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40, 0x00000000}, - {0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80, 0x00000000}, - {0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de, 0x00000000}, - {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000}, - {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000}, - {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000}, - {0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b}, - {0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff}, - {0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6}, - {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00}, - {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a214652, 0x0a214652, 0x0a22a652}, - {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, - {0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063}, - {0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63}, - {0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063}, - {0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63}, - {0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063, 0x00000063}, +static const u32 ar9271Modes_high_power_tx_gain_9271[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a300, 0x00000000, 0x00000000, 0x00010000, 0x00010000}, + {0x0000a304, 0x00000000, 0x00000000, 0x00016200, 0x00016200}, + {0x0000a308, 0x00000000, 0x00000000, 0x00018201, 0x00018201}, + {0x0000a30c, 0x00000000, 0x00000000, 0x0001b240, 0x0001b240}, + {0x0000a310, 0x00000000, 0x00000000, 0x0001d241, 0x0001d241}, + {0x0000a314, 0x00000000, 0x00000000, 0x0001f600, 0x0001f600}, + {0x0000a318, 0x00000000, 0x00000000, 0x00022800, 0x00022800}, + {0x0000a31c, 0x00000000, 0x00000000, 0x00026802, 0x00026802}, + {0x0000a320, 0x00000000, 0x00000000, 0x0002b805, 0x0002b805}, + {0x0000a324, 0x00000000, 0x00000000, 0x0002ea41, 0x0002ea41}, + {0x0000a328, 0x00000000, 0x00000000, 0x00038b00, 0x00038b00}, + {0x0000a32c, 0x00000000, 0x00000000, 0x0003ab40, 0x0003ab40}, + {0x0000a330, 0x00000000, 0x00000000, 0x0003cd80, 0x0003cd80}, + {0x0000a334, 0x000368de, 0x000368de, 0x000368de, 0x000368de}, + {0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e}, + {0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e}, + {0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df}, + {0x00007838, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b}, + {0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff}, + {0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba}, + {0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00}, + {0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a214652, 0x0a214652}, + {0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7}, + {0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063}, + {0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63}, + {0x0000a398, 0x00000063, 0x00000063, 0x00000063, 0x00000063}, + {0x0000a3dc, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63}, + {0x0000a3e0, 0x00000063, 0x00000063, 0x00000063, 0x00000063}, }; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c index 45b262fe2c25..f7d8e516a2a9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c @@ -170,33 +170,104 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) return true; } -static void ar9002_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen, - bool is_firstseg, bool is_lastseg, - const void *ds0, dma_addr_t buf_addr, - unsigned int qcu) +static void +ar9002_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) { struct ar5416_desc *ads = AR5416DESC(ds); + u32 ctl1, ctl6; - ads->ds_data = buf_addr; - - if (is_firstseg) { - ads->ds_ctl1 |= seglen | (is_lastseg ? 0 : AR_TxMore); - } else if (is_lastseg) { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = seglen; - ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; - ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; - } else { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = seglen | AR_TxMore; - ads->ds_ctl2 = 0; - ads->ds_ctl3 = 0; - } ads->ds_txstatus0 = ads->ds_txstatus1 = 0; ads->ds_txstatus2 = ads->ds_txstatus3 = 0; ads->ds_txstatus4 = ads->ds_txstatus5 = 0; 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]; + + ctl1 = i->buf_len[0] | (i->is_last ? 0 : AR_TxMore); + ctl6 = SM(i->keytype, AR_EncrType); + + if (AR_SREV_9285(ah)) { + ads->ds_ctl8 = 0; + ads->ds_ctl9 = 0; + ads->ds_ctl10 = 0; + ads->ds_ctl11 = 0; + } + + 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) + | set11nTries(i->rates, 1) + | set11nTries(i->rates, 2) + | set11nTries(i->rates, 3) + | (i->dur_update ? AR_DurUpdateEna : 0) + | SM(0, AR_BurstDur); + + ACCESS_ONCE(ads->ds_ctl3) = set11nRate(i->rates, 0) + | set11nRate(i->rates, 1) + | set11nRate(i->rates, 2) + | set11nRate(i->rates, 3); + } else { + ACCESS_ONCE(ads->ds_ctl2) = 0; + ACCESS_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; + return; + } + + ctl1 |= (i->keyix != ATH9K_TXKEYIX_INVALID ? SM(i->keyix, AR_DestIdx) : 0) + | SM(i->type, AR_FrameType) + | (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) + | (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) + | (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); + + switch (i->aggr) { + case AGGR_BUF_FIRST: + ctl6 |= SM(i->aggr_len, AR_AggrLen); + /* fall through */ + case AGGR_BUF_MIDDLE: + ctl1 |= AR_IsAggr | AR_MoreAggr; + ctl6 |= SM(i->ndelim, AR_PadDelim); + break; + case AGGR_BUF_LAST: + ctl1 |= AR_IsAggr; + break; + case AGGR_BUF_NONE: + break; + } + + ACCESS_ONCE(ads->ds_ctl0) = (i->pkt_len & AR_FrameLen) + | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(i->txpower, AR_XmitPower) + | (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)); + + ACCESS_ONCE(ads->ds_ctl1) = ctl1; + ACCESS_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); + + ACCESS_ONCE(ads->ds_ctl5) = set11nPktDurRTSCTS(i->rates, 2) + | set11nPktDurRTSCTS(i->rates, 3); + + 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); } static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, @@ -271,145 +342,6 @@ static int ar9002_hw_proc_txdesc(struct ath_hw *ah, void *ds, return 0; } -static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds, - u32 pktLen, enum ath9k_pkt_type type, - u32 txPower, u32 keyIx, - enum ath9k_key_type keyType, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (txPower > 63) - txPower = 63; - - ads->ds_ctl0 = (pktLen & AR_FrameLen) - | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(txPower, AR_XmitPower) - | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) - | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); - - ads->ds_ctl1 = - (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) - | SM(type, AR_FrameType) - | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) - | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) - | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); - - ads->ds_ctl6 = SM(keyType, AR_EncrType); - - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) { - ads->ds_ctl8 = 0; - ads->ds_ctl9 = 0; - ads->ds_ctl10 = 0; - ads->ds_ctl11 = 0; - } -} - -static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (val) - ads->ds_ctl0 |= AR_ClrDestMask; - else - ads->ds_ctl0 &= ~AR_ClrDestMask; -} - -static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, - void *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - struct ar5416_desc *last_ads = AR5416DESC(lastds); - u32 ds_ctl0; - - if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { - ds_ctl0 = ads->ds_ctl0; - - if (flags & ATH9K_TXDESC_RTSENA) { - ds_ctl0 &= ~AR_CTSEnable; - ds_ctl0 |= AR_RTSEnable; - } else { - ds_ctl0 &= ~AR_RTSEnable; - ds_ctl0 |= AR_CTSEnable; - } - - ads->ds_ctl0 = ds_ctl0; - } else { - ads->ds_ctl0 = - (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); - } - - ads->ds_ctl2 = set11nTries(series, 0) - | set11nTries(series, 1) - | set11nTries(series, 2) - | set11nTries(series, 3) - | (durUpdateEn ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); - - ads->ds_ctl3 = set11nRate(series, 0) - | set11nRate(series, 1) - | set11nRate(series, 2) - | set11nRate(series, 3); - - ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) - | set11nPktDurRTSCTS(series, 1); - - ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) - | set11nPktDurRTSCTS(series, 3); - - ads->ds_ctl7 = set11nRateFlags(series, 0) - | set11nRateFlags(series, 1) - | set11nRateFlags(series, 2) - | set11nRateFlags(series, 3) - | SM(rtsctsRate, AR_RTSCTSRate); - last_ads->ds_ctl2 = ads->ds_ctl2; - last_ads->ds_ctl3 = ads->ds_ctl3; -} - -static void ar9002_hw_set11n_aggr_first(struct ath_hw *ah, void *ds, - u32 aggrLen) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); - ads->ds_ctl6 &= ~AR_AggrLen; - ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); -} - -static void ar9002_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds, - u32 numDelims) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - unsigned int ctl6; - - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); - - ctl6 = ads->ds_ctl6; - ctl6 &= ~AR_PadDelim; - ctl6 |= SM(numDelims, AR_PadDelim); - ads->ds_ctl6 = ctl6; -} - -static void ar9002_hw_set11n_aggr_last(struct ath_hw *ah, void *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= AR_IsAggr; - ads->ds_ctl1 &= ~AR_MoreAggr; - ads->ds_ctl6 &= ~AR_PadDelim; -} - -static void ar9002_hw_clr11n_aggr(struct ath_hw *ah, void *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); -} - void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags) { @@ -433,13 +365,6 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah) ops->rx_enable = ar9002_hw_rx_enable; ops->set_desc_link = ar9002_hw_set_desc_link; ops->get_isr = ar9002_hw_get_isr; - ops->fill_txdesc = ar9002_hw_fill_txdesc; + ops->set_txdesc = ar9002_set_txdesc; ops->proc_txdesc = ar9002_hw_proc_txdesc; - ops->set11n_txdesc = ar9002_hw_set11n_txdesc; - ops->set11n_ratescenario = ar9002_hw_set11n_ratescenario; - ops->set11n_aggr_first = ar9002_hw_set11n_aggr_first; - ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle; - ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last; - ops->clr11n_aggr = ar9002_hw_clr11n_aggr; - ops->set_clrdmask = ar9002_hw_set_clrdmask; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 3e69c631ebb4..026f9de15d15 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -24,11 +24,11 @@ static const u32 ar9300_2p2_radio_postamble[][5] = { {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}, }; @@ -190,7 +190,7 @@ static const u32 ar9300_2p2_radio_core[][2] = { {0x00016288, 0x05a20408}, {0x0001628c, 0x00038c07}, {0x00016290, 0x00000004}, - {0x00016294, 0x458aa14f}, + {0x00016294, 0x458a214f}, {0x00016380, 0x00000000}, {0x00016384, 0x00000000}, {0x00016388, 0x00800700}, @@ -636,7 +636,7 @@ static const u32 ar9300_2p2_baseband_postamble[][5] = { {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0}, + {0x0000a204, 0x000036c0, 0x000036c4, 0x000036c4, 0x000036c0}, {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, {0x0000a22c, 0x01026a2f, 0x01026a2f, 0x01026a2f, 0x01026a2f}, {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, @@ -835,108 +835,108 @@ 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, 0x5a08442e, 0x5a08442e, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x5e0a4431, 0x5e0a4431, 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, 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, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, - {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, - {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, - {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, - {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, - {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, - {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6}, - {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001}, - {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index f48051c50092..16851cb109a6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -17,8 +17,9 @@ #include "hw.h" #include "hw-ops.h" #include "ar9003_phy.h" +#include "ar9003_rtt.h" -#define MAX_MEASUREMENT 8 +#define MAX_MEASUREMENT MAX_IQCAL_MEASUREMENT #define MAX_MAG_DELTA 11 #define MAX_PHS_DELTA 10 @@ -615,11 +616,10 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, { int mp_max = -64, max_idx = 0; int mp_min = 63, min_idx = 0; - int mp_avg = 0, i, outlier_idx = 0; + int mp_avg = 0, i, outlier_idx = 0, mp_count = 0; /* find min/max mismatch across all calibrated gains */ for (i = 0; i < nmeasurement; i++) { - mp_avg += mp_coeff[i]; if (mp_coeff[i] > mp_max) { mp_max = mp_coeff[i]; max_idx = i; @@ -632,10 +632,20 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, /* 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))) + (abs(mp_coeff[i]) < abs(mp_min))) { mp_avg += mp_coeff[i]; + mp_count++; + } } - mp_avg /= (nmeasurement - 1); + + /* + * finding mean magnitude/phase if possible, otherwise + * just use the last value as the mean + */ + if (mp_count) + mp_avg /= mp_count; + else + mp_avg = mp_coeff[nmeasurement - 1]; /* detect outlier */ if (abs(mp_max - mp_min) > max_delta) { @@ -643,16 +653,19 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, outlier_idx = max_idx; else outlier_idx = min_idx; + + mp_coeff[outlier_idx] = mp_avg; } - mp_coeff[outlier_idx] = mp_avg; } static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, u8 num_chains, - struct coeff *coeff) + struct coeff *coeff, + bool is_reusable) { int i, im, nmeasurement; 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++) { @@ -702,7 +715,13 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, REG_RMW_FIELD(ah, tx_corr_coeff[im][i], AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, coeff->iqc_coeff[0]); + + if (caldata) + caldata->tx_corr_coeff[im][i] = + coeff->iqc_coeff[0]; } + if (caldata) + caldata->num_measures[i] = nmeasurement; } REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, @@ -710,8 +729,10 @@ 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); - return; + if (caldata) + caldata->done_txiqcal_once = is_reusable; + return; } static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah) @@ -738,7 +759,7 @@ 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) +static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah, bool is_reusable) { struct ath_common *common = ath9k_hw_common(ah); const u32 txiqcal_status[AR9300_MAX_CHAINS] = { @@ -827,7 +848,8 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah) coeff.phs_coeff[i][im] -= 128; } } - ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff); + ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, + &coeff, is_reusable); return; @@ -835,23 +857,129 @@ tx_iqcal_fail: ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n"); return; } + +static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) +{ + struct ath9k_hw_cal_data *caldata = ah->caldata; + u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS]; + int i, im; + + 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); + if (!AR_SREV_9485(ah)) { + tx_corr_coeff[i * 2][1] = + tx_corr_coeff[(i * 2) + 1][1] = + AR_PHY_TX_IQCAL_CORR_COEFF_B1(i); + + tx_corr_coeff[i * 2][2] = + tx_corr_coeff[(i * 2) + 1][2] = + AR_PHY_TX_IQCAL_CORR_COEFF_B2(i); + } + } + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->txchainmask & (1 << i))) + continue; + + for (im = 0; im < caldata->num_measures[i]; im++) { + if ((im % 2) == 0) + REG_RMW_FIELD(ah, tx_corr_coeff[im][i], + AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, + caldata->tx_corr_coeff[im][i]); + else + REG_RMW_FIELD(ah, tx_corr_coeff[im][i], + AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, + caldata->tx_corr_coeff[im][i]); + } + } + + REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, + AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); + REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, + AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); +} + +static bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) +{ + struct ath9k_rtt_hist *hist; + u32 *table; + int i; + bool restore; + + if (!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT) || !ah->caldata) + return false; + + hist = &ah->caldata->rtt_hist; + ar9003_hw_rtt_enable(ah); + ar9003_hw_rtt_set_mask(ah, 0x10); + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + table = &hist->table[i][hist->num_readings][0]; + ar9003_hw_rtt_load_hist(ah, i, table); + } + restore = ar9003_hw_rtt_force_restore(ah); + ar9003_hw_rtt_disable(ah); + + return restore; +} + static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); - struct ath9k_hw_capabilities *pCap = &ah->caps; - int val; - bool txiqcal_done = false; + struct ath9k_hw_cal_data *caldata = ah->caldata; + bool txiqcal_done = false, txclcal_done = false; + bool is_reusable = true, status = true; + bool run_rtt_cal = false, run_agc_cal; + bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT); + 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; + int i, j; + u32 cl_idx[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0, + AR_PHY_CL_TAB_1, + AR_PHY_CL_TAB_2 }; + + if (rtt) { + if (!ar9003_hw_rtt_restore(ah, chan)) + run_rtt_cal = true; + + ath_dbg(common, ATH_DBG_CALIBRATE, "RTT restore %s\n", + run_rtt_cal ? "failed" : "succeed"); + } + run_agc_cal = run_rtt_cal; - val = REG_READ(ah, AR_ENT_OTP); - ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val); + if (run_rtt_cal) { + ar9003_hw_rtt_enable(ah); + ar9003_hw_rtt_set_mask(ah, 0x00); + ar9003_hw_rtt_clear_hist(ah); + } - /* Configure rx/tx chains before running AGC/TxiQ cals */ - if (val & AR_ENT_OTP_CHAIN2_DISABLE) - ar9003_hw_set_chain_masks(ah, 0x3, 0x3); - else - ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask, - pCap->tx_chainmask); + 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 (ah->enabled_cals & TX_CL_CAL) { + if (caldata && caldata->done_txclcal_once) + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, + AR_PHY_CL_CAL_ENABLE); + else { + REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, + AR_PHY_CL_CAL_ENABLE); + run_agc_cal = true; + } + } + + if (!(ah->enabled_cals & TX_IQ_CAL)) + goto skip_tx_iqcal; /* Do Tx IQ Calibration */ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1, @@ -862,34 +990,98 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, * For AR9485 or later chips, TxIQ cal runs as part of * AGC calibration */ - if (AR_SREV_9485_OR_LATER(ah)) - txiqcal_done = true; - else { - 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); - } - - /* Calibrate the AGC */ - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - /* Poll for offset calibration complete */ - if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, - 0, AH_WAIT_TIMEOUT)) { + 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, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + else + REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + txiqcal_done = run_agc_cal = true; + goto skip_tx_iqcal; + } else if (caldata && !caldata->done_txiqcal_once) + run_agc_cal = true; + + 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); + +skip_tx_iqcal: + 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) | + AR_PHY_AGC_CONTROL_CAL); + + /* Poll for offset calibration complete */ + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + } + if (rtt && !run_rtt_cal) { + agc_ctrl |= agc_supp_cals; + REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl); + } + + if (!status) { + if (run_rtt_cal) + ar9003_hw_rtt_disable(ah); + ath_dbg(common, ATH_DBG_CALIBRATE, - "offset calibration failed to complete in 1ms; noisy environment?\n"); + "offset calibration failed to complete in 1ms;" + "noisy environment?\n"); return false; } if (txiqcal_done) - ar9003_hw_tx_iq_cal_post_proc(ah); + ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable); + else if (caldata && caldata->done_txiqcal_once) + ar9003_hw_tx_iq_cal_reload(ah); + +#define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j)) + if (caldata && (ah->enabled_cals & TX_CL_CAL)) { + txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & + AR_PHY_AGC_CONTROL_CLC_SUCCESS); + if (caldata->done_txclcal_once) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->txchainmask & (1 << i))) + continue; + for (j = 0; j < MAX_CL_TAB_ENTRY; j++) + REG_WRITE(ah, CL_TAB_ENTRY(cl_idx[i]), + caldata->tx_clcal[i][j]); + } + } else if (is_reusable && txclcal_done) { + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->txchainmask & (1 << i))) + continue; + for (j = 0; j < MAX_CL_TAB_ENTRY; j++) + caldata->tx_clcal[i][j] = + REG_READ(ah, + CL_TAB_ENTRY(cl_idx[i])); + } + caldata->done_txclcal_once = true; + } + } +#undef CL_TAB_ENTRY + + if (run_rtt_cal && caldata) { + struct ath9k_rtt_hist *hist = &caldata->rtt_hist; + if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) { + u32 *table; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + table = &hist->table[i][hist->num_readings][0]; + ar9003_hw_rtt_fill_hist(ah, i, table); + } + } - /* Revert chainmasks to their original values before NF cal */ - ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + ar9003_hw_rtt_disable(ah); + } + ath9k_hw_loadnf(ah, chan); ath9k_hw_start_nfcal(ah, true); /* Initialize list pointers */ @@ -916,8 +1108,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, if (ah->cal_list_curr) ath9k_hw_reset_calibration(ah, ah->cal_list_curr); - if (ah->caldata) - ah->caldata->CalValid = 0; + if (caldata) + caldata->CalValid = 0; return true; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 1b9400371eaf..3b262ba6b172 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -22,25 +22,6 @@ #define COMP_HDR_LEN 4 #define COMP_CKSUM_LEN 2 -#define AR_CH0_TOP (0x00016288) -#define AR_CH0_TOP_XPABIASLVL (0x300) -#define AR_CH0_TOP_XPABIASLVL_S (8) - -#define AR_CH0_THERM (0x00016290) -#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_COM2_ALL (0xffffff) -#define AR_SWITCH_TABLE_COM2_ALL_S (0) - -#define AR_SWITCH_TABLE_ALL (0xfff) -#define AR_SWITCH_TABLE_ALL_S (0) - #define LE16(x) __constant_cpu_to_le16(x) #define LE32(x) __constant_cpu_to_le32(x) @@ -158,7 +139,7 @@ static const struct ar9300_eeprom ar9300_default = { .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -360,7 +341,7 @@ static const struct ar9300_eeprom ar9300_default = { .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -735,7 +716,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -937,7 +918,7 @@ static const struct ar9300_eeprom ar9300_x113 = { .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -1313,7 +1294,7 @@ static const struct ar9300_eeprom ar9300_h112 = { .papdRateMaskHt20 = LE32(0x80c080), .papdRateMaskHt40 = LE32(0x80c080), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -1515,7 +1496,7 @@ static const struct ar9300_eeprom ar9300_h112 = { .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -1891,7 +1872,7 @@ static const struct ar9300_eeprom ar9300_x112 = { .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -2093,7 +2074,7 @@ static const struct ar9300_eeprom ar9300_x112 = { .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -2468,7 +2449,7 @@ static const struct ar9300_eeprom ar9300_h116 = { .papdRateMaskHt20 = LE32(0x0c80C080), .papdRateMaskHt40 = LE32(0x0080C080), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -2670,7 +2651,7 @@ static const struct ar9300_eeprom ar9300_h116 = { .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -3014,8 +2995,6 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, return get_unaligned_be16(eep->macAddr + 4); case EEP_REG_0: return le16_to_cpu(pBase->regDmn[0]); - case EEP_REG_1: - return le16_to_cpu(pBase->regDmn[1]); case EEP_OP_CAP: return pBase->deviceCap; case EEP_OP_MODE: @@ -3040,6 +3019,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, return (pBase->miscConfiguration >> 0x3) & 0x1; case EEP_ANT_DIV_CTL1: return eep->base_ext1.ant_div_control; + case EEP_ANTENNA_GAIN_5G: + return eep->modalHeader5G.antennaGain; + case EEP_ANTENNA_GAIN_2G: + return eep->modalHeader2G.antennaGain; default: return 0; } @@ -3318,7 +3301,7 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, word = kzalloc(2048, GFP_KERNEL); if (!word) - return -1; + return -ENOMEM; memcpy(mptr, &ar9300_default, mdata_size); @@ -3418,6 +3401,133 @@ static bool ath9k_hw_ar9300_fill_eeprom(struct ath_hw *ah) return true; } +#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) +static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size, + struct ar9300_modal_eep_header *modal_hdr) +{ + PR_EEP("Chain0 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[0])); + PR_EEP("Chain1 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[1])); + PR_EEP("Chain2 Ant. Control", le16_to_cpu(modal_hdr->antCtrlChain[2])); + PR_EEP("Ant. Common Control", le32_to_cpu(modal_hdr->antCtrlCommon)); + PR_EEP("Ant. Common Control2", le32_to_cpu(modal_hdr->antCtrlCommon2)); + PR_EEP("Ant. Gain", modal_hdr->antennaGain); + PR_EEP("Switch Settle", modal_hdr->switchSettling); + PR_EEP("Chain0 xatten1DB", modal_hdr->xatten1DB[0]); + PR_EEP("Chain1 xatten1DB", modal_hdr->xatten1DB[1]); + PR_EEP("Chain2 xatten1DB", modal_hdr->xatten1DB[2]); + PR_EEP("Chain0 xatten1Margin", modal_hdr->xatten1Margin[0]); + PR_EEP("Chain1 xatten1Margin", modal_hdr->xatten1Margin[1]); + PR_EEP("Chain2 xatten1Margin", modal_hdr->xatten1Margin[2]); + PR_EEP("Temp Slope", modal_hdr->tempSlope); + PR_EEP("Volt Slope", modal_hdr->voltSlope); + PR_EEP("spur Channels0", modal_hdr->spurChans[0]); + PR_EEP("spur Channels1", modal_hdr->spurChans[1]); + PR_EEP("spur Channels2", modal_hdr->spurChans[2]); + PR_EEP("spur Channels3", modal_hdr->spurChans[3]); + PR_EEP("spur Channels4", modal_hdr->spurChans[4]); + PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]); + PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]); + PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); + PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); + PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); + PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); + PR_EEP("txClip", modal_hdr->txClip); + PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); + PR_EEP("Chain0 ob", modal_hdr->ob[0]); + PR_EEP("Chain1 ob", modal_hdr->ob[1]); + PR_EEP("Chain2 ob", modal_hdr->ob[2]); + + PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]); + PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]); + PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]); + PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]); + PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]); + PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]); + PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]); + PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]); + PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]); + + return len; +} + +static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, + u8 *buf, u32 len, u32 size) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ar9300_base_eep_hdr *pBase; + + if (!dump_base_hdr) { + len += snprintf(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 += ar9003_dump_modal_eeprom(buf, len, size, + &eep->modalHeader5G); + goto out; + } + + pBase = &eep->baseEepHeader; + + PR_EEP("EEPROM Version", ah->eeprom.ar9300_eep.eepromVersion); + PR_EEP("RegDomain1", le16_to_cpu(pBase->regDmn[0])); + PR_EEP("RegDomain2", le16_to_cpu(pBase->regDmn[1])); + PR_EEP("TX Mask", (pBase->txrxMask >> 4)); + PR_EEP("RX Mask", (pBase->txrxMask & 0x0f)); + PR_EEP("Allow 5GHz", !!(pBase->opCapFlags.opFlags & + AR5416_OPFLAGS_11A)); + PR_EEP("Allow 2GHz", !!(pBase->opCapFlags.opFlags & + AR5416_OPFLAGS_11G)); + PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags.opFlags & + AR5416_OPFLAGS_N_2G_HT20)); + PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags.opFlags & + AR5416_OPFLAGS_N_2G_HT40)); + PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags.opFlags & + 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("RF Silent", pBase->rfSilent); + PR_EEP("BT option", pBase->blueToothOptions); + PR_EEP("Device Cap", pBase->deviceCap); + PR_EEP("Device Type", pBase->deviceType); + PR_EEP("Power Table Offset", pBase->pwrTableOffset); + PR_EEP("Tuning Caps1", pBase->params_for_tuning_caps[0]); + PR_EEP("Tuning Caps2", pBase->params_for_tuning_caps[1]); + PR_EEP("Enable Tx Temp Comp", !!(pBase->featureEnable & BIT(0))); + PR_EEP("Enable Tx Volt Comp", !!(pBase->featureEnable & BIT(1))); + PR_EEP("Enable fast clock", !!(pBase->featureEnable & BIT(2))); + PR_EEP("Enable doubling", !!(pBase->featureEnable & BIT(3))); + PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4))); + PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5))); + PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0))); + PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1); + PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio); + PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio); + PR_EEP("WLAN LED Gpio", pBase->wlanLedGpio); + PR_EEP("Rx Band Select Gpio", pBase->rxBandSelectGpio); + PR_EEP("Tx Gain", pBase->txrxgain >> 4); + 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); +out: + if (len > size) + len = size; + + return len; +} +#else +static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, + u8 *buf, u32 len, u32 size) +{ + return 0; +} +#endif + /* XXX: review hardware docs */ static int ath9k_hw_ar9300_get_eeprom_ver(struct ath_hw *ah) { @@ -3446,6 +3556,8 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) 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); + else if (AR_SREV_9462(ah)) + REG_RMW_FIELD(ah, AR_CH0_TOP, 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, @@ -3456,6 +3568,19 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) } } +static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is_2ghz) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + __le32 val; + + if (is_2ghz) + val = eep->modalHeader2G.switchcomspdt; + else + val = eep->modalHeader5G.switchcomspdt; + return le32_to_cpu(val); +} + + static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) { struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; @@ -3510,7 +3635,36 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz); - REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value); + if (AR_SREV_9462(ah)) { + if (AR_SREV_9462_10(ah)) { + value &= ~AR_SWITCH_TABLE_COM_SPDT; + value |= 0x00100000; + } + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, + AR_SWITCH_TABLE_COM_AR9462_ALL, value); + } else + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, + AR_SWITCH_TABLE_COM_ALL, value); + + + /* + * AR9462 defines new switch table for BT/WLAN, + * here's new field name in XXX.ref for both 2G and 5G. + * Register: [GLB_CONTROL] GLB_CONTROL (@0x20044) + * 15:12 R/W SWITCH_TABLE_COM_SPDT_WLAN_RX + * SWITCH_TABLE_COM_SPDT_WLAN_RX + * + * 11:8 R/W SWITCH_TABLE_COM_SPDT_WLAN_TX + * SWITCH_TABLE_COM_SPDT_WLAN_TX + * + * 7:4 R/W SWITCH_TABLE_COM_SPDT_WLAN_IDLE + * SWITCH_TABLE_COM_SPDT_WLAN_IDLE + */ + if (AR_SREV_9462_20_OR_LATER(ah)) { + value = ar9003_switch_com_spdt_get(ah, is2ghz); + REG_RMW_FIELD(ah, AR_PHY_GLB_CONTROL, + AR_SWITCH_TABLE_COM_SPDT_ALL, value); + } value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz); REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); @@ -3710,6 +3864,7 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) { int internal_regulator = ath9k_hw_ar9300_get_eeprom(ah, EEP_INTERNAL_REGULATOR); + u32 reg_val; if (internal_regulator) { if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) { @@ -3754,13 +3909,16 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set); if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set)) return; + } else if (AR_SREV_9462(ah)) { + reg_val = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG); + REG_WRITE(ah, AR_PHY_PMU1, reg_val); } else { /* Internal regulator is ON. Write swreg register. */ - int swreg = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG); + reg_val = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG); REG_WRITE(ah, AR_RTC_REG_CONTROL1, REG_READ(ah, AR_RTC_REG_CONTROL1) & (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM)); - REG_WRITE(ah, AR_RTC_REG_CONTROL0, swreg); + REG_WRITE(ah, AR_RTC_REG_CONTROL0, reg_val); /* Set REG_CONTROL1.SWREG_PROGRAM */ REG_WRITE(ah, AR_RTC_REG_CONTROL1, REG_READ(ah, @@ -3771,22 +3929,24 @@ static void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) 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, - AR_PHY_PMU2_PGM)) + 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, - AR_PHY_PMU1_PWD)) + 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, - AR_PHY_PMU2_PGM)) + AR_PHY_PMU2_PGM)) udelay(10); - } else - REG_WRITE(ah, AR_RTC_SLEEP_CLK, - (REG_READ(ah, - AR_RTC_SLEEP_CLK) | - AR_RTC_FORCE_SWREG_PRD)); + } else if (AR_SREV_9462(ah)) + REG_RMW_FIELD(ah, AR_PHY_PMU1, AR_PHY_PMU1_PWD, 0x1); + else { + reg_val = REG_READ(ah, AR_RTC_SLEEP_CLK) | + AR_RTC_FORCE_SWREG_PRD; + REG_WRITE(ah, AR_RTC_SLEEP_CLK, reg_val); + } } } @@ -4061,7 +4221,7 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray) /* Write the power for duplicated frames - HT40 */ /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */ - REG_WRITE(ah, 0xa3e0, + REG_WRITE(ah, AR_PHY_POWER_TX_RATE(8), POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) | POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) | @@ -4366,6 +4526,12 @@ static int ar9003_hw_power_control_override(struct ath_hw *ah, tempSlope = eep->modalHeader5G.tempSlope; REG_RMW_FIELD(ah, AR_PHY_TPC_19, AR_PHY_TPC_19_ALPHA_THERM, tempSlope); + + if (AR_SREV_9462_20(ah)) + REG_RMW_FIELD(ah, AR_PHY_TPC_19_B1, + AR_PHY_TPC_19_B1_ALPHA_THERM, tempSlope); + + REG_RMW_FIELD(ah, AR_PHY_TPC_18, AR_PHY_TPC_18_THERM_CAL_VALUE, temperature[0]); @@ -4600,20 +4766,14 @@ static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep, static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, u8 *pPwrArray, u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, + u8 antenna_reduction, u16 powerLimit) { - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep; u16 twiceMaxEdgePower = MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = { - 0, 3, 6, 9, MAX_RATE_POWER - }; int i; - int16_t twiceLargestAntenna; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 scaledPower = 0, minCtlPower; static const u16 ctlModesFor11a[] = { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; @@ -4631,28 +4791,7 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah, bool is2ghz = IS_CHAN_2GHZ(chan); ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - /* Compute TxPower reduction due to Antenna Gain */ - if (is2ghz) - twiceLargestAntenna = pEepData->modalHeader2G.antennaGain; - else - twiceLargestAntenna = pEepData->modalHeader5G.antennaGain; - - twiceLargestAntenna = (int16_t)min((twiceAntennaReduction) - - twiceLargestAntenna, 0); - - /* - * scaledPower is the minimum of the user input power level - * and the regulatory allowed power level - */ - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(regulatory->tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = powerLimit - antenna_reduction; /* * Reduce scaled Power by number of chains active to get @@ -4839,7 +4978,6 @@ static inline u8 mcsidx_to_tgtpwridx(unsigned int mcs_idx, u8 base_pwridx) static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, u8 powerLimit, bool test) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); @@ -4892,7 +5030,6 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, ar9003_hw_set_power_per_rate_table(ah, chan, targetPowerValT2, cfgCtl, twiceAntennaReduction, - twiceMaxRegulatoryPower, powerLimit); if (ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) { @@ -4922,25 +5059,7 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah, "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]); } - /* - * This is the TX power we send back to driver core, - * and it can use to pass to userspace to display our - * currently configured TX power setting. - * - * Since power is rate dependent, use one of the indices - * from the AR9300_Rates enum to select an entry from - * targetPowerValT2[] to report. Currently returns the - * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps - * as CCK power is less interesting (?). - */ - i = ALL_TARGET_LEGACY_6_24; /* legacy */ - if (IS_CHAN_HT40(chan)) - i = ALL_TARGET_HT40_0_8_16; /* ht40 */ - else if (IS_CHAN_HT20(chan)) - i = ALL_TARGET_HT20_0_8_16; /* ht20 */ - - ah->txpower_limit = targetPowerValT2[i]; - regulatory->max_power_level = targetPowerValT2[i]; + ah->txpower_limit = regulatory->max_power_level; /* Write target power array to registers */ ar9003_hw_tx_power_regwrite(ah, targetPowerValT2); @@ -5015,6 +5134,7 @@ const struct eeprom_ops eep_ar9300_ops = { .check_eeprom = ath9k_hw_ar9300_check_eeprom, .get_eeprom = ath9k_hw_ar9300_get_eeprom, .fill_eeprom = ath9k_hw_ar9300_fill_eeprom, + .dump_eeprom = ath9k_hw_ar9003_dump_eeprom, .get_eeprom_ver = ath9k_hw_ar9300_get_eeprom_ver, .get_eeprom_rev = ath9k_hw_ar9300_get_eeprom_rev, .set_board_values = ath9k_hw_ar9300_set_board_values, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index ab21a4915981..6335a867527e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -233,7 +233,8 @@ struct ar9300_modal_eep_header { u8 thresh62; __le32 papdRateMaskHt20; __le32 papdRateMaskHt40; - u8 futureModal[10]; + __le16 switchcomspdt; + u8 futureModal[8]; } __packed; struct ar9300_cal_data_per_freq_op_loop { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index ad2bb2bf4e8a..fb937ba93e0c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -21,6 +21,9 @@ #include "ar9340_initvals.h" #include "ar9330_1p1_initvals.h" #include "ar9330_1p2_initvals.h" +#include "ar9580_1p0_initvals.h" +#include "ar9462_1p0_initvals.h" +#include "ar9462_2p0_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -31,6 +34,14 @@ */ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) { +#define PCIE_PLL_ON_CREQ_DIS_L1_2P0 \ + ar9462_pciephy_pll_on_clkreq_disable_L1_2p0 + +#define AR9462_BB_CTX_COEFJ(x) \ + ar9462_##x##_baseband_core_txfir_coeff_japan_2484 + +#define AR9462_BBC_TXIFR_COEFFJ \ + ar9462_2p0_baseband_core_txfir_coeff_japan_2484 if (AR_SREV_9330_11(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -253,6 +264,182 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9485_1_1_pcie_phy_clkreq_disable_L1, ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), 2); + } else if (AR_SREV_9462_10(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_1p0_mac_core, + ARRAY_SIZE(ar9462_1p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9462_1p0_mac_postamble, + ARRAY_SIZE(ar9462_1p0_mac_postamble), + 5); + + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9462_1p0_baseband_core, + ARRAY_SIZE(ar9462_1p0_baseband_core), + 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9462_1p0_baseband_postamble, + ARRAY_SIZE(ar9462_1p0_baseband_postamble), 5); + + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9462_1p0_radio_core, + ARRAY_SIZE(ar9462_1p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9462_1p0_radio_postamble, + ARRAY_SIZE(ar9462_1p0_radio_postamble), 5); + + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9462_1p0_soc_preamble, + ARRAY_SIZE(ar9462_1p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9462_1p0_soc_postamble, + ARRAY_SIZE(ar9462_1p0_soc_postamble), 5); + + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_rx_gain_table_1p0, + ARRAY_SIZE(ar9462_common_rx_gain_table_1p0), 2); + + /* Awake -> Sleep Setting */ + INIT_INI_ARRAY(&ah->iniPcieSerdes, + ar9462_pcie_phy_clkreq_disable_L1_1p0, + ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0), + 2); + + /* Sleep -> Awake Setting */ + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + ar9462_pcie_phy_clkreq_disable_L1_1p0, + ARRAY_SIZE(ar9462_pcie_phy_clkreq_disable_L1_1p0), + 2); + + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9462_modes_fast_clock_1p0, + ARRAY_SIZE(ar9462_modes_fast_clock_1p0), 3); + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + AR9462_BB_CTX_COEFJ(1p0), + ARRAY_SIZE(AR9462_BB_CTX_COEFJ(1p0)), 2); + + } else if (AR_SREV_9462_20(ah)) { + + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core, + ARRAY_SIZE(ar9462_2p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9462_2p0_mac_postamble, + ARRAY_SIZE(ar9462_2p0_mac_postamble), 5); + + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9462_2p0_baseband_core, + ARRAY_SIZE(ar9462_2p0_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9462_2p0_baseband_postamble, + ARRAY_SIZE(ar9462_2p0_baseband_postamble), 5); + + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9462_2p0_radio_core, + ARRAY_SIZE(ar9462_2p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9462_2p0_radio_postamble, + ARRAY_SIZE(ar9462_2p0_radio_postamble), 5); + INIT_INI_ARRAY(&ah->ini_radio_post_sys2ant, + ar9462_2p0_radio_postamble_sys2ant, + ARRAY_SIZE(ar9462_2p0_radio_postamble_sys2ant), + 5); + + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9462_2p0_soc_preamble, + ARRAY_SIZE(ar9462_2p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9462_2p0_soc_postamble, + ARRAY_SIZE(ar9462_2p0_soc_postamble), 5); + + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_rx_gain_table_2p0, + ARRAY_SIZE(ar9462_common_rx_gain_table_2p0), 2); + + INIT_INI_ARRAY(&ah->ini_BTCOEX_MAX_TXPWR, + ar9462_2p0_BTCOEX_MAX_TXPWR_table, + ARRAY_SIZE(ar9462_2p0_BTCOEX_MAX_TXPWR_table), + 2); + + /* Awake -> Sleep Setting */ + INIT_INI_ARRAY(&ah->iniPcieSerdes, + PCIE_PLL_ON_CREQ_DIS_L1_2P0, + ARRAY_SIZE(PCIE_PLL_ON_CREQ_DIS_L1_2P0), + 2); + /* Sleep -> Awake Setting */ + INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, + PCIE_PLL_ON_CREQ_DIS_L1_2P0, + ARRAY_SIZE(PCIE_PLL_ON_CREQ_DIS_L1_2P0), + 2); + + /* Fast clock modal settings */ + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9462_modes_fast_clock_2p0, + ARRAY_SIZE(ar9462_modes_fast_clock_2p0), 3); + + INIT_INI_ARRAY(&ah->iniCckfirJapan2484, + AR9462_BB_CTX_COEFJ(2p0), + ARRAY_SIZE(AR9462_BB_CTX_COEFJ(2p0)), 2); + + INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ, + ARRAY_SIZE(AR9462_BBC_TXIFR_COEFFJ), 2); + + } else if (AR_SREV_9580(ah)) { + /* mac */ + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + ar9580_1p0_mac_core, + ARRAY_SIZE(ar9580_1p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar9580_1p0_mac_postamble, + ARRAY_SIZE(ar9580_1p0_mac_postamble), 5); + + /* bb */ + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar9580_1p0_baseband_core, + ARRAY_SIZE(ar9580_1p0_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar9580_1p0_baseband_postamble, + ARRAY_SIZE(ar9580_1p0_baseband_postamble), 5); + + /* radio */ + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar9580_1p0_radio_core, + ARRAY_SIZE(ar9580_1p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar9580_1p0_radio_postamble, + ARRAY_SIZE(ar9580_1p0_radio_postamble), 5); + + /* soc */ + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar9580_1p0_soc_preamble, + ARRAY_SIZE(ar9580_1p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar9580_1p0_soc_postamble, + ARRAY_SIZE(ar9580_1p0_soc_postamble), 5); + + /* rx/tx gain */ + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9580_1p0_rx_gain_table, + ARRAY_SIZE(ar9580_1p0_rx_gain_table), 2); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9580_1p0_low_ob_db_tx_gain_table, + ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table), + 5); + + INIT_INI_ARRAY(&ah->iniModesAdditional, + ar9580_1p0_modes_fast_clock, + ARRAY_SIZE(ar9580_1p0_modes_fast_clock), + 3); } else { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -323,178 +510,293 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) } } +static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) +{ + if (AR_SREV_9330_12(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9331_modes_lowest_ob_db_tx_gain_1p2, + ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p2), + 5); + else if (AR_SREV_9330_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9331_modes_lowest_ob_db_tx_gain_1p1, + ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p1), + 5); + else if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9485_modes_lowest_ob_db_tx_gain_1_1, + ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), + 5); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9580_1p0_lowest_ob_db_tx_gain_table, + ARRAY_SIZE(ar9580_1p0_lowest_ob_db_tx_gain_table), + 5); + else if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9462_modes_low_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9462_modes_low_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9462_20(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9462_modes_low_ob_db_tx_gain_table_2p0, + ARRAY_SIZE(ar9462_modes_low_ob_db_tx_gain_table_2p0), + 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_lowest_ob_db_tx_gain_table_2p2, + ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2), + 5); +} + +static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) +{ + if (AR_SREV_9330_12(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9331_modes_high_ob_db_tx_gain_1p2, + ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p2), + 5); + else if (AR_SREV_9330_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9331_modes_high_ob_db_tx_gain_1p1, + ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p1), + 5); + else if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9485Modes_high_ob_db_tx_gain_1_1, + ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), + 5); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9580_1p0_high_ob_db_tx_gain_table, + ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table), + 5); + else if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9462_modes_high_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9462_modes_high_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9462_20(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9462_modes_high_ob_db_tx_gain_table_2p0, + ARRAY_SIZE(ar9462_modes_high_ob_db_tx_gain_table_2p0), + 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_ob_db_tx_gain_table_2p2, + ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2), + 5); +} + +static void ar9003_tx_gain_table_mode2(struct ath_hw *ah) +{ + if (AR_SREV_9330_12(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9331_modes_low_ob_db_tx_gain_1p2, + ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p2), + 5); + else if (AR_SREV_9330_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9331_modes_low_ob_db_tx_gain_1p1, + ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p1), + 5); + else if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9485Modes_low_ob_db_tx_gain_1_1, + ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), + 5); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9580_1p0_low_ob_db_tx_gain_table, + ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table), + 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_low_ob_db_tx_gain_table_2p2, + ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2), + 5); +} + +static void ar9003_tx_gain_table_mode3(struct ath_hw *ah) +{ + if (AR_SREV_9330_12(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9331_modes_high_power_tx_gain_1p2, + ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p2), + 5); + else if (AR_SREV_9330_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9331_modes_high_power_tx_gain_1p1, + ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p1), + 5); + else if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_lowest_ob_db_tx_gain_table_1p0, + ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), + 5); + else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9485Modes_high_power_tx_gain_1_1, + ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), + 5); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9580_1p0_high_power_tx_gain_table, + ARRAY_SIZE(ar9580_1p0_high_power_tx_gain_table), + 5); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_power_tx_gain_table_2p2, + ARRAY_SIZE(ar9300Modes_high_power_tx_gain_table_2p2), + 5); +} + static void ar9003_tx_gain_table_apply(struct ath_hw *ah) { switch (ar9003_hw_get_tx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9330_12(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_lowest_ob_db_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p2), - 5); - else if (AR_SREV_9330_11(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_lowest_ob_db_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p1), - 5); - else if (AR_SREV_9340(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_lowest_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), - 5); - else if (AR_SREV_9485_11(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485_modes_lowest_ob_db_tx_gain_1_1, - ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), - 5); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_lowest_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2), - 5); + ar9003_tx_gain_table_mode0(ah); break; case 1: - if (AR_SREV_9330_12(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_high_ob_db_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p2), - 5); - else if (AR_SREV_9330_11(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_high_ob_db_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p1), - 5); - else if (AR_SREV_9340(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_lowest_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), - 5); - else if (AR_SREV_9485_11(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_ob_db_tx_gain_1_1, - ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), - 5); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2), - 5); + ar9003_tx_gain_table_mode1(ah); break; case 2: - if (AR_SREV_9330_12(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_low_ob_db_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p2), - 5); - else if (AR_SREV_9330_11(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_low_ob_db_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p1), - 5); - else if (AR_SREV_9340(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_lowest_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), - 5); - else if (AR_SREV_9485_11(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_low_ob_db_tx_gain_1_1, - ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), - 5); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_low_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2), - 5); + ar9003_tx_gain_table_mode2(ah); break; case 3: - if (AR_SREV_9330_12(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_high_power_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p2), - 5); - else if (AR_SREV_9330_11(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_high_power_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p1), - 5); - else if (AR_SREV_9340(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_lowest_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), - 5); - else if (AR_SREV_9485_11(ah)) - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_power_tx_gain_1_1, - ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), - 5); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_power_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_high_power_tx_gain_table_2p2), - 5); + ar9003_tx_gain_table_mode3(ah); break; } } +static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) +{ + if (AR_SREV_9330_12(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9331_common_rx_gain_1p2, + ARRAY_SIZE(ar9331_common_rx_gain_1p2), + 2); + else if (AR_SREV_9330_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9331_common_rx_gain_1p1, + ARRAY_SIZE(ar9331_common_rx_gain_1p1), + 2); + else if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_rx_gain_table_1p0), + 2); + else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9485Common_wo_xlna_rx_gain_1_1, + ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), + 2); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9580_1p0_rx_gain_table, + ARRAY_SIZE(ar9580_1p0_rx_gain_table), + 2); + else if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_rx_gain_table_1p0, + ARRAY_SIZE(ar9462_common_rx_gain_table_1p0), + 2); + else if (AR_SREV_9462_20(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_rx_gain_table_2p0, + ARRAY_SIZE(ar9462_common_rx_gain_table_2p0), + 2); + else + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9300Common_rx_gain_table_2p2, + ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), + 2); +} + +static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) +{ + if (AR_SREV_9330_12(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9331_common_wo_xlna_rx_gain_1p2, + ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p2), + 2); + else if (AR_SREV_9330_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9331_common_wo_xlna_rx_gain_1p1, + ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p1), + 2); + else if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9340Common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), + 2); + else if (AR_SREV_9485_11(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9485Common_wo_xlna_rx_gain_1_1, + ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), + 2); + else if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_wo_xlna_rx_gain_table_1p0, + ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_1p0), + 2); + else if (AR_SREV_9462_20(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_wo_xlna_rx_gain_table_2p0, + ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_2p0), + 2); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9580_1p0_wo_xlna_rx_gain_table, + ARRAY_SIZE(ar9580_1p0_wo_xlna_rx_gain_table), + 2); + else + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9300Common_wo_xlna_rx_gain_table_2p2, + ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2), + 2); +} + +static void ar9003_rx_gain_table_mode2(struct ath_hw *ah) +{ + if (AR_SREV_9462_10(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_mixed_rx_gain_table_1p0, + ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_1p0), 2); + else if (AR_SREV_9462_20(ah)) + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar9462_common_mixed_rx_gain_table_2p0, + ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2); +} + static void ar9003_rx_gain_table_apply(struct ath_hw *ah) { switch (ar9003_hw_get_rx_gain_idx(ah)) { case 0: default: - if (AR_SREV_9330_12(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_rx_gain_1p2, - ARRAY_SIZE(ar9331_common_rx_gain_1p2), - 2); - else if (AR_SREV_9330_11(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_rx_gain_1p1, - ARRAY_SIZE(ar9331_common_rx_gain_1p1), - 2); - else if (AR_SREV_9340(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9340Common_rx_gain_table_1p0, - ARRAY_SIZE(ar9340Common_rx_gain_table_1p0), - 2); - else if (AR_SREV_9485_11(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_wo_xlna_rx_gain_1_1, - ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), - 2); - else - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_rx_gain_table_2p2, - ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), - 2); + ar9003_rx_gain_table_mode0(ah); break; case 1: - if (AR_SREV_9330_12(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_wo_xlna_rx_gain_1p2, - ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p2), - 2); - else if (AR_SREV_9330_11(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_wo_xlna_rx_gain_1p1, - ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p1), - 2); - else if (AR_SREV_9340(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9340Common_wo_xlna_rx_gain_table_1p0, - ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), - 2); - else if (AR_SREV_9485_11(ah)) - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_wo_xlna_rx_gain_1_1, - ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), - 2); - else - INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_wo_xlna_rx_gain_table_2p2, - ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2), - 2); + ar9003_rx_gain_table_mode1(ah); + break; + case 2: + ar9003_rx_gain_table_mode2(ah); break; } } @@ -516,14 +818,10 @@ static void ar9003_hw_init_mode_gain_regs(struct ath_hw *ah) * register as the other analog registers. Hence the 9 writes. */ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, - int restore, - int power_off) + bool power_off) { - if (ah->is_pciexpress != true || ah->aspm_enabled != true) - return; - /* Nothing to do on restore for 11N */ - if (!restore) { + 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); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 8ff0b88a29b9..b363cc06cfd9 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -21,6 +21,132 @@ static void ar9003_hw_rx_enable(struct ath_hw *hw) REG_WRITE(hw, AR_CR, 0); } +static void +ar9003_set_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_info *i) +{ + struct ar9003_txc *ads = ds; + int checksum = 0; + u32 val, ctl12, ctl17; + + val = (ATHEROS_VENDOR_ID << AR_DescId_S) | + (1 << AR_TxRxDesc_S) | + (1 << AR_CtrlStat_S) | + (i->qcu << AR_TxQcuNum_S) | 0x17; + + checksum += val; + ACCESS_ONCE(ads->info) = val; + + checksum += i->link; + ACCESS_ONCE(ads->link) = i->link; + + checksum += i->buf_addr[0]; + ACCESS_ONCE(ads->data0) = i->buf_addr[0]; + checksum += i->buf_addr[1]; + ACCESS_ONCE(ads->data1) = i->buf_addr[1]; + checksum += i->buf_addr[2]; + ACCESS_ONCE(ads->data2) = i->buf_addr[2]; + checksum += i->buf_addr[3]; + ACCESS_ONCE(ads->data3) = i->buf_addr[3]; + + checksum += (val = (i->buf_len[0] << AR_BufLen_S) & AR_BufLen); + ACCESS_ONCE(ads->ctl3) = val; + checksum += (val = (i->buf_len[1] << AR_BufLen_S) & AR_BufLen); + ACCESS_ONCE(ads->ctl5) = val; + checksum += (val = (i->buf_len[2] << AR_BufLen_S) & AR_BufLen); + ACCESS_ONCE(ads->ctl7) = val; + checksum += (val = (i->buf_len[3] << AR_BufLen_S) & AR_BufLen); + ACCESS_ONCE(ads->ctl9) = val; + + checksum = (u16) (((checksum & 0xffff) + (checksum >> 16)) & 0xffff); + ACCESS_ONCE(ads->ctl10) = checksum; + + if (i->is_first || i->is_last) { + ACCESS_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); + + ACCESS_ONCE(ads->ctl14) = set11nRate(i->rates, 0) + | set11nRate(i->rates, 1) + | set11nRate(i->rates, 2) + | set11nRate(i->rates, 3); + } else { + ACCESS_ONCE(ads->ctl13) = 0; + ACCESS_ONCE(ads->ctl14) = 0; + } + + ads->ctl20 = 0; + ads->ctl21 = 0; + ads->ctl22 = 0; + + 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; + return; + } + + ACCESS_ONCE(ads->ctl11) = (i->pkt_len & AR_FrameLen) + | (i->flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(i->txpower, AR_XmitPower) + | (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)); + + ctl12 = (i->keyix != ATH9K_TXKEYIX_INVALID ? + SM(i->keyix, AR_DestIdx) : 0) + | SM(i->type, AR_FrameType) + | (i->flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) + | (i->flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) + | (i->flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); + + ctl17 |= (i->flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0); + switch (i->aggr) { + case AGGR_BUF_FIRST: + ctl17 |= SM(i->aggr_len, AR_AggrLen); + /* fall through */ + case AGGR_BUF_MIDDLE: + ctl12 |= AR_IsAggr | AR_MoreAggr; + ctl17 |= SM(i->ndelim, AR_PadDelim); + break; + case AGGR_BUF_LAST: + ctl12 |= AR_IsAggr; + break; + case AGGR_BUF_NONE: + break; + } + + 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; + + ACCESS_ONCE(ads->ctl15) = set11nPktDurRTSCTS(i->rates, 0) + | set11nPktDurRTSCTS(i->rates, 1); + + ACCESS_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); + + ACCESS_ONCE(ads->ctl19) = AR_Not_Sounding; +} + static u16 ar9003_calc_ptr_chksum(struct ar9003_txc *ads) { int checksum; @@ -185,47 +311,6 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) return true; } -static void ar9003_hw_fill_txdesc(struct ath_hw *ah, void *ds, u32 seglen, - bool is_firstseg, bool is_lastseg, - const void *ds0, dma_addr_t buf_addr, - unsigned int qcu) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - unsigned int descid = 0; - - ads->info = (ATHEROS_VENDOR_ID << AR_DescId_S) | - (1 << AR_TxRxDesc_S) | - (1 << AR_CtrlStat_S) | - (qcu << AR_TxQcuNum_S) | 0x17; - - ads->data0 = buf_addr; - ads->data1 = 0; - ads->data2 = 0; - ads->data3 = 0; - - ads->ctl3 = (seglen << AR_BufLen_S); - ads->ctl3 &= AR_BufLen; - - /* Fill in pointer checksum and descriptor id */ - ads->ctl10 = ar9003_calc_ptr_chksum(ads); - ads->ctl10 |= (descid << AR_TxDescId_S); - - if (is_firstseg) { - ads->ctl12 |= (is_lastseg ? 0 : AR_TxMore); - } else if (is_lastseg) { - ads->ctl11 = 0; - ads->ctl12 = 0; - ads->ctl13 = AR9003TXC_CONST(ds0)->ctl13; - ads->ctl14 = AR9003TXC_CONST(ds0)->ctl14; - } else { - /* XXX Intermediate descriptor in a multi-descriptor frame.*/ - ads->ctl11 = 0; - ads->ctl12 = AR_TxMore; - ads->ctl13 = 0; - ads->ctl14 = 0; - } -} - static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, struct ath_tx_status *ts) { @@ -253,8 +338,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, return -EIO; } - if (status & AR_TxOpExceeded) - ts->ts_status |= ATH9K_TXERR_XTXOP; ts->ts_rateindex = MS(status, AR_FinalTxIdx); ts->ts_seqnum = MS(status, AR_SeqNum); ts->tid = MS(status, AR_TxTid); @@ -264,6 +347,8 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_status = 0; ts->ts_flags = 0; + if (status & AR_TxOpExceeded) + ts->ts_status |= ATH9K_TXERR_XTXOP; status = ACCESS_ONCE(ads->status2); ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); @@ -310,185 +395,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, return 0; } -static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds, - u32 pktlen, enum ath9k_pkt_type type, u32 txpower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - if (txpower > ah->txpower_limit) - txpower = ah->txpower_limit; - - if (txpower > 63) - txpower = 63; - - ads->ctl11 = (pktlen & AR_FrameLen) - | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(txpower, AR_XmitPower) - | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0) - | (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0); - - ads->ctl12 = - (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) - | SM(type, AR_FrameType) - | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) - | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) - | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); - - ads->ctl17 = SM(keyType, AR_EncrType) | - (flags & ATH9K_TXDESC_LDPC ? AR_LDPC : 0); - ads->ctl18 = 0; - ads->ctl19 = AR_Not_Sounding; - - ads->ctl20 = 0; - ads->ctl21 = 0; - ads->ctl22 = 0; -} - -static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - if (val) - ads->ctl11 |= AR_ClrDestMask; - else - ads->ctl11 &= ~AR_ClrDestMask; -} - -static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, - void *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - struct ar9003_txc *last_ads = (struct ar9003_txc *) lastds; - u_int32_t ctl11; - - if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { - ctl11 = ads->ctl11; - - if (flags & ATH9K_TXDESC_RTSENA) { - ctl11 &= ~AR_CTSEnable; - ctl11 |= AR_RTSEnable; - } else { - ctl11 &= ~AR_RTSEnable; - ctl11 |= AR_CTSEnable; - } - - ads->ctl11 = ctl11; - } else { - ads->ctl11 = (ads->ctl11 & ~(AR_RTSEnable | AR_CTSEnable)); - } - - ads->ctl13 = set11nTries(series, 0) - | set11nTries(series, 1) - | set11nTries(series, 2) - | set11nTries(series, 3) - | (durUpdateEn ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); - - ads->ctl14 = set11nRate(series, 0) - | set11nRate(series, 1) - | set11nRate(series, 2) - | set11nRate(series, 3); - - ads->ctl15 = set11nPktDurRTSCTS(series, 0) - | set11nPktDurRTSCTS(series, 1); - - ads->ctl16 = set11nPktDurRTSCTS(series, 2) - | set11nPktDurRTSCTS(series, 3); - - ads->ctl18 = set11nRateFlags(series, 0) - | set11nRateFlags(series, 1) - | set11nRateFlags(series, 2) - | set11nRateFlags(series, 3) - | SM(rtsctsRate, AR_RTSCTSRate); - ads->ctl19 = AR_Not_Sounding; - - last_ads->ctl13 = ads->ctl13; - last_ads->ctl14 = ads->ctl14; -} - -static void ar9003_hw_set11n_aggr_first(struct ath_hw *ah, void *ds, - u32 aggrLen) -{ -#define FIRST_DESC_NDELIMS 60 - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - ads->ctl12 |= (AR_IsAggr | AR_MoreAggr); - - if (ah->ent_mode & AR_ENT_OTP_MPSD) { - u32 ctl17, ndelim; - /* - * Add delimiter when using RTS/CTS with aggregation - * and non enterprise AR9003 card - */ - ctl17 = ads->ctl17; - ndelim = MS(ctl17, AR_PadDelim); - - if (ndelim < FIRST_DESC_NDELIMS) { - aggrLen += (FIRST_DESC_NDELIMS - ndelim) * 4; - ndelim = FIRST_DESC_NDELIMS; - } - - ctl17 &= ~AR_AggrLen; - ctl17 |= SM(aggrLen, AR_AggrLen); - - ctl17 &= ~AR_PadDelim; - ctl17 |= SM(ndelim, AR_PadDelim); - - ads->ctl17 = ctl17; - } else { - ads->ctl17 &= ~AR_AggrLen; - ads->ctl17 |= SM(aggrLen, AR_AggrLen); - } -} - -static void ar9003_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds, - u32 numDelims) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - unsigned int ctl17; - - ads->ctl12 |= (AR_IsAggr | AR_MoreAggr); - - /* - * We use a stack variable to manipulate ctl6 to reduce uncached - * read modify, modfiy, write. - */ - ctl17 = ads->ctl17; - ctl17 &= ~AR_PadDelim; - ctl17 |= SM(numDelims, AR_PadDelim); - ads->ctl17 = ctl17; -} - -static void ar9003_hw_set11n_aggr_last(struct ath_hw *ah, void *ds) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - ads->ctl12 |= AR_IsAggr; - ads->ctl12 &= ~AR_MoreAggr; - ads->ctl17 &= ~AR_PadDelim; -} - -static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds) -{ - struct ar9003_txc *ads = (struct ar9003_txc *) ds; - - ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr); -} - -void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains) -{ - struct ar9003_txc *ads = ds; - - ads->ctl12 |= SM(chains, AR_PAPRDChainMask); -} -EXPORT_SYMBOL(ar9003_hw_set_paprd_txdesc); - void ar9003_hw_attach_mac_ops(struct ath_hw *hw) { struct ath_hw_ops *ops = ath9k_hw_ops(hw); @@ -496,15 +402,8 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw) ops->rx_enable = ar9003_hw_rx_enable; ops->set_desc_link = ar9003_hw_set_desc_link; ops->get_isr = ar9003_hw_get_isr; - ops->fill_txdesc = ar9003_hw_fill_txdesc; + ops->set_txdesc = ar9003_set_txdesc; ops->proc_txdesc = ar9003_hw_proc_txdesc; - ops->set11n_txdesc = ar9003_hw_set11n_txdesc; - ops->set11n_ratescenario = ar9003_hw_set11n_ratescenario; - ops->set11n_aggr_first = ar9003_hw_set11n_aggr_first; - ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle; - ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last; - ops->clr11n_aggr = ar9003_hw_clr11n_aggr; - ops->set_clrdmask = ar9003_hw_set_clrdmask; } void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size) @@ -531,17 +430,18 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, /* TODO: byte swap on big endian for ar9300_10 */ - if ((rxsp->status11 & AR_RxDone) == 0) - return -EINPROGRESS; + if (!rxs) { + if ((rxsp->status11 & AR_RxDone) == 0) + return -EINPROGRESS; - if (MS(rxsp->ds_info, AR_DescId) != 0x168c) - return -EINVAL; + if (MS(rxsp->ds_info, AR_DescId) != 0x168c) + return -EINVAL; - if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) - return -EINPROGRESS; + if ((rxsp->ds_info & (AR_TxRxDesc | AR_CtrlStat)) != 0) + return -EINPROGRESS; - if (!rxs) return 0; + } rxs->rs_status = 0; rxs->rs_flags = 0; @@ -625,8 +525,8 @@ int ath9k_hw_process_rxdesc_edma(struct ath_hw *ah, struct ath_rx_status *rxs, rxs->rs_status |= ATH9K_RXERR_DECRYPT; else if (rxsp->status11 & AR_MichaelErr) rxs->rs_status |= ATH9K_RXERR_MIC; - else if (rxsp->status11 & AR_KeyMiss) - rxs->rs_status |= ATH9K_RXERR_DECRYPT; + if (rxsp->status11 & AR_KeyMiss) + rxs->rs_status |= ATH9K_RXERR_KEYMISS; } return 0; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index f80d1d633980..0c462c904cbe 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -19,7 +19,6 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val) { - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath9k_channel *chan = ah->curchan; struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; @@ -54,13 +53,7 @@ void ar9003_paprd_enable(struct ath_hw *ah, bool val) if (val) { ah->paprd_table_write_done = true; - - ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(regulatory, chan), - chan->chan->max_antenna_gain * 2, - chan->chan->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit), false); + ath9k_hw_apply_txpower(ah, chan); } REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL0_B0, @@ -113,7 +106,7 @@ static int ar9003_get_training_power_5g(struct ath_hw *ah) if (delta > scale) return -1; - switch (get_streams(common->tx_chainmask)) { + switch (get_streams(ah->txchainmask)) { case 1: delta = 6; break; @@ -126,7 +119,7 @@ static int ar9003_get_training_power_5g(struct ath_hw *ah) default: delta = 0; ath_dbg(common, ATH_DBG_CALIBRATE, - "Invalid tx-chainmask: %u\n", common->tx_chainmask); + "Invalid tx-chainmask: %u\n", ah->txchainmask); } power += delta; @@ -147,7 +140,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) AR_PHY_PAPRD_CTRL1_B2 }; int training_power; - int i; + int i, val; if (IS_CHAN_2GHZ(ah->curchan)) training_power = ar9003_get_training_power_2g(ah); @@ -207,8 +200,9 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) AR_PHY_PAPRD_TRAINER_CNTL1_CF_PAPRD_AGC2_SETTLING, 28); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL1, AR_PHY_PAPRD_TRAINER_CNTL1_CF_CF_PAPRD_TRAIN_ENABLE, 1); + val = AR_SREV_9462(ah) ? 0x91 : 147; REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL2, - AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, 147); + AR_PHY_PAPRD_TRAINER_CNTL2_CF_PAPRD_INIT_RX_BB_GAIN, val); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_FINE_CORR_LEN, 4); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, @@ -217,7 +211,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); - if (AR_SREV_9485(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9462(ah)) REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3); @@ -225,9 +219,10 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -6); + val = AR_SREV_9462(ah) ? -10 : -15; REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_ADC_DESIRED_SIZE, - -15); + val); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_BBTXMIX_DISABLE, 1); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL4, @@ -757,6 +752,7 @@ void ar9003_paprd_populate_single_table(struct ath_hw *ah, training_power); if (ah->caps.tx_chainmask & BIT(2)) + /* val AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL correct? */ REG_RMW_FIELD(ah, AR_PHY_PAPRD_CTRL1_B2, AR_PHY_PAPRD_CTRL1_PAPRD_POWER_AT_AM2AM_CAL, training_power); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index fcafec0605f4..fe96997921d3 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -370,7 +370,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, else spur_subchannel_sd = 0; - spur_freq_sd = ((freq_offset + 10) << 9) / 11; + spur_freq_sd = (freq_offset << 9) / 11; } else { if (REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, @@ -379,7 +379,7 @@ static void ar9003_hw_spur_ofdm_work(struct ath_hw *ah, else spur_subchannel_sd = 1; - spur_freq_sd = ((freq_offset - 10) << 9) / 11; + spur_freq_sd = (freq_offset << 9) / 11; } @@ -482,7 +482,7 @@ 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_WALSH | + phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_SHORT_GI_40 | enableDacFifo; /* Configure baseband for dynamic 20/40 operation */ @@ -540,7 +540,7 @@ static void ar9003_hw_init_bb(struct ath_hw *ah, udelay(synthDelay + BASE_ACTIVATE_DELAY); } -void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) +static void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) { switch (rx) { case 0x5: @@ -559,6 +559,9 @@ void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx) if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7)) REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); + else if (AR_SREV_9462(ah)) + /* xxx only when MCI support is enabled */ + REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); else REG_WRITE(ah, AR_SELFGEN_MASK, tx); @@ -592,6 +595,9 @@ static void ar9003_hw_override_ini(struct ath_hw *ah) 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); + + REG_SET_BIT(ah, AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV); } static void ar9003_hw_prog_ini(struct ath_hw *ah, @@ -625,9 +631,7 @@ static void ar9003_hw_prog_ini(struct ath_hw *ah, static int ar9003_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); unsigned int regWrites = 0, i; - struct ieee80211_channel *channel = chan->chan; u32 modesIndex; switch (chan->chanmode) { @@ -658,6 +662,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, ar9003_hw_prog_ini(ah, &ah->iniMac[i], modesIndex); ar9003_hw_prog_ini(ah, &ah->iniBB[i], modesIndex); ar9003_hw_prog_ini(ah, &ah->iniRadio[i], modesIndex); + if (i == ATH_INI_POST && AR_SREV_9462_20(ah)) + ar9003_hw_prog_ini(ah, + &ah->ini_radio_post_sys2ant, + modesIndex); } REG_WRITE_ARRAY(&ah->iniModesRxGain, 1, regWrites); @@ -677,17 +685,27 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); + if (AR_SREV_9462(ah)) + ar9003_hw_prog_ini(ah, &ah->ini_BTCOEX_MAX_TXPWR, 1); + + ah->modes_index = modesIndex; ar9003_hw_override_ini(ah); ar9003_hw_set_channel_regs(ah, chan); ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + ath9k_hw_apply_txpower(ah, chan); + + if (AR_SREV_9462(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; - /* Set TX power */ - ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit), false); + 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; } @@ -785,16 +803,6 @@ static void ar9003_hw_rfbus_done(struct ath_hw *ah) REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); } -static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value) -{ - u32 v = REG_READ(ah, AR_PHY_CCK_DETECT); - if (value) - v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - else - v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - REG_WRITE(ah, AR_PHY_CCK_DETECT, v); -} - static bool ar9003_hw_ani_control(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param) { @@ -1253,6 +1261,73 @@ static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } +static int ar9003_hw_fast_chan_change(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 *ini_reloaded) +{ + unsigned int regWrites = 0; + 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 (modesIndex == ah->modes_index) { + *ini_reloaded = false; + goto set_rfmode; + } + + ar9003_hw_prog_ini(ah, &ah->iniSOC[ATH_INI_POST], modesIndex); + ar9003_hw_prog_ini(ah, &ah->iniMac[ATH_INI_POST], modesIndex); + ar9003_hw_prog_ini(ah, &ah->iniBB[ATH_INI_POST], modesIndex); + ar9003_hw_prog_ini(ah, &ah->iniRadio[ATH_INI_POST], modesIndex); + if (AR_SREV_9462_20(ah)) + ar9003_hw_prog_ini(ah, + &ah->ini_radio_post_sys2ant, + modesIndex); + + REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + + /* + * For 5GHz channels requiring Fast Clock, apply + * different modal values. + */ + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) + REG_WRITE_ARRAY(&ah->iniModesAdditional, modesIndex, regWrites); + + if (AR_SREV_9330(ah)) + REG_WRITE_ARRAY(&ah->iniModesAdditional, 1, regWrites); + + if (AR_SREV_9340(ah) && !ah->is_clk_25mhz) + REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites); + + ah->modes_index = modesIndex; + *ini_reloaded = true; + +set_rfmode: + ar9003_hw_set_rfmode(ah, chan); + return 0; +} + void ar9003_hw_attach_phy_ops(struct ath_hw *ah) { struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); @@ -1277,11 +1352,11 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->set_delta_slope = ar9003_hw_set_delta_slope; priv_ops->rfbus_req = ar9003_hw_rfbus_req; priv_ops->rfbus_done = ar9003_hw_rfbus_done; - priv_ops->set_diversity = ar9003_hw_set_diversity; priv_ops->ani_control = ar9003_hw_ani_control; priv_ops->do_getnf = ar9003_hw_do_getnf; priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs; priv_ops->set_radar_params = ar9003_hw_set_radar_params; + priv_ops->fast_chan_change = ar9003_hw_fast_chan_change; ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get; ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 5c590429f120..2f4023e66081 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -325,10 +325,10 @@ #define AR_PHY_RX_OCGAIN (AR_AGC_BASE + 0x200) -#define AR_PHY_CCA_NOM_VAL_9300_2GHZ -110 -#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_NOM_VAL_9300_2GHZ (AR_SREV_9462(ah) ? -127 : -110) +#define AR_PHY_CCA_NOM_VAL_9300_5GHZ (AR_SREV_9462(ah) ? -127 : -115) +#define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ (AR_SREV_9462(ah) ? -127 : -125) +#define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ (AR_SREV_9462(ah) ? -127 : -125) #define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -95 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -100 @@ -572,6 +572,8 @@ #define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300) +#define AR_PHY_TX_IQCAL_CONTROL_0 (AR_SM_BASE + AR_SREV_9485(ah) ? \ + 0x3c4 : 0x444) #define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \ 0x3c8 : 0x448) #define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \ @@ -581,6 +583,7 @@ #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \ (AR_SREV_9485(ah) ? \ 0x3d0 : 0x450) + ((_i) << 2)) +#define AR_PHY_RTT_CTRL (AR_SM_BASE + 0x380) #define AR_PHY_WATCHDOG_STATUS (AR_SM_BASE + 0x5c0) #define AR_PHY_WATCHDOG_CTL_1 (AR_SM_BASE + 0x5c4) @@ -600,6 +603,17 @@ #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 + (AR_SREV_9462_10(ah) ? \ + 0x4c0 : 0x4c4)) +#define AR_PHY_AIC_STAT_1_B0 (AR_SM_BASE + (AR_SREV_9462_10(ah) ? \ + 0x4c4 : 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_SYNTH4 0x1608c #define AR_PHY_SYNTH4_LONG_SHIFT_SELECT 0x00000002 @@ -609,7 +623,35 @@ #define AR_PHY_65NM_CH0_BIAS2 0x160c4 #define AR_PHY_65NM_CH0_BIAS4 0x160cc #define AR_PHY_65NM_CH0_RXTX4 0x1610c -#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : 0x1628c) + +#define AR_CH0_TOP (AR_SREV_9300(ah) ? 0x16288 : \ + ((AR_SREV_9462(ah) ? 0x1628c : 0x16280))) +#define AR_CH0_TOP_XPABIASLVL (0x300) +#define AR_CH0_TOP_XPABIASLVL_S (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) +#define AR_SWITCH_TABLE_COM_AR9462_ALL_S (0) +#define AR_SWITCH_TABLE_COM_SPDT (0x00f00000) +#define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0) +#define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4) + +#define AR_SWITCH_TABLE_COM2_ALL (0xffffff) +#define AR_SWITCH_TABLE_COM2_ALL_S (0) + +#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_9485(ah) ? 0x1628c : 0x16294)) #define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 #define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 @@ -625,21 +667,23 @@ #define AR_PHY_65NM_CH2_RXTX1 0x16900 #define AR_PHY_65NM_CH2_RXTX2 0x16904 -#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : 0x16284) +#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ + (AR_SREV_9485(ah) ? 0x16284 : 0x16290)) #define AR_CH0_TOP2_XPABIASLVL 0xf000 #define AR_CH0_TOP2_XPABIASLVL_S 12 -#define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : 0x16290) +#define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : \ + (AR_SREV_9485(ah) ? 0x16290 : 0x16298)) #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 0x16c40 +#define AR_PHY_PMU1 (AR_SREV_9462(ah) ? 0x16340 : 0x16c40) #define AR_PHY_PMU1_PWD 0x1 #define AR_PHY_PMU1_PWD_S 0 -#define AR_PHY_PMU2 0x16c44 +#define AR_PHY_PMU2 (AR_SREV_9462(ah) ? 0x16344 : 0x16c44) #define AR_PHY_PMU2_PGM 0x00200000 #define AR_PHY_PMU2_PGM_S 21 @@ -779,6 +823,22 @@ #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 #define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004 +#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION 0x00000001 +#define AR_PHY_RTT_CTRL_ENA_RADIO_RETENTION_S 0 +#define AR_PHY_RTT_CTRL_RESTORE_MASK 0x0000007E +#define AR_PHY_RTT_CTRL_RESTORE_MASK_S 1 +#define AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE 0x00000080 +#define AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE_S 7 +#define AR_PHY_RTT_SW_RTT_TABLE_ACCESS 0x00000001 +#define AR_PHY_RTT_SW_RTT_TABLE_ACCESS_S 0 +#define AR_PHY_RTT_SW_RTT_TABLE_WRITE 0x00000002 +#define AR_PHY_RTT_SW_RTT_TABLE_WRITE_S 1 +#define AR_PHY_RTT_SW_RTT_TABLE_ADDR 0x0000001C +#define AR_PHY_RTT_SW_RTT_TABLE_ADDR_S 2 +#define AR_PHY_RTT_SW_RTT_TABLE_DATA 0xFFFFFFF0 +#define AR_PHY_RTT_SW_RTT_TABLE_DATA_S 4 +#define AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL 0x80000000 +#define AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL_S 31 #define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000 #define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18 #define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001 @@ -839,19 +899,42 @@ */ #define AR_SM1_BASE 0xb200 -#define AR_PHY_SWITCH_CHAIN_1 (AR_SM1_BASE + 0x84) -#define AR_PHY_FCAL_2_1 (AR_SM1_BASE + 0xd0) -#define AR_PHY_DFT_TONE_CTL_1 (AR_SM1_BASE + 0xd4) -#define AR_PHY_CL_TAB_1 (AR_SM1_BASE + 0x100) -#define AR_PHY_CHAN_INFO_GAIN_1 (AR_SM1_BASE + 0x180) -#define AR_PHY_TPC_4_B1 (AR_SM1_BASE + 0x204) -#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 + 0x240) +#define AR_PHY_SWITCH_CHAIN_1 (AR_SM1_BASE + 0x84) +#define AR_PHY_FCAL_2_1 (AR_SM1_BASE + 0xd0) +#define AR_PHY_DFT_TONE_CTL_1 (AR_SM1_BASE + 0xd4) +#define AR_PHY_CL_TAB_1 (AR_SM1_BASE + 0x100) +#define AR_PHY_CHAN_INFO_GAIN_1 (AR_SM1_BASE + 0x180) +#define AR_PHY_TPC_4_B1 (AR_SM1_BASE + 0x204) +#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_AR9300(ah) ? \ + 0x240 : 0x280)) +#define AR_PHY_TPC_19_B1 (AR_SM1_BASE + 0x240) +#define AR_PHY_TPC_19_B1_ALPHA_THERM 0xff +#define AR_PHY_TPC_19_B1_ALPHA_THERM_S 0 #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) ? \ + AR_SM1_BASE : AR_SM_BASE) /* * Channel 2 Register Map */ @@ -914,6 +997,13 @@ #define AR_PHY_RSSI_3 (AR_AGC3_BASE + 0x180) +/* GLB Registers */ +#define AR_GLB_BASE 0x20000 +#define AR_PHY_GLB_CONTROL (AR_GLB_BASE + 0x44) +#define AR_GLB_SCRATCH(_ah) (AR_GLB_BASE + \ + (AR_SREV_9462_20(_ah) ? 0x4c : 0x50)) +#define AR_GLB_STATUS (AR_GLB_BASE + 0x48) + /* * Misc helper defines */ @@ -1124,6 +1214,4 @@ #define AR_PHY_CL_TAB_CL_GAIN_MOD 0x1f #define AR_PHY_CL_TAB_CL_GAIN_MOD_S 0 -void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); - #endif /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c new file mode 100644 index 000000000000..48803ee9c0d6 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "hw.h" +#include "ar9003_phy.h" + +#define RTT_RESTORE_TIMEOUT 1000 +#define RTT_ACCESS_TIMEOUT 100 +#define RTT_BAD_VALUE 0x0bad0bad + +/* + * RTT (Radio Retention Table) hardware implementation information + * + * There is an internal table (i.e. the rtt) for each chain (or bank). + * Each table contains 6 entries and each entry is corresponding to + * a specific calibration parameter as depicted below. + * 0~2 - DC offset DAC calibration: loop, low, high (offsetI/Q_...) + * 3 - Filter cal (filterfc) + * 4 - RX gain settings + * 5 - Peak detector offset calibration (agc_caldac) + */ + +void ar9003_hw_rtt_enable(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_PHY_RTT_CTRL, 1); +} + +void ar9003_hw_rtt_disable(struct ath_hw *ah) +{ + REG_WRITE(ah, AR_PHY_RTT_CTRL, 0); +} + +void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask) +{ + REG_RMW_FIELD(ah, AR_PHY_RTT_CTRL, + AR_PHY_RTT_CTRL_RESTORE_MASK, rtt_mask); +} + +bool ar9003_hw_rtt_force_restore(struct ath_hw *ah) +{ + if (!ath9k_hw_wait(ah, AR_PHY_RTT_CTRL, + AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE, + 0, RTT_RESTORE_TIMEOUT)) + return false; + + REG_RMW_FIELD(ah, AR_PHY_RTT_CTRL, + AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE, 1); + + if (!ath9k_hw_wait(ah, AR_PHY_RTT_CTRL, + AR_PHY_RTT_CTRL_FORCE_RADIO_RESTORE, + 0, RTT_RESTORE_TIMEOUT)) + return false; + + return true; +} + +static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain, + u32 index, u32 data28) +{ + u32 val; + + val = SM(data28, AR_PHY_RTT_SW_RTT_TABLE_DATA); + REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain), val); + + val = SM(0, AR_PHY_RTT_SW_RTT_TABLE_ACCESS) | + SM(1, AR_PHY_RTT_SW_RTT_TABLE_WRITE) | + SM(index, AR_PHY_RTT_SW_RTT_TABLE_ADDR); + REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val); + udelay(1); + + val |= SM(1, AR_PHY_RTT_SW_RTT_TABLE_ACCESS); + REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val); + udelay(1); + + if (!ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), + AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0, + RTT_ACCESS_TIMEOUT)) + return; + + val &= ~SM(1, AR_PHY_RTT_SW_RTT_TABLE_WRITE); + REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val); + udelay(1); + + ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), + AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0, + RTT_ACCESS_TIMEOUT); +} + +void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table) +{ + int i; + + for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) + ar9003_hw_rtt_load_hist_entry(ah, chain, i, table[i]); +} + +static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index) +{ + u32 val; + + val = SM(0, AR_PHY_RTT_SW_RTT_TABLE_ACCESS) | + SM(0, AR_PHY_RTT_SW_RTT_TABLE_WRITE) | + SM(index, AR_PHY_RTT_SW_RTT_TABLE_ADDR); + + REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val); + udelay(1); + + val |= SM(1, AR_PHY_RTT_SW_RTT_TABLE_ACCESS); + REG_WRITE(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), val); + udelay(1); + + if (!ath9k_hw_wait(ah, AR_PHY_RTT_TABLE_SW_INTF_B(chain), + AR_PHY_RTT_SW_RTT_TABLE_ACCESS, 0, + RTT_ACCESS_TIMEOUT)) + return RTT_BAD_VALUE; + + val = REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain)); + + return val; +} + +void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table) +{ + int i; + + for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) + table[i] = ar9003_hw_rtt_fill_hist_entry(ah, chain, i); +} + +void ar9003_hw_rtt_clear_hist(struct ath_hw *ah) +{ + int i, j; + + for (i = 0; i < AR9300_MAX_CHAINS; i++) { + if (!(ah->rxchainmask & (1 << i))) + continue; + for (j = 0; j < MAX_RTT_TABLE_ENTRY; j++) + ar9003_hw_rtt_load_hist_entry(ah, i, j, 0); + } +} diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h new file mode 100644 index 000000000000..030758d087d6 --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef AR9003_RTT_H +#define AR9003_RTT_H + +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); +bool ar9003_hw_rtt_force_restore(struct ath_hw *ah); +void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table); +void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table); +void ar9003_hw_rtt_clear_hist(struct ath_hw *ah); + +#endif diff --git a/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h new file mode 100644 index 000000000000..5c55ae389adb --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9462_1p0_initvals.h @@ -0,0 +1,1833 @@ +/* + * Copyright (c) 2010 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_9462_1P0_H +#define INITVALS_9462_1P0_H + +/* AR9462 1.0 */ + +static const u32 ar9462_1p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00060085}, + {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}, + {0x00001810, 0x0f000003}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00080000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008050, 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, 0x13881c20}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00005}, + {0x000080d8, 0x00400002}, + {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}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x00008170, 0x18486e00}, + {0x00008174, 0x33332210}, + {0x00008178, 0x00000000}, + {0x0000817c, 0x00020000}, + {0x000081c4, 0x33332210}, + {0x000081c8, 0x00000000}, + {0x000081cc, 0x00000000}, + {0x000081d4, 0x00000000}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f400}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e800}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x99c00010}, + {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, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x0000001f}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0xffff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48105b}, + {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}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x000301ff}, +}; + +static const u32 ar9462_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { + /* Addr allmodes */ + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x6f7f0301}, + {0x0000a3a0, 0xca9228ee}, +}; + +static const u32 ar9462_1p0_sys3ant[][2] = { + /* Addr allmodes */ + {0x00063280, 0x00040807}, + {0x00063284, 0x104ccccc}, +}; + +static const u32 ar9462_pcie_phy_clkreq_enable_L1_1p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x10053e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000580c}, +}; + +static const u32 ar9462_1p0_mac_core_emulation[][2] = { + /* Addr allmodes */ + {0x00000030, 0x00060085}, + {0x00000044, 0x00000008}, + {0x0000805c, 0xffffc7ff}, + {0x00008344, 0xaa4a105b}, +}; + +static const u32 ar9462_common_rx_gain_table_ar9280_2p0_1p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x02000101}, + {0x0000a004, 0x02000102}, + {0x0000a008, 0x02000103}, + {0x0000a00c, 0x02000104}, + {0x0000a010, 0x02000200}, + {0x0000a014, 0x02000201}, + {0x0000a018, 0x02000202}, + {0x0000a01c, 0x02000203}, + {0x0000a020, 0x02000204}, + {0x0000a024, 0x02000205}, + {0x0000a028, 0x02000208}, + {0x0000a02c, 0x02000302}, + {0x0000a030, 0x02000303}, + {0x0000a034, 0x02000304}, + {0x0000a038, 0x02000400}, + {0x0000a03c, 0x02010300}, + {0x0000a040, 0x02010301}, + {0x0000a044, 0x02010302}, + {0x0000a048, 0x02000500}, + {0x0000a04c, 0x02010400}, + {0x0000a050, 0x02020300}, + {0x0000a054, 0x02020301}, + {0x0000a058, 0x02020302}, + {0x0000a05c, 0x02020303}, + {0x0000a060, 0x02020400}, + {0x0000a064, 0x02030300}, + {0x0000a068, 0x02030301}, + {0x0000a06c, 0x02030302}, + {0x0000a070, 0x02030303}, + {0x0000a074, 0x02030400}, + {0x0000a078, 0x02040300}, + {0x0000a07c, 0x02040301}, + {0x0000a080, 0x02040302}, + {0x0000a084, 0x02040303}, + {0x0000a088, 0x02030500}, + {0x0000a08c, 0x02040400}, + {0x0000a090, 0x02050203}, + {0x0000a094, 0x02050204}, + {0x0000a098, 0x02050205}, + {0x0000a09c, 0x02040500}, + {0x0000a0a0, 0x02050301}, + {0x0000a0a4, 0x02050302}, + {0x0000a0a8, 0x02050303}, + {0x0000a0ac, 0x02050400}, + {0x0000a0b0, 0x02050401}, + {0x0000a0b4, 0x02050402}, + {0x0000a0b8, 0x02050403}, + {0x0000a0bc, 0x02050500}, + {0x0000a0c0, 0x02050501}, + {0x0000a0c4, 0x02050502}, + {0x0000a0c8, 0x02050503}, + {0x0000a0cc, 0x02050504}, + {0x0000a0d0, 0x02050600}, + {0x0000a0d4, 0x02050601}, + {0x0000a0d8, 0x02050602}, + {0x0000a0dc, 0x02050603}, + {0x0000a0e0, 0x02050604}, + {0x0000a0e4, 0x02050700}, + {0x0000a0e8, 0x02050701}, + {0x0000a0ec, 0x02050702}, + {0x0000a0f0, 0x02050703}, + {0x0000a0f4, 0x02050704}, + {0x0000a0f8, 0x02050705}, + {0x0000a0fc, 0x02050708}, + {0x0000a100, 0x02050709}, + {0x0000a104, 0x0205070a}, + {0x0000a108, 0x0205070b}, + {0x0000a10c, 0x0205070c}, + {0x0000a110, 0x0205070d}, + {0x0000a114, 0x02050710}, + {0x0000a118, 0x02050711}, + {0x0000a11c, 0x02050712}, + {0x0000a120, 0x02050713}, + {0x0000a124, 0x02050714}, + {0x0000a128, 0x02050715}, + {0x0000a12c, 0x02050730}, + {0x0000a130, 0x02050731}, + {0x0000a134, 0x02050732}, + {0x0000a138, 0x02050733}, + {0x0000a13c, 0x02050734}, + {0x0000a140, 0x02050735}, + {0x0000a144, 0x02050750}, + {0x0000a148, 0x02050751}, + {0x0000a14c, 0x02050752}, + {0x0000a150, 0x02050753}, + {0x0000a154, 0x02050754}, + {0x0000a158, 0x02050755}, + {0x0000a15c, 0x02050770}, + {0x0000a160, 0x02050771}, + {0x0000a164, 0x02050772}, + {0x0000a168, 0x02050773}, + {0x0000a16c, 0x02050774}, + {0x0000a170, 0x02050775}, + {0x0000a174, 0x00000776}, + {0x0000a178, 0x00000776}, + {0x0000a17c, 0x00000776}, + {0x0000a180, 0x00000776}, + {0x0000a184, 0x00000776}, + {0x0000a188, 0x00000776}, + {0x0000a18c, 0x00000776}, + {0x0000a190, 0x00000776}, + {0x0000a194, 0x00000776}, + {0x0000a198, 0x00000776}, + {0x0000a19c, 0x00000776}, + {0x0000a1a0, 0x00000776}, + {0x0000a1a4, 0x00000776}, + {0x0000a1a8, 0x00000776}, + {0x0000a1ac, 0x00000776}, + {0x0000a1b0, 0x00000776}, + {0x0000a1b4, 0x00000776}, + {0x0000a1b8, 0x00000776}, + {0x0000a1bc, 0x00000776}, + {0x0000a1c0, 0x00000776}, + {0x0000a1c4, 0x00000776}, + {0x0000a1c8, 0x00000776}, + {0x0000a1cc, 0x00000776}, + {0x0000a1d0, 0x00000776}, + {0x0000a1d4, 0x00000776}, + {0x0000a1d8, 0x00000776}, + {0x0000a1dc, 0x00000776}, + {0x0000a1e0, 0x00000776}, + {0x0000a1e4, 0x00000776}, + {0x0000a1e8, 0x00000776}, + {0x0000a1ec, 0x00000776}, + {0x0000a1f0, 0x00000776}, + {0x0000a1f4, 0x00000776}, + {0x0000a1f8, 0x00000776}, + {0x0000a1fc, 0x00000776}, + {0x0000b000, 0x02000101}, + {0x0000b004, 0x02000102}, + {0x0000b008, 0x02000103}, + {0x0000b00c, 0x02000104}, + {0x0000b010, 0x02000200}, + {0x0000b014, 0x02000201}, + {0x0000b018, 0x02000202}, + {0x0000b01c, 0x02000203}, + {0x0000b020, 0x02000204}, + {0x0000b024, 0x02000205}, + {0x0000b028, 0x02000208}, + {0x0000b02c, 0x02000302}, + {0x0000b030, 0x02000303}, + {0x0000b034, 0x02000304}, + {0x0000b038, 0x02000400}, + {0x0000b03c, 0x02010300}, + {0x0000b040, 0x02010301}, + {0x0000b044, 0x02010302}, + {0x0000b048, 0x02000500}, + {0x0000b04c, 0x02010400}, + {0x0000b050, 0x02020300}, + {0x0000b054, 0x02020301}, + {0x0000b058, 0x02020302}, + {0x0000b05c, 0x02020303}, + {0x0000b060, 0x02020400}, + {0x0000b064, 0x02030300}, + {0x0000b068, 0x02030301}, + {0x0000b06c, 0x02030302}, + {0x0000b070, 0x02030303}, + {0x0000b074, 0x02030400}, + {0x0000b078, 0x02040300}, + {0x0000b07c, 0x02040301}, + {0x0000b080, 0x02040302}, + {0x0000b084, 0x02040303}, + {0x0000b088, 0x02030500}, + {0x0000b08c, 0x02040400}, + {0x0000b090, 0x02050203}, + {0x0000b094, 0x02050204}, + {0x0000b098, 0x02050205}, + {0x0000b09c, 0x02040500}, + {0x0000b0a0, 0x02050301}, + {0x0000b0a4, 0x02050302}, + {0x0000b0a8, 0x02050303}, + {0x0000b0ac, 0x02050400}, + {0x0000b0b0, 0x02050401}, + {0x0000b0b4, 0x02050402}, + {0x0000b0b8, 0x02050403}, + {0x0000b0bc, 0x02050500}, + {0x0000b0c0, 0x02050501}, + {0x0000b0c4, 0x02050502}, + {0x0000b0c8, 0x02050503}, + {0x0000b0cc, 0x02050504}, + {0x0000b0d0, 0x02050600}, + {0x0000b0d4, 0x02050601}, + {0x0000b0d8, 0x02050602}, + {0x0000b0dc, 0x02050603}, + {0x0000b0e0, 0x02050604}, + {0x0000b0e4, 0x02050700}, + {0x0000b0e8, 0x02050701}, + {0x0000b0ec, 0x02050702}, + {0x0000b0f0, 0x02050703}, + {0x0000b0f4, 0x02050704}, + {0x0000b0f8, 0x02050705}, + {0x0000b0fc, 0x02050708}, + {0x0000b100, 0x02050709}, + {0x0000b104, 0x0205070a}, + {0x0000b108, 0x0205070b}, + {0x0000b10c, 0x0205070c}, + {0x0000b110, 0x0205070d}, + {0x0000b114, 0x02050710}, + {0x0000b118, 0x02050711}, + {0x0000b11c, 0x02050712}, + {0x0000b120, 0x02050713}, + {0x0000b124, 0x02050714}, + {0x0000b128, 0x02050715}, + {0x0000b12c, 0x02050730}, + {0x0000b130, 0x02050731}, + {0x0000b134, 0x02050732}, + {0x0000b138, 0x02050733}, + {0x0000b13c, 0x02050734}, + {0x0000b140, 0x02050735}, + {0x0000b144, 0x02050750}, + {0x0000b148, 0x02050751}, + {0x0000b14c, 0x02050752}, + {0x0000b150, 0x02050753}, + {0x0000b154, 0x02050754}, + {0x0000b158, 0x02050755}, + {0x0000b15c, 0x02050770}, + {0x0000b160, 0x02050771}, + {0x0000b164, 0x02050772}, + {0x0000b168, 0x02050773}, + {0x0000b16c, 0x02050774}, + {0x0000b170, 0x02050775}, + {0x0000b174, 0x00000776}, + {0x0000b178, 0x00000776}, + {0x0000b17c, 0x00000776}, + {0x0000b180, 0x00000776}, + {0x0000b184, 0x00000776}, + {0x0000b188, 0x00000776}, + {0x0000b18c, 0x00000776}, + {0x0000b190, 0x00000776}, + {0x0000b194, 0x00000776}, + {0x0000b198, 0x00000776}, + {0x0000b19c, 0x00000776}, + {0x0000b1a0, 0x00000776}, + {0x0000b1a4, 0x00000776}, + {0x0000b1a8, 0x00000776}, + {0x0000b1ac, 0x00000776}, + {0x0000b1b0, 0x00000776}, + {0x0000b1b4, 0x00000776}, + {0x0000b1b8, 0x00000776}, + {0x0000b1bc, 0x00000776}, + {0x0000b1c0, 0x00000776}, + {0x0000b1c4, 0x00000776}, + {0x0000b1c8, 0x00000776}, + {0x0000b1cc, 0x00000776}, + {0x0000b1d0, 0x00000776}, + {0x0000b1d4, 0x00000776}, + {0x0000b1d8, 0x00000776}, + {0x0000b1dc, 0x00000776}, + {0x0000b1e0, 0x00000776}, + {0x0000b1e4, 0x00000776}, + {0x0000b1e8, 0x00000776}, + {0x0000b1ec, 0x00000776}, + {0x0000b1f0, 0x00000776}, + {0x0000b1f4, 0x00000776}, + {0x0000b1f8, 0x00000776}, + {0x0000b1fc, 0x00000776}, +}; + +static const u32 ar9200_ar9280_2p0_radio_core_1p0[][2] = { + /* Addr allmodes */ + {0x00007800, 0x00040000}, + {0x00007804, 0xdb005012}, + {0x00007808, 0x04924914}, + {0x0000780c, 0x21084210}, + {0x00007810, 0x6d801300}, + {0x00007814, 0x0019beff}, + {0x00007818, 0x07e41000}, + {0x0000781c, 0x00392000}, + {0x00007820, 0x92592480}, + {0x00007824, 0x00040000}, + {0x00007828, 0xdb005012}, + {0x0000782c, 0x04924914}, + {0x00007830, 0x21084210}, + {0x00007834, 0x6d801300}, + {0x00007838, 0x0019beff}, + {0x0000783c, 0x07e40000}, + {0x00007840, 0x00392000}, + {0x00007844, 0x92592480}, + {0x00007848, 0x00100000}, + {0x0000784c, 0x773f0567}, + {0x00007850, 0x54214514}, + {0x00007854, 0x12035828}, + {0x00007858, 0x92592692}, + {0x0000785c, 0x00000000}, + {0x00007860, 0x56400000}, + {0x00007864, 0x0a8e370e}, + {0x00007868, 0xc0102850}, + {0x0000786c, 0x812d4000}, + {0x00007870, 0x807ec400}, + {0x00007874, 0x001b6db0}, + {0x00007878, 0x00376b63}, + {0x0000787c, 0x06db6db6}, + {0x00007880, 0x006d8000}, + {0x00007884, 0xffeffffe}, + {0x00007888, 0xffeffffe}, + {0x0000788c, 0x00010000}, + {0x00007890, 0x02060aeb}, + {0x00007894, 0x5a108000}, +}; + +static const u32 ar9462_1p0_baseband_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221}, + {0x00009e44, 0x005c0000, 0x005c0000, 0x005c0000, 0x005c0000}, + {0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111}, + {0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20}, + {0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c}, + {0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a}, + {0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c}, + {0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc}, + {0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4}, + {0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc}, + {0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede}, + {0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e}, + {0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e}, + {0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; + +static const u32 ar9462_pcie_phy_pll_on_clkreq_disable_L1_1p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x10012e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000580c}, +}; + +static const u32 ar9462_common_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, 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_modes_high_ob_db_tx_gain_table_1p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {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, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {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}, + {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, + {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, +}; + +static const u32 ar9462_common_wo_xlna_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, 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_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 ar9462_1p0_mac_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8}, + {0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017}, +}; + +static const u32 ar9462_1p0_tx_gain_table_baseband_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002}, + {0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004}, + {0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c}, + {0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b}, + {0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a}, + {0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a}, + {0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a}, + {0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a}, + {0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a}, + {0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a}, + {0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a}, + {0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a}, +}; + +static const u32 ar9462_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524}, + {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24646c08, 0x24646c08}, + {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70}, + {0x0001610c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, + {0x0001650c, 0x48000000, 0x40000000, 0x40000000, 0x40000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, +}; + +static const u32 ar9462_1p0_soc_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00001133, 0x00001133, 0x00001133, 0x00001133}, +}; + +static const u32 ar9462_1p0_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, 0x32840bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098e4, 0x01ffffff}, + {0x000098e8, 0x01ffffff}, + {0x000098ec, 0x01ffffff}, + {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}, + {0x00009e54, 0x64c355c7}, + {0x00009e58, 0xfd897735}, + {0x00009e5c, 0xe9198724}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {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}, + {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, 0x0c9bd380}, + {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, 0x00100000}, + {0x0000a440, 0x00000000}, + {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, 0x00000838}, + {0x0000a6b0, 0x0000000a}, + {0x0000a6b4, 0x28f12c01}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000001}, + {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}, + {0x0000b6b0, 0x0000000a}, + {0x0000b6b4, 0x00c00001}, +}; + +static const u32 ar9462_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, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x0131b7c0, 0x0131b7c4, 0x0131b7c4, 0x0131b7c0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, + {0x0000a234, 0x00000fff, 0x10000fff, 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, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150}, + {0x0000a288, 0x00000110, 0x00000110, 0x00100110, 0x00100110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, +}; + +static const u32 ar9462_modes_fast_clock_1p0[][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_modes_low_ob_db_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, 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}, + {0x00016444, 0x012482d4, 0x012482d4, 0x012482d4, 0x012482d4}, + {0x00016448, 0x64992000, 0x64992000, 0x64992000, 0x64992000}, +}; + +static const u32 ar9462_1p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233}, +}; + +static const u32 ar9462_common_mixed_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, 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_pcie_phy_clkreq_disable_L1_1p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x10013e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000580c}, +}; + +static const u32 ar9462_1p0_baseband_core_emulation[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafa68e30}, + {0x00009884, 0x00002842}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009e50, 0x00000000}, + {0x00009fcc, 0x00000014}, + {0x0000a344, 0x00000010}, + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x71733d01}, + {0x0000a3a0, 0xd0ad5c12}, + {0x0000a3c0, 0x22222220}, + {0x0000a3c4, 0x22222222}, + {0x0000a404, 0x00418a11}, + {0x0000a418, 0x050001ce}, + {0x0000a438, 0x00001800}, + {0x0000a458, 0x01444452}, + {0x0000a644, 0x3fad9d74}, + {0x0000a690, 0x00000038}, +}; + +static const u32 ar9462_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016010, 0x6d820001}, + {0x00016040, 0x7f80fff8}, + {0x0001604c, 0x2699e04f}, + {0x00016050, 0x6db6db6c}, + {0x00016054, 0x6db60000}, + {0x00016058, 0x6c200000}, + {0x00016080, 0x00040000}, + {0x00016084, 0x9a68048c}, + {0x00016088, 0x54214514}, + {0x0001608c, 0x12030409}, + {0x00016090, 0x24926490}, + {0x00016098, 0xd2888888}, + {0x000160a0, 0x0a108ffe}, + {0x000160a4, 0x812fc490}, + {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, 0x3d841400}, + {0x00016288, 0x00000000}, + {0x0001628c, 0xe3000000}, + {0x00016290, 0xa1005080}, + {0x00016294, 0x00000020}, + {0x00016298, 0x50a02900}, + {0x00016340, 0x121e4276}, + {0x00016344, 0x00300000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016410, 0x6c800001}, + {0x00016440, 0x7f80fff8}, + {0x0001644c, 0x4699e04f}, + {0x00016450, 0x6db6db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x3fffbe04}, + {0x00016504, 0xfff80000}, + {0x00016508, 0x00200400}, + {0x00016510, 0x00000000}, + {0x00016544, 0x02084080}, + {0x00016548, 0x000080c0}, +}; + +static const u32 ar9462_1p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x00007020, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, +}; + +static const u32 ar9462_1p0_sys2ant[][2] = { + /* Addr allmodes */ + {0x00063120, 0x00801980}, +}; + +#endif /* INITVALS_9462_1P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h new file mode 100644 index 000000000000..9c51b395b4ff --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -0,0 +1,1928 @@ +/* + * Copyright (c) 2010 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_9462_2P0_H +#define INITVALS_9462_2P0_H + +/* AR9462 2.0 */ + +static const u32 ar9462_modes_fast_clock_2p0[][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_pciephy_clkreq_enable_L1_2p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x18253ede}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0003580c}, +}; + +static const u32 ar9462_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, 0x3039605e, 0x33795d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcfd5c782, 0xcfd5c782}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x013187c0, 0x013187c4, 0x013187c4, 0x013187c0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, + {0x0000a234, 0x00000fff, 0x10000fff, 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, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {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}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x00100000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000550, 0x00000550}, +}; + +static const u32 ar9462_2p0_mac_core_emulation[][2] = { + /* Addr allmodes */ + {0x00000030, 0x000e0085}, + {0x00000044, 0x00000008}, + {0x0000805c, 0xffffc7ff}, + {0x00008344, 0xaa4a105b}, +}; + +static const u32 ar9462_common_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, 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_pciephy_clkreq_disable_L1_2p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x18213ede}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0003580c}, +}; + +static const u32 ar9462_pciephy_pll_on_clkreq_disable_L1_2p0[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x18212ede}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0003580c}, +}; + +static const u32 ar9462_2p0_sys3ant[][2] = { + /* Addr allmodes */ + {0x00063280, 0x00040807}, + {0x00063284, 0x104ccccc}, +}; + +static const u32 ar9462_common_rx_gain_table_ar9280_2p0[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x02000101}, + {0x0000a004, 0x02000102}, + {0x0000a008, 0x02000103}, + {0x0000a00c, 0x02000104}, + {0x0000a010, 0x02000200}, + {0x0000a014, 0x02000201}, + {0x0000a018, 0x02000202}, + {0x0000a01c, 0x02000203}, + {0x0000a020, 0x02000204}, + {0x0000a024, 0x02000205}, + {0x0000a028, 0x02000208}, + {0x0000a02c, 0x02000302}, + {0x0000a030, 0x02000303}, + {0x0000a034, 0x02000304}, + {0x0000a038, 0x02000400}, + {0x0000a03c, 0x02010300}, + {0x0000a040, 0x02010301}, + {0x0000a044, 0x02010302}, + {0x0000a048, 0x02000500}, + {0x0000a04c, 0x02010400}, + {0x0000a050, 0x02020300}, + {0x0000a054, 0x02020301}, + {0x0000a058, 0x02020302}, + {0x0000a05c, 0x02020303}, + {0x0000a060, 0x02020400}, + {0x0000a064, 0x02030300}, + {0x0000a068, 0x02030301}, + {0x0000a06c, 0x02030302}, + {0x0000a070, 0x02030303}, + {0x0000a074, 0x02030400}, + {0x0000a078, 0x02040300}, + {0x0000a07c, 0x02040301}, + {0x0000a080, 0x02040302}, + {0x0000a084, 0x02040303}, + {0x0000a088, 0x02030500}, + {0x0000a08c, 0x02040400}, + {0x0000a090, 0x02050203}, + {0x0000a094, 0x02050204}, + {0x0000a098, 0x02050205}, + {0x0000a09c, 0x02040500}, + {0x0000a0a0, 0x02050301}, + {0x0000a0a4, 0x02050302}, + {0x0000a0a8, 0x02050303}, + {0x0000a0ac, 0x02050400}, + {0x0000a0b0, 0x02050401}, + {0x0000a0b4, 0x02050402}, + {0x0000a0b8, 0x02050403}, + {0x0000a0bc, 0x02050500}, + {0x0000a0c0, 0x02050501}, + {0x0000a0c4, 0x02050502}, + {0x0000a0c8, 0x02050503}, + {0x0000a0cc, 0x02050504}, + {0x0000a0d0, 0x02050600}, + {0x0000a0d4, 0x02050601}, + {0x0000a0d8, 0x02050602}, + {0x0000a0dc, 0x02050603}, + {0x0000a0e0, 0x02050604}, + {0x0000a0e4, 0x02050700}, + {0x0000a0e8, 0x02050701}, + {0x0000a0ec, 0x02050702}, + {0x0000a0f0, 0x02050703}, + {0x0000a0f4, 0x02050704}, + {0x0000a0f8, 0x02050705}, + {0x0000a0fc, 0x02050708}, + {0x0000a100, 0x02050709}, + {0x0000a104, 0x0205070a}, + {0x0000a108, 0x0205070b}, + {0x0000a10c, 0x0205070c}, + {0x0000a110, 0x0205070d}, + {0x0000a114, 0x02050710}, + {0x0000a118, 0x02050711}, + {0x0000a11c, 0x02050712}, + {0x0000a120, 0x02050713}, + {0x0000a124, 0x02050714}, + {0x0000a128, 0x02050715}, + {0x0000a12c, 0x02050730}, + {0x0000a130, 0x02050731}, + {0x0000a134, 0x02050732}, + {0x0000a138, 0x02050733}, + {0x0000a13c, 0x02050734}, + {0x0000a140, 0x02050735}, + {0x0000a144, 0x02050750}, + {0x0000a148, 0x02050751}, + {0x0000a14c, 0x02050752}, + {0x0000a150, 0x02050753}, + {0x0000a154, 0x02050754}, + {0x0000a158, 0x02050755}, + {0x0000a15c, 0x02050770}, + {0x0000a160, 0x02050771}, + {0x0000a164, 0x02050772}, + {0x0000a168, 0x02050773}, + {0x0000a16c, 0x02050774}, + {0x0000a170, 0x02050775}, + {0x0000a174, 0x00000776}, + {0x0000a178, 0x00000776}, + {0x0000a17c, 0x00000776}, + {0x0000a180, 0x00000776}, + {0x0000a184, 0x00000776}, + {0x0000a188, 0x00000776}, + {0x0000a18c, 0x00000776}, + {0x0000a190, 0x00000776}, + {0x0000a194, 0x00000776}, + {0x0000a198, 0x00000776}, + {0x0000a19c, 0x00000776}, + {0x0000a1a0, 0x00000776}, + {0x0000a1a4, 0x00000776}, + {0x0000a1a8, 0x00000776}, + {0x0000a1ac, 0x00000776}, + {0x0000a1b0, 0x00000776}, + {0x0000a1b4, 0x00000776}, + {0x0000a1b8, 0x00000776}, + {0x0000a1bc, 0x00000776}, + {0x0000a1c0, 0x00000776}, + {0x0000a1c4, 0x00000776}, + {0x0000a1c8, 0x00000776}, + {0x0000a1cc, 0x00000776}, + {0x0000a1d0, 0x00000776}, + {0x0000a1d4, 0x00000776}, + {0x0000a1d8, 0x00000776}, + {0x0000a1dc, 0x00000776}, + {0x0000a1e0, 0x00000776}, + {0x0000a1e4, 0x00000776}, + {0x0000a1e8, 0x00000776}, + {0x0000a1ec, 0x00000776}, + {0x0000a1f0, 0x00000776}, + {0x0000a1f4, 0x00000776}, + {0x0000a1f8, 0x00000776}, + {0x0000a1fc, 0x00000776}, + {0x0000b000, 0x02000101}, + {0x0000b004, 0x02000102}, + {0x0000b008, 0x02000103}, + {0x0000b00c, 0x02000104}, + {0x0000b010, 0x02000200}, + {0x0000b014, 0x02000201}, + {0x0000b018, 0x02000202}, + {0x0000b01c, 0x02000203}, + {0x0000b020, 0x02000204}, + {0x0000b024, 0x02000205}, + {0x0000b028, 0x02000208}, + {0x0000b02c, 0x02000302}, + {0x0000b030, 0x02000303}, + {0x0000b034, 0x02000304}, + {0x0000b038, 0x02000400}, + {0x0000b03c, 0x02010300}, + {0x0000b040, 0x02010301}, + {0x0000b044, 0x02010302}, + {0x0000b048, 0x02000500}, + {0x0000b04c, 0x02010400}, + {0x0000b050, 0x02020300}, + {0x0000b054, 0x02020301}, + {0x0000b058, 0x02020302}, + {0x0000b05c, 0x02020303}, + {0x0000b060, 0x02020400}, + {0x0000b064, 0x02030300}, + {0x0000b068, 0x02030301}, + {0x0000b06c, 0x02030302}, + {0x0000b070, 0x02030303}, + {0x0000b074, 0x02030400}, + {0x0000b078, 0x02040300}, + {0x0000b07c, 0x02040301}, + {0x0000b080, 0x02040302}, + {0x0000b084, 0x02040303}, + {0x0000b088, 0x02030500}, + {0x0000b08c, 0x02040400}, + {0x0000b090, 0x02050203}, + {0x0000b094, 0x02050204}, + {0x0000b098, 0x02050205}, + {0x0000b09c, 0x02040500}, + {0x0000b0a0, 0x02050301}, + {0x0000b0a4, 0x02050302}, + {0x0000b0a8, 0x02050303}, + {0x0000b0ac, 0x02050400}, + {0x0000b0b0, 0x02050401}, + {0x0000b0b4, 0x02050402}, + {0x0000b0b8, 0x02050403}, + {0x0000b0bc, 0x02050500}, + {0x0000b0c0, 0x02050501}, + {0x0000b0c4, 0x02050502}, + {0x0000b0c8, 0x02050503}, + {0x0000b0cc, 0x02050504}, + {0x0000b0d0, 0x02050600}, + {0x0000b0d4, 0x02050601}, + {0x0000b0d8, 0x02050602}, + {0x0000b0dc, 0x02050603}, + {0x0000b0e0, 0x02050604}, + {0x0000b0e4, 0x02050700}, + {0x0000b0e8, 0x02050701}, + {0x0000b0ec, 0x02050702}, + {0x0000b0f0, 0x02050703}, + {0x0000b0f4, 0x02050704}, + {0x0000b0f8, 0x02050705}, + {0x0000b0fc, 0x02050708}, + {0x0000b100, 0x02050709}, + {0x0000b104, 0x0205070a}, + {0x0000b108, 0x0205070b}, + {0x0000b10c, 0x0205070c}, + {0x0000b110, 0x0205070d}, + {0x0000b114, 0x02050710}, + {0x0000b118, 0x02050711}, + {0x0000b11c, 0x02050712}, + {0x0000b120, 0x02050713}, + {0x0000b124, 0x02050714}, + {0x0000b128, 0x02050715}, + {0x0000b12c, 0x02050730}, + {0x0000b130, 0x02050731}, + {0x0000b134, 0x02050732}, + {0x0000b138, 0x02050733}, + {0x0000b13c, 0x02050734}, + {0x0000b140, 0x02050735}, + {0x0000b144, 0x02050750}, + {0x0000b148, 0x02050751}, + {0x0000b14c, 0x02050752}, + {0x0000b150, 0x02050753}, + {0x0000b154, 0x02050754}, + {0x0000b158, 0x02050755}, + {0x0000b15c, 0x02050770}, + {0x0000b160, 0x02050771}, + {0x0000b164, 0x02050772}, + {0x0000b168, 0x02050773}, + {0x0000b16c, 0x02050774}, + {0x0000b170, 0x02050775}, + {0x0000b174, 0x00000776}, + {0x0000b178, 0x00000776}, + {0x0000b17c, 0x00000776}, + {0x0000b180, 0x00000776}, + {0x0000b184, 0x00000776}, + {0x0000b188, 0x00000776}, + {0x0000b18c, 0x00000776}, + {0x0000b190, 0x00000776}, + {0x0000b194, 0x00000776}, + {0x0000b198, 0x00000776}, + {0x0000b19c, 0x00000776}, + {0x0000b1a0, 0x00000776}, + {0x0000b1a4, 0x00000776}, + {0x0000b1a8, 0x00000776}, + {0x0000b1ac, 0x00000776}, + {0x0000b1b0, 0x00000776}, + {0x0000b1b4, 0x00000776}, + {0x0000b1b8, 0x00000776}, + {0x0000b1bc, 0x00000776}, + {0x0000b1c0, 0x00000776}, + {0x0000b1c4, 0x00000776}, + {0x0000b1c8, 0x00000776}, + {0x0000b1cc, 0x00000776}, + {0x0000b1d0, 0x00000776}, + {0x0000b1d4, 0x00000776}, + {0x0000b1d8, 0x00000776}, + {0x0000b1dc, 0x00000776}, + {0x0000b1e0, 0x00000776}, + {0x0000b1e4, 0x00000776}, + {0x0000b1e8, 0x00000776}, + {0x0000b1ec, 0x00000776}, + {0x0000b1f0, 0x00000776}, + {0x0000b1f4, 0x00000776}, + {0x0000b1f8, 0x00000776}, + {0x0000b1fc, 0x00000776}, +}; + +static const u32 ar9200_ar9280_2p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00007800, 0x00040000}, + {0x00007804, 0xdb005012}, + {0x00007808, 0x04924914}, + {0x0000780c, 0x21084210}, + {0x00007810, 0x6d801300}, + {0x00007814, 0x0019beff}, + {0x00007818, 0x07e41000}, + {0x0000781c, 0x00392000}, + {0x00007820, 0x92592480}, + {0x00007824, 0x00040000}, + {0x00007828, 0xdb005012}, + {0x0000782c, 0x04924914}, + {0x00007830, 0x21084210}, + {0x00007834, 0x6d801300}, + {0x00007838, 0x0019beff}, + {0x0000783c, 0x07e40000}, + {0x00007840, 0x00392000}, + {0x00007844, 0x92592480}, + {0x00007848, 0x00100000}, + {0x0000784c, 0x773f0567}, + {0x00007850, 0x54214514}, + {0x00007854, 0x12035828}, + {0x00007858, 0x92592692}, + {0x0000785c, 0x00000000}, + {0x00007860, 0x56400000}, + {0x00007864, 0x0a8e370e}, + {0x00007868, 0xc0102850}, + {0x0000786c, 0x812d4000}, + {0x00007870, 0x807ec400}, + {0x00007874, 0x001b6db0}, + {0x00007878, 0x00376b63}, + {0x0000787c, 0x06db6db6}, + {0x00007880, 0x006d8000}, + {0x00007884, 0xffeffffe}, + {0x00007888, 0xffeffffe}, + {0x0000788c, 0x00010000}, + {0x00007890, 0x02060aeb}, + {0x00007894, 0x5a108000}, +}; + +static const u32 ar9462_2p0_mac_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00008014, 0x10f810f8, 0x10f810f8, 0x10f810f8, 0x10f810f8}, + {0x0000801c, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017, 0x0e8d8017}, +}; + +static const u32 ar9462_2p0_radio_postamble_sys3ant[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, + {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008}, + {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008}, +}; + +static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e3c, 0xcf946221, 0xcf946221, 0xcf946221, 0xcf946221}, + {0x00009e44, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000, 0xfc5c0000}, + {0x0000a258, 0x02020200, 0x02020200, 0x02020200, 0x02020200}, + {0x0000a25c, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a28c, 0x00011111, 0x00011111, 0x00011111, 0x00011111}, + {0x0000a2c4, 0x00148d18, 0x00148d18, 0x00148d20, 0x00148d20}, + {0x0000a2d8, 0xf999a800, 0xf999a800, 0xf999a80c, 0xf999a80c}, + {0x0000a50c, 0x0000c00a, 0x0000c00a, 0x0000c00a, 0x0000c00a}, + {0x0000a538, 0x00038e8c, 0x00038e8c, 0x00038e8c, 0x00038e8c}, + {0x0000a53c, 0x0003cecc, 0x0003cecc, 0x0003cecc, 0x0003cecc}, + {0x0000a540, 0x00040ed4, 0x00040ed4, 0x00040ed4, 0x00040ed4}, + {0x0000a544, 0x00044edc, 0x00044edc, 0x00044edc, 0x00044edc}, + {0x0000a548, 0x00048ede, 0x00048ede, 0x00048ede, 0x00048ede}, + {0x0000a54c, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e, 0x0004cf1e}, + {0x0000a550, 0x00050f5e, 0x00050f5e, 0x00050f5e, 0x00050f5e}, + {0x0000a554, 0x00054f9e, 0x00054f9e, 0x00054f9e, 0x00054f9e}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; + +static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808}, + {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008}, + {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008}, +}; + +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] = { + /* 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_2p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233}, +}; + +static const u32 ar9462_2p0_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, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009e54, 0xe4c355c7}, + {0x00009e58, 0xfd897735}, + {0x00009e5c, 0xe9198724}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {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}, + {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, 0x0c9bd380}, + {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, 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, 0x00000001}, + {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_2p0_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_modes_high_ob_db_tx_gain_table_2p0[][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, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {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, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {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_2p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016010, 0x6d820001}, + {0x00016040, 0x7f80fff8}, + {0x0001604c, 0x2699e04f}, + {0x00016050, 0x6db6db6c}, + {0x00016058, 0x6c200000}, + {0x00016080, 0x00040000}, + {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, 0x3d841400}, + {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_2p0_tx_gain_table_baseband_postamble_emulation[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a410, 0x000000d5, 0x000000d5, 0x000000d5, 0x000000d5}, + {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a504, 0x00004002, 0x00004002, 0x00004002, 0x00004002}, + {0x0000a508, 0x00008004, 0x00008004, 0x00008004, 0x00008004}, + {0x0000a510, 0x0001000c, 0x0001000c, 0x0001000c, 0x0001000c}, + {0x0000a514, 0x0001420b, 0x0001420b, 0x0001420b, 0x0001420b}, + {0x0000a518, 0x0001824a, 0x0001824a, 0x0001824a, 0x0001824a}, + {0x0000a51c, 0x0001c44a, 0x0001c44a, 0x0001c44a, 0x0001c44a}, + {0x0000a520, 0x0002064a, 0x0002064a, 0x0002064a, 0x0002064a}, + {0x0000a524, 0x0002484a, 0x0002484a, 0x0002484a, 0x0002484a}, + {0x0000a528, 0x00028a4a, 0x00028a4a, 0x00028a4a, 0x00028a4a}, + {0x0000a52c, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a, 0x0002cc4a}, + {0x0000a530, 0x00030e4a, 0x00030e4a, 0x00030e4a, 0x00030e4a}, + {0x0000a534, 0x00034e8a, 0x00034e8a, 0x00034e8a, 0x00034e8a}, +}; + +static const u32 ar9462_2p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x00007020, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, +}; + +static const u32 ar9462_2p0_sys2ant[][2] = { + /* Addr allmodes */ + {0x00063120, 0x00801980}, +}; + +static const u32 ar9462_2p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x000e0085}, + {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}, + {0x00001810, 0x0f000003}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00080000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008050, 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, 0x13881c20}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00b00005}, + {0x000080d8, 0x00400002}, + {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}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x00008170, 0x18486e00}, + {0x00008174, 0x33332210}, + {0x00008178, 0x00000000}, + {0x0000817c, 0x00020000}, + {0x000081c4, 0x33332210}, + {0x000081c8, 0x00000000}, + {0x000081cc, 0x00000000}, + {0x000081d4, 0x00000000}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f400}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e800}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x99c00010}, + {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, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x0000001f}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0xffff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48105b}, + {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}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {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] = { + /* 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_modes_green_ob_db_tx_gain_table_2p0[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, + {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, + {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, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec}, + {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, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180}, + {0x00016444, 0x056d82e4, 0x056d82e4, 0x056d82e4, 0x056d82e4}, + {0x00016448, 0x8db49000, 0x8db49000, 0x8db49000, 0x8db49000}, + {0x00016454, 0x6db60180, 0x6db60180, 0x6db60180, 0x6db60180}, +}; + +static const u32 ar9462_2p0_BTCOEX_MAX_TXPWR_table[][2] = { + /* Addr allmodes */ + {0x000018c0, 0x10101010}, + {0x000018c4, 0x10101010}, + {0x000018c8, 0x10101010}, + {0x000018cc, 0x10101010}, + {0x000018d0, 0x10101010}, + {0x000018d4, 0x10101010}, + {0x000018d8, 0x10101010}, + {0x000018dc, 0x10101010}, +}; + +static const u32 ar9462_2p0_baseband_core_emulation[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafa68e30}, + {0x00009884, 0x00002842}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009e50, 0x00000000}, + {0x00009fcc, 0x00000014}, + {0x0000a344, 0x00000010}, + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x71733d01}, + {0x0000a3a0, 0xd0ad5c12}, + {0x0000a3c0, 0x22222220}, + {0x0000a3c4, 0x22222222}, + {0x0000a404, 0x00418a11}, + {0x0000a418, 0x050001ce}, + {0x0000a438, 0x00001800}, + {0x0000a458, 0x01444452}, + {0x0000a644, 0x3fad9d74}, + {0x0000a690, 0x00000038}, +}; + +#endif /* INITVALS_9462_2P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h new file mode 100644 index 000000000000..06b3f0df9fad --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -0,0 +1,1673 @@ +/* + * Copyright (c) 2010 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_9580_1P0_H +#define INITVALS_9580_1P0_H + +/* AR9580 1.0 */ + +static const u32 ar9580_1p0_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, 0x0000000b, 0x00000016}, + {0x0000a254, 0x00000898, 0x00001130}, +}; + +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}, + {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, + {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, + {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008}, +}; + +static const u32 ar9580_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x3280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a290}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x0d000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {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, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009e54, 0x00000000}, + {0x00009fc0, 0x803e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {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}, + {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, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {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, 0x00100000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {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, 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 ar9580_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 ar9580_1p0_low_ob_db_tx_gain_table[][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, 0x12000400, 0x12000400}, + {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27002223, 0x27002223, 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, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {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, 0x12800400, 0x12800400}, + {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {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}, + {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}, +}; + +static const u32 ar9580_1p0_high_power_tx_gain_table[][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, 0x12000400, 0x12000400}, + {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27002223, 0x27002223, 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, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {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, 0x12800400, 0x12800400}, + {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {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}, + {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}, +}; + +static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][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, 0x12000400, 0x12000400}, + {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27002223, 0x27002223, 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, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {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, 0x12800400, 0x12800400}, + {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, + {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, + {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, + {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, + {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, + {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, + {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, + {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, + {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, + {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, + {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, + {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, + {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83}, + {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84}, + {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3}, + {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5}, + {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9}, + {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb}, + {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, + {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}, + {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, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +static const u32 ar9580_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { + /* Addr allmodes */ + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x6f7f0301}, + {0x0000a3a0, 0xca9228ee}, +}; + +static const u32 ar9580_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}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f400}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e800}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x9bc00010}, + {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, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x00000007}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0x00ff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48105b}, + {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, 0x000301ff}, +}; + +static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][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, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x3e02222c, 0x3e02222c, 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, 0x21802220, 0x21802220, 0x15800402, 0x15800402}, + {0x0000a59c, 0x27802223, 0x27802223, 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, 0x5c82486b, 0x5c82486b, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x7082708c, 0x7082708c, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x7782b08c, 0x7782b08c, 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}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, + {0x00016048, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, + {0x00016448, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x056db2e4, 0x056db2e4}, + {0x00016848, 0x66480001, 0x66480001, 0x8e480001, 0x8e480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +static const u32 ar9580_1p0_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 ar9580_1p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, +}; + +static const u32 ar9580_1p0_high_ob_db_tx_gain_table[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 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, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, + {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, + {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, + {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, + {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}, +}; + +static const u32 ar9580_1p0_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, 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 ar9580_1p0_radio_core[][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}, +}; + +static const u32 ar9580_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, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x000036c0, 0x000036c4, 0x000036c4, 0x000036c0}, + {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, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {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}, + {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, 0x00000150, 0x00000150}, + {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {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}, +}; + +#endif /* INITVALS_9580_1P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 46393f90f16c..1c269f50822b 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -87,17 +87,14 @@ struct ath_config { * @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) - * @BUF_XRETRY: To denote excessive retries of the buffer */ enum buffer_type { BUF_AMPDU = BIT(0), BUF_AGGR = BIT(1), - BUF_XRETRY = BIT(2), }; #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) -#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) #define ATH_TXSTATUS_RING_SIZE 64 @@ -206,18 +203,19 @@ struct ath_atx_ac { }; struct ath_frame_info { + struct ath_buf *bf; int framelen; - u32 keyix; enum ath9k_key_type keytype; + u8 keyix; u8 retries; - u16 seqno; }; struct ath_buf_state { u8 bf_type; u8 bfs_paprd; + u8 ndelim; + u16 seqno; unsigned long bfs_paprd_timestamp; - enum ath9k_internal_frame_type bfs_ftype; }; struct ath_buf { @@ -230,13 +228,12 @@ struct ath_buf { 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; - u16 bf_flags; struct ath_buf_state bf_state; }; struct ath_atx_tid { struct list_head list; - struct list_head buf_q; + struct sk_buff_head buf_q; struct ath_node *an; struct ath_atx_ac *ac; unsigned long tx_buf[BITS_TO_LONGS(ATH_TID_MAX_BUFS)]; @@ -273,14 +270,11 @@ struct ath_node { struct ath_tx_control { struct ath_txq *txq; struct ath_node *an; - int if_id; - enum ath9k_internal_frame_type frame_type; u8 paprd; }; #define ATH_TX_ERROR 0x01 -#define ATH_TX_XRETRY 0x02 -#define ATH_TX_BAR 0x04 +#define ATH_TX_BAR 0x02 /** * @txq_map: Index is mac80211 queue number. This is @@ -346,7 +340,8 @@ 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); -bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an); +void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, + struct ath_node *an); /********/ /* VIFs */ @@ -427,6 +422,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); #define ATH_PAPRD_TIMEOUT 100 /* msecs */ +void ath_reset_work(struct work_struct *work); void ath_hw_check(struct work_struct *work); void ath_hw_pll_work(struct work_struct *work); void ath_paprd_calibrate(struct work_struct *work); @@ -462,6 +458,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc); #define ATH_LED_PIN_9287 8 #define ATH_LED_PIN_9300 10 #define ATH_LED_PIN_9485 6 +#define ATH_LED_PIN_9462 0 #ifdef CONFIG_MAC80211_LEDS void ath_init_leds(struct ath_softc *sc); @@ -561,8 +558,7 @@ struct ath_ant_comb { #define SC_OP_BT_PRIORITY_DETECTED BIT(12) #define SC_OP_BT_SCAN BIT(13) #define SC_OP_ANI_RUN BIT(14) -#define SC_OP_ENABLE_APM BIT(15) -#define SC_OP_PRIM_STA_VIF BIT(16) +#define SC_OP_PRIM_STA_VIF BIT(15) /* Powersave flags */ #define PS_WAIT_FOR_BEACON BIT(0) @@ -570,7 +566,6 @@ struct ath_ant_comb { #define PS_WAIT_FOR_PSPOLL_DATA BIT(2) #define PS_WAIT_FOR_TX_ACK BIT(3) #define PS_BEACON_SYNC BIT(4) -#define PS_TSFOOR_SYNC BIT(5) struct ath_rate_table; @@ -608,6 +603,7 @@ struct ath_softc { struct mutex mutex; struct work_struct paprd_work; struct work_struct hw_check_work; + struct work_struct hw_reset_work; struct completion paprd_complete; unsigned int hw_busy_count; @@ -651,10 +647,10 @@ struct ath_softc { struct ath_descdma txsdma; struct ath_ant_comb ant_comb; + u8 ant_tx, ant_rx; }; void ath9k_tasklet(unsigned long data); -int ath_reset(struct ath_softc *sc, bool retry_tx); int ath_cabq_update(struct ath_softc *); static inline void ath_read_cachesize(struct ath_common *common, int *csz) @@ -668,11 +664,11 @@ extern int led_blink; extern bool is_ath9k_unloaded; irqreturn_t ath_isr(int irq, void *dev); -void ath9k_init_crypto(struct ath_softc *sc); -int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, +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); void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw); bool ath9k_uses_beacons(int type); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 0d13ff74a68b..a13cabb95435 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -73,44 +73,39 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, struct sk_buff *skb = bf->bf_mpdu; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - struct ath_desc *ds; - struct ath9k_11n_rate_series series[4]; - int flags, ctsrate = 0, ctsduration = 0; + struct ath_tx_info info; struct ieee80211_supported_band *sband; + u8 chainmask = ah->txchainmask; u8 rate = 0; ath9k_reset_beacon_status(sc); - ds = bf->bf_desc; - flags = ATH9K_TXDESC_NOACK; - - ds->ds_link = 0; - sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) rate |= sband->bitrates[rateidx].hw_value_short; - ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, - ATH9K_PKT_TYPE_BEACON, - MAX_RATE_POWER, - ATH9K_TXKEYIX_INVALID, - ATH9K_KEY_TYPE_CLEAR, - flags); - - /* NB: beacon's BufLen must be a multiple of 4 bytes */ - ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4), - true, true, ds, bf->bf_buf_addr, - sc->beacon.beaconq); - - memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); - series[0].Tries = 1; - series[0].Rate = rate; - series[0].ChSel = ath_txchainmask_reduction(sc, - common->tx_chainmask, series[0].Rate); - series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; - ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, - series, 4, 0); + memset(&info, 0, sizeof(info)); + info.pkt_len = skb->len + FCS_LEN; + info.type = ATH9K_PKT_TYPE_BEACON; + info.txpower = MAX_RATE_POWER; + info.keyix = ATH9K_TXKEYIX_INVALID; + info.keytype = ATH9K_KEY_TYPE_CLEAR; + info.flags = ATH9K_TXDESC_NOACK; + + info.buf_addr[0] = bf->bf_buf_addr; + info.buf_len[0] = roundup(skb->len, 4); + + info.is_first = true; + info.is_last = true; + + info.qcu = sc->beacon.beaconq; + + info.rates[0].Tries = 1; + info.rates[0].Rate = rate; + info.rates[0].ChSel = ath_txchainmask_reduction(sc, chainmask, rate); + + ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); } static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) @@ -386,9 +381,7 @@ void ath_beacon_tasklet(unsigned long data) ath_dbg(common, ATH_DBG_BSTUCK, "beacon is officially stuck\n"); sc->sc_flags |= SC_OP_TSF_RESET; - spin_lock(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock(&sc->sc_pcu_lock); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } return; @@ -519,9 +512,11 @@ static void ath_beacon_config_ap(struct ath_softc *sc, /* Set the computed AP beacon timers */ ath9k_hw_disable_interrupts(ah); + sc->sc_flags |= SC_OP_TSF_RESET; ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); } /* @@ -648,12 +643,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc, ath9k_hw_set_sta_beacon_timers(ah, &bs); ah->imask |= ATH9K_INT_BMISS; - /* - * If the beacon config is called beacause of TSFOOR, - * Interrupts will be enabled back at the end of ath9k_tasklet - */ - if (!(sc->ps_flags & PS_TSFOOR_SYNC)) - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); } static void ath_beacon_config_adhoc(struct ath_softc *sc, @@ -687,12 +678,9 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc, ath9k_hw_disable_interrupts(ah); ath9k_beacon_init(sc, nexttbtt, intval); sc->beacon.bmisscnt = 0; - /* - * If the beacon config is called beacause of TSFOOR, - * Interrupts will be enabled back at the end of ath9k_tasklet - */ - if (!(sc->ps_flags & PS_TSFOOR_SYNC)) - ath9k_hw_set_interrupts(ah, ah->imask); + + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); } static bool ath9k_allow_beacon_config(struct ath_softc *sc, @@ -833,11 +821,11 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) if (status) { /* Re-enable beaconing */ ah->imask |= ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); } else { /* Disable SWBA interrupt */ ah->imask &= ~ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); tasklet_kill(&sc->bcon_tasklet); ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); } diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c index a1250c586e40..ebaf304f464b 100644 --- a/drivers/net/wireless/ath/ath9k/calib.c +++ b/drivers/net/wireless/ath/ath9k/calib.c @@ -63,13 +63,25 @@ static s16 ath9k_hw_get_default_nf(struct ath_hw *ah, return ath9k_hw_get_nf_limits(ah, chan)->nominal; } +s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan) +{ + s8 noise = ATH_DEFAULT_NOISE_FLOOR; + + if (chan && chan->noisefloor) { + s8 delta = chan->noisefloor - + ath9k_hw_get_default_nf(ah, chan); + if (delta > 0) + noise += delta; + } + return noise; +} +EXPORT_SYMBOL(ath9k_hw_getchan_noise); static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, struct ath9k_hw_cal_data *cal, int16_t *nfarray) { struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_conf *conf = &common->hw->conf; struct ath_nf_limits *limit; struct ath9k_nfcal_hist *h; bool high_nf_mid = false; @@ -81,7 +93,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah, for (i = 0; i < NUM_NF_READINGS; i++) { if (!(chainmask & (1 << i)) || - ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))) + ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(ah->curchan))) continue; h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; @@ -378,6 +390,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) if (!caldata) { chan->noisefloor = nf; + ah->noise = ath9k_hw_getchan_noise(ah, chan); return false; } @@ -385,6 +398,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan) caldata->nfcal_pending = false; ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray); chan->noisefloor = h[0].privNF; + ah->noise = ath9k_hw_getchan_noise(ah, chan); return true; } diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 1bef41d1b1ff..05b9dbf81850 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -108,6 +108,7 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah, 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); #endif /* CALIB_H */ diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index fa6bd2d189e5..905f1b313961 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -161,14 +161,42 @@ EXPORT_SYMBOL(ath9k_cmn_count_streams); void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow, u16 new_txpow, u16 *txpower) { - if (cur_txpow != new_txpow) { + struct ath_regulatory *reg = ath9k_hw_regulatory(ah); + + if (reg->power_limit != new_txpow) { ath9k_hw_set_txpowerlimit(ah, new_txpow, false); /* read back in case value is clamped */ - *txpower = ath9k_hw_regulatory(ah)->power_limit; + *txpower = reg->max_power_level; } } EXPORT_SYMBOL(ath9k_cmn_update_txpow); +void ath9k_cmn_init_crypto(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + int i = 0; + + /* Get the hardware key cache size. */ + common->keymax = AR_KEYTABLE_SIZE; + + /* + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. + */ + if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) + common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; + + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < common->keymax; i++) + ath_hw_keyreset(common, (u16) i); +} +EXPORT_SYMBOL(ath9k_cmn_init_crypto); + static int __init ath9k_cmn_init(void) { return 0; diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h index 77ec288b5a70..ad14fecc76c6 100644 --- a/drivers/net/wireless/ath/ath9k/common.h +++ b/drivers/net/wireless/ath/ath9k/common.h @@ -62,3 +62,4 @@ 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 d1eb89611ff7..327aa28f6030 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -95,11 +95,11 @@ 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_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; char buf[32]; unsigned int len; - len = sprintf(buf, "0x%08x\n", common->tx_chainmask); + len = sprintf(buf, "0x%08x\n", ah->txchainmask); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -107,7 +107,7 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use size_t count, loff_t *ppos) { 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 long mask; char buf[32]; ssize_t len; @@ -120,8 +120,8 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use if (strict_strtoul(buf, 0, &mask)) return -EINVAL; - common->tx_chainmask = mask; - sc->sc_ah->caps.tx_chainmask = mask; + ah->txchainmask = mask; + ah->caps.tx_chainmask = mask; return count; } @@ -138,11 +138,11 @@ 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_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_hw *ah = sc->sc_ah; char buf[32]; unsigned int len; - len = sprintf(buf, "0x%08x\n", common->rx_chainmask); + len = sprintf(buf, "0x%08x\n", ah->rxchainmask); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -150,7 +150,7 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use size_t count, loff_t *ppos) { 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 long mask; char buf[32]; ssize_t len; @@ -163,8 +163,8 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use if (strict_strtoul(buf, 0, &mask)) return -EINVAL; - common->rx_chainmask = mask; - sc->sc_ah->caps.rx_chainmask = mask; + ah->rxchainmask = mask; + ah->caps.rx_chainmask = mask; return count; } @@ -523,9 +523,22 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf, if (tmp & ATH9K_RX_FILTER_PHYRADAR) len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR"); if (tmp & ATH9K_RX_FILTER_MCAST_BCAST_ALL) - len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL\n"); - else - len += snprintf(buf + len, sizeof(buf) - len, "\n"); + len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL"); + + len += snprintf(buf + len, sizeof(buf) - len, + "\n\nReset causes:\n" + " baseband hang: %d\n" + " baseband watchdog: %d\n" + " fatal hardware error interrupt: %d\n" + " tx hardware error: %d\n" + " tx path hang: %d\n" + " pll rx hang: %d\n", + sc->debug.stats.reset[RESET_TYPE_BB_HANG], + sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG], + sc->debug.stats.reset[RESET_TYPE_FATAL_INT], + sc->debug.stats.reset[RESET_TYPE_TX_ERROR], + sc->debug.stats.reset[RESET_TYPE_TX_HANG], + sc->debug.stats.reset[RESET_TYPE_PLL_HANG]); if (len > sizeof(buf)) len = sizeof(buf); @@ -711,7 +724,7 @@ static ssize_t read_file_stations(struct file *file, char __user *user_buf, " tid: %p %s %s %i %p %p\n", tid, tid->sched ? "sched" : "idle", tid->paused ? "paused" : "running", - list_empty(&tid->buf_q), + skb_queue_empty(&tid->buf_q), tid->an, tid->ac); if (len >= size) goto done; @@ -826,20 +839,23 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf, } void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts, struct ath_txq *txq) + struct ath_tx_status *ts, struct ath_txq *txq, + unsigned int flags) { +#define TX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].ts\ + [sc->debug.tsidx].c) int qnum = txq->axq_qnum; TX_STAT_INC(qnum, tx_pkts_all); sc->debug.stats.txstats[qnum].tx_bytes_all += bf->bf_mpdu->len; if (bf_isampdu(bf)) { - if (bf_isxretried(bf)) + if (flags & ATH_TX_BAR) TX_STAT_INC(qnum, a_xretries); else TX_STAT_INC(qnum, a_completed); } else { - if (bf_isxretried(bf)) + if (ts->ts_status & ATH9K_TXERR_XRETRY) TX_STAT_INC(qnum, xretries); else TX_STAT_INC(qnum, completed); @@ -857,6 +873,35 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, TX_STAT_INC(qnum, data_underrun); if (ts->ts_flags & ATH9K_TX_DELIM_UNDERRUN) TX_STAT_INC(qnum, delim_underrun); + + spin_lock(&sc->debug.samp_lock); + TX_SAMP_DBG(jiffies) = jiffies; + TX_SAMP_DBG(rssi_ctl0) = ts->ts_rssi_ctl0; + TX_SAMP_DBG(rssi_ctl1) = ts->ts_rssi_ctl1; + TX_SAMP_DBG(rssi_ctl2) = ts->ts_rssi_ctl2; + TX_SAMP_DBG(rssi_ext0) = ts->ts_rssi_ext0; + TX_SAMP_DBG(rssi_ext1) = ts->ts_rssi_ext1; + TX_SAMP_DBG(rssi_ext2) = ts->ts_rssi_ext2; + TX_SAMP_DBG(rateindex) = ts->ts_rateindex; + TX_SAMP_DBG(isok) = !!(ts->ts_status & ATH9K_TXERR_MASK); + TX_SAMP_DBG(rts_fail_cnt) = ts->ts_shortretry; + TX_SAMP_DBG(data_fail_cnt) = ts->ts_longretry; + TX_SAMP_DBG(rssi) = ts->ts_rssi; + TX_SAMP_DBG(tid) = ts->tid; + TX_SAMP_DBG(qid) = ts->qid; + + if (ts->ts_flags & ATH9K_TX_BA) { + TX_SAMP_DBG(ba_low) = ts->ba_low; + TX_SAMP_DBG(ba_high) = ts->ba_high; + } else { + TX_SAMP_DBG(ba_low) = 0; + TX_SAMP_DBG(ba_high) = 0; + } + + sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock(&sc->debug.samp_lock); + +#undef TX_SAMP_DBG } static const struct file_operations fops_xmit = { @@ -995,6 +1040,8 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) { #define RX_STAT_INC(c) sc->debug.stats.rxstats.c++ #define RX_PHY_ERR_INC(c) sc->debug.stats.rxstats.phy_err_stats[c]++ +#define RX_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].rs\ + [sc->debug.rsidx].c) u32 phyerr; @@ -1030,8 +1077,25 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs) sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna; + spin_lock(&sc->debug.samp_lock); + RX_SAMP_DBG(jiffies) = jiffies; + RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0; + RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1; + RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2; + RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0; + RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1; + RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2; + RX_SAMP_DBG(antenna) = rs->rs_antenna; + RX_SAMP_DBG(rssi) = rs->rs_rssi; + RX_SAMP_DBG(rate) = rs->rs_rate; + RX_SAMP_DBG(is_mybeacon) = rs->is_mybeacon; + + sc->debug.rsidx = (sc->debug.rsidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock(&sc->debug.samp_lock); + #undef RX_STAT_INC #undef RX_PHY_ERR_INC +#undef RX_SAMP_DBG } static const struct file_operations fops_recv = { @@ -1163,6 +1227,389 @@ 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) +{ + struct ath_softc *sc = file->private_data; + struct ath_hw *ah = sc->sc_ah; + struct ath9k_nfcal_hist *h = sc->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"); + 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); + for (j = 0; j < nread; j++) + len += snprintf(buf + len, size - len, + " %d", h[i].nfCalBuffer[j]); + len += snprintf(buf + len, size - len, "\n"); + } + + 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_dump_nfcal = { + .read = read_file_dump_nfcal, + .open = ath9k_debugfs_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) +{ + 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; + + 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 = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static ssize_t read_file_modal_eeprom(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; + + 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 = ath9k_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void ath9k_debug_samp_bb_mac(struct ath_softc *sc) +{ +#define ATH_SAMP_DBG(c) (sc->debug.bb_mac_samp[sc->debug.sampidx].c) + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + unsigned long flags; + int i; + + ath9k_ps_wakeup(sc); + + spin_lock_bh(&sc->debug.samp_lock); + + spin_lock_irqsave(&common->cc_lock, flags); + ath_hw_cycle_counters_update(common); + + ATH_SAMP_DBG(cc.cycles) = common->cc_ani.cycles; + ATH_SAMP_DBG(cc.rx_busy) = common->cc_ani.rx_busy; + ATH_SAMP_DBG(cc.rx_frame) = common->cc_ani.rx_frame; + ATH_SAMP_DBG(cc.tx_frame) = common->cc_ani.tx_frame; + spin_unlock_irqrestore(&common->cc_lock, flags); + + ATH_SAMP_DBG(noise) = ah->noise; + + REG_WRITE_D(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + ATH_SAMP_DBG(dma_dbg_reg_vals[i]) = REG_READ_D(ah, + AR_DMADBG_0 + (i * sizeof(u32))); + + ATH_SAMP_DBG(pcu_obs) = REG_READ_D(ah, AR_OBS_BUS_1); + ATH_SAMP_DBG(pcu_cr) = REG_READ_D(ah, AR_CR); + + memcpy(ATH_SAMP_DBG(nfCalHist), sc->caldata.nfCalHist, + sizeof(ATH_SAMP_DBG(nfCalHist))); + + sc->debug.sampidx = (sc->debug.sampidx + 1) % ATH_DBG_MAX_SAMPLES; + spin_unlock_bh(&sc->debug.samp_lock); + ath9k_ps_restore(sc); + +#undef ATH_SAMP_DBG +} + +static int open_file_bb_mac_samps(struct inode *inode, struct file *file) +{ +#define ATH_SAMP_DBG(c) bb_mac_samp[sampidx].c + struct ath_softc *sc = inode->i_private; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_conf *conf = &common->hw->conf; + struct ath_dbg_bb_mac_samp *bb_mac_samp; + struct ath9k_nfcal_hist *h; + int i, j, qcuOffset = 0, dcuOffset = 0; + u32 *qcuBase, *dcuBase, size = 30000, len = 0; + u32 sampidx = 0; + u8 *buf; + u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; + u8 nread; + + if (sc->sc_flags & SC_OP_INVALID) + return -EAGAIN; + + buf = vmalloc(size); + if (!buf) + return -ENOMEM; + bb_mac_samp = vmalloc(sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES); + if (!bb_mac_samp) { + vfree(buf); + return -ENOMEM; + } + /* Account the current state too */ + ath9k_debug_samp_bb_mac(sc); + + spin_lock_bh(&sc->debug.samp_lock); + memcpy(bb_mac_samp, sc->debug.bb_mac_samp, + sizeof(*bb_mac_samp) * ATH_DBG_MAX_SAMPLES); + len += snprintf(buf + len, size - len, + "Current Sample Index: %d\n", sc->debug.sampidx); + spin_unlock_bh(&sc->debug.samp_lock); + + len += snprintf(buf + len, size - len, + "Raw DMA Debug Dump:\n"); + len += snprintf(buf + len, size - len, "Sample |\t"); + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + len += snprintf(buf + len, size - len, " DMA Reg%d |\t", i); + len += snprintf(buf + len, size - len, "\n"); + + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + len += snprintf(buf + len, size - len, "%d\t", sampidx); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) + len += snprintf(buf + len, size - len, " %08x\t", + ATH_SAMP_DBG(dma_dbg_reg_vals[i])); + len += snprintf(buf + len, size - len, "\n"); + } + len += snprintf(buf + len, size - len, "\n"); + + len += snprintf(buf + len, size - len, + "Sample Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]); + dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]); + + for (i = 0; i < ATH9K_NUM_QUEUES; i++, + qcuOffset += 4, dcuOffset += 5) { + if (i == 8) { + qcuOffset = 0; + qcuBase++; + } + + if (i == 6) { + dcuOffset = 0; + dcuBase++; + } + if (!sc->debug.stats.txstats[i].queued) + continue; + + len += snprintf(buf + len, size - len, + "%4d %7d %2x %1x %2x %2x\n", + sampidx, i, + (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> + (qcuOffset + 3), + ATH_SAMP_DBG(dma_dbg_reg_vals[2]) & + (0x7 << (i * 3)) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + } + len += snprintf(buf + len, size - len, "\n"); + } + len += snprintf(buf + len, size - len, + "samp qcu_sh qcu_fh qcu_comp dcu_comp dcu_arb dcu_fp " + "ch_idle_dur ch_idle_dur_val txfifo_val0 txfifo_val1 " + "txfifo_dcu0 txfifo_dcu1 pcu_obs AR_CR\n"); + + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + qcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[0]); + dcuBase = &ATH_SAMP_DBG(dma_dbg_reg_vals[4]); + + len += snprintf(buf + len, size - len, "%4d %5x %5x ", sampidx, + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x003c0000) >> 18, + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x03c00000) >> 22); + len += snprintf(buf + len, size - len, "%7x %8x ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[3]) & 0x1c000000) >> 26, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x3)); + len += snprintf(buf + len, size - len, "%7x %7x ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x06000000) >> 25, + (ATH_SAMP_DBG(dma_dbg_reg_vals[5]) & 0x38000000) >> 27); + len += snprintf(buf + len, size - len, "%7d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x000003fc) >> 2, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000400) >> 10); + len += snprintf(buf + len, size - len, "%12d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00000800) >> 11, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x00001000) >> 12); + len += snprintf(buf + len, size - len, "%12d %12d ", + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x0001e000) >> 13, + (ATH_SAMP_DBG(dma_dbg_reg_vals[6]) & 0x001e0000) >> 17); + len += snprintf(buf + len, size - len, "0x%07x 0x%07x\n", + ATH_SAMP_DBG(pcu_obs), ATH_SAMP_DBG(pcu_cr)); + } + + len += snprintf(buf + len, size - len, + "Sample ChNoise Chain privNF #Reading Readings\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + h = ATH_SAMP_DBG(nfCalHist); + if (!ATH_SAMP_DBG(noise)) + continue; + + 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, + "%4d %5d %4d\t %d\t %d\t", + sampidx, ATH_SAMP_DBG(noise), + 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"); + } + } + len += snprintf(buf + len, size - len, "\nCycle counters:\n" + "Sample Total Rxbusy Rxframes Txframes\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + if (!ATH_SAMP_DBG(cc.cycles)) + continue; + len += snprintf(buf + len, size - len, + "%4d %08x %08x %08x %08x\n", + sampidx, ATH_SAMP_DBG(cc.cycles), + ATH_SAMP_DBG(cc.rx_busy), + ATH_SAMP_DBG(cc.rx_frame), + ATH_SAMP_DBG(cc.tx_frame)); + } + + len += snprintf(buf + len, size - len, "Tx status Dump :\n"); + len += snprintf(buf + len, size - len, + "Sample rssi:- ctl0 ctl1 ctl2 ext0 ext1 ext2 comb " + "isok rts_fail data_fail rate tid qid " + "ba_low ba_high tx_before(ms)\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) { + if (!ATH_SAMP_DBG(ts[i].jiffies)) + continue; + len += snprintf(buf + len, size - len, "%-14d" + "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-8d " + "%-9d %-4d %-3d %-3d %08x %08x %-11d\n", + sampidx, + ATH_SAMP_DBG(ts[i].rssi_ctl0), + ATH_SAMP_DBG(ts[i].rssi_ctl1), + ATH_SAMP_DBG(ts[i].rssi_ctl2), + ATH_SAMP_DBG(ts[i].rssi_ext0), + ATH_SAMP_DBG(ts[i].rssi_ext1), + ATH_SAMP_DBG(ts[i].rssi_ext2), + ATH_SAMP_DBG(ts[i].rssi), + ATH_SAMP_DBG(ts[i].isok), + ATH_SAMP_DBG(ts[i].rts_fail_cnt), + ATH_SAMP_DBG(ts[i].data_fail_cnt), + ATH_SAMP_DBG(ts[i].rateindex), + ATH_SAMP_DBG(ts[i].tid), + ATH_SAMP_DBG(ts[i].qid), + ATH_SAMP_DBG(ts[i].ba_low), + ATH_SAMP_DBG(ts[i].ba_high), + jiffies_to_msecs(jiffies - + ATH_SAMP_DBG(ts[i].jiffies))); + } + } + + len += snprintf(buf + len, size - len, "Rx status Dump :\n"); + len += snprintf(buf + len, size - len, "Sample rssi:- ctl0 ctl1 ctl2 " + "ext0 ext1 ext2 comb beacon ant rate rx_before(ms)\n"); + for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) { + for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) { + if (!ATH_SAMP_DBG(rs[i].jiffies)) + continue; + len += snprintf(buf + len, size - len, "%-14d" + "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-9s %-2d %02x %-13d\n", + sampidx, + ATH_SAMP_DBG(rs[i].rssi_ctl0), + ATH_SAMP_DBG(rs[i].rssi_ctl1), + ATH_SAMP_DBG(rs[i].rssi_ctl2), + ATH_SAMP_DBG(rs[i].rssi_ext0), + ATH_SAMP_DBG(rs[i].rssi_ext1), + ATH_SAMP_DBG(rs[i].rssi_ext2), + ATH_SAMP_DBG(rs[i].rssi), + ATH_SAMP_DBG(rs[i].is_mybeacon) ? + "True" : "False", + ATH_SAMP_DBG(rs[i].antenna), + ATH_SAMP_DBG(rs[i].rate), + jiffies_to_msecs(jiffies - + ATH_SAMP_DBG(rs[i].jiffies))); + } + } + + vfree(bb_mac_samp); + file->private_data = buf; + + return 0; +#undef ATH_SAMP_DBG +} + +static const struct file_operations fops_samps = { + .open = open_file_bb_mac_samps, + .read = ath9k_debugfs_read_buf, + .release = ath9k_debugfs_release_buf, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + + int ath9k_init_debug(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1206,6 +1653,14 @@ int ath9k_init_debug(struct ath_hw *ah) &ah->config.cwm_ignore_extcca); debugfs_create_file("regdump", S_IRUSR, 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); + debugfs_create_file("samples", S_IRUSR, sc->debug.debugfs_phy, sc, + &fops_samps); debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); @@ -1214,5 +1669,9 @@ int ath9k_init_debug(struct ath_hw *ah) sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); sc->debug.regidx = 0; + memset(&sc->debug.bb_mac_samp, 0, sizeof(sc->debug.bb_mac_samp)); + sc->debug.sampidx = 0; + sc->debug.tsidx = 0; + sc->debug.rsidx = 0; return 0; } diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index 4a04510e1111..356352ac2d6e 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -25,8 +25,10 @@ struct ath_buf; #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]++ #else #define TX_STAT_INC(q, c) do { } while (0) +#define RESET_STAT_INC(sc, type) do { } while (0) #endif #ifdef CONFIG_ATH9K_DEBUGFS @@ -171,23 +173,80 @@ struct ath_rx_stats { u8 rs_antenna; }; +enum ath_reset_type { + RESET_TYPE_BB_HANG, + RESET_TYPE_BB_WATCHDOG, + RESET_TYPE_FATAL_INT, + RESET_TYPE_TX_ERROR, + RESET_TYPE_TX_HANG, + RESET_TYPE_PLL_HANG, + __RESET_TYPE_MAX +}; + struct ath_stats { struct ath_interrupt_stats istats; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; struct ath_rx_stats rxstats; + u32 reset[__RESET_TYPE_MAX]; +}; + +#define ATH_DBG_MAX_SAMPLES 10 +struct ath_dbg_bb_mac_samp { + u32 dma_dbg_reg_vals[ATH9K_NUM_DMA_DEBUG_REGS]; + u32 pcu_obs, pcu_cr, noise; + struct { + u64 jiffies; + int8_t rssi_ctl0; + int8_t rssi_ctl1; + int8_t rssi_ctl2; + int8_t rssi_ext0; + int8_t rssi_ext1; + int8_t rssi_ext2; + int8_t rssi; + bool isok; + u8 rts_fail_cnt; + u8 data_fail_cnt; + u8 rateindex; + u8 qid; + u8 tid; + u32 ba_low; + u32 ba_high; + } ts[ATH_DBG_MAX_SAMPLES]; + struct { + u64 jiffies; + int8_t rssi_ctl0; + int8_t rssi_ctl1; + int8_t rssi_ctl2; + int8_t rssi_ext0; + int8_t rssi_ext1; + int8_t rssi_ext2; + int8_t rssi; + bool is_mybeacon; + u8 antenna; + u8 rate; + } rs[ATH_DBG_MAX_SAMPLES]; + struct ath_cycle_counters cc; + struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; }; struct ath9k_debug { struct dentry *debugfs_phy; u32 regidx; struct ath_stats stats; + spinlock_t samp_lock; + struct ath_dbg_bb_mac_samp bb_mac_samp[ATH_DBG_MAX_SAMPLES]; + u8 sampidx; + u8 tsidx; + u8 rsidx; }; int ath9k_init_debug(struct ath_hw *ah); +void ath9k_debug_samp_bb_mac(struct ath_softc *sc); void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, - struct ath_tx_status *ts, struct ath_txq *txq); + struct ath_tx_status *ts, struct ath_txq *txq, + unsigned int flags); void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs); #else @@ -197,6 +256,10 @@ static inline int ath9k_init_debug(struct ath_hw *ah) return 0; } +static inline void ath9k_debug_samp_bb_mac(struct ath_softc *sc) +{ +} + static inline void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) { @@ -205,7 +268,8 @@ static inline void ath_debug_stat_interrupt(struct ath_softc *sc, static inline void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, - struct ath_txq *txq) + struct ath_txq *txq, + unsigned int flags) { } diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c index e61404dda8c5..e46f751ab508 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.c +++ b/drivers/net/wireless/ath/ath9k/eeprom.c @@ -456,12 +456,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah, pPdGainBoundaries[i] = min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]); - if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } + minDelta = 0; if (i == 0) { if (AR_SREV_9280_20_OR_LATER(ah)) diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index de99c0da52e4..49abd34be741 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -104,16 +104,11 @@ #define OLC_FOR_AR9287_10_LATER (AR_SREV_9287_11_OR_LATER(ah) && \ ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)) -#define AR_EEPROM_RFSILENT_GPIO_SEL 0x001c -#define AR_EEPROM_RFSILENT_GPIO_SEL_S 2 -#define AR_EEPROM_RFSILENT_POLARITY 0x0002 -#define AR_EEPROM_RFSILENT_POLARITY_S 1 - #define EEP_RFSILENT_ENABLED 0x0001 #define EEP_RFSILENT_ENABLED_S 0 #define EEP_RFSILENT_POLARITY 0x0002 #define EEP_RFSILENT_POLARITY_S 1 -#define EEP_RFSILENT_GPIO_SEL 0x001c +#define EEP_RFSILENT_GPIO_SEL (AR_SREV_9462(ah) ? 0x00fc : 0x001c) #define EEP_RFSILENT_GPIO_SEL_S 2 #define AR5416_OPFLAGS_11A 0x01 @@ -225,7 +220,6 @@ enum eeprom_param { EEP_MAC_MID, EEP_MAC_LSW, EEP_REG_0, - EEP_REG_1, EEP_OP_CAP, EEP_OP_MODE, EEP_RF_SILENT, @@ -253,7 +247,9 @@ enum eeprom_param { EEP_PAPRD, EEP_MODAL_VER, EEP_ANT_DIV_CTL1, - EEP_CHAIN_MASK_REDUCE + EEP_CHAIN_MASK_REDUCE, + EEP_ANTENNA_GAIN_2G, + EEP_ANTENNA_GAIN_5G }; enum ar5416_rates { @@ -649,14 +645,15 @@ struct eeprom_ops { int (*check_eeprom)(struct ath_hw *hw); u32 (*get_eeprom)(struct ath_hw *hw, enum eeprom_param param); bool (*fill_eeprom)(struct ath_hw *hw); + u32 (*dump_eeprom)(struct ath_hw *hw, bool dump_base_hdr, u8 *buf, + u32 len, u32 size); int (*get_eeprom_ver)(struct ath_hw *hw); int (*get_eeprom_rev)(struct ath_hw *hw); void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan); void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan); void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, u8 powerLimit, - bool test); + u8 powerLimit, bool test); u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); }; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c index 47cc95086e6e..9a7520f987f0 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c @@ -72,6 +72,117 @@ 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) +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. Gain", modal_hdr->antennaGainCh[0]); + PR_EEP("Switch Settle", modal_hdr->switchSettling); + PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]); + PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]); + PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); + PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize); + PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]); + PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff); + PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn); + PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); + PR_EEP("CCA Threshold)", modal_hdr->thresh62); + PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); + PR_EEP("xpdGain", modal_hdr->xpdGain); + PR_EEP("External PD", modal_hdr->xpd); + PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]); + PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]); + PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap); + PR_EEP("O/D Bias Version", modal_hdr->version); + PR_EEP("CCK OutputBias", modal_hdr->ob_0); + PR_EEP("BPSK OutputBias", modal_hdr->ob_1); + PR_EEP("QPSK OutputBias", modal_hdr->ob_2); + PR_EEP("16QAM OutputBias", modal_hdr->ob_3); + PR_EEP("64QAM OutputBias", modal_hdr->ob_4); + PR_EEP("CCK Driver1_Bias", modal_hdr->db1_0); + PR_EEP("BPSK Driver1_Bias", modal_hdr->db1_1); + PR_EEP("QPSK Driver1_Bias", modal_hdr->db1_2); + PR_EEP("16QAM Driver1_Bias", modal_hdr->db1_3); + PR_EEP("64QAM Driver1_Bias", modal_hdr->db1_4); + PR_EEP("CCK Driver2_Bias", modal_hdr->db2_0); + PR_EEP("BPSK Driver2_Bias", modal_hdr->db2_1); + PR_EEP("QPSK Driver2_Bias", modal_hdr->db2_2); + PR_EEP("16QAM Driver2_Bias", modal_hdr->db2_3); + PR_EEP("64QAM Driver2_Bias", modal_hdr->db2_4); + PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); + PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); + PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]); + PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]); + PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40); + PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]); + PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]); + PR_EEP("Ant. Diversity ctl1", modal_hdr->antdiv_ctl1); + PR_EEP("Ant. Diversity ctl2", modal_hdr->antdiv_ctl2); + PR_EEP("TX Diversity", modal_hdr->tx_diversity); + + return len; +} + +static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, + u8 *buf, u32 len, u32 size) +{ + struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; + + if (!dump_base_hdr) { + len += snprintf(buf + len, size - len, + "%20s :\n", "2GHz modal Header"); + len += ath9k_dump_4k_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("TX Mask", pBase->txMask); + PR_EEP("RX Mask", pBase->rxMask); + PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); + PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); + PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags & + AR5416_OPFLAGS_N_2G_HT20)); + PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags & + AR5416_OPFLAGS_N_2G_HT40)); + PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags & + 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("TX Gain type", pBase->txGainType); + + len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", + pBase->macAddr); + +out: + if (len > size) + len = size; + + return len; +} +#else +static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, + u8 *buf, u32 len, u32 size) +{ + return 0; +} +#endif + + #undef SIZE_EEPROM_4K static int ath9k_hw_4k_check_eeprom(struct ath_hw *ah) @@ -211,8 +322,6 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, return get_unaligned_be16(pBase->macAddr + 4); case EEP_REG_0: return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; case EEP_OP_CAP: return pBase->deviceCap; case EEP_OP_MODE: @@ -238,18 +347,16 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah, case EEP_ANT_DIV_CTL1: return pModal->antdiv_ctl1; case EEP_TXGAIN_TYPE: - if (ver_minor >= AR5416_EEP_MINOR_VER_19) - return pBase->txGainType; - else - return AR5416_EEP_TXGAIN_ORIGINAL; + return pBase->txGainType; + case EEP_ANTENNA_GAIN_2G: + return pModal->antennaGainCh[0]; default: return 0; } } static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) + struct ath9k_channel *chan) { struct ath_common *common = ath9k_hw_common(ah); struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; @@ -298,12 +405,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_3, 0); for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) { - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && - (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; + regChainOffset = i * 0x1000; if (pEepData->baseEepHeader.txMask & (1 << i)) { pRawDataset = pEepData->calPierData2G[i]; @@ -316,19 +418,17 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, ENABLE_REGWRITE_BUFFER(ah); - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { - REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } + REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; for (j = 0; j < 32; j++) { @@ -356,16 +456,13 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah, REGWRITE_BUFFER_FLUSH(ah); } } - - *pTxPowerIndexOffset = 0; } static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, + u16 antenna_reduction, u16 powerLimit) { #define CMP_TEST_GRP \ @@ -374,20 +471,16 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, || (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL)) - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); int i; - int16_t twiceLargestAntenna; u16 twiceMinEdgePower; u16 twiceMaxEdgePower = MAX_RATE_POWER; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 scaledPower = 0, minCtlPower; u16 numCtlModes; const u16 *pCtlMode; u16 ctlMode, freq; struct chan_centers centers; struct cal_ctl_data_4k *rep; struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, MAX_RATE_POWER }; struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { 0, { 0, 0, 0, 0} }; @@ -405,19 +498,7 @@ static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah, ath9k_hw_get_channel_centers(ah, chan, ¢ers); - twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(regulatory->tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - scaledPower = max((u16)0, scaledPower); - + scaledPower = powerLimit - antenna_reduction; numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; pCtlMode = ctlModesFor11g; @@ -573,14 +654,12 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, u8 powerLimit, bool test) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_4k *pEepData = &ah->eeprom.map4k; struct modal_eep_4k_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; u8 ht40PowerIncForPdadc = 2; int i; @@ -594,14 +673,12 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, ath9k_hw_set_4k_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, twiceAntennaReduction, - twiceMaxRegulatoryPower, powerLimit); - ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset); + ath9k_hw_set_4k_power_cal_table(ah, chan); regulatory->max_power_level = 0; for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); if (ratesArray[i] > MAX_RATE_POWER) ratesArray[i] = MAX_RATE_POWER; @@ -612,19 +689,8 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, if (test) return; - /* Update regulatory */ - i = rate6mb; - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - regulatory->max_power_level = ratesArray[i]; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; - } + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2; ENABLE_REGWRITE_BUFFER(ah); @@ -694,28 +760,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah, REGWRITE_BUFFER_FLUSH(ah); } -static void ath9k_hw_4k_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - struct modal_eep_4k_header *pModal; - struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; - u8 biaslevel; - - if (ah->hw_version.macVersion != AR_SREV_VERSION_9160) - return; - - if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &eep->modalHeader; - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - INI_RA(&ah->iniAddac, 7, 1) = - (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; - } -} - static void ath9k_hw_4k_set_gain(struct ath_hw *ah, struct modal_eep_4k_header *pModal, struct ar5416_eeprom_4k *eep, @@ -783,6 +827,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, u8 txRxAttenLocal; u8 ob[5], db1[5], db2[5]; u8 ant_div_control1, ant_div_control2; + u8 bb_desired_scale; u32 regVal; pModal = &eep->modalHeader; @@ -1002,30 +1047,29 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah, AR_PHY_SETTLING_SWITCH, pModal->swSettleHt40); } - if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) { - u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna & - EEP_4K_BB_DESIRED_SCALE_MASK); - if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) { - u32 pwrctrl, mask, clr; - - mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25); - pwrctrl = mask * bb_desired_scale; - clr = mask * 0x1f; - 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); - - mask = BIT(0)|BIT(5)|BIT(15); - pwrctrl = mask * bb_desired_scale; - clr = mask * 0x1f; - REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr); - - mask = BIT(0)|BIT(5); - pwrctrl = mask * bb_desired_scale; - clr = mask * 0x1f; - REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); - REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); - } + + bb_desired_scale = (pModal->bb_scale_smrt_antenna & + EEP_4K_BB_DESIRED_SCALE_MASK); + if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) { + u32 pwrctrl, mask, clr; + + mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + 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); + + mask = BIT(0)|BIT(5)|BIT(15); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr); + + mask = BIT(0)|BIT(5); + pwrctrl = mask * bb_desired_scale; + clr = mask * 0x1f; + REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr); + REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr); } } @@ -1063,10 +1107,10 @@ const struct eeprom_ops eep_4k_ops = { .check_eeprom = ath9k_hw_4k_check_eeprom, .get_eeprom = ath9k_hw_4k_get_eeprom, .fill_eeprom = ath9k_hw_4k_fill_eeprom, + .dump_eeprom = ath9k_hw_4k_dump_eeprom, .get_eeprom_ver = ath9k_hw_4k_get_eeprom_ver, .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, .set_board_values = ath9k_hw_4k_set_board_values, - .set_addac = ath9k_hw_4k_set_addac, .set_txpower = ath9k_hw_4k_set_txpower, .get_spur_channel = ath9k_hw_4k_get_spur_channel }; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c index d6f6b192f450..4f5c50a87ce3 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c @@ -76,6 +76,111 @@ 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) +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. Gain", modal_hdr->antennaGainCh[0]); + PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); + PR_EEP("Switch Settle", modal_hdr->switchSettling); + PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]); + PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]); + PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]); + PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]); + PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); + PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff); + PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn); + PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); + PR_EEP("CCA Threshold)", modal_hdr->thresh62); + PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]); + PR_EEP("xpdGain", modal_hdr->xpdGain); + PR_EEP("External PD", modal_hdr->xpd); + PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]); + PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]); + PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]); + PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]); + PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap); + PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); + PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); + PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]); + PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]); + PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]); + PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]); + PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40); + PR_EEP("AR92x7 Version", modal_hdr->version); + PR_EEP("DriverBias1", modal_hdr->db1); + PR_EEP("DriverBias2", modal_hdr->db1); + PR_EEP("CCK OutputBias", modal_hdr->ob_cck); + PR_EEP("PSK OutputBias", modal_hdr->ob_psk); + PR_EEP("QAM OutputBias", modal_hdr->ob_qam); + PR_EEP("PAL_OFF OutputBias", modal_hdr->ob_pal_off); + + return len; +} + +static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, + u8 *buf, u32 len, u32 size) +{ + struct ar9287_eeprom *eep = &ah->eeprom.map9287; + struct base_eep_ar9287_header *pBase = &eep->baseEepHeader; + + if (!dump_base_hdr) { + len += snprintf(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("TX Mask", pBase->txMask); + PR_EEP("RX Mask", pBase->rxMask); + PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); + PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); + PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags & + AR5416_OPFLAGS_N_2G_HT20)); + PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags & + AR5416_OPFLAGS_N_2G_HT40)); + PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags & + 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("Power Table Offset", pBase->pwrTableOffset); + PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); + + len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", + pBase->macAddr); + +out: + if (len > size) + len = size; + + return len; +} +#else +static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, + u8 *buf, u32 len, u32 size) +{ + return 0; +} +#endif + + static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah) { u32 sum = 0, el, integer; @@ -203,8 +308,6 @@ static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah, return get_unaligned_be16(pBase->macAddr + 4); case EEP_REG_0: return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; case EEP_OP_CAP: return pBase->deviceCap; case EEP_OP_MODE: @@ -231,6 +334,9 @@ static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah, return pBase->tempSensSlopePalOn; else return 0; + case EEP_ANTENNA_GAIN_2G: + return max_t(u8, pModal->antennaGainCh[0], + pModal->antennaGainCh[1]); default: return 0; } @@ -307,8 +413,7 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah, } static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) + struct ath9k_channel *chan) { struct cal_data_per_freq_ar9287 *pRawDataset; struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop; @@ -444,16 +549,13 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah, REGWRITE_BUFFER_FLUSH(ah); } } - - *pTxPowerIndexOffset = 0; } static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, + u16 antenna_reduction, u16 powerLimit) { #define CMP_CTL \ @@ -467,12 +569,8 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); u16 twiceMaxEdgePower = MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, MAX_RATE_POWER }; int i; - int16_t twiceLargestAntenna; struct cal_ctl_data_ar9287 *rep; struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} }, targetPowerCck = {0, {0, 0, 0, 0} }; @@ -480,7 +578,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, targetPowerCckExt = {0, {0, 0, 0, 0} }; struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = {0, {0, 0, 0, 0} }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 scaledPower = 0, minCtlPower; static const u16 ctlModesFor11g[] = { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40 @@ -495,24 +593,7 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, tx_chainmask = ah->txchainmask; ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - /* Compute TxPower reduction due to Antenna Gain */ - twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0], - pEepData->modalHeader.antennaGainCh[1]); - twiceLargestAntenna = (int16_t)min((AntennaReduction) - - twiceLargestAntenna, 0); - - /* - * scaledPower is the minimum of the user input power level - * and the regulatory allowed power level. - */ - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) - maxRegAllowedPower -= - (tpScaleReductionTable[(regulatory->tp_scale)] * 2); - - scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = powerLimit - antenna_reduction; /* * Reduce scaled Power by number of chains active @@ -713,14 +794,12 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah, static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, u8 powerLimit, bool test) { struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar9287_eeprom *pEepData = &ah->eeprom.map9287; struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader; int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; u8 ht40PowerIncForPdadc = 2; int i; @@ -733,14 +812,12 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, ath9k_hw_set_ar9287_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, twiceAntennaReduction, - twiceMaxRegulatoryPower, powerLimit); - ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset); + ath9k_hw_set_ar9287_power_cal_table(ah, chan); regulatory->max_power_level = 0; for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); if (ratesArray[i] > MAX_RATE_POWER) ratesArray[i] = MAX_RATE_POWER; @@ -751,17 +828,8 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, if (test) return; - if (IS_CHAN_2GHZ(chan)) - i = rate1l; - else - i = rate6mb; - - regulatory->max_power_level = ratesArray[i]; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; - } + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2; ENABLE_REGWRITE_BUFFER(ah); @@ -851,11 +919,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah, REGWRITE_BUFFER_FLUSH(ah); } -static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah, - struct ath9k_channel *chan) -{ -} - static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -1003,10 +1066,10 @@ const struct eeprom_ops eep_ar9287_ops = { .check_eeprom = ath9k_hw_ar9287_check_eeprom, .get_eeprom = ath9k_hw_ar9287_get_eeprom, .fill_eeprom = ath9k_hw_ar9287_fill_eeprom, + .dump_eeprom = ath9k_hw_ar9287_dump_eeprom, .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver, .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev, .set_board_values = ath9k_hw_ar9287_set_board_values, - .set_addac = ath9k_hw_ar9287_set_addac, .set_txpower = ath9k_hw_ar9287_set_txpower, .get_spur_channel = ath9k_hw_ar9287_get_spur_channel }; diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c index b9540a992616..81e629671679 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom_def.c +++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c @@ -133,6 +133,136 @@ static bool ath9k_hw_def_fill_eeprom(struct ath_hw *ah) #undef SIZE_EEPROM_DEF +#if defined(CONFIG_ATH9K_DEBUGFS) || defined(CONFIG_ATH9K_HTC_DEBUGFS) +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. Gain", modal_hdr->antennaGainCh[0]); + PR_EEP("Chain1 Ant. Gain", modal_hdr->antennaGainCh[1]); + PR_EEP("Chain2 Ant. Gain", modal_hdr->antennaGainCh[2]); + PR_EEP("Switch Settle", modal_hdr->switchSettling); + PR_EEP("Chain0 TxRxAtten", modal_hdr->txRxAttenCh[0]); + PR_EEP("Chain1 TxRxAtten", modal_hdr->txRxAttenCh[1]); + PR_EEP("Chain2 TxRxAtten", modal_hdr->txRxAttenCh[2]); + PR_EEP("Chain0 RxTxMargin", modal_hdr->rxTxMarginCh[0]); + PR_EEP("Chain1 RxTxMargin", modal_hdr->rxTxMarginCh[1]); + PR_EEP("Chain2 RxTxMargin", modal_hdr->rxTxMarginCh[2]); + PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize); + PR_EEP("PGA Desired size", modal_hdr->pgaDesiredSize); + PR_EEP("Chain0 xlna Gain", modal_hdr->xlnaGainCh[0]); + PR_EEP("Chain1 xlna Gain", modal_hdr->xlnaGainCh[1]); + PR_EEP("Chain2 xlna Gain", modal_hdr->xlnaGainCh[2]); + PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff); + PR_EEP("txEndToRxOn", modal_hdr->txEndToRxOn); + PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn); + PR_EEP("CCA Threshold)", modal_hdr->thresh62); + PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]); + PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]); + PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]); + PR_EEP("xpdGain", modal_hdr->xpdGain); + PR_EEP("External PD", modal_hdr->xpd); + PR_EEP("Chain0 I Coefficient", modal_hdr->iqCalICh[0]); + PR_EEP("Chain1 I Coefficient", modal_hdr->iqCalICh[1]); + PR_EEP("Chain2 I Coefficient", modal_hdr->iqCalICh[2]); + PR_EEP("Chain0 Q Coefficient", modal_hdr->iqCalQCh[0]); + PR_EEP("Chain1 Q Coefficient", modal_hdr->iqCalQCh[1]); + PR_EEP("Chain2 Q Coefficient", modal_hdr->iqCalQCh[2]); + PR_EEP("pdGainOverlap", modal_hdr->pdGainOverlap); + PR_EEP("Chain0 OutputBias", modal_hdr->ob); + PR_EEP("Chain0 DriverBias", modal_hdr->db); + PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl); + PR_EEP("2chain pwr decrease", modal_hdr->pwrDecreaseFor2Chain); + PR_EEP("3chain pwr decrease", modal_hdr->pwrDecreaseFor3Chain); + PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart); + PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn); + PR_EEP("HT40 Power Inc.", modal_hdr->ht40PowerIncForPdadc); + PR_EEP("Chain0 bswAtten", modal_hdr->bswAtten[0]); + PR_EEP("Chain1 bswAtten", modal_hdr->bswAtten[1]); + PR_EEP("Chain2 bswAtten", modal_hdr->bswAtten[2]); + PR_EEP("Chain0 bswMargin", modal_hdr->bswMargin[0]); + PR_EEP("Chain1 bswMargin", modal_hdr->bswMargin[1]); + PR_EEP("Chain2 bswMargin", modal_hdr->bswMargin[2]); + PR_EEP("HT40 Switch Settle", modal_hdr->swSettleHt40); + PR_EEP("Chain0 xatten2Db", modal_hdr->xatten2Db[0]); + PR_EEP("Chain1 xatten2Db", modal_hdr->xatten2Db[1]); + PR_EEP("Chain2 xatten2Db", modal_hdr->xatten2Db[2]); + PR_EEP("Chain0 xatten2Margin", modal_hdr->xatten2Margin[0]); + PR_EEP("Chain1 xatten2Margin", modal_hdr->xatten2Margin[1]); + PR_EEP("Chain2 xatten2Margin", modal_hdr->xatten2Margin[2]); + 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]); + + return len; +} + +static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, + u8 *buf, u32 len, u32 size) +{ + struct ar5416_eeprom_def *eep = &ah->eeprom.def; + struct base_eep_header *pBase = &eep->baseEepHeader; + + if (!dump_base_hdr) { + len += snprintf(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 += 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("TX Mask", pBase->txMask); + PR_EEP("RX Mask", pBase->rxMask); + PR_EEP("Allow 5GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11A)); + PR_EEP("Allow 2GHz", !!(pBase->opCapFlags & AR5416_OPFLAGS_11G)); + PR_EEP("Disable 2GHz HT20", !!(pBase->opCapFlags & + AR5416_OPFLAGS_N_2G_HT20)); + PR_EEP("Disable 2GHz HT40", !!(pBase->opCapFlags & + AR5416_OPFLAGS_N_2G_HT40)); + PR_EEP("Disable 5Ghz HT20", !!(pBase->opCapFlags & + 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("OpenLoop Power Ctrl", pBase->openLoopPwrCntl); + + len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress", + pBase->macAddr); + +out: + if (len > size) + len = size; + + return len; +} +#else +static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr, + u8 *buf, u32 len, u32 size) +{ + return 0; +} +#endif + + static int ath9k_hw_def_check_eeprom(struct ath_hw *ah) { struct ar5416_eeprom_def *eep = @@ -270,6 +400,7 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, struct ar5416_eeprom_def *eep = &ah->eeprom.def; struct modal_eep_header *pModal = eep->modalHeader; struct base_eep_header *pBase = &eep->baseEepHeader; + int band = 0; switch (param) { case EEP_NFTHRESH_5: @@ -284,8 +415,6 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, return get_unaligned_be16(pBase->macAddr + 4); case EEP_REG_0: return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; case EEP_OP_CAP: return pBase->deviceCap; case EEP_OP_MODE: @@ -337,6 +466,14 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah, return pBase->pwr_table_offset; else return AR5416_PWR_TABLE_OFFSET_DB; + case EEP_ANTENNA_GAIN_2G: + band = 1; + /* fall through */ + case EEP_ANTENNA_GAIN_5G: + return max_t(u8, max_t(u8, + pModal[band].antennaGainCh[0], + pModal[band].antennaGainCh[1]), + pModal[band].antennaGainCh[2]); default: return 0; } @@ -417,8 +554,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, break; } - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) + if ((ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) regChainOffset = (i == 1) ? 0x2000 : 0x1000; else regChainOffset = i * 0x1000; @@ -435,9 +571,8 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah, SM(pModal->iqCalQCh[i], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) - ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, - regChainOffset, i); + ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal, + regChainOffset, i); } if (AR_SREV_9280_20_OR_LATER(ah)) { @@ -693,8 +828,7 @@ static void ath9k_adjust_pdadc_values(struct ath_hw *ah, } static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) + struct ath9k_channel *chan) { #define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x) #define SM_PDGAIN_B(x, y) \ @@ -764,8 +898,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, xpdGainValues[2]); for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_20_OR_LATER(ah) && - (ah->rxchainmask == 5 || ah->txchainmask == 5) && + if ((ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0)) { regChainOffset = (i == 1) ? 0x2000 : 0x1000; } else @@ -806,27 +939,24 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, ENABLE_REGWRITE_BUFFER(ah); - if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) { - if (OLC_FOR_AR9280_20_LATER) { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(0x6, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | - SM_PD_GAIN(1) | SM_PD_GAIN(2) | - SM_PD_GAIN(3) | SM_PD_GAIN(4)); - } else { - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| - SM_PDGAIN_B(0, 1) | - SM_PDGAIN_B(1, 2) | - SM_PDGAIN_B(2, 3) | - SM_PDGAIN_B(3, 4)); - } + if (OLC_FOR_AR9280_20_LATER) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(0x6, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) | + SM_PD_GAIN(1) | SM_PD_GAIN(2) | + SM_PD_GAIN(3) | SM_PD_GAIN(4)); + } else { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)| + SM_PDGAIN_B(0, 1) | + SM_PDGAIN_B(1, 2) | + SM_PDGAIN_B(2, 3) | + SM_PDGAIN_B(3, 4)); } - ath9k_adjust_pdadc_values(ah, pwr_table_offset, diff, pdadcValues); @@ -855,7 +985,6 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah, } } - *pTxPowerIndexOffset = 0; #undef SM_PD_GAIN #undef SM_PDGAIN_B } @@ -864,21 +993,15 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl, - u16 AntennaReduction, - u16 twiceMaxRegulatoryPower, + u16 antenna_reduction, u16 powerLimit) { #define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ #define REDUCE_SCALED_POWER_BY_THREE_CHAIN 9 /* 10*log10(3)*2 */ - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ar5416_eeprom_def *pEepData = &ah->eeprom.def; u16 twiceMaxEdgePower = MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, MAX_RATE_POWER }; - int i; - int16_t twiceLargestAntenna; struct cal_ctl_data *rep; struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { 0, { 0, 0, 0, 0} @@ -890,7 +1013,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { 0, {0, 0, 0, 0} }; - u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 scaledPower = 0, minCtlPower; static const u16 ctlModesFor11a[] = { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; @@ -909,27 +1032,7 @@ static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah, ath9k_hw_get_channel_centers(ah, chan, ¢ers); - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); - - twiceLargestAntenna = max((u8)twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - - twiceLargestAntenna = (int16_t)min(AntennaReduction - - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(regulatory->tp_scale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = powerLimit - antenna_reduction; switch (ar5416_get_ntxchains(tx_chainmask)) { case 1: @@ -1134,7 +1237,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, struct ath9k_channel *chan, u16 cfgCtl, u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, u8 powerLimit, bool test) { #define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta) @@ -1143,7 +1245,6 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, struct modal_eep_header *pModal = &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; u8 ht40PowerIncForPdadc = 2; int i, cck_ofdm_delta = 0; @@ -1157,31 +1258,18 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah, ath9k_hw_set_def_power_per_rate_table(ah, chan, &ratesArray[0], cfgCtl, twiceAntennaReduction, - twiceMaxRegulatoryPower, powerLimit); - ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset); + ath9k_hw_set_def_power_cal_table(ah, chan); regulatory->max_power_level = 0; for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); if (ratesArray[i] > MAX_RATE_POWER) ratesArray[i] = MAX_RATE_POWER; if (ratesArray[i] > regulatory->max_power_level) regulatory->max_power_level = ratesArray[i]; } - if (!test) { - i = rate6mb; - - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - regulatory->max_power_level = ratesArray[i]; - } - switch(ar5416_get_ntxchains(ah->txchainmask)) { case 1: break; @@ -1336,6 +1424,7 @@ const struct eeprom_ops eep_def_ops = { .check_eeprom = ath9k_hw_def_check_eeprom, .get_eeprom = ath9k_hw_def_get_eeprom, .fill_eeprom = ath9k_hw_def_fill_eeprom, + .dump_eeprom = ath9k_hw_def_dump_eeprom, .get_eeprom_ver = ath9k_hw_def_get_eeprom_ver, .get_eeprom_rev = ath9k_hw_def_get_eeprom_rev, .set_board_values = ath9k_hw_def_set_board_values, diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index bc713fc28191..655576c8fdab 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -48,6 +48,8 @@ void ath_init_leds(struct ath_softc *sc) sc->sc_ah->led_pin = ATH_LED_PIN_9485; else if (AR_SREV_9300(sc->sc_ah)) sc->sc_ah->led_pin = ATH_LED_PIN_9300; + else if (AR_SREV_9462(sc->sc_ah)) + sc->sc_ah->led_pin = ATH_LED_PIN_9462; else sc->sc_ah->led_pin = ATH_LED_PIN_DEF; } @@ -82,9 +84,14 @@ void ath_init_leds(struct ath_softc *sc) static bool ath_is_rfkill_set(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; + bool is_blocked; - return ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == + ath9k_ps_wakeup(sc); + is_blocked = ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == ah->rfkill_polarity; + ath9k_ps_restore(sc); + + return is_blocked; } void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) @@ -148,7 +155,8 @@ static void ath9k_gen_timer_start(struct ath_hw *ah, if ((ah->imask & ATH9K_INT_GENTIMER) == 0) { ath9k_hw_disable_interrupts(ah); ah->imask |= ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); } } @@ -162,7 +170,8 @@ static void ath9k_gen_timer_stop(struct ath_hw *ah, struct ath_gen_timer *timer) if (timer_table->timer_mask.val == 0) { ath9k_hw_disable_interrupts(ah); ah->imask &= ~ATH9K_INT_GENTIMER; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); } } diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index d3f4a59cd456..77c8ded8de57 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -38,6 +38,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ { USB_DEVICE(0x040D, 0x3801) }, /* VIA */ { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */ + { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */ { USB_DEVICE(0x0cf3, 0x7015), .driver_info = AR9287_USB }, /* Atheros */ diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 5bc022087e65..da5596766d82 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -521,8 +521,6 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb, int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv, u8 enable_coex); -void ath9k_htc_station_work(struct work_struct *work); -void ath9k_htc_aggr_work(struct work_struct *work); void ath9k_htc_ani_work(struct work_struct *work); void ath9k_htc_start_ani(struct ath9k_htc_priv *priv); void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv); @@ -542,7 +540,6 @@ 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_htc_tx_failed(struct ath9k_htc_priv *priv); void ath9k_tx_failed_tasklet(unsigned long data); void ath9k_htc_tx_cleanup_timer(unsigned long data); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index db2352e5cc0d..e3a02eb8e0cc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -228,8 +228,14 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv) static bool ath_is_rfkill_set(struct ath9k_htc_priv *priv) { - return ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == - priv->ah->rfkill_polarity; + bool is_blocked; + + ath9k_htc_ps_wakeup(priv); + is_blocked = ath9k_hw_gpio_get(priv->ah, priv->ah->rfkill_gpio) == + priv->ah->rfkill_polarity; + ath9k_htc_ps_restore(priv); + + return is_blocked; } void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 3bea7ea86f0a..966661c9e586 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -509,8 +509,8 @@ static void setup_ht_cap(struct ath9k_htc_priv *priv, memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); /* ath9k_htc supports only 1 or 2 stream devices */ - tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2); - rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2); + tx_streams = ath9k_cmn_count_streams(priv->ah->txchainmask, 2); + rx_streams = ath9k_cmn_count_streams(priv->ah->rxchainmask, 2); ath_dbg(common, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", @@ -572,25 +572,6 @@ err: return -EINVAL; } -static void ath9k_init_crypto(struct ath9k_htc_priv *priv) -{ - struct ath_common *common = ath9k_hw_common(priv->ah); - int i = 0; - - /* Get the hardware key cache size. */ - common->keymax = AR_KEYTABLE_SIZE; - - if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) - common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; - - /* - * Reset the key cache since some parts do not - * reset the contents on initial power up. - */ - for (i = 0; i < common->keymax; i++) - ath_hw_keyreset(common, (u16) i); -} - static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv) { if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) { @@ -620,9 +601,6 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - common->tx_chainmask = priv->ah->caps.tx_chainmask; - common->rx_chainmask = priv->ah->caps.rx_chainmask; - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); priv->ah->opmode = NL80211_IFTYPE_STATION; @@ -666,7 +644,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, return -ENOMEM; ah->hw_version.devid = devid; - ah->hw_version.subsysid = 0; /* FIXME */ ah->hw_version.usbdev = drv_info; ah->ah_flags |= AH_USE_EEPROM; ah->reg_ops.read = ath9k_regread; @@ -721,7 +698,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) priv->cur_beacon_conf.bslot[i] = NULL; - ath9k_init_crypto(priv); + ath9k_cmn_init_crypto(ah); ath9k_init_channels_rates(priv); ath9k_init_misc(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 7212acb2bd6c..0b9a0e8a4958 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -826,8 +826,7 @@ void ath9k_htc_ani_work(struct work_struct *work) if (longcal || shortcal) common->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, - common->rx_chainmask, - longcal); + ah->rxchainmask, longcal); ath9k_htc_ps_restore(priv); } @@ -1300,6 +1299,7 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, if (priv->op_flags & OP_INVALID) { ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_ANY, "Unable to configure filter on invalid state\n"); + mutex_unlock(&priv->mutex); return; } ath9k_htc_ps_wakeup(priv); @@ -1352,7 +1352,8 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw, return ret; } -static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath9k_htc_priv *priv = hw->priv; @@ -1563,7 +1564,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } -static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) +static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath9k_htc_priv *priv = hw->priv; u64 tsf; @@ -1577,7 +1579,8 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) { struct ath9k_htc_priv *priv = hw->priv; @@ -1588,7 +1591,8 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf) mutex_unlock(&priv->mutex); } -static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw) +static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath9k_htc_priv *priv = hw->priv; @@ -1736,6 +1740,22 @@ out: return ret; } + +static int ath9k_htc_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct ath9k_htc_priv *priv = hw->priv; + struct ath_hw *ah = priv->ah; + struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats; + + stats->dot11ACKFailureCount = mib_stats->ackrcv_bad; + stats->dot11RTSFailureCount = mib_stats->rts_bad; + stats->dot11FCSErrorCount = mib_stats->fcs_bad; + stats->dot11RTSSuccessCount = mib_stats->rts_good; + + return 0; +} + struct ieee80211_ops ath9k_htc_ops = { .tx = ath9k_htc_tx, .start = ath9k_htc_start, @@ -1759,4 +1779,5 @@ struct ieee80211_ops ath9k_htc_ops = { .rfkill_poll = ath9k_htc_rfkill_poll_state, .set_coverage_class = ath9k_htc_set_coverage_class, .set_bitrate_mask = ath9k_htc_set_bitrate_mask, + .get_stats = ath9k_htc_get_stats, }; diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index cb29e8875386..e74c233757a2 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -22,10 +22,12 @@ /* Hardware core and driver accessible callbacks */ static inline void ath9k_hw_configpcipowersave(struct ath_hw *ah, - int restore, - int power_off) + bool power_off) { - ath9k_hw_ops(ah)->config_pci_powersave(ah, restore, power_off); + if (ah->aspm_enabled != true) + return; + + ath9k_hw_ops(ah)->config_pci_powersave(ah, power_off); } static inline void ath9k_hw_rxena(struct ath_hw *ah) @@ -52,13 +54,10 @@ static inline bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked) return ath9k_hw_ops(ah)->get_isr(ah, masked); } -static inline void ath9k_hw_filltxdesc(struct ath_hw *ah, void *ds, u32 seglen, - bool is_firstseg, bool is_lastseg, - const void *ds0, dma_addr_t buf_addr, - unsigned int qcu) +static inline void ath9k_hw_set_txdesc(struct ath_hw *ah, void *ds, + struct ath_tx_info *i) { - ath9k_hw_ops(ah)->fill_txdesc(ah, ds, seglen, is_firstseg, is_lastseg, - ds0, buf_addr, qcu); + return ath9k_hw_ops(ah)->set_txdesc(ah, ds, i); } static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds, @@ -67,55 +66,6 @@ static inline int ath9k_hw_txprocdesc(struct ath_hw *ah, void *ds, return ath9k_hw_ops(ah)->proc_txdesc(ah, ds, ts); } -static inline void ath9k_hw_set11n_txdesc(struct ath_hw *ah, void *ds, - u32 pktLen, enum ath9k_pkt_type type, - u32 txPower, u32 keyIx, - enum ath9k_key_type keyType, - u32 flags) -{ - ath9k_hw_ops(ah)->set11n_txdesc(ah, ds, pktLen, type, txPower, keyIx, - keyType, flags); -} - -static inline void ath9k_hw_set11n_ratescenario(struct ath_hw *ah, void *ds, - void *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags) -{ - ath9k_hw_ops(ah)->set11n_ratescenario(ah, ds, lastds, durUpdateEn, - rtsctsRate, rtsctsDuration, series, - nseries, flags); -} - -static inline void ath9k_hw_set11n_aggr_first(struct ath_hw *ah, void *ds, - u32 aggrLen) -{ - ath9k_hw_ops(ah)->set11n_aggr_first(ah, ds, aggrLen); -} - -static inline void ath9k_hw_set11n_aggr_middle(struct ath_hw *ah, void *ds, - u32 numDelims) -{ - ath9k_hw_ops(ah)->set11n_aggr_middle(ah, ds, numDelims); -} - -static inline void ath9k_hw_set11n_aggr_last(struct ath_hw *ah, void *ds) -{ - ath9k_hw_ops(ah)->set11n_aggr_last(ah, ds); -} - -static inline void ath9k_hw_clr11n_aggr(struct ath_hw *ah, void *ds) -{ - ath9k_hw_ops(ah)->clr11n_aggr(ah, ds); -} - -static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val) -{ - ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val); -} - static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf) { @@ -231,11 +181,6 @@ static inline void ath9k_hw_restore_chainmask(struct ath_hw *ah) return ath9k_hw_private_ops(ah)->restore_chainmask(ah); } -static inline void ath9k_hw_set_diversity(struct ath_hw *ah, bool value) -{ - return ath9k_hw_private_ops(ah)->set_diversity(ah, value); -} - static inline bool ath9k_hw_ani_control(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param) { @@ -260,4 +205,11 @@ static inline void ath9k_hw_setup_calibration(struct ath_hw *ah, ath9k_hw_private_ops(ah)->setup_calibration(ah, currCal); } +static inline int ath9k_hw_fast_chan_change(struct ath_hw *ah, + struct ath9k_channel *chan, + u8 *ini_reloaded) +{ + return ath9k_hw_private_ops(ah)->fast_chan_change(ah, chan, + ini_reloaded); +} #endif /* ATH9K_HW_OPS_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 8dcefe74f4c3..f16d2033081f 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -284,7 +284,12 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) ah->hw_version.macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); - ah->is_pciexpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; + + if (AR_SREV_9462(ah)) + ah->is_pciexpress = true; + else + ah->is_pciexpress = (val & + AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; } else { if (!AR_SREV_9100(ah)) ah->hw_version.macVersion = MS(val, AR_SREV_VERSION); @@ -428,7 +433,6 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) regulatory->country_code = CTRY_DEFAULT; regulatory->power_limit = MAX_RATE_POWER; - regulatory->tp_scale = ATH9K_TP_SCALE_MAX; ah->hw_version.magic = AR5416_MAGIC; ah->hw_version.subvendorid = 0; @@ -440,7 +444,7 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) if (AR_SREV_9100(ah)) ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; ah->enable_32kHz_clock = DONT_USE_32KHZ; - ah->slottime = 20; + ah->slottime = ATH9K_SLOT_TIME_9; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; } @@ -537,6 +541,9 @@ static int __ath9k_hw_init(struct ath_hw *ah) return -EIO; } + if (AR_SREV_9462(ah)) + ah->WARegVal &= ~AR_WA_D3_L1_DISABLE; + ath9k_hw_init_defaults(ah); ath9k_hw_init_config(ah); @@ -580,6 +587,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) case AR_SREV_VERSION_9330: case AR_SREV_VERSION_9485: case AR_SREV_VERSION_9340: + case AR_SREV_VERSION_9462: break; default: ath_err(common, @@ -603,10 +611,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) ath9k_hw_init_mode_regs(ah); - - if (ah->is_pciexpress) - ath9k_hw_aspm_init(ah); - else + if (!ah->is_pciexpress) ath9k_hw_disablepcie(ah); if (!AR_SREV_9300_20_OR_LATER(ah)) @@ -621,6 +626,9 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (r) return r; + if (ah->is_pciexpress) + ath9k_hw_aspm_init(ah); + r = ath9k_hw_init_macaddr(ah); if (r) { ath_err(common, "Failed to initialize MAC address\n"); @@ -663,6 +671,8 @@ int ath9k_hw_init(struct ath_hw *ah) case AR9300_DEVID_AR9485_PCIE: case AR9300_DEVID_AR9330: case AR9300_DEVID_AR9340: + case AR9300_DEVID_AR9580: + case AR9300_DEVID_AR9462: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) @@ -959,7 +969,7 @@ 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; + int acktimeout, ctstimeout; int slottime; int sifstime; int rx_lat = 0, tx_lat = 0, eifs = 0; @@ -974,7 +984,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) if (ah->misc_mode != 0) REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode); - rx_lat = 37; + if (IS_CHAN_A_FAST_CLOCK(ah, chan)) + rx_lat = 41; + else + rx_lat = 37; tx_lat = 54; if (IS_CHAN_HALF_RATE(chan)) { @@ -988,7 +1001,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) sifstime = 32; } else if (IS_CHAN_QUARTER_RATE(chan)) { eifs = 340; - rx_lat *= 4; + rx_lat = (rx_lat * 4) - 1; tx_lat *= 4; if (IS_CHAN_A_FAST_CLOCK(ah, chan)) tx_lat += 22; @@ -996,8 +1009,14 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) slottime = 21; sifstime = 64; } else { - eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS); - reg = REG_READ(ah, AR_USEC); + if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) { + eifs = AR_D_GBL_IFS_EIFS_ASYNC_FIFO; + reg = AR_USEC_ASYNC_FIFO; + } else { + eifs = REG_READ(ah, AR_D_GBL_IFS_EIFS)/ + common->clockrate; + reg = REG_READ(ah, AR_USEC); + } rx_lat = MS(reg, AR_USEC_RX_LAT); tx_lat = MS(reg, AR_USEC_TX_LAT); @@ -1010,6 +1029,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) /* As defined by IEEE 802.11-2007 17.3.8.6 */ acktimeout = slottime + sifstime + 3 * ah->coverage_class; + ctstimeout = acktimeout; /* * Workaround for early ACK timeouts, add an offset to match the @@ -1024,7 +1044,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ath9k_hw_set_sifs_time(ah, sifstime); ath9k_hw_setslottime(ah, slottime); ath9k_hw_set_ack_timeout(ah, acktimeout); - ath9k_hw_set_cts_timeout(ah, acktimeout); + ath9k_hw_set_cts_timeout(ah, ctstimeout); if (ah->globaltxtimeout != (u32) -1) ath9k_hw_set_global_txtimeout(ah, ah->globaltxtimeout); @@ -1329,6 +1349,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah) static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type) { + if (AR_SREV_9300_20_OR_LATER(ah)) { REG_WRITE(ah, AR_WA, ah->WARegVal); udelay(10); @@ -1370,11 +1391,17 @@ static bool ath9k_hw_chip_reset(struct ath_hw *ah, static bool ath9k_hw_channel_change(struct ath_hw *ah, struct ath9k_channel *chan) { - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_channel *channel = chan->chan; 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); for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { @@ -1389,6 +1416,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return false; } + if (edma && (band_switch || mode_diff)) { + ath9k_hw_mark_phy_inactive(ah); + udelay(5); + + ath9k_hw_init_pll(ah, NULL); + + if (ath9k_hw_fast_chan_change(ah, chan, &ini_reloaded)) { + ath_err(common, "Failed to do fast channel change\n"); + return false; + } + } + ath9k_hw_set_channel_regs(ah, chan); r = ath9k_hw_rf_set_freq(ah, chan); @@ -1397,14 +1436,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, return false; } ath9k_hw_set_clockrate(ah); - - ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit), false); - + ath9k_hw_apply_txpower(ah, chan); ath9k_hw_rfbus_done(ah); if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan)) @@ -1412,6 +1444,18 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah, 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); + + ath9k_hw_init_bb(ah, chan); + + if (band_switch || ini_reloaded) + ath9k_hw_init_cal(ah, chan); + ah->ah_flags &= ~AH_FASTCC; + } + return true; } @@ -1467,9 +1511,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, u32 macStaId1; u64 tsf = 0; int i, r; - - ah->txchainmask = common->tx_chainmask; - ah->rxchainmask = common->rx_chainmask; + bool allow_fbs = false; if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) return -EIO; @@ -1486,15 +1528,24 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, memset(caldata, 0, sizeof(*caldata)); ath9k_init_nfcal_hist_buffer(ah, chan); } + ah->noise = ath9k_hw_getchan_noise(ah, chan); + + if (AR_SREV_9280(ah) && common->bus_ops->ath_bus_type == ATH_PCI) + bChannelChange = false; + + if (caldata && + caldata->done_txiqcal_once && + caldata->done_txclcal_once && + caldata->rtt_hist.num_readings) + allow_fbs = true; if (bChannelChange && (ah->chip_fullsleep != true) && (ah->curchan != NULL) && (chan->channel != ah->curchan->channel) && - ((chan->channelFlags & CHANNEL_ALL) == - (ah->curchan->channelFlags & CHANNEL_ALL)) && - (!AR_SREV_9280(ah) || AR_DEVID_7010(ah))) { - + (allow_fbs || + ((chan->channelFlags & CHANNEL_ALL) == + (ah->curchan->channelFlags & CHANNEL_ALL)))) { if (ath9k_hw_channel_change(ah, chan)) { ath9k_hw_loadnf(ah, ah->curchan); ath9k_hw_start_nfcal(ah, true); @@ -1665,6 +1716,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_init_bb(ah, chan); + if (caldata) { + caldata->done_txiqcal_once = false; + caldata->done_txclcal_once = false; + caldata->rtt_hist.num_readings = 0; + } if (!ath9k_hw_init_cal(ah, chan)) return -EIO; @@ -1734,25 +1790,40 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) { REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (setChip) { + if (AR_SREV_9462(ah)) { + REG_WRITE(ah, AR_TIMER_MODE, + REG_READ(ah, AR_TIMER_MODE) & 0xFFFFFF00); + REG_WRITE(ah, AR_NDP2_TIMER_MODE, REG_READ(ah, + AR_NDP2_TIMER_MODE) & 0xFFFFFF00); + REG_WRITE(ah, AR_SLP32_INC, + REG_READ(ah, AR_SLP32_INC) & 0xFFF00000); + /* xxx Required for WLAN only case ? */ + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, 0); + udelay(100); + } + /* * 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, AR_RTC_FORCE_WAKE_EN); + + if (AR_SREV_9462(ah)) + udelay(100); + if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah)) REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); /* Shutdown chip. Active low */ - if (!AR_SREV_5416(ah) && !AR_SREV_9271(ah)) - REG_CLR_BIT(ah, (AR_RTC_RESET), - AR_RTC_RESET_EN); + if (!AR_SREV_5416(ah) && + !AR_SREV_9271(ah) && !AR_SREV_9462_10(ah)) { + REG_CLR_BIT(ah, AR_RTC_RESET, AR_RTC_RESET_EN); + udelay(2); + } } /* Clear Bit 14 of AR_WA 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->WARegVal & ~AR_WA_D3_L1_DISABLE); } /* @@ -1762,6 +1833,8 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) */ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip) { + u32 val; + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); if (setChip) { struct ath9k_hw_capabilities *pCap = &ah->caps; @@ -1771,12 +1844,30 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah, int setChip) REG_WRITE(ah, AR_RTC_FORCE_WAKE, 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 + * 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 + * SYS_WAKING and SYS_SLEEPING messages which will make + * BT CPU to busy to process. + */ + if (AR_SREV_9462(ah)) { + val = REG_READ(ah, AR_MCI_INTERRUPT_RX_MSG_EN) & + ~AR_MCI_INTERRUPT_RX_HW_MSG_MASK; + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_EN, val); + } /* * 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); + + if (AR_SREV_9462(ah)) + udelay(30); } } @@ -2027,11 +2118,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0); regulatory->current_rd = eeval; - eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1); - if (AR_SREV_9285_12_OR_LATER(ah)) - eeval |= AR9285_RDEXT_DEFAULT; - regulatory->current_rd_ext = eeval; - if (ah->opmode != NL80211_IFTYPE_AP && ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) { if (regulatory->current_rd == 0x64 || @@ -2083,6 +2169,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->tx_chainmask = fixup_chainmask(chip_chainmask, pCap->tx_chainmask); pCap->rx_chainmask = fixup_chainmask(chip_chainmask, pCap->rx_chainmask); + ah->txchainmask = pCap->tx_chainmask; + ah->rxchainmask = pCap->rx_chainmask; ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA; @@ -2101,6 +2189,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *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)) @@ -2233,6 +2325,14 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) rx_chainmask >>= 1; } + if (AR_SREV_9300_20_OR_LATER(ah)) { + ah->enabled_cals |= TX_IQ_CAL; + if (!AR_SREV_9330(ah)) + ah->enabled_cals |= TX_IQ_ON_AGC_CAL; + } + if (AR_SREV_9462(ah)) + pCap->hw_caps |= ATH9K_HW_CAP_RTT; + return 0; } @@ -2393,6 +2493,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits) ENABLE_REGWRITE_BUFFER(ah); + if (AR_SREV_9462(ah)) + bits |= ATH9K_RX_FILTER_CONTROL_WRAPPER; + REG_WRITE(ah, AR_RX_FILTER, bits); phybits = 0; @@ -2434,20 +2537,56 @@ bool ath9k_hw_disable(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_disable); +static int get_antenna_gain(struct ath_hw *ah, struct ath9k_channel *chan) +{ + enum eeprom_param gain_param; + + if (IS_CHAN_2GHZ(chan)) + gain_param = EEP_ANTENNA_GAIN_2G; + else + gain_param = EEP_ANTENNA_GAIN_5G; + + return ah->eep_ops->get_eeprom(ah, gain_param); +} + +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; + + if (!chan) + return; + + channel = chan->chan; + chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_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, false); +} + void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) { - struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah); + struct ath_regulatory *reg = ath9k_hw_regulatory(ah); struct ath9k_channel *chan = ah->curchan; struct ieee80211_channel *channel = chan->chan; - regulatory->power_limit = min(limit, (u32) MAX_RATE_POWER); + reg->power_limit = min_t(int, limit, MAX_RATE_POWER); + if (test) + channel->max_power = MAX_RATE_POWER / 2; - ah->eep_ops->set_txpower(ah, chan, - ath9k_regd_get_ctl(regulatory, chan), - channel->max_antenna_gain * 2, - channel->max_power * 2, - min((u32) MAX_RATE_POWER, - (u32) regulatory->power_limit), test); + ath9k_hw_apply_txpower(ah, chan); + + if (test) + channel->max_power = DIV_ROUND_UP(reg->max_power_level, 2); } EXPORT_SYMBOL(ath9k_hw_set_txpowerlimit); @@ -2646,6 +2785,20 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah, REG_SET_BIT(ah, gen_tmr_configuration[timer->index].mode_addr, gen_tmr_configuration[timer->index].mode_mask); + if (AR_SREV_9462(ah)) { + /* + * Starting from AR9462, each generic timer can select which tsf + * to use. But we still follow the old rule, 0 - 7 use tsf and + * 8 - 15 use tsf2. + */ + if ((timer->index < AR_GEN_TIMER_BANK_1_LEN)) + REG_CLR_BIT(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL, + (1 << timer->index)); + else + REG_SET_BIT(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL, + (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) | @@ -2749,7 +2902,9 @@ static struct { { AR_SREV_VERSION_9271, "9271" }, { AR_SREV_VERSION_9300, "9300" }, { AR_SREV_VERSION_9330, "9330" }, + { AR_SREV_VERSION_9340, "9340" }, { AR_SREV_VERSION_9485, "9485" }, + { AR_SREV_VERSION_9462, "9462" }, }; /* For devices with external radios */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c79889036ec4..f389b3c93cf3 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -45,6 +45,8 @@ #define AR9300_DEVID_PCIE 0x0030 #define AR9300_DEVID_AR9340 0x0031 #define AR9300_DEVID_AR9485_PCIE 0x0032 +#define AR9300_DEVID_AR9580 0x0033 +#define AR9300_DEVID_AR9462 0x0034 #define AR9300_DEVID_AR9330 0x0035 #define AR5416_AR9100_DEVID 0x000b @@ -93,6 +95,12 @@ (_ah)->reg_ops.write_flush((_ah)); \ } while (0) +#define PR_EEP(_s, _val) \ + do { \ + len += snprintf(buf + len, size - len, "%20s : %10d\n", \ + _s, (_val)); \ + } while (0) + #define SM(_v, _f) (((_v) << _f##_S) & _f) #define MS(_v, _f) (((_v) & _f) >> _f##_S) #define REG_RMW_FIELD(_a, _r, _f, _v) \ @@ -194,6 +202,7 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_2GHZ = BIT(13), ATH9K_HW_CAP_5GHZ = BIT(14), ATH9K_HW_CAP_APM = BIT(15), + ATH9K_HW_CAP_RTT = BIT(16), }; struct ath9k_hw_capabilities { @@ -329,6 +338,16 @@ enum ath9k_int { CHANNEL_HT40PLUS | \ CHANNEL_HT40MINUS) +#define MAX_RTT_TABLE_ENTRY 6 +#define RTT_HIST_MAX 3 +struct ath9k_rtt_hist { + u32 table[AR9300_MAX_CHAINS][RTT_HIST_MAX][MAX_RTT_TABLE_ENTRY]; + u8 num_readings; +}; + +#define MAX_IQCAL_MEASUREMENT 8 +#define MAX_CL_TAB_ENTRY 16 + struct ath9k_hw_cal_data { u16 channel; u32 channelFlags; @@ -338,9 +357,15 @@ struct ath9k_hw_cal_data { bool paprd_done; bool nfcal_pending; bool nfcal_interference; + bool done_txiqcal_once; + bool done_txclcal_once; u16 small_signal_gain[AR9300_MAX_CHAINS]; u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ]; + u32 num_measures[AR9300_MAX_CHAINS]; + int tx_corr_coeff[MAX_IQCAL_MEASUREMENT][AR9300_MAX_CHAINS]; + u32 tx_clcal[AR9300_MAX_CHAINS][MAX_CL_TAB_ENTRY]; struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; + struct ath9k_rtt_hist rtt_hist; }; struct ath9k_channel { @@ -382,14 +407,6 @@ enum ath9k_power_mode { ATH9K_PM_UNDEFINED }; -enum ath9k_tp_scale { - ATH9K_TP_SCALE_MAX = 0, - ATH9K_TP_SCALE_50, - ATH9K_TP_SCALE_25, - ATH9K_TP_SCALE_12, - ATH9K_TP_SCALE_MIN -}; - enum ser_reg_mode { SER_REG_MODE_OFF = 0, SER_REG_MODE_ON = 1, @@ -438,7 +455,6 @@ struct ath9k_hw_version { u16 phyRev; u16 analog5GhzRev; u16 analog2GhzRev; - u16 subsysid; enum ath_usb_dev usbdev; }; @@ -577,7 +593,6 @@ struct ath_hw_private_ops { bool (*rfbus_req)(struct ath_hw *ah); void (*rfbus_done)(struct ath_hw *ah); void (*restore_chainmask)(struct ath_hw *ah); - void (*set_diversity)(struct ath_hw *ah, bool value); u32 (*compute_pll_control)(struct ath_hw *ah, struct ath9k_channel *chan); bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd, @@ -585,6 +600,8 @@ struct ath_hw_private_ops { void (*do_getnf)(struct ath_hw *ah, int16_t nfarray[NUM_NF_READINGS]); void (*set_radar_params)(struct ath_hw *ah, struct ath_hw_radar_conf *conf); + int (*fast_chan_change)(struct ath_hw *ah, struct ath9k_channel *chan, + u8 *ini_reloaded); /* ANI */ void (*ani_cache_ini_regs)(struct ath_hw *ah); @@ -601,8 +618,7 @@ struct ath_hw_private_ops { */ struct ath_hw_ops { void (*config_pci_powersave)(struct ath_hw *ah, - int restore, - int power_off); + bool power_off); void (*rx_enable)(struct ath_hw *ah); void (*set_desc_link)(void *ds, u32 link); bool (*calibrate)(struct ath_hw *ah, @@ -610,30 +626,10 @@ struct ath_hw_ops { u8 rxchainmask, bool longcal); bool (*get_isr)(struct ath_hw *ah, enum ath9k_int *masked); - void (*fill_txdesc)(struct ath_hw *ah, void *ds, u32 seglen, - bool is_firstseg, bool is_is_lastseg, - const void *ds0, dma_addr_t buf_addr, - unsigned int qcu); + 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); - void (*set11n_txdesc)(struct ath_hw *ah, void *ds, - u32 pktLen, enum ath9k_pkt_type type, - u32 txPower, u32 keyIx, - enum ath9k_key_type keyType, - u32 flags); - void (*set11n_ratescenario)(struct ath_hw *ah, void *ds, - void *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags); - void (*set11n_aggr_first)(struct ath_hw *ah, void *ds, - u32 aggrLen); - void (*set11n_aggr_middle)(struct ath_hw *ah, void *ds, - u32 numDelims); - void (*set11n_aggr_last)(struct ath_hw *ah, void *ds); - void (*clr11n_aggr)(struct ath_hw *ah, void *ds); - void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val); void (*antdiv_comb_conf_get)(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf); void (*antdiv_comb_conf_set)(struct ath_hw *ah, @@ -647,9 +643,16 @@ struct ath_nf_limits { s16 nominal; }; +enum ath_cal_list { + TX_IQ_CAL = BIT(0), + TX_IQ_ON_AGC_CAL = BIT(1), + TX_CL_CAL = BIT(2), +}; + /* ah_flags */ #define AH_USE_EEPROM 0x1 #define AH_UNPLUGGED 0x2 /* The card has been physically removed. */ +#define AH_FASTCC 0x4 struct ath_hw { struct ath_ops reg_ops; @@ -690,6 +693,7 @@ struct ath_hw { enum nl80211_iftype opmode; enum ath9k_power_mode power_mode; + s8 noise; struct ath9k_hw_cal_data *caldata; struct ath9k_pacal_info pacal_info; struct ar5416Stats stats; @@ -703,8 +707,10 @@ struct ath_hw { u32 txdesc_interrupt_mask; u32 txeol_interrupt_mask; u32 txurn_interrupt_mask; + atomic_t intr_ref_cnt; bool chip_fullsleep; u32 atim_window; + u32 modes_index; /* Calibration */ u32 supp_cals; @@ -743,6 +749,7 @@ struct ath_hw { int32_t sign[AR5416_MAX_CHAINS]; } meas3; u16 cal_samples; + u8 enabled_cals; u32 sta_id1_defaults; u32 misc_mode; @@ -820,11 +827,14 @@ struct ath_hw { struct ar5416IniArray iniModes_9271_1_0_only; struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirJapan2484; + struct ar5416IniArray ini_japan2484; struct ar5416IniArray iniCommon_normal_cck_fir_coeff_9271; struct ar5416IniArray iniCommon_japan_2484_cck_fir_coeff_9271; struct ar5416IniArray iniModes_9271_ANI_reg; struct ar5416IniArray iniModes_high_power_tx_gain_9271; struct ar5416IniArray iniModes_normal_power_tx_gain_9271; + struct ar5416IniArray ini_radio_post_sys2ant; + struct ar5416IniArray ini_BTCOEX_MAX_TXPWR; struct ar5416IniArray iniMac[ATH_INI_NUM_SPLIT]; struct ar5416IniArray iniBB[ATH_INI_NUM_SPLIT]; @@ -978,6 +988,7 @@ void ath9k_hw_htc_resetinit(struct ath_hw *ah); /* PHY */ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled, u32 *coef_mantissa, u32 *coef_exponent); +void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan); /* * Code Specific to AR5008, AR9001 or AR9002, @@ -1030,10 +1041,6 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); -#define ATH_PCIE_CAP_LINK_CTRL 0x70 -#define ATH_PCIE_CAP_LINK_L0S 1 -#define ATH_PCIE_CAP_LINK_L1 2 - #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index aa0ff7e2c922..af1b32549531 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -270,8 +270,8 @@ static void setup_ht_cap(struct ath_softc *sc, /* set up supported mcs set */ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams); - rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams); + tx_streams = ath9k_cmn_count_streams(ah->txchainmask, max_streams); + rx_streams = ath9k_cmn_count_streams(ah->rxchainmask, max_streams); ath_dbg(common, ATH_DBG_CONFIG, "TX streams %d, RX streams: %d\n", @@ -404,31 +404,6 @@ fail: return error; } -void ath9k_init_crypto(struct ath_softc *sc) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - int i = 0; - - /* Get the hardware key cache size. */ - common->keymax = AR_KEYTABLE_SIZE; - - /* - * Reset the key cache since some parts do not - * reset the contents on initial power up. - */ - for (i = 0; i < common->keymax; i++) - ath_hw_keyreset(common, (u16) i); - - /* - * Check whether the separate key cache entries - * are required to handle both tx+rx MIC keys. - * With split mic keys the number of stations is limited - * to 27 otherwise 59. - */ - if (sc->sc_ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) - common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED; -} - static int ath9k_init_btcoex(struct ath_softc *sc) { struct ath_txq *txq; @@ -531,10 +506,6 @@ static void ath9k_init_misc(struct ath_softc *sc) sc->sc_flags |= SC_OP_RXAGGR; } - common->tx_chainmask = sc->sc_ah->caps.tx_chainmask; - common->rx_chainmask = sc->sc_ah->caps.rx_chainmask; - - ath9k_hw_set_diversity(sc->sc_ah, true); sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah); memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); @@ -548,7 +519,7 @@ static void ath9k_init_misc(struct ath_softc *sc) sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; } -static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, +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; @@ -563,10 +534,10 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, ah->hw = sc->hw; ah->hw_version.devid = devid; - ah->hw_version.subsysid = subsysid; ah->reg_ops.read = ath9k_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; if (!pdata) { @@ -597,6 +568,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, mutex_init(&sc->mutex); #ifdef CONFIG_ATH9K_DEBUGFS spin_lock_init(&sc->nodes_lock); + spin_lock_init(&sc->debug.samp_lock); INIT_LIST_HEAD(&sc->nodes); #endif tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); @@ -630,7 +602,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid, if (ret) goto err_btcoex; - ath9k_init_crypto(sc); + ath9k_cmn_init_crypto(sc->sc_ah); ath9k_init_misc(sc); return 0; @@ -654,7 +626,6 @@ 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_regulatory *reg = ath9k_hw_regulatory(ah); int i; sband = &sc->sbands[band]; @@ -663,17 +634,14 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band) 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); - chan->max_power = reg->max_power_level / 2; } } static void ath9k_init_txpower_limits(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_channel *curchan = ah->curchan; - ah->txchainmask = common->tx_chainmask; if (ah->caps.hw_caps & ATH9K_HW_CAP_2GHZ) ath9k_init_band_txpower(sc, IEEE80211_BAND_2GHZ); if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) @@ -682,9 +650,22 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) 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); +} + + void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + 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 | @@ -722,6 +703,16 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->sta_data_size = sizeof(struct ath_node); hw->vif_data_size = sizeof(struct ath_vif); + hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; + hw->wiphy->available_antennas_tx = BIT(ah->caps.max_txchains) - 1; + + /* single chain devices with rx diversity */ + if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) + hw->wiphy->available_antennas_rx = BIT(0) | BIT(1); + + sc->ant_rx = hw->wiphy->available_antennas_rx; + sc->ant_tx = hw->wiphy->available_antennas_tx; + #ifdef CONFIG_ATH9K_RATE_CONTROL hw->rate_control_algorithm = "ath9k_rate_control"; #endif @@ -733,17 +724,12 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &sc->sbands[IEEE80211_BAND_5GHZ]; - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { - 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); - } + ath9k_reload_chainmask_settings(sc); SET_IEEE80211_PERM_ADDR(hw, common->macaddr); } -int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, +int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { struct ieee80211_hw *hw = sc->hw; @@ -753,7 +739,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, struct ath_regulatory *reg; /* Bring up device */ - error = ath9k_init_softc(devid, sc, subsysid, bus_ops); + error = ath9k_init_softc(devid, sc, bus_ops); if (error != 0) goto error_init; @@ -806,6 +792,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid, goto error_world; } + 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); diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index b6b523a897e5..6a8fdf33a527 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -62,18 +62,6 @@ void ath9k_hw_txstart(struct ath_hw *ah, u32 q) } EXPORT_SYMBOL(ath9k_hw_txstart); -void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; -} -EXPORT_SYMBOL(ath9k_hw_cleartxdesc); - u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q) { u32 npend; @@ -345,21 +333,8 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, } memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); qi->tqi_type = type; - if (qinfo == NULL) { - qi->tqi_qflags = - TXQ_FLAG_TXOKINT_ENABLE - | TXQ_FLAG_TXERRINT_ENABLE - | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; - qi->tqi_aifs = INIT_AIFS; - qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; - qi->tqi_cwmax = INIT_CWMAX; - qi->tqi_shretry = INIT_SH_RETRY; - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_physCompBuf = 0; - } else { - qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; - (void) ath9k_hw_set_txq_props(ah, q, qinfo); - } + qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; + (void) ath9k_hw_set_txq_props(ah, q, qinfo); return q; } @@ -564,7 +539,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q) EXPORT_SYMBOL(ath9k_hw_resettxqueue); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - struct ath_rx_status *rs, u64 tsf) + struct ath_rx_status *rs) { struct ar5416_desc ads; struct ar5416_desc *adsp = AR5416DESC(ds); @@ -609,7 +584,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, else rs->rs_keyix = ATH9K_RXKEYIX_INVALID; - rs->rs_rate = RXSTATUS_RATE(ah, (&ads)); + rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate); rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; @@ -645,8 +620,8 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, rs->rs_status |= ATH9K_RXERR_DECRYPT; else if (ads.ds_rxstatus8 & AR_MichaelErr) rs->rs_status |= ATH9K_RXERR_MIC; - else if (ads.ds_rxstatus8 & AR_KeyMiss) - rs->rs_status |= ATH9K_RXERR_DECRYPT; + if (ads.ds_rxstatus8 & AR_KeyMiss) + rs->rs_status |= ATH9K_RXERR_KEYMISS; } return 0; @@ -800,6 +775,11 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); + if (!(ah->imask & ATH9K_INT_GLOBAL)) + atomic_set(&ah->intr_ref_cnt, -1); + else + atomic_dec(&ah->intr_ref_cnt); + ath_dbg(common, ATH_DBG_INTERRUPT, "disable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); @@ -821,6 +801,13 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) if (!(ah->imask & ATH9K_INT_GLOBAL)) return; + if (!atomic_inc_and_test(&ah->intr_ref_cnt)) { + ath_dbg(common, ATH_DBG_INTERRUPT, + "Do not enable IER ref count %d\n", + atomic_read(&ah->intr_ref_cnt)); + return; + } + if (AR_SREV_9340(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; @@ -840,9 +827,9 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_enable_interrupts); -void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) +void ath9k_hw_set_interrupts(struct ath_hw *ah) { - enum ath9k_int omask = ah->imask; + enum ath9k_int ints = ah->imask; u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); @@ -850,9 +837,8 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) if (!(ints & ATH9K_INT_GLOBAL)) ath9k_hw_disable_interrupts(ah); - ath_dbg(common, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); + ath_dbg(common, ATH_DBG_INTERRUPT, "New interrupt mask 0x%x\n", ints); - /* TODO: global int Ref count */ mask = ints & ATH9K_INT_COMMON; mask2 = 0; @@ -929,9 +915,6 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) REG_CLR_BIT(ah, AR_IMR_S5, AR_IMR_S5_TIM_TIMER); } - if (ints & ATH9K_INT_GLOBAL) - ath9k_hw_enable_interrupts(ah); - return; } EXPORT_SYMBOL(ath9k_hw_set_interrupts); diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 8e848c4d16ba..11dbd1473a13 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -17,10 +17,6 @@ #ifndef MAC_H #define MAC_H -#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ? \ - MS(ads->ds_rxstatus0, AR_RxRate) : \ - (ads->ds_rxstatus3 >> 2) & 0xFF) - #define set11nTries(_series, _index) \ (SM((_series)[_index].Tries, AR_XmitDataTries##_index)) @@ -79,9 +75,10 @@ #define ATH9K_TXERR_XTXOP 0x08 #define ATH9K_TXERR_TIMER_EXPIRED 0x10 #define ATH9K_TX_ACKED 0x20 +#define ATH9K_TX_FLUSH 0x40 #define ATH9K_TXERR_MASK \ (ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO | \ - ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED) + ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED | ATH9K_TX_FLUSH) #define ATH9K_TX_BA 0x01 #define ATH9K_TX_PWRMGMT 0x02 @@ -146,6 +143,7 @@ struct ath_rx_status { u8 rs_moreaggr; u8 rs_num_delims; u8 rs_flags; + bool is_mybeacon; u32 evm0; u32 evm1; u32 evm2; @@ -184,6 +182,7 @@ struct ath_htc_rx_status { #define ATH9K_RXERR_FIFO 0x04 #define ATH9K_RXERR_DECRYPT 0x08 #define ATH9K_RXERR_MIC 0x10 +#define ATH9K_RXERR_KEYMISS 0x20 #define ATH9K_RX_MORE 0x01 #define ATH9K_RX_MORE_AGGR 0x02 @@ -194,7 +193,7 @@ struct ath_htc_rx_status { #define ATH9K_RX_DECRYPT_BUSY 0x40 #define ATH9K_RXKEYIX_INVALID ((u8)-1) -#define ATH9K_TXKEYIX_INVALID ((u32)-1) +#define ATH9K_TXKEYIX_INVALID ((u8)-1) enum ath9k_phyerr { ATH9K_PHYERR_UNDERRUN = 0, /* Transmit underrun */ @@ -262,7 +261,11 @@ struct ath_desc { #define ATH9K_TXDESC_VMF 0x0100 #define ATH9K_TXDESC_FRAG_IS_ON 0x0200 #define ATH9K_TXDESC_LOWRXCHAIN 0x0400 -#define ATH9K_TXDESC_LDPC 0x00010000 +#define ATH9K_TXDESC_LDPC 0x0800 +#define ATH9K_TXDESC_CLRDMASK 0x1000 + +#define ATH9K_TXDESC_PAPRD 0x70000 +#define ATH9K_TXDESC_PAPRD_S 16 #define ATH9K_RXDESC_INTREQ 0x0020 @@ -643,6 +646,7 @@ enum ath9k_rx_filter { ATH9K_RX_FILTER_PSPOLL = 0x00004000, ATH9K_RX_FILTER_PHYRADAR = 0x00002000, ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, + ATH9K_RX_FILTER_CONTROL_WRAPPER = 0x00080000, }; #define ATH9K_RATESERIES_RTS_CTS 0x0001 @@ -658,6 +662,13 @@ struct ath9k_11n_rate_series { u32 RateFlags; }; +enum aggr_type { + AGGR_BUF_NONE, + AGGR_BUF_FIRST, + AGGR_BUF_MIDDLE, + AGGR_BUF_LAST, +}; + enum ath9k_key_type { ATH9K_KEY_TYPE_CLEAR, ATH9K_KEY_TYPE_WEP, @@ -665,6 +676,33 @@ enum ath9k_key_type { ATH9K_KEY_TYPE_TKIP, }; +struct ath_tx_info { + u8 qcu; + + bool is_first; + bool is_last; + + enum aggr_type aggr; + u8 ndelim; + u16 aggr_len; + + dma_addr_t link; + int pkt_len; + u32 flags; + + dma_addr_t buf_addr[4]; + int buf_len[4]; + + struct ath9k_11n_rate_series rates[4]; + u8 rtscts_rate; + bool dur_update; + + enum ath9k_pkt_type type; + enum ath9k_key_type keytype; + u8 keyix; + u8 txpower; +}; + struct ath_hw; struct ath9k_channel; enum ath9k_int; @@ -672,7 +710,6 @@ enum ath9k_int; u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); void ath9k_hw_txstart(struct ath_hw *ah, u32 q); -void ath9k_hw_cleartxdesc(struct ath_hw *ah, void *ds); u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); bool ath9k_hw_stop_dma_queue(struct ath_hw *ah, u32 q); @@ -687,7 +724,7 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type, bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q); bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q); int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds, - struct ath_rx_status *rs, u64 tsf); + struct ath_rx_status *rs); void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds, u32 size, u32 flags); bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set); @@ -699,7 +736,7 @@ int ath9k_hw_beaconq_setup(struct ath_hw *ah); /* Interrupt Handling */ bool ath9k_hw_intrpend(struct ath_hw *ah); -void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); +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); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 722967b86cf1..93fbe6f40898 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -111,24 +111,29 @@ void ath9k_ps_wakeup(struct ath_softc *sc) 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; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (--sc->ps_usecount != 0) goto unlock; - spin_lock(&common->cc_lock); - ath_hw_cycle_counters_update(common); - spin_unlock(&common->cc_lock); - if (sc->ps_idle) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP); + mode = ATH9K_PM_FULL_SLEEP; else if (sc->ps_enabled && !(sc->ps_flags & (PS_WAIT_FOR_BEACON | PS_WAIT_FOR_CAB | PS_WAIT_FOR_PSPOLL_DATA | PS_WAIT_FOR_TX_ACK))) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP); + mode = ATH9K_PM_NETWORK_SLEEP; + else + goto unlock; + + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); + spin_unlock(&common->cc_lock); + + ath9k_hw_setpower(sc->sc_ah, mode); unlock: spin_unlock_irqrestore(&sc->sc_pm_lock, flags); @@ -163,7 +168,7 @@ static void ath_update_survey_nf(struct ath_softc *sc, int channel) if (chan->noisefloor) { survey->filled |= SURVEY_INFO_NOISE_DBM; - survey->noise = chan->noisefloor; + survey->noise = ath9k_hw_getchan_noise(ah, chan); } } @@ -212,104 +217,168 @@ static int ath_update_survey_stats(struct ath_softc *sc) return ret; } -/* - * 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) +static void __ath_cancel_work(struct ath_softc *sc) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_conf *conf = &common->hw->conf; - bool fastcc = true, stopped; - struct ieee80211_channel *channel = hw->conf.channel; - struct ath9k_hw_cal_data *caldata = NULL; - int r; - - if (sc->sc_flags & SC_OP_INVALID) - return -EIO; - - sc->hw_busy_count = 0; - - del_timer_sync(&common->ani.timer); 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_pll_work); +} - ath9k_ps_wakeup(sc); +static void ath_cancel_work(struct ath_softc *sc) +{ + __ath_cancel_work(sc); + cancel_work_sync(&sc->hw_reset_work); +} - spin_lock_bh(&sc->sc_pcu_lock); +static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + bool ret; - /* - * This is only performed if the channel settings have - * actually changed. - * - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - ath9k_hw_disable_interrupts(ah); - stopped = ath_drain_all_txq(sc, false); + ieee80211_stop_queues(sc->hw); - if (!ath_stoprecv(sc)) - stopped = false; + sc->hw_busy_count = 0; + del_timer_sync(&common->ani.timer); - if (!ath9k_hw_check_alive(ah)) - stopped = false; + ath9k_debug_samp_bb_mac(sc); + ath9k_hw_disable_interrupts(ah); - /* XXX: do not flush receive queue here. We don't want - * to flush data frames already in queue because of - * changing channel. */ + ret = ath_drain_all_txq(sc, retry_tx); - if (!stopped || !(sc->sc_flags & SC_OP_OFFCHANNEL)) - fastcc = false; + if (!ath_stoprecv(sc)) + ret = false; - if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) - caldata = &sc->caldata; + if (!flush) { + if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) + ath_rx_tasklet(sc, 1, true); + ath_rx_tasklet(sc, 1, false); + } else { + ath_flushrecv(sc); + } - ath_dbg(common, ATH_DBG_CONFIG, - "(%u MHz) -> (%u MHz), conf_is_ht40: %d fastcc: %d\n", - sc->sc_ah->curchan->channel, - channel->center_freq, conf_is_ht40(conf), - fastcc); + return ret; +} - r = ath9k_hw_reset(ah, hchan, caldata, fastcc); - if (r) { - ath_err(common, - "Unable to reset channel (%u MHz), reset status %d\n", - channel->center_freq, r); - goto ps_restore; - } +static bool ath_complete_reset(struct ath_softc *sc, bool start) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); - r = -EIO; - goto ps_restore; + return false; } ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); - if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) { + if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) && start) { if (sc->sc_flags & SC_OP_BEACONS) ath_set_beacon(sc); + ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2); if (!common->disable_ani) ath_start_ani(common); } - ps_restore: - ieee80211_wake_queues(hw); + if (ath9k_hw_ops(ah)->antdiv_comb_conf_get && sc->ant_rx != 3) { + 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); + } + + ieee80211_wake_queues(sc->hw); + + return true; +} + +static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, + bool retry_tx) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_cal_data *caldata = NULL; + bool fastcc = true; + bool flush = false; + int r; + + __ath_cancel_work(sc); + + spin_lock_bh(&sc->sc_pcu_lock); + + if (!(sc->sc_flags & SC_OP_OFFCHANNEL)) { + fastcc = false; + caldata = &sc->caldata; + } + + if (!hchan) { + fastcc = false; + flush = true; + hchan = ah->curchan; + } + + if (fastcc && !ath9k_hw_check_alive(ah)) + fastcc = false; + + if (!ath_prepare_reset(sc, retry_tx, flush)) + fastcc = false; + ath_dbg(common, ATH_DBG_CONFIG, + "Reset to %u MHz, HT40: %d fastcc: %d\n", + hchan->channel, !!(hchan->channelFlags & (CHANNEL_HT40MINUS | + CHANNEL_HT40PLUS)), + fastcc); + + r = ath9k_hw_reset(ah, hchan, caldata, fastcc); + if (r) { + ath_err(common, + "Unable to reset channel, reset status %d\n", r); + goto out; + } + + if (!ath_complete_reset(sc, true)) + r = -EIO; + +out: spin_unlock_bh(&sc->sc_pcu_lock); + 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 (sc->sc_flags & SC_OP_INVALID) + return -EIO; + + ath9k_ps_wakeup(sc); + + r = ath_reset_internal(sc, hchan, false); ath9k_ps_restore(sc); + return r; } @@ -317,7 +386,6 @@ static void ath_paprd_activate(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_cal_data *caldata = ah->caldata; - struct ath_common *common = ath9k_hw_common(ah); int chain; if (!caldata || !caldata->paprd_done) @@ -326,7 +394,7 @@ static void ath_paprd_activate(struct ath_softc *sc) ath9k_ps_wakeup(sc); ar9003_paprd_enable(ah, false); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(common->tx_chainmask & BIT(chain))) + if (!(ah->txchainmask & BIT(chain))) continue; ar9003_paprd_populate_single_table(ah, caldata, chain); @@ -413,7 +481,7 @@ void ath_paprd_calibrate(struct work_struct *work) memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { - if (!(common->tx_chainmask & BIT(chain))) + if (!(ah->txchainmask & BIT(chain))) continue; chain_ok = 0; @@ -534,7 +602,7 @@ void ath_ani_calibrate(unsigned long data) if (longcal || shortcal) { common->ani.caldone = ath9k_hw_calibrate(ah, ah->curchan, - common->rx_chainmask, longcal); + ah->rxchainmask, longcal); } ath9k_ps_restore(sc); @@ -545,6 +613,7 @@ set_timer: * The interval must be the shortest necessary to satisfy ANI, * short calibration and long calibration. */ + ath9k_debug_samp_bb_mac(sc); cal_interval = ATH_LONG_CALINTERVAL; if (sc->sc_ah->config.enable_ani) cal_interval = min(cal_interval, @@ -564,7 +633,6 @@ set_timer: static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) { struct ath_node *an; - struct ath_hw *ah = sc->sc_ah; an = (struct ath_node *)sta->drv_priv; #ifdef CONFIG_ATH9K_DEBUGFS @@ -573,9 +641,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) spin_unlock(&sc->nodes_lock); an->sta = sta; #endif - if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM) - sc->sc_flags |= SC_OP_ENABLE_APM; - if (sc->sc_flags & SC_OP_TXAGGR) { ath_tx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + @@ -599,74 +664,6 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) ath_tx_node_cleanup(sc, an); } -void ath_hw_check(struct work_struct *work) -{ - 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; - - ath9k_ps_wakeup(sc); - if (ath9k_hw_check_alive(sc->sc_ah)) - goto out; - - spin_lock_irqsave(&common->cc_lock, flags); - busy = ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); - - ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " - "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); - if (busy >= 99) { - if (++sc->hw_busy_count >= 3) { - spin_lock_bh(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); - } - } else if (busy >= 0) - sc->hw_busy_count = 0; - -out: - ath9k_ps_restore(sc); -} - -static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) -{ - static int count; - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - - if (pll_sqsum >= 0x40000) { - count++; - if (count == 3) { - /* Rx is hung for more than 500ms. Reset it */ - ath_dbg(common, ATH_DBG_RESET, - "Possible RX hang, resetting"); - spin_lock_bh(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); - count = 0; - } - } else - count = 0; -} - -void ath_hw_pll_work(struct work_struct *work) -{ - struct ath_softc *sc = container_of(work, struct ath_softc, - hw_pll_work.work); - u32 pll_sqsum; - - if (AR_SREV_9485(sc->sc_ah)) { - - ath9k_ps_wakeup(sc); - pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); - ath9k_ps_restore(sc); - - ath_hw_pll_rx_hang_check(sc, pll_sqsum); - - ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); - } -} - void ath9k_tasklet(unsigned long data) { @@ -677,16 +674,24 @@ void ath9k_tasklet(unsigned long data) u32 status = sc->intrstatus; u32 rxmask; + ath9k_ps_wakeup(sc); + spin_lock(&sc->sc_pcu_lock); + if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_BB_WATCHDOG)) { - spin_lock(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock(&sc->sc_pcu_lock); - return; - } +#ifdef CONFIG_ATH9K_DEBUGFS + enum ath_reset_type type; - ath9k_ps_wakeup(sc); - spin_lock(&sc->sc_pcu_lock); + if (status & ATH9K_INT_FATAL) + type = RESET_TYPE_FATAL_INT; + else + type = RESET_TYPE_BB_WATCHDOG; + + RESET_STAT_INC(sc, type); +#endif + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + goto out; + } /* * Only run the baseband hang check if beacons stop working in AP or @@ -706,8 +711,7 @@ void ath9k_tasklet(unsigned long data) */ ath_dbg(common, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); - sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC | - PS_TSFOOR_SYNC; + sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC; } if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) @@ -736,6 +740,7 @@ void ath9k_tasklet(unsigned long data) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); +out: /* re-enable hardware interrupt */ ath9k_hw_enable_interrupts(ah); @@ -826,11 +831,9 @@ irqreturn_t ath_isr(int irq, void *dev) if (status & ATH9K_INT_TXURN) ath9k_hw_updatetxtriglevel(ah, true); - if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { - if (status & ATH9K_INT_RXEOL) { - ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); - ath9k_hw_set_interrupts(ah, ah->imask); - } + if (status & ATH9K_INT_RXEOL) { + ah->imask &= ~(ATH9K_INT_RXEOL | ATH9K_INT_RXORN); + ath9k_hw_set_interrupts(ah); } if (status & ATH9K_INT_MIB) { @@ -886,8 +889,9 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_ps_wakeup(sc); spin_lock_bh(&sc->sc_pcu_lock); + atomic_set(&ah->intr_ref_cnt, -1); - ath9k_hw_configpcipowersave(ah, 0, 0); + ath9k_hw_configpcipowersave(ah, false); if (!ah->curchan) ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); @@ -899,27 +903,13 @@ static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) channel->center_freq, r); } - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - if (ath_startrecv(sc) != 0) { - ath_err(common, "Unable to restart recv logic\n"); - goto out; - } - if (sc->sc_flags & SC_OP_BEACONS) - ath_set_beacon(sc); /* restart beacons */ - - /* Re-Enable interrupts */ - ath9k_hw_set_interrupts(ah, ah->imask); + ath_complete_reset(sc, true); /* Enable LED */ ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(ah, ah->led_pin, 0); - ieee80211_wake_queues(hw); - ieee80211_queue_delayed_work(hw, &sc->hw_pll_work, HZ/2); - -out: spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); @@ -932,11 +922,10 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) int r; ath9k_ps_wakeup(sc); - cancel_delayed_work_sync(&sc->hw_pll_work); - spin_lock_bh(&sc->sc_pcu_lock); + ath_cancel_work(sc); - ieee80211_stop_queues(hw); + spin_lock_bh(&sc->sc_pcu_lock); /* * Keep the LED on when the radio is disabled @@ -947,13 +936,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_cfg_gpio_input(ah, ah->led_pin); } - /* Disable interrupts */ - ath9k_hw_disable_interrupts(ah); - - ath_drain_all_txq(sc, false); /* clear pending tx frames */ - - ath_stoprecv(sc); /* turn off frame recv */ - ath_flushrecv(sc); /* flush recv queue */ + ath_prepare_reset(sc, false, true); if (!ah->curchan) ah->curchan = ath9k_cmn_get_curchannel(hw, ah); @@ -967,55 +950,19 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) ath9k_hw_phy_disable(ah); - ath9k_hw_configpcipowersave(ah, 1, 1); + ath9k_hw_configpcipowersave(ah, true); spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); } -int ath_reset(struct ath_softc *sc, bool retry_tx) +static int ath_reset(struct ath_softc *sc, bool retry_tx) { - struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); - struct ieee80211_hw *hw = sc->hw; int r; - sc->hw_busy_count = 0; - - /* Stop ANI */ - - del_timer_sync(&common->ani.timer); - ath9k_ps_wakeup(sc); - ieee80211_stop_queues(hw); - - ath9k_hw_disable_interrupts(ah); - ath_drain_all_txq(sc, retry_tx); - - ath_stoprecv(sc); - ath_flushrecv(sc); - - r = ath9k_hw_reset(ah, sc->sc_ah->curchan, ah->caldata, false); - if (r) - ath_err(common, - "Unable to reset hardware; reset status %d\n", r); - - if (ath_startrecv(sc) != 0) - ath_err(common, "Unable to start recv logic\n"); - - /* - * We may be doing a reset in response to a request - * that changes the channel so update any state that - * might change as a result. - */ - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - - if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL))) - ath_set_beacon(sc); /* restart beacons */ - - ath9k_hw_set_interrupts(ah, ah->imask); + r = ath_reset_internal(sc, NULL, retry_tx); if (retry_tx) { int i; @@ -1028,15 +975,83 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) } } - ieee80211_wake_queues(hw); + ath9k_ps_restore(sc); + + return r; +} + +void ath_reset_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); + + ath_reset(sc, true); +} + +void ath_hw_check(struct work_struct *work) +{ + 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; + + ath9k_ps_wakeup(sc); + if (ath9k_hw_check_alive(sc->sc_ah)) + goto out; + + spin_lock_irqsave(&common->cc_lock, flags); + busy = ath_update_survey_stats(sc); + spin_unlock_irqrestore(&common->cc_lock, flags); + + ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " + "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); + if (busy >= 99) { + if (++sc->hw_busy_count >= 3) { + RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + } - /* Start ANI */ - if (!common->disable_ani) - ath_start_ani(common); + } else if (busy >= 0) + sc->hw_busy_count = 0; +out: ath9k_ps_restore(sc); +} - return r; +static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) +{ + static int count; + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + if (pll_sqsum >= 0x40000) { + count++; + if (count == 3) { + /* Rx is hung for more than 500ms. Reset it */ + ath_dbg(common, ATH_DBG_RESET, + "Possible RX hang, resetting"); + RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + count = 0; + } + } else + count = 0; +} + +void ath_hw_pll_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, + hw_pll_work.work); + u32 pll_sqsum; + + if (AR_SREV_9485(sc->sc_ah)) { + + ath9k_ps_wakeup(sc); + pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); + ath9k_ps_restore(sc); + + ath_hw_pll_rx_hang_check(sc, pll_sqsum); + + ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); + } } /**********************/ @@ -1066,7 +1081,7 @@ static int ath9k_start(struct ieee80211_hw *hw) init_channel = ath9k_cmn_get_curchannel(hw, ah); /* Reset SERDES registers */ - ath9k_hw_configpcipowersave(ah, 0, 0); + ath9k_hw_configpcipowersave(ah, false); /* * The basic interface to setting the hardware in a good @@ -1085,28 +1100,6 @@ static int ath9k_start(struct ieee80211_hw *hw) goto mutex_unlock; } - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath9k_cmn_update_txpow(ah, sc->curtxpow, - sc->config.txpowlimit, &sc->curtxpow); - - /* - * Setup the hardware after reset: - * The receive engine is set going. - * Frame transmit is handled entirely - * in the frame output path; there's nothing to do - * here except setup the interrupt mask. - */ - if (ath_startrecv(sc) != 0) { - ath_err(common, "Unable to start recv logic\n"); - r = -EIO; - spin_unlock_bh(&sc->sc_pcu_lock); - goto mutex_unlock; - } - spin_unlock_bh(&sc->sc_pcu_lock); - /* Setup our intr mask. */ ah->imask = ATH9K_INT_TX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN | ATH9K_INT_FATAL | @@ -1129,11 +1122,14 @@ static int ath9k_start(struct ieee80211_hw *hw) /* Disable BMISS interrupt when we're not associated */ ah->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(ah, ah->imask); - ieee80211_wake_queues(hw); + if (!ath_complete_reset(sc, false)) { + r = -EIO; + spin_unlock_bh(&sc->sc_pcu_lock); + goto mutex_unlock; + } - ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); + spin_unlock_bh(&sc->sc_pcu_lock); if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && !ah->btcoex_hw.enabled) { @@ -1141,8 +1137,6 @@ static int ath9k_start(struct ieee80211_hw *hw) AR_STOMP_LOW_WLAN_WGHT); ath9k_hw_btcoex_enable(ah); - if (common->bus_ops->bt_coex_prep) - common->bus_ops->bt_coex_prep(common); if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_resume(sc); } @@ -1228,10 +1222,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); - cancel_delayed_work_sync(&sc->tx_complete_work); - cancel_delayed_work_sync(&sc->hw_pll_work); - cancel_work_sync(&sc->paprd_work); - cancel_work_sync(&sc->hw_check_work); + ath_cancel_work(sc); if (sc->sc_flags & SC_OP_INVALID) { ath_dbg(common, ATH_DBG_ANY, "Device not present\n"); @@ -1418,7 +1409,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ah->imask &= ~ATH9K_INT_TSFOOR; } - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); /* Set up ANI */ if (iter_data.naps > 0) { @@ -1593,7 +1584,7 @@ static void ath9k_enable_ps(struct ath_softc *sc) if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { if ((ah->imask & ATH9K_INT_TIM_TIMER) == 0) { ah->imask |= ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); } ath9k_hw_setrxabort(ah, 1); } @@ -1613,7 +1604,7 @@ static void ath9k_disable_ps(struct ath_softc *sc) PS_WAIT_FOR_TX_ACK); if (ah->imask & ATH9K_INT_TIM_TIMER) { ah->imask &= ~ATH9K_INT_TIM_TIMER; - ath9k_hw_set_interrupts(ah, ah->imask); + ath9k_hw_set_interrupts(ah); } } @@ -1676,6 +1667,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { struct ieee80211_channel *curchan = hw->conf.channel; + struct ath9k_channel old_chan; int pos = curchan->hw_value; int old_pos = -1; unsigned long flags; @@ -1692,15 +1684,25 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) "Set channel: %d MHz type: %d\n", curchan->center_freq, conf->channel_type); - ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], - curchan, conf->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); /* + * Preserve the current channel values, before updating + * the same channel + */ + if (old_pos == pos) { + memcpy(&old_chan, &sc->sc_ah->channels[pos], + sizeof(struct ath9k_channel)); + ah->curchan = &old_chan; + } + + ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], + curchan, conf->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 @@ -1844,8 +1846,7 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, switch (cmd) { case STA_NOTIFY_SLEEP: an->sleeping = true; - if (ath_tx_aggr_sleep(sc, an)) - ieee80211_sta_set_tim(sta); + ath_tx_aggr_sleep(sta, sc, an); break; case STA_NOTIFY_AWAKE: an->sleeping = false; @@ -1854,7 +1855,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, } } -static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int ath9k_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct ath_softc *sc = hw->priv; @@ -2032,6 +2034,7 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) /* Stop ANI */ sc->sc_flags &= ~SC_OP_ANI_RUN; del_timer_sync(&common->ani.timer); + memset(&sc->caldata, 0, sizeof(sc->caldata)); } } @@ -2153,7 +2156,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, ath9k_ps_restore(sc); } -static u64 ath9k_get_tsf(struct ieee80211_hw *hw) +static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; u64 tsf; @@ -2167,7 +2170,9 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void ath9k_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + u64 tsf) { struct ath_softc *sc = hw->priv; @@ -2178,7 +2183,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf) mutex_unlock(&sc->mutex); } -static void ath9k_reset_tsf(struct ieee80211_hw *hw) +static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; @@ -2341,9 +2346,11 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop) ath9k_ps_wakeup(sc); spin_lock_bh(&sc->sc_pcu_lock); drain_txq = ath_drain_all_txq(sc, false); + spin_unlock_bh(&sc->sc_pcu_lock); + if (!drain_txq) ath_reset(sc, false); - spin_unlock_bh(&sc->sc_pcu_lock); + ath9k_ps_restore(sc); ieee80211_wake_queues(hw); @@ -2406,6 +2413,73 @@ skip: return sc->beacon.tx_last; } +static int ath9k_get_stats(struct ieee80211_hw *hw, + struct ieee80211_low_level_stats *stats) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath9k_mib_stats *mib_stats = &ah->ah_mibStats; + + stats->dot11ACKFailureCount = mib_stats->ackrcv_bad; + stats->dot11RTSFailureCount = mib_stats->rts_bad; + stats->dot11FCSErrorCount = mib_stats->fcs_bad; + stats->dot11RTSSuccessCount = mib_stats->rts_good; + return 0; +} + +static u32 fill_chainmask(u32 cap, u32 new) +{ + u32 filled = 0; + int i; + + for (i = 0; cap && new; i++, cap >>= 1) { + if (!(cap & BIT(0))) + continue; + + if (new & BIT(0)) + filled |= BIT(i); + + new >>= 1; + } + + return filled; +} + +static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + + if (!rx_ant || !tx_ant) + return -EINVAL; + + sc->ant_rx = rx_ant; + sc->ant_tx = tx_ant; + + if (ah->caps.rx_chainmask == 1) + return 0; + + /* AR9100 runs into calibration issues if not all rx chains are enabled */ + if (AR_SREV_9100(ah)) + ah->rxchainmask = 0x7; + else + 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); + + return 0; +} + +static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +{ + struct ath_softc *sc = hw->priv; + + *tx_ant = sc->ant_tx; + *rx_ant = sc->ant_rx; + return 0; +} + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2430,5 +2504,8 @@ struct ieee80211_ops ath9k_ops = { .set_coverage_class = ath9k_set_coverage_class, .flush = ath9k_flush, .tx_frames_pending = ath9k_tx_frames_pending, - .tx_last_beacon = ath9k_tx_last_beacon, + .tx_last_beacon = ath9k_tx_last_beacon, + .get_stats = ath9k_get_stats, + .set_antenna = ath9k_set_antenna, + .get_antenna = ath9k_get_antenna, }; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index be4ea1329813..edb0b4b3da3a 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -32,9 +32,12 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_VDEVICE(ATHEROS, 0x002E) }, /* PCI-E */ { PCI_VDEVICE(ATHEROS, 0x0030) }, /* PCI-E AR9300 */ { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E AR9485 */ + { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E AR9580 */ + { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E AR9462 */ { 0 } }; + /* return bus cachesize in 4B word units */ static void ath_pci_read_cachesize(struct ath_common *common, int *csz) { @@ -88,23 +91,6 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data) return true; } -/* - * Bluetooth coexistance requires disabling ASPM. - */ -static void ath_pci_bt_coex_prep(struct ath_common *common) -{ - struct ath_softc *sc = (struct ath_softc *) common->priv; - struct pci_dev *pdev = to_pci_dev(sc->dev); - u8 aspm; - - if (!pci_is_pcie(pdev)) - return; - - pci_read_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, &aspm); - aspm &= ~(ATH_PCIE_CAP_LINK_L0S | ATH_PCIE_CAP_LINK_L1); - pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); -} - static void ath_pci_extn_synch_enable(struct ath_common *common) { struct ath_softc *sc = (struct ath_softc *) common->priv; @@ -116,6 +102,7 @@ static void ath_pci_extn_synch_enable(struct ath_common *common) pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl); } +/* 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; @@ -125,19 +112,38 @@ static void ath_pci_aspm_init(struct ath_common *common) int pos; u8 aspm; - if (!pci_is_pcie(pdev)) + pos = pci_pcie_cap(pdev); + if (!pos) return; parent = pdev->bus->self; - if (WARN_ON(!parent)) + if (!parent) return; + if (ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) { + /* Bluetooth coexistance requires disabling ASPM. */ + pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &aspm); + aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); + pci_write_config_byte(pdev, pos + PCI_EXP_LNKCTL, aspm); + + /* + * Both upstream and downstream PCIe components should + * have the same ASPM settings. + */ + pos = pci_pcie_cap(parent); + pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm); + aspm &= ~(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); + pci_write_config_byte(parent, pos + PCI_EXP_LNKCTL, aspm); + + return; + } + pos = pci_pcie_cap(parent); pci_read_config_byte(parent, pos + PCI_EXP_LNKCTL, &aspm); if (aspm & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { ah->aspm_enabled = true; /* Initialize PCIe PM and SERDES registers. */ - ath9k_hw_configpcipowersave(ah, 0, 0); + ath9k_hw_configpcipowersave(ah, false); } } @@ -145,7 +151,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = { .ath_bus_type = ATH_PCI, .read_cachesize = ath_pci_read_cachesize, .eeprom_read = ath_pci_eeprom_read, - .bt_coex_prep = ath_pci_bt_coex_prep, .extn_synch_en = ath_pci_extn_synch_enable, .aspm_init = ath_pci_aspm_init, }; @@ -156,7 +161,6 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; - u16 subsysid; u32 val; int ret = 0; char hw_name[64]; @@ -250,8 +254,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) sc->irq = pdev->irq; - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsysid); - ret = ath9k_init_device(id->device, sc, subsysid, &ath_pci_bus_ops); + ret = ath9k_init_device(id->device, sc, &ath_pci_bus_ops); if (ret) { dev_err(&pdev->dev, "Failed to initialize device\n"); goto err_init; @@ -330,17 +333,17 @@ static int ath_pci_resume(struct device *device) if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + ath9k_ps_wakeup(sc); /* Enable LED */ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 1); + ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); /* * Reset key cache to sane defaults (all entries cleared) instead of * semi-random values after suspend/resume. */ - ath9k_ps_wakeup(sc); - ath9k_init_crypto(sc); + ath9k_cmn_init_crypto(sc->sc_ah); ath9k_ps_restore(sc); sc->ps_idle = true; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index c04a6c3cac7f..8448281dd069 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -603,7 +603,8 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, static u8 ath_rc_get_highest_rix(struct ath_softc *sc, struct ath_rate_priv *ath_rc_priv, const struct ath_rate_table *rate_table, - int *is_probing) + int *is_probing, + bool legacy) { u32 best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; @@ -624,6 +625,8 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc, u8 per_thres; rate = ath_rc_priv->valid_rate_index[index]; + if (legacy && !(rate_table->info[rate].rate_flags & RC_LEGACY)) + continue; if (rate > ath_rc_priv->rate_max_phy) continue; @@ -767,7 +770,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, 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; + u8 try_per_rate, i = 0, rix, high_rix; int is_probe = 0; if (rate_control_send_low(sta, priv_sta, txrc)) @@ -786,7 +789,9 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, try_per_rate = 4; rate_table = ath_rc_priv->rate_table; - rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe); + rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, + &is_probe, false); + high_rix = rix; /* * If we're in HT mode and both us and our peer supports LDPC. @@ -822,10 +827,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, } /* Fill in the other rates for multirate retry */ - for ( ; i < 4; i++) { - /* Use twice the number of tries for the last MRR segment. */ - if (i + 1 == 4) - try_per_rate = 8; + for ( ; i < 3; i++) { ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix); /* All other rates in the series have RTS enabled */ @@ -833,6 +835,24 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, try_per_rate, rix, 1); } + /* Use twice the number of tries for the last MRR segment. */ + try_per_rate = 8; + + /* + * Use a legacy rate as last retry to ensure that the frame + * is tried in both MCS and legacy rates. + */ + if ((rates[2].flags & IEEE80211_TX_RC_MCS) && + (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) || + (ath_rc_priv->per[high_rix] > 45))) + rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, + &is_probe, true); + else + ath_rc_get_lower_rix(rate_table, 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 @@ -1342,12 +1362,6 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) return; - if (!(tx_info->flags & IEEE80211_TX_STAT_AMPDU)) { - tx_info->status.ampdu_ack_len = - (tx_info->flags & IEEE80211_TX_STAT_ACK ? 1 : 0); - tx_info->status.ampdu_len = 1; - } - if (!(tx_info->flags & IEEE80211_TX_STAT_ACK)) tx_status = 1; @@ -1484,7 +1498,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, if (rc->rate_table == NULL) return 0; - max = 80 + rc->rate_table->rate_cnt * 1024 + 1; + max = 80 + rc->rate_table_size * 1024 + 1; buf = kmalloc(max, GFP_KERNEL); if (buf == NULL) return -ENOMEM; @@ -1494,7 +1508,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf, "HT", "MCS", "Rate", "Success", "Retries", "XRetries", "PER"); - for (i = 0; i < rc->rate_table->rate_cnt; i++) { + for (i = 0; i < rc->rate_table_size; i++) { u32 ratekbps = rc->rate_table->info[i].ratekbps; struct ath_rc_stats *stats = &rc->rcstats[i]; char mcs[5]; diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h index c3d850207bee..b7a4bcd3eec7 100644 --- a/drivers/net/wireless/ath/ath9k/rc.h +++ b/drivers/net/wireless/ath/ath9k/rc.h @@ -221,12 +221,6 @@ struct ath_rate_priv { struct ath_rc_stats rcstats[RATE_TABLE_SIZE]; }; -enum ath9k_internal_frame_type { - ATH9K_IFT_NOT_INTERNAL, - ATH9K_IFT_PAUSE, - ATH9K_IFT_UNPAUSE -}; - #ifdef CONFIG_ATH9K_RATE_CONTROL int ath_rate_control_register(void); void ath_rate_control_unregister(void); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 4c21f8cbdeb5..67b862cdae6d 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -433,12 +433,9 @@ void ath_rx_cleanup(struct ath_softc *sc) u32 ath_calcrxfilter(struct ath_softc *sc) { -#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) - u32 rfilt; - rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) - | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST + rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ATH9K_RX_FILTER_MCAST; if (sc->rx.rxfilter & FIF_PROBE_REQ) @@ -586,22 +583,11 @@ 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 ieee80211_mgmt *mgmt; struct ath_common *common = ath9k_hw_common(sc->sc_ah); if (skb->len < 24 + 8 + 2 + 2) return; - mgmt = (struct ieee80211_mgmt *)skb->data; - if (memcmp(common->curbssid, mgmt->bssid, ETH_ALEN) != 0) { - /* TODO: This doesn't work well if you have stations - * associated to two different APs because curbssid - * is just the last AP that any of the stations associated - * with. - */ - return; /* not from our current AP */ - } - sc->ps_flags &= ~PS_WAIT_FOR_BEACON; if (sc->ps_flags & PS_BEACON_SYNC) { @@ -609,7 +595,6 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) ath_dbg(common, ATH_DBG_PS, "Reconfigure Beacon timers based on timestamp from the AP\n"); ath_set_beacon(sc); - sc->ps_flags &= ~PS_TSFOOR_SYNC; } if (ath_beacon_dtim_pending_cab(skb)) { @@ -638,7 +623,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) } } -static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) +static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon) { struct ieee80211_hdr *hdr; struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -647,7 +632,7 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb) /* Process Beacon and CAB receive in PS state */ if (((sc->ps_flags & PS_WAIT_FOR_BEACON) || ath9k_check_auto_sleep(sc)) - && ieee80211_is_beacon(hdr->frame_control)) + && mybeacon) ath_rx_ps_beacon(sc, skb); else if ((sc->ps_flags & PS_WAIT_FOR_CAB) && (ieee80211_is_data(hdr->frame_control) || @@ -770,7 +755,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, * on. All this is necessary because of our use of * a self-linked list to avoid rx overruns. */ - ret = ath9k_hw_rxprocdesc(ah, ds, rs, 0); + ret = ath9k_hw_rxprocdesc(ah, ds, rs); if (ret == -EINPROGRESS) { struct ath_rx_status trs; struct ath_buf *tbf; @@ -796,7 +781,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc, */ tds = tbf->bf_desc; - ret = ath9k_hw_rxprocdesc(ah, tds, &trs, 0); + ret = ath9k_hw_rxprocdesc(ah, tds, &trs); if (ret == -EINPROGRESS) return NULL; } @@ -823,6 +808,7 @@ static bool ath9k_rx_accept(struct ath_common *common, struct ath_rx_status *rx_stats, bool *decrypt_error) { + 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; @@ -833,8 +819,10 @@ static bool ath9k_rx_accept(struct ath_common *common, 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 && !(rx_stats->rs_status & - (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC)); + strip_mic = is_valid_tkip && ieee80211_is_data(fc) && + !(rx_stats->rs_status & + (ATH9K_RXERR_DECRYPT | ATH9K_RXERR_CRC | ATH9K_RXERR_MIC | + ATH9K_RXERR_KEYMISS)); if (!rx_stats->rs_datalen) return false; @@ -862,6 +850,8 @@ static bool ath9k_rx_accept(struct ath_common *common, * 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; @@ -869,7 +859,8 @@ static bool ath9k_rx_accept(struct ath_common *common, if (rx_stats->rs_status & ATH9K_RXERR_PHY) return false; - if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) { + if ((rx_stats->rs_status & ATH9K_RXERR_DECRYPT) || + (!is_mc && (rx_stats->rs_status & ATH9K_RXERR_KEYMISS))) { *decrypt_error = true; mic_error = false; } @@ -879,17 +870,14 @@ static bool ath9k_rx_accept(struct ath_common *common, * decryption and MIC failures. For monitor mode, * we also ignore the CRC error. */ - if (ah->is_monitoring) { - if (rx_stats->rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - return false; - } else { - if (rx_stats->rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - return false; - } - } + 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; } /* @@ -945,7 +933,7 @@ static int ath9k_process_rate(struct ath_common *common, * No valid hardware bitrate found -- we should not get here * because hardware has already validated this frame as OK. */ - ath_dbg(common, ATH_DBG_XMIT, + ath_dbg(common, ATH_DBG_ANY, "unsupported hw bitrate detected 0x%02x using 1 Mbit\n", rx_stats->rs_rate); @@ -960,23 +948,12 @@ static void ath9k_process_rssi(struct ath_common *common, struct ath_softc *sc = hw->priv; struct ath_hw *ah = common->ah; int last_rssi; - __le16 fc; - if ((ah->opmode != NL80211_IFTYPE_STATION) && - (ah->opmode != NL80211_IFTYPE_ADHOC)) + if (!rx_stats->is_mybeacon || + ((ah->opmode != NL80211_IFTYPE_STATION) && + (ah->opmode != NL80211_IFTYPE_ADHOC))) return; - fc = hdr->frame_control; - if (!ieee80211_is_beacon(fc) || - compare_ether_addr(hdr->addr3, common->curbssid)) { - /* TODO: This doesn't work well if you have stations - * associated to two different APs because curbssid - * is just the last AP that any of the stations associated - * with. - */ - return; - } - if (rx_stats->rs_rssi != ATH9K_RSSI_BAD && !rx_stats->rs_moreaggr) ATH_RSSI_LPF(sc->last_rssi, rx_stats->rs_rssi); @@ -1003,6 +980,8 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, struct ieee80211_rx_status *rx_status, bool *decrypt_error) { + struct ath_hw *ah = common->ah; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); /* @@ -1023,7 +1002,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common, rx_status->band = hw->conf.channel->band; rx_status->freq = hw->conf.channel->center_freq; - rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi; + rx_status->signal = ah->noise + rx_stats->rs_rssi; rx_status->antenna = rx_stats->rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_MPDU; @@ -1791,11 +1770,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) struct ieee80211_rx_status *rxs; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - /* - * The hw can technically differ from common->hw when using ath9k - * virtual wiphy so to account for that we iterate over the active - * wiphys and find the appropriate wiphy and therefore hw. - */ struct ieee80211_hw *hw = sc->hw; struct ieee80211_hdr *hdr; int retval; @@ -1849,6 +1823,11 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) hdr = (struct ieee80211_hdr *) (hdr_skb->data + rx_status_len); rxs = IEEE80211_SKB_RXCB(hdr_skb); + if (ieee80211_is_beacon(hdr->frame_control) && + !compare_ether_addr(hdr->addr3, common->curbssid)) + rs.is_mybeacon = true; + else + rs.is_mybeacon = false; ath_debug_stat_rx(sc, &rs); @@ -1856,7 +1835,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) * If we're asked to flush receive queue, directly * chain it back at the queue without processing it. */ - if (flush) + if (sc->sc_flags & SC_OP_RXFLUSH) goto requeue_drop_frag; retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs, @@ -1961,13 +1940,13 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) spin_lock_irqsave(&sc->sc_pm_lock, flags); if ((sc->ps_flags & (PS_WAIT_FOR_BEACON | - PS_WAIT_FOR_CAB | - PS_WAIT_FOR_PSPOLL_DATA)) || - ath9k_check_auto_sleep(sc)) - ath_rx_ps(sc, skb); + PS_WAIT_FOR_CAB | + PS_WAIT_FOR_PSPOLL_DATA)) || + ath9k_check_auto_sleep(sc)) + 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) + if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx == 3) ath_ant_comb_scan(sc, &rs); ieee80211_rx(hw, skb); @@ -1984,11 +1963,17 @@ requeue: } else { list_move_tail(&bf->list, &sc->rx.rxbuf); ath_rx_buf_link(sc, bf); - ath9k_hw_rxena(ah); + if (!flush) + ath9k_hw_rxena(ah); } } while (1); spin_unlock_bh(&sc->rx.rxbuflock); + if (!(ah->imask & ATH9K_INT_RXEOL)) { + ah->imask |= (ATH9K_INT_RXEOL | ATH9K_INT_RXORN); + ath9k_hw_set_interrupts(ah); + } + return 0; } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index fa4c0bbce6b9..8fcb7e9e8399 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -619,6 +619,7 @@ #define AR_D_GBL_IFS_EIFS 0x10b0 #define AR_D_GBL_IFS_EIFS_M 0x0000FFFF #define AR_D_GBL_IFS_EIFS_RESV0 0xFFFF0000 +#define AR_D_GBL_IFS_EIFS_ASYNC_FIFO 363 #define AR_D_GBL_IFS_MISC 0x10f0 #define AR_D_GBL_IFS_MISC_LFSR_SLICE_SEL 0x00000007 @@ -793,14 +794,15 @@ #define AR_SREV_REVISION_9485_10 0 #define AR_SREV_REVISION_9485_11 1 #define AR_SREV_VERSION_9340 0x300 +#define AR_SREV_VERSION_9580 0x1C0 +#define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */ +#define AR_SREV_VERSION_9462 0x280 +#define AR_SREV_REVISION_9462_10 0 +#define AR_SREV_REVISION_9462_20 2 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ ((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE)) -#define AR_SREV_5416_20_OR_LATER(_ah) \ - (((AR_SREV_5416(_ah)) && \ - ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20)) || \ - ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100)) #define AR_SREV_5416_22_OR_LATER(_ah) \ (((AR_SREV_5416(_ah)) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \ @@ -893,6 +895,33 @@ (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_10(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_10)) + +#define AR_SREV_9462_20(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9462_20)) + +#define AR_SREV_9462_20_OR_LATER(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ + ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20)) + +#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)) + +/* NOTE: When adding chips newer than Peacock, add chip check here */ +#define AR_SREV_9580_10_OR_LATER(_ah) \ + (AR_SREV_9580(_ah)) + enum ath_usb_dev { AR9280_USB = 1, /* AR7010 + AR9280, UB94 */ AR9287_USB = 2, /* AR7010 + AR9287, UB95 */ @@ -1117,7 +1146,7 @@ enum { #define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4) #define AR_ENT_OTP 0x40d8 #define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000 -#define AR_ENT_OTP_MPSD 0x00800000 +#define AR_ENT_OTP_MIN_PKT_SIZE_DISABLE 0x00800000 #define AR_CH0_BB_DPLL1 0x16180 #define AR_CH0_BB_DPLL1_REFDIV 0xF8000000 @@ -1489,6 +1518,7 @@ enum { #define AR_USEC_TX_LAT_S 14 #define AR_USEC_RX_LAT 0x1F800000 #define AR_USEC_RX_LAT_S 23 +#define AR_USEC_ASYNC_FIFO 0x12E00074 #define AR_RESET_TSF 0x8020 #define AR_RESET_TSF_ONCE 0x01000000 @@ -1763,6 +1793,7 @@ enum { #define AR_TXOP_12_15 0x81fc #define AR_NEXT_NDP2_TIMER 0x8180 +#define AR_GEN_TIMER_BANK_1_LEN 8 #define AR_FIRST_NDP_TIMER 7 #define AR_NDP2_PERIOD 0x81a0 #define AR_NDP2_TIMER_MODE 0x81c0 @@ -1851,9 +1882,10 @@ enum { #define AR_PCU_MISC_MODE2_HWWAR2 0x02000000 #define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000 -#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358 -#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400 -#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 +#define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358 +#define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400 +#define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 +#define AR_MAC_PCU_GEN_TIMER_TSF_SEL 0x83d8 #define AR_AES_MUTE_MASK0 0x805c @@ -1901,7 +1933,42 @@ enum { #define AR_PHY_AGC_CONTROL_NO_UPDATE_NF 0x00020000 /* don't update noise floor automatically */ #define AR_PHY_AGC_CONTROL_EXT_NF_PWR_MEAS 0x00040000 /* extend noise floor power measurement */ #define AR_PHY_AGC_CONTROL_CLC_SUCCESS 0x00080000 /* carrier leak calibration done */ +#define AR_PHY_AGC_CONTROL_PKDET_CAL 0x00100000 #define AR_PHY_AGC_CONTROL_YCOK_MAX 0x000003c0 #define AR_PHY_AGC_CONTROL_YCOK_MAX_S 6 +/* MCI Registers */ +#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) + + #endif diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index cc595712f518..03b0a651a591 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -48,19 +48,23 @@ static u16 bits_per_symbol[][2] = { #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 list_head *bf_head); + 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); static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, struct ath_tx_status *ts, int txok, int sendbar); static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, struct list_head *head, bool internal); -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len); 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, bool update_rc); + int txok); static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, int seqno); +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); enum { MCS_HT20, @@ -129,7 +133,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) spin_lock_bh(&txq->axq_lock); tid->paused = false; - if (list_empty(&tid->buf_q)) + if (skb_queue_empty(&tid->buf_q)) goto unlock; ath_tx_queue_tid(txq, tid); @@ -149,6 +153,7 @@ static struct ath_frame_info *get_frame_info(struct sk_buff *skb) static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { struct ath_txq *txq = tid->ac->txq; + struct sk_buff *skb; struct ath_buf *bf; struct list_head bf_head; struct ath_tx_status ts; @@ -159,17 +164,17 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) memset(&ts, 0, sizeof(ts)); spin_lock_bh(&txq->axq_lock); - while (!list_empty(&tid->buf_q)) { - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - list_move_tail(&bf->list, &bf_head); + while ((skb = __skb_dequeue(&tid->buf_q))) { + fi = get_frame_info(skb); + bf = fi->bf; spin_unlock_bh(&txq->axq_lock); - fi = get_frame_info(bf->bf_mpdu); - if (fi->retries) { - ath_tx_update_baw(sc, tid, fi->seqno); + if (bf && 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, 1); } else { - ath_tx_send_normal(sc, txq, NULL, &bf_head); + ath_tx_send_normal(sc, txq, NULL, skb); } spin_lock_bh(&txq->axq_lock); } @@ -219,6 +224,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { + struct sk_buff *skb; struct ath_buf *bf; struct list_head bf_head; struct ath_tx_status ts; @@ -227,16 +233,21 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, memset(&ts, 0, sizeof(ts)); INIT_LIST_HEAD(&bf_head); - for (;;) { - if (list_empty(&tid->buf_q)) - break; + while ((skb = __skb_dequeue(&tid->buf_q))) { + fi = get_frame_info(skb); + bf = fi->bf; - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - list_move_tail(&bf->list, &bf_head); + if (!bf) { + spin_unlock(&txq->axq_lock); + ath_tx_complete(sc, skb, ATH_TX_ERROR, txq); + spin_lock(&txq->axq_lock); + continue; + } + + list_add_tail(&bf->list, &bf_head); - fi = get_frame_info(bf->bf_mpdu); if (fi->retries) - ath_tx_update_baw(sc, tid, fi->seqno); + ath_tx_update_baw(sc, tid, bf->bf_state.seqno); spin_unlock(&txq->axq_lock); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); @@ -251,6 +262,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, struct sk_buff *skb) { struct ath_frame_info *fi = get_frame_info(skb); + struct ath_buf *bf = fi->bf; struct ieee80211_hdr *hdr; TX_STAT_INC(txq->axq_qnum, a_retries); @@ -259,6 +271,8 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, hdr = (struct ieee80211_hdr *)skb->data; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); + dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, + sizeof(*hdr), DMA_TO_DEVICE); } static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) @@ -326,7 +340,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, while (bf) { fi = get_frame_info(bf->bf_mpdu); - ba_index = ATH_BA_INDEX(seq_st, fi->seqno); + ba_index = ATH_BA_INDEX(seq_st, bf->bf_state.seqno); (*nframes)++; if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) @@ -349,7 +363,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, 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, bf_pending; + struct list_head bf_head; + struct sk_buff_head bf_pending; u16 seq_st = 0, acked_cnt = 0, txfail_cnt = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0; @@ -358,7 +373,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_frame_info *fi; int nframes; u8 tidno; - bool clear_filter; + bool flush = !!(ts->ts_status & ATH9K_TX_FLUSH); skb = bf->bf_mpdu; hdr = (struct ieee80211_hdr *)skb->data; @@ -377,11 +392,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, while (bf) { bf_next = bf->bf_next; - bf->bf_state.bf_type |= BUF_XRETRY; if (!bf->bf_stale || bf_next != NULL) list_move_tail(&bf->list, &bf_head); - ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0, 0); @@ -422,11 +435,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, } } - INIT_LIST_HEAD(&bf_pending); - INIT_LIST_HEAD(&bf_head); + __skb_queue_head_init(&bf_pending); ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad); while (bf) { + u16 seqno = bf->bf_state.seqno; + txfail = txpending = sendbar = 0; bf_next = bf->bf_next; @@ -434,7 +448,7 @@ 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 (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) { + if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, seqno))) { /* transmit completion, subframe is * acked by block ack */ acked_cnt++; @@ -448,15 +462,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * the un-acked sub-frames */ txfail = 1; + } else if (flush) { + txpending = 1; } else if (fi->retries < ATH_MAX_SW_RETRIES) { - if (!(ts->ts_status & ATH9K_TXERR_FILT) || - !an->sleeping) + if (txok || !an->sleeping) ath_tx_set_retry(sc, txq, bf->bf_mpdu); - clear_filter = true; txpending = 1; } else { - bf->bf_state.bf_type |= BUF_XRETRY; txfail = 1; sendbar = 1; txfail_cnt++; @@ -467,10 +480,10 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * Make sure the last desc is reclaimed if it * not a holding desc. */ - if (!bf_last->bf_stale || bf_next != NULL) + INIT_LIST_HEAD(&bf_head); + if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) || + bf_next != NULL || !bf_last->bf_stale) list_move_tail(&bf->list, &bf_head); - else - INIT_LIST_HEAD(&bf_head); if (!txpending || (tid->state & AGGR_CLEANUP)) { /* @@ -478,22 +491,19 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * block-ack window */ spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, fi->seqno); + ath_tx_update_baw(sc, tid, seqno); spin_unlock_bh(&txq->axq_lock); 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, true); + ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok); rc_update = false; - } else { - ath_tx_rc_status(sc, bf, ts, nframes, nbad, txok, false); } ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, !txfail, sendbar); } else { /* retry the un-acked ones */ - ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false); if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) { if (bf->bf_next == NULL && bf_last->bf_stale) { struct ath_buf *tbf; @@ -506,29 +516,17 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, */ if (!tbf) { spin_lock_bh(&txq->axq_lock); - ath_tx_update_baw(sc, tid, fi->seqno); + ath_tx_update_baw(sc, tid, seqno); spin_unlock_bh(&txq->axq_lock); - bf->bf_state.bf_type |= - BUF_XRETRY; - ath_tx_rc_status(sc, bf, ts, nframes, - nbad, 0, false); ath_tx_complete_buf(sc, bf, txq, &bf_head, - ts, 0, 0); + ts, 0, + !flush); break; } - ath9k_hw_cleartxdesc(sc->sc_ah, - tbf->bf_desc); - list_add_tail(&tbf->list, &bf_head); - } else { - /* - * Clear descriptor status words for - * software retry - */ - ath9k_hw_cleartxdesc(sc->sc_ah, - bf->bf_desc); + fi->bf = tbf; } } @@ -536,22 +534,25 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, * Put this buffer to the temporary pending * queue to retain ordering */ - list_splice_tail_init(&bf_head, &bf_pending); + __skb_queue_tail(&bf_pending, skb); } bf = bf_next; } /* prepend un-acked frames to the beginning of the pending frame queue */ - if (!list_empty(&bf_pending)) { + if (!skb_queue_empty(&bf_pending)) { if (an->sleeping) - ieee80211_sta_set_tim(sta); + ieee80211_sta_set_buffered(sta, tid->tidno, true); spin_lock_bh(&txq->axq_lock); - if (clear_filter) - tid->ac->clear_ps_filter = true; - list_splice(&bf_pending, &tid->buf_q); - ath_tx_queue_tid(txq, tid); + skb_queue_splice(&bf_pending, &tid->buf_q); + if (!an->sleeping) { + ath_tx_queue_tid(txq, tid); + + if (ts->ts_status & ATH9K_TXERR_FILT) + tid->ac->clear_ps_filter = true; + } spin_unlock_bh(&txq->axq_lock); } @@ -566,8 +567,32 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_unlock(); - if (needreset) - ath_reset(sc, false); + if (needreset) { + RESET_STAT_INC(sc, RESET_TYPE_TX_ERROR); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + } +} + +static bool ath_lookup_legacy(struct ath_buf *bf) +{ + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; + int i; + + skb = bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + rates = tx_info->control.rates; + + for (i = 0; i < 4; i++) { + if (!rates[i].count || rates[i].idx < 0) + break; + + if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) + return true; + } + + return false; } static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, @@ -643,8 +668,10 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, * meet the minimum required mpdudensity. */ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf, u16 frmlen) + struct ath_buf *bf, u16 frmlen, + bool first_subfrm) { +#define FIRST_DESC_NDELIMS 60 struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols; @@ -667,6 +694,14 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, ndelim += ATH_AGGR_ENCRYPTDELIM; /* + * Add delimiter when using RTS/CTS with aggregation + * and non enterprise AR9003 card + */ + if (first_subfrm && !AR_SREV_9580_10_OR_LATER(sc->sc_ah) && + (sc->sc_ah->ent_mode & AR_ENT_OTP_MIN_PKT_SIZE_DISABLE)) + ndelim = max(ndelim, FIRST_DESC_NDELIMS); + + /* * Convert desired mpdu density from microeconds to bytes based * on highest rate in rate series (i.e. first rate) to determine * required minimum length for subframe. Take into account @@ -711,22 +746,33 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, int *aggr_len) { #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) - struct ath_buf *bf, *bf_first, *bf_prev = NULL; + struct ath_buf *bf, *bf_first = NULL, *bf_prev = NULL; int rl = 0, nframes = 0, ndelim, prev_al = 0; u16 aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; struct ieee80211_tx_info *tx_info; struct ath_frame_info *fi; - - bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); + struct sk_buff *skb; + u16 seqno; do { - bf = list_first_entry(&tid->buf_q, struct ath_buf, list); - fi = get_frame_info(bf->bf_mpdu); + skb = skb_peek(&tid->buf_q); + fi = get_frame_info(skb); + bf = fi->bf; + if (!fi->bf) + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + + if (!bf) + continue; + + bf->bf_state.bf_type = BUF_AMPDU | BUF_AGGR; + seqno = bf->bf_state.seqno; + if (!bf_first) + bf_first = bf; /* do not step over block-ack window */ - if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) { + if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { status = ATH_AGGR_BAW_CLOSED; break; } @@ -740,14 +786,14 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, al_delta = ATH_AGGR_DELIM_SZ + fi->framelen; if (nframes && - (aggr_limit < (al + bpad + al_delta + prev_al))) { + ((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) || - !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS))) + if (nframes && (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) break; /* do not exceed subframe limit */ @@ -755,7 +801,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, status = ATH_AGGR_LIMITED; break; } - nframes++; /* add padding for previous frame to aggregation length */ al += bpad + al_delta; @@ -764,25 +809,26 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * Get the delimiters needed to meet the MPDU * density for this node. */ - ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen); + ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen, + !nframes); bpad = PADBYTES(al_delta) + (ndelim << 2); + nframes++; bf->bf_next = NULL; - ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0); /* link buffers of this frame to the aggregate */ if (!fi->retries) - ath_tx_addto_baw(sc, tid, fi->seqno); - ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); - list_move_tail(&bf->list, bf_q); - if (bf_prev) { + ath_tx_addto_baw(sc, tid, 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; - ath9k_hw_set_desc_link(sc->sc_ah, bf_prev->bf_desc, - bf->bf_daddr); - } + bf_prev = bf; - } while (!list_empty(&tid->buf_q)); + } while (!skb_queue_empty(&tid->buf_q)); *aggr_len = al; @@ -790,17 +836,236 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, #undef PADBYTES } +/* + * rix - rate index + * pktlen - total bytes (delims + data + fcs + pads + pad delims) + * 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 nbits, nsymbits, duration, nsymbols; + int streams; + + /* find number of symbols: PLCP + data */ + streams = HT_RC_2_STREAMS(rix); + nbits = (pktlen << 3) + OFDM_PLCP_BITS; + nsymbits = bits_per_symbol[rix % 8][width] * streams; + nsymbols = (nbits + nsymbits - 1) / nsymbits; + + if (!half_gi) + duration = SYMBOL_TIME(nsymbols); + else + duration = SYMBOL_TIME_HALFGI(nsymbols); + + /* addup duration for legacy/ht training and signal fields */ + duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); + + return duration; +} + +static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_info *info, int len) +{ + struct ath_hw *ah = sc->sc_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; + int i; + u8 rix = 0; + + skb = bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + rates = tx_info->control.rates; + hdr = (struct ieee80211_hdr *)skb->data; + + /* set dur_update_en for l-sig computation except for PS-Poll frames */ + info->dur_update = !ieee80211_is_pspoll(hdr->frame_control); + + /* + * We check if Short Preamble is needed for the CTS rate by + * checking the BSS's global flag. + * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. + */ + rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); + info->rtscts_rate = rate->hw_value; + if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) + info->rtscts_rate |= rate->hw_value_short; + + for (i = 0; i < 4; i++) { + bool is_40, is_sgi, is_sp; + int phy; + + if (!rates[i].count || (rates[i].idx < 0)) + continue; + + rix = rates[i].idx; + info->rates[i].Tries = rates[i].count; + + if (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) { + info->rates[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; + info->flags |= ATH9K_TXDESC_CTSENA; + } + + if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + info->rates[i].RateFlags |= ATH9K_RATESERIES_2040; + if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) + info->rates[i].RateFlags |= ATH9K_RATESERIES_HALFGI; + + is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI); + is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH); + is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); + + if (rates[i].flags & IEEE80211_TX_RC_MCS) { + /* MCS rates */ + 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, + is_40, is_sgi, is_sp); + if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) + info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; + continue; + } + + /* legacy rates */ + if ((tx_info->band == IEEE80211_BAND_2GHZ) && + !(rate->flags & IEEE80211_RATE_ERP_G)) + phy = WLAN_RC_PHY_CCK; + else + phy = WLAN_RC_PHY_OFDM; + + rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; + info->rates[i].Rate = rate->hw_value; + if (rate->hw_value_short) { + if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) + info->rates[i].Rate |= rate->hw_value_short; + } else { + is_sp = false; + } + + if (bf->bf_state.bfs_paprd) + info->rates[i].ChSel = ah->txchainmask; + else + info->rates[i].ChSel = ath_txchainmask_reduction(sc, + ah->txchainmask, info->rates[i].Rate); + + info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, + phy, rate->bitrate * 100, len, rix, is_sp); + } + + /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ + if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit)) + info->flags &= ~ATH9K_TXDESC_RTSENA; + + /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */ + if (info->flags & ATH9K_TXDESC_RTSENA) + info->flags &= ~ATH9K_TXDESC_CTSENA; +} + +static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr; + enum ath9k_pkt_type htype; + __le16 fc; + + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + + if (ieee80211_is_beacon(fc)) + htype = ATH9K_PKT_TYPE_BEACON; + else if (ieee80211_is_probe_resp(fc)) + htype = ATH9K_PKT_TYPE_PROBE_RESP; + else if (ieee80211_is_atim(fc)) + htype = ATH9K_PKT_TYPE_ATIM; + else if (ieee80211_is_pspoll(fc)) + htype = ATH9K_PKT_TYPE_PSPOLL; + else + htype = ATH9K_PKT_TYPE_NORMAL; + + return htype; +} + +static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf, + struct ath_txq *txq, int len) +{ + struct ath_hw *ah = sc->sc_ah; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); + struct ath_buf *bf_first = bf; + struct ath_tx_info info; + bool aggr = !!(bf->bf_state.bf_type & BUF_AGGR); + + memset(&info, 0, sizeof(info)); + info.is_first = true; + info.is_last = true; + info.txpower = MAX_RATE_POWER; + info.qcu = txq->axq_qnum; + + info.flags = ATH9K_TXDESC_INTREQ; + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + info.flags |= ATH9K_TXDESC_NOACK; + if (tx_info->flags & IEEE80211_TX_CTL_LDPC) + info.flags |= ATH9K_TXDESC_LDPC; + + ath_buf_set_rate(sc, bf, &info, len); + + if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) + info.flags |= ATH9K_TXDESC_CLRDMASK; + + if (bf->bf_state.bfs_paprd) + info.flags |= (u32) bf->bf_state.bfs_paprd << ATH9K_TXDESC_PAPRD_S; + + + while (bf) { + struct sk_buff *skb = bf->bf_mpdu; + struct ath_frame_info *fi = get_frame_info(skb); + + info.type = get_hw_packet_type(skb); + if (bf->bf_next) + info.link = bf->bf_next->bf_daddr; + else + info.link = 0; + + info.buf_addr[0] = bf->bf_buf_addr; + info.buf_len[0] = skb->len; + info.pkt_len = fi->framelen; + info.keyix = fi->keyix; + info.keytype = fi->keytype; + + if (aggr) { + if (bf == bf_first) + info.aggr = AGGR_BUF_FIRST; + else if (!bf->bf_next) + info.aggr = AGGR_BUF_LAST; + else + info.aggr = AGGR_BUF_MIDDLE; + + info.ndelim = bf->bf_state.ndelim; + info.aggr_len = len; + } + + ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); + bf = bf->bf_next; + } +} + static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { struct ath_buf *bf; enum ATH_AGGR_STATUS status; - struct ath_frame_info *fi; + struct ieee80211_tx_info *tx_info; struct list_head bf_q; int aggr_len; do { - if (list_empty(&tid->buf_q)) + if (skb_queue_empty(&tid->buf_q)) return; INIT_LIST_HEAD(&bf_q); @@ -816,34 +1081,25 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, 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; - ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); + tx_info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; + } else { + tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; } /* if only one frame, send as non-aggregate */ if (bf == bf->bf_lastbf) { - fi = get_frame_info(bf->bf_mpdu); - - bf->bf_state.bf_type &= ~BUF_AGGR; - ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); - ath_buf_set_rate(sc, bf, fi->framelen); - ath_tx_txqaddbuf(sc, txq, &bf_q, false); - continue; + 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); } - /* setup first desc of aggregate */ - bf->bf_state.bf_type |= BUF_AGGR; - ath_buf_set_rate(sc, bf, aggr_len); - ath9k_hw_set11n_aggr_first(sc->sc_ah, bf->bf_desc, aggr_len); - - /* anchor last desc of aggregate */ - ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc); - + ath_tx_fill_desc(sc, bf, txq, aggr_len); ath_tx_txqaddbuf(sc, txq, &bf_q, false); - TX_STAT_INC(txq->axq_qnum, a_aggr); - } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH && status != ATH_AGGR_BAW_CLOSED); } @@ -902,12 +1158,13 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) ath_tx_flush_tid(sc, txtid); } -bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) +void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, + struct ath_node *an) { struct ath_atx_tid *tid; struct ath_atx_ac *ac; struct ath_txq *txq; - bool buffered = false; + bool buffered; int tidno; for (tidno = 0, tid = &an->tid[tidno]; @@ -921,8 +1178,7 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) spin_lock_bh(&txq->axq_lock); - if (!list_empty(&tid->buf_q)) - buffered = true; + buffered = !skb_queue_empty(&tid->buf_q); tid->sched = false; list_del(&tid->list); @@ -933,9 +1189,9 @@ bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an) } spin_unlock_bh(&txq->axq_lock); - } - return buffered; + ieee80211_sta_set_buffered(sta, tidno, buffered); + } } void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) @@ -954,7 +1210,7 @@ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an) spin_lock_bh(&txq->axq_lock); ac->clear_ps_filter = true; - if (!list_empty(&tid->buf_q) && !tid->paused) { + if (!skb_queue_empty(&tid->buf_q) && !tid->paused) { ath_tx_queue_tid(txq, tid); ath_txq_schedule(sc, txq); } @@ -1004,7 +1260,6 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_tx_queue_info qi; static const int subtype_txq_to_hwq[] = { [WME_AC_BE] = ATH_TXQ_AC_BE, @@ -1054,12 +1309,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) */ return NULL; } - if (axq_qnum >= ARRAY_SIZE(sc->tx.txq)) { - ath_err(common, "qnum %u out of range, max %zu!\n", - axq_qnum, ARRAY_SIZE(sc->tx.txq)); - ath9k_hw_releasetxqueue(ah, axq_qnum); - return NULL; - } if (!ATH_TXQ_SETUP(sc, axq_qnum)) { struct ath_txq *txq = &sc->tx.txq[axq_qnum]; @@ -1156,6 +1405,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq, struct ath_tx_status ts; memset(&ts, 0, sizeof(ts)); + ts.ts_status = ATH9K_TX_FLUSH; INIT_LIST_HEAD(&bf_head); while (!list_empty(list)) { @@ -1222,7 +1472,8 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_txq *txq; - int i, npend = 0; + int i; + u32 npend = 0; if (sc->sc_flags & SC_OP_INVALID) return true; @@ -1234,11 +1485,12 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx) if (!ATH_TXQ_SETUP(sc, i)) continue; - npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum); + if (ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum)) + npend |= BIT(i); } if (npend) - ath_err(common, "Failed to stop TX DMA!\n"); + ath_err(common, "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)) @@ -1271,7 +1523,7 @@ 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; - if (list_empty(&txq->axq_acq) || + if (work_pending(&sc->hw_reset_work) || list_empty(&txq->axq_acq) || txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) return; @@ -1298,7 +1550,7 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) * add tid to round-robin queue if more frames * are pending for the tid */ - if (!list_empty(&tid->buf_q)) + if (!skb_queue_empty(&tid->buf_q)) ath_tx_queue_tid(txq, tid); if (tid == last_tid || @@ -1390,12 +1642,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, } static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, - struct ath_buf *bf, struct ath_tx_control *txctl) + struct sk_buff *skb, struct ath_tx_control *txctl) { - struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); + struct ath_frame_info *fi = get_frame_info(skb); struct list_head bf_head; - - bf->bf_state.bf_type |= BUF_AMPDU; + struct ath_buf *bf; /* * Do not queue to h/w when any of the following conditions is true: @@ -1404,113 +1655,82 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, * - seqno is not within block-ack window * - h/w queue depth exceeds low water mark */ - if (!list_empty(&tid->buf_q) || tid->paused || - !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) || + if (!skb_queue_empty(&tid->buf_q) || tid->paused || + !BAW_WITHIN(tid->seq_start, tid->baw_size, tid->seq_next) || txctl->txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) { /* * Add this frame to software queue for scheduling later * for aggregation. */ TX_STAT_INC(txctl->txq->axq_qnum, a_queued_sw); - list_add_tail(&bf->list, &tid->buf_q); - ath_tx_queue_tid(txctl->txq, tid); + __skb_queue_tail(&tid->buf_q, skb); + if (!txctl->an || !txctl->an->sleeping) + ath_tx_queue_tid(txctl->txq, tid); return; } + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) + return; + + bf->bf_state.bf_type = BUF_AMPDU; INIT_LIST_HEAD(&bf_head); list_add(&bf->list, &bf_head); /* Add sub-frame to BAW */ - if (!fi->retries) - ath_tx_addto_baw(sc, tid, fi->seqno); + ath_tx_addto_baw(sc, tid, bf->bf_state.seqno); /* Queue to h/w without aggregation */ TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw); bf->bf_lastbf = bf; - ath_buf_set_rate(sc, bf, fi->framelen); + ath_tx_fill_desc(sc, bf, txctl->txq, fi->framelen); ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false); } static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - struct list_head *bf_head) + struct ath_atx_tid *tid, struct sk_buff *skb) { - struct ath_frame_info *fi; + struct ath_frame_info *fi = get_frame_info(skb); + struct list_head bf_head; struct ath_buf *bf; - bf = list_first_entry(bf_head, struct ath_buf, list); - bf->bf_state.bf_type &= ~BUF_AMPDU; + bf = fi->bf; + if (!bf) + bf = ath_tx_setup_buffer(sc, txq, tid, skb); + + if (!bf) + return; + + INIT_LIST_HEAD(&bf_head); + list_add_tail(&bf->list, &bf_head); + bf->bf_state.bf_type = 0; /* update starting sequence number for subsequent ADDBA request */ if (tid) INCR(tid->seq_start, IEEE80211_SEQ_MAX); bf->bf_lastbf = bf; - fi = get_frame_info(bf->bf_mpdu); - ath_buf_set_rate(sc, bf, fi->framelen); - ath_tx_txqaddbuf(sc, txq, bf_head, false); + ath_tx_fill_desc(sc, bf, txq, fi->framelen); + ath_tx_txqaddbuf(sc, txq, &bf_head, false); TX_STAT_INC(txq->axq_qnum, queued); } -static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - enum ath9k_pkt_type htype; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_beacon(fc)) - htype = ATH9K_PKT_TYPE_BEACON; - else if (ieee80211_is_probe_resp(fc)) - htype = ATH9K_PKT_TYPE_PROBE_RESP; - else if (ieee80211_is_atim(fc)) - htype = ATH9K_PKT_TYPE_ATIM; - else if (ieee80211_is_pspoll(fc)) - htype = ATH9K_PKT_TYPE_PSPOLL; - else - htype = ATH9K_PKT_TYPE_NORMAL; - - return htype; -} - static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, int framelen) { - struct ath_softc *sc = hw->priv; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_frame_info *fi = get_frame_info(skb); struct ath_node *an = NULL; - struct ath_atx_tid *tid; enum ath9k_key_type keytype; - u16 seqno = 0; - u8 tidno; keytype = ath9k_cmn_get_hw_crypto_keytype(skb); if (sta) an = (struct ath_node *) sta->drv_priv; - hdr = (struct ieee80211_hdr *)skb->data; - if (an && ieee80211_is_data_qos(hdr->frame_control) && - conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) { - - tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; - - /* - * Override seqno set by upper layer with the one - * in tx aggregation state. - */ - tid = ATH_AN_2_TID(an, tidno); - seqno = tid->seq_next; - hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT); - INCR(tid->seq_next, IEEE80211_SEQ_MAX); - } - memset(fi, 0, sizeof(*fi)); if (hw_key) fi->keyix = hw_key->hw_key_idx; @@ -1520,199 +1740,50 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; fi->framelen = framelen; - fi->seqno = seqno; -} - -static int setup_tx_flags(struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int flags = 0; - - flags |= ATH9K_TXDESC_INTREQ; - - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - flags |= ATH9K_TXDESC_NOACK; - - if (tx_info->flags & IEEE80211_TX_CTL_LDPC) - flags |= ATH9K_TXDESC_LDPC; - - return flags; -} - -/* - * rix - rate index - * pktlen - total bytes (delims + data + fcs + pads + pad delims) - * 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 nbits, nsymbits, duration, nsymbols; - int streams; - - /* find number of symbols: PLCP + data */ - streams = HT_RC_2_STREAMS(rix); - nbits = (pktlen << 3) + OFDM_PLCP_BITS; - nsymbits = bits_per_symbol[rix % 8][width] * streams; - nsymbols = (nbits + nsymbits - 1) / nsymbits; - - if (!half_gi) - duration = SYMBOL_TIME(nsymbols); - else - duration = SYMBOL_TIME_HALFGI(nsymbols); - - /* addup duration for legacy/ht training and signal fields */ - duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); - - return duration; } 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 ((sc->sc_flags & SC_OP_ENABLE_APM) && - (curchan->channelFlags & CHANNEL_5GHZ) && - (chainmask == 0x7) && (rate < 0x90)) + if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && + (curchan->channelFlags & CHANNEL_5GHZ) && + (chainmask == 0x7) && (rate < 0x90)) return 0x3; else return chainmask; } -static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) -{ - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath9k_11n_rate_series series[4]; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ieee80211_tx_rate *rates; - const struct ieee80211_rate *rate; - struct ieee80211_hdr *hdr; - int i, flags = 0; - u8 rix = 0, ctsrate = 0; - bool is_pspoll; - - memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); - - skb = bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - rates = tx_info->control.rates; - hdr = (struct ieee80211_hdr *)skb->data; - is_pspoll = ieee80211_is_pspoll(hdr->frame_control); - - /* - * We check if Short Preamble is needed for the CTS rate by - * checking the BSS's global flag. - * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. - */ - rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); - ctsrate = rate->hw_value; - if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - ctsrate |= rate->hw_value_short; - - for (i = 0; i < 4; i++) { - bool is_40, is_sgi, is_sp; - int phy; - - if (!rates[i].count || (rates[i].idx < 0)) - continue; - - rix = rates[i].idx; - series[i].Tries = rates[i].count; - - if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) { - series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - flags |= ATH9K_TXDESC_RTSENA; - } else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - flags |= ATH9K_TXDESC_CTSENA; - } - - if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) - series[i].RateFlags |= ATH9K_RATESERIES_2040; - if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) - series[i].RateFlags |= ATH9K_RATESERIES_HALFGI; - - is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI); - is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH); - is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); - - if (rates[i].flags & IEEE80211_TX_RC_MCS) { - /* MCS rates */ - series[i].Rate = rix | 0x80; - series[i].ChSel = ath_txchainmask_reduction(sc, - common->tx_chainmask, series[i].Rate); - series[i].PktDuration = ath_pkt_duration(sc, rix, len, - is_40, is_sgi, is_sp); - if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) - series[i].RateFlags |= ATH9K_RATESERIES_STBC; - continue; - } - - /* legacy rates */ - if ((tx_info->band == IEEE80211_BAND_2GHZ) && - !(rate->flags & IEEE80211_RATE_ERP_G)) - phy = WLAN_RC_PHY_CCK; - else - phy = WLAN_RC_PHY_OFDM; - - rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; - series[i].Rate = rate->hw_value; - if (rate->hw_value_short) { - if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) - series[i].Rate |= rate->hw_value_short; - } else { - is_sp = false; - } - - if (bf->bf_state.bfs_paprd) - series[i].ChSel = common->tx_chainmask; - else - series[i].ChSel = ath_txchainmask_reduction(sc, - common->tx_chainmask, series[i].Rate); - - series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah, - phy, rate->bitrate * 100, len, rix, is_sp); - } - - /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ - if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit)) - flags &= ~ATH9K_TXDESC_RTSENA; - - /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */ - if (flags & ATH9K_TXDESC_RTSENA) - flags &= ~ATH9K_TXDESC_CTSENA; - - /* set dur_update_en for l-sig computation except for PS-Poll frames */ - ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc, - bf->bf_lastbf->bf_desc, - !is_pspoll, ctsrate, - 0, series, 4, flags); - -} - -static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, +/* + * Assign a descriptor (and sequence number if necessary, + * and map buffer for DMA. Frees skb on error + */ +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) { - struct ath_softc *sc = hw->priv; - struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_frame_info *fi = get_frame_info(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_buf *bf; - struct ath_desc *ds; - int frm_type; + u16 seqno; bf = ath_tx_get_buffer(sc); if (!bf) { ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n"); - return NULL; + goto error; } ATH_TXBUF_RESET(bf); - bf->bf_flags = setup_tx_flags(skb); + if (tid) { + seqno = tid->seq_next; + hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); + INCR(tid->seq_next, IEEE80211_SEQ_MAX); + bf->bf_state.seqno = seqno; + } + bf->bf_mpdu = skb; bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, @@ -1723,38 +1794,26 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ath_err(ath9k_hw_common(sc->sc_ah), "dma_mapping_error() on TX\n"); ath_tx_return_buffer(sc, bf); - return NULL; + goto error; } - frm_type = get_hw_packet_type(skb); - - ds = bf->bf_desc; - ath9k_hw_set_desc_link(ah, ds, 0); - - ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER, - fi->keyix, fi->keytype, bf->bf_flags); - - ath9k_hw_filltxdesc(ah, ds, - skb->len, /* segment length */ - true, /* first segment */ - true, /* last segment */ - ds, /* first descriptor */ - bf->bf_buf_addr, - txq->axq_qnum); - + fi->bf = bf; return bf; + +error: + dev_kfree_skb_any(skb); + return NULL; } /* FIXME: tx power */ -static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, +static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb, struct ath_tx_control *txctl) { - struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct list_head bf_head; struct ath_atx_tid *tid = NULL; + struct ath_buf *bf; u8 tidno; spin_lock_bh(&txctl->txq->axq_lock); @@ -1772,27 +1831,21 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, * Try aggregation if it's a unicast data frame * and the destination is HT capable. */ - ath_tx_send_ampdu(sc, tid, bf, txctl); + ath_tx_send_ampdu(sc, tid, skb, txctl); } else { - INIT_LIST_HEAD(&bf_head); - list_add_tail(&bf->list, &bf_head); + bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb); + if (!bf) + goto out; - bf->bf_state.bfs_ftype = txctl->frame_type; bf->bf_state.bfs_paprd = txctl->paprd; - if (bf->bf_state.bfs_paprd) - ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc, - bf->bf_state.bfs_paprd); - if (txctl->paprd) bf->bf_state.bfs_paprd_timestamp = jiffies; - if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) - ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true); - - ath_tx_send_normal(sc, txctl->txq, tid, &bf_head); + ath_tx_send_normal(sc, txctl->txq, tid, skb); } +out: spin_unlock_bh(&txctl->txq->axq_lock); } @@ -1806,7 +1859,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_vif *vif = info->control.vif; struct ath_softc *sc = hw->priv; struct ath_txq *txq = txctl->txq; - struct ath_buf *bf; int padpos, padsize; int frmlen = skb->len + FCS_LEN; int q; @@ -1839,6 +1891,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, skb_push(skb, padsize); memmove(skb->data, skb->data + padsize, padpos); + hdr = (struct ieee80211_hdr *) skb->data; } if ((vif && vif->type != NL80211_IFTYPE_AP && @@ -1853,10 +1906,6 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, * info are no longer valid (overwritten by the ath_frame_info data. */ - bf = ath_tx_setup_buffer(hw, txctl->txq, skb); - if (unlikely(!bf)) - return -ENOMEM; - q = skb_get_queue_mapping(skb); spin_lock_bh(&txq->axq_lock); if (txq == sc->tx.txq_map[q] && @@ -1866,8 +1915,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, } spin_unlock_bh(&txq->axq_lock); - ath_tx_start_dma(sc, bf, txctl); - + ath_tx_start_dma(sc, skb, txctl); return 0; } @@ -1876,7 +1924,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, /*****************/ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - int tx_flags, int ftype, struct ath_txq *txq) + int tx_flags, struct ath_txq *txq) { struct ieee80211_hw *hw = sc->hw; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -1889,10 +1937,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, if (tx_flags & ATH_TX_BAR) tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { + if (!(tx_flags & ATH_TX_ERROR)) /* Frame was ACKed */ tx_info->flags |= IEEE80211_TX_STAT_ACK; - } padpos = ath9k_cmn_padpos(hdr->frame_control); padsize = padpos & 3; @@ -1936,18 +1983,18 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_status *ts, int txok, int sendbar) { struct sk_buff *skb = bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); unsigned long flags; int tx_flags = 0; if (sendbar) tx_flags = ATH_TX_BAR; - if (!txok) { + if (!txok) tx_flags |= ATH_TX_ERROR; - if (bf_isxretried(bf)) - tx_flags |= ATH_TX_XRETRY; - } + if (ts->ts_status & ATH9K_TXERR_FILT) + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); bf->bf_buf_addr = 0; @@ -1960,9 +2007,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, else complete(&sc->paprd_complete); } else { - ath_debug_stat_tx(sc, bf, ts, txq); - ath_tx_complete(sc, skb, tx_flags, - bf->bf_state.bfs_ftype, txq); + ath_debug_stat_tx(sc, bf, ts, txq, tx_flags); + ath_tx_complete(sc, skb, tx_flags, txq); } /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't * accidentally reference it later. @@ -1979,7 +2025,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, 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, bool update_rc) + int txok) { struct sk_buff *skb = bf->bf_mpdu; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; @@ -1994,19 +2040,16 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, tx_rateindex = ts->ts_rateindex; WARN_ON(tx_rateindex >= hw->max_rates); - if (ts->ts_status & ATH9K_TXERR_FILT) - tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) { + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { tx_info->flags |= IEEE80211_TX_STAT_AMPDU; BUG_ON(nbad > nframes); - - tx_info->status.ampdu_len = nframes; - tx_info->status.ampdu_ack_len = nframes - nbad; } + tx_info->status.ampdu_len = nframes; + tx_info->status.ampdu_ack_len = nframes - nbad; if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) { + (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) == 0) { /* * If an underrun error is seen assume it as an excessive * retry only if max frame trigger level has been reached @@ -2019,9 +2062,9 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf, * successfully by eventually preferring slower rates. * This itself should also alleviate congestion on the bus. */ - if (ieee80211_is_data(hdr->frame_control) && - (ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | - ATH9K_TX_DELIM_UNDERRUN)) && + if (unlikely(ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN | + ATH9K_TX_DELIM_UNDERRUN)) && + ieee80211_is_data(hdr->frame_control) && ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level) tx_info->status.rates[tx_rateindex].count = hw->max_rate_tries; @@ -2052,13 +2095,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq, spin_unlock_bh(&txq->axq_lock); if (!bf_isampdu(bf)) { - /* - * This frame is sent out as a single frame. - * Use hardware retry status for this frame. - */ - if (ts->ts_status & ATH9K_TXERR_XRETRY) - bf->bf_state.bf_type |= BUF_XRETRY; - ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true); + ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0); } else ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true); @@ -2085,6 +2122,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) spin_lock_bh(&txq->axq_lock); for (;;) { + if (work_pending(&sc->hw_reset_work)) + break; + if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; if (sc->sc_flags & SC_OP_TXAGGR) @@ -2172,9 +2212,8 @@ static void ath_tx_complete_poll_work(struct work_struct *work) if (needreset) { ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET, "tx hung, resetting the chip\n"); - spin_lock_bh(&sc->sc_pcu_lock); - ath_reset(sc, true); - spin_unlock_bh(&sc->sc_pcu_lock); + RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); } ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, @@ -2207,6 +2246,9 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) int status; for (;;) { + if (work_pending(&sc->hw_reset_work)) + break; + status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); if (status == -EINPROGRESS) break; @@ -2361,7 +2403,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) tid->sched = false; tid->paused = false; tid->state &= ~AGGR_CLEANUP; - INIT_LIST_HEAD(&tid->buf_q); + __skb_queue_head_init(&tid->buf_q); acno = TID_TO_WME_AC(tidno); tid->ac = &an->ac[acno]; tid->state &= ~AGGR_ADDBA_COMPLETE; diff --git a/drivers/net/wireless/ath/carl9170/Kconfig b/drivers/net/wireless/ath/carl9170/Kconfig index 2d1b821b440d..267d5dcf82dc 100644 --- a/drivers/net/wireless/ath/carl9170/Kconfig +++ b/drivers/net/wireless/ath/carl9170/Kconfig @@ -39,3 +39,17 @@ config CARL9170_WPC bool depends on CARL9170 && (INPUT = y || INPUT = CARL9170) default y + +config CARL9170_HWRNG + bool "Random number generator" + depends on CARL9170 && (HW_RANDOM = y || HW_RANDOM = CARL9170) + default n + help + Provides a hardware random number generator to the kernel. + + SECURITY WARNING: It's relatively easy to eavesdrop all + generated random numbers from the transport stream with + usbmon [software] or special usb sniffer hardware. + + Say N, unless your setup[i.e.: embedded system] has no + other rng source and you can afford to take the risk. diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index c5427a72a1e2..6cfbb419e2f6 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -43,6 +43,7 @@ #include <linux/firmware.h> #include <linux/completion.h> #include <linux/spinlock.h> +#include <linux/hw_random.h> #include <net/cfg80211.h> #include <net/mac80211.h> #include <linux/usb.h> @@ -151,6 +152,7 @@ struct carl9170_sta_tid { #define CARL9170_TX_TIMEOUT 2500 #define CARL9170_JANITOR_DELAY 128 #define CARL9170_QUEUE_STUCK_TIMEOUT 5500 +#define CARL9170_STAT_WORK 30000 #define CARL9170_NUM_TX_AGG_MAX 30 @@ -282,6 +284,7 @@ struct ar9170 { bool rx_stream; bool tx_stream; bool rx_filter; + bool hw_counters; unsigned int mem_blocks; unsigned int mem_block_size; unsigned int rx_size; @@ -331,11 +334,21 @@ struct ar9170 { /* PHY */ struct ieee80211_channel *channel; + unsigned int num_channels; int noise[4]; unsigned int chan_fail; unsigned int total_chan_fail; u8 heavy_clip; u8 ht_settings; + struct { + u64 active; /* usec */ + u64 cca; /* usec */ + u64 tx_time; /* usec */ + u64 rx_total; + u64 rx_overrun; + } tally; + struct delayed_work stat_work; + struct survey_info *survey; /* power calibration data */ u8 power_5G_leg[4]; @@ -437,6 +450,17 @@ struct ar9170 { unsigned int off_override; bool state; } ps; + +#ifdef CONFIG_CARL9170_HWRNG +# define CARL9170_HWRNG_CACHE_SIZE CARL9170_MAX_CMD_PAYLOAD_LEN + struct { + struct hwrng rng; + bool initialized; + char name[30 + 1]; + u16 cache[CARL9170_HWRNG_CACHE_SIZE / sizeof(u16)]; + unsigned int cache_idx; + } rng; +#endif /* CONFIG_CARL9170_HWRNG */ }; enum carl9170_ps_off_override_reasons { diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c index cdfc94c371b4..195dc6538110 100644 --- a/drivers/net/wireless/ath/carl9170/cmd.c +++ b/drivers/net/wireless/ath/carl9170/cmd.c @@ -36,6 +36,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <asm/div64.h> #include "carl9170.h" #include "cmd.h" @@ -165,6 +166,39 @@ int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id, return __carl9170_exec_cmd(ar, cmd, true); } +int carl9170_collect_tally(struct ar9170 *ar) +{ + struct carl9170_tally_rsp tally; + struct survey_info *info; + unsigned int tick; + int err; + + err = carl9170_exec_cmd(ar, CARL9170_CMD_TALLY, 0, NULL, + sizeof(tally), (u8 *)&tally); + if (err) + return err; + + tick = le32_to_cpu(tally.tick); + if (tick) { + ar->tally.active += le32_to_cpu(tally.active) / tick; + ar->tally.cca += le32_to_cpu(tally.cca) / tick; + ar->tally.tx_time += le32_to_cpu(tally.tx_time) / tick; + ar->tally.rx_total += le32_to_cpu(tally.rx_total); + ar->tally.rx_overrun += le32_to_cpu(tally.rx_overrun); + + if (ar->channel) { + info = &ar->survey[ar->channel->hw_value]; + info->channel_time = ar->tally.active; + info->channel_time_busy = ar->tally.cca; + info->channel_time_tx = ar->tally.tx_time; + do_div(info->channel_time, 1000); + do_div(info->channel_time_busy, 1000); + do_div(info->channel_time_tx, 1000); + } + } + return 0; +} + int carl9170_powersave(struct ar9170 *ar, const bool ps) { struct carl9170_cmd *cmd; diff --git a/drivers/net/wireless/ath/carl9170/cmd.h b/drivers/net/wireless/ath/carl9170/cmd.h index d5f95bdc75c1..885c42778b8b 100644 --- a/drivers/net/wireless/ath/carl9170/cmd.h +++ b/drivers/net/wireless/ath/carl9170/cmd.h @@ -50,6 +50,7 @@ int carl9170_echo_test(struct ar9170 *ar, u32 v); int carl9170_reboot(struct ar9170 *ar); int carl9170_mac_reset(struct ar9170 *ar); int carl9170_powersave(struct ar9170 *ar, const bool power_on); +int carl9170_collect_tally(struct ar9170 *ar); int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id, const u32 mode, const u32 addr, const u32 len); diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 39ddea5794f7..f4cae1cccbff 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -266,6 +266,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) FIF_PROMISC_IN_BSS; } + if (SUPP(CARL9170FW_HW_COUNTERS)) + ar->fw.hw_counters = true; + if (SUPP(CARL9170FW_WOL)) device_set_wakeup_enable(&ar->udev->dev, true); diff --git a/drivers/net/wireless/ath/carl9170/fwcmd.h b/drivers/net/wireless/ath/carl9170/fwcmd.h index 0a6dec529b59..9443c802b25b 100644 --- a/drivers/net/wireless/ath/carl9170/fwcmd.h +++ b/drivers/net/wireless/ath/carl9170/fwcmd.h @@ -55,6 +55,7 @@ enum carl9170_cmd_oids { CARL9170_CMD_READ_TSF = 0x06, CARL9170_CMD_RX_FILTER = 0x07, CARL9170_CMD_WOL = 0x08, + CARL9170_CMD_TALLY = 0x09, /* CAM */ CARL9170_CMD_EKEY = 0x10, @@ -286,6 +287,15 @@ struct carl9170_tsf_rsp { } __packed; #define CARL9170_TSF_RSP_SIZE 8 +struct carl9170_tally_rsp { + __le32 active; + __le32 cca; + __le32 tx_time; + __le32 rx_total; + __le32 rx_overrun; + __le32 tick; +} __packed; + struct carl9170_rsp { struct carl9170_cmd_head hdr; @@ -300,6 +310,7 @@ struct carl9170_rsp { struct carl9170_gpio gpio; struct carl9170_tsf_rsp tsf; struct carl9170_psm psm; + struct carl9170_tally_rsp tally; u8 data[CARL9170_MAX_CMD_PAYLOAD_LEN]; } __packed; } __packed __aligned(4); diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 0474e6638d21..f06e0695d412 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -413,6 +413,9 @@ static int carl9170_op_start(struct ieee80211_hw *hw) carl9170_set_state_when(ar, CARL9170_IDLE, CARL9170_STARTED); + ieee80211_queue_delayed_work(ar->hw, &ar->stat_work, + round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK))); + ieee80211_wake_queues(ar->hw); err = 0; @@ -423,6 +426,7 @@ out: static void carl9170_cancel_worker(struct ar9170 *ar) { + cancel_delayed_work_sync(&ar->stat_work); cancel_delayed_work_sync(&ar->tx_janitor); #ifdef CONFIG_CARL9170_LEDS cancel_delayed_work_sync(&ar->led_work); @@ -794,6 +798,43 @@ static void carl9170_ps_work(struct work_struct *work) mutex_unlock(&ar->mutex); } +static int carl9170_update_survey(struct ar9170 *ar, bool flush, bool noise) +{ + int err; + + if (noise) { + err = carl9170_get_noisefloor(ar); + if (err) + return err; + } + + if (ar->fw.hw_counters) { + err = carl9170_collect_tally(ar); + if (err) + return err; + } + + if (flush) + memset(&ar->tally, 0, sizeof(ar->tally)); + + return 0; +} + +static void carl9170_stat_work(struct work_struct *work) +{ + struct ar9170 *ar = container_of(work, struct ar9170, stat_work.work); + int err; + + mutex_lock(&ar->mutex); + err = carl9170_update_survey(ar, false, true); + mutex_unlock(&ar->mutex); + + if (err) + return; + + ieee80211_queue_delayed_work(ar->hw, &ar->stat_work, + round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK))); +} static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) { @@ -828,11 +869,19 @@ static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) if (err) goto out; + err = carl9170_update_survey(ar, true, false); + if (err) + goto out; + err = carl9170_set_channel(ar, hw->conf.channel, hw->conf.channel_type, CARL9170_RFI_NONE); if (err) goto out; + err = carl9170_update_survey(ar, false, true); + if (err) + goto out; + err = carl9170_set_dyn_sifs_ack(ar); if (err) goto out; @@ -1029,7 +1078,8 @@ out: mutex_unlock(&ar->mutex); } -static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw) +static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ar9170 *ar = hw->priv; struct carl9170_tsf_rsp tsf; @@ -1255,7 +1305,8 @@ static int carl9170_op_sta_remove(struct ieee80211_hw *hw, return 0; } -static int carl9170_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int carl9170_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *param) { struct ar9170 *ar = hw->priv; @@ -1421,24 +1472,159 @@ static int carl9170_register_wps_button(struct ar9170 *ar) } #endif /* CONFIG_CARL9170_WPC */ -static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx, - struct survey_info *survey) +#ifdef CONFIG_CARL9170_HWRNG +static int carl9170_rng_get(struct ar9170 *ar) { - struct ar9170 *ar = hw->priv; + +#define RW (CARL9170_MAX_CMD_PAYLOAD_LEN / sizeof(u32)) +#define RB (CARL9170_MAX_CMD_PAYLOAD_LEN) + + static const __le32 rng_load[RW] = { + [0 ... (RW - 1)] = cpu_to_le32(AR9170_RAND_REG_NUM)}; + + u32 buf[RW]; + + unsigned int i, off = 0, transfer, count; int err; - if (idx != 0) - return -ENOENT; + BUILD_BUG_ON(RB > CARL9170_MAX_CMD_PAYLOAD_LEN); + + if (!IS_ACCEPTING_CMD(ar) || !ar->rng.initialized) + return -EAGAIN; + + count = ARRAY_SIZE(ar->rng.cache); + while (count) { + err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG, + RB, (u8 *) rng_load, + RB, (u8 *) buf); + if (err) + return err; + + transfer = min_t(unsigned int, count, RW); + for (i = 0; i < transfer; i++) + ar->rng.cache[off + i] = buf[i]; + + off += transfer; + count -= transfer; + } + + ar->rng.cache_idx = 0; + +#undef RW +#undef RB + return 0; +} + +static int carl9170_rng_read(struct hwrng *rng, u32 *data) +{ + struct ar9170 *ar = (struct ar9170 *)rng->priv; + int ret = -EIO; mutex_lock(&ar->mutex); - err = carl9170_get_noisefloor(ar); + if (ar->rng.cache_idx >= ARRAY_SIZE(ar->rng.cache)) { + ret = carl9170_rng_get(ar); + if (ret) { + mutex_unlock(&ar->mutex); + return ret; + } + } + + *data = ar->rng.cache[ar->rng.cache_idx++]; mutex_unlock(&ar->mutex); - if (err) + + return sizeof(u16); +} + +static void carl9170_unregister_hwrng(struct ar9170 *ar) +{ + if (ar->rng.initialized) { + hwrng_unregister(&ar->rng.rng); + ar->rng.initialized = false; + } +} + +static int carl9170_register_hwrng(struct ar9170 *ar) +{ + int err; + + snprintf(ar->rng.name, ARRAY_SIZE(ar->rng.name), + "%s_%s", KBUILD_MODNAME, wiphy_name(ar->hw->wiphy)); + ar->rng.rng.name = ar->rng.name; + ar->rng.rng.data_read = carl9170_rng_read; + ar->rng.rng.priv = (unsigned long)ar; + + if (WARN_ON(ar->rng.initialized)) + return -EALREADY; + + err = hwrng_register(&ar->rng.rng); + if (err) { + dev_err(&ar->udev->dev, "Failed to register the random " + "number generator (%d)\n", err); return err; + } + + ar->rng.initialized = true; + + err = carl9170_rng_get(ar); + if (err) { + carl9170_unregister_hwrng(ar); + return err; + } + + return 0; +} +#endif /* CONFIG_CARL9170_HWRNG */ + +static int carl9170_op_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct ar9170 *ar = hw->priv; + struct ieee80211_channel *chan; + struct ieee80211_supported_band *band; + int err, b, i; - survey->channel = ar->channel; + chan = ar->channel; + if (!chan) + return -ENODEV; + + if (idx == chan->hw_value) { + mutex_lock(&ar->mutex); + err = carl9170_update_survey(ar, false, true); + mutex_unlock(&ar->mutex); + if (err) + return err; + } + + for (b = 0; b < IEEE80211_NUM_BANDS; b++) { + band = ar->hw->wiphy->bands[b]; + + if (!band) + continue; + + for (i = 0; i < band->n_channels; i++) { + if (band->channels[i].hw_value == idx) { + chan = &band->channels[i]; + goto found; + } + } + } + return -ENOENT; + +found: + memcpy(survey, &ar->survey[idx], sizeof(*survey)); + + survey->channel = chan; survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = ar->noise[0]; + + if (ar->channel == chan) + survey->filled |= SURVEY_INFO_IN_USE; + + if (ar->fw.hw_counters) { + survey->filled |= SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_BUSY | + SURVEY_INFO_CHANNEL_TIME_TX; + } + return 0; } @@ -1571,6 +1757,7 @@ void *carl9170_alloc(size_t priv_size) INIT_WORK(&ar->ping_work, carl9170_ping_work); INIT_WORK(&ar->restart_work, carl9170_restart_work); INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work); + INIT_DELAYED_WORK(&ar->stat_work, carl9170_stat_work); INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor); INIT_LIST_HEAD(&ar->tx_ampdu_list); rcu_assign_pointer(ar->tx_ampdu_iter, @@ -1654,6 +1841,7 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) struct ath_regulatory *regulatory = &ar->common.regulatory; unsigned int rx_streams, tx_streams, tx_params = 0; int bands = 0; + int chans = 0; if (ar->eeprom.length == cpu_to_le16(0xffff)) return -ENODATA; @@ -1677,14 +1865,24 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) { ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &carl9170_band_2GHz; + chans += carl9170_band_2GHz.n_channels; bands++; } if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) { ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &carl9170_band_5GHz; + chans += carl9170_band_5GHz.n_channels; bands++; } + if (!bands) + return -EINVAL; + + ar->survey = kzalloc(sizeof(struct survey_info) * chans, GFP_KERNEL); + if (!ar->survey) + return -ENOMEM; + ar->num_channels = chans; + /* * I measured this, a bandswitch takes roughly * 135 ms and a frequency switch about 80. @@ -1698,12 +1896,11 @@ static int carl9170_parse_eeprom(struct ar9170 *ar) ar->hw->channel_change_time = 80 * 1000; regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]); - regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]); /* second part of wiphy init */ SET_IEEE80211_PERM_ADDR(ar->hw, ar->eeprom.mac_address); - return bands ? 0 : -EINVAL; + return 0; } static int carl9170_reg_notifier(struct wiphy *wiphy, @@ -1787,6 +1984,12 @@ int carl9170_register(struct ar9170 *ar) goto err_unreg; #endif /* CONFIG_CARL9170_WPC */ +#ifdef CONFIG_CARL9170_HWRNG + err = carl9170_register_hwrng(ar); + if (err) + goto err_unreg; +#endif /* CONFIG_CARL9170_HWRNG */ + dev_info(&ar->udev->dev, "Atheros AR9170 is registered as '%s'\n", wiphy_name(ar->hw->wiphy)); @@ -1819,6 +2022,10 @@ void carl9170_unregister(struct ar9170 *ar) } #endif /* CONFIG_CARL9170_WPC */ +#ifdef CONFIG_CARL9170_HWRNG + carl9170_unregister_hwrng(ar); +#endif /* CONFIG_CARL9170_HWRNG */ + carl9170_cancel_worker(ar); cancel_work_sync(&ar->restart_work); @@ -1836,6 +2043,9 @@ void carl9170_free(struct ar9170 *ar) kfree(ar->mem_bitmap); ar->mem_bitmap = NULL; + kfree(ar->survey); + ar->survey = NULL; + mutex_destroy(&ar->mutex); ieee80211_free_hw(ar->hw); diff --git a/drivers/net/wireless/ath/carl9170/phy.c b/drivers/net/wireless/ath/carl9170/phy.c index aa147a9120b6..472efc7e3402 100644 --- a/drivers/net/wireless/ath/carl9170/phy.c +++ b/drivers/net/wireless/ath/carl9170/phy.c @@ -578,11 +578,10 @@ static int carl9170_init_phy(struct ar9170 *ar, enum ieee80211_band band) if (err) return err; - /* XXX: remove magic! */ - if (is_2ghz) - err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC, 0x5163); - else - err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC, 0x5143); + if (!ar->fw.hw_counters) { + err = carl9170_write_reg(ar, AR9170_PWR_REG_PLL_ADDAC, + is_2ghz ? 0x5163 : 0x5143); + } return err; } @@ -1574,6 +1573,9 @@ int carl9170_get_noisefloor(struct ar9170 *ar) AR9170_PHY_EXT_CCA_MIN_PWR, phy_res[i + 2]), 8); } + if (ar->channel) + ar->survey[ar->channel->hw_value].noise = ar->noise[0]; + return 0; } @@ -1766,10 +1768,6 @@ int carl9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel, ar->chan_fail = 0; } - err = carl9170_get_noisefloor(ar); - if (err) - return err; - if (ar->heavy_clip) { err = carl9170_write_reg(ar, AR9170_PHY_REG_HEAVY_CLIP_ENABLE, 0x200 | ar->heavy_clip); diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index 64703778cfea..e651db856344 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H #define CARL9170FW_VERSION_YEAR 11 -#define CARL9170FW_VERSION_MONTH 6 -#define CARL9170FW_VERSION_DAY 30 +#define CARL9170FW_VERSION_MONTH 8 +#define CARL9170FW_VERSION_DAY 15 #define CARL9170FW_VERSION_GIT "1.9.4" #endif /* __CARL9170_SHARED_VERSION_H */ diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index c325202fdc5f..d9218fe02036 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c @@ -57,22 +57,18 @@ struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, } EXPORT_SYMBOL(ath_rxbuf_alloc); -int ath_printk(const char *level, struct ath_common *common, - const char *fmt, ...) +void ath_printk(const char *level, const char *fmt, ...) { struct va_format vaf; va_list args; - int rtn; va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - rtn = printk("%sath: %pV", level, &vaf); + printk("%sath: %pV", level, &vaf); va_end(args); - - return rtn; } EXPORT_SYMBOL(ath_printk); diff --git a/drivers/net/wireless/ath/regd.h b/drivers/net/wireless/ath/regd.h index 172f63f671cf..03a8268ccf21 100644 --- a/drivers/net/wireless/ath/regd.h +++ b/drivers/net/wireless/ath/regd.h @@ -101,7 +101,7 @@ enum CountryCode { CTRY_GERMANY = 276, CTRY_GREECE = 300, CTRY_GREENLAND = 304, - CTRY_GRENEDA = 308, + CTRY_GRENADA = 308, CTRY_GUAM = 316, CTRY_GUATEMALA = 320, CTRY_HAITI = 332, diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h index 24b53839fc3a..bdd2b4d61f2f 100644 --- a/drivers/net/wireless/ath/regd_common.h +++ b/drivers/net/wireless/ath/regd_common.h @@ -332,7 +332,7 @@ static struct country_code_to_enum_rd allCountries[] = { {CTRY_GERMANY, ETSI1_WORLD, "DE"}, {CTRY_GREECE, ETSI1_WORLD, "GR"}, {CTRY_GREENLAND, ETSI1_WORLD, "GL"}, - {CTRY_GRENEDA, FCC3_FCCA, "GD"}, + {CTRY_GRENADA, FCC3_FCCA, "GD"}, {CTRY_GUAM, FCC1_FCCA, "GU"}, {CTRY_GUATEMALA, FCC1_FCCA, "GT"}, {CTRY_HAITI, ETSI1_WORLD, "HT"}, diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 3cab843afb05..b97a40ed5fff 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig @@ -114,22 +114,22 @@ config B43_PHY_N affect other devices support and may provide support for basic needs. config B43_PHY_LP - bool "Support for low-power (LP-PHY) devices (EXPERIMENTAL)" - depends on B43 && EXPERIMENTAL + bool "Support for low-power (LP-PHY) devices" + depends on B43 default y ---help--- Support for the LP-PHY. The LP-PHY is a low-power PHY built into some notebooks - and embedded devices. It supports 802.11a/g + and embedded devices. It supports 802.11a/b/g (802.11a support is optional, and currently disabled). config B43_PHY_HT - bool "Support for HT-PHY devices (BROKEN)" - depends on B43 && BROKEN + bool "Support for HT-PHY (high throughput) devices (EXPERIMENTAL)" + depends on B43 && EXPERIMENTAL ---help--- Support for the HT-PHY. - Say N, this is BROKEN and crashes driver. + Enables support for BCM4331 and possibly other chipsets with that PHY. config B43_PHY_LCN bool "Support for LCN-PHY devices (BROKEN)" @@ -169,13 +169,3 @@ config B43_DEBUG Say N, if you are a distributor or user building a release kernel for production use. Only say Y, if you are debugging a problem in the b43 driver sourcecode. - -config B43_FORCE_PIO - bool "Force usage of PIO instead of DMA" - depends on B43 && B43_DEBUG - ---help--- - This will disable DMA and always enable PIO instead. - - Say N! - This is only for debugging the PIO engine code. You do - _NOT_ want to enable this. diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index c818b0bc88ec..447a2307c9d9 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -17,11 +17,6 @@ #include "phy_common.h" -/* The unique identifier of the firmware that's officially supported by - * this driver version. */ -#define B43_SUPPORTED_FIRMWARE_ID "FW13" - - #ifdef CONFIG_B43_DEBUG # define B43_DEBUG 1 #else @@ -112,21 +107,61 @@ #define B43_MMIO_RADIO_HWENABLED_LO 0x49A #define B43_MMIO_GPIO_CONTROL 0x49C #define B43_MMIO_GPIO_MASK 0x49E +#define B43_MMIO_TXE0_CTL 0x500 +#define B43_MMIO_TXE0_AUX 0x502 +#define B43_MMIO_TXE0_TS_LOC 0x504 +#define B43_MMIO_TXE0_TIME_OUT 0x506 +#define B43_MMIO_TXE0_WM_0 0x508 +#define B43_MMIO_TXE0_WM_1 0x50A +#define B43_MMIO_TXE0_PHYCTL 0x50C +#define B43_MMIO_TXE0_STATUS 0x50E +#define B43_MMIO_TXE0_MMPLCP0 0x510 +#define B43_MMIO_TXE0_MMPLCP1 0x512 +#define B43_MMIO_TXE0_PHYCTL1 0x514 +#define B43_MMIO_XMTFIFODEF 0x520 +#define B43_MMIO_XMTFIFO_FRAME_CNT 0x522 /* core rev>= 16 only */ +#define B43_MMIO_XMTFIFO_BYTE_CNT 0x524 /* core rev>= 16 only */ +#define B43_MMIO_XMTFIFO_HEAD 0x526 /* core rev>= 16 only */ +#define B43_MMIO_XMTFIFO_RD_PTR 0x528 /* core rev>= 16 only */ +#define B43_MMIO_XMTFIFO_WR_PTR 0x52A /* core rev>= 16 only */ +#define B43_MMIO_XMTFIFODEF1 0x52C /* core rev>= 16 only */ +#define B43_MMIO_XMTFIFOCMD 0x540 +#define B43_MMIO_XMTFIFOFLUSH 0x542 +#define B43_MMIO_XMTFIFOTHRESH 0x544 +#define B43_MMIO_XMTFIFORDY 0x546 +#define B43_MMIO_XMTFIFOPRIRDY 0x548 +#define B43_MMIO_XMTFIFORQPRI 0x54A +#define B43_MMIO_XMTTPLATETXPTR 0x54C +#define B43_MMIO_XMTTPLATEPTR 0x550 +#define B43_MMIO_SMPL_CLCT_STRPTR 0x552 /* core rev>= 22 only */ +#define B43_MMIO_SMPL_CLCT_STPPTR 0x554 /* core rev>= 22 only */ +#define B43_MMIO_SMPL_CLCT_CURPTR 0x556 /* core rev>= 22 only */ +#define B43_MMIO_XMTTPLATEDATALO 0x560 +#define B43_MMIO_XMTTPLATEDATAHI 0x562 +#define B43_MMIO_XMTSEL 0x568 +#define B43_MMIO_XMTTXCNT 0x56A +#define B43_MMIO_XMTTXSHMADDR 0x56C #define B43_MMIO_TSF_CFP_START_LOW 0x604 #define B43_MMIO_TSF_CFP_START_HIGH 0x606 #define B43_MMIO_TSF_CFP_PRETBTT 0x612 +#define B43_MMIO_TSF_CLK_FRAC_LOW 0x62E +#define B43_MMIO_TSF_CLK_FRAC_HIGH 0x630 #define B43_MMIO_TSF_0 0x632 /* core rev < 3 only */ #define B43_MMIO_TSF_1 0x634 /* core rev < 3 only */ #define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */ #define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */ #define B43_MMIO_RNG 0x65A #define B43_MMIO_IFSSLOT 0x684 /* Interframe slot time */ -#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */ +#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */ +#define B43_MMIO_IFSSTAT 0x690 +#define B43_MMIO_IFSMEDBUSYCTL 0x692 +#define B43_MMIO_IFTXDUR 0x694 #define B43_MMIO_IFSCTL_USE_EDCF 0x0004 #define B43_MMIO_POWERUP_DELAY 0x6A8 #define B43_MMIO_BTCOEX_CTL 0x6B4 /* Bluetooth Coexistence Control */ #define B43_MMIO_BTCOEX_STAT 0x6B6 /* Bluetooth Coexistence Status */ #define B43_MMIO_BTCOEX_TXCTL 0x6B8 /* Bluetooth Coexistence Transmit Control */ +#define B43_MMIO_WEPCTL 0x7C0 /* SPROM boardflags_lo values */ #define B43_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ @@ -594,6 +629,7 @@ struct b43_dma { struct b43_dmaring *rx_ring; u32 translation; /* Routing bits */ + bool translation_in_low; /* Should translation bit go into low addr? */ bool parity; /* Check for parity */ }; @@ -694,6 +730,12 @@ struct b43_firmware_file { enum b43_firmware_file_type type; }; +enum b43_firmware_hdr_format { + B43_FW_HDR_598, + B43_FW_HDR_410, + B43_FW_HDR_351, +}; + /* Pointers to the firmware data and meta information about it. */ struct b43_firmware { /* Microcode */ @@ -710,6 +752,9 @@ struct b43_firmware { /* Firmware patchlevel */ u16 patch; + /* Format of header used by firmware */ + enum b43_firmware_hdr_format hdr_format; + /* Set to true, if we are using an opensource firmware. * Use this to check for proprietary vs opensource. */ bool opensource; @@ -875,7 +920,7 @@ struct b43_wl { struct b43_leds leds; /* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */ - u8 pio_scratchspace[110] __attribute__((__aligned__(8))); + u8 pio_scratchspace[118] __attribute__((__aligned__(8))); u8 pio_tailspace[4] __attribute__((__aligned__(8))); }; @@ -965,12 +1010,6 @@ static inline bool b43_using_pio_transfers(struct b43_wldev *dev) return dev->__using_pio_transfers; } -#ifdef CONFIG_B43_FORCE_PIO -# define B43_PIO_DEFAULT 1 -#else -# define B43_PIO_DEFAULT 0 -#endif - /* Message printing */ void b43info(struct b43_wl *wl, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c index 05f6c7bff6ab..424692df239d 100644 --- a/drivers/net/wireless/b43/bus.c +++ b/drivers/net/wireless/b43/bus.c @@ -3,6 +3,8 @@ Broadcom B43 wireless driver Bus abstraction layer + Copyright (c) 2011 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 481e534534eb..5e45604f0f5d 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -47,6 +47,38 @@ * into separate slots. */ #define TX_SLOTS_PER_FRAME 2 +static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr, + enum b43_addrtype addrtype) +{ + u32 uninitialized_var(addr); + + switch (addrtype) { + case B43_DMA_ADDR_LOW: + addr = lower_32_bits(dmaaddr); + if (dma->translation_in_low) { + addr &= ~SSB_DMA_TRANSLATION_MASK; + addr |= dma->translation; + } + break; + case B43_DMA_ADDR_HIGH: + addr = upper_32_bits(dmaaddr); + if (!dma->translation_in_low) { + addr &= ~SSB_DMA_TRANSLATION_MASK; + addr |= dma->translation; + } + break; + case B43_DMA_ADDR_EXT: + if (dma->translation_in_low) + addr = lower_32_bits(dmaaddr); + else + addr = upper_32_bits(dmaaddr); + addr &= SSB_DMA_TRANSLATION_MASK; + addr >>= SSB_DMA_TRANSLATION_SHIFT; + break; + } + + return addr; +} /* 32bit DMA ops. */ static @@ -77,10 +109,9 @@ static void op32_fill_descriptor(struct b43_dmaring *ring, slot = (int)(&(desc->dma32) - descbase); B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); - addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK); - addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; - addr |= ring->dev->dma.translation; + addr = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW); + addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT); + ctl = bufsize & B43_DMA32_DCTL_BYTECNT; if (slot == ring->nr_slots - 1) ctl |= B43_DMA32_DCTL_DTABLEEND; @@ -170,11 +201,10 @@ static void op64_fill_descriptor(struct b43_dmaring *ring, slot = (int)(&(desc->dma64) - descbase); B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); - addrlo = (u32) (dmaaddr & 0xFFFFFFFF); - addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); - addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; - addrhi |= ring->dev->dma.translation; + addrlo = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_LOW); + addrhi = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_HIGH); + addrext = b43_dma_address(&ring->dev->dma, dmaaddr, B43_DMA_ADDR_EXT); + if (slot == ring->nr_slots - 1) ctl0 |= B43_DMA64_DCTL0_DTABLEEND; if (start) @@ -389,33 +419,34 @@ static int alloc_ringmemory(struct b43_dmaring *ring) gfp_t flags = GFP_KERNEL; /* The specs call for 4K buffers for 30- and 32-bit DMA with 4K - * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing - * has shown that 4K is sufficient for the latter as long as the buffer - * does not cross an 8K boundary. - * - * For unknown reasons - possibly a hardware error - the BCM4311 rev - * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, - * which accounts for the GFP_DMA flag below. - * - * The flags here must match the flags in free_ringmemory below! + * alignment and 8K buffers for 64-bit DMA with 8K alignment. + * In practice we could use smaller buffers for the latter, but the + * alignment is really important because of the hardware bug. If bit + * 0x00001000 is used in DMA address, some hardware (like BCM4331) + * copies that bit into B43_DMA64_RXSTATUS and we get false values from + * B43_DMA64_RXSTATDPTR. Let's just use 8K buffers even if we don't use + * more than 256 slots for ring. */ - if (ring->type == B43_DMA_64BIT) - flags |= GFP_DMA; + u16 ring_mem_size = (ring->type == B43_DMA_64BIT) ? + B43_DMA64_RINGMEMSIZE : B43_DMA32_RINGMEMSIZE; + ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev, - B43_DMA_RINGMEMSIZE, - &(ring->dmabase), flags); + ring_mem_size, &(ring->dmabase), + flags); if (!ring->descbase) { b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); return -ENOMEM; } - memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE); + memset(ring->descbase, 0, ring_mem_size); return 0; } static void free_ringmemory(struct b43_dmaring *ring) { - dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE, + u16 ring_mem_size = (ring->type == B43_DMA_64BIT) ? + B43_DMA64_RINGMEMSIZE : B43_DMA32_RINGMEMSIZE; + dma_free_coherent(ring->dev->dev->dma_dev, ring_mem_size, ring->descbase, ring->dmabase); } @@ -658,41 +689,37 @@ static int dmacontroller_setup(struct b43_dmaring *ring) int err = 0; u32 value; u32 addrext; - u32 trans = ring->dev->dma.translation; bool parity = ring->dev->dma.parity; + u32 addrlo; + u32 addrhi; if (ring->tx) { if (ring->type == B43_DMA_64BIT) { u64 ringbase = (u64) (ring->dmabase); + addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT); + addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW); + addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH); - addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; value = B43_DMA64_TXENABLE; value |= (addrext << B43_DMA64_TXADDREXT_SHIFT) & B43_DMA64_TXADDREXT_MASK; if (!parity) value |= B43_DMA64_TXPARITYDISABLE; b43_dma_write(ring, B43_DMA64_TXCTL, value); - b43_dma_write(ring, B43_DMA64_TXRINGLO, - (ringbase & 0xFFFFFFFF)); - b43_dma_write(ring, B43_DMA64_TXRINGHI, - ((ringbase >> 32) & - ~SSB_DMA_TRANSLATION_MASK) - | trans); + b43_dma_write(ring, B43_DMA64_TXRINGLO, addrlo); + b43_dma_write(ring, B43_DMA64_TXRINGHI, addrhi); } else { u32 ringbase = (u32) (ring->dmabase); + addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT); + addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW); - addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; value = B43_DMA32_TXENABLE; value |= (addrext << B43_DMA32_TXADDREXT_SHIFT) & B43_DMA32_TXADDREXT_MASK; if (!parity) value |= B43_DMA32_TXPARITYDISABLE; b43_dma_write(ring, B43_DMA32_TXCTL, value); - b43_dma_write(ring, B43_DMA32_TXRING, - (ringbase & ~SSB_DMA_TRANSLATION_MASK) - | trans); + b43_dma_write(ring, B43_DMA32_TXRING, addrlo); } } else { err = alloc_initial_descbuffers(ring); @@ -700,9 +727,10 @@ static int dmacontroller_setup(struct b43_dmaring *ring) goto out; if (ring->type == B43_DMA_64BIT) { u64 ringbase = (u64) (ring->dmabase); + addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT); + addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW); + addrhi = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_HIGH); - addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT); value |= B43_DMA64_RXENABLE; value |= (addrext << B43_DMA64_RXADDREXT_SHIFT) @@ -710,19 +738,15 @@ static int dmacontroller_setup(struct b43_dmaring *ring) if (!parity) value |= B43_DMA64_RXPARITYDISABLE; b43_dma_write(ring, B43_DMA64_RXCTL, value); - b43_dma_write(ring, B43_DMA64_RXRINGLO, - (ringbase & 0xFFFFFFFF)); - b43_dma_write(ring, B43_DMA64_RXRINGHI, - ((ringbase >> 32) & - ~SSB_DMA_TRANSLATION_MASK) - | trans); + b43_dma_write(ring, B43_DMA64_RXRINGLO, addrlo); + b43_dma_write(ring, B43_DMA64_RXRINGHI, addrhi); b43_dma_write(ring, B43_DMA64_RXINDEX, ring->nr_slots * sizeof(struct b43_dmadesc64)); } else { u32 ringbase = (u32) (ring->dmabase); + addrext = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_EXT); + addrlo = b43_dma_address(&ring->dev->dma, ringbase, B43_DMA_ADDR_LOW); - addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT); value |= B43_DMA32_RXENABLE; value |= (addrext << B43_DMA32_RXADDREXT_SHIFT) @@ -730,9 +754,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring) if (!parity) value |= B43_DMA32_RXPARITYDISABLE; b43_dma_write(ring, B43_DMA32_RXCTL, value); - b43_dma_write(ring, B43_DMA32_RXRING, - (ringbase & ~SSB_DMA_TRANSLATION_MASK) - | trans); + b43_dma_write(ring, B43_DMA32_RXRING, addrlo); b43_dma_write(ring, B43_DMA32_RXINDEX, ring->nr_slots * sizeof(struct b43_dmadesc32)); } @@ -872,8 +894,17 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev, ring->current_slot = -1; } else { if (ring->index == 0) { - ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE; - ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET; + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: + ring->rx_buffersize = B43_DMA0_RX_FW598_BUFSIZE; + ring->frameoffset = B43_DMA0_RX_FW598_FO; + break; + case B43_FW_HDR_410: + case B43_FW_HDR_351: + ring->rx_buffersize = B43_DMA0_RX_FW351_BUFSIZE; + ring->frameoffset = B43_DMA0_RX_FW351_FO; + break; + } } else B43_WARN_ON(1); } @@ -1066,6 +1097,25 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask) return 0; } +/* Some hardware with 64-bit DMA seems to be bugged and looks for translation + * bit in low address word instead of high one. + */ +static bool b43_dma_translation_in_low_word(struct b43_wldev *dev, + enum b43_dmatype type) +{ + if (type != B43_DMA_64BIT) + return 1; + +#ifdef CONFIG_B43_SSB + if (dev->dev->bus_type == B43_BUS_SSB && + dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI && + !(dev->dev->sdev->bus->host_pci->is_pcie && + ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)) + return 1; +#endif + return 0; +} + int b43_dma_init(struct b43_wldev *dev) { struct b43_dma *dma = &dev->dma; @@ -1091,6 +1141,7 @@ int b43_dma_init(struct b43_wldev *dev) break; #endif } + dma->translation_in_low = b43_dma_translation_in_low_word(dev, type); dma->parity = true; #ifdef CONFIG_B43_BCMA diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h index cdf87094efe8..315b96ed1d90 100644 --- a/drivers/net/wireless/b43/dma.h +++ b/drivers/net/wireless/b43/dma.h @@ -161,13 +161,17 @@ struct b43_dmadesc_generic { } __packed; /* Misc DMA constants */ -#define B43_DMA_RINGMEMSIZE PAGE_SIZE -#define B43_DMA0_RX_FRAMEOFFSET 30 +#define B43_DMA32_RINGMEMSIZE 4096 +#define B43_DMA64_RINGMEMSIZE 8192 +/* Offset of frame with actual data */ +#define B43_DMA0_RX_FW598_FO 38 +#define B43_DMA0_RX_FW351_FO 30 /* DMA engine tuning knobs */ #define B43_TXRING_SLOTS 256 #define B43_RXRING_SLOTS 64 -#define B43_DMA0_RX_BUFFERSIZE (B43_DMA0_RX_FRAMEOFFSET + IEEE80211_MAX_FRAME_LEN) +#define B43_DMA0_RX_FW598_BUFSIZE (B43_DMA0_RX_FW598_FO + IEEE80211_MAX_FRAME_LEN) +#define B43_DMA0_RX_FW351_BUFSIZE (B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN) /* Pointer poison */ #define B43_DMA_PTR_POISON ((void *)ERR_PTR(-ENOMEM)) @@ -212,6 +216,12 @@ enum b43_dmatype { B43_DMA_64BIT = 64, }; +enum b43_addrtype { + B43_DMA_ADDR_LOW, + B43_DMA_ADDR_HIGH, + B43_DMA_ADDR_EXT, +}; + struct b43_dmaring { /* Lowlevel DMA ops. */ const struct b43_dma_ops *ops; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index e293a7921bf0..7cf4125a1624 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -7,6 +7,7 @@ Copyright (c) 2005-2009 Michael Buesch <m@bues.ch> Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> + Copyright (c) 2010-2011 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> SDIO support Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es> @@ -37,7 +38,6 @@ #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/firmware.h> -#include <linux/wireless.h> #include <linux/workqueue.h> #include <linux/skbuff.h> #include <linux/io.h> @@ -65,9 +65,9 @@ MODULE_AUTHOR("Martin Langer"); MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); MODULE_AUTHOR("Gábor Stefanik"); +MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki"); MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); MODULE_FIRMWARE("b43/ucode11.fw"); MODULE_FIRMWARE("b43/ucode13.fw"); MODULE_FIRMWARE("b43/ucode14.fw"); @@ -109,12 +109,13 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT; module_param_named(verbose, b43_modparam_verbose, int, 0644); MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug"); -static int b43_modparam_pio = B43_PIO_DEFAULT; +static int b43_modparam_pio = 0; module_param_named(pio, b43_modparam_pio, int, 0644); MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO"); #ifdef CONFIG_B43_BCMA static const struct bcma_device_id b43_bcma_tbl[] = { + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x11, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS), @@ -320,6 +321,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev); static int b43_wireless_core_start(struct b43_wldev *dev); +static void b43_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed); static int b43_ratelimit(struct b43_wl *wl) { @@ -724,52 +729,59 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on) for (i = 0; i < 5; i++) b43_ram_write(dev, i * 4, buffer[i]); - b43_write16(dev, 0x0568, 0x0000); + b43_write16(dev, B43_MMIO_XMTSEL, 0x0000); + if (dev->dev->core_rev < 11) - b43_write16(dev, 0x07C0, 0x0000); + b43_write16(dev, B43_MMIO_WEPCTL, 0x0000); else - b43_write16(dev, 0x07C0, 0x0100); + b43_write16(dev, B43_MMIO_WEPCTL, 0x0100); + value = (ofdm ? 0x41 : 0x40); - b43_write16(dev, 0x050C, value); - if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP)) - b43_write16(dev, 0x0514, 0x1A02); - b43_write16(dev, 0x0508, 0x0000); - b43_write16(dev, 0x050A, 0x0000); - b43_write16(dev, 0x054C, 0x0000); - b43_write16(dev, 0x056A, 0x0014); - b43_write16(dev, 0x0568, 0x0826); - b43_write16(dev, 0x0500, 0x0000); - if (!pa_on && (phy->type == B43_PHYTYPE_N)) { - //SPEC TODO - } + b43_write16(dev, B43_MMIO_TXE0_PHYCTL, value); + if (phy->type == B43_PHYTYPE_N || phy->type == B43_PHYTYPE_LP || + phy->type == B43_PHYTYPE_LCN) + b43_write16(dev, B43_MMIO_TXE0_PHYCTL1, 0x1A02); + + b43_write16(dev, B43_MMIO_TXE0_WM_0, 0x0000); + b43_write16(dev, B43_MMIO_TXE0_WM_1, 0x0000); + + b43_write16(dev, B43_MMIO_XMTTPLATETXPTR, 0x0000); + b43_write16(dev, B43_MMIO_XMTTXCNT, 0x0014); + b43_write16(dev, B43_MMIO_XMTSEL, 0x0826); + b43_write16(dev, B43_MMIO_TXE0_CTL, 0x0000); + + if (!pa_on && phy->type == B43_PHYTYPE_N) + ; /*b43_nphy_pa_override(dev, false) */ switch (phy->type) { case B43_PHYTYPE_N: - b43_write16(dev, 0x0502, 0x00D0); + case B43_PHYTYPE_LCN: + b43_write16(dev, B43_MMIO_TXE0_AUX, 0x00D0); break; case B43_PHYTYPE_LP: - b43_write16(dev, 0x0502, 0x0050); + b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0050); break; default: - b43_write16(dev, 0x0502, 0x0030); + b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0030); } + b43_read16(dev, B43_MMIO_TXE0_AUX); if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5) b43_radio_write16(dev, 0x0051, 0x0017); for (i = 0x00; i < max_loop; i++) { - value = b43_read16(dev, 0x050E); + value = b43_read16(dev, B43_MMIO_TXE0_STATUS); if (value & 0x0080) break; udelay(10); } for (i = 0x00; i < 0x0A; i++) { - value = b43_read16(dev, 0x050E); + value = b43_read16(dev, B43_MMIO_TXE0_STATUS); if (value & 0x0400) break; udelay(10); } for (i = 0x00; i < 0x19; i++) { - value = b43_read16(dev, 0x0690); + value = b43_read16(dev, B43_MMIO_IFSSTAT); if (!(value & 0x0100)) break; udelay(10); @@ -2511,6 +2523,12 @@ static int b43_upload_microcode(struct b43_wldev *dev) } dev->fw.rev = fwrev; dev->fw.patch = fwpatch; + if (dev->fw.rev >= 598) + dev->fw.hdr_format = B43_FW_HDR_598; + else if (dev->fw.rev >= 410) + dev->fw.hdr_format = B43_FW_HDR_410; + else + dev->fw.hdr_format = B43_FW_HDR_351; dev->fw.opensource = (fwdate == 0xFFFF); /* Default to use-all-queues. */ @@ -2558,7 +2576,7 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->fw.rev, dev->fw.patch); wiphy->hw_version = dev->dev->core_id; - if (b43_is_old_txhdr_format(dev)) { + if (dev->fw.hdr_format == B43_FW_HDR_351) { /* We're over the deadline, but we keep support for old fw * until it turns out to be in major conflict with something new. */ b43warn(dev->wl, "You are using an old firmware image. " @@ -2944,6 +2962,8 @@ static void b43_rate_memory_init(struct b43_wldev *dev) case B43_PHYTYPE_G: case B43_PHYTYPE_N: case B43_PHYTYPE_LP: + case B43_PHYTYPE_HT: + case B43_PHYTYPE_LCN: b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1); b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1); @@ -3539,7 +3559,8 @@ static void b43_qos_init(struct b43_wldev *dev) b43dbg(dev->wl, "QoS enabled\n"); } -static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue, +static int b43_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 _queue, const struct ieee80211_tx_queue_params *params) { struct b43_wl *wl = hw_to_b43_wl(hw); @@ -3586,7 +3607,7 @@ static int b43_op_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 b43_op_get_tsf(struct ieee80211_hw *hw) +static u64 b43_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -3605,7 +3626,8 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void b43_op_set_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u64 tsf) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; @@ -3779,14 +3801,24 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) struct ieee80211_conf *conf = &hw->conf; int antenna; int err = 0; + bool reload_bss = false; mutex_lock(&wl->mutex); + dev = wl->current_dev; + /* Switch the band (if necessary). This might change the active core. */ err = b43_switch_band(wl, conf->channel); if (err) goto out_unlock_mutex; - dev = wl->current_dev; + + /* Need to reload all settings if the core changed */ + if (dev != wl->current_dev) { + dev = wl->current_dev; + changed = ~0; + reload_bss = true; + } + phy = &dev->phy; if (conf_is_ht(conf)) @@ -3847,6 +3879,9 @@ out_mac_enable: out_unlock_mutex: mutex_unlock(&wl->mutex); + if (wl->vif && reload_bss) + b43_op_bss_info_changed(hw, wl->vif, &wl->vif->bss_conf, ~0); + return err; } @@ -3935,7 +3970,8 @@ static void b43_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON_INT && (b43_is_mode(wl, NL80211_IFTYPE_AP) || b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT) || - b43_is_mode(wl, NL80211_IFTYPE_ADHOC))) + b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) && + conf->beacon_int) b43_set_beacon_int(dev, conf->beacon_int); if (changed & BSS_CHANGED_BASIC_RATES) @@ -4108,10 +4144,13 @@ out_unlock: * because the core might be gone away while we unlocked the mutex. */ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev) { - struct b43_wl *wl = dev->wl; + struct b43_wl *wl; struct b43_wldev *orig_dev; u32 mask; + if (!dev) + return NULL; + wl = dev->wl; redo: if (!dev || b43_status(dev) < B43_STAT_STARTED) return dev; @@ -4630,8 +4669,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev) b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); if (b43_bus_host_is_pcmcia(dev->dev) || - b43_bus_host_is_sdio(dev->dev) || - dev->use_pio) { + b43_bus_host_is_sdio(dev->dev)) { + dev->__using_pio_transfers = 1; + err = b43_pio_init(dev); + } else if (dev->use_pio) { + b43warn(dev->wl, "Forced PIO by use_pio module parameter. " + "This should not be needed and will result in lower " + "performance.\n"); dev->__using_pio_transfers = 1; err = b43_pio_init(dev); } else { @@ -4703,6 +4747,9 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, out_mutex_unlock: mutex_unlock(&wl->mutex); + if (err == 0) + b43_op_bss_info_changed(hw, vif, &vif->bss_conf, ~0); + return err; } @@ -4773,6 +4820,9 @@ static int b43_op_start(struct ieee80211_hw *hw) out_mutex_unlock: mutex_unlock(&wl->mutex); + /* reload configuration */ + b43_op_config(hw, ~0); + return err; } @@ -4929,10 +4979,18 @@ out: if (err) wl->current_dev = NULL; /* Failed to init the dev. */ mutex_unlock(&wl->mutex); - if (err) + + if (err) { b43err(wl, "Controller restart FAILED\n"); - else - b43info(wl, "Controller restarted\n"); + return; + } + + /* reload configuration */ + b43_op_config(wl->hw, ~0); + if (wl->vif) + b43_op_bss_info_changed(wl->hw, wl->vif, &wl->vif->bss_conf, ~0); + + b43info(wl, "Controller restarted\n"); } static int b43_setup_bands(struct b43_wldev *dev, @@ -5417,8 +5475,7 @@ static void b43_print_driverinfo(void) feat_sdio = "S"; #endif printk(KERN_INFO "Broadcom 43xx driver loaded " - "[ Features: %s%s%s%s%s, Firmware-ID: " - B43_SUPPORTED_FIRMWARE_ID " ]\n", + "[ Features: %s%s%s%s%s ]\n", feat_pci, feat_pcmcia, feat_nphy, feat_leds, feat_sdio); } diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index 07f009ff5ee2..3ea44bb03684 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -448,6 +448,38 @@ bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type) channel_type == NL80211_CHAN_HT40PLUS); } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ +void b43_phy_force_clock(struct b43_wldev *dev, bool force) +{ + u32 tmp; + + WARN_ON(dev->phy.type != B43_PHYTYPE_N && + dev->phy.type != B43_PHYTYPE_HT); + + switch (dev->dev->bus_type) { +#ifdef CONFIG_B43_BCMA + case B43_BUS_BCMA: + tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); + if (force) + tmp |= BCMA_IOCTL_FGC; + else + tmp &= ~BCMA_IOCTL_FGC; + bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); + break; +#endif +#ifdef CONFIG_B43_SSB + case B43_BUS_SSB: + tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); + if (force) + tmp |= SSB_TMSLOW_FGC; + else + tmp &= ~SSB_TMSLOW_FGC; + ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); + break; +#endif + } +} + /* http://bcm-v4.sipsolutions.net/802.11/PHY/Cordic */ struct b43_c32 b43_cordic(int theta) { diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h index aa77ba612a92..9233b13fc16d 100644 --- a/drivers/net/wireless/b43/phy_common.h +++ b/drivers/net/wireless/b43/phy_common.h @@ -444,6 +444,8 @@ void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on); bool b43_channel_type_is_40mhz(enum nl80211_channel_type channel_type); +void b43_phy_force_clock(struct b43_wldev *dev, bool force); + struct b43_c32 b43_cordic(int theta); #endif /* LINUX_B43_PHY_COMMON_H_ */ diff --git a/drivers/net/wireless/b43/phy_ht.c b/drivers/net/wireless/b43/phy_ht.c index 7c40919651a7..7416c5e9154d 100644 --- a/drivers/net/wireless/b43/phy_ht.c +++ b/drivers/net/wireless/b43/phy_ht.c @@ -3,6 +3,8 @@ Broadcom B43 wireless driver IEEE 802.11n HT-PHY support + Copyright (c) 2011 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -152,6 +154,92 @@ static void b43_radio_2059_init(struct b43_wldev *dev) } /************************************************** + * Various PHY ops + **************************************************/ + +static void b43_phy_ht_zero_extg(struct b43_wldev *dev) +{ + u8 i, j; + u16 base[] = { 0x40, 0x60, 0x80 }; + + for (i = 0; i < ARRAY_SIZE(base); i++) { + for (j = 0; j < 4; j++) + b43_phy_write(dev, B43_PHY_EXTG(base[i] + j), 0); + } + + for (i = 0; i < ARRAY_SIZE(base); i++) + b43_phy_write(dev, B43_PHY_EXTG(base[i] + 0xc), 0); +} + +/* Some unknown AFE (Analog Frondned) op */ +static void b43_phy_ht_afe_unk1(struct b43_wldev *dev) +{ + u8 i; + + const u16 ctl_regs[3][2] = { + { B43_PHY_HT_AFE_CTL1, B43_PHY_HT_AFE_CTL2 }, + { B43_PHY_HT_AFE_CTL3, B43_PHY_HT_AFE_CTL4 }, + { B43_PHY_HT_AFE_CTL5, B43_PHY_HT_AFE_CTL6}, + }; + + for (i = 0; i < 3; i++) { + /* TODO: verify masks&sets */ + b43_phy_set(dev, ctl_regs[i][1], 0x4); + b43_phy_set(dev, ctl_regs[i][0], 0x4); + b43_phy_mask(dev, ctl_regs[i][1], ~0x1); + b43_phy_set(dev, ctl_regs[i][0], 0x1); + b43_httab_write(dev, B43_HTTAB16(8, 5 + (i * 0x10)), 0); + b43_phy_mask(dev, ctl_regs[i][0], ~0x4); + } +} + +static void b43_phy_ht_force_rf_sequence(struct b43_wldev *dev, u16 rf_seq) +{ + u8 i; + + u16 save_seq_mode = b43_phy_read(dev, B43_PHY_HT_RF_SEQ_MODE); + b43_phy_set(dev, B43_PHY_HT_RF_SEQ_MODE, 0x3); + + b43_phy_set(dev, B43_PHY_HT_RF_SEQ_TRIG, rf_seq); + for (i = 0; i < 200; i++) { + if (!(b43_phy_read(dev, B43_PHY_HT_RF_SEQ_STATUS) & rf_seq)) { + i = 0; + break; + } + msleep(1); + } + if (i) + b43err(dev->wl, "Forcing RF sequence timeout\n"); + + b43_phy_write(dev, B43_PHY_HT_RF_SEQ_MODE, save_seq_mode); +} + +static void b43_phy_ht_read_clip_detection(struct b43_wldev *dev, u16 *clip_st) +{ + clip_st[0] = b43_phy_read(dev, B43_PHY_HT_C1_CLIP1THRES); + clip_st[1] = b43_phy_read(dev, B43_PHY_HT_C2_CLIP1THRES); + clip_st[2] = b43_phy_read(dev, B43_PHY_HT_C3_CLIP1THRES); +} + +static void b43_phy_ht_bphy_init(struct b43_wldev *dev) +{ + unsigned int i; + u16 val; + + val = 0x1E1F; + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val); + val -= 0x202; + } + val = 0x3E3F; + for (i = 0; i < 16; i++) { + b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val); + val -= 0x202; + } + b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668); +} + +/************************************************** * Channel switching ops. **************************************************/ @@ -255,8 +343,125 @@ static void b43_phy_ht_op_prepare_structs(struct b43_wldev *dev) static int b43_phy_ht_op_init(struct b43_wldev *dev) { + u16 tmp; + u16 clip_state[3]; + b43_phy_ht_tables_init(dev); + b43_phy_mask(dev, 0x0be, ~0x2); + b43_phy_set(dev, 0x23f, 0x7ff); + b43_phy_set(dev, 0x240, 0x7ff); + b43_phy_set(dev, 0x241, 0x7ff); + + b43_phy_ht_zero_extg(dev); + + b43_phy_mask(dev, B43_PHY_EXTG(0), ~0x3); + + b43_phy_write(dev, B43_PHY_HT_AFE_CTL1, 0); + b43_phy_write(dev, B43_PHY_HT_AFE_CTL3, 0); + b43_phy_write(dev, B43_PHY_HT_AFE_CTL5, 0); + + b43_phy_write(dev, B43_PHY_EXTG(0x103), 0x20); + b43_phy_write(dev, B43_PHY_EXTG(0x101), 0x20); + b43_phy_write(dev, 0x20d, 0xb8); + b43_phy_write(dev, B43_PHY_EXTG(0x14f), 0xc8); + b43_phy_write(dev, 0x70, 0x50); + b43_phy_write(dev, 0x1ff, 0x30); + + if (0) /* TODO: condition */ + ; /* TODO: PHY op on reg 0x217 */ + + b43_phy_read(dev, 0xb0); /* TODO: what for? */ + b43_phy_set(dev, 0xb0, 0x1); + + b43_phy_set(dev, 0xb1, 0x91); + b43_phy_write(dev, 0x32f, 0x0003); + b43_phy_write(dev, 0x077, 0x0010); + b43_phy_write(dev, 0x0b4, 0x0258); + b43_phy_mask(dev, 0x17e, ~0x4000); + + b43_phy_write(dev, 0x0b9, 0x0072); + + b43_httab_write_few(dev, B43_HTTAB16(7, 0x14e), 2, 0x010f, 0x010f); + b43_httab_write_few(dev, B43_HTTAB16(7, 0x15e), 2, 0x010f, 0x010f); + b43_httab_write_few(dev, B43_HTTAB16(7, 0x16e), 2, 0x010f, 0x010f); + + b43_phy_ht_afe_unk1(dev); + + b43_httab_write_few(dev, B43_HTTAB16(7, 0x130), 9, 0x777, 0x111, 0x111, + 0x777, 0x111, 0x111, 0x777, 0x111, 0x111); + + b43_httab_write(dev, B43_HTTAB16(7, 0x120), 0x0777); + b43_httab_write(dev, B43_HTTAB16(7, 0x124), 0x0777); + + b43_httab_write(dev, B43_HTTAB16(8, 0x00), 0x02); + b43_httab_write(dev, B43_HTTAB16(8, 0x10), 0x02); + b43_httab_write(dev, B43_HTTAB16(8, 0x20), 0x02); + + b43_httab_write_few(dev, B43_HTTAB16(8, 0x08), 4, + 0x8e, 0x96, 0x96, 0x96); + b43_httab_write_few(dev, B43_HTTAB16(8, 0x18), 4, + 0x8f, 0x9f, 0x9f, 0x9f); + b43_httab_write_few(dev, B43_HTTAB16(8, 0x28), 4, + 0x8f, 0x9f, 0x9f, 0x9f); + + b43_httab_write_few(dev, B43_HTTAB16(8, 0x0c), 4, 0x2, 0x2, 0x2, 0x2); + b43_httab_write_few(dev, B43_HTTAB16(8, 0x1c), 4, 0x2, 0x2, 0x2, 0x2); + b43_httab_write_few(dev, B43_HTTAB16(8, 0x2c), 4, 0x2, 0x2, 0x2, 0x2); + + b43_phy_maskset(dev, 0x0280, 0xff00, 0x3e); + b43_phy_maskset(dev, 0x0283, 0xff00, 0x3e); + b43_phy_maskset(dev, B43_PHY_OFDM(0x0141), 0xff00, 0x46); + b43_phy_maskset(dev, 0x0283, 0xff00, 0x40); + + b43_httab_write_few(dev, B43_HTTAB16(00, 0x8), 4, + 0x09, 0x0e, 0x13, 0x18); + b43_httab_write_few(dev, B43_HTTAB16(01, 0x8), 4, + 0x09, 0x0e, 0x13, 0x18); + /* TODO: Did wl mean 2 instead of 40? */ + b43_httab_write_few(dev, B43_HTTAB16(40, 0x8), 4, + 0x09, 0x0e, 0x13, 0x18); + + b43_phy_maskset(dev, B43_PHY_OFDM(0x24), 0x3f, 0xd); + b43_phy_maskset(dev, B43_PHY_OFDM(0x64), 0x3f, 0xd); + b43_phy_maskset(dev, B43_PHY_OFDM(0xa4), 0x3f, 0xd); + + b43_phy_set(dev, B43_PHY_EXTG(0x060), 0x1); + b43_phy_set(dev, B43_PHY_EXTG(0x064), 0x1); + b43_phy_set(dev, B43_PHY_EXTG(0x080), 0x1); + b43_phy_set(dev, B43_PHY_EXTG(0x084), 0x1); + + /* Copy some tables entries */ + tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x144)); + b43_httab_write(dev, B43_HTTAB16(7, 0x14a), tmp); + tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x154)); + b43_httab_write(dev, B43_HTTAB16(7, 0x15a), tmp); + tmp = b43_httab_read(dev, B43_HTTAB16(7, 0x164)); + b43_httab_write(dev, B43_HTTAB16(7, 0x16a), tmp); + + /* Reset CCA */ + b43_phy_force_clock(dev, true); + tmp = b43_phy_read(dev, B43_PHY_HT_BBCFG); + b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp | B43_PHY_HT_BBCFG_RSTCCA); + b43_phy_write(dev, B43_PHY_HT_BBCFG, tmp & ~B43_PHY_HT_BBCFG_RSTCCA); + b43_phy_force_clock(dev, false); + + b43_mac_phy_clock_set(dev, true); + + b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RX2TX); + b43_phy_ht_force_rf_sequence(dev, B43_PHY_HT_RF_SEQ_TRIG_RST2RX); + + /* TODO: PHY op on reg 0xb0 */ + + /* TODO: Should we restore it? Or store it in global PHY info? */ + b43_phy_ht_read_clip_detection(dev, clip_state); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_ht_bphy_init(dev); + + b43_httab_write_bulk(dev, B43_HTTAB32(0x1a, 0xc0), + B43_HTTAB_1A_C0_LATE_SIZE, b43_httab_0x1a_0xc0_late); + return 0; } diff --git a/drivers/net/wireless/b43/phy_ht.h b/drivers/net/wireless/b43/phy_ht.h index 7ad7affc8df0..6544c4293b34 100644 --- a/drivers/net/wireless/b43/phy_ht.h +++ b/drivers/net/wireless/b43/phy_ht.h @@ -4,7 +4,11 @@ #include "phy_common.h" +#define B43_PHY_HT_BBCFG 0x001 /* BB config */ +#define B43_PHY_HT_BBCFG_RSTCCA 0x4000 /* Reset CCA */ +#define B43_PHY_HT_BBCFG_RSTRX 0x8000 /* Reset RX */ #define B43_PHY_HT_BANDCTL 0x009 /* Band control */ +#define B43_PHY_HT_BANDCTL_5GHZ 0x0001 /* Use the 5GHz band */ #define B43_PHY_HT_TABLE_ADDR 0x072 /* Table address */ #define B43_PHY_HT_TABLE_DATALO 0x073 /* Table data low */ #define B43_PHY_HT_TABLE_DATAHI 0x074 /* Table data high */ @@ -15,6 +19,21 @@ #define B43_PHY_HT_BW5 0x1D2 #define B43_PHY_HT_BW6 0x1D3 +#define B43_PHY_HT_C1_CLIP1THRES B43_PHY_OFDM(0x00E) +#define B43_PHY_HT_C2_CLIP1THRES B43_PHY_OFDM(0x04E) +#define B43_PHY_HT_C3_CLIP1THRES B43_PHY_OFDM(0x08E) + +#define B43_PHY_HT_RF_SEQ_MODE B43_PHY_EXTG(0x000) +#define B43_PHY_HT_RF_SEQ_TRIG B43_PHY_EXTG(0x003) +#define B43_PHY_HT_RF_SEQ_TRIG_RX2TX 0x0001 /* RX2TX */ +#define B43_PHY_HT_RF_SEQ_TRIG_TX2RX 0x0002 /* TX2RX */ +#define B43_PHY_HT_RF_SEQ_TRIG_UPGH 0x0004 /* Update gain H */ +#define B43_PHY_HT_RF_SEQ_TRIG_UPGL 0x0008 /* Update gain L */ +#define B43_PHY_HT_RF_SEQ_TRIG_UPGU 0x0010 /* Update gain U */ +#define B43_PHY_HT_RF_SEQ_TRIG_RST2RX 0x0020 /* Reset to RX */ +#define B43_PHY_HT_RF_SEQ_STATUS B43_PHY_EXTG(0x004) +/* Values for the status are the same as for the trigger */ + #define B43_PHY_HT_RF_CTL1 B43_PHY_EXTG(0x010) #define B43_PHY_HT_AFE_CTL1 B43_PHY_EXTG(0x110) diff --git a/drivers/net/wireless/b43/phy_lcn.c b/drivers/net/wireless/b43/phy_lcn.c index 9f7dbbd5ced6..a13e28ef6246 100644 --- a/drivers/net/wireless/b43/phy_lcn.c +++ b/drivers/net/wireless/b43/phy_lcn.c @@ -3,6 +3,8 @@ Broadcom B43 wireless driver IEEE 802.11n LCN-PHY support + Copyright (c) 2011 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -18,6 +20,14 @@ the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, Boston, MA 02110-1301, USA. + This file incorporates work covered by the following copyright and + permission notice: + + Copyright (c) 2010 Broadcom Corporation + + 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. */ #include <linux/slab.h> @@ -27,12 +37,852 @@ #include "tables_phy_lcn.h" #include "main.h" +struct lcn_tx_gains { + u16 gm_gain; + u16 pga_gain; + u16 pad_gain; + u16 dac_gain; +}; + +struct lcn_tx_iir_filter { + u8 type; + u16 values[16]; +}; + +enum lcn_sense_type { + B43_SENSE_TEMP, + B43_SENSE_VBAT, +}; + +/* In theory it's PHY common function, move if needed */ +/* brcms_b_switch_macfreq */ +static void b43_phy_switch_macfreq(struct b43_wldev *dev, u8 spurmode) +{ + if (dev->dev->chip_id == 43224 || dev->dev->chip_id == 43225) { + switch (spurmode) { + case 2: /* 126 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); + break; + case 1: /* 123 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); + break; + default: /* 120 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8); + break; + } + } else if (dev->phy.type == B43_PHYTYPE_LCN) { + switch (spurmode) { + case 1: /* 82 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC); + break; + default: /* 80 Mhz */ + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD); + b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC); + break; + } + } +} + +/************************************************** + * Radio 2064. + **************************************************/ + +/* wlc_lcnphy_radio_2064_channel_tune_4313 */ +static void b43_radio_2064_channel_setup(struct b43_wldev *dev) +{ + u16 save[2]; + + b43_radio_set(dev, 0x09d, 0x4); + b43_radio_write(dev, 0x09e, 0xf); + + /* Channel specific values in theory, in practice always the same */ + b43_radio_write(dev, 0x02a, 0xb); + b43_radio_maskset(dev, 0x030, ~0x3, 0xa); + b43_radio_maskset(dev, 0x091, ~0x3, 0); + b43_radio_maskset(dev, 0x038, ~0xf, 0x7); + b43_radio_maskset(dev, 0x030, ~0xc, 0x8); + b43_radio_maskset(dev, 0x05e, ~0xf, 0x8); + b43_radio_maskset(dev, 0x05e, ~0xf0, 0x80); + b43_radio_write(dev, 0x06c, 0x80); + + save[0] = b43_radio_read(dev, 0x044); + save[1] = b43_radio_read(dev, 0x12b); + + b43_radio_set(dev, 0x044, 0x7); + b43_radio_set(dev, 0x12b, 0xe); + + /* TODO */ + + b43_radio_write(dev, 0x040, 0xfb); + + b43_radio_write(dev, 0x041, 0x9a); + b43_radio_write(dev, 0x042, 0xa3); + b43_radio_write(dev, 0x043, 0x0c); + + /* TODO */ + + b43_radio_set(dev, 0x044, 0x0c); + udelay(1); + + b43_radio_write(dev, 0x044, save[0]); + b43_radio_write(dev, 0x12b, save[1]); + + if (dev->phy.rev == 1) { + /* brcmsmac uses outdated 0x3 for 0x038 */ + b43_radio_write(dev, 0x038, 0x0); + b43_radio_write(dev, 0x091, 0x7); + } +} + +/* wlc_radio_2064_init */ +static void b43_radio_2064_init(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + b43_radio_write(dev, 0x09c, 0x0020); + b43_radio_write(dev, 0x105, 0x0008); + } else { + /* TODO */ + } + b43_radio_write(dev, 0x032, 0x0062); + b43_radio_write(dev, 0x033, 0x0019); + b43_radio_write(dev, 0x090, 0x0010); + b43_radio_write(dev, 0x010, 0x0000); + if (dev->phy.rev == 1) { + b43_radio_write(dev, 0x060, 0x007f); + b43_radio_write(dev, 0x061, 0x0072); + b43_radio_write(dev, 0x062, 0x007f); + } + b43_radio_write(dev, 0x01d, 0x0002); + b43_radio_write(dev, 0x01e, 0x0006); + + b43_phy_write(dev, 0x4ea, 0x4688); + b43_phy_maskset(dev, 0x4eb, ~0x7, 0x2); + b43_phy_mask(dev, 0x4eb, ~0x01c0); + b43_phy_maskset(dev, 0x46a, 0xff00, 0x19); + + b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x55), 0); + + b43_radio_mask(dev, 0x05b, (u16) ~0xff02); + b43_radio_set(dev, 0x004, 0x40); + b43_radio_set(dev, 0x120, 0x10); + b43_radio_set(dev, 0x078, 0x80); + b43_radio_set(dev, 0x129, 0x2); + b43_radio_set(dev, 0x057, 0x1); + b43_radio_set(dev, 0x05b, 0x2); + + /* TODO: wait for some bit to be set */ + b43_radio_read(dev, 0x05c); + + b43_radio_mask(dev, 0x05b, (u16) ~0xff02); + b43_radio_mask(dev, 0x057, (u16) ~0xff01); + + b43_phy_write(dev, 0x933, 0x2d6b); + b43_phy_write(dev, 0x934, 0x2d6b); + b43_phy_write(dev, 0x935, 0x2d6b); + b43_phy_write(dev, 0x936, 0x2d6b); + b43_phy_write(dev, 0x937, 0x016b); + + b43_radio_mask(dev, 0x057, (u16) ~0xff02); + b43_radio_write(dev, 0x0c2, 0x006f); +} + +/************************************************** + * Various PHY ops + **************************************************/ + +/* wlc_lcnphy_toggle_afe_pwdn */ +static void b43_phy_lcn_afe_set_unset(struct b43_wldev *dev) +{ + u16 afe_ctl2 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL2); + u16 afe_ctl1 = b43_phy_read(dev, B43_PHY_LCN_AFE_CTL1); + + b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 | 0x1); + b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 | 0x1); + + b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2 & ~0x1); + b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1 & ~0x1); + + b43_phy_write(dev, B43_PHY_LCN_AFE_CTL2, afe_ctl2); + b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1); +} + +/* wlc_lcnphy_get_pa_gain */ +static u16 b43_phy_lcn_get_pa_gain(struct b43_wldev *dev) +{ + return (b43_phy_read(dev, 0x4fb) & 0x7f00) >> 8; +} + +/* wlc_lcnphy_set_dac_gain */ +static void b43_phy_lcn_set_dac_gain(struct b43_wldev *dev, u16 dac_gain) +{ + u16 dac_ctrl; + + dac_ctrl = b43_phy_read(dev, 0x439); + dac_ctrl = dac_ctrl & 0xc7f; + dac_ctrl = dac_ctrl | (dac_gain << 7); + b43_phy_maskset(dev, 0x439, ~0xfff, dac_ctrl); +} + +/* wlc_lcnphy_set_bbmult */ +static void b43_phy_lcn_set_bbmult(struct b43_wldev *dev, u8 m0) +{ + b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x57), m0 << 8); +} + +/* wlc_lcnphy_clear_tx_power_offsets */ +static void b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev *dev) +{ + u8 i; + + if (1) { /* FIXME */ + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x340); + for (i = 0; i < 30; i++) { + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0); + } + } + + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, (0x7 << 10) | 0x80); + for (i = 0; i < 64; i++) { + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, 0); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, 0); + } +} + +/* wlc_lcnphy_rev0_baseband_init */ +static void b43_phy_lcn_rev0_baseband_init(struct b43_wldev *dev) +{ + b43_radio_write(dev, 0x11c, 0); + + b43_phy_write(dev, 0x43b, 0); + b43_phy_write(dev, 0x43c, 0); + b43_phy_write(dev, 0x44c, 0); + b43_phy_write(dev, 0x4e6, 0); + b43_phy_write(dev, 0x4f9, 0); + b43_phy_write(dev, 0x4b0, 0); + b43_phy_write(dev, 0x938, 0); + b43_phy_write(dev, 0x4b0, 0); + b43_phy_write(dev, 0x44e, 0); + + b43_phy_set(dev, 0x567, 0x03); + + b43_phy_set(dev, 0x44a, 0x44); + b43_phy_write(dev, 0x44a, 0x80); + + if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM)) + ; /* TODO */ + b43_phy_maskset(dev, 0x634, ~0xff, 0xc); + if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM) { + b43_phy_maskset(dev, 0x634, ~0xff, 0xa); + b43_phy_write(dev, 0x910, 0x1); + } + + b43_phy_write(dev, 0x910, 0x1); + + b43_phy_maskset(dev, 0x448, ~0x300, 0x100); + b43_phy_maskset(dev, 0x608, ~0xff, 0x17); + b43_phy_maskset(dev, 0x604, ~0x7ff, 0x3ea); +} + +/* wlc_lcnphy_bu_tweaks */ +static void b43_phy_lcn_bu_tweaks(struct b43_wldev *dev) +{ + b43_phy_set(dev, 0x805, 0x1); + + b43_phy_maskset(dev, 0x42f, ~0x7, 0x3); + b43_phy_maskset(dev, 0x030, ~0x7, 0x3); + + b43_phy_write(dev, 0x414, 0x1e10); + b43_phy_write(dev, 0x415, 0x0640); + + b43_phy_maskset(dev, 0x4df, (u16) ~0xff00, 0xf700); + + b43_phy_set(dev, 0x44a, 0x44); + b43_phy_write(dev, 0x44a, 0x80); + + b43_phy_maskset(dev, 0x434, ~0xff, 0xfd); + b43_phy_maskset(dev, 0x420, ~0xff, 0x10); + + if (dev->dev->bus_sprom->board_rev >= 0x1204) + b43_radio_set(dev, 0x09b, 0xf0); + + b43_phy_write(dev, 0x7d6, 0x0902); + + b43_phy_maskset(dev, 0x429, ~0xf, 0x9); + b43_phy_maskset(dev, 0x429, ~(0x3f << 4), 0xe << 4); + + if (dev->phy.rev == 1) { + b43_phy_maskset(dev, 0x423, ~0xff, 0x46); + b43_phy_maskset(dev, 0x411, ~0xff, 1); + b43_phy_set(dev, 0x434, 0xff); /* FIXME: update to wl */ + + /* TODO: wl operates on PHY 0x416, brcmsmac is outdated here */ + + b43_phy_maskset(dev, 0x656, ~0xf, 2); + b43_phy_set(dev, 0x44d, 4); + + b43_radio_set(dev, 0x0f7, 0x4); + b43_radio_mask(dev, 0x0f1, ~0x3); + b43_radio_maskset(dev, 0x0f2, ~0xf8, 0x90); + b43_radio_maskset(dev, 0x0f3, ~0x3, 0x2); + b43_radio_maskset(dev, 0x0f3, ~0xf0, 0xa0); + + b43_radio_set(dev, 0x11f, 0x2); + + b43_phy_lcn_clear_tx_power_offsets(dev); + + /* TODO: something more? */ + } +} + +/* wlc_lcnphy_vbat_temp_sense_setup */ +static void b43_phy_lcn_sense_setup(struct b43_wldev *dev, + enum lcn_sense_type sense_type) +{ + u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain; + u16 auxpga_vmid; + u8 tx_pwr_idx; + u8 i; + + u16 save_radio_regs[6][2] = { + { 0x007, 0 }, { 0x0ff, 0 }, { 0x11f, 0 }, { 0x005, 0 }, + { 0x025, 0 }, { 0x112, 0 }, + }; + u16 save_phy_regs[14][2] = { + { 0x503, 0 }, { 0x4a4, 0 }, { 0x4d0, 0 }, { 0x4d9, 0 }, + { 0x4da, 0 }, { 0x4a6, 0 }, { 0x938, 0 }, { 0x939, 0 }, + { 0x4d8, 0 }, { 0x4d0, 0 }, { 0x4d7, 0 }, { 0x4a5, 0 }, + { 0x40d, 0 }, { 0x4a2, 0 }, + }; + u16 save_radio_4a4; + + msleep(1); + + /* Save */ + for (i = 0; i < 6; i++) + save_radio_regs[i][1] = b43_radio_read(dev, + save_radio_regs[i][0]); + for (i = 0; i < 14; i++) + save_phy_regs[i][1] = b43_phy_read(dev, save_phy_regs[i][0]); + b43_mac_suspend(dev); + save_radio_4a4 = b43_radio_read(dev, 0x4a4); + /* wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); */ + tx_pwr_idx = dev->phy.lcn->tx_pwr_curr_idx; + + /* Setup */ + /* TODO: wlc_lcnphy_set_tx_pwr_by_index(pi, 127); */ + b43_radio_set(dev, 0x007, 0x1); + b43_radio_set(dev, 0x0ff, 0x10); + b43_radio_set(dev, 0x11f, 0x4); + + b43_phy_mask(dev, 0x503, ~0x1); + b43_phy_mask(dev, 0x503, ~0x4); + b43_phy_mask(dev, 0x4a4, ~0x4000); + b43_phy_mask(dev, 0x4a4, (u16) ~0x8000); + b43_phy_mask(dev, 0x4d0, ~0x20); + b43_phy_set(dev, 0x4a5, 0xff); + b43_phy_maskset(dev, 0x4a5, ~0x7000, 0x5000); + b43_phy_mask(dev, 0x4a5, ~0x700); + b43_phy_maskset(dev, 0x40d, ~0xff, 64); + b43_phy_maskset(dev, 0x40d, ~0x700, 0x600); + b43_phy_maskset(dev, 0x4a2, ~0xff, 64); + b43_phy_maskset(dev, 0x4a2, ~0x700, 0x600); + b43_phy_maskset(dev, 0x4d9, ~0x70, 0x20); + b43_phy_maskset(dev, 0x4d9, ~0x700, 0x300); + b43_phy_maskset(dev, 0x4d9, ~0x7000, 0x1000); + b43_phy_mask(dev, 0x4da, ~0x1000); + b43_phy_set(dev, 0x4da, 0x2000); + b43_phy_set(dev, 0x4a6, 0x8000); + + b43_radio_write(dev, 0x025, 0xc); + b43_radio_set(dev, 0x005, 0x8); + b43_phy_set(dev, 0x938, 0x4); + b43_phy_set(dev, 0x939, 0x4); + b43_phy_set(dev, 0x4a4, 0x1000); + + /* FIXME: don't hardcode */ + b43_lcntab_write(dev, B43_LCNTAB16(0x8, 0x6), 0x640); + + switch (sense_type) { + case B43_SENSE_TEMP: + b43_phy_set(dev, 0x4d7, 0x8); + b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x1000); + auxpga_vmidcourse = 8; + auxpga_vmidfine = 0x4; + auxpga_gain = 2; + b43_radio_set(dev, 0x082, 0x20); + break; + case B43_SENSE_VBAT: + b43_phy_set(dev, 0x4d7, 0x8); + b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x3000); + auxpga_vmidcourse = 7; + auxpga_vmidfine = 0xa; + auxpga_gain = 2; + break; + } + auxpga_vmid = (0x200 | (auxpga_vmidcourse << 4) | auxpga_vmidfine); + + b43_phy_set(dev, 0x4d8, 0x1); + b43_phy_maskset(dev, 0x4d8, ~(0x3ff << 2), auxpga_vmid << 2); + b43_phy_set(dev, 0x4d8, 0x2); + b43_phy_maskset(dev, 0x4d8, ~(0x7 << 12), auxpga_gain << 12); + b43_phy_set(dev, 0x4d0, 0x20); + b43_radio_write(dev, 0x112, 0x6); + + b43_dummy_transmission(dev, true, false); + /* Wait if not done */ + if (!(b43_phy_read(dev, 0x476) & 0x8000)) + udelay(10); + + /* Restore */ + for (i = 0; i < 6; i++) + b43_radio_write(dev, save_radio_regs[i][0], + save_radio_regs[i][1]); + for (i = 0; i < 14; i++) + b43_phy_write(dev, save_phy_regs[i][0], save_phy_regs[i][1]); + /* TODO: wlc_lcnphy_set_tx_pwr_by_index(tx_pwr_idx) */ + b43_radio_write(dev, 0x4a4, save_radio_4a4); + + b43_mac_enable(dev); + + msleep(1); +} + +static bool b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev *dev, + u8 filter_type) +{ + int i, j; + u16 phy_regs[] = { 0x910, 0x91e, 0x91f, 0x924, 0x925, 0x926, 0x920, + 0x921, 0x927, 0x928, 0x929, 0x922, 0x923, 0x930, + 0x931, 0x932 }; + /* Table is from brcmsmac, values for type 25 were outdated, probably + * others need updating too */ + struct lcn_tx_iir_filter tx_iir_filters_cck[] = { + { 0, { 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, + 1582, 64, 128, 64 } }, + { 1, { 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, + 1863, 93, 167, 93 } }, + { 2, { 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, + 778, 1582, 64, 128, 64 } }, + { 3, { 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, + 754, 1760, 170, 340, 170 } }, + { 20, { 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, + 767, 1760, 256, 185, 256 } }, + { 21, { 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, + 767, 1760, 256, 273, 256 } }, + { 22, { 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, + 767, 1760, 256, 352, 256 } }, + { 23, { 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, + 767, 1760, 128, 233, 128 } }, + { 24, { 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, + 1760, 256, 1881, 256 } }, + { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, + 1760, 262, 1878, 262 } }, + /* brcmsmac version { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, + * 256, 471, 256, 765, 1760, 256, 1881, 256 } }, */ + { 26, { 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, + 1864, 128, 384, 288 } }, + { 27, { 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, + 613, 1864, 128, 384, 288 } }, + { 30, { 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, + 754, 1760, 170, 340, 170 } }, + }; + + for (i = 0; i < ARRAY_SIZE(tx_iir_filters_cck); i++) { + if (tx_iir_filters_cck[i].type == filter_type) { + for (j = 0; j < 16; j++) + b43_phy_write(dev, phy_regs[j], + tx_iir_filters_cck[i].values[j]); + return true; + } + } + + return false; +} + +static bool b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev *dev, + u8 filter_type) +{ + int i, j; + u16 phy_regs[] = { 0x90f, 0x900, 0x901, 0x906, 0x907, 0x908, 0x902, + 0x903, 0x909, 0x90a, 0x90b, 0x904, 0x905, 0x90c, + 0x90d, 0x90e }; + struct lcn_tx_iir_filter tx_iir_filters_ofdm[] = { + { 0, { 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, + 0x0, 0x278, 0xfea0, 0x80, 0x100, 0x80 } }, + { 1, { 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, 750, + 0xFE2B, 212, 0xFFCE, 212 } }, + { 2, { 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748, + 0xFEF2, 128, 0xFFE2, 128 } }, + }; + + for (i = 0; i < ARRAY_SIZE(tx_iir_filters_ofdm); i++) { + if (tx_iir_filters_ofdm[i].type == filter_type) { + for (j = 0; j < 16; j++) + b43_phy_write(dev, phy_regs[j], + tx_iir_filters_ofdm[i].values[j]); + return true; + } + } + + return false; +} + +/* wlc_lcnphy_set_tx_gain_override */ +static void b43_phy_lcn_set_tx_gain_override(struct b43_wldev *dev, bool enable) +{ + b43_phy_maskset(dev, 0x4b0, ~(0x1 << 7), enable << 7); + b43_phy_maskset(dev, 0x4b0, ~(0x1 << 14), enable << 14); + b43_phy_maskset(dev, 0x43b, ~(0x1 << 6), enable << 6); +} + +/* wlc_lcnphy_set_tx_gain */ +static void b43_phy_lcn_set_tx_gain(struct b43_wldev *dev, + struct lcn_tx_gains *target_gains) +{ + u16 pa_gain = b43_phy_lcn_get_pa_gain(dev); + + b43_phy_write(dev, 0x4b5, + (target_gains->gm_gain | (target_gains->pga_gain << 8))); + b43_phy_maskset(dev, 0x4fb, ~0x7fff, + (target_gains->pad_gain | (pa_gain << 8))); + b43_phy_write(dev, 0x4fc, + (target_gains->gm_gain | (target_gains->pga_gain << 8))); + b43_phy_maskset(dev, 0x4fd, ~0x7fff, + (target_gains->pad_gain | (pa_gain << 8))); + + b43_phy_lcn_set_dac_gain(dev, target_gains->dac_gain); + b43_phy_lcn_set_tx_gain_override(dev, true); +} + +/* wlc_lcnphy_tx_pwr_ctrl_init */ +static void b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev *dev) +{ + struct lcn_tx_gains tx_gains; + u8 bbmult; + + b43_mac_suspend(dev); + + if (!dev->phy.lcn->hw_pwr_ctl_capable) { + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + tx_gains.gm_gain = 4; + tx_gains.pga_gain = 12; + tx_gains.pad_gain = 12; + tx_gains.dac_gain = 0; + bbmult = 150; + } else { + tx_gains.gm_gain = 7; + tx_gains.pga_gain = 15; + tx_gains.pad_gain = 14; + tx_gains.dac_gain = 0; + bbmult = 150; + } + b43_phy_lcn_set_tx_gain(dev, &tx_gains); + b43_phy_lcn_set_bbmult(dev, bbmult); + b43_phy_lcn_sense_setup(dev, B43_SENSE_TEMP); + } else { + b43err(dev->wl, "TX power control not supported for this HW\n"); + } + + b43_mac_enable(dev); +} + +/* wlc_lcnphy_txrx_spur_avoidance_mode */ +static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev, + bool enable) +{ + if (enable) { + b43_phy_write(dev, 0x942, 0x7); + b43_phy_write(dev, 0x93b, ((1 << 13) + 23)); + b43_phy_write(dev, 0x93c, ((1 << 13) + 1989)); + + b43_phy_write(dev, 0x44a, 0x084); + b43_phy_write(dev, 0x44a, 0x080); + b43_phy_write(dev, 0x6d3, 0x2222); + b43_phy_write(dev, 0x6d3, 0x2220); + } else { + b43_phy_write(dev, 0x942, 0x0); + b43_phy_write(dev, 0x93b, ((0 << 13) + 23)); + b43_phy_write(dev, 0x93c, ((0 << 13) + 1989)); + } + b43_phy_switch_macfreq(dev, enable); +} + +/************************************************** + * Channel switching ops. + **************************************************/ + +/* wlc_lcnphy_set_chanspec_tweaks */ +static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel) +{ + struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc; + + b43_phy_maskset(dev, 0x448, ~0x300, (channel == 14) ? 0x200 : 0x100); + + if (channel == 1 || channel == 2 || channel == 3 || channel == 4 || + channel == 9 || channel == 10 || channel == 11 || channel == 12) { + bcma_chipco_pll_write(cc, 0x2, 0x03000c04); + bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x0); + bcma_chipco_pll_write(cc, 0x4, 0x200005c0); + + bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400); + + b43_phy_write(dev, 0x942, 0); + + b43_phy_lcn_txrx_spur_avoidance_mode(dev, false); + b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1b00); + b43_phy_write(dev, 0x425, 0x5907); + } else { + bcma_chipco_pll_write(cc, 0x2, 0x03140c04); + bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x333333); + bcma_chipco_pll_write(cc, 0x4, 0x202c2820); + + bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400); + + b43_phy_write(dev, 0x942, 0); + + b43_phy_lcn_txrx_spur_avoidance_mode(dev, true); + b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00); + b43_phy_write(dev, 0x425, 0x590a); + } + + b43_phy_set(dev, 0x44a, 0x44); + b43_phy_write(dev, 0x44a, 0x80); +} + +/* wlc_phy_chanspec_set_lcnphy */ +static int b43_phy_lcn_set_channel(struct b43_wldev *dev, + struct ieee80211_channel *channel, + enum nl80211_channel_type channel_type) +{ + static const u16 sfo_cfg[14][2] = { + {965, 1087}, {967, 1085}, {969, 1082}, {971, 1080}, {973, 1078}, + {975, 1076}, {977, 1073}, {979, 1071}, {981, 1069}, {983, 1067}, + {985, 1065}, {987, 1063}, {989, 1060}, {994, 1055}, + }; + + b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value); + + b43_phy_set(dev, 0x44a, 0x44); + b43_phy_write(dev, 0x44a, 0x80); + + b43_radio_2064_channel_setup(dev); + mdelay(1); + + b43_phy_lcn_afe_set_unset(dev); + + b43_phy_write(dev, 0x657, sfo_cfg[channel->hw_value - 1][0]); + b43_phy_write(dev, 0x658, sfo_cfg[channel->hw_value - 1][1]); + + if (channel->hw_value == 14) { + b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (2) << 8); + b43_phy_lcn_load_tx_iir_cck_filter(dev, 3); + } else { + b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (1) << 8); + /* brcmsmac uses filter_type 2, we follow wl with 25 */ + b43_phy_lcn_load_tx_iir_cck_filter(dev, 25); + } + /* brcmsmac uses filter_type 2, we follow wl with 0 */ + b43_phy_lcn_load_tx_iir_ofdm_filter(dev, 0); + + b43_phy_maskset(dev, 0x4eb, ~(0x7 << 3), 0x1 << 3); + + return 0; +} + +/************************************************** + * Basic PHY ops. + **************************************************/ + +static int b43_phy_lcn_op_allocate(struct b43_wldev *dev) +{ + struct b43_phy_lcn *phy_lcn; + + phy_lcn = kzalloc(sizeof(*phy_lcn), GFP_KERNEL); + if (!phy_lcn) + return -ENOMEM; + dev->phy.lcn = phy_lcn; + + return 0; +} + +static void b43_phy_lcn_op_free(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_lcn *phy_lcn = phy->lcn; + + kfree(phy_lcn); + phy->lcn = NULL; +} + +static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_lcn *phy_lcn = phy->lcn; + + memset(phy_lcn, 0, sizeof(*phy_lcn)); +} + +/* wlc_phy_init_lcnphy */ +static int b43_phy_lcn_op_init(struct b43_wldev *dev) +{ + struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc; + + b43_phy_set(dev, 0x44a, 0x80); + b43_phy_mask(dev, 0x44a, 0x7f); + b43_phy_set(dev, 0x6d1, 0x80); + b43_phy_write(dev, 0x6d0, 0x7); + + b43_phy_lcn_afe_set_unset(dev); + + b43_phy_write(dev, 0x60a, 0xa0); + b43_phy_write(dev, 0x46a, 0x19); + b43_phy_maskset(dev, 0x663, 0xFF00, 0x64); + + b43_phy_lcn_tables_init(dev); + + b43_phy_lcn_rev0_baseband_init(dev); + b43_phy_lcn_bu_tweaks(dev); + + if (dev->phy.radio_ver == 0x2064) + b43_radio_2064_init(dev); + else + B43_WARN_ON(1); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + b43_phy_lcn_tx_pwr_ctl_init(dev); + + b43_switch_channel(dev, dev->phy.channel); + + bcma_chipco_regctl_maskset(cc, 0, 0xf, 0x9); + bcma_chipco_chipctl_maskset(cc, 0, 0, 0x03cddddd); + + /* TODO */ + + b43_phy_set(dev, 0x448, 0x4000); + udelay(100); + b43_phy_mask(dev, 0x448, ~0x4000); + + /* TODO */ + + return 0; +} + +static void b43_phy_lcn_op_software_rfkill(struct b43_wldev *dev, + bool blocked) +{ + if (b43_read32(dev, B43_MMIO_MACCTL) & B43_MACCTL_ENABLED) + b43err(dev->wl, "MAC not suspended\n"); + + if (blocked) { + b43_phy_mask(dev, B43_PHY_LCN_RF_CTL2, ~0x7c00); + b43_phy_set(dev, B43_PHY_LCN_RF_CTL1, 0x1f00); + + b43_phy_mask(dev, B43_PHY_LCN_RF_CTL5, ~0x7f00); + b43_phy_mask(dev, B43_PHY_LCN_RF_CTL4, ~0x2); + b43_phy_set(dev, B43_PHY_LCN_RF_CTL3, 0x808); + + b43_phy_mask(dev, B43_PHY_LCN_RF_CTL7, ~0x8); + b43_phy_set(dev, B43_PHY_LCN_RF_CTL6, 0x8); + } else { + b43_phy_mask(dev, B43_PHY_LCN_RF_CTL1, ~0x1f00); + b43_phy_mask(dev, B43_PHY_LCN_RF_CTL3, ~0x808); + b43_phy_mask(dev, B43_PHY_LCN_RF_CTL6, ~0x8); + } +} + +static void b43_phy_lcn_op_switch_analog(struct b43_wldev *dev, bool on) +{ + if (on) { + b43_phy_mask(dev, B43_PHY_LCN_AFE_CTL1, ~0x7); + } else { + b43_phy_set(dev, B43_PHY_LCN_AFE_CTL2, 0x7); + b43_phy_set(dev, B43_PHY_LCN_AFE_CTL1, 0x7); + } +} + +static int b43_phy_lcn_op_switch_channel(struct b43_wldev *dev, + unsigned int new_channel) +{ + struct ieee80211_channel *channel = dev->wl->hw->conf.channel; + enum nl80211_channel_type channel_type = dev->wl->hw->conf.channel_type; + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if ((new_channel < 1) || (new_channel > 14)) + return -EINVAL; + } else { + return -EINVAL; + } + + return b43_phy_lcn_set_channel(dev, channel, channel_type); +} + +static unsigned int b43_phy_lcn_op_get_default_chan(struct b43_wldev *dev) +{ + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + return 1; + return 36; +} + +static enum b43_txpwr_result +b43_phy_lcn_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi) +{ + return B43_TXPWR_RES_DONE; +} + +static void b43_phy_lcn_op_adjust_txpower(struct b43_wldev *dev) +{ +} + +/************************************************** + * R/W ops. + **************************************************/ + +static u16 b43_phy_lcn_op_read(struct b43_wldev *dev, u16 reg) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + return b43_read16(dev, B43_MMIO_PHY_DATA); +} + +static void b43_phy_lcn_op_write(struct b43_wldev *dev, u16 reg, u16 value) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, value); +} + +static void b43_phy_lcn_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask, + u16 set) +{ + b43_write16(dev, B43_MMIO_PHY_CONTROL, reg); + b43_write16(dev, B43_MMIO_PHY_DATA, + (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set); +} + +static u16 b43_phy_lcn_op_radio_read(struct b43_wldev *dev, u16 reg) +{ + /* LCN-PHY needs 0x200 for read access */ + reg |= 0x200; + + b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg); + return b43_read16(dev, B43_MMIO_RADIO24_DATA); +} + +static void b43_phy_lcn_op_radio_write(struct b43_wldev *dev, u16 reg, + u16 value) +{ + b43_write16(dev, B43_MMIO_RADIO24_CONTROL, reg); + b43_write16(dev, B43_MMIO_RADIO24_DATA, value); +} + /************************************************** * PHY ops struct. **************************************************/ const struct b43_phy_operations b43_phyops_lcn = { - /* .allocate = b43_phy_lcn_op_allocate, .free = b43_phy_lcn_op_free, .prepare_structs = b43_phy_lcn_op_prepare_structs, @@ -48,5 +898,4 @@ const struct b43_phy_operations b43_phyops_lcn = { .get_default_chan = b43_phy_lcn_op_get_default_chan, .recalc_txpower = b43_phy_lcn_op_recalc_txpower, .adjust_txpower = b43_phy_lcn_op_adjust_txpower, - */ }; diff --git a/drivers/net/wireless/b43/phy_lcn.h b/drivers/net/wireless/b43/phy_lcn.h index c046c2a6cab4..6a7092e13fff 100644 --- a/drivers/net/wireless/b43/phy_lcn.h +++ b/drivers/net/wireless/b43/phy_lcn.h @@ -4,11 +4,28 @@ #include "phy_common.h" +#define B43_PHY_LCN_AFE_CTL1 B43_PHY_OFDM(0x03B) +#define B43_PHY_LCN_AFE_CTL2 B43_PHY_OFDM(0x03C) +#define B43_PHY_LCN_RF_CTL1 B43_PHY_OFDM(0x04C) +#define B43_PHY_LCN_RF_CTL2 B43_PHY_OFDM(0x04D) +#define B43_PHY_LCN_TABLE_ADDR B43_PHY_OFDM(0x055) /* Table address */ +#define B43_PHY_LCN_TABLE_DATALO B43_PHY_OFDM(0x056) /* Table data low */ +#define B43_PHY_LCN_TABLE_DATAHI B43_PHY_OFDM(0x057) /* Table data high */ +#define B43_PHY_LCN_RF_CTL3 B43_PHY_OFDM(0x0B0) +#define B43_PHY_LCN_RF_CTL4 B43_PHY_OFDM(0x0B1) +#define B43_PHY_LCN_RF_CTL5 B43_PHY_OFDM(0x0B7) +#define B43_PHY_LCN_RF_CTL6 B43_PHY_OFDM(0x0F9) +#define B43_PHY_LCN_RF_CTL7 B43_PHY_OFDM(0x0FA) + + struct b43_phy_lcn { + bool hw_pwr_ctl; + bool hw_pwr_ctl_capable; + u8 tx_pwr_curr_idx; }; struct b43_phy_operations; extern const struct b43_phy_operations b43_phyops_lcn; -#endif /* B43_PHY_LCN_H_ */
\ No newline at end of file +#endif /* B43_PHY_LCN_H_ */ diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 3b46360da99b..b17d9b6c33a5 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -4,6 +4,7 @@ IEEE 802.11n PHY support Copyright (c) 2008 Michael Buesch <m@bues.ch> + Copyright (c) 2010-2011 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -77,6 +78,7 @@ enum b43_nphy_rssi_type { B43_NPHY_RSSI_TBD, }; +/* TODO: reorder functions */ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable); static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd, @@ -87,6 +89,14 @@ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field, u16 value, u8 core, bool off); static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field, u16 value, u8 core); +static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev); + +static inline bool b43_nphy_ipa(struct b43_wldev *dev) +{ + enum ieee80211_band band = b43_current_band(dev->wl); + return ((dev->phy.n->ipa2g_on && band == IEEE80211_BAND_2GHZ) || + (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ)); +} void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna) {//TODO @@ -248,15 +258,25 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) { struct b43_phy_n *nphy = dev->phy.n; u8 i; - u16 tmp; + u16 bmask, val, tmp; + enum ieee80211_band band = b43_current_band(dev->wl); if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 1); nphy->txpwrctrl = enable; if (!enable) { - if (dev->phy.rev >= 3) - ; /* TODO */ + if (dev->phy.rev >= 3 && + (b43_phy_read(dev, B43_NPHY_TXPCTL_CMD) & + (B43_NPHY_TXPCTL_CMD_COEFF | + B43_NPHY_TXPCTL_CMD_HWPCTLEN | + B43_NPHY_TXPCTL_CMD_PCTLEN))) { + /* We disable enabled TX pwr ctl, save it's state */ + nphy->tx_pwr_idx[0] = b43_phy_read(dev, + B43_NPHY_C1_TXPCTL_STAT) & 0x7f; + nphy->tx_pwr_idx[1] = b43_phy_read(dev, + B43_NPHY_C2_TXPCTL_STAT) & 0x7f; + } b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6840); for (i = 0; i < 84; i++) @@ -285,10 +305,67 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable) b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~B43_NPHY_BPHY_CTL3_SCALE, 0x5A); - if (dev->phy.rev < 2 && 0) - ; /* TODO */ + if (dev->phy.rev < 2 && dev->phy.is_40mhz) + b43_hf_write(dev, b43_hf_read(dev) | B43_HF_TSSIRPSMW); } else { - b43err(dev->wl, "enabling tx pwr ctrl not implemented yet\n"); + b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84, + nphy->adj_pwr_tbl); + b43_ntab_write_bulk(dev, B43_NTAB16(27, 64), 84, + nphy->adj_pwr_tbl); + + bmask = B43_NPHY_TXPCTL_CMD_COEFF | + B43_NPHY_TXPCTL_CMD_HWPCTLEN; + /* wl does useless check for "enable" param here */ + val = B43_NPHY_TXPCTL_CMD_COEFF | B43_NPHY_TXPCTL_CMD_HWPCTLEN; + if (dev->phy.rev >= 3) { + bmask |= B43_NPHY_TXPCTL_CMD_PCTLEN; + if (val) + val |= B43_NPHY_TXPCTL_CMD_PCTLEN; + } + b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, ~(bmask), val); + + if (band == IEEE80211_BAND_5GHZ) { + b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, + ~B43_NPHY_TXPCTL_CMD_INIT, 0x64); + if (dev->phy.rev > 1) + b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT, + ~B43_NPHY_TXPCTL_INIT_PIDXI1, + 0x64); + } + + if (dev->phy.rev >= 3) { + if (nphy->tx_pwr_idx[0] != 128 && + nphy->tx_pwr_idx[1] != 128) { + /* Recover TX pwr ctl state */ + b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, + ~B43_NPHY_TXPCTL_CMD_INIT, + nphy->tx_pwr_idx[0]); + if (dev->phy.rev > 1) + b43_phy_maskset(dev, + B43_NPHY_TXPCTL_INIT, + ~0xff, nphy->tx_pwr_idx[1]); + } + } + + if (dev->phy.rev >= 3) { + b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x100); + b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x100); + } else { + b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x4000); + } + + if (dev->phy.rev == 2) + b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x3b); + else if (dev->phy.rev < 2) + b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x40); + + if (dev->phy.rev < 2 && dev->phy.is_40mhz) + b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_TSSIRPSMW); + + if (b43_nphy_ipa(dev)) { + b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x4); + b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x4); + } } if (nphy->hang_avoid) @@ -369,22 +446,23 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) else b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN2, dac_gain); - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D10 + i); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, radio_gain); - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C57); - tmp = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + b43_ntab_write(dev, B43_NTAB16(0x7, 0x110 + i), radio_gain); + tmp = b43_ntab_read(dev, B43_NTAB16(0xF, 0x57)); if (i == 0) tmp = (tmp & 0x00FF) | (bbmult << 8); else tmp = (tmp & 0xFF00) | bbmult; - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C57); - b43_phy_write(dev, B43_NPHY_TABLE_DATALO, tmp); - - if (0) - ; /* TODO */ + b43_ntab_write(dev, B43_NTAB16(0xF, 0x57), tmp); + + if (b43_nphy_ipa(dev)) { + u32 tmp32; + u16 reg = (i == 0) ? + B43_NPHY_PAPD_EN0 : B43_NPHY_PAPD_EN1; + tmp32 = b43_ntab_read(dev, B43_NTAB32(26 + i, txpi[i])); + b43_phy_maskset(dev, reg, 0xE00F, (u32) tmp32 << 4); + b43_phy_set(dev, reg, 0x4); + } } b43_phy_mask(dev, B43_NPHY_BPHY_CTL2, ~B43_NPHY_BPHY_CTL2_LUT); @@ -393,6 +471,57 @@ static void b43_nphy_tx_power_fix(struct b43_wldev *dev) b43_nphy_stay_in_carrier_search(dev, 0); } +static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + + const u32 *table = NULL; +#if 0 + TODO: b43_ntab_papd_pga_gain_delta_ipa_2* + u32 rfpwr_offset; + u8 pga_gain; + int i; +#endif + + if (phy->rev >= 3) { + if (b43_nphy_ipa(dev)) { + table = b43_nphy_get_ipa_gain_table(dev); + } else { + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + if (phy->rev == 3) + table = b43_ntab_tx_gain_rev3_5ghz; + if (phy->rev == 4) + table = b43_ntab_tx_gain_rev4_5ghz; + else + table = b43_ntab_tx_gain_rev5plus_5ghz; + } else { + table = b43_ntab_tx_gain_rev3plus_2ghz; + } + } + } else { + table = b43_ntab_tx_gain_rev0_1_2; + } + b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, table); + b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, table); + + if (phy->rev >= 3) { +#if 0 + nphy->gmval = (table[0] >> 16) & 0x7000; + + for (i = 0; i < 128; i++) { + pga_gain = (table[i] >> 24) & 0xF; + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) + rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_2g[pga_gain]; + else + rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_5g[pga_gain]; + b43_ntab_write(dev, B43_NTAB32(26, 576 + i), + rfpwr_offset); + b43_ntab_write(dev, B43_NTAB32(27, 576 + i), + rfpwr_offset); + } +#endif + } +} /* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */ static void b43_radio_2055_setup(struct b43_wldev *dev, @@ -581,14 +710,10 @@ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable) /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */ static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev) { - struct b43_phy_n *nphy = dev->phy.n; u16 tmp; - enum ieee80211_band band = b43_current_band(dev->wl); - bool ipa = (nphy->ipa2g_on && band == IEEE80211_BAND_2GHZ) || - (nphy->ipa5g_on && band == IEEE80211_BAND_5GHZ); if (dev->phy.rev >= 3) { - if (ipa) { + if (b43_nphy_ipa(dev)) { tmp = 4; b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2, (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp); @@ -600,49 +725,17 @@ static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */ -static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force) -{ - u32 tmp; - - if (dev->phy.type != B43_PHYTYPE_N) - return; - - switch (dev->dev->bus_type) { -#ifdef CONFIG_B43_BCMA - case B43_BUS_BCMA: - tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL); - if (force) - tmp |= BCMA_IOCTL_FGC; - else - tmp &= ~BCMA_IOCTL_FGC; - bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp); - break; -#endif -#ifdef CONFIG_B43_SSB - case B43_BUS_SSB: - tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW); - if (force) - tmp |= SSB_TMSLOW_FGC; - else - tmp &= ~SSB_TMSLOW_FGC; - ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp); - break; -#endif - } -} - /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */ static void b43_nphy_reset_cca(struct b43_wldev *dev) { u16 bbcfg; - b43_nphy_bmac_clock_fgc(dev, 1); + b43_phy_force_clock(dev, 1); bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG); b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA); udelay(1); b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA); - b43_nphy_bmac_clock_fgc(dev, 0); + b43_phy_force_clock(dev, 0); b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX); } @@ -931,11 +1024,7 @@ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask) static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev) { u16 array[4]; - int i; - - b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C50); - for (i = 0; i < 4; i++) - array[i] = b43_phy_read(dev, B43_NPHY_TABLE_DATALO); + b43_ntab_read_bulk(dev, B43_NTAB16(0xF, 0x50), 4, array); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]); b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]); @@ -1398,180 +1487,220 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev) } } -/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ -static void b43_nphy_workarounds(struct b43_wldev *dev) +static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev) { + struct b43_phy_n *nphy = dev->phy.n; struct ssb_sprom *sprom = dev->dev->bus_sprom; - struct b43_phy *phy = &dev->phy; - struct b43_phy_n *nphy = phy->n; - - u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 }; - u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 }; - u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 }; - u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 }; + /* TX to RX */ + u8 tx2rx_events[9] = { 0x4, 0x3, 0x6, 0x5, 0x2, 0x1, 0x8, 0x1F }; + u8 tx2rx_delays[9] = { 8, 4, 2, 2, 4, 4, 6, 1 }; + /* RX to TX */ + u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3, + 0x1F }; + u8 rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 }; + u8 rx2tx_events[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0x3, 0x4, 0x1F }; + u8 rx2tx_delays[9] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 }; u16 tmp16; u32 tmp32; - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) - b43_nphy_classifier(dev, 1, 0); - else - b43_nphy_classifier(dev, 1, 1); + tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0)); + tmp32 &= 0xffffff; + b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32); + + b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x0125); + b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x01B3); + b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x0105); + b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x016E); + b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0x00CD); + b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x0020); + + b43_phy_write(dev, B43_NPHY_C2_CLIP1_MEDGAIN, 0x000C); + b43_phy_write(dev, 0x2AE, 0x000C); + + /* TX to RX */ + b43_nphy_set_rf_sequence(dev, 1, tx2rx_events, tx2rx_delays, 9); + + /* RX to TX */ + if (b43_nphy_ipa(dev)) + b43_nphy_set_rf_sequence(dev, 1, rx2tx_events_ipa, + rx2tx_delays_ipa, 9); + if (nphy->hw_phyrxchain != 3 && + nphy->hw_phyrxchain != nphy->hw_phytxchain) { + if (b43_nphy_ipa(dev)) { + rx2tx_delays[5] = 59; + rx2tx_delays[6] = 1; + rx2tx_events[7] = 0x1F; + } + b43_nphy_set_rf_sequence(dev, 1, rx2tx_events, rx2tx_delays, 9); + } - if (nphy->hang_avoid) - b43_nphy_stay_in_carrier_search(dev, 1); + tmp16 = (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) ? + 0x2 : 0x9C40; + b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, tmp16); - b43_phy_set(dev, B43_NPHY_IQFLIP, - B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); + b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700); - if (dev->phy.rev >= 3) { - tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0)); - tmp32 &= 0xffffff; - b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32); + b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D); + b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D); - b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x0125); - b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x01B3); - b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x0105); - b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x016E); - b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0x00CD); - b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x0020); + b43_nphy_gain_ctrl_workarounds(dev); - b43_phy_write(dev, B43_NPHY_C2_CLIP1_MEDGAIN, 0x000C); - b43_phy_write(dev, 0x2AE, 0x000C); + b43_ntab_write(dev, B43_NTAB32(8, 0), 2); + b43_ntab_write(dev, B43_NTAB32(8, 16), 2); - /* TODO */ + /* TODO */ - tmp16 = (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) ? - 0x2 : 0x9C40; - b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, tmp16); + b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_MAST_BIAS, 0x00); + b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_MAST_BIAS, 0x00); + b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_BIAS_MAIN, 0x06); + b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_MAIN, 0x06); + b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_BIAS_AUX, 0x07); + b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_AUX, 0x07); + b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_LOB_BIAS, 0x88); + b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_LOB_BIAS, 0x88); + b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXG_CMFB_IDAC, 0x00); + b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXG_CMFB_IDAC, 0x00); + + /* N PHY WAR TX Chain Update with hw_phytxchain as argument */ + + if ((sprom->boardflags2_lo & B43_BFL2_APLL_WAR && + b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || + (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR && + b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) + tmp32 = 0x00088888; + else + tmp32 = 0x88888888; + b43_ntab_write(dev, B43_NTAB32(30, 1), tmp32); + b43_ntab_write(dev, B43_NTAB32(30, 2), tmp32); + b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32); + + if (dev->phy.rev == 4 && + b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { + b43_radio_write(dev, B2056_TX0 | B2056_TX_GMBB_IDAC, + 0x70); + b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC, + 0x70); + } - b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700); + b43_phy_write(dev, 0x224, 0x039C); + b43_phy_write(dev, 0x225, 0x0357); + b43_phy_write(dev, 0x226, 0x0317); + b43_phy_write(dev, 0x227, 0x02D7); + b43_phy_write(dev, 0x228, 0x039C); + b43_phy_write(dev, 0x229, 0x0357); + b43_phy_write(dev, 0x22A, 0x0317); + b43_phy_write(dev, 0x22B, 0x02D7); + b43_phy_write(dev, 0x22C, 0x039C); + b43_phy_write(dev, 0x22D, 0x0357); + b43_phy_write(dev, 0x22E, 0x0317); + b43_phy_write(dev, 0x22F, 0x02D7); +} - b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D); - b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D); +static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev) +{ + struct ssb_sprom *sprom = dev->dev->bus_sprom; + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; - b43_nphy_gain_ctrl_workarounds(dev); + u8 events1[7] = { 0x0, 0x1, 0x2, 0x8, 0x4, 0x5, 0x3 }; + u8 delays1[7] = { 0x8, 0x6, 0x6, 0x2, 0x4, 0x3C, 0x1 }; - b43_ntab_write(dev, B43_NTAB32(8, 0), 2); - b43_ntab_write(dev, B43_NTAB32(8, 16), 2); + u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 }; + u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 }; - /* TODO */ + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ && + nphy->band5g_pwrgain) { + b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8); + b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8); + } else { + b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); + b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8); + } - b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_MAST_BIAS, 0x00); - b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_MAST_BIAS, 0x00); - b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_BIAS_MAIN, 0x06); - b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_MAIN, 0x06); - b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_BIAS_AUX, 0x07); - b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_BIAS_AUX, 0x07); - b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXA_LOB_BIAS, 0x88); - b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXA_LOB_BIAS, 0x88); - b43_radio_write(dev, B2056_RX0 | B2056_RX_MIXG_CMFB_IDAC, 0x00); - b43_radio_write(dev, B2056_RX1 | B2056_RX_MIXG_CMFB_IDAC, 0x00); - - /* N PHY WAR TX Chain Update with hw_phytxchain as argument */ - - if ((sprom->boardflags2_lo & B43_BFL2_APLL_WAR && - b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) || - (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR && - b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) - tmp32 = 0x00088888; - else - tmp32 = 0x88888888; - b43_ntab_write(dev, B43_NTAB32(30, 1), tmp32); - b43_ntab_write(dev, B43_NTAB32(30, 2), tmp32); - b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32); - - if (dev->phy.rev == 4 && - b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) { - b43_radio_write(dev, B2056_TX0 | B2056_TX_GMBB_IDAC, - 0x70); - b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC, - 0x70); - } + b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A); + b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A); + b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); + b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); - b43_phy_write(dev, 0x224, 0x039C); - b43_phy_write(dev, 0x225, 0x0357); - b43_phy_write(dev, 0x226, 0x0317); - b43_phy_write(dev, 0x227, 0x02D7); - b43_phy_write(dev, 0x228, 0x039C); - b43_phy_write(dev, 0x229, 0x0357); - b43_phy_write(dev, 0x22A, 0x0317); - b43_phy_write(dev, 0x22B, 0x02D7); - b43_phy_write(dev, 0x22C, 0x039C); - b43_phy_write(dev, 0x22D, 0x0357); - b43_phy_write(dev, 0x22E, 0x0317); - b43_phy_write(dev, 0x22F, 0x02D7); - } else { - if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ && - nphy->band5g_pwrgain) { - b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8); - b43_radio_mask(dev, B2055_C2_TX_RF_SPARE, ~0x8); - } else { - b43_radio_set(dev, B2055_C1_TX_RF_SPARE, 0x8); - b43_radio_set(dev, B2055_C2_TX_RF_SPARE, 0x8); - } + if (dev->phy.rev < 2) { + b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000); + b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0x0000); + b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB); + b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x0800); + b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x0800); + } - b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A); - b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A); - b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA); - b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); + b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); - if (dev->phy.rev < 2) { - b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000); - b43_ntab_write(dev, B43_NTAB16(8, 0x18), 0x0000); - b43_ntab_write(dev, B43_NTAB16(8, 0x07), 0x7AAB); - b43_ntab_write(dev, B43_NTAB16(8, 0x17), 0x7AAB); - b43_ntab_write(dev, B43_NTAB16(8, 0x06), 0x0800); - b43_ntab_write(dev, B43_NTAB16(8, 0x16), 0x0800); - } + if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD && + dev->dev->board_type == 0x8B) { + delays1[0] = 0x1; + delays1[5] = 0x14; + } + b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7); + b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8); - b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301); + b43_nphy_gain_ctrl_workarounds(dev); - if (sprom->boardflags2_lo & 0x100 && - dev->dev->board_type == 0x8B) { - delays1[0] = 0x1; - delays1[5] = 0x14; - } - b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7); - b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7); + if (dev->phy.rev < 2) { + if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2) + b43_hf_write(dev, b43_hf_read(dev) | + B43_HF_MLADVW); + } else if (dev->phy.rev == 2) { + b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0); + b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0); + } - b43_nphy_gain_ctrl_workarounds(dev); + if (dev->phy.rev < 2) + b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, + ~B43_NPHY_SCRAM_SIGCTL_SCM); + + /* Set phase track alpha and beta */ + b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); + b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); + b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); + b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); + b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); + b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); + + b43_phy_mask(dev, B43_NPHY_PIL_DW1, + ~B43_NPHY_PIL_DW_64QAM & 0xFFFF); + b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5); + b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4); + b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00); + + if (dev->phy.rev == 2) + b43_phy_set(dev, B43_NPHY_FINERX2_CGC, + B43_NPHY_FINERX2_CGC_DECGC); +} - if (dev->phy.rev < 2) { - if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2) - b43_hf_write(dev, b43_hf_read(dev) | - B43_HF_MLADVW); - } else if (dev->phy.rev == 2) { - b43_phy_write(dev, B43_NPHY_CRSCHECK2, 0); - b43_phy_write(dev, B43_NPHY_CRSCHECK3, 0); - } +/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */ +static void b43_nphy_workarounds(struct b43_wldev *dev) +{ + struct b43_phy *phy = &dev->phy; + struct b43_phy_n *nphy = phy->n; - if (dev->phy.rev < 2) - b43_phy_mask(dev, B43_NPHY_SCRAM_SIGCTL, - ~B43_NPHY_SCRAM_SIGCTL_SCM); + if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) + b43_nphy_classifier(dev, 1, 0); + else + b43_nphy_classifier(dev, 1, 1); - /* Set phase track alpha and beta */ - b43_phy_write(dev, B43_NPHY_PHASETR_A0, 0x125); - b43_phy_write(dev, B43_NPHY_PHASETR_A1, 0x1B3); - b43_phy_write(dev, B43_NPHY_PHASETR_A2, 0x105); - b43_phy_write(dev, B43_NPHY_PHASETR_B0, 0x16E); - b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD); - b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20); + if (nphy->hang_avoid) + b43_nphy_stay_in_carrier_search(dev, 1); - b43_phy_mask(dev, B43_NPHY_PIL_DW1, - ~B43_NPHY_PIL_DW_64QAM & 0xFFFF); - b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5); - b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4); - b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00); + b43_phy_set(dev, B43_NPHY_IQFLIP, + B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2); - if (dev->phy.rev == 2) - b43_phy_set(dev, B43_NPHY_FINERX2_CGC, - B43_NPHY_FINERX2_CGC_DECGC); - } + if (dev->phy.rev >= 3) + b43_nphy_workarounds_rev3plus(dev); + else + b43_nphy_workarounds_rev1_2(dev); if (nphy->hang_avoid) b43_nphy_stay_in_carrier_search(dev, 0); @@ -2167,7 +2296,6 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type) static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type) { - struct b43_phy_n *nphy = dev->phy.n; u8 i; u16 reg, val; @@ -2231,10 +2359,7 @@ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type) enum ieee80211_band band = b43_current_band(dev->wl); - if ((nphy->ipa2g_on && - band == IEEE80211_BAND_2GHZ) || - (nphy->ipa5g_on && - band == IEEE80211_BAND_5GHZ)) + if (b43_nphy_ipa(dev)) val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE; else val = 0x11; @@ -2609,8 +2734,8 @@ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev) { if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { if (dev->phy.rev >= 6) { - /* TODO If the chip is 47162 - return txpwrctrl_tx_gain_ipa_rev5 */ + if (dev->dev->chip_id == 47162) + return txpwrctrl_tx_gain_ipa_rev5; return txpwrctrl_tx_gain_ipa_rev6; } else if (dev->phy.rev >= 5) { return txpwrctrl_tx_gain_ipa_rev5; @@ -2860,10 +2985,7 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev) enum ieee80211_band band = b43_current_band(dev->wl); - if ((nphy->ipa2g_on && - band == IEEE80211_BAND_2GHZ) || - (nphy->ipa5g_on && - band == IEEE80211_BAND_5GHZ)) { + if (b43_nphy_ipa(dev)) { table = b43_nphy_get_ipa_gain_table(dev); } else { if (band == IEEE80211_BAND_5GHZ) { @@ -3680,7 +3802,7 @@ int b43_phy_initn(struct b43_wldev *dev) b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20); b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20); - if (sprom->boardflags2_lo & 0x100 || + if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD || (dev->dev->board_vendor == PCI_VENDOR_ID_APPLE && dev->dev->board_type == 0x8B)) b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0); @@ -3699,8 +3821,7 @@ int b43_phy_initn(struct b43_wldev *dev) } tmp2 = b43_current_band(dev->wl); - if ((nphy->ipa2g_on && tmp2 == IEEE80211_BAND_2GHZ) || - (nphy->ipa5g_on && tmp2 == IEEE80211_BAND_5GHZ)) { + if (b43_nphy_ipa(dev)) { b43_phy_set(dev, B43_NPHY_PAPD_EN0, 0x1); b43_phy_maskset(dev, B43_NPHY_EPS_TABLE_ADJ0, 0x007F, nphy->papd_epsilon_offset[0] << 7); @@ -3715,11 +3836,11 @@ int b43_phy_initn(struct b43_wldev *dev) b43_nphy_workarounds(dev); /* Reset CCA, in init code it differs a little from standard way */ - b43_nphy_bmac_clock_fgc(dev, 1); + b43_phy_force_clock(dev, 1); tmp = b43_phy_read(dev, B43_NPHY_BBCFG); b43_phy_write(dev, B43_NPHY_BBCFG, tmp | B43_NPHY_BBCFG_RSTCCA); b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA); - b43_nphy_bmac_clock_fgc(dev, 0); + b43_phy_force_clock(dev, 0); b43_mac_phy_clock_set(dev, true); @@ -3738,15 +3859,7 @@ int b43_phy_initn(struct b43_wldev *dev) b43_nphy_tx_power_fix(dev); /* TODO N PHY TX Power Control Idle TSSI */ /* TODO N PHY TX Power Control Setup */ - - if (phy->rev >= 3) { - /* TODO */ - } else { - b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, - b43_ntab_tx_gain_rev0_1_2); - b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, - b43_ntab_tx_gain_rev0_1_2); - } + b43_nphy_tx_gain_table_upload(dev); if (nphy->phyrxchain != 3) b43_nphy_set_rx_core_state(dev, nphy->phyrxchain); @@ -3950,6 +4063,10 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev) nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */ nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */ nphy->perical = 2; /* avoid additional rssi cal on init (like wl) */ + /* 128 can mean disabled-by-default state of TX pwr ctl. Max value is + * 0x7f == 127 and we check for 128 when restoring TX pwr ctl. */ + nphy->tx_pwr_idx[0] = 128; + nphy->tx_pwr_idx[1] = 128; } static void b43_nphy_op_free(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/phy_n.h b/drivers/net/wireless/b43/phy_n.h index e789a89f1047..fbf520285bd1 100644 --- a/drivers/net/wireless/b43/phy_n.h +++ b/drivers/net/wireless/b43/phy_n.h @@ -764,6 +764,8 @@ struct b43_phy_n { u8 cal_orig_pwr_idx[2]; u8 measure_hold; u8 phyrxchain; + u8 hw_phyrxchain; + u8 hw_phytxchain; u8 perical; u32 deaf_count; u32 rxcalparams; @@ -783,6 +785,8 @@ struct b43_phy_n { u16 mphase_txcal_bestcoeffs[11]; bool txpwrctrl; + u8 tx_pwr_idx[2]; + u16 adj_pwr_tbl[84]; u16 txcal_bbmult; u16 txiqlocal_bestc[11]; bool txiqlocal_coeffsvalid; diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 6e4228c3ed1b..fcff923b3c18 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -611,7 +611,7 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) struct b43_wldev *dev = q->dev; struct b43_wl *wl = dev->wl; u16 len; - u32 macstat; + u32 macstat = 0; unsigned int i, padding; struct sk_buff *skb; const char *err_msg = NULL; @@ -676,7 +676,15 @@ data_ready: goto rx_error; } - macstat = le32_to_cpu(rxhdr->mac_status); + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: + macstat = le32_to_cpu(rxhdr->format_598.mac_status); + break; + case B43_FW_HDR_410: + case B43_FW_HDR_351: + macstat = le32_to_cpu(rxhdr->format_351.mac_status); + break; + } if (macstat & B43_RX_MAC_FCSERR) { if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) { /* Drop frames with failed FCS. */ diff --git a/drivers/net/wireless/b43/radio_2055.c b/drivers/net/wireless/b43/radio_2055.c index 93643f18c2b3..5289a18ddd8c 100644 --- a/drivers/net/wireless/b43/radio_2055.c +++ b/drivers/net/wireless/b43/radio_2055.c @@ -4,6 +4,7 @@ IEEE 802.11n PHY and radio device data tables Copyright (c) 2008 Michael Buesch <m@bues.ch> + Copyright (c) 2010 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/b43/radio_2056.c b/drivers/net/wireless/b43/radio_2056.c index 8890df067029..a01f776ca4de 100644 --- a/drivers/net/wireless/b43/radio_2056.c +++ b/drivers/net/wireless/b43/radio_2056.c @@ -3,6 +3,8 @@ Broadcom B43 wireless driver IEEE 802.11n 2056 radio device data tables + Copyright (c) 2010 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or diff --git a/drivers/net/wireless/b43/radio_2056.h b/drivers/net/wireless/b43/radio_2056.h index d52df6be705a..a7159d8578be 100644 --- a/drivers/net/wireless/b43/radio_2056.h +++ b/drivers/net/wireless/b43/radio_2056.h @@ -1,29 +1,3 @@ -/* - - Broadcom B43 wireless driver - - Copyright (c) 2010 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> - - Some parts of the code in this file are derived from the brcm80211 - driver Copyright (c) 2010 Broadcom Corporation - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, - Boston, MA 02110-1301, USA. - -*/ - #ifndef B43_RADIO_2056_H_ #define B43_RADIO_2056_H_ diff --git a/drivers/net/wireless/b43/radio_2059.c b/drivers/net/wireless/b43/radio_2059.c index f029f6e1f5d1..d4ce8a12ff9a 100644 --- a/drivers/net/wireless/b43/radio_2059.c +++ b/drivers/net/wireless/b43/radio_2059.c @@ -3,6 +3,8 @@ Broadcom B43 wireless driver IEEE 802.11n 2059 radio device data tables + Copyright (c) 2011 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c index 916f238a71df..7b326f2efdc9 100644 --- a/drivers/net/wireless/b43/tables_nphy.c +++ b/drivers/net/wireless/b43/tables_nphy.c @@ -4,6 +4,7 @@ IEEE 802.11n PHY data tables Copyright (c) 2008 Michael Buesch <m@bues.ch> + Copyright (c) 2010 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/drivers/net/wireless/b43/tables_phy_ht.c b/drivers/net/wireless/b43/tables_phy_ht.c index 603938657b15..176c49d74ef4 100644 --- a/drivers/net/wireless/b43/tables_phy_ht.c +++ b/drivers/net/wireless/b43/tables_phy_ht.c @@ -3,6 +3,8 @@ Broadcom B43 wireless driver IEEE 802.11n HT-PHY data tables + Copyright (c) 2011 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -574,6 +576,42 @@ static const u32 b43_httab_0x24[] = { 0x005d0582, 0x005805d6, 0x0053062e, 0x004e068c, }; +/* Some late-init table */ +const u32 b43_httab_0x1a_0xc0_late[] = { + 0x10f90040, 0x10e10040, 0x10e1003c, 0x10c9003d, + 0x10b9003c, 0x10a9003d, 0x10a1003c, 0x1099003b, + 0x1091003b, 0x1089003a, 0x1081003a, 0x10790039, + 0x10710039, 0x1069003a, 0x1061003b, 0x1059003d, + 0x1051003f, 0x10490042, 0x1049003e, 0x1049003b, + 0x1041003e, 0x1041003b, 0x1039003e, 0x1039003b, + 0x10390038, 0x10390035, 0x1031003a, 0x10310036, + 0x10310033, 0x1029003a, 0x10290037, 0x10290034, + 0x10290031, 0x10210039, 0x10210036, 0x10210033, + 0x10210030, 0x1019003c, 0x10190039, 0x10190036, + 0x10190033, 0x10190030, 0x1019002d, 0x1019002b, + 0x10190028, 0x1011003a, 0x10110036, 0x10110033, + 0x10110030, 0x1011002e, 0x1011002b, 0x10110029, + 0x10110027, 0x10110024, 0x10110022, 0x10110020, + 0x1011001f, 0x1011001d, 0x1009003a, 0x10090037, + 0x10090034, 0x10090031, 0x1009002e, 0x1009002c, + 0x10090029, 0x10090027, 0x10090025, 0x10090023, + 0x10090021, 0x1009001f, 0x1009001d, 0x1009001b, + 0x1009001a, 0x10090018, 0x10090017, 0x10090016, + 0x10090015, 0x10090013, 0x10090012, 0x10090011, + 0x10090010, 0x1009000f, 0x1009000f, 0x1009000e, + 0x1009000d, 0x1009000c, 0x1009000c, 0x1009000b, + 0x1009000a, 0x1009000a, 0x10090009, 0x10090009, + 0x10090008, 0x10090008, 0x10090007, 0x10090007, + 0x10090007, 0x10090006, 0x10090006, 0x10090005, + 0x10090005, 0x10090005, 0x10090005, 0x10090004, + 0x10090004, 0x10090004, 0x10090004, 0x10090003, + 0x10090003, 0x10090003, 0x10090003, 0x10090003, + 0x10090003, 0x10090002, 0x10090002, 0x10090002, + 0x10090002, 0x10090002, 0x10090002, 0x10090002, + 0x10090002, 0x10090002, 0x10090001, 0x10090001, + 0x10090001, 0x10090001, 0x10090001, 0x10090001, +}; + /************************************************** * R/W ops. **************************************************/ @@ -674,6 +712,51 @@ void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value) return; } +void b43_httab_write_few(struct b43_wldev *dev, u32 offset, size_t num, ...) +{ + va_list args; + u32 type, value; + unsigned int i; + + type = offset & B43_HTTAB_TYPEMASK; + offset &= 0xFFFF; + + va_start(args, num); + switch (type) { + case B43_HTTAB_8BIT: + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + for (i = 0; i < num; i++) { + value = va_arg(args, int); + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value); + } + break; + case B43_HTTAB_16BIT: + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + for (i = 0; i < num; i++) { + value = va_arg(args, int); + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, value); + } + break; + case B43_HTTAB_32BIT: + b43_phy_write(dev, B43_PHY_HT_TABLE_ADDR, offset); + for (i = 0; i < num; i++) { + value = va_arg(args, int); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATAHI, + value >> 16); + b43_phy_write(dev, B43_PHY_HT_TABLE_DATALO, + value & 0xFFFF); + } + break; + default: + B43_WARN_ON(1); + } + va_end(args); + + return; +} + void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, const void *_data) { @@ -723,6 +806,9 @@ void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset, } while (0) void b43_phy_ht_tables_init(struct b43_wldev *dev) { + BUILD_BUG_ON(ARRAY_SIZE(b43_httab_0x1a_0xc0_late) != + B43_HTTAB_1A_C0_LATE_SIZE); + httab_upload(dev, B43_HTTAB16(0x12, 0), b43_httab_0x12); httab_upload(dev, B43_HTTAB16(0x27, 0), b43_httab_0x27); httab_upload(dev, B43_HTTAB16(0x26, 0), b43_httab_0x26); diff --git a/drivers/net/wireless/b43/tables_phy_ht.h b/drivers/net/wireless/b43/tables_phy_ht.h index ea3be382c894..1b5ef2bc770c 100644 --- a/drivers/net/wireless/b43/tables_phy_ht.h +++ b/drivers/net/wireless/b43/tables_phy_ht.h @@ -14,9 +14,13 @@ u32 b43_httab_read(struct b43_wldev *dev, u32 offset); void b43_httab_read_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, void *_data); void b43_httab_write(struct b43_wldev *dev, u32 offset, u32 value); +void b43_httab_write_few(struct b43_wldev *dev, u32 offset, size_t num, ...); void b43_httab_write_bulk(struct b43_wldev *dev, u32 offset, unsigned int nr_elements, const void *_data); void b43_phy_ht_tables_init(struct b43_wldev *dev); +#define B43_HTTAB_1A_C0_LATE_SIZE 128 +extern const u32 b43_httab_0x1a_0xc0_late[]; + #endif /* B43_TABLES_PHY_HT_H_ */ diff --git a/drivers/net/wireless/b43/tables_phy_lcn.c b/drivers/net/wireless/b43/tables_phy_lcn.c index 40c1d0915dd3..5176363cadf2 100644 --- a/drivers/net/wireless/b43/tables_phy_lcn.c +++ b/drivers/net/wireless/b43/tables_phy_lcn.c @@ -3,6 +3,8 @@ Broadcom B43 wireless driver IEEE 802.11n LCN-PHY data tables + Copyright (c) 2011 RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or @@ -25,10 +27,698 @@ #include "phy_common.h" #include "phy_lcn.h" +struct b43_lcntab_tx_gain_tbl_entry { + u8 gm; + u8 pga; + u8 pad; + u8 dac; + u8 bb_mult; +}; + +/************************************************** + * Static tables. + **************************************************/ + +static const u16 b43_lcntab_0x02[] = { + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, 0x014d, + 0x014d, 0x014d, 0x014d, 0x014d, +}; + +static const u16 b43_lcntab_0x01[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const u32 b43_lcntab_0x0b[] = { + 0x000141f8, 0x000021f8, 0x000021fb, 0x000041fb, + 0x0001fedb, 0x0000217b, 0x00002133, 0x000040eb, + 0x0001fea3, 0x0000024b, +}; + +static const u32 b43_lcntab_0x0c[] = { + 0x00100001, 0x00200010, 0x00300001, 0x00400010, + 0x00500022, 0x00600122, 0x00700222, 0x00800322, + 0x00900422, 0x00a00522, 0x00b00622, 0x00c00722, + 0x00d00822, 0x00f00922, 0x00100a22, 0x00200b22, + 0x00300c22, 0x00400d22, 0x00500e22, 0x00600f22, +}; + +static const u32 b43_lcntab_0x0d[] = { + 0x00000000, 0x00000000, 0x10000000, 0x00000000, + 0x20000000, 0x00000000, 0x30000000, 0x00000000, + 0x40000000, 0x00000000, 0x50000000, 0x00000000, + 0x60000000, 0x00000000, 0x70000000, 0x00000000, + 0x80000000, 0x00000000, 0x90000000, 0x00000008, + 0xa0000000, 0x00000008, 0xb0000000, 0x00000008, + 0xc0000000, 0x00000008, 0xd0000000, 0x00000008, + 0xe0000000, 0x00000008, 0xf0000000, 0x00000008, + 0x00000000, 0x00000009, 0x10000000, 0x00000009, + 0x20000000, 0x00000019, 0x30000000, 0x00000019, + 0x40000000, 0x00000019, 0x50000000, 0x00000019, + 0x60000000, 0x00000019, 0x70000000, 0x00000019, + 0x80000000, 0x00000019, 0x90000000, 0x00000019, + 0xa0000000, 0x00000019, 0xb0000000, 0x00000019, + 0xc0000000, 0x00000019, 0xd0000000, 0x00000019, + 0xe0000000, 0x00000019, 0xf0000000, 0x00000019, + 0x00000000, 0x0000001a, 0x10000000, 0x0000001a, + 0x20000000, 0x0000001a, 0x30000000, 0x0000001a, + 0x40000000, 0x0000001a, 0x50000000, 0x00000002, + 0x60000000, 0x00000002, 0x70000000, 0x00000002, + 0x80000000, 0x00000002, 0x90000000, 0x00000002, + 0xa0000000, 0x00000002, 0xb0000000, 0x00000002, + 0xc0000000, 0x0000000a, 0xd0000000, 0x0000000a, + 0xe0000000, 0x0000000a, 0xf0000000, 0x0000000a, + 0x00000000, 0x0000000b, 0x10000000, 0x0000000b, + 0x20000000, 0x0000000b, 0x30000000, 0x0000000b, + 0x40000000, 0x0000000b, 0x50000000, 0x0000001b, + 0x60000000, 0x0000001b, 0x70000000, 0x0000001b, + 0x80000000, 0x0000001b, 0x90000000, 0x0000001b, + 0xa0000000, 0x0000001b, 0xb0000000, 0x0000001b, + 0xc0000000, 0x0000001b, 0xd0000000, 0x0000001b, + 0xe0000000, 0x0000001b, 0xf0000000, 0x0000001b, + 0x00000000, 0x0000001c, 0x10000000, 0x0000001c, + 0x20000000, 0x0000001c, 0x30000000, 0x0000001c, + 0x40000000, 0x0000001c, 0x50000000, 0x0000001c, + 0x60000000, 0x0000001c, 0x70000000, 0x0000001c, + 0x80000000, 0x0000001c, 0x90000000, 0x0000001c, +}; + +static const u16 b43_lcntab_0x0e[] = { + 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, + 0x0407, 0x0408, 0x0409, 0x040a, 0x058b, 0x058c, + 0x058d, 0x058e, 0x058f, 0x0090, 0x0091, 0x0092, + 0x0193, 0x0194, 0x0195, 0x0196, 0x0197, 0x0198, + 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e, + 0x019f, 0x01a0, 0x01a1, 0x01a2, 0x01a3, 0x01a4, + 0x01a5, 0x0000, +}; + +static const u16 b43_lcntab_0x0f[] = { + 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009, + 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005, + 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009, + 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005, + 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009, + 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005, + 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009, + 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005, + 0x000a, 0x0009, 0x0006, 0x0005, 0x000a, 0x0009, + 0x0006, 0x0005, 0x000a, 0x0009, 0x0006, 0x0005, + 0x000a, 0x0009, 0x0006, 0x0005, +}; + +static const u16 b43_lcntab_0x10[] = { + 0x005f, 0x0036, 0x0029, 0x001f, 0x005f, 0x0036, + 0x0029, 0x001f, 0x005f, 0x0036, 0x0029, 0x001f, + 0x005f, 0x0036, 0x0029, 0x001f, +}; + +static const u16 b43_lcntab_0x11[] = { + 0x0009, 0x000f, 0x0014, 0x0018, 0x00fe, 0x0007, + 0x000b, 0x000f, 0x00fb, 0x00fe, 0x0001, 0x0005, + 0x0008, 0x000b, 0x000e, 0x0011, 0x0014, 0x0017, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0003, 0x0006, 0x0009, 0x000c, 0x000f, + 0x0012, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, + 0x0006, 0x0009, 0x000c, 0x000f, 0x0012, 0x0015, + 0x0018, 0x001b, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0003, 0x00eb, 0x0000, 0x0000, +}; + +static const u32 b43_lcntab_0x12[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000004, 0x00000000, 0x00000004, 0x00000008, + 0x00000001, 0x00000005, 0x00000009, 0x0000000d, + 0x0000004d, 0x0000008d, 0x0000000d, 0x0000004d, + 0x0000008d, 0x000000cd, 0x0000004f, 0x0000008f, + 0x000000cf, 0x000000d3, 0x00000113, 0x00000513, + 0x00000913, 0x00000953, 0x00000d53, 0x00001153, + 0x00001193, 0x00005193, 0x00009193, 0x0000d193, + 0x00011193, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000004, + 0x00000000, 0x00000004, 0x00000008, 0x00000001, + 0x00000005, 0x00000009, 0x0000000d, 0x0000004d, + 0x0000008d, 0x0000000d, 0x0000004d, 0x0000008d, + 0x000000cd, 0x0000004f, 0x0000008f, 0x000000cf, + 0x000000d3, 0x00000113, 0x00000513, 0x00000913, + 0x00000953, 0x00000d53, 0x00001153, 0x00005153, + 0x00009153, 0x0000d153, 0x00011153, 0x00015153, + 0x00019153, 0x0001d153, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, +}; + +static const u16 b43_lcntab_0x14[] = { + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0002, 0x0003, 0x0001, 0x0003, 0x0002, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0003, + 0x0001, 0x0003, 0x0002, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, +}; + +static const u16 b43_lcntab_0x17[] = { + 0x001a, 0x0034, 0x004e, 0x0068, 0x009c, 0x00d0, + 0x00ea, 0x0104, 0x0034, 0x0068, 0x009c, 0x00d0, + 0x0138, 0x01a0, 0x01d4, 0x0208, 0x004e, 0x009c, + 0x00ea, 0x0138, 0x01d4, 0x0270, 0x02be, 0x030c, + 0x0068, 0x00d0, 0x0138, 0x01a0, 0x0270, 0x0340, + 0x03a8, 0x0410, 0x0018, 0x009c, 0x00d0, 0x0104, + 0x00ea, 0x0138, 0x0186, 0x00d0, 0x0104, 0x0104, + 0x0138, 0x016c, 0x016c, 0x01a0, 0x0138, 0x0186, + 0x0186, 0x01d4, 0x0222, 0x0222, 0x0270, 0x0104, + 0x0138, 0x016c, 0x0138, 0x016c, 0x01a0, 0x01d4, + 0x01a0, 0x01d4, 0x0208, 0x0208, 0x023c, 0x0186, + 0x01d4, 0x0222, 0x01d4, 0x0222, 0x0270, 0x02be, + 0x0270, 0x02be, 0x030c, 0x030c, 0x035a, 0x0036, + 0x006c, 0x00a2, 0x00d8, 0x0144, 0x01b0, 0x01e6, + 0x021c, 0x006c, 0x00d8, 0x0144, 0x01b0, 0x0288, + 0x0360, 0x03cc, 0x0438, 0x00a2, 0x0144, 0x01e6, + 0x0288, 0x03cc, 0x0510, 0x05b2, 0x0654, 0x00d8, + 0x01b0, 0x0288, 0x0360, 0x0510, 0x06c0, 0x0798, + 0x0870, 0x0018, 0x0144, 0x01b0, 0x021c, 0x01e6, + 0x0288, 0x032a, 0x01b0, 0x021c, 0x021c, 0x0288, + 0x02f4, 0x02f4, 0x0360, 0x0288, 0x032a, 0x032a, + 0x03cc, 0x046e, 0x046e, 0x0510, 0x021c, 0x0288, + 0x02f4, 0x0288, 0x02f4, 0x0360, 0x03cc, 0x0360, + 0x03cc, 0x0438, 0x0438, 0x04a4, 0x032a, 0x03cc, + 0x046e, 0x03cc, 0x046e, 0x0510, 0x05b2, 0x0510, + 0x05b2, 0x0654, 0x0654, 0x06f6, +}; + +static const u16 b43_lcntab_0x00[] = { + 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, + 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, + 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600, + 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, + 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, + 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static const u32 b43_lcntab_0x18[] = { + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, + 0x00080000, 0x00080000, 0x00080000, 0x00080000, +}; + +/************************************************** + * TX gain. + **************************************************/ + +const struct b43_lcntab_tx_gain_tbl_entry + b43_lcntab_tx_gain_tbl_2ghz_ext_pa_rev0[B43_LCNTAB_TX_GAIN_SIZE] = { + { 0x03, 0x00, 0x1f, 0x0, 0x48 }, + { 0x03, 0x00, 0x1f, 0x0, 0x46 }, + { 0x03, 0x00, 0x1f, 0x0, 0x44 }, + { 0x03, 0x00, 0x1e, 0x0, 0x43 }, + { 0x03, 0x00, 0x1d, 0x0, 0x44 }, + { 0x03, 0x00, 0x1c, 0x0, 0x44 }, + { 0x03, 0x00, 0x1b, 0x0, 0x45 }, + { 0x03, 0x00, 0x1a, 0x0, 0x46 }, + { 0x03, 0x00, 0x19, 0x0, 0x46 }, + { 0x03, 0x00, 0x18, 0x0, 0x47 }, + { 0x03, 0x00, 0x17, 0x0, 0x48 }, + { 0x03, 0x00, 0x17, 0x0, 0x46 }, + { 0x03, 0x00, 0x16, 0x0, 0x47 }, + { 0x03, 0x00, 0x15, 0x0, 0x48 }, + { 0x03, 0x00, 0x15, 0x0, 0x46 }, + { 0x03, 0x00, 0x15, 0x0, 0x44 }, + { 0x03, 0x00, 0x15, 0x0, 0x42 }, + { 0x03, 0x00, 0x15, 0x0, 0x40 }, + { 0x03, 0x00, 0x15, 0x0, 0x3f }, + { 0x03, 0x00, 0x14, 0x0, 0x40 }, + { 0x03, 0x00, 0x13, 0x0, 0x41 }, + { 0x03, 0x00, 0x13, 0x0, 0x40 }, + { 0x03, 0x00, 0x12, 0x0, 0x41 }, + { 0x03, 0x00, 0x12, 0x0, 0x40 }, + { 0x03, 0x00, 0x11, 0x0, 0x41 }, + { 0x03, 0x00, 0x11, 0x0, 0x40 }, + { 0x03, 0x00, 0x10, 0x0, 0x41 }, + { 0x03, 0x00, 0x10, 0x0, 0x40 }, + { 0x03, 0x00, 0x10, 0x0, 0x3e }, + { 0x03, 0x00, 0x10, 0x0, 0x3c }, + { 0x03, 0x00, 0x10, 0x0, 0x3a }, + { 0x03, 0x00, 0x0f, 0x0, 0x3d }, + { 0x03, 0x00, 0x0f, 0x0, 0x3b }, + { 0x03, 0x00, 0x0e, 0x0, 0x3d }, + { 0x03, 0x00, 0x0e, 0x0, 0x3c }, + { 0x03, 0x00, 0x0e, 0x0, 0x3a }, + { 0x03, 0x00, 0x0d, 0x0, 0x3c }, + { 0x03, 0x00, 0x0d, 0x0, 0x3b }, + { 0x03, 0x00, 0x0c, 0x0, 0x3e }, + { 0x03, 0x00, 0x0c, 0x0, 0x3c }, + { 0x03, 0x00, 0x0c, 0x0, 0x3a }, + { 0x03, 0x00, 0x0b, 0x0, 0x3e }, + { 0x03, 0x00, 0x0b, 0x0, 0x3c }, + { 0x03, 0x00, 0x0b, 0x0, 0x3b }, + { 0x03, 0x00, 0x0b, 0x0, 0x39 }, + { 0x03, 0x00, 0x0a, 0x0, 0x3d }, + { 0x03, 0x00, 0x0a, 0x0, 0x3b }, + { 0x03, 0x00, 0x0a, 0x0, 0x39 }, + { 0x03, 0x00, 0x09, 0x0, 0x3e }, + { 0x03, 0x00, 0x09, 0x0, 0x3c }, + { 0x03, 0x00, 0x09, 0x0, 0x3a }, + { 0x03, 0x00, 0x09, 0x0, 0x39 }, + { 0x03, 0x00, 0x08, 0x0, 0x3e }, + { 0x03, 0x00, 0x08, 0x0, 0x3c }, + { 0x03, 0x00, 0x08, 0x0, 0x3a }, + { 0x03, 0x00, 0x08, 0x0, 0x39 }, + { 0x03, 0x00, 0x08, 0x0, 0x37 }, + { 0x03, 0x00, 0x07, 0x0, 0x3d }, + { 0x03, 0x00, 0x07, 0x0, 0x3c }, + { 0x03, 0x00, 0x07, 0x0, 0x3a }, + { 0x03, 0x00, 0x07, 0x0, 0x38 }, + { 0x03, 0x00, 0x07, 0x0, 0x37 }, + { 0x03, 0x00, 0x06, 0x0, 0x3e }, + { 0x03, 0x00, 0x06, 0x0, 0x3c }, + { 0x03, 0x00, 0x06, 0x0, 0x3a }, + { 0x03, 0x00, 0x06, 0x0, 0x39 }, + { 0x03, 0x00, 0x06, 0x0, 0x37 }, + { 0x03, 0x00, 0x06, 0x0, 0x36 }, + { 0x03, 0x00, 0x06, 0x0, 0x34 }, + { 0x03, 0x00, 0x05, 0x0, 0x3d }, + { 0x03, 0x00, 0x05, 0x0, 0x3b }, + { 0x03, 0x00, 0x05, 0x0, 0x39 }, + { 0x03, 0x00, 0x05, 0x0, 0x38 }, + { 0x03, 0x00, 0x05, 0x0, 0x36 }, + { 0x03, 0x00, 0x05, 0x0, 0x35 }, + { 0x03, 0x00, 0x05, 0x0, 0x33 }, + { 0x03, 0x00, 0x04, 0x0, 0x3e }, + { 0x03, 0x00, 0x04, 0x0, 0x3c }, + { 0x03, 0x00, 0x04, 0x0, 0x3a }, + { 0x03, 0x00, 0x04, 0x0, 0x39 }, + { 0x03, 0x00, 0x04, 0x0, 0x37 }, + { 0x03, 0x00, 0x04, 0x0, 0x36 }, + { 0x03, 0x00, 0x04, 0x0, 0x34 }, + { 0x03, 0x00, 0x04, 0x0, 0x33 }, + { 0x03, 0x00, 0x04, 0x0, 0x31 }, + { 0x03, 0x00, 0x04, 0x0, 0x30 }, + { 0x03, 0x00, 0x04, 0x0, 0x2e }, + { 0x03, 0x00, 0x03, 0x0, 0x3c }, + { 0x03, 0x00, 0x03, 0x0, 0x3a }, + { 0x03, 0x00, 0x03, 0x0, 0x39 }, + { 0x03, 0x00, 0x03, 0x0, 0x37 }, + { 0x03, 0x00, 0x03, 0x0, 0x36 }, + { 0x03, 0x00, 0x03, 0x0, 0x34 }, + { 0x03, 0x00, 0x03, 0x0, 0x33 }, + { 0x03, 0x00, 0x03, 0x0, 0x31 }, + { 0x03, 0x00, 0x03, 0x0, 0x30 }, + { 0x03, 0x00, 0x03, 0x0, 0x2e }, + { 0x03, 0x00, 0x03, 0x0, 0x2d }, + { 0x03, 0x00, 0x03, 0x0, 0x2c }, + { 0x03, 0x00, 0x03, 0x0, 0x2b }, + { 0x03, 0x00, 0x03, 0x0, 0x29 }, + { 0x03, 0x00, 0x02, 0x0, 0x3d }, + { 0x03, 0x00, 0x02, 0x0, 0x3b }, + { 0x03, 0x00, 0x02, 0x0, 0x39 }, + { 0x03, 0x00, 0x02, 0x0, 0x38 }, + { 0x03, 0x00, 0x02, 0x0, 0x36 }, + { 0x03, 0x00, 0x02, 0x0, 0x35 }, + { 0x03, 0x00, 0x02, 0x0, 0x33 }, + { 0x03, 0x00, 0x02, 0x0, 0x32 }, + { 0x03, 0x00, 0x02, 0x0, 0x30 }, + { 0x03, 0x00, 0x02, 0x0, 0x2f }, + { 0x03, 0x00, 0x02, 0x0, 0x2e }, + { 0x03, 0x00, 0x02, 0x0, 0x2c }, + { 0x03, 0x00, 0x02, 0x0, 0x2b }, + { 0x03, 0x00, 0x02, 0x0, 0x2a }, + { 0x03, 0x00, 0x02, 0x0, 0x29 }, + { 0x03, 0x00, 0x02, 0x0, 0x27 }, + { 0x03, 0x00, 0x02, 0x0, 0x26 }, + { 0x03, 0x00, 0x02, 0x0, 0x25 }, + { 0x03, 0x00, 0x02, 0x0, 0x24 }, + { 0x03, 0x00, 0x02, 0x0, 0x23 }, + { 0x03, 0x00, 0x02, 0x0, 0x22 }, + { 0x03, 0x00, 0x02, 0x0, 0x21 }, + { 0x03, 0x00, 0x02, 0x0, 0x20 }, + { 0x03, 0x00, 0x01, 0x0, 0x3f }, + { 0x03, 0x00, 0x01, 0x0, 0x3d }, + { 0x03, 0x00, 0x01, 0x0, 0x3b }, + { 0x03, 0x00, 0x01, 0x0, 0x39 }, +}; + +/************************************************** + * SW control. + **************************************************/ + +const u16 b43_lcntab_sw_ctl_4313_epa_rev0[] = { + 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008, + 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001, + 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008, + 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001, + 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008, + 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001, + 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008, + 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001, + 0x0002, 0x0008, 0x0004, 0x0001, 0x0002, 0x0008, + 0x0004, 0x0001, 0x0002, 0x0008, 0x0004, 0x0001, + 0x0002, 0x0008, 0x0004, 0x0001, +}; + +/************************************************** + * R/W ops. + **************************************************/ + +u32 b43_lcntab_read(struct b43_wldev *dev, u32 offset) +{ + u32 type, value; + + type = offset & B43_LCNTAB_TYPEMASK; + offset &= ~B43_LCNTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + switch (type) { + case B43_LCNTAB_8BIT: + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO) & 0xFF; + break; + case B43_LCNTAB_16BIT: + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO); + break; + case B43_LCNTAB_32BIT: + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset); + value = b43_phy_read(dev, B43_PHY_LCN_TABLE_DATALO); + value |= (b43_phy_read(dev, B43_PHY_LCN_TABLE_DATAHI) << 16); + break; + default: + B43_WARN_ON(1); + value = 0; + } + + return value; +} + +void b43_lcntab_read_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, void *_data) +{ + u32 type; + u8 *data = _data; + unsigned int i; + + type = offset & B43_LCNTAB_TYPEMASK; + offset &= ~B43_LCNTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset); + + for (i = 0; i < nr_elements; i++) { + switch (type) { + case B43_LCNTAB_8BIT: + *data = b43_phy_read(dev, + B43_PHY_LCN_TABLE_DATALO) & 0xFF; + data++; + break; + case B43_LCNTAB_16BIT: + *((u16 *)data) = b43_phy_read(dev, + B43_PHY_LCN_TABLE_DATALO); + data += 2; + break; + case B43_LCNTAB_32BIT: + *((u32 *)data) = b43_phy_read(dev, + B43_PHY_LCN_TABLE_DATALO); + *((u32 *)data) |= (b43_phy_read(dev, + B43_PHY_LCN_TABLE_DATAHI) << 16); + data += 4; + break; + default: + B43_WARN_ON(1); + } + } +} + +void b43_lcntab_write(struct b43_wldev *dev, u32 offset, u32 value) +{ + u32 type; + + type = offset & B43_LCNTAB_TYPEMASK; + offset &= 0xFFFF; + + switch (type) { + case B43_LCNTAB_8BIT: + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value); + break; + case B43_LCNTAB_16BIT: + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value); + break; + case B43_LCNTAB_32BIT: + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, value >> 16); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value & 0xFFFF); + break; + default: + B43_WARN_ON(1); + } + + return; +} + +void b43_lcntab_write_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, const void *_data) +{ + u32 type, value; + const u8 *data = _data; + unsigned int i; + + type = offset & B43_LCNTAB_TYPEMASK; + offset &= ~B43_LCNTAB_TYPEMASK; + B43_WARN_ON(offset > 0xFFFF); + + b43_phy_write(dev, B43_PHY_LCN_TABLE_ADDR, offset); + + for (i = 0; i < nr_elements; i++) { + switch (type) { + case B43_LCNTAB_8BIT: + value = *data; + data++; + B43_WARN_ON(value & ~0xFF); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value); + break; + case B43_LCNTAB_16BIT: + value = *((u16 *)data); + data += 2; + B43_WARN_ON(value & ~0xFFFF); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, value); + break; + case B43_LCNTAB_32BIT: + value = *((u32 *)data); + data += 4; + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATAHI, + value >> 16); + b43_phy_write(dev, B43_PHY_LCN_TABLE_DATALO, + value & 0xFFFF); + break; + default: + B43_WARN_ON(1); + } + } +} + /************************************************** * Tables ops. **************************************************/ +#define lcntab_upload(dev, offset, data) do { \ + b43_lcntab_write_bulk(dev, offset, ARRAY_SIZE(data), data); \ + } while (0) +static void b43_phy_lcn_upload_static_tables(struct b43_wldev *dev) +{ + lcntab_upload(dev, B43_LCNTAB16(0x02, 0), b43_lcntab_0x02); + lcntab_upload(dev, B43_LCNTAB16(0x01, 0), b43_lcntab_0x01); + lcntab_upload(dev, B43_LCNTAB32(0x0b, 0), b43_lcntab_0x0b); + lcntab_upload(dev, B43_LCNTAB32(0x0c, 0), b43_lcntab_0x0c); + lcntab_upload(dev, B43_LCNTAB32(0x0d, 0), b43_lcntab_0x0d); + lcntab_upload(dev, B43_LCNTAB16(0x0e, 0), b43_lcntab_0x0e); + lcntab_upload(dev, B43_LCNTAB16(0x0f, 0), b43_lcntab_0x0f); + lcntab_upload(dev, B43_LCNTAB16(0x10, 0), b43_lcntab_0x10); + lcntab_upload(dev, B43_LCNTAB16(0x11, 0), b43_lcntab_0x11); + lcntab_upload(dev, B43_LCNTAB32(0x12, 0), b43_lcntab_0x12); + lcntab_upload(dev, B43_LCNTAB16(0x14, 0), b43_lcntab_0x14); + lcntab_upload(dev, B43_LCNTAB16(0x17, 0), b43_lcntab_0x17); + lcntab_upload(dev, B43_LCNTAB16(0x00, 0), b43_lcntab_0x00); + lcntab_upload(dev, B43_LCNTAB32(0x18, 0), b43_lcntab_0x18); +} + +void b43_phy_lcn_load_tx_gain_tab(struct b43_wldev *dev, + const struct b43_lcntab_tx_gain_tbl_entry *gain_table) +{ + u32 i; + u32 val; + + u16 pa_gain = 0x70; + if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_FEM) + pa_gain = 0x10; + + for (i = 0; i < B43_LCNTAB_TX_GAIN_SIZE; i++) { + val = ((pa_gain << 24) | + (gain_table[i].pad << 16) | + (gain_table[i].pga << 8) | + gain_table[i].gm); + b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0xc0 + i), val); + + /* brcmsmac doesn't maskset, we follow newer wl here */ + val = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0x140 + i)); + val &= 0x000fffff; + val |= ((gain_table[i].dac << 28) | + (gain_table[i].bb_mult << 20)); + b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0x140 + i), val); + } +} + +/* wlc_lcnphy_load_rfpower */ +static void b43_phy_lcn_load_rfpower(struct b43_wldev *dev) +{ + u32 bbmult, rfgain; + u8 i; + + for (i = 0; i < 128; i++) { + bbmult = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0x140 + i)); + bbmult >>= 20; + rfgain = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0xc0 + i)); + + /* TODO: calculate value for 0x240 + i table offset + * b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0x240 + i), val); + */ + } +} + +/* Not implemented in brcmsmac, noticed in wl in MMIO dump */ +static void b43_phy_lcn_rewrite_rfpower_table(struct b43_wldev *dev) +{ + int i; + u32 tmp; + for (i = 0; i < 128; i++) { + tmp = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0x240 + i)); + b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0x240 + i), tmp); + } +} + +/* wlc_lcnphy_clear_papd_comptable */ +static void b43_phy_lcn_clean_papd_comp_table(struct b43_wldev *dev) +{ + u8 i; + + for (i = 0; i < 0x80; i++) + b43_lcntab_write(dev, B43_LCNTAB32(0x18, i), 0x80000); +} + +/* wlc_lcnphy_tbl_init */ void b43_phy_lcn_tables_init(struct b43_wldev *dev) { + struct ssb_sprom *sprom = dev->dev->bus_sprom; + + b43_phy_lcn_upload_static_tables(dev); + + if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) { + if (sprom->boardflags_lo & B43_BFL_FEM) + b43_phy_lcn_load_tx_gain_tab(dev, + b43_lcntab_tx_gain_tbl_2ghz_ext_pa_rev0); + else + b43err(dev->wl, + "TX gain table unknown for this card\n"); + } + + if (sprom->boardflags_lo & B43_BFL_FEM && + !(sprom->boardflags_hi & B43_BFH_FEM_BT)) + b43_lcntab_write_bulk(dev, B43_LCNTAB16(0xf, 0), + ARRAY_SIZE(b43_lcntab_sw_ctl_4313_epa_rev0), + b43_lcntab_sw_ctl_4313_epa_rev0); + else + b43err(dev->wl, "SW ctl table is unknown for this card\n"); + + b43_phy_lcn_load_rfpower(dev); + b43_phy_lcn_rewrite_rfpower_table(dev); + b43_phy_lcn_clean_papd_comp_table(dev); } diff --git a/drivers/net/wireless/b43/tables_phy_lcn.h b/drivers/net/wireless/b43/tables_phy_lcn.h index 5e31b15b81ec..caff9db6831f 100644 --- a/drivers/net/wireless/b43/tables_phy_lcn.h +++ b/drivers/net/wireless/b43/tables_phy_lcn.h @@ -1,6 +1,24 @@ #ifndef B43_TABLES_PHY_LCN_H_ #define B43_TABLES_PHY_LCN_H_ +/* The LCN-PHY tables. */ +#define B43_LCNTAB_TYPEMASK 0xF0000000 +#define B43_LCNTAB_8BIT 0x10000000 +#define B43_LCNTAB_16BIT 0x20000000 +#define B43_LCNTAB_32BIT 0x30000000 +#define B43_LCNTAB8(table, offset) (((table) << 10) | (offset) | B43_LCNTAB_8BIT) +#define B43_LCNTAB16(table, offset) (((table) << 10) | (offset) | B43_LCNTAB_16BIT) +#define B43_LCNTAB32(table, offset) (((table) << 10) | (offset) | B43_LCNTAB_32BIT) + +#define B43_LCNTAB_TX_GAIN_SIZE 128 + +u32 b43_lcntab_read(struct b43_wldev *dev, u32 offset); +void b43_lcntab_read_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, void *_data); +void b43_lcntab_write(struct b43_wldev *dev, u32 offset, u32 value); +void b43_lcntab_write_bulk(struct b43_wldev *dev, u32 offset, + unsigned int nr_elements, const void *_data); + void b43_phy_lcn_tables_init(struct b43_wldev *dev); #endif /* B43_TABLES_PHY_LCN_H_ */ diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index b74f25ec1ab4..c73e8600d218 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -337,12 +337,19 @@ int b43_generate_txhdr(struct b43_wldev *dev, memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len); } } - if (b43_is_old_txhdr_format(dev)) { - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->old_format.plcp), + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_598.plcp), plcp_fragment_len, rate); - } else { - b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->new_format.plcp), + break; + case B43_FW_HDR_351: + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_351.plcp), + plcp_fragment_len, rate); + break; + case B43_FW_HDR_410: + b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->format_410.plcp), plcp_fragment_len, rate); + break; } b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb), plcp_fragment_len, rate_fb); @@ -415,10 +422,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; - struct ieee80211_hdr *hdr; + struct ieee80211_hdr *uninitialized_var(hdr); int rts_rate, rts_rate_fb; int rts_rate_ofdm, rts_rate_fb_ofdm; - struct b43_plcp_hdr6 *plcp; + struct b43_plcp_hdr6 *uninitialized_var(plcp); struct ieee80211_rate *rts_cts_rate; rts_cts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info); @@ -429,14 +436,21 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { - struct ieee80211_cts *cts; + struct ieee80211_cts *uninitialized_var(cts); - if (b43_is_old_txhdr_format(dev)) { + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: cts = (struct ieee80211_cts *) - (txhdr->old_format.rts_frame); - } else { + (txhdr->format_598.rts_frame); + break; + case B43_FW_HDR_351: cts = (struct ieee80211_cts *) - (txhdr->new_format.rts_frame); + (txhdr->format_351.rts_frame); + break; + case B43_FW_HDR_410: + cts = (struct ieee80211_cts *) + (txhdr->format_410.rts_frame); + break; } ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, @@ -444,14 +458,21 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= B43_TXH_MAC_SENDCTS; len = sizeof(struct ieee80211_cts); } else { - struct ieee80211_rts *rts; + struct ieee80211_rts *uninitialized_var(rts); - if (b43_is_old_txhdr_format(dev)) { + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: rts = (struct ieee80211_rts *) - (txhdr->old_format.rts_frame); - } else { + (txhdr->format_598.rts_frame); + break; + case B43_FW_HDR_351: rts = (struct ieee80211_rts *) - (txhdr->new_format.rts_frame); + (txhdr->format_351.rts_frame); + break; + case B43_FW_HDR_410: + rts = (struct ieee80211_rts *) + (txhdr->format_410.rts_frame); + break; } ieee80211_rts_get(dev->wl->hw, info->control.vif, fragment_data, fragment_len, @@ -462,22 +483,36 @@ int b43_generate_txhdr(struct b43_wldev *dev, len += FCS_LEN; /* Generate the PLCP headers for the RTS/CTS frame */ - if (b43_is_old_txhdr_format(dev)) - plcp = &txhdr->old_format.rts_plcp; - else - plcp = &txhdr->new_format.rts_plcp; + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: + plcp = &txhdr->format_598.rts_plcp; + break; + case B43_FW_HDR_351: + plcp = &txhdr->format_351.rts_plcp; + break; + case B43_FW_HDR_410: + plcp = &txhdr->format_410.rts_plcp; + break; + } b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, len, rts_rate); plcp = &txhdr->rts_plcp_fb; b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)plcp, len, rts_rate_fb); - if (b43_is_old_txhdr_format(dev)) { + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: hdr = (struct ieee80211_hdr *) - (&txhdr->old_format.rts_frame); - } else { + (&txhdr->format_598.rts_frame); + break; + case B43_FW_HDR_351: hdr = (struct ieee80211_hdr *) - (&txhdr->new_format.rts_frame); + (&txhdr->format_351.rts_frame); + break; + case B43_FW_HDR_410: + hdr = (struct ieee80211_hdr *) + (&txhdr->format_410.rts_frame); + break; } txhdr->rts_dur_fb = hdr->duration_id; @@ -505,10 +540,17 @@ int b43_generate_txhdr(struct b43_wldev *dev, } /* Magic cookie */ - if (b43_is_old_txhdr_format(dev)) - txhdr->old_format.cookie = cpu_to_le16(cookie); - else - txhdr->new_format.cookie = cpu_to_le16(cookie); + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: + txhdr->format_598.cookie = cpu_to_le16(cookie); + break; + case B43_FW_HDR_351: + txhdr->format_351.cookie = cpu_to_le16(cookie); + break; + case B43_FW_HDR_410: + txhdr->format_410.cookie = cpu_to_le16(cookie); + break; + } if (phy->type == B43_PHYTYPE_N) { txhdr->phy_ctl1 = @@ -611,8 +653,9 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) struct ieee80211_hdr *wlhdr; const struct b43_rxhdr_fw4 *rxhdr = _rxhdr; __le16 fctl; - u16 phystat0, phystat3, chanstat, mactime; - u32 macstat; + u16 phystat0, phystat3; + u16 uninitialized_var(chanstat), uninitialized_var(mactime); + u32 uninitialized_var(macstat); u16 chanid; u16 phytype; int padding; @@ -622,9 +665,19 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) /* Get metadata about the frame from the header. */ phystat0 = le16_to_cpu(rxhdr->phy_status0); phystat3 = le16_to_cpu(rxhdr->phy_status3); - macstat = le32_to_cpu(rxhdr->mac_status); - mactime = le16_to_cpu(rxhdr->mac_time); - chanstat = le16_to_cpu(rxhdr->channel); + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: + macstat = le32_to_cpu(rxhdr->format_598.mac_status); + mactime = le16_to_cpu(rxhdr->format_598.mac_time); + chanstat = le16_to_cpu(rxhdr->format_598.channel); + break; + case B43_FW_HDR_410: + case B43_FW_HDR_351: + macstat = le32_to_cpu(rxhdr->format_351.mac_status); + mactime = le16_to_cpu(rxhdr->format_351.mac_time); + chanstat = le16_to_cpu(rxhdr->format_351.channel); + break; + } phytype = chanstat & B43_RX_CHAN_PHYTYPE; if (unlikely(macstat & B43_RX_MAC_FCSERR)) { @@ -682,16 +735,22 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) } /* Link quality statistics */ - if ((chanstat & B43_RX_CHAN_PHYTYPE) == B43_PHYTYPE_N) { -// s8 rssi = max(rxhdr->power0, rxhdr->power1); - //TODO: Find out what the rssi value is (dBm or percentage?) - // and also find out what the maximum possible value is. - // Fill status.ssi and status.signal fields. - } else { + switch (chanstat & B43_RX_CHAN_PHYTYPE) { + case B43_PHYTYPE_N: + if (rxhdr->power0 == 16 || rxhdr->power0 == 32) + status.signal = max(rxhdr->power1, rxhdr->power2); + else + status.signal = max(rxhdr->power0, rxhdr->power1); + break; + case B43_PHYTYPE_A: + case B43_PHYTYPE_B: + case B43_PHYTYPE_G: + case B43_PHYTYPE_LP: status.signal = b43_rssi_postprocess(dev, rxhdr->jssi, (phystat0 & B43_RX_PHYST0_OFDM), (phystat0 & B43_RX_PHYST0_GAINCTL), (phystat3 & B43_RX_PHYST3_TRSTATE)); + break; } if (phystat0 & B43_RX_PHYST0_OFDM) @@ -744,6 +803,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) break; case B43_PHYTYPE_N: case B43_PHYTYPE_LP: + case B43_PHYTYPE_HT: /* chanid is the SHM channel cookie. Which is the plain * channel number in b43. */ if (chanstat & B43_RX_CHAN_5GHZ) { diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 42debb5cd6fa..16c514d54afa 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -46,7 +46,24 @@ struct b43_txhdr { __le32 timeout; /* Timeout */ union { - /* The new r410 format. */ + /* Tested with 598.314, 644.1001 and 666.2 */ + struct { + __le16 mimo_antenna; /* MIMO antenna select */ + __le16 preload_size; /* Preload size */ + PAD_BYTES(2); + __le16 cookie; /* TX frame cookie */ + __le16 tx_status; /* TX status */ + __le16 max_n_mpdus; + __le16 max_a_bytes_mrt; + __le16 max_a_bytes_fbr; + __le16 min_m_bytes; + struct b43_plcp_hdr6 rts_plcp; /* RTS PLCP header */ + __u8 rts_frame[16]; /* The RTS frame (if used) */ + PAD_BYTES(2); + struct b43_plcp_hdr6 plcp; /* Main PLCP header */ + } format_598 __packed; + + /* Tested with 410.2160, 478.104 and 508.* */ struct { __le16 mimo_antenna; /* MIMO antenna select */ __le16 preload_size; /* Preload size */ @@ -57,9 +74,9 @@ struct b43_txhdr { __u8 rts_frame[16]; /* The RTS frame (if used) */ PAD_BYTES(2); struct b43_plcp_hdr6 plcp; /* Main PLCP header */ - } new_format __packed; + } format_410 __packed; - /* The old r351 format. */ + /* Tested with 351.126 */ struct { PAD_BYTES(2); __le16 cookie; /* TX frame cookie */ @@ -68,7 +85,7 @@ struct b43_txhdr { __u8 rts_frame[16]; /* The RTS frame (if used) */ PAD_BYTES(2); struct b43_plcp_hdr6 plcp; /* Main PLCP header */ - } old_format __packed; + } format_351 __packed; } __packed; } __packed; @@ -166,19 +183,18 @@ struct b43_tx_legacy_rate_phy_ctl_entry { #define B43_TXH_PHY1_MODUL_QAM256 0x2000 /* QAM256 */ -/* r351 firmware compatibility stuff. */ -static inline -bool b43_is_old_txhdr_format(struct b43_wldev *dev) -{ - return (dev->fw.rev <= 351); -} - static inline size_t b43_txhdr_size(struct b43_wldev *dev) { - if (b43_is_old_txhdr_format(dev)) + switch (dev->fw.hdr_format) { + case B43_FW_HDR_598: + return 112 + sizeof(struct b43_plcp_hdr6); + case B43_FW_HDR_410: + return 104 + sizeof(struct b43_plcp_hdr6); + case B43_FW_HDR_351: return 100 + sizeof(struct b43_plcp_hdr6); - return 104 + sizeof(struct b43_plcp_hdr6); + } + return 0; } @@ -232,11 +248,33 @@ struct b43_rxhdr_fw4 { __s8 power1; /* PHY RX Status 1: Power 1 */ } __packed; } __packed; - __le16 phy_status2; /* PHY RX Status 2 */ + union { + /* RSSI for N-PHYs */ + struct { + __s8 power2; + PAD_BYTES(1); + } __packed; + + __le16 phy_status2; /* PHY RX Status 2 */ + } __packed; __le16 phy_status3; /* PHY RX Status 3 */ - __le32 mac_status; /* MAC RX status */ - __le16 mac_time; - __le16 channel; + union { + /* Tested with 598.314, 644.1001 and 666.2 */ + struct { + __le16 phy_status4; /* PHY RX Status 4 */ + __le16 phy_status5; /* PHY RX Status 5 */ + __le32 mac_status; /* MAC RX status */ + __le16 mac_time; + __le16 channel; + } format_598 __packed; + + /* Tested with 351.126, 410.2160, 478.104 and 508.* */ + struct { + __le32 mac_status; /* MAC RX status */ + __le16 mac_time; + __le16 channel; + } format_351 __packed; + } __packed; } __packed; /* PHY RX Status 0 */ diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index a610a352102a..12b518251581 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -14,7 +14,6 @@ #include <linux/ssb/ssb.h> #include <linux/ssb/ssb_driver_chipcommon.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include "debugfs.h" @@ -23,10 +22,6 @@ #include "phy.h" -/* The unique identifier of the firmware that's officially supported by this - * driver version. */ -#define B43legacy_SUPPORTED_FIRMWARE_ID "FW10" - #define B43legacy_IRQWAIT_MAX_RETRIES 20 /* MMIO offsets */ diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 5010c477abdf..c5535adf6991 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -42,10 +42,9 @@ /* 32bit DMA ops. */ static -struct b43legacy_dmadesc_generic *op32_idx2desc( - struct b43legacy_dmaring *ring, - int slot, - struct b43legacy_dmadesc_meta **meta) +struct b43legacy_dmadesc32 *op32_idx2desc(struct b43legacy_dmaring *ring, + int slot, + struct b43legacy_dmadesc_meta **meta) { struct b43legacy_dmadesc32 *desc; @@ -53,11 +52,11 @@ struct b43legacy_dmadesc_generic *op32_idx2desc( desc = ring->descbase; desc = &(desc[slot]); - return (struct b43legacy_dmadesc_generic *)desc; + return (struct b43legacy_dmadesc32 *)desc; } static void op32_fill_descriptor(struct b43legacy_dmaring *ring, - struct b43legacy_dmadesc_generic *desc, + struct b43legacy_dmadesc32 *desc, dma_addr_t dmaaddr, u16 bufsize, int start, int end, int irq) { @@ -67,7 +66,7 @@ static void op32_fill_descriptor(struct b43legacy_dmaring *ring, u32 addr; u32 addrext; - slot = (int)(&(desc->dma32) - descbase); + slot = (int)(desc - descbase); B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK); @@ -87,8 +86,8 @@ static void op32_fill_descriptor(struct b43legacy_dmaring *ring, ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT) & B43legacy_DMA32_DCTL_ADDREXT_MASK; - desc->dma32.control = cpu_to_le32(ctl); - desc->dma32.address = cpu_to_le32(addr); + desc->control = cpu_to_le32(ctl); + desc->address = cpu_to_le32(addr); } static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot) @@ -128,121 +127,6 @@ static void op32_set_current_rxslot(struct b43legacy_dmaring *ring, (u32)(slot * sizeof(struct b43legacy_dmadesc32))); } -static const struct b43legacy_dma_ops dma32_ops = { - .idx2desc = op32_idx2desc, - .fill_descriptor = op32_fill_descriptor, - .poke_tx = op32_poke_tx, - .tx_suspend = op32_tx_suspend, - .tx_resume = op32_tx_resume, - .get_current_rxslot = op32_get_current_rxslot, - .set_current_rxslot = op32_set_current_rxslot, -}; - -/* 64bit DMA ops. */ -static -struct b43legacy_dmadesc_generic *op64_idx2desc( - struct b43legacy_dmaring *ring, - int slot, - struct b43legacy_dmadesc_meta - **meta) -{ - struct b43legacy_dmadesc64 *desc; - - *meta = &(ring->meta[slot]); - desc = ring->descbase; - desc = &(desc[slot]); - - return (struct b43legacy_dmadesc_generic *)desc; -} - -static void op64_fill_descriptor(struct b43legacy_dmaring *ring, - struct b43legacy_dmadesc_generic *desc, - dma_addr_t dmaaddr, u16 bufsize, - int start, int end, int irq) -{ - struct b43legacy_dmadesc64 *descbase = ring->descbase; - int slot; - u32 ctl0 = 0; - u32 ctl1 = 0; - u32 addrlo; - u32 addrhi; - u32 addrext; - - slot = (int)(&(desc->dma64) - descbase); - B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); - - addrlo = (u32)(dmaaddr & 0xFFFFFFFF); - addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK); - addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; - addrhi |= ring->dev->dma.translation; - if (slot == ring->nr_slots - 1) - ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND; - if (start) - ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART; - if (end) - ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND; - if (irq) - ctl0 |= B43legacy_DMA64_DCTL0_IRQ; - ctl1 |= (bufsize - ring->frameoffset) - & B43legacy_DMA64_DCTL1_BYTECNT; - ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT) - & B43legacy_DMA64_DCTL1_ADDREXT_MASK; - - desc->dma64.control0 = cpu_to_le32(ctl0); - desc->dma64.control1 = cpu_to_le32(ctl1); - desc->dma64.address_low = cpu_to_le32(addrlo); - desc->dma64.address_high = cpu_to_le32(addrhi); -} - -static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot) -{ - b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX, - (u32)(slot * sizeof(struct b43legacy_dmadesc64))); -} - -static void op64_tx_suspend(struct b43legacy_dmaring *ring) -{ - b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, - b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) - | B43legacy_DMA64_TXSUSPEND); -} - -static void op64_tx_resume(struct b43legacy_dmaring *ring) -{ - b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, - b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL) - & ~B43legacy_DMA64_TXSUSPEND); -} - -static int op64_get_current_rxslot(struct b43legacy_dmaring *ring) -{ - u32 val; - - val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS); - val &= B43legacy_DMA64_RXSTATDPTR; - - return (val / sizeof(struct b43legacy_dmadesc64)); -} - -static void op64_set_current_rxslot(struct b43legacy_dmaring *ring, - int slot) -{ - b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, - (u32)(slot * sizeof(struct b43legacy_dmadesc64))); -} - -static const struct b43legacy_dma_ops dma64_ops = { - .idx2desc = op64_idx2desc, - .fill_descriptor = op64_fill_descriptor, - .poke_tx = op64_poke_tx, - .tx_suspend = op64_tx_suspend, - .tx_resume = op64_tx_resume, - .get_current_rxslot = op64_get_current_rxslot, - .set_current_rxslot = op64_set_current_rxslot, -}; - - static inline int free_slots(struct b43legacy_dmaring *ring) { return (ring->nr_slots - ring->used_slots); @@ -358,14 +242,6 @@ return 0; static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type, int controller_idx) { - static const u16 map64[] = { - B43legacy_MMIO_DMA64_BASE0, - B43legacy_MMIO_DMA64_BASE1, - B43legacy_MMIO_DMA64_BASE2, - B43legacy_MMIO_DMA64_BASE3, - B43legacy_MMIO_DMA64_BASE4, - B43legacy_MMIO_DMA64_BASE5, - }; static const u16 map32[] = { B43legacy_MMIO_DMA32_BASE0, B43legacy_MMIO_DMA32_BASE1, @@ -375,11 +251,6 @@ static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type, B43legacy_MMIO_DMA32_BASE5, }; - if (type == B43legacy_DMA_64BIT) { - B43legacy_WARN_ON(!(controller_idx >= 0 && - controller_idx < ARRAY_SIZE(map64))); - return map64[controller_idx]; - } B43legacy_WARN_ON(!(controller_idx >= 0 && controller_idx < ARRAY_SIZE(map32))); return map32[controller_idx]; @@ -491,25 +362,15 @@ static int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, might_sleep(); - offset = (type == B43legacy_DMA_64BIT) ? - B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL; + offset = B43legacy_DMA32_RXCTL; b43legacy_write32(dev, mmio_base + offset, 0); for (i = 0; i < 10; i++) { - offset = (type == B43legacy_DMA_64BIT) ? - B43legacy_DMA64_RXSTATUS : B43legacy_DMA32_RXSTATUS; + offset = B43legacy_DMA32_RXSTATUS; value = b43legacy_read32(dev, mmio_base + offset); - if (type == B43legacy_DMA_64BIT) { - value &= B43legacy_DMA64_RXSTAT; - if (value == B43legacy_DMA64_RXSTAT_DISABLED) { - i = -1; - break; - } - } else { - value &= B43legacy_DMA32_RXSTATE; - if (value == B43legacy_DMA32_RXSTAT_DISABLED) { - i = -1; - break; - } + value &= B43legacy_DMA32_RXSTATE; + if (value == B43legacy_DMA32_RXSTAT_DISABLED) { + i = -1; + break; } msleep(1); } @@ -533,43 +394,24 @@ static int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, might_sleep(); for (i = 0; i < 10; i++) { - offset = (type == B43legacy_DMA_64BIT) ? - B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS; + offset = B43legacy_DMA32_TXSTATUS; value = b43legacy_read32(dev, mmio_base + offset); - if (type == B43legacy_DMA_64BIT) { - value &= B43legacy_DMA64_TXSTAT; - if (value == B43legacy_DMA64_TXSTAT_DISABLED || - value == B43legacy_DMA64_TXSTAT_IDLEWAIT || - value == B43legacy_DMA64_TXSTAT_STOPPED) - break; - } else { - value &= B43legacy_DMA32_TXSTATE; - if (value == B43legacy_DMA32_TXSTAT_DISABLED || - value == B43legacy_DMA32_TXSTAT_IDLEWAIT || - value == B43legacy_DMA32_TXSTAT_STOPPED) - break; - } + value &= B43legacy_DMA32_TXSTATE; + if (value == B43legacy_DMA32_TXSTAT_DISABLED || + value == B43legacy_DMA32_TXSTAT_IDLEWAIT || + value == B43legacy_DMA32_TXSTAT_STOPPED) + break; msleep(1); } - offset = (type == B43legacy_DMA_64BIT) ? B43legacy_DMA64_TXCTL : - B43legacy_DMA32_TXCTL; + offset = B43legacy_DMA32_TXCTL; b43legacy_write32(dev, mmio_base + offset, 0); for (i = 0; i < 10; i++) { - offset = (type == B43legacy_DMA_64BIT) ? - B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS; + offset = B43legacy_DMA32_TXSTATUS; value = b43legacy_read32(dev, mmio_base + offset); - if (type == B43legacy_DMA_64BIT) { - value &= B43legacy_DMA64_TXSTAT; - if (value == B43legacy_DMA64_TXSTAT_DISABLED) { - i = -1; - break; - } - } else { - value &= B43legacy_DMA32_TXSTATE; - if (value == B43legacy_DMA32_TXSTAT_DISABLED) { - i = -1; - break; - } + value &= B43legacy_DMA32_TXSTATE; + if (value == B43legacy_DMA32_TXSTAT_DISABLED) { + i = -1; + break; } msleep(1); } @@ -601,9 +443,6 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring, if ((u64)addr + buffersize > (1ULL << 32)) goto address_error; break; - case B43legacy_DMA_64BIT: - /* Currently we can't have addresses beyond 64 bits in the kernel. */ - break; } /* The address is OK. */ @@ -617,7 +456,7 @@ address_error: } static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, - struct b43legacy_dmadesc_generic *desc, + struct b43legacy_dmadesc32 *desc, struct b43legacy_dmadesc_meta *meta, gfp_t gfp_flags) { @@ -653,8 +492,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, meta->skb = skb; meta->dmaaddr = dmaaddr; - ring->ops->fill_descriptor(ring, desc, dmaaddr, - ring->rx_buffersize, 0, 0, 0); + op32_fill_descriptor(ring, desc, dmaaddr, ring->rx_buffersize, 0, 0, 0); rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data); rxhdr->frame_len = 0; @@ -671,11 +509,11 @@ static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring) { int i; int err = -ENOMEM; - struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc32 *desc; struct b43legacy_dmadesc_meta *meta; for (i = 0; i < ring->nr_slots; i++) { - desc = ring->ops->idx2desc(ring, i, &meta); + desc = op32_idx2desc(ring, i, &meta); err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); if (err) { @@ -692,7 +530,7 @@ out: err_unwind: for (i--; i >= 0; i--) { - desc = ring->ops->idx2desc(ring, i, &meta); + desc = op32_idx2desc(ring, i, &meta); unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); dev_kfree_skb(meta->skb); @@ -710,83 +548,35 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring) u32 value; u32 addrext; u32 trans = ring->dev->dma.translation; + u32 ringbase = (u32)(ring->dmabase); if (ring->tx) { - if (ring->type == B43legacy_DMA_64BIT) { - u64 ringbase = (u64)(ring->dmabase); - - addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; - value = B43legacy_DMA64_TXENABLE; - value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT) - & B43legacy_DMA64_TXADDREXT_MASK; - b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL, - value); - b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, - (ringbase & 0xFFFFFFFF)); - b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, - ((ringbase >> 32) - & ~SSB_DMA_TRANSLATION_MASK) - | trans); - } else { - u32 ringbase = (u32)(ring->dmabase); - - addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; - value = B43legacy_DMA32_TXENABLE; - value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT) - & B43legacy_DMA32_TXADDREXT_MASK; - b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, - value); - b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, - (ringbase & - ~SSB_DMA_TRANSLATION_MASK) - | trans); - } + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = B43legacy_DMA32_TXENABLE; + value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT) + & B43legacy_DMA32_TXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL, value); + b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, + (ringbase & ~SSB_DMA_TRANSLATION_MASK) + | trans); } else { err = alloc_initial_descbuffers(ring); if (err) goto out; - if (ring->type == B43legacy_DMA_64BIT) { - u64 ringbase = (u64)(ring->dmabase); - - addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; - value = (ring->frameoffset << - B43legacy_DMA64_RXFROFF_SHIFT); - value |= B43legacy_DMA64_RXENABLE; - value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT) - & B43legacy_DMA64_RXADDREXT_MASK; - b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL, - value); - b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, - (ringbase & 0xFFFFFFFF)); - b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, - ((ringbase >> 32) & - ~SSB_DMA_TRANSLATION_MASK) | - trans); - b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX, - 200); - } else { - u32 ringbase = (u32)(ring->dmabase); - - addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) - >> SSB_DMA_TRANSLATION_SHIFT; - value = (ring->frameoffset << - B43legacy_DMA32_RXFROFF_SHIFT); - value |= B43legacy_DMA32_RXENABLE; - value |= (addrext << - B43legacy_DMA32_RXADDREXT_SHIFT) - & B43legacy_DMA32_RXADDREXT_MASK; - b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, - value); - b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, - (ringbase & - ~SSB_DMA_TRANSLATION_MASK) - | trans); - b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, - 200); - } + + addrext = (ringbase & SSB_DMA_TRANSLATION_MASK) + >> SSB_DMA_TRANSLATION_SHIFT; + value = (ring->frameoffset << + B43legacy_DMA32_RXFROFF_SHIFT); + value |= B43legacy_DMA32_RXENABLE; + value |= (addrext << B43legacy_DMA32_RXADDREXT_SHIFT) + & B43legacy_DMA32_RXADDREXT_MASK; + b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL, value); + b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, + (ringbase & ~SSB_DMA_TRANSLATION_MASK) + | trans); + b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX, 200); } out: @@ -799,19 +589,11 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring) if (ring->tx) { b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base, ring->type); - if (ring->type == B43legacy_DMA_64BIT) { - b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0); - b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0); - } else - b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0); + b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0); } else { b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base, ring->type); - if (ring->type == B43legacy_DMA_64BIT) { - b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0); - b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0); - } else - b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0); + b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0); } } @@ -823,7 +605,7 @@ static void free_all_descbuffers(struct b43legacy_dmaring *ring) if (!ring->used_slots) return; for (i = 0; i < ring->nr_slots; i++) { - ring->ops->idx2desc(ring, i, &meta); + op32_idx2desc(ring, i, &meta); if (!meta->skb) { B43legacy_WARN_ON(!ring->tx); @@ -844,9 +626,6 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev) u32 tmp; u16 mmio_base; - tmp = b43legacy_read32(dev, SSB_TMSHIGH); - if (tmp & SSB_TMSHIGH_DMA64) - return DMA_BIT_MASK(64); mmio_base = b43legacy_dmacontroller_base(0, 0); b43legacy_write32(dev, mmio_base + B43legacy_DMA32_TXCTL, @@ -865,8 +644,6 @@ static enum b43legacy_dmatype dma_mask_to_engine_type(u64 dmamask) return B43legacy_DMA_30BIT; if (dmamask == DMA_BIT_MASK(32)) return B43legacy_DMA_32BIT; - if (dmamask == DMA_BIT_MASK(64)) - return B43legacy_DMA_64BIT; B43legacy_WARN_ON(1); return B43legacy_DMA_30BIT; } @@ -937,10 +714,6 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, ring->nr_slots = nr_slots; ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index); ring->index = controller_index; - if (type == B43legacy_DMA_64BIT) - ring->ops = &dma64_ops; - else - ring->ops = &dma32_ops; if (for_tx) { ring->tx = 1; ring->current_slot = -1; @@ -1247,12 +1020,11 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, struct sk_buff **in_skb) { struct sk_buff *skb = *in_skb; - const struct b43legacy_dma_ops *ops = ring->ops; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); u8 *header; int slot, old_top_slot, old_used_slots; int err; - struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc32 *desc; struct b43legacy_dmadesc_meta *meta; struct b43legacy_dmadesc_meta *meta_hdr; struct sk_buff *bounce_skb; @@ -1265,7 +1037,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, /* Get a slot for the header. */ slot = request_slot(ring); - desc = ops->idx2desc(ring, slot, &meta_hdr); + desc = op32_idx2desc(ring, slot, &meta_hdr); memset(meta_hdr, 0, sizeof(*meta_hdr)); header = &(ring->txhdr_cache[slot * sizeof( @@ -1287,12 +1059,12 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, ring->used_slots = old_used_slots; return -EIO; } - ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, + op32_fill_descriptor(ring, desc, meta_hdr->dmaaddr, sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0); /* Get a slot for the payload. */ slot = request_slot(ring); - desc = ops->idx2desc(ring, slot, &meta); + desc = op32_idx2desc(ring, slot, &meta); memset(meta, 0, sizeof(*meta)); meta->skb = skb; @@ -1328,12 +1100,12 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, } } - ops->fill_descriptor(ring, desc, meta->dmaaddr, + op32_fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1); wmb(); /* previous stuff MUST be done */ /* Now transfer the whole frame. */ - ops->poke_tx(ring, next_slot(ring, slot)); + op32_poke_tx(ring, next_slot(ring, slot)); return 0; out_free_bounce: @@ -1429,7 +1201,6 @@ out_unlock: void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, const struct b43legacy_txstatus *status) { - const struct b43legacy_dma_ops *ops; struct b43legacy_dmaring *ring; struct b43legacy_dmadesc_meta *meta; int retry_limit; @@ -1442,10 +1213,9 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, spin_lock(&ring->lock); B43legacy_WARN_ON(!ring->tx); - ops = ring->ops; while (1) { B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots)); - ops->idx2desc(ring, slot, &meta); + op32_idx2desc(ring, slot, &meta); if (meta->skb) unmap_descbuffer(ring, meta->dmaaddr, @@ -1528,8 +1298,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, static void dma_rx(struct b43legacy_dmaring *ring, int *slot) { - const struct b43legacy_dma_ops *ops = ring->ops; - struct b43legacy_dmadesc_generic *desc; + struct b43legacy_dmadesc32 *desc; struct b43legacy_dmadesc_meta *meta; struct b43legacy_rxhdr_fw3 *rxhdr; struct sk_buff *skb; @@ -1537,7 +1306,7 @@ static void dma_rx(struct b43legacy_dmaring *ring, int err; dma_addr_t dmaaddr; - desc = ops->idx2desc(ring, *slot, &meta); + desc = op32_idx2desc(ring, *slot, &meta); sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); skb = meta->skb; @@ -1589,7 +1358,7 @@ static void dma_rx(struct b43legacy_dmaring *ring, s32 tmp = len; while (1) { - desc = ops->idx2desc(ring, *slot, &meta); + desc = op32_idx2desc(ring, *slot, &meta); /* recycle the descriptor buffer. */ sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize); @@ -1626,13 +1395,12 @@ drop: void b43legacy_dma_rx(struct b43legacy_dmaring *ring) { - const struct b43legacy_dma_ops *ops = ring->ops; int slot; int current_slot; int used_slots = 0; B43legacy_WARN_ON(ring->tx); - current_slot = ops->get_current_rxslot(ring); + current_slot = op32_get_current_rxslot(ring); B43legacy_WARN_ON(!(current_slot >= 0 && current_slot < ring->nr_slots)); @@ -1641,7 +1409,7 @@ void b43legacy_dma_rx(struct b43legacy_dmaring *ring) dma_rx(ring, &slot); update_max_used_slots(ring, ++used_slots); } - ops->set_current_rxslot(ring, slot); + op32_set_current_rxslot(ring, slot); ring->current_slot = slot; } @@ -1651,7 +1419,7 @@ static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring) spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); - ring->ops->tx_suspend(ring); + op32_tx_suspend(ring); spin_unlock_irqrestore(&ring->lock, flags); } @@ -1661,7 +1429,7 @@ static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring) spin_lock_irqsave(&ring->lock, flags); B43legacy_WARN_ON(!ring->tx); - ring->ops->tx_resume(ring); + op32_tx_resume(ring); spin_unlock_irqrestore(&ring->lock, flags); } diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h index 686941c242fc..504a58767e95 100644 --- a/drivers/net/wireless/b43legacy/dma.h +++ b/drivers/net/wireless/b43legacy/dma.h @@ -82,90 +82,6 @@ struct b43legacy_dmadesc32 { #define B43legacy_DMA32_DCTL_FRAMESTART 0x80000000 - -/*** 64-bit DMA Engine. ***/ - -/* 64-bit DMA controller registers. */ -#define B43legacy_DMA64_TXCTL 0x00 -#define B43legacy_DMA64_TXENABLE 0x00000001 -#define B43legacy_DMA64_TXSUSPEND 0x00000002 -#define B43legacy_DMA64_TXLOOPBACK 0x00000004 -#define B43legacy_DMA64_TXFLUSH 0x00000010 -#define B43legacy_DMA64_TXADDREXT_MASK 0x00030000 -#define B43legacy_DMA64_TXADDREXT_SHIFT 16 -#define B43legacy_DMA64_TXINDEX 0x04 -#define B43legacy_DMA64_TXRINGLO 0x08 -#define B43legacy_DMA64_TXRINGHI 0x0C -#define B43legacy_DMA64_TXSTATUS 0x10 -#define B43legacy_DMA64_TXSTATDPTR 0x00001FFF -#define B43legacy_DMA64_TXSTAT 0xF0000000 -#define B43legacy_DMA64_TXSTAT_DISABLED 0x00000000 -#define B43legacy_DMA64_TXSTAT_ACTIVE 0x10000000 -#define B43legacy_DMA64_TXSTAT_IDLEWAIT 0x20000000 -#define B43legacy_DMA64_TXSTAT_STOPPED 0x30000000 -#define B43legacy_DMA64_TXSTAT_SUSP 0x40000000 -#define B43legacy_DMA64_TXERROR 0x14 -#define B43legacy_DMA64_TXERRDPTR 0x0001FFFF -#define B43legacy_DMA64_TXERR 0xF0000000 -#define B43legacy_DMA64_TXERR_NOERR 0x00000000 -#define B43legacy_DMA64_TXERR_PROT 0x10000000 -#define B43legacy_DMA64_TXERR_UNDERRUN 0x20000000 -#define B43legacy_DMA64_TXERR_TRANSFER 0x30000000 -#define B43legacy_DMA64_TXERR_DESCREAD 0x40000000 -#define B43legacy_DMA64_TXERR_CORE 0x50000000 -#define B43legacy_DMA64_RXCTL 0x20 -#define B43legacy_DMA64_RXENABLE 0x00000001 -#define B43legacy_DMA64_RXFROFF_MASK 0x000000FE -#define B43legacy_DMA64_RXFROFF_SHIFT 1 -#define B43legacy_DMA64_RXDIRECTFIFO 0x00000100 -#define B43legacy_DMA64_RXADDREXT_MASK 0x00030000 -#define B43legacy_DMA64_RXADDREXT_SHIFT 16 -#define B43legacy_DMA64_RXINDEX 0x24 -#define B43legacy_DMA64_RXRINGLO 0x28 -#define B43legacy_DMA64_RXRINGHI 0x2C -#define B43legacy_DMA64_RXSTATUS 0x30 -#define B43legacy_DMA64_RXSTATDPTR 0x00001FFF -#define B43legacy_DMA64_RXSTAT 0xF0000000 -#define B43legacy_DMA64_RXSTAT_DISABLED 0x00000000 -#define B43legacy_DMA64_RXSTAT_ACTIVE 0x10000000 -#define B43legacy_DMA64_RXSTAT_IDLEWAIT 0x20000000 -#define B43legacy_DMA64_RXSTAT_STOPPED 0x30000000 -#define B43legacy_DMA64_RXSTAT_SUSP 0x40000000 -#define B43legacy_DMA64_RXERROR 0x34 -#define B43legacy_DMA64_RXERRDPTR 0x0001FFFF -#define B43legacy_DMA64_RXERR 0xF0000000 -#define B43legacy_DMA64_RXERR_NOERR 0x00000000 -#define B43legacy_DMA64_RXERR_PROT 0x10000000 -#define B43legacy_DMA64_RXERR_UNDERRUN 0x20000000 -#define B43legacy_DMA64_RXERR_TRANSFER 0x30000000 -#define B43legacy_DMA64_RXERR_DESCREAD 0x40000000 -#define B43legacy_DMA64_RXERR_CORE 0x50000000 - -/* 64-bit DMA descriptor. */ -struct b43legacy_dmadesc64 { - __le32 control0; - __le32 control1; - __le32 address_low; - __le32 address_high; -} __packed; -#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000 -#define B43legacy_DMA64_DCTL0_IRQ 0x20000000 -#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000 -#define B43legacy_DMA64_DCTL0_FRAMESTART 0x80000000 -#define B43legacy_DMA64_DCTL1_BYTECNT 0x00001FFF -#define B43legacy_DMA64_DCTL1_ADDREXT_MASK 0x00030000 -#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT 16 - - - -struct b43legacy_dmadesc_generic { - union { - struct b43legacy_dmadesc32 dma32; - struct b43legacy_dmadesc64 dma64; - } __packed; -} __packed; - - /* Misc DMA constants */ #define B43legacy_DMA_RINGMEMSIZE PAGE_SIZE #define B43legacy_DMA0_RX_FRAMEOFFSET 30 @@ -197,35 +113,12 @@ struct b43legacy_dmadesc_meta { bool is_last_fragment; }; -struct b43legacy_dmaring; - -/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */ -struct b43legacy_dma_ops { - struct b43legacy_dmadesc_generic * (*idx2desc) - (struct b43legacy_dmaring *ring, - int slot, - struct b43legacy_dmadesc_meta - **meta); - void (*fill_descriptor)(struct b43legacy_dmaring *ring, - struct b43legacy_dmadesc_generic *desc, - dma_addr_t dmaaddr, u16 bufsize, - int start, int end, int irq); - void (*poke_tx)(struct b43legacy_dmaring *ring, int slot); - void (*tx_suspend)(struct b43legacy_dmaring *ring); - void (*tx_resume)(struct b43legacy_dmaring *ring); - int (*get_current_rxslot)(struct b43legacy_dmaring *ring); - void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot); -}; - enum b43legacy_dmatype { B43legacy_DMA_30BIT = 30, B43legacy_DMA_32BIT = 32, - B43legacy_DMA_64BIT = 64, }; struct b43legacy_dmaring { - /* Lowlevel DMA ops. */ - const struct b43legacy_dma_ops *ops; /* Kernel virtual base address of the ring memory. */ void *descbase; /* Meta data about all descriptors. */ diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 04c03b212a5e..a3b72cd72c66 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -35,7 +35,6 @@ #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/firmware.h> -#include <linux/wireless.h> #include <linux/workqueue.h> #include <linux/sched.h> #include <linux/skbuff.h> @@ -61,7 +60,6 @@ MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID); MODULE_FIRMWARE("b43legacy/ucode2.fw"); MODULE_FIRMWARE("b43legacy/ucode4.fw"); @@ -2468,7 +2466,8 @@ out: } } -static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int b43legacy_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { return 0; @@ -3785,7 +3784,8 @@ static int b43legacy_wireless_init(struct ssb_device *dev) INIT_WORK(&wl->beacon_update_trigger, b43legacy_beacon_update_trigger_work); ssb_set_devtypedata(dev, wl); - b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id); + b43legacyinfo(wl, "Broadcom %04X WLAN found (core revision %u)\n", + dev->bus->chip_id, dev->id.revision); err = 0; out: return err; @@ -3947,8 +3947,7 @@ static void b43legacy_print_driverinfo(void) feat_dma = "D"; #endif printk(KERN_INFO "Broadcom 43xx-legacy driver loaded " - "[ Features: %s%s%s%s, Firmware-ID: " - B43legacy_SUPPORTED_FIRMWARE_ID " ]\n", + "[ Features: %s%s%s%s ]\n", feat_pci, feat_leds, feat_pio, feat_dma); } diff --git a/drivers/net/wireless/brcm80211/Kconfig b/drivers/net/wireless/brcm80211/Kconfig new file mode 100644 index 000000000000..2069fc8f7ad1 --- /dev/null +++ b/drivers/net/wireless/brcm80211/Kconfig @@ -0,0 +1,35 @@ +config BRCMUTIL + tristate + +config BRCMSMAC + tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver" + depends on PCI + depends on MAC80211 + depends on BCMA=n + select BRCMUTIL + select FW_LOADER + select CRC_CCITT + select CRC8 + select CORDIC + ---help--- + This module adds support for PCIe wireless adapters based on Broadcom + IEEE802.11n SoftMAC chipsets. If you choose to build a module, it'll + be called brcmsmac.ko. + +config BRCMFMAC + tristate "Broadcom IEEE802.11n embedded FullMAC WLAN driver" + depends on MMC + depends on CFG80211 + select BRCMUTIL + select FW_LOADER + ---help--- + This module adds support for embedded wireless adapters based on + Broadcom IEEE802.11n FullMAC chipsets. This driver uses the kernel's + wireless extensions subsystem. If you choose to build a module, + it'll be called brcmfmac.ko. + +config BRCMDBG + bool "Broadcom driver debug functions" + depends on BRCMSMAC || BRCMFMAC + ---help--- + Selecting this enables additional code for debug purposes. diff --git a/drivers/net/wireless/brcm80211/Makefile b/drivers/net/wireless/brcm80211/Makefile new file mode 100644 index 000000000000..f41c047eca82 --- /dev/null +++ b/drivers/net/wireless/brcm80211/Makefile @@ -0,0 +1,23 @@ +# +# Makefile fragment for Broadcom 802.11n Networking Device Driver +# +# Copyright (c) 2010 Broadcom Corporation +# +# 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. + +# common flags +subdir-ccflags-$(CONFIG_BRCMDBG) += -DBCMDBG + +obj-$(CONFIG_BRCMUTIL) += brcmutil/ +obj-$(CONFIG_BRCMFMAC) += brcmfmac/ +obj-$(CONFIG_BRCMSMAC) += brcmsmac/ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile new file mode 100644 index 000000000000..b44e3094588a --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -0,0 +1,33 @@ +# +# Makefile fragment for Broadcom 802.11n Networking Device Driver +# +# Copyright (c) 2010 Broadcom Corporation +# +# 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. + +ccflags-y += \ + -Idrivers/net/wireless/brcm80211/brcmfmac \ + -Idrivers/net/wireless/brcm80211/include + +DHDOFILES = \ + wl_cfg80211.o \ + dhd_cdc.o \ + dhd_common.o \ + dhd_sdio.o \ + dhd_linux.o \ + bcmsdh.o \ + bcmsdh_sdmmc.o + +obj-$(CONFIG_BRCMFMAC) += brcmfmac.o +brcmfmac-objs += $(DHDOFILES) +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h b/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h new file mode 100644 index 000000000000..d7d3afd5a10f --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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 _bcmchip_h_ +#define _bcmchip_h_ + +/* bcm4329 */ +/* SDIO device core, ID 0x829 */ +#define BCM4329_CORE_BUS_BASE 0x18011000 +/* internal memory core, ID 0x80e */ +#define BCM4329_CORE_SOCRAM_BASE 0x18003000 +/* ARM Cortex M3 core, ID 0x82a */ +#define BCM4329_CORE_ARM_BASE 0x18002000 +#define BCM4329_RAMSIZE 0x48000 +/* firmware name */ +#define BCM4329_FW_NAME "brcm/bcm4329-fullmac-4.bin" +#define BCM4329_NV_NAME "brcm/bcm4329-fullmac-4.txt" + +#endif /* _bcmchip_h_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c new file mode 100644 index 000000000000..bff9dcd6fadc --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ +/* ****************** SDIO CARD Interface Functions **************************/ + +#include <linux/types.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> +#include <linux/sched.h> +#include <linux/completion.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/card.h> + +#include <defs.h> +#include <brcm_hw_ids.h> +#include <brcmu_utils.h> +#include <brcmu_wifi.h> +#include <soc.h> +#include "dhd.h" +#include "dhd_bus.h" +#include "dhd_dbg.h" +#include "sdio_host.h" + +#define SDIOH_API_ACCESS_RETRY_LIMIT 2 + +static void brcmf_sdioh_irqhandler(struct sdio_func *func) +{ + struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev); + + brcmf_dbg(TRACE, "***IRQHandler\n"); + + sdio_release_host(func); + + brcmf_sdbrcm_isr(sdiodev->bus); + + sdio_claim_host(func); +} + +int brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev) +{ + brcmf_dbg(TRACE, "Entering\n"); + + sdio_claim_host(sdiodev->func[1]); + sdio_claim_irq(sdiodev->func[1], brcmf_sdioh_irqhandler); + sdio_release_host(sdiodev->func[1]); + + return 0; +} + +int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev) +{ + brcmf_dbg(TRACE, "Entering\n"); + + sdio_claim_host(sdiodev->func[1]); + sdio_release_irq(sdiodev->func[1]); + sdio_release_host(sdiodev->func[1]); + + return 0; +} + +u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, + int *err) +{ + int status; + s32 retry = 0; + u8 data = 0; + + do { + if (retry) /* wait for 1 ms till bus get settled down */ + udelay(1000); + status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num, + addr, (u8 *) &data); + } while (status != 0 + && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); + if (err) + *err = status; + + brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n", + fnc_num, addr, data); + + return data; +} + +void +brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, + u8 data, int *err) +{ + int status; + s32 retry = 0; + + do { + if (retry) /* wait for 1 ms till bus get settled down */ + udelay(1000); + status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num, + addr, (u8 *) &data); + } while (status != 0 + && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); + if (err) + *err = status; + + brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n", + fnc_num, addr, data); +} + +int +brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) +{ + int err = 0; + brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, + (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); + if (!err) + brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_SBADDRMID, + (address >> 16) & SBSDIO_SBADDRMID_MASK, + &err); + if (!err) + brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_SBADDRHIGH, + (address >> 24) & SBSDIO_SBADDRHIGH_MASK, + &err); + + return err; +} + +u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size) +{ + int status; + u32 word = 0; + uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; + + brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr); + + if (bar0 != sdiodev->sbwad) { + if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0)) + return 0xFFFFFFFF; + + sdiodev->sbwad = bar0; + } + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + if (size == 4) + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1, + addr, &word, size); + + sdiodev->regfail = (status != 0); + + brcmf_dbg(INFO, "u32data = 0x%x\n", word); + + /* if ok, return appropriately masked word */ + if (status == 0) { + switch (size) { + case sizeof(u8): + return word & 0xff; + case sizeof(u16): + return word & 0xffff; + case sizeof(u32): + return word; + default: + sdiodev->regfail = true; + + } + } + + /* otherwise, bad sdio access or invalid size */ + brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size); + return 0xFFFFFFFF; +} + +u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size, + u32 data) +{ + int status; + uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; + int err = 0; + + brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", + addr, size * 8, data); + + if (bar0 != sdiodev->sbwad) { + err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); + if (err) + return err; + + sdiodev->sbwad = bar0; + } + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + if (size == 4) + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + status = + brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1, + addr, &data, size); + sdiodev->regfail = (status != 0); + + if (status == 0) + return 0; + + brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n", + data, addr, size); + return 0xFFFFFFFF; +} + +bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev) +{ + return sdiodev->regfail; +} + +int +brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, + u8 *buf, uint nbytes, struct sk_buff *pkt) +{ + int status; + uint incr_fix; + uint width; + uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; + int err = 0; + + brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); + + /* Async not implemented yet */ + if (flags & SDIO_REQ_ASYNC) + return -ENOTSUPP; + + if (bar0 != sdiodev->sbwad) { + err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); + if (err) + return err; + + sdiodev->sbwad = bar0; + } + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + + incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; + width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; + if (width == 4) + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + status = brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_READ, + fn, addr, width, nbytes, buf, pkt); + + return status; +} + +int +brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt) +{ + uint incr_fix; + uint width; + uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; + int err = 0; + + brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n", fn, addr, nbytes); + + /* Async not implemented yet */ + if (flags & SDIO_REQ_ASYNC) + return -ENOTSUPP; + + if (bar0 != sdiodev->sbwad) { + err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); + if (err) + return err; + + sdiodev->sbwad = bar0; + } + + addr &= SBSDIO_SB_OFT_ADDR_MASK; + + incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC; + width = (flags & SDIO_REQ_4BYTE) ? 4 : 2; + if (width == 4) + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + return brcmf_sdioh_request_buffer(sdiodev, incr_fix, SDIOH_WRITE, fn, + addr, width, nbytes, buf, pkt); +} + +int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, u32 addr, + u8 *buf, uint nbytes) +{ + addr &= SBSDIO_SB_OFT_ADDR_MASK; + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + + return brcmf_sdioh_request_buffer(sdiodev, SDIOH_DATA_INC, + (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1, + addr, 4, nbytes, buf, NULL); +} + +int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn) +{ + char t_func = (char)fn; + brcmf_dbg(TRACE, "Enter\n"); + + /* issue abort cmd52 command through F0 */ + brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, + SDIO_CCCR_ABORT, &t_func); + + brcmf_dbg(TRACE, "Exit\n"); + return 0; +} + +int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) +{ + u32 regs = 0; + int ret = 0; + + ret = brcmf_sdioh_attach(sdiodev); + if (ret) + goto out; + + regs = SI_ENUM_BASE; + + /* Report the BAR, to fix if needed */ + sdiodev->sbwad = SI_ENUM_BASE; + + /* try to attach to the target device */ + sdiodev->bus = brcmf_sdbrcm_probe(0, 0, 0, 0, regs, sdiodev); + if (!sdiodev->bus) { + brcmf_dbg(ERROR, "device attach failed\n"); + ret = -ENODEV; + goto out; + } + +out: + if (ret) + brcmf_sdio_remove(sdiodev); + + return ret; +} +EXPORT_SYMBOL(brcmf_sdio_probe); + +int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev) +{ + if (sdiodev->bus) { + brcmf_sdbrcm_disconnect(sdiodev->bus); + sdiodev->bus = NULL; + } + + brcmf_sdioh_detach(sdiodev); + + sdiodev->sbwad = 0; + + return 0; +} +EXPORT_SYMBOL(brcmf_sdio_remove); + +void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, bool enable) +{ + if (enable) + brcmf_sdbrcm_wd_timer(sdiodev->bus, BRCMF_WD_POLL_MS); + else + brcmf_sdbrcm_wd_timer(sdiodev->bus, 0); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c new file mode 100644 index 000000000000..bbaeb2d5c93a --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/types.h> +#include <linux/netdevice.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/core.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/mmc/card.h> +#include <linux/suspend.h> +#include <linux/errno.h> +#include <linux/sched.h> /* request_irq() */ +#include <linux/module.h> +#include <net/cfg80211.h> + +#include <defs.h> +#include <brcm_hw_ids.h> +#include <brcmu_utils.h> +#include <brcmu_wifi.h> +#include "sdio_host.h" +#include "dhd.h" +#include "dhd_dbg.h" +#include "wl_cfg80211.h" + +#define SDIO_VENDOR_ID_BROADCOM 0x02d0 + +#define DMA_ALIGN_MASK 0x03 + +#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 + +#define SDIO_FUNC1_BLOCKSIZE 64 +#define SDIO_FUNC2_BLOCKSIZE 512 + +/* devices we support, null terminated */ +static const struct sdio_device_id brcmf_sdmmc_ids[] = { + {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, + { /* end: all zeroes */ }, +}; +MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); + +static bool +brcmf_pm_resume_error(struct brcmf_sdio_dev *sdiodev) +{ + bool is_err = false; +#ifdef CONFIG_PM_SLEEP + is_err = atomic_read(&sdiodev->suspend); +#endif + return is_err; +} + +static void +brcmf_pm_resume_wait(struct brcmf_sdio_dev *sdiodev, wait_queue_head_t *wq) +{ +#ifdef CONFIG_PM_SLEEP + int retry = 0; + while (atomic_read(&sdiodev->suspend) && retry++ != 30) + wait_event_timeout(*wq, false, HZ/100); +#endif +} + +static inline int brcmf_sdioh_f0_write_byte(struct brcmf_sdio_dev *sdiodev, + uint regaddr, u8 *byte) +{ + struct sdio_func *sdfunc = sdiodev->func[0]; + int err_ret; + + /* + * Can only directly write to some F0 registers. + * Handle F2 enable/disable and Abort command + * as a special case. + */ + if (regaddr == SDIO_CCCR_IOEx) { + sdfunc = sdiodev->func[2]; + if (sdfunc) { + sdio_claim_host(sdfunc); + if (*byte & SDIO_FUNC_ENABLE_2) { + /* Enable Function 2 */ + err_ret = sdio_enable_func(sdfunc); + if (err_ret) + brcmf_dbg(ERROR, + "enable F2 failed:%d\n", + err_ret); + } else { + /* Disable Function 2 */ + err_ret = sdio_disable_func(sdfunc); + if (err_ret) + brcmf_dbg(ERROR, + "Disable F2 failed:%d\n", + err_ret); + } + sdio_release_host(sdfunc); + } + } else if (regaddr == SDIO_CCCR_ABORT) { + sdio_claim_host(sdfunc); + sdio_writeb(sdfunc, *byte, regaddr, &err_ret); + sdio_release_host(sdfunc); + } else if (regaddr < 0xF0) { + brcmf_dbg(ERROR, "F0 Wr:0x%02x: write disallowed\n", regaddr); + err_ret = -EPERM; + } else { + sdio_claim_host(sdfunc); + sdio_f0_writeb(sdfunc, *byte, regaddr, &err_ret); + sdio_release_host(sdfunc); + } + + return err_ret; +} + +int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, uint func, + uint regaddr, u8 *byte) +{ + int err_ret; + + brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr); + + brcmf_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait); + if (brcmf_pm_resume_error(sdiodev)) + return -EIO; + + if (rw && func == 0) { + /* handle F0 separately */ + err_ret = brcmf_sdioh_f0_write_byte(sdiodev, regaddr, byte); + } else { + sdio_claim_host(sdiodev->func[func]); + if (rw) /* CMD52 Write */ + sdio_writeb(sdiodev->func[func], *byte, regaddr, + &err_ret); + else if (func == 0) { + *byte = sdio_f0_readb(sdiodev->func[func], regaddr, + &err_ret); + } else { + *byte = sdio_readb(sdiodev->func[func], regaddr, + &err_ret); + } + sdio_release_host(sdiodev->func[func]); + } + + if (err_ret) + brcmf_dbg(ERROR, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", + rw ? "write" : "read", func, regaddr, *byte, err_ret); + + return err_ret; +} + +int brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, + uint rw, uint func, uint addr, u32 *word, + uint nbytes) +{ + int err_ret = -EIO; + + if (func == 0) { + brcmf_dbg(ERROR, "Only CMD52 allowed to F0\n"); + return -EINVAL; + } + + brcmf_dbg(INFO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", + rw, func, addr, nbytes); + + brcmf_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); + if (brcmf_pm_resume_error(sdiodev)) + return -EIO; + /* Claim host controller */ + sdio_claim_host(sdiodev->func[func]); + + if (rw) { /* CMD52 Write */ + if (nbytes == 4) + sdio_writel(sdiodev->func[func], *word, addr, + &err_ret); + else if (nbytes == 2) + sdio_writew(sdiodev->func[func], (*word & 0xFFFF), + addr, &err_ret); + else + brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); + } else { /* CMD52 Read */ + if (nbytes == 4) + *word = sdio_readl(sdiodev->func[func], addr, &err_ret); + else if (nbytes == 2) + *word = sdio_readw(sdiodev->func[func], addr, + &err_ret) & 0xFFFF; + else + brcmf_dbg(ERROR, "Invalid nbytes: %d\n", nbytes); + } + + /* Release host controller */ + sdio_release_host(sdiodev->func[func]); + + if (err_ret) + brcmf_dbg(ERROR, "Failed to %s word, Err: 0x%08x\n", + rw ? "write" : "read", err_ret); + + return err_ret; +} + +static int +brcmf_sdioh_request_packet(struct brcmf_sdio_dev *sdiodev, uint fix_inc, + uint write, uint func, uint addr, + struct sk_buff *pkt) +{ + bool fifo = (fix_inc == SDIOH_DATA_FIX); + u32 SGCount = 0; + int err_ret = 0; + + struct sk_buff *pnext; + + brcmf_dbg(TRACE, "Enter\n"); + + brcmf_pm_resume_wait(sdiodev, &sdiodev->request_packet_wait); + if (brcmf_pm_resume_error(sdiodev)) + return -EIO; + + /* Claim host controller */ + sdio_claim_host(sdiodev->func[func]); + for (pnext = pkt; pnext; pnext = pnext->next) { + uint pkt_len = pnext->len; + pkt_len += 3; + pkt_len &= 0xFFFFFFFC; + + if ((write) && (!fifo)) { + err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, + ((u8 *) (pnext->data)), + pkt_len); + } else if (write) { + err_ret = sdio_memcpy_toio(sdiodev->func[func], addr, + ((u8 *) (pnext->data)), + pkt_len); + } else if (fifo) { + err_ret = sdio_readsb(sdiodev->func[func], + ((u8 *) (pnext->data)), + addr, pkt_len); + } else { + err_ret = sdio_memcpy_fromio(sdiodev->func[func], + ((u8 *) (pnext->data)), + addr, pkt_len); + } + + if (err_ret) { + brcmf_dbg(ERROR, "%s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", + write ? "TX" : "RX", pnext, SGCount, addr, + pkt_len, err_ret); + } else { + brcmf_dbg(TRACE, "%s xfr'd %p[%d], addr=0x%05x, len=%d\n", + write ? "TX" : "RX", pnext, SGCount, addr, + pkt_len); + } + + if (!fifo) + addr += pkt_len; + SGCount++; + + } + + /* Release host controller */ + sdio_release_host(sdiodev->func[func]); + + brcmf_dbg(TRACE, "Exit\n"); + return err_ret; +} + +/* + * This function takes a buffer or packet, and fixes everything up + * so that in the end, a DMA-able packet is created. + * + * A buffer does not have an associated packet pointer, + * and may or may not be aligned. + * A packet may consist of a single packet, or a packet chain. + * If it is a packet chain, then all the packets in the chain + * must be properly aligned. + * + * If the packet data is not aligned, then there may only be + * one packet, and in this case, it is copied to a new + * aligned packet. + * + */ +int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, + uint fix_inc, uint write, uint func, uint addr, + uint reg_width, uint buflen_u, u8 *buffer, + struct sk_buff *pkt) +{ + int Status; + struct sk_buff *mypkt = NULL; + + brcmf_dbg(TRACE, "Enter\n"); + + brcmf_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait); + if (brcmf_pm_resume_error(sdiodev)) + return -EIO; + /* Case 1: we don't have a packet. */ + if (pkt == NULL) { + brcmf_dbg(DATA, "Creating new %s Packet, len=%d\n", + write ? "TX" : "RX", buflen_u); + mypkt = brcmu_pkt_buf_get_skb(buflen_u); + if (!mypkt) { + brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", + buflen_u); + return -EIO; + } + + /* For a write, copy the buffer data into the packet. */ + if (write) + memcpy(mypkt->data, buffer, buflen_u); + + Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, + func, addr, mypkt); + + /* For a read, copy the packet data back to the buffer. */ + if (!write) + memcpy(buffer, mypkt->data, buflen_u); + + brcmu_pkt_buf_free_skb(mypkt); + } else if (((ulong) (pkt->data) & DMA_ALIGN_MASK) != 0) { + /* + * Case 2: We have a packet, but it is unaligned. + * In this case, we cannot have a chain (pkt->next == NULL) + */ + brcmf_dbg(DATA, "Creating aligned %s Packet, len=%d\n", + write ? "TX" : "RX", pkt->len); + mypkt = brcmu_pkt_buf_get_skb(pkt->len); + if (!mypkt) { + brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: len %d\n", + pkt->len); + return -EIO; + } + + /* For a write, copy the buffer data into the packet. */ + if (write) + memcpy(mypkt->data, pkt->data, pkt->len); + + Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, + func, addr, mypkt); + + /* For a read, copy the packet data back to the buffer. */ + if (!write) + memcpy(pkt->data, mypkt->data, mypkt->len); + + brcmu_pkt_buf_free_skb(mypkt); + } else { /* case 3: We have a packet and + it is aligned. */ + brcmf_dbg(DATA, "Aligned %s Packet, direct DMA\n", + write ? "Tx" : "Rx"); + Status = brcmf_sdioh_request_packet(sdiodev, fix_inc, write, + func, addr, pkt); + } + + return Status; +} + +/* Read client card reg */ +static int +brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr, + int regsize, u32 *data) +{ + + if ((func == 0) || (regsize == 1)) { + u8 temp = 0; + + brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr, + &temp); + *data = temp; + *data &= 0xff; + brcmf_dbg(DATA, "byte read data=0x%02x\n", *data); + } else { + brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr, + data, regsize); + if (regsize == 2) + *data &= 0xffff; + + brcmf_dbg(DATA, "word read data=0x%08x\n", *data); + } + + return SUCCESS; +} + +static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr) +{ + /* read 24 bits and return valid 17 bit addr */ + int i; + u32 scratch, regdata; + __le32 scratch_le; + u8 *ptr = (u8 *)&scratch_le; + + for (i = 0; i < 3; i++) { + if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1, + ®data)) != SUCCESS) + brcmf_dbg(ERROR, "Can't read!\n"); + + *ptr++ = (u8) regdata; + regaddr++; + } + + /* Only the lower 17-bits are valid */ + scratch = le32_to_cpu(scratch_le); + scratch &= 0x0001FFFF; + return scratch; +} + +static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev) +{ + int err_ret; + u32 fbraddr; + u8 func; + + brcmf_dbg(TRACE, "\n"); + + /* Get the Card's common CIS address */ + sdiodev->func_cis_ptr[0] = brcmf_sdioh_get_cisaddr(sdiodev, + SDIO_CCCR_CIS); + brcmf_dbg(INFO, "Card's Common CIS Ptr = 0x%x\n", + sdiodev->func_cis_ptr[0]); + + /* Get the Card's function CIS (for each function) */ + for (fbraddr = SDIO_FBR_BASE(1), func = 1; + func <= sdiodev->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { + sdiodev->func_cis_ptr[func] = + brcmf_sdioh_get_cisaddr(sdiodev, SDIO_FBR_CIS + fbraddr); + brcmf_dbg(INFO, "Function %d CIS Ptr = 0x%x\n", + func, sdiodev->func_cis_ptr[func]); + } + + /* Enable Function 1 */ + sdio_claim_host(sdiodev->func[1]); + err_ret = sdio_enable_func(sdiodev->func[1]); + sdio_release_host(sdiodev->func[1]); + if (err_ret) + brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret); + + return false; +} + +/* + * Public entry points & extern's + */ +int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev) +{ + int err_ret = 0; + + brcmf_dbg(TRACE, "\n"); + + sdiodev->num_funcs = 2; + + sdio_claim_host(sdiodev->func[1]); + err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE); + sdio_release_host(sdiodev->func[1]); + if (err_ret) { + brcmf_dbg(ERROR, "Failed to set F1 blocksize\n"); + goto out; + } + + sdio_claim_host(sdiodev->func[2]); + err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE); + sdio_release_host(sdiodev->func[2]); + if (err_ret) { + brcmf_dbg(ERROR, "Failed to set F2 blocksize\n"); + goto out; + } + + brcmf_sdioh_enablefuncs(sdiodev); + +out: + brcmf_dbg(TRACE, "Done\n"); + return err_ret; +} + +void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev) +{ + brcmf_dbg(TRACE, "\n"); + + /* Disable Function 2 */ + sdio_claim_host(sdiodev->func[2]); + sdio_disable_func(sdiodev->func[2]); + sdio_release_host(sdiodev->func[2]); + + /* Disable Function 1 */ + sdio_claim_host(sdiodev->func[1]); + sdio_disable_func(sdiodev->func[1]); + sdio_release_host(sdiodev->func[1]); + +} + +static int brcmf_ops_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int ret = 0; + struct brcmf_sdio_dev *sdiodev; + brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(TRACE, "func->class=%x\n", func->class); + brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor); + brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device); + brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num); + + if (func->num == 1) { + if (dev_get_drvdata(&func->card->dev)) { + brcmf_dbg(ERROR, "card private drvdata occupied\n"); + return -ENXIO; + } + sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL); + if (!sdiodev) + return -ENOMEM; + sdiodev->func[0] = func->card->sdio_func[0]; + sdiodev->func[1] = func; + dev_set_drvdata(&func->card->dev, sdiodev); + + atomic_set(&sdiodev->suspend, false); + init_waitqueue_head(&sdiodev->request_byte_wait); + init_waitqueue_head(&sdiodev->request_word_wait); + init_waitqueue_head(&sdiodev->request_packet_wait); + init_waitqueue_head(&sdiodev->request_buffer_wait); + } + + if (func->num == 2) { + sdiodev = dev_get_drvdata(&func->card->dev); + if ((!sdiodev) || (sdiodev->func[1]->card != func->card)) + return -ENODEV; + sdiodev->func[2] = func; + + brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n"); + ret = brcmf_sdio_probe(sdiodev); + } + + return ret; +} + +static void brcmf_ops_sdio_remove(struct sdio_func *func) +{ + struct brcmf_sdio_dev *sdiodev; + brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(INFO, "func->class=%x\n", func->class); + brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor); + brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device); + brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num); + + if (func->num == 2) { + sdiodev = dev_get_drvdata(&func->card->dev); + brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n"); + brcmf_sdio_remove(sdiodev); + dev_set_drvdata(&func->card->dev, NULL); + kfree(sdiodev); + } +} + +#ifdef CONFIG_PM_SLEEP +static int brcmf_sdio_suspend(struct device *dev) +{ + mmc_pm_flag_t sdio_flags; + struct brcmf_sdio_dev *sdiodev; + struct sdio_func *func = dev_to_sdio_func(dev); + int ret = 0; + + brcmf_dbg(TRACE, "\n"); + + sdiodev = dev_get_drvdata(&func->card->dev); + + atomic_set(&sdiodev->suspend, true); + + sdio_flags = sdio_get_host_pm_caps(sdiodev->func[1]); + if (!(sdio_flags & MMC_PM_KEEP_POWER)) { + brcmf_dbg(ERROR, "Host can't keep power while suspended\n"); + return -EINVAL; + } + + ret = sdio_set_host_pm_flags(sdiodev->func[1], MMC_PM_KEEP_POWER); + if (ret) { + brcmf_dbg(ERROR, "Failed to set pm_flags\n"); + return ret; + } + + brcmf_sdio_wdtmr_enable(sdiodev, false); + + return ret; +} + +static int brcmf_sdio_resume(struct device *dev) +{ + struct brcmf_sdio_dev *sdiodev; + struct sdio_func *func = dev_to_sdio_func(dev); + + sdiodev = dev_get_drvdata(&func->card->dev); + brcmf_sdio_wdtmr_enable(sdiodev, true); + atomic_set(&sdiodev->suspend, false); + return 0; +} + +static const struct dev_pm_ops brcmf_sdio_pm_ops = { + .suspend = brcmf_sdio_suspend, + .resume = brcmf_sdio_resume, +}; +#endif /* CONFIG_PM_SLEEP */ + +static struct sdio_driver brcmf_sdmmc_driver = { + .probe = brcmf_ops_sdio_probe, + .remove = brcmf_ops_sdio_remove, + .name = "brcmfmac", + .id_table = brcmf_sdmmc_ids, +#ifdef CONFIG_PM_SLEEP + .drv = { + .pm = &brcmf_sdio_pm_ops, + }, +#endif /* CONFIG_PM_SLEEP */ +}; + +/* bus register interface */ +int brcmf_bus_register(void) +{ + brcmf_dbg(TRACE, "Enter\n"); + + return sdio_register_driver(&brcmf_sdmmc_driver); +} + +void brcmf_bus_unregister(void) +{ + brcmf_dbg(TRACE, "Enter\n"); + + sdio_unregister_driver(&brcmf_sdmmc_driver); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h new file mode 100644 index 000000000000..4645766b4070 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +/**************** + * Common types * + */ + +#ifndef _BRCMF_H_ +#define _BRCMF_H_ + +#define BRCMF_VERSION_STR "4.218.248.5" + +/******************************************************************************* + * IO codes that are interpreted by dongle firmware + ******************************************************************************/ +#define BRCMF_C_UP 2 +#define BRCMF_C_SET_PROMISC 10 +#define BRCMF_C_GET_RATE 12 +#define BRCMF_C_GET_INFRA 19 +#define BRCMF_C_SET_INFRA 20 +#define BRCMF_C_GET_AUTH 21 +#define BRCMF_C_SET_AUTH 22 +#define BRCMF_C_GET_BSSID 23 +#define BRCMF_C_GET_SSID 25 +#define BRCMF_C_SET_SSID 26 +#define BRCMF_C_GET_CHANNEL 29 +#define BRCMF_C_GET_SRL 31 +#define BRCMF_C_GET_LRL 33 +#define BRCMF_C_GET_RADIO 37 +#define BRCMF_C_SET_RADIO 38 +#define BRCMF_C_GET_PHYTYPE 39 +#define BRCMF_C_SET_KEY 45 +#define BRCMF_C_SET_PASSIVE_SCAN 49 +#define BRCMF_C_SCAN 50 +#define BRCMF_C_SCAN_RESULTS 51 +#define BRCMF_C_DISASSOC 52 +#define BRCMF_C_REASSOC 53 +#define BRCMF_C_SET_ROAM_TRIGGER 55 +#define BRCMF_C_SET_ROAM_DELTA 57 +#define BRCMF_C_GET_DTIMPRD 77 +#define BRCMF_C_SET_COUNTRY 84 +#define BRCMF_C_GET_PM 85 +#define BRCMF_C_SET_PM 86 +#define BRCMF_C_GET_AP 117 +#define BRCMF_C_SET_AP 118 +#define BRCMF_C_GET_RSSI 127 +#define BRCMF_C_GET_WSEC 133 +#define BRCMF_C_SET_WSEC 134 +#define BRCMF_C_GET_PHY_NOISE 135 +#define BRCMF_C_GET_BSS_INFO 136 +#define BRCMF_C_SET_SCAN_CHANNEL_TIME 185 +#define BRCMF_C_SET_SCAN_UNASSOC_TIME 187 +#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 201 +#define BRCMF_C_GET_VALID_CHANNELS 217 +#define BRCMF_C_GET_KEY_PRIMARY 235 +#define BRCMF_C_SET_KEY_PRIMARY 236 +#define BRCMF_C_SET_SCAN_PASSIVE_TIME 258 +#define BRCMF_C_GET_VAR 262 +#define BRCMF_C_SET_VAR 263 + +/* phy types (returned by WLC_GET_PHYTPE) */ +#define WLC_PHY_TYPE_A 0 +#define WLC_PHY_TYPE_B 1 +#define WLC_PHY_TYPE_G 2 +#define WLC_PHY_TYPE_N 4 +#define WLC_PHY_TYPE_LP 5 +#define WLC_PHY_TYPE_SSN 6 +#define WLC_PHY_TYPE_HT 7 +#define WLC_PHY_TYPE_LCN 8 +#define WLC_PHY_TYPE_NULL 0xf + +#define BRCMF_EVENTING_MASK_LEN 16 + +#define TOE_TX_CSUM_OL 0x00000001 +#define TOE_RX_CSUM_OL 0x00000002 + +#define BRCMF_BSS_INFO_VERSION 108 /* current ver of brcmf_bss_info struct */ + +/* size of brcmf_scan_params not including variable length array */ +#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64 + +/* masks for channel and ssid count */ +#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff +#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16 + +#define BRCMF_SCAN_ACTION_START 1 +#define BRCMF_SCAN_ACTION_CONTINUE 2 +#define WL_SCAN_ACTION_ABORT 3 + +#define BRCMF_ISCAN_REQ_VERSION 1 + +/* brcmf_iscan_results status values */ +#define BRCMF_SCAN_RESULTS_SUCCESS 0 +#define BRCMF_SCAN_RESULTS_PARTIAL 1 +#define BRCMF_SCAN_RESULTS_PENDING 2 +#define BRCMF_SCAN_RESULTS_ABORTED 3 +#define BRCMF_SCAN_RESULTS_NO_MEM 4 + +/* Indicates this key is using soft encrypt */ +#define WL_SOFT_KEY (1 << 0) +/* primary (ie tx) key */ +#define BRCMF_PRIMARY_KEY (1 << 1) +/* Reserved for backward compat */ +#define WL_KF_RES_4 (1 << 4) +/* Reserved for backward compat */ +#define WL_KF_RES_5 (1 << 5) +/* Indicates a group key for a IBSS PEER */ +#define WL_IBSS_PEER_GROUP_KEY (1 << 6) + +/* For supporting multiple interfaces */ +#define BRCMF_MAX_IFS 16 +#define BRCMF_DEL_IF -0xe +#define BRCMF_BAD_IF -0xf + +#define DOT11_BSSTYPE_ANY 2 +#define DOT11_MAX_DEFAULT_KEYS 4 + +#define BRCMF_EVENT_MSG_LINK 0x01 +#define BRCMF_EVENT_MSG_FLUSHTXQ 0x02 +#define BRCMF_EVENT_MSG_GROUP 0x04 + +struct brcmf_event_msg { + __be16 version; + __be16 flags; + __be32 event_type; + __be32 status; + __be32 reason; + __be32 auth_type; + __be32 datalen; + u8 addr[ETH_ALEN]; + char ifname[IFNAMSIZ]; +} __packed; + +struct brcm_ethhdr { + u16 subtype; + u16 length; + u8 version; + u8 oui[3]; + u16 usr_subtype; +} __packed; + +struct brcmf_event { + struct ethhdr eth; + struct brcm_ethhdr hdr; + struct brcmf_event_msg msg; +} __packed; + +struct dngl_stats { + unsigned long rx_packets; /* total packets received */ + unsigned long tx_packets; /* total packets transmitted */ + unsigned long rx_bytes; /* total bytes received */ + unsigned long tx_bytes; /* total bytes transmitted */ + unsigned long rx_errors; /* bad packets received */ + unsigned long tx_errors; /* packet transmit problems */ + unsigned long rx_dropped; /* packets dropped by dongle */ + unsigned long tx_dropped; /* packets dropped by dongle */ + unsigned long multicast; /* multicast packets received */ +}; + +/* event codes sent by the dongle to this driver */ +#define BRCMF_E_SET_SSID 0 +#define BRCMF_E_JOIN 1 +#define BRCMF_E_START 2 +#define BRCMF_E_AUTH 3 +#define BRCMF_E_AUTH_IND 4 +#define BRCMF_E_DEAUTH 5 +#define BRCMF_E_DEAUTH_IND 6 +#define BRCMF_E_ASSOC 7 +#define BRCMF_E_ASSOC_IND 8 +#define BRCMF_E_REASSOC 9 +#define BRCMF_E_REASSOC_IND 10 +#define BRCMF_E_DISASSOC 11 +#define BRCMF_E_DISASSOC_IND 12 +#define BRCMF_E_QUIET_START 13 +#define BRCMF_E_QUIET_END 14 +#define BRCMF_E_BEACON_RX 15 +#define BRCMF_E_LINK 16 +#define BRCMF_E_MIC_ERROR 17 +#define BRCMF_E_NDIS_LINK 18 +#define BRCMF_E_ROAM 19 +#define BRCMF_E_TXFAIL 20 +#define BRCMF_E_PMKID_CACHE 21 +#define BRCMF_E_RETROGRADE_TSF 22 +#define BRCMF_E_PRUNE 23 +#define BRCMF_E_AUTOAUTH 24 +#define BRCMF_E_EAPOL_MSG 25 +#define BRCMF_E_SCAN_COMPLETE 26 +#define BRCMF_E_ADDTS_IND 27 +#define BRCMF_E_DELTS_IND 28 +#define BRCMF_E_BCNSENT_IND 29 +#define BRCMF_E_BCNRX_MSG 30 +#define BRCMF_E_BCNLOST_MSG 31 +#define BRCMF_E_ROAM_PREP 32 +#define BRCMF_E_PFN_NET_FOUND 33 +#define BRCMF_E_PFN_NET_LOST 34 +#define BRCMF_E_RESET_COMPLETE 35 +#define BRCMF_E_JOIN_START 36 +#define BRCMF_E_ROAM_START 37 +#define BRCMF_E_ASSOC_START 38 +#define BRCMF_E_IBSS_ASSOC 39 +#define BRCMF_E_RADIO 40 +#define BRCMF_E_PSM_WATCHDOG 41 +#define BRCMF_E_PROBREQ_MSG 44 +#define BRCMF_E_SCAN_CONFIRM_IND 45 +#define BRCMF_E_PSK_SUP 46 +#define BRCMF_E_COUNTRY_CODE_CHANGED 47 +#define BRCMF_E_EXCEEDED_MEDIUM_TIME 48 +#define BRCMF_E_ICV_ERROR 49 +#define BRCMF_E_UNICAST_DECODE_ERROR 50 +#define BRCMF_E_MULTICAST_DECODE_ERROR 51 +#define BRCMF_E_TRACE 52 +#define BRCMF_E_IF 54 +#define BRCMF_E_RSSI 56 +#define BRCMF_E_PFN_SCAN_COMPLETE 57 +#define BRCMF_E_EXTLOG_MSG 58 +#define BRCMF_E_ACTION_FRAME 59 +#define BRCMF_E_ACTION_FRAME_COMPLETE 60 +#define BRCMF_E_PRE_ASSOC_IND 61 +#define BRCMF_E_PRE_REASSOC_IND 62 +#define BRCMF_E_CHANNEL_ADOPTED 63 +#define BRCMF_E_AP_STARTED 64 +#define BRCMF_E_DFS_AP_STOP 65 +#define BRCMF_E_DFS_AP_RESUME 66 +#define BRCMF_E_RESERVED1 67 +#define BRCMF_E_RESERVED2 68 +#define BRCMF_E_ESCAN_RESULT 69 +#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70 +#define BRCMF_E_DCS_REQUEST 73 + +#define BRCMF_E_FIFO_CREDIT_MAP 74 + +#define BRCMF_E_LAST 75 + +#define BRCMF_E_STATUS_SUCCESS 0 +#define BRCMF_E_STATUS_FAIL 1 +#define BRCMF_E_STATUS_TIMEOUT 2 +#define BRCMF_E_STATUS_NO_NETWORKS 3 +#define BRCMF_E_STATUS_ABORT 4 +#define BRCMF_E_STATUS_NO_ACK 5 +#define BRCMF_E_STATUS_UNSOLICITED 6 +#define BRCMF_E_STATUS_ATTEMPT 7 +#define BRCMF_E_STATUS_PARTIAL 8 +#define BRCMF_E_STATUS_NEWSCAN 9 +#define BRCMF_E_STATUS_NEWASSOC 10 +#define BRCMF_E_STATUS_11HQUIET 11 +#define BRCMF_E_STATUS_SUPPRESS 12 +#define BRCMF_E_STATUS_NOCHANS 13 +#define BRCMF_E_STATUS_CS_ABORT 15 +#define BRCMF_E_STATUS_ERROR 16 + +#define BRCMF_E_REASON_INITIAL_ASSOC 0 +#define BRCMF_E_REASON_LOW_RSSI 1 +#define BRCMF_E_REASON_DEAUTH 2 +#define BRCMF_E_REASON_DISASSOC 3 +#define BRCMF_E_REASON_BCNS_LOST 4 +#define BRCMF_E_REASON_MINTXRATE 9 +#define BRCMF_E_REASON_TXFAIL 10 + +#define BRCMF_E_REASON_FAST_ROAM_FAILED 5 +#define BRCMF_E_REASON_DIRECTED_ROAM 6 +#define BRCMF_E_REASON_TSPEC_REJECTED 7 +#define BRCMF_E_REASON_BETTER_AP 8 + +#define BRCMF_E_PRUNE_ENCR_MISMATCH 1 +#define BRCMF_E_PRUNE_BCAST_BSSID 2 +#define BRCMF_E_PRUNE_MAC_DENY 3 +#define BRCMF_E_PRUNE_MAC_NA 4 +#define BRCMF_E_PRUNE_REG_PASSV 5 +#define BRCMF_E_PRUNE_SPCT_MGMT 6 +#define BRCMF_E_PRUNE_RADAR 7 +#define BRCMF_E_RSN_MISMATCH 8 +#define BRCMF_E_PRUNE_NO_COMMON_RATES 9 +#define BRCMF_E_PRUNE_BASIC_RATES 10 +#define BRCMF_E_PRUNE_CIPHER_NA 12 +#define BRCMF_E_PRUNE_KNOWN_STA 13 +#define BRCMF_E_PRUNE_WDS_PEER 15 +#define BRCMF_E_PRUNE_QBSS_LOAD 16 +#define BRCMF_E_PRUNE_HOME_AP 17 + +#define BRCMF_E_SUP_OTHER 0 +#define BRCMF_E_SUP_DECRYPT_KEY_DATA 1 +#define BRCMF_E_SUP_BAD_UCAST_WEP128 2 +#define BRCMF_E_SUP_BAD_UCAST_WEP40 3 +#define BRCMF_E_SUP_UNSUP_KEY_LEN 4 +#define BRCMF_E_SUP_PW_KEY_CIPHER 5 +#define BRCMF_E_SUP_MSG3_TOO_MANY_IE 6 +#define BRCMF_E_SUP_MSG3_IE_MISMATCH 7 +#define BRCMF_E_SUP_NO_INSTALL_FLAG 8 +#define BRCMF_E_SUP_MSG3_NO_GTK 9 +#define BRCMF_E_SUP_GRP_KEY_CIPHER 10 +#define BRCMF_E_SUP_GRP_MSG1_NO_GTK 11 +#define BRCMF_E_SUP_GTK_DECRYPT_FAIL 12 +#define BRCMF_E_SUP_SEND_FAIL 13 +#define BRCMF_E_SUP_DEAUTH 14 + +#define BRCMF_E_IF_ADD 1 +#define BRCMF_E_IF_DEL 2 +#define BRCMF_E_IF_CHANGE 3 + +#define BRCMF_E_IF_ROLE_STA 0 +#define BRCMF_E_IF_ROLE_AP 1 +#define BRCMF_E_IF_ROLE_WDS 2 + +#define BRCMF_E_LINK_BCN_LOSS 1 +#define BRCMF_E_LINK_DISASSOC 2 +#define BRCMF_E_LINK_ASSOC_REC 3 +#define BRCMF_E_LINK_BSSCFG_DIS 4 + +/* The level of bus communication with the dongle */ +enum brcmf_bus_state { + BRCMF_BUS_DOWN, /* Not ready for frame transfers */ + BRCMF_BUS_LOAD, /* Download access only (CPU reset) */ + BRCMF_BUS_DATA /* Ready for frame transfers */ +}; + +/* Pattern matching filter. Specifies an offset within received packets to + * start matching, the pattern to match, the size of the pattern, and a bitmask + * that indicates which bits within the pattern should be matched. + */ +struct brcmf_pkt_filter_pattern_le { + /* + * Offset within received packet to start pattern matching. + * Offset '0' is the first byte of the ethernet header. + */ + __le32 offset; + /* Size of the pattern. Bitmask must be the same size.*/ + __le32 size_bytes; + /* + * Variable length mask and pattern data. mask starts at offset 0. + * Pattern immediately follows mask. + */ + u8 mask_and_pattern[1]; +}; + +/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */ +struct brcmf_pkt_filter_le { + __le32 id; /* Unique filter id, specified by app. */ + __le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */ + __le32 negate_match; /* Negate the result of filter matches */ + union { /* Filter definitions */ + struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */ + } u; +}; + +/* IOVAR "pkt_filter_enable" parameter. */ +struct brcmf_pkt_filter_enable_le { + __le32 id; /* Unique filter id */ + __le32 enable; /* Enable/disable bool */ +}; + +/* BSS info structure + * Applications MUST CHECK ie_offset field and length field to access IEs and + * next bss_info structure in a vector (in struct brcmf_scan_results) + */ +struct brcmf_bss_info { + __le32 version; /* version field */ + __le32 length; /* byte length of data in this record, + * starting at version and including IEs + */ + u8 BSSID[ETH_ALEN]; + __le16 beacon_period; /* units are Kusec */ + __le16 capability; /* Capability information */ + u8 SSID_len; + u8 SSID[32]; + struct { + __le32 count; /* # rates in this set */ + u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */ + } rateset; /* supported rates */ + __le16 chanspec; /* chanspec for bss */ + __le16 atim_window; /* units are Kusec */ + u8 dtim_period; /* DTIM period */ + __le16 RSSI; /* receive signal strength (in dBm) */ + s8 phy_noise; /* noise (in dBm) */ + + u8 n_cap; /* BSS is 802.11N Capable */ + /* 802.11N BSS Capabilities (based on HT_CAP_*): */ + __le32 nbss_cap; + u8 ctl_ch; /* 802.11N BSS control channel number */ + __le32 reserved32[1]; /* Reserved for expansion of BSS properties */ + u8 flags; /* flags */ + u8 reserved[3]; /* Reserved for expansion of BSS properties */ + u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */ + + __le16 ie_offset; /* offset at which IEs start, from beginning */ + __le32 ie_length; /* byte length of Information Elements */ + __le16 SNR; /* average SNR of during frame reception */ + /* Add new fields here */ + /* variable length Information Elements */ +}; + +struct brcm_rateset_le { + /* # rates in this set */ + __le32 count; + /* rates in 500kbps units w/hi bit set if basic */ + u8 rates[WL_NUMRATES]; +}; + +struct brcmf_ssid { + u32 SSID_len; + unsigned char SSID[32]; +}; + +struct brcmf_ssid_le { + __le32 SSID_len; + unsigned char SSID[32]; +}; + +struct brcmf_scan_params_le { + struct brcmf_ssid_le ssid_le; /* default: {0, ""} */ + u8 bssid[ETH_ALEN]; /* default: bcast */ + s8 bss_type; /* default: any, + * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT + */ + u8 scan_type; /* flags, 0 use default */ + __le32 nprobes; /* -1 use default, number of probes per channel */ + __le32 active_time; /* -1 use default, dwell time per channel for + * active scanning + */ + __le32 passive_time; /* -1 use default, dwell time per channel + * for passive scanning + */ + __le32 home_time; /* -1 use default, dwell time for the + * home channel between channel scans + */ + __le32 channel_num; /* count of channels and ssids that follow + * + * low half is count of channels in + * channel_list, 0 means default (use all + * available channels) + * + * high half is entries in struct brcmf_ssid + * array that follows channel_list, aligned for + * s32 (4 bytes) meaning an odd channel count + * implies a 2-byte pad between end of + * channel_list and first ssid + * + * if ssid count is zero, single ssid in the + * fixed parameter portion is assumed, otherwise + * ssid in the fixed portion is ignored + */ + __le16 channel_list[1]; /* list of chanspecs */ +}; + +/* incremental scan struct */ +struct brcmf_iscan_params_le { + __le32 version; + __le16 action; + __le16 scan_duration; + struct brcmf_scan_params_le params_le; +}; + +struct brcmf_scan_results { + u32 buflen; + u32 version; + u32 count; + struct brcmf_bss_info bss_info[1]; +}; + +struct brcmf_scan_results_le { + __le32 buflen; + __le32 version; + __le32 count; + struct brcmf_bss_info bss_info[1]; +}; + +/* used for association with a specific BSSID and chanspec list */ +struct brcmf_assoc_params_le { + /* 00:00:00:00:00:00: broadcast scan */ + u8 bssid[ETH_ALEN]; + /* 0: all available channels, otherwise count of chanspecs in + * chanspec_list */ + __le32 chanspec_num; + /* list of chanspecs */ + __le16 chanspec_list[1]; +}; + +/* used for join with or without a specific bssid and channel list */ +struct brcmf_join_params { + struct brcmf_ssid_le ssid_le; + struct brcmf_assoc_params_le params_le; +}; + +/* size of brcmf_scan_results not including variable length array */ +#define BRCMF_SCAN_RESULTS_FIXED_SIZE \ + (sizeof(struct brcmf_scan_results) - sizeof(struct brcmf_bss_info)) + +/* incremental scan results struct */ +struct brcmf_iscan_results { + union { + u32 status; + __le32 status_le; + }; + union { + struct brcmf_scan_results results; + struct brcmf_scan_results_le results_le; + }; +}; + +/* size of brcmf_iscan_results not including variable length array */ +#define BRCMF_ISCAN_RESULTS_FIXED_SIZE \ + (BRCMF_SCAN_RESULTS_FIXED_SIZE + \ + offsetof(struct brcmf_iscan_results, results)) + +struct brcmf_wsec_key { + u32 index; /* key index */ + u32 len; /* key length */ + u8 data[WLAN_MAX_KEY_LEN]; /* key data */ + u32 pad_1[18]; + u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ + u32 flags; /* misc flags */ + u32 pad_2[3]; + u32 iv_initialized; /* has IV been initialized already? */ + u32 pad_3; + /* Rx IV */ + struct { + u32 hi; /* upper 32 bits of IV */ + u16 lo; /* lower 16 bits of IV */ + } rxiv; + u32 pad_4[2]; + u8 ea[ETH_ALEN]; /* per station */ +}; + +/* + * dongle requires same struct as above but with fields in little endian order + */ +struct brcmf_wsec_key_le { + __le32 index; /* key index */ + __le32 len; /* key length */ + u8 data[WLAN_MAX_KEY_LEN]; /* key data */ + __le32 pad_1[18]; + __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */ + __le32 flags; /* misc flags */ + __le32 pad_2[3]; + __le32 iv_initialized; /* has IV been initialized already? */ + __le32 pad_3; + /* Rx IV */ + struct { + __le32 hi; /* upper 32 bits of IV */ + __le16 lo; /* lower 16 bits of IV */ + } rxiv; + __le32 pad_4[2]; + u8 ea[ETH_ALEN]; /* per station */ +}; + +/* Used to get specific STA parameters */ +struct brcmf_scb_val_le { + __le32 val; + u8 ea[ETH_ALEN]; +}; + +/* channel encoding */ +struct brcmf_channel_info_le { + __le32 hw_channel; + __le32 target_channel; + __le32 scan_channel; +}; + +/* Bus independent dongle command */ +struct brcmf_dcmd { + uint cmd; /* common dongle cmd definition */ + void *buf; /* pointer to user buffer */ + uint len; /* length of user buffer */ + u8 set; /* get or set request (optional) */ + uint used; /* bytes read or written (optional) */ + uint needed; /* bytes needed (optional) */ +}; + +/* Forward decls for struct brcmf_pub (see below) */ +struct brcmf_bus; /* device bus info */ +struct brcmf_proto; /* device communication protocol info */ +struct brcmf_info; /* device driver info */ +struct brcmf_cfg80211_dev; /* cfg80211 device info */ + +/* Common structure for module and instance linkage */ +struct brcmf_pub { + /* Linkage ponters */ + struct brcmf_bus *bus; + struct brcmf_proto *prot; + struct brcmf_info *info; + struct brcmf_cfg80211_dev *config; + + /* Internal brcmf items */ + bool up; /* Driver up/down (to OS) */ + bool txoff; /* Transmit flow-controlled */ + enum brcmf_bus_state busstate; + uint hdrlen; /* Total BRCMF header length (proto + bus) */ + uint maxctl; /* Max size rxctl request from proto to bus */ + uint rxsz; /* Rx buffer size bus module should use */ + u8 wme_dp; /* wme discard priority */ + + /* Dongle media info */ + bool iswl; /* Dongle-resident driver is wl */ + unsigned long drv_version; /* Version of dongle-resident driver */ + u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */ + struct dngl_stats dstats; /* Stats for dongle-based data */ + + /* Additional stats for the bus level */ + + /* Data packets sent to dongle */ + unsigned long tx_packets; + /* Multicast data packets sent to dongle */ + unsigned long tx_multicast; + /* Errors in sending data to dongle */ + unsigned long tx_errors; + /* Control packets sent to dongle */ + unsigned long tx_ctlpkts; + /* Errors sending control frames to dongle */ + unsigned long tx_ctlerrs; + /* Packets sent up the network interface */ + unsigned long rx_packets; + /* Multicast packets sent up the network interface */ + unsigned long rx_multicast; + /* Errors processing rx data packets */ + unsigned long rx_errors; + /* Control frames processed from dongle */ + unsigned long rx_ctlpkts; + + /* Errors in processing rx control frames */ + unsigned long rx_ctlerrs; + /* Packets dropped locally (no memory) */ + unsigned long rx_dropped; + /* Packets flushed due to unscheduled sendup thread */ + unsigned long rx_flushed; + /* Number of times dpc scheduled by watchdog timer */ + unsigned long wd_dpc_sched; + + /* Number of packets where header read-ahead was used. */ + unsigned long rx_readahead_cnt; + /* Number of tx packets we had to realloc for headroom */ + unsigned long tx_realloc; + /* Number of flow control pkts recvd */ + unsigned long fc_packets; + + /* Last error return */ + int bcmerror; + uint tickcnt; + + /* Last error from dongle */ + int dongle_error; + + /* Suspend disable flag flag */ + int suspend_disable_flag; /* "1" to disable all extra powersaving + during suspend */ + int in_suspend; /* flag set to 1 when early suspend called */ + int dtim_skip; /* dtim skip , default 0 means wake each dtim */ + + /* Pkt filter defination */ + char *pktfilter[100]; + int pktfilter_count; + + u8 country_code[BRCM_CNTRY_BUF_SZ]; + char eventmask[BRCMF_EVENTING_MASK_LEN]; + +}; + +struct brcmf_if_event { + u8 ifidx; + u8 action; + u8 flags; + u8 bssidx; +}; + +struct bcmevent_name { + uint event; + const char *name; +}; + +extern const struct bcmevent_name bcmevent_names[]; + +extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen, + char *buf, uint len); + +/* Indication from bus module regarding presence/insertion of dongle. + * Return struct brcmf_pub pointer, used as handle to OS module in later calls. + * Returned structure should have bus and prot pointers filled in. + * bus_hdrlen specifies required headroom for bus module header. + */ +extern struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, + uint bus_hdrlen); +extern int brcmf_net_attach(struct brcmf_pub *drvr, int idx); +extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev); + +extern s32 brcmf_exec_dcmd(struct net_device *dev, u32 cmd, void *arg, u32 len); + +/* Indication from bus module regarding removal/absence of dongle */ +extern void brcmf_detach(struct brcmf_pub *drvr); + +/* Indication from bus module to change flow-control state */ +extern void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool on); + +extern bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, + struct sk_buff *pkt, int prec); + +/* Receive frame for delivery to OS. Callee disposes of rxp. */ +extern void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, + struct sk_buff *rxp, int numpkt); + +/* Return pointer to interface name */ +extern char *brcmf_ifname(struct brcmf_pub *drvr, int idx); + +/* Notify tx completion */ +extern void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, + bool success); + +/* Query dongle */ +extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len); + +/* OS independent layer functions */ +extern int brcmf_os_proto_block(struct brcmf_pub *drvr); +extern int brcmf_os_proto_unblock(struct brcmf_pub *drvr); +#ifdef BCMDBG +extern int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size); +#endif /* BCMDBG */ + +extern int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name); +extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx, + void *pktdata, struct brcmf_event_msg *, + void **data_ptr); + +extern void brcmf_c_init(void); + +extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, + struct net_device *ndev, char *name, u8 *mac_addr, + u32 flags, u8 bssidx); +extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx); + +/* Send packet to dongle via data channel */ +extern int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx,\ + struct sk_buff *pkt); + +extern int brcmf_bus_start(struct brcmf_pub *drvr); + +extern void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg); +extern void brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, + int enable, int master_mode); + +#define BRCMF_DCMD_SMLEN 256 /* "small" cmd buffer required */ +#define BRCMF_DCMD_MEDLEN 1536 /* "med" cmd buffer required */ +#define BRCMF_DCMD_MAXLEN 8192 /* max length cmd buffer required */ + +/* message levels */ +#define BRCMF_ERROR_VAL 0x0001 +#define BRCMF_TRACE_VAL 0x0002 +#define BRCMF_INFO_VAL 0x0004 +#define BRCMF_DATA_VAL 0x0008 +#define BRCMF_CTL_VAL 0x0010 +#define BRCMF_TIMER_VAL 0x0020 +#define BRCMF_HDRS_VAL 0x0040 +#define BRCMF_BYTES_VAL 0x0080 +#define BRCMF_INTR_VAL 0x0100 +#define BRCMF_GLOM_VAL 0x0400 +#define BRCMF_EVENT_VAL 0x0800 +#define BRCMF_BTA_VAL 0x1000 +#define BRCMF_ISCAN_VAL 0x2000 + +/* Enter idle immediately (no timeout) */ +#define BRCMF_IDLE_IMMEDIATE (-1) +#define BRCMF_IDLE_ACTIVE 0 /* Do not request any SD clock change + when idle */ +#define BRCMF_IDLE_INTERVAL 1 + +#endif /* _BRCMF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h new file mode 100644 index 000000000000..a249407c9a1b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCMF_BUS_H_ +#define _BRCMF_BUS_H_ + +/* Packet alignment for most efficient SDIO (can change based on platform) */ +#define BRCMF_SDALIGN (1 << 6) + +/* watchdog polling interval in ms */ +#define BRCMF_WD_POLL_MS 10 + +/* + * Exported from brcmf bus module (brcmf_usb, brcmf_sdio) + */ + +/* Indicate (dis)interest in finding dongles. */ +extern int brcmf_bus_register(void); +extern void brcmf_bus_unregister(void); + +/* obtain linux device object providing bus function */ +extern struct device *brcmf_bus_get_device(struct brcmf_bus *bus); + +/* Stop bus module: clear pending frames, disable data flow */ +extern void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus); + +/* Initialize bus module: prepare for communication w/dongle */ +extern int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr); + +/* Send a data frame to the dongle. Callee disposes of txp. */ +extern int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *txp); + +/* Send/receive a control message to/from the dongle. + * Expects caller to enforce a single outstanding transaction. + */ +extern int +brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); + +extern int +brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen); + +extern void brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick); + +#endif /* _BRCMF_BUS_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c new file mode 100644 index 000000000000..e34c5c3d1d55 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +/******************************************************************************* + * Communicates with the dongle by using dcmd codes. + * For certain dcmd codes, the dongle interprets string data from the host. + ******************************************************************************/ + +#include <linux/types.h> +#include <linux/netdevice.h> +#include <linux/sched.h> +#include <defs.h> + +#include <brcmu_utils.h> +#include <brcmu_wifi.h> + +#include "dhd.h" +#include "dhd_proto.h" +#include "dhd_bus.h" +#include "dhd_dbg.h" + +struct brcmf_proto_cdc_dcmd { + __le32 cmd; /* dongle command value */ + __le32 len; /* lower 16: output buflen; + * upper 16: input buflen (excludes header) */ + __le32 flags; /* flag defns given below */ + __le32 status; /* status code returned from the device */ +}; + +/* Max valid buffer size that can be sent to the dongle */ +#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) + +/* CDC flag definitions */ +#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */ +#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ +#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */ +#define CDC_DCMD_IF_SHIFT 12 +#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */ +#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */ +#define CDC_DCMD_ID(flags) \ + (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT) + +/* + * BDC header - Broadcom specific extension of CDC. + * Used on data packets to convey priority across USB. + */ +#define BDC_HEADER_LEN 4 +#define BDC_PROTO_VER 1 /* Protocol version */ +#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */ +#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */ +#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */ +#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */ +#define BDC_PRIORITY_MASK 0x7 +#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */ +#define BDC_FLAG2_IF_SHIFT 0 + +#define BDC_GET_IF_IDX(hdr) \ + ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT)) +#define BDC_SET_IF_IDX(hdr, idx) \ + ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \ + ((idx) << BDC_FLAG2_IF_SHIFT))) + +struct brcmf_proto_bdc_header { + u8 flags; + u8 priority; /* 802.1d Priority, 4:7 flow control info for usb */ + u8 flags2; + u8 rssi; +}; + + +#define RETRIES 2 /* # of retries to retrieve matching dcmd response */ +#define BUS_HEADER_LEN (16+BRCMF_SDALIGN) /* Must be atleast SDPCM_RESERVE + * (amount of header tha might be added) + * plus any space that might be needed + * for alignment padding. + */ +#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for + * round off at the end of buffer + */ + +struct brcmf_proto { + u16 reqid; + u8 pending; + u32 lastcmd; + u8 bus_header[BUS_HEADER_LEN]; + struct brcmf_proto_cdc_dcmd msg; + unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN]; +}; + +static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr) +{ + struct brcmf_proto *prot = drvr->prot; + int len = le32_to_cpu(prot->msg.len) + + sizeof(struct brcmf_proto_cdc_dcmd); + + brcmf_dbg(TRACE, "Enter\n"); + + /* NOTE : cdc->msg.len holds the desired length of the buffer to be + * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area + * is actually sent to the dongle + */ + if (len > CDC_MAX_MSG_SIZE) + len = CDC_MAX_MSG_SIZE; + + /* Send request */ + return brcmf_sdbrcm_bus_txctl(drvr->bus, (unsigned char *)&prot->msg, + len); +} + +static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) +{ + int ret; + struct brcmf_proto *prot = drvr->prot; + + brcmf_dbg(TRACE, "Enter\n"); + + do { + ret = brcmf_sdbrcm_bus_rxctl(drvr->bus, + (unsigned char *)&prot->msg, + len + sizeof(struct brcmf_proto_cdc_dcmd)); + if (ret < 0) + break; + } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id); + + return ret; +} + +int +brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len) +{ + struct brcmf_proto *prot = drvr->prot; + struct brcmf_proto_cdc_dcmd *msg = &prot->msg; + void *info; + int ret = 0, retries = 0; + u32 id, flags; + + brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); + + /* Respond "bcmerror" and "bcmerrorstr" with local cache */ + if (cmd == BRCMF_C_GET_VAR && buf) { + if (!strcmp((char *)buf, "bcmerrorstr")) { + strncpy((char *)buf, "bcm_error", + BCME_STRLEN); + goto done; + } else if (!strcmp((char *)buf, "bcmerror")) { + *(int *)buf = drvr->dongle_error; + goto done; + } + } + + memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); + + msg->cmd = cpu_to_le32(cmd); + msg->len = cpu_to_le32(len); + flags = (++prot->reqid << CDC_DCMD_ID_SHIFT); + flags = (flags & ~CDC_DCMD_IF_MASK) | + (ifidx << CDC_DCMD_IF_SHIFT); + msg->flags = cpu_to_le32(flags); + + if (buf) + memcpy(prot->buf, buf, len); + + ret = brcmf_proto_cdc_msg(drvr); + if (ret < 0) { + brcmf_dbg(ERROR, "brcmf_proto_cdc_msg failed w/status %d\n", + ret); + goto done; + } + +retry: + /* wait for interrupt and get first fragment */ + ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); + if (ret < 0) + goto done; + + flags = le32_to_cpu(msg->flags); + id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; + + if ((id < prot->reqid) && (++retries < RETRIES)) + goto retry; + if (id != prot->reqid) { + brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n", + brcmf_ifname(drvr, ifidx), id, prot->reqid); + ret = -EINVAL; + goto done; + } + + /* Check info buffer */ + info = (void *)&msg[1]; + + /* Copy info buffer */ + if (buf) { + if (ret < (int)len) + len = ret; + memcpy(buf, info, len); + } + + /* Check the ERROR flag */ + if (flags & CDC_DCMD_ERROR) { + ret = le32_to_cpu(msg->status); + /* Cache error from dongle */ + drvr->dongle_error = ret; + } + +done: + return ret; +} + +int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd, + void *buf, uint len) +{ + struct brcmf_proto *prot = drvr->prot; + struct brcmf_proto_cdc_dcmd *msg = &prot->msg; + int ret = 0; + u32 flags, id; + + brcmf_dbg(TRACE, "Enter\n"); + brcmf_dbg(CTL, "cmd %d len %d\n", cmd, len); + + memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd)); + + msg->cmd = cpu_to_le32(cmd); + msg->len = cpu_to_le32(len); + flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET; + flags = (flags & ~CDC_DCMD_IF_MASK) | + (ifidx << CDC_DCMD_IF_SHIFT); + msg->flags = cpu_to_le32(flags); + + if (buf) + memcpy(prot->buf, buf, len); + + ret = brcmf_proto_cdc_msg(drvr); + if (ret < 0) + goto done; + + ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len); + if (ret < 0) + goto done; + + flags = le32_to_cpu(msg->flags); + id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT; + + if (id != prot->reqid) { + brcmf_dbg(ERROR, "%s: unexpected request id %d (expected %d)\n", + brcmf_ifname(drvr, ifidx), id, prot->reqid); + ret = -EINVAL; + goto done; + } + + /* Check the ERROR flag */ + if (flags & CDC_DCMD_ERROR) { + ret = le32_to_cpu(msg->status); + /* Cache error from dongle */ + drvr->dongle_error = ret; + } + +done: + return ret; +} + +int +brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd, + int len) +{ + struct brcmf_proto *prot = drvr->prot; + int ret = -1; + + if (drvr->busstate == BRCMF_BUS_DOWN) { + brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n"); + return ret; + } + brcmf_os_proto_block(drvr); + + brcmf_dbg(TRACE, "Enter\n"); + + if (len > BRCMF_DCMD_MAXLEN) + goto done; + + if (prot->pending == true) { + brcmf_dbg(TRACE, "CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", + dcmd->cmd, (unsigned long)dcmd->cmd, prot->lastcmd, + (unsigned long)prot->lastcmd); + if (dcmd->cmd == BRCMF_C_SET_VAR || + dcmd->cmd == BRCMF_C_GET_VAR) + brcmf_dbg(TRACE, "iovar cmd=%s\n", (char *)dcmd->buf); + + goto done; + } + + prot->pending = true; + prot->lastcmd = dcmd->cmd; + if (dcmd->set) + ret = brcmf_proto_cdc_set_dcmd(drvr, ifidx, dcmd->cmd, + dcmd->buf, len); + else { + ret = brcmf_proto_cdc_query_dcmd(drvr, ifidx, dcmd->cmd, + dcmd->buf, len); + if (ret > 0) + dcmd->used = ret - + sizeof(struct brcmf_proto_cdc_dcmd); + } + + if (ret >= 0) + ret = 0; + else { + struct brcmf_proto_cdc_dcmd *msg = &prot->msg; + /* len == needed when set/query fails from dongle */ + dcmd->needed = le32_to_cpu(msg->len); + } + + /* Intercept the wme_dp dongle cmd here */ + if (!ret && dcmd->cmd == BRCMF_C_SET_VAR && + !strcmp(dcmd->buf, "wme_dp")) { + int slen; + __le32 val = 0; + + slen = strlen("wme_dp") + 1; + if (len >= (int)(slen + sizeof(int))) + memcpy(&val, (char *)dcmd->buf + slen, sizeof(int)); + drvr->wme_dp = (u8) le32_to_cpu(val); + } + + prot->pending = false; + +done: + brcmf_os_proto_unblock(drvr); + + return ret; +} + +static bool pkt_sum_needed(struct sk_buff *skb) +{ + return skb->ip_summed == CHECKSUM_PARTIAL; +} + +static void pkt_set_sum_good(struct sk_buff *skb, bool x) +{ + skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE); +} + +void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, + struct sk_buff *pktbuf) +{ + struct brcmf_proto_bdc_header *h; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Push BDC header used to convey priority for buses that don't */ + + skb_push(pktbuf, BDC_HEADER_LEN); + + h = (struct brcmf_proto_bdc_header *)(pktbuf->data); + + h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); + if (pkt_sum_needed(pktbuf)) + h->flags |= BDC_FLAG_SUM_NEEDED; + + h->priority = (pktbuf->priority & BDC_PRIORITY_MASK); + h->flags2 = 0; + h->rssi = 0; + BDC_SET_IF_IDX(h, ifidx); +} + +int brcmf_proto_hdrpull(struct brcmf_pub *drvr, int *ifidx, + struct sk_buff *pktbuf) +{ + struct brcmf_proto_bdc_header *h; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Pop BDC header used to convey priority for buses that don't */ + + if (pktbuf->len < BDC_HEADER_LEN) { + brcmf_dbg(ERROR, "rx data too short (%d < %d)\n", + pktbuf->len, BDC_HEADER_LEN); + return -EBADE; + } + + h = (struct brcmf_proto_bdc_header *)(pktbuf->data); + + *ifidx = BDC_GET_IF_IDX(h); + if (*ifidx >= BRCMF_MAX_IFS) { + brcmf_dbg(ERROR, "rx data ifnum out of range (%d)\n", *ifidx); + return -EBADE; + } + + if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != + BDC_PROTO_VER) { + brcmf_dbg(ERROR, "%s: non-BDC packet received, flags 0x%x\n", + brcmf_ifname(drvr, *ifidx), h->flags); + return -EBADE; + } + + if (h->flags & BDC_FLAG_SUM_GOOD) { + brcmf_dbg(INFO, "%s: BDC packet received with good rx-csum, flags 0x%x\n", + brcmf_ifname(drvr, *ifidx), h->flags); + pkt_set_sum_good(pktbuf, true); + } + + pktbuf->priority = h->priority & BDC_PRIORITY_MASK; + + skb_pull(pktbuf, BDC_HEADER_LEN); + + return 0; +} + +int brcmf_proto_attach(struct brcmf_pub *drvr) +{ + struct brcmf_proto *cdc; + + cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC); + if (!cdc) + goto fail; + + /* ensure that the msg buf directly follows the cdc msg struct */ + if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) { + brcmf_dbg(ERROR, "struct brcmf_proto is not correctly defined\n"); + goto fail; + } + + drvr->prot = cdc; + drvr->hdrlen += BDC_HEADER_LEN; + drvr->maxctl = BRCMF_DCMD_MAXLEN + + sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN; + return 0; + +fail: + kfree(cdc); + return -ENOMEM; +} + +/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ +void brcmf_proto_detach(struct brcmf_pub *drvr) +{ + kfree(drvr->prot); + drvr->prot = NULL; +} + +void brcmf_proto_dstats(struct brcmf_pub *drvr) +{ + /* No stats from dongle added yet, copy bus stats */ + drvr->dstats.tx_packets = drvr->tx_packets; + drvr->dstats.tx_errors = drvr->tx_errors; + drvr->dstats.rx_packets = drvr->rx_packets; + drvr->dstats.rx_errors = drvr->rx_errors; + drvr->dstats.rx_dropped = drvr->rx_dropped; + drvr->dstats.multicast = drvr->rx_multicast; + return; +} + +int brcmf_proto_init(struct brcmf_pub *drvr) +{ + int ret = 0; + char buf[128]; + + brcmf_dbg(TRACE, "Enter\n"); + + brcmf_os_proto_block(drvr); + + /* Get the device MAC address */ + strcpy(buf, "cur_etheraddr"); + ret = brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, + buf, sizeof(buf)); + if (ret < 0) { + brcmf_os_proto_unblock(drvr); + return ret; + } + memcpy(drvr->mac, buf, ETH_ALEN); + + brcmf_os_proto_unblock(drvr); + + ret = brcmf_c_preinit_dcmds(drvr); + + /* Always assumes wl for now */ + drvr->iswl = true; + + return ret; +} + +void brcmf_proto_stop(struct brcmf_pub *drvr) +{ + /* Nothing to do for CDC */ +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c new file mode 100644 index 000000000000..891826197f96 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -0,0 +1,895 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/kernel.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/netdevice.h> +#include <asm/unaligned.h> +#include <defs.h> +#include <brcmu_wifi.h> +#include <brcmu_utils.h> +#include "dhd.h" +#include "dhd_bus.h" +#include "dhd_proto.h" +#include "dhd_dbg.h" + +#define BRCM_OUI "\x00\x10\x18" +#define DOT11_OUI_LEN 3 +#define BCMILCP_BCM_SUBTYPE_EVENT 1 +#define PKTFILTER_BUF_SIZE 2048 +#define BRCMF_ARPOL_MODE 0xb /* agent|snoop|peer_autoreply */ + +int brcmf_msg_level; + +#define MSGTRACE_VERSION 1 + +#define BRCMF_PKT_FILTER_FIXED_LEN offsetof(struct brcmf_pkt_filter_le, u) +#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN \ + offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern) + +#ifdef BCMDBG +static const char brcmf_version[] = + "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " + __DATE__ " at " __TIME__; +#else +static const char brcmf_version[] = + "Dongle Host Driver, version " BRCMF_VERSION_STR; +#endif + +/* Message trace header */ +struct msgtrace_hdr { + u8 version; + u8 spare; + __be16 len; /* Len of the trace */ + __be32 seqnum; /* Sequence number of message. Useful + * if the messsage has been lost + * because of DMA error or a bus reset + * (ex: SDIO Func2) + */ + __be32 discarded_bytes; /* Number of discarded bytes because of + trace overflow */ + __be32 discarded_printf; /* Number of discarded printf + because of trace overflow */ +} __packed; + + +uint +brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen) +{ + uint len; + + len = strlen(name) + 1; + + if ((len + datalen) > buflen) + return 0; + + strncpy(buf, name, buflen); + + /* append data onto the end of the name string */ + memcpy(&buf[len], data, datalen); + len += datalen; + + return len; +} + +void brcmf_c_init(void) +{ + /* Init global variables at run-time, not as part of the declaration. + * This is required to support init/de-init of the driver. + * Initialization + * of globals as part of the declaration results in non-deterministic + * behaviour since the value of the globals may be different on the + * first time that the driver is initialized vs subsequent + * initializations. + */ + brcmf_msg_level = BRCMF_ERROR_VAL; +} + +bool brcmf_c_prec_enq(struct brcmf_pub *drvr, struct pktq *q, + struct sk_buff *pkt, int prec) +{ + struct sk_buff *p; + int eprec = -1; /* precedence to evict from */ + bool discard_oldest; + + /* Fast case, precedence queue is not full and we are also not + * exceeding total queue length + */ + if (!pktq_pfull(q, prec) && !pktq_full(q)) { + brcmu_pktq_penq(q, prec, pkt); + return true; + } + + /* Determine precedence from which to evict packet, if any */ + if (pktq_pfull(q, prec)) + eprec = prec; + else if (pktq_full(q)) { + p = brcmu_pktq_peek_tail(q, &eprec); + if (eprec > prec) + return false; + } + + /* Evict if needed */ + if (eprec >= 0) { + /* Detect queueing to unconfigured precedence */ + discard_oldest = ac_bitmap_tst(drvr->wme_dp, eprec); + if (eprec == prec && !discard_oldest) + return false; /* refuse newer (incoming) packet */ + /* Evict packet according to discard policy */ + p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : + brcmu_pktq_pdeq_tail(q, eprec); + if (p == NULL) + brcmf_dbg(ERROR, "brcmu_pktq_penq() failed, oldest %d\n", + discard_oldest); + + brcmu_pkt_buf_free_skb(p); + } + + /* Enqueue */ + p = brcmu_pktq_penq(q, prec, pkt); + if (p == NULL) + brcmf_dbg(ERROR, "brcmu_pktq_penq() failed\n"); + + return p != NULL; +} + +#ifdef BCMDBG +static void +brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data) +{ + uint i, status, reason; + bool group = false, flush_txq = false, link = false; + char *auth_str, *event_name; + unsigned char *buf; + char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; + static struct { + uint event; + char *event_name; + } event_names[] = { + { + BRCMF_E_SET_SSID, "SET_SSID"}, { + BRCMF_E_JOIN, "JOIN"}, { + BRCMF_E_START, "START"}, { + BRCMF_E_AUTH, "AUTH"}, { + BRCMF_E_AUTH_IND, "AUTH_IND"}, { + BRCMF_E_DEAUTH, "DEAUTH"}, { + BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, { + BRCMF_E_ASSOC, "ASSOC"}, { + BRCMF_E_ASSOC_IND, "ASSOC_IND"}, { + BRCMF_E_REASSOC, "REASSOC"}, { + BRCMF_E_REASSOC_IND, "REASSOC_IND"}, { + BRCMF_E_DISASSOC, "DISASSOC"}, { + BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, { + BRCMF_E_QUIET_START, "START_QUIET"}, { + BRCMF_E_QUIET_END, "END_QUIET"}, { + BRCMF_E_BEACON_RX, "BEACON_RX"}, { + BRCMF_E_LINK, "LINK"}, { + BRCMF_E_MIC_ERROR, "MIC_ERROR"}, { + BRCMF_E_NDIS_LINK, "NDIS_LINK"}, { + BRCMF_E_ROAM, "ROAM"}, { + BRCMF_E_TXFAIL, "TXFAIL"}, { + BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, { + BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, { + BRCMF_E_PRUNE, "PRUNE"}, { + BRCMF_E_AUTOAUTH, "AUTOAUTH"}, { + BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, { + BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, { + BRCMF_E_ADDTS_IND, "ADDTS_IND"}, { + BRCMF_E_DELTS_IND, "DELTS_IND"}, { + BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, { + BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, { + BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, { + BRCMF_E_ROAM_PREP, "ROAM_PREP"}, { + BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, { + BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, { + BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, { + BRCMF_E_JOIN_START, "JOIN_START"}, { + BRCMF_E_ROAM_START, "ROAM_START"}, { + BRCMF_E_ASSOC_START, "ASSOC_START"}, { + BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, { + BRCMF_E_RADIO, "RADIO"}, { + BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, { + BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, { + BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, { + BRCMF_E_PSK_SUP, "PSK_SUP"}, { + BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, { + BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, { + BRCMF_E_ICV_ERROR, "ICV_ERROR"}, { + BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, { + BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, { + BRCMF_E_TRACE, "TRACE"}, { + BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, { + BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, { + BRCMF_E_IF, "IF"}, { + BRCMF_E_RSSI, "RSSI"}, { + BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"} + }; + uint event_type, flags, auth_type, datalen; + static u32 seqnum_prev; + struct msgtrace_hdr hdr; + u32 nblost; + char *s, *p; + + event_type = be32_to_cpu(event->event_type); + flags = be16_to_cpu(event->flags); + status = be32_to_cpu(event->status); + reason = be32_to_cpu(event->reason); + auth_type = be32_to_cpu(event->auth_type); + datalen = be32_to_cpu(event->datalen); + /* debug dump of event messages */ + sprintf(eabuf, "%pM", event->addr); + + event_name = "UNKNOWN"; + for (i = 0; i < ARRAY_SIZE(event_names); i++) { + if (event_names[i].event == event_type) + event_name = event_names[i].event_name; + } + + brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type); + brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n", + flags, status, reason, auth_type, eabuf); + + if (flags & BRCMF_EVENT_MSG_LINK) + link = true; + if (flags & BRCMF_EVENT_MSG_GROUP) + group = true; + if (flags & BRCMF_EVENT_MSG_FLUSHTXQ) + flush_txq = true; + + switch (event_type) { + case BRCMF_E_START: + case BRCMF_E_DEAUTH: + case BRCMF_E_DISASSOC: + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); + break; + + case BRCMF_E_ASSOC_IND: + case BRCMF_E_REASSOC_IND: + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); + break; + + case BRCMF_E_ASSOC: + case BRCMF_E_REASSOC: + if (status == BRCMF_E_STATUS_SUCCESS) + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n", + event_name, eabuf); + else if (status == BRCMF_E_STATUS_TIMEOUT) + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n", + event_name, eabuf); + else if (status == BRCMF_E_STATUS_FAIL) + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n", + event_name, eabuf, (int)reason); + else + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n", + event_name, eabuf, (int)status); + break; + + case BRCMF_E_DEAUTH_IND: + case BRCMF_E_DISASSOC_IND: + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n", + event_name, eabuf, (int)reason); + break; + + case BRCMF_E_AUTH: + case BRCMF_E_AUTH_IND: + if (auth_type == WLAN_AUTH_OPEN) + auth_str = "Open System"; + else if (auth_type == WLAN_AUTH_SHARED_KEY) + auth_str = "Shared Key"; + else { + sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); + auth_str = err_msg; + } + if (event_type == BRCMF_E_AUTH_IND) + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n", + event_name, eabuf, auth_str); + else if (status == BRCMF_E_STATUS_SUCCESS) + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n", + event_name, eabuf, auth_str); + else if (status == BRCMF_E_STATUS_TIMEOUT) + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n", + event_name, eabuf, auth_str); + else if (status == BRCMF_E_STATUS_FAIL) { + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", + event_name, eabuf, auth_str, (int)reason); + } + + break; + + case BRCMF_E_JOIN: + case BRCMF_E_ROAM: + case BRCMF_E_SET_SSID: + if (status == BRCMF_E_STATUS_SUCCESS) + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", + event_name, eabuf); + else if (status == BRCMF_E_STATUS_FAIL) + brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name); + else if (status == BRCMF_E_STATUS_NO_NETWORKS) + brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n", + event_name); + else + brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n", + event_name, (int)status); + break; + + case BRCMF_E_BEACON_RX: + if (status == BRCMF_E_STATUS_SUCCESS) + brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name); + else if (status == BRCMF_E_STATUS_FAIL) + brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name); + else + brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n", + event_name, status); + break; + + case BRCMF_E_LINK: + brcmf_dbg(EVENT, "MACEVENT: %s %s\n", + event_name, link ? "UP" : "DOWN"); + break; + + case BRCMF_E_MIC_ERROR: + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n", + event_name, eabuf, group, flush_txq); + break; + + case BRCMF_E_ICV_ERROR: + case BRCMF_E_UNICAST_DECODE_ERROR: + case BRCMF_E_MULTICAST_DECODE_ERROR: + brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf); + break; + + case BRCMF_E_TXFAIL: + brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf); + break; + + case BRCMF_E_SCAN_COMPLETE: + case BRCMF_E_PMKID_CACHE: + brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name); + break; + + case BRCMF_E_PFN_NET_FOUND: + case BRCMF_E_PFN_NET_LOST: + case BRCMF_E_PFN_SCAN_COMPLETE: + brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name); + break; + + case BRCMF_E_PSK_SUP: + case BRCMF_E_PRUNE: + brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n", + event_name, (int)status, (int)reason); + break; + + case BRCMF_E_TRACE: + buf = (unsigned char *) event_data; + memcpy(&hdr, buf, sizeof(struct msgtrace_hdr)); + + if (hdr.version != MSGTRACE_VERSION) { + brcmf_dbg(ERROR, + "MACEVENT: %s [unsupported version --> brcmf" + " version:%d dongle version:%d]\n", + event_name, MSGTRACE_VERSION, hdr.version); + /* Reset datalen to avoid display below */ + datalen = 0; + break; + } + + /* There are 2 bytes available at the end of data */ + *(buf + sizeof(struct msgtrace_hdr) + + be16_to_cpu(hdr.len)) = '\0'; + + if (be32_to_cpu(hdr.discarded_bytes) + || be32_to_cpu(hdr.discarded_printf)) + brcmf_dbg(ERROR, + "WLC_E_TRACE: [Discarded traces in dongle -->" + " discarded_bytes %d discarded_printf %d]\n", + be32_to_cpu(hdr.discarded_bytes), + be32_to_cpu(hdr.discarded_printf)); + + nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1; + if (nblost > 0) + brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum " + " %d nblost %d\n", be32_to_cpu(hdr.seqnum), + nblost); + seqnum_prev = be32_to_cpu(hdr.seqnum); + + /* Display the trace buffer. Advance from \n to \n to + * avoid display big + * printf (issue with Linux printk ) + */ + p = (char *)&buf[sizeof(struct msgtrace_hdr)]; + while ((s = strstr(p, "\n")) != NULL) { + *s = '\0'; + printk(KERN_DEBUG"%s\n", p); + p = s + 1; + } + printk(KERN_DEBUG "%s\n", p); + + /* Reset datalen to avoid display below */ + datalen = 0; + break; + + case BRCMF_E_RSSI: + brcmf_dbg(EVENT, "MACEVENT: %s %d\n", + event_name, be32_to_cpu(*((__be32 *)event_data))); + break; + + default: + brcmf_dbg(EVENT, + "MACEVENT: %s %d, MAC %s, status %d, reason %d, " + "auth %d\n", event_name, event_type, eabuf, + (int)status, (int)reason, (int)auth_type); + break; + } + + /* show any appended data */ + if (datalen) { + buf = (unsigned char *) event_data; + brcmf_dbg(EVENT, " data (%d) : ", datalen); + for (i = 0; i < datalen; i++) + brcmf_dbg(EVENT, " 0x%02x ", *buf++); + brcmf_dbg(EVENT, "\n"); + } +} +#endif /* BCMDBG */ + +int +brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata, + struct brcmf_event_msg *event, void **data_ptr) +{ + /* check whether packet is a BRCM event pkt */ + struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata; + struct brcmf_if_event *ifevent; + char *event_data; + u32 type, status; + u16 flags; + int evlen; + + if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) { + brcmf_dbg(ERROR, "mismatched OUI, bailing\n"); + return -EBADE; + } + + /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ + if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) != + BCMILCP_BCM_SUBTYPE_EVENT) { + brcmf_dbg(ERROR, "mismatched subtype, bailing\n"); + return -EBADE; + } + + *data_ptr = &pvt_data[1]; + event_data = *data_ptr; + + /* memcpy since BRCM event pkt may be unaligned. */ + memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg)); + + type = get_unaligned_be32(&event->event_type); + flags = get_unaligned_be16(&event->flags); + status = get_unaligned_be32(&event->status); + evlen = get_unaligned_be32(&event->datalen) + + sizeof(struct brcmf_event); + + switch (type) { + case BRCMF_E_IF: + ifevent = (struct brcmf_if_event *) event_data; + brcmf_dbg(TRACE, "if event\n"); + + if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) { + if (ifevent->action == BRCMF_E_IF_ADD) + brcmf_add_if(drvr_priv, ifevent->ifidx, NULL, + event->ifname, + pvt_data->eth.h_dest, + ifevent->flags, ifevent->bssidx); + else + brcmf_del_if(drvr_priv, ifevent->ifidx); + } else { + brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n", + ifevent->ifidx, event->ifname); + } + + /* send up the if event: btamp user needs it */ + *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); + break; + + /* These are what external supplicant/authenticator wants */ + case BRCMF_E_LINK: + case BRCMF_E_ASSOC_IND: + case BRCMF_E_REASSOC_IND: + case BRCMF_E_DISASSOC_IND: + case BRCMF_E_MIC_ERROR: + default: + /* Fall through: this should get _everything_ */ + + *ifidx = brcmf_ifname2idx(drvr_priv, event->ifname); + brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n", + type, flags, status); + + /* put it back to BRCMF_E_NDIS_LINK */ + if (type == BRCMF_E_NDIS_LINK) { + u32 temp1; + __be32 temp2; + + temp1 = get_unaligned_be32(&event->event_type); + brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n", + temp1); + + temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK); + memcpy((void *)(&pvt_data->msg.event_type), &temp2, + sizeof(pvt_data->msg.event_type)); + } + break; + } + +#ifdef BCMDBG + brcmf_c_show_host_event(event, event_data); +#endif /* BCMDBG */ + + return 0; +} + +/* Convert user's input in hex pattern to byte-size mask */ +static int brcmf_c_pattern_atoh(char *src, char *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { + brcmf_dbg(ERROR, "Mask invalid format. Needs to start with 0x\n"); + return -EINVAL; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + brcmf_dbg(ERROR, "Mask invalid format. Length must be even.\n"); + return -EINVAL; + } + for (i = 0; *src != '\0'; i++) { + unsigned long res; + char num[3]; + strncpy(num, src, 2); + num[2] = '\0'; + if (kstrtoul(num, 16, &res)) + return -EINVAL; + dst[i] = (u8)res; + src += 2; + } + return i; +} + +void +brcmf_c_pktfilter_offload_enable(struct brcmf_pub *drvr, char *arg, int enable, + int master_mode) +{ + unsigned long res; + char *argv[8]; + int i = 0; + const char *str; + int buf_len; + int str_len; + char *arg_save = NULL, *arg_org = NULL; + int rc; + char buf[128]; + struct brcmf_pkt_filter_enable_le enable_parm; + struct brcmf_pkt_filter_enable_le *pkt_filterp; + __le32 mmode_le; + + arg_save = kmalloc(strlen(arg) + 1, GFP_ATOMIC); + if (!arg_save) + goto fail; + + arg_org = arg_save; + memcpy(arg_save, arg, strlen(arg) + 1); + + argv[i] = strsep(&arg_save, " "); + + i = 0; + if (NULL == argv[i]) { + brcmf_dbg(ERROR, "No args provided\n"); + goto fail; + } + + str = "pkt_filter_enable"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[str_len] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (struct brcmf_pkt_filter_enable_le *) (buf + str_len + 1); + + /* Parse packet filter id. */ + enable_parm.id = 0; + if (!kstrtoul(argv[i], 0, &res)) + enable_parm.id = cpu_to_le32((u32)res); + + /* Parse enable/disable value. */ + enable_parm.enable = cpu_to_le32(enable); + + buf_len += sizeof(enable_parm); + memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm)); + + /* Enable/disable the specified filter. */ + rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); + rc = rc >= 0 ? 0 : rc; + if (rc) + brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", + arg, rc); + else + brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg); + + /* Contorl the master mode */ + mmode_le = cpu_to_le32(master_mode); + brcmf_c_mkiovar("pkt_filter_mode", (char *)&mmode_le, 4, buf, + sizeof(buf)); + rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, + sizeof(buf)); + rc = rc >= 0 ? 0 : rc; + if (rc) + brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", + arg, rc); + +fail: + kfree(arg_org); +} + +void brcmf_c_pktfilter_offload_set(struct brcmf_pub *drvr, char *arg) +{ + const char *str; + struct brcmf_pkt_filter_le pkt_filter; + struct brcmf_pkt_filter_le *pkt_filterp; + unsigned long res; + int buf_len; + int str_len; + int rc; + u32 mask_size; + u32 pattern_size; + char *argv[8], *buf = NULL; + int i = 0; + char *arg_save = NULL, *arg_org = NULL; + + arg_save = kstrdup(arg, GFP_ATOMIC); + if (!arg_save) + goto fail; + + arg_org = arg_save; + + buf = kmalloc(PKTFILTER_BUF_SIZE, GFP_ATOMIC); + if (!buf) + goto fail; + + argv[i] = strsep(&arg_save, " "); + while (argv[i++]) + argv[i] = strsep(&arg_save, " "); + + i = 0; + if (NULL == argv[i]) { + brcmf_dbg(ERROR, "No args provided\n"); + goto fail; + } + + str = "pkt_filter_add"; + strcpy(buf, str); + str_len = strlen(str); + buf_len = str_len + 1; + + pkt_filterp = (struct brcmf_pkt_filter_le *) (buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = 0; + if (!kstrtoul(argv[i], 0, &res)) + pkt_filter.id = cpu_to_le32((u32)res); + + if (NULL == argv[++i]) { + brcmf_dbg(ERROR, "Polarity not provided\n"); + goto fail; + } + + /* Parse filter polarity. */ + pkt_filter.negate_match = 0; + if (!kstrtoul(argv[i], 0, &res)) + pkt_filter.negate_match = cpu_to_le32((u32)res); + + if (NULL == argv[++i]) { + brcmf_dbg(ERROR, "Filter type not provided\n"); + goto fail; + } + + /* Parse filter type. */ + pkt_filter.type = 0; + if (!kstrtoul(argv[i], 0, &res)) + pkt_filter.type = cpu_to_le32((u32)res); + + if (NULL == argv[++i]) { + brcmf_dbg(ERROR, "Offset not provided\n"); + goto fail; + } + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = 0; + if (!kstrtoul(argv[i], 0, &res)) + pkt_filter.u.pattern.offset = cpu_to_le32((u32)res); + + if (NULL == argv[++i]) { + brcmf_dbg(ERROR, "Bitmask not provided\n"); + goto fail; + } + + /* Parse pattern filter mask. */ + mask_size = + brcmf_c_pattern_atoh + (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern); + + if (NULL == argv[++i]) { + brcmf_dbg(ERROR, "Pattern not provided\n"); + goto fail; + } + + /* Parse pattern filter pattern. */ + pattern_size = + brcmf_c_pattern_atoh(argv[i], + (char *)&pkt_filterp->u.pattern. + mask_and_pattern[mask_size]); + + if (mask_size != pattern_size) { + brcmf_dbg(ERROR, "Mask and pattern not the same size\n"); + goto fail; + } + + pkt_filter.u.pattern.size_bytes = cpu_to_le32(mask_size); + buf_len += BRCMF_PKT_FILTER_FIXED_LEN; + buf_len += (BRCMF_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); + + /* Keep-alive attributes are set in local + * variable (keep_alive_pkt), and + ** then memcpy'ed into buffer (keep_alive_pktp) since there is no + ** guarantee that the buffer is properly aligned. + */ + memcpy((char *)pkt_filterp, + &pkt_filter, + BRCMF_PKT_FILTER_FIXED_LEN + BRCMF_PKT_FILTER_PATTERN_FIXED_LEN); + + rc = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, buf, buf_len); + rc = rc >= 0 ? 0 : rc; + + if (rc) + brcmf_dbg(TRACE, "failed to add pktfilter %s, retcode = %d\n", + arg, rc); + else + brcmf_dbg(TRACE, "successfully added pktfilter %s\n", arg); + +fail: + kfree(arg_org); + + kfree(buf); +} + +static void brcmf_c_arp_offload_set(struct brcmf_pub *drvr, int arp_mode) +{ + char iovbuf[32]; + int retcode; + + brcmf_c_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); + retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, + iovbuf, sizeof(iovbuf)); + retcode = retcode >= 0 ? 0 : retcode; + if (retcode) + brcmf_dbg(TRACE, "failed to set ARP offload mode to 0x%x, retcode = %d\n", + arp_mode, retcode); + else + brcmf_dbg(TRACE, "successfully set ARP offload mode to 0x%x\n", + arp_mode); +} + +static void brcmf_c_arp_offload_enable(struct brcmf_pub *drvr, int arp_enable) +{ + char iovbuf[32]; + int retcode; + + brcmf_c_mkiovar("arpoe", (char *)&arp_enable, 4, + iovbuf, sizeof(iovbuf)); + retcode = brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, + iovbuf, sizeof(iovbuf)); + retcode = retcode >= 0 ? 0 : retcode; + if (retcode) + brcmf_dbg(TRACE, "failed to enable ARP offload to %d, retcode = %d\n", + arp_enable, retcode); + else + brcmf_dbg(TRACE, "successfully enabled ARP offload to %d\n", + arp_enable); +} + +int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) +{ + char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for + "event_msgs" + '\0' + bitvec */ + uint up = 0; + char buf[128], *ptr; + u32 dongle_align = BRCMF_SDALIGN; + u32 glom = 0; + u32 roaming = 1; + uint bcn_timeout = 3; + int scan_assoc_time = 40; + int scan_unassoc_time = 40; + int i; + + brcmf_os_proto_block(drvr); + + /* Set Country code */ + if (drvr->country_code[0] != 0) { + if (brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_COUNTRY, + drvr->country_code, + sizeof(drvr->country_code)) < 0) + brcmf_dbg(ERROR, "country code setting failed\n"); + } + + /* query for 'ver' to get version info from firmware */ + memset(buf, 0, sizeof(buf)); + ptr = buf; + brcmf_c_mkiovar("ver", NULL, 0, buf, sizeof(buf)); + brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, buf, sizeof(buf)); + strsep(&ptr, "\n"); + /* Print fw version info */ + brcmf_dbg(ERROR, "Firmware version = %s\n", buf); + + /* Match Host and Dongle rx alignment */ + brcmf_c_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, + sizeof(iovbuf)); + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, + sizeof(iovbuf)); + + /* disable glom option per default */ + brcmf_c_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, + sizeof(iovbuf)); + + /* Setup timeout if Beacons are lost and roam is off to report + link down */ + brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, + sizeof(iovbuf)); + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, + sizeof(iovbuf)); + + /* Enable/Disable build-in roaming to allowed ext supplicant to take + of romaing */ + brcmf_c_mkiovar("roam_off", (char *)&roaming, 4, + iovbuf, sizeof(iovbuf)); + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, + sizeof(iovbuf)); + + /* Force STA UP */ + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up)); + + /* Setup event_msgs */ + brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, + iovbuf, sizeof(iovbuf)); + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, + sizeof(iovbuf)); + + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_CHANNEL_TIME, + (char *)&scan_assoc_time, sizeof(scan_assoc_time)); + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_SCAN_UNASSOC_TIME, + (char *)&scan_unassoc_time, sizeof(scan_unassoc_time)); + + /* Set and enable ARP offload feature */ + brcmf_c_arp_offload_set(drvr, BRCMF_ARPOL_MODE); + brcmf_c_arp_offload_enable(drvr, true); + + /* Set up pkt filter */ + for (i = 0; i < drvr->pktfilter_count; i++) { + brcmf_c_pktfilter_offload_set(drvr, drvr->pktfilter[i]); + brcmf_c_pktfilter_offload_enable(drvr, drvr->pktfilter[i], + 0, true); + } + + brcmf_os_proto_unblock(drvr); + + return 0; +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h new file mode 100644 index 000000000000..7467922f0536 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCMF_DBG_H_ +#define _BRCMF_DBG_H_ + +#if defined(BCMDBG) + +#define brcmf_dbg(level, fmt, ...) \ +do { \ + if (BRCMF_ERROR_VAL == BRCMF_##level##_VAL) { \ + if (brcmf_msg_level & BRCMF_##level##_VAL) { \ + if (net_ratelimit()) \ + printk(KERN_DEBUG "%s: " fmt, \ + __func__, ##__VA_ARGS__); \ + } \ + } else { \ + if (brcmf_msg_level & BRCMF_##level##_VAL) { \ + printk(KERN_DEBUG "%s: " fmt, \ + __func__, ##__VA_ARGS__); \ + } \ + } \ +} while (0) + +#define BRCMF_DATA_ON() (brcmf_msg_level & BRCMF_DATA_VAL) +#define BRCMF_CTL_ON() (brcmf_msg_level & BRCMF_CTL_VAL) +#define BRCMF_HDRS_ON() (brcmf_msg_level & BRCMF_HDRS_VAL) +#define BRCMF_BYTES_ON() (brcmf_msg_level & BRCMF_BYTES_VAL) +#define BRCMF_GLOM_ON() (brcmf_msg_level & BRCMF_GLOM_VAL) + +#else /* (defined BCMDBG) || (defined BCMDBG) */ + +#define brcmf_dbg(level, fmt, ...) no_printk(fmt, ##__VA_ARGS__) + +#define BRCMF_DATA_ON() 0 +#define BRCMF_CTL_ON() 0 +#define BRCMF_HDRS_ON() 0 +#define BRCMF_BYTES_ON() 0 +#define BRCMF_GLOM_ON() 0 + +#endif /* defined(BCMDBG) */ + +extern int brcmf_msg_level; + +#endif /* _BRCMF_DBG_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c new file mode 100644 index 000000000000..4acbac5a74c6 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -0,0 +1,1356 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/init.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/slab.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/mmc/sdio_func.h> +#include <linux/random.h> +#include <linux/spinlock.h> +#include <linux/ethtool.h> +#include <linux/fcntl.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/hardirq.h> +#include <linux/mutex.h> +#include <linux/wait.h> +#include <linux/module.h> +#include <net/cfg80211.h> +#include <net/rtnetlink.h> +#include <defs.h> +#include <brcmu_utils.h> +#include <brcmu_wifi.h> + +#include "dhd.h" +#include "dhd_bus.h" +#include "dhd_proto.h" +#include "dhd_dbg.h" +#include "wl_cfg80211.h" +#include "bcmchip.h" + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver."); +MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards"); +MODULE_LICENSE("Dual BSD/GPL"); + + +/* Interface control information */ +struct brcmf_if { + struct brcmf_info *info; /* back pointer to brcmf_info */ + /* OS/stack specifics */ + struct net_device *ndev; + struct net_device_stats stats; + int idx; /* iface idx in dongle */ + int state; /* interface state */ + u8 mac_addr[ETH_ALEN]; /* assigned MAC address */ +}; + +/* Local private structure (extension of pub) */ +struct brcmf_info { + struct brcmf_pub pub; + + /* OS/stack specifics */ + struct brcmf_if *iflist[BRCMF_MAX_IFS]; + + struct mutex proto_block; + + struct work_struct setmacaddr_work; + struct work_struct multicast_work; + u8 macvalue[ETH_ALEN]; + atomic_t pend_8021x_cnt; +}; + +/* Error bits */ +module_param(brcmf_msg_level, int, 0); + + +static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev) +{ + int i = 0; + + while (i < BRCMF_MAX_IFS) { + if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev) + return i; + i++; + } + + return BRCMF_BAD_IF; +} + +int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name) +{ + int i = BRCMF_MAX_IFS; + struct brcmf_if *ifp; + + if (name == NULL || *name == '\0') + return 0; + + while (--i > 0) { + ifp = drvr_priv->iflist[i]; + if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ)) + break; + } + + brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name); + + return i; /* default - the primary interface */ +} + +char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx) +{ + struct brcmf_info *drvr_priv = drvr->info; + + if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) { + brcmf_dbg(ERROR, "ifidx %d out of range\n", ifidx); + return "<if_bad>"; + } + + if (drvr_priv->iflist[ifidx] == NULL) { + brcmf_dbg(ERROR, "null i/f %d\n", ifidx); + return "<if_null>"; + } + + if (drvr_priv->iflist[ifidx]->ndev) + return drvr_priv->iflist[ifidx]->ndev->name; + + return "<if_none>"; +} + +static void _brcmf_set_multicast_list(struct work_struct *work) +{ + struct net_device *ndev; + struct netdev_hw_addr *ha; + u32 dcmd_value, cnt; + __le32 cnt_le; + __le32 dcmd_le_value; + + struct brcmf_dcmd dcmd; + char *buf, *bufp; + uint buflen; + int ret; + + struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info, + multicast_work); + + ndev = drvr_priv->iflist[0]->ndev; + cnt = netdev_mc_count(ndev); + + /* Determine initial value of allmulti flag */ + dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false; + + /* Send down the multicast list first. */ + + buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN); + bufp = buf = kmalloc(buflen, GFP_ATOMIC); + if (!bufp) + return; + + strcpy(bufp, "mcast_list"); + bufp += strlen("mcast_list") + 1; + + cnt_le = cpu_to_le32(cnt); + memcpy(bufp, &cnt_le, sizeof(cnt)); + bufp += sizeof(cnt_le); + + netdev_for_each_mc_addr(ha, ndev) { + if (!cnt) + break; + memcpy(bufp, ha->addr, ETH_ALEN); + bufp += ETH_ALEN; + cnt--; + } + + memset(&dcmd, 0, sizeof(dcmd)); + dcmd.cmd = BRCMF_C_SET_VAR; + dcmd.buf = buf; + dcmd.len = buflen; + dcmd.set = true; + + ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); + if (ret < 0) { + brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n", + brcmf_ifname(&drvr_priv->pub, 0), cnt); + dcmd_value = cnt ? true : dcmd_value; + } + + kfree(buf); + + /* Now send the allmulti setting. This is based on the setting in the + * net_device flags, but might be modified above to be turned on if we + * were trying to set some addresses and dongle rejected it... + */ + + buflen = sizeof("allmulti") + sizeof(dcmd_value); + buf = kmalloc(buflen, GFP_ATOMIC); + if (!buf) + return; + + dcmd_le_value = cpu_to_le32(dcmd_value); + + if (!brcmf_c_mkiovar + ("allmulti", (void *)&dcmd_le_value, + sizeof(dcmd_le_value), buf, buflen)) { + brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n", + brcmf_ifname(&drvr_priv->pub, 0), + (int)sizeof(dcmd_value), buflen); + kfree(buf); + return; + } + + memset(&dcmd, 0, sizeof(dcmd)); + dcmd.cmd = BRCMF_C_SET_VAR; + dcmd.buf = buf; + dcmd.len = buflen; + dcmd.set = true; + + ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); + if (ret < 0) { + brcmf_dbg(ERROR, "%s: set allmulti %d failed\n", + brcmf_ifname(&drvr_priv->pub, 0), + le32_to_cpu(dcmd_le_value)); + } + + kfree(buf); + + /* Finally, pick up the PROMISC flag as well, like the NIC + driver does */ + + dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false; + dcmd_le_value = cpu_to_le32(dcmd_value); + + memset(&dcmd, 0, sizeof(dcmd)); + dcmd.cmd = BRCMF_C_SET_PROMISC; + dcmd.buf = &dcmd_le_value; + dcmd.len = sizeof(dcmd_le_value); + dcmd.set = true; + + ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); + if (ret < 0) { + brcmf_dbg(ERROR, "%s: set promisc %d failed\n", + brcmf_ifname(&drvr_priv->pub, 0), + le32_to_cpu(dcmd_le_value)); + } +} + +static void +_brcmf_set_mac_address(struct work_struct *work) +{ + char buf[32]; + struct brcmf_dcmd dcmd; + int ret; + + struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info, + setmacaddr_work); + + brcmf_dbg(TRACE, "enter\n"); + if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue, + ETH_ALEN, buf, 32)) { + brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n", + brcmf_ifname(&drvr_priv->pub, 0)); + return; + } + memset(&dcmd, 0, sizeof(dcmd)); + dcmd.cmd = BRCMF_C_SET_VAR; + dcmd.buf = buf; + dcmd.len = 32; + dcmd.set = true; + + ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len); + if (ret < 0) + brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n", + brcmf_ifname(&drvr_priv->pub, 0)); + else + memcpy(drvr_priv->iflist[0]->ndev->dev_addr, + drvr_priv->macvalue, ETH_ALEN); + + return; +} + +static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr) +{ + struct brcmf_info *drvr_priv = *(struct brcmf_info **) + netdev_priv(ndev); + struct sockaddr *sa = (struct sockaddr *)addr; + int ifidx; + + ifidx = brcmf_net2idx(drvr_priv, ndev); + if (ifidx == BRCMF_BAD_IF) + return -1; + + memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN); + schedule_work(&drvr_priv->setmacaddr_work); + return 0; +} + +static void brcmf_netdev_set_multicast_list(struct net_device *ndev) +{ + struct brcmf_info *drvr_priv = *(struct brcmf_info **) + netdev_priv(ndev); + int ifidx; + + ifidx = brcmf_net2idx(drvr_priv, ndev); + if (ifidx == BRCMF_BAD_IF) + return; + + schedule_work(&drvr_priv->multicast_work); +} + +int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf) +{ + struct brcmf_info *drvr_priv = drvr->info; + + /* Reject if down */ + if (!drvr->up || (drvr->busstate == BRCMF_BUS_DOWN)) + return -ENODEV; + + /* Update multicast statistic */ + if (pktbuf->len >= ETH_ALEN) { + u8 *pktdata = (u8 *) (pktbuf->data); + struct ethhdr *eh = (struct ethhdr *)pktdata; + + if (is_multicast_ether_addr(eh->h_dest)) + drvr->tx_multicast++; + if (ntohs(eh->h_proto) == ETH_P_PAE) + atomic_inc(&drvr_priv->pend_8021x_cnt); + } + + /* If the protocol uses a data header, apply it */ + brcmf_proto_hdrpush(drvr, ifidx, pktbuf); + + /* Use bus module to send data frame */ + return brcmf_sdbrcm_bus_txdata(drvr->bus, pktbuf); +} + +static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int ret; + struct brcmf_info *drvr_priv = *(struct brcmf_info **) + netdev_priv(ndev); + int ifidx; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Reject if down */ + if (!drvr_priv->pub.up || (drvr_priv->pub.busstate == BRCMF_BUS_DOWN)) { + brcmf_dbg(ERROR, "xmit rejected pub.up=%d busstate=%d\n", + drvr_priv->pub.up, drvr_priv->pub.busstate); + netif_stop_queue(ndev); + return -ENODEV; + } + + ifidx = brcmf_net2idx(drvr_priv, ndev); + if (ifidx == BRCMF_BAD_IF) { + brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx); + netif_stop_queue(ndev); + return -ENODEV; + } + + /* Make sure there's enough room for any header */ + if (skb_headroom(skb) < drvr_priv->pub.hdrlen) { + struct sk_buff *skb2; + + brcmf_dbg(INFO, "%s: insufficient headroom\n", + brcmf_ifname(&drvr_priv->pub, ifidx)); + drvr_priv->pub.tx_realloc++; + skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen); + dev_kfree_skb(skb); + skb = skb2; + if (skb == NULL) { + brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n", + brcmf_ifname(&drvr_priv->pub, ifidx)); + ret = -ENOMEM; + goto done; + } + } + + ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb); + +done: + if (ret) + drvr_priv->pub.dstats.tx_dropped++; + else + drvr_priv->pub.tx_packets++; + + /* Return ok: we always eat the packet */ + return 0; +} + +void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state) +{ + struct net_device *ndev; + struct brcmf_info *drvr_priv = drvr->info; + + brcmf_dbg(TRACE, "Enter\n"); + + drvr->txoff = state; + ndev = drvr_priv->iflist[ifidx]->ndev; + if (state == ON) + netif_stop_queue(ndev); + else + netif_wake_queue(ndev); +} + +static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx, + void *pktdata, struct brcmf_event_msg *event, + void **data) +{ + int bcmerror = 0; + + bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data); + if (bcmerror != 0) + return bcmerror; + + if (drvr_priv->iflist[*ifidx]->ndev) + brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->ndev, + event, *data); + + return bcmerror; +} + +void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb, + int numpkt) +{ + struct brcmf_info *drvr_priv = drvr->info; + unsigned char *eth; + uint len; + void *data; + struct sk_buff *pnext, *save_pktbuf; + int i; + struct brcmf_if *ifp; + struct brcmf_event_msg event; + + brcmf_dbg(TRACE, "Enter\n"); + + save_pktbuf = skb; + + for (i = 0; skb && i < numpkt; i++, skb = pnext) { + + pnext = skb->next; + skb->next = NULL; + + /* Get the protocol, maintain skb around eth_type_trans() + * The main reason for this hack is for the limitation of + * Linux 2.4 where 'eth_type_trans' uses the + * 'net->hard_header_len' + * to perform skb_pull inside vs ETH_HLEN. Since to avoid + * coping of the packet coming from the network stack to add + * BDC, Hardware header etc, during network interface + * registration + * we set the 'net->hard_header_len' to ETH_HLEN + extra space + * required + * for BDC, Hardware header etc. and not just the ETH_HLEN + */ + eth = skb->data; + len = skb->len; + + ifp = drvr_priv->iflist[ifidx]; + if (ifp == NULL) + ifp = drvr_priv->iflist[0]; + + skb->dev = ifp->ndev; + skb->protocol = eth_type_trans(skb, skb->dev); + + if (skb->pkt_type == PACKET_MULTICAST) + drvr_priv->pub.rx_multicast++; + + skb->data = eth; + skb->len = len; + + /* Strip header, count, deliver upward */ + skb_pull(skb, ETH_HLEN); + + /* Process special event packets and then discard them */ + if (ntohs(skb->protocol) == ETH_P_LINK_CTL) + brcmf_host_event(drvr_priv, &ifidx, + skb_mac_header(skb), + &event, &data); + + if (drvr_priv->iflist[ifidx] && + !drvr_priv->iflist[ifidx]->state) + ifp = drvr_priv->iflist[ifidx]; + + if (ifp->ndev) + ifp->ndev->last_rx = jiffies; + + drvr->dstats.rx_bytes += skb->len; + drvr->rx_packets++; /* Local count */ + + if (in_interrupt()) + netif_rx(skb); + else + /* If the receive is not processed inside an ISR, + * the softirqd must be woken explicitly to service + * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled + * by netif_rx_ni(), but in earlier kernels, we need + * to do it manually. + */ + netif_rx_ni(skb); + } +} + +void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success) +{ + uint ifidx; + struct brcmf_info *drvr_priv = drvr->info; + struct ethhdr *eh; + u16 type; + + brcmf_proto_hdrpull(drvr, &ifidx, txp); + + eh = (struct ethhdr *)(txp->data); + type = ntohs(eh->h_proto); + + if (type == ETH_P_PAE) + atomic_dec(&drvr_priv->pend_8021x_cnt); + +} + +static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev) +{ + struct brcmf_info *drvr_priv = *(struct brcmf_info **) + netdev_priv(ndev); + struct brcmf_if *ifp; + int ifidx; + + brcmf_dbg(TRACE, "Enter\n"); + + ifidx = brcmf_net2idx(drvr_priv, ndev); + if (ifidx == BRCMF_BAD_IF) + return NULL; + + ifp = drvr_priv->iflist[ifidx]; + + if (drvr_priv->pub.up) + /* Use the protocol to get dongle stats */ + brcmf_proto_dstats(&drvr_priv->pub); + + /* Copy dongle stats to net device stats */ + ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets; + ifp->stats.tx_packets = drvr_priv->pub.dstats.tx_packets; + ifp->stats.rx_bytes = drvr_priv->pub.dstats.rx_bytes; + ifp->stats.tx_bytes = drvr_priv->pub.dstats.tx_bytes; + ifp->stats.rx_errors = drvr_priv->pub.dstats.rx_errors; + ifp->stats.tx_errors = drvr_priv->pub.dstats.tx_errors; + ifp->stats.rx_dropped = drvr_priv->pub.dstats.rx_dropped; + ifp->stats.tx_dropped = drvr_priv->pub.dstats.tx_dropped; + ifp->stats.multicast = drvr_priv->pub.dstats.multicast; + + return &ifp->stats; +} + +/* Retrieve current toe component enables, which are kept + as a bitmap in toe_ol iovar */ +static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol) +{ + struct brcmf_dcmd dcmd; + __le32 toe_le; + char buf[32]; + int ret; + + memset(&dcmd, 0, sizeof(dcmd)); + + dcmd.cmd = BRCMF_C_GET_VAR; + dcmd.buf = buf; + dcmd.len = (uint) sizeof(buf); + dcmd.set = false; + + strcpy(buf, "toe_ol"); + ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); + if (ret < 0) { + /* Check for older dongle image that doesn't support toe_ol */ + if (ret == -EIO) { + brcmf_dbg(ERROR, "%s: toe not supported by device\n", + brcmf_ifname(&drvr_priv->pub, ifidx)); + return -EOPNOTSUPP; + } + + brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n", + brcmf_ifname(&drvr_priv->pub, ifidx), ret); + return ret; + } + + memcpy(&toe_le, buf, sizeof(u32)); + *toe_ol = le32_to_cpu(toe_le); + return 0; +} + +/* Set current toe component enables in toe_ol iovar, + and set toe global enable iovar */ +static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol) +{ + struct brcmf_dcmd dcmd; + char buf[32]; + int ret; + __le32 toe_le = cpu_to_le32(toe_ol); + + memset(&dcmd, 0, sizeof(dcmd)); + + dcmd.cmd = BRCMF_C_SET_VAR; + dcmd.buf = buf; + dcmd.len = (uint) sizeof(buf); + dcmd.set = true; + + /* Set toe_ol as requested */ + strcpy(buf, "toe_ol"); + memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32)); + + ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); + if (ret < 0) { + brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n", + brcmf_ifname(&drvr_priv->pub, ifidx), ret); + return ret; + } + + /* Enable toe globally only if any components are enabled. */ + toe_le = cpu_to_le32(toe_ol != 0); + + strcpy(buf, "toe"); + memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32)); + + ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len); + if (ret < 0) { + brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n", + brcmf_ifname(&drvr_priv->pub, ifidx), ret); + return ret; + } + + return 0; +} + +static void brcmf_ethtool_get_drvinfo(struct net_device *ndev, + struct ethtool_drvinfo *info) +{ + struct brcmf_info *drvr_priv = *(struct brcmf_info **) + netdev_priv(ndev); + + sprintf(info->driver, KBUILD_MODNAME); + sprintf(info->version, "%lu", drvr_priv->pub.drv_version); + sprintf(info->fw_version, "%s", BCM4329_FW_NAME); + sprintf(info->bus_info, "%s", + dev_name(brcmf_bus_get_device(drvr_priv->pub.bus))); +} + +static struct ethtool_ops brcmf_ethtool_ops = { + .get_drvinfo = brcmf_ethtool_get_drvinfo +}; + +static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr) +{ + struct ethtool_drvinfo info; + char drvname[sizeof(info.driver)]; + u32 cmd; + struct ethtool_value edata; + u32 toe_cmpnt, csum_dir; + int ret; + + brcmf_dbg(TRACE, "Enter\n"); + + /* all ethtool calls start with a cmd word */ + if (copy_from_user(&cmd, uaddr, sizeof(u32))) + return -EFAULT; + + switch (cmd) { + case ETHTOOL_GDRVINFO: + /* Copy out any request driver name */ + if (copy_from_user(&info, uaddr, sizeof(info))) + return -EFAULT; + strncpy(drvname, info.driver, sizeof(info.driver)); + drvname[sizeof(info.driver) - 1] = '\0'; + + /* clear struct for return */ + memset(&info, 0, sizeof(info)); + info.cmd = cmd; + + /* if requested, identify ourselves */ + if (strcmp(drvname, "?dhd") == 0) { + sprintf(info.driver, "dhd"); + strcpy(info.version, BRCMF_VERSION_STR); + } + + /* otherwise, require dongle to be up */ + else if (!drvr_priv->pub.up) { + brcmf_dbg(ERROR, "dongle is not up\n"); + return -ENODEV; + } + + /* finally, report dongle driver type */ + else if (drvr_priv->pub.iswl) + sprintf(info.driver, "wl"); + else + sprintf(info.driver, "xx"); + + sprintf(info.version, "%lu", drvr_priv->pub.drv_version); + if (copy_to_user(uaddr, &info, sizeof(info))) + return -EFAULT; + brcmf_dbg(CTL, "given %*s, returning %s\n", + (int)sizeof(drvname), drvname, info.driver); + break; + + /* Get toe offload components from dongle */ + case ETHTOOL_GRXCSUM: + case ETHTOOL_GTXCSUM: + ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt); + if (ret < 0) + return ret; + + csum_dir = + (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; + + edata.cmd = cmd; + edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; + + if (copy_to_user(uaddr, &edata, sizeof(edata))) + return -EFAULT; + break; + + /* Set toe offload components in dongle */ + case ETHTOOL_SRXCSUM: + case ETHTOOL_STXCSUM: + if (copy_from_user(&edata, uaddr, sizeof(edata))) + return -EFAULT; + + /* Read the current settings, update and write back */ + ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt); + if (ret < 0) + return ret; + + csum_dir = + (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; + + if (edata.data != 0) + toe_cmpnt |= csum_dir; + else + toe_cmpnt &= ~csum_dir; + + ret = brcmf_toe_set(drvr_priv, 0, toe_cmpnt); + if (ret < 0) + return ret; + + /* If setting TX checksum mode, tell Linux the new mode */ + if (cmd == ETHTOOL_STXCSUM) { + if (edata.data) + drvr_priv->iflist[0]->ndev->features |= + NETIF_F_IP_CSUM; + else + drvr_priv->iflist[0]->ndev->features &= + ~NETIF_F_IP_CSUM; + } + + break; + + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr, + int cmd) +{ + struct brcmf_info *drvr_priv = *(struct brcmf_info **) + netdev_priv(ndev); + int ifidx; + + ifidx = brcmf_net2idx(drvr_priv, ndev); + brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd); + + if (ifidx == BRCMF_BAD_IF) + return -1; + + if (cmd == SIOCETHTOOL) + return brcmf_ethtool(drvr_priv, ifr->ifr_data); + + return -EOPNOTSUPP; +} + +/* called only from within this driver. Sends a command to the dongle. */ +s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len) +{ + struct brcmf_dcmd dcmd; + s32 err = 0; + int buflen = 0; + bool is_set_key_cmd; + struct brcmf_info *drvr_priv = *(struct brcmf_info **) + netdev_priv(ndev); + int ifidx; + + memset(&dcmd, 0, sizeof(dcmd)); + dcmd.cmd = cmd; + dcmd.buf = arg; + dcmd.len = len; + + ifidx = brcmf_net2idx(drvr_priv, ndev); + + if (dcmd.buf != NULL) + buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN); + + /* send to dongle (must be up, and wl) */ + if ((drvr_priv->pub.busstate != BRCMF_BUS_DATA)) { + brcmf_dbg(ERROR, "DONGLE_DOWN\n"); + err = -EIO; + goto done; + } + + if (!drvr_priv->pub.iswl) { + err = -EIO; + goto done; + } + + /* + * Intercept BRCMF_C_SET_KEY CMD - serialize M4 send and + * set key CMD to prevent M4 encryption. + */ + is_set_key_cmd = ((dcmd.cmd == BRCMF_C_SET_KEY) || + ((dcmd.cmd == BRCMF_C_SET_VAR) && + !(strncmp("wsec_key", dcmd.buf, 9))) || + ((dcmd.cmd == BRCMF_C_SET_VAR) && + !(strncmp("bsscfg:wsec_key", dcmd.buf, 15)))); + if (is_set_key_cmd) + brcmf_netdev_wait_pend8021x(ndev); + + err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen); + +done: + if (err > 0) + err = 0; + + return err; +} + +static int brcmf_netdev_stop(struct net_device *ndev) +{ + struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev); + + brcmf_dbg(TRACE, "Enter\n"); + brcmf_cfg80211_down(drvr->config); + if (drvr->up == 0) + return 0; + + /* Set state and stop OS transmissions */ + drvr->up = 0; + netif_stop_queue(ndev); + + return 0; +} + +static int brcmf_netdev_open(struct net_device *ndev) +{ + struct brcmf_info *drvr_priv = *(struct brcmf_info **) + netdev_priv(ndev); + u32 toe_ol; + int ifidx = brcmf_net2idx(drvr_priv, ndev); + s32 ret = 0; + + brcmf_dbg(TRACE, "ifidx %d\n", ifidx); + + if (ifidx == 0) { /* do it only for primary eth0 */ + + /* try to bring up bus */ + ret = brcmf_bus_start(&drvr_priv->pub); + if (ret != 0) { + brcmf_dbg(ERROR, "failed with code %d\n", ret); + return -1; + } + atomic_set(&drvr_priv->pend_8021x_cnt, 0); + + memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN); + + /* Get current TOE mode from dongle */ + if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0 + && (toe_ol & TOE_TX_CSUM_OL) != 0) + drvr_priv->iflist[ifidx]->ndev->features |= + NETIF_F_IP_CSUM; + else + drvr_priv->iflist[ifidx]->ndev->features &= + ~NETIF_F_IP_CSUM; + } + /* Allow transmit calls */ + netif_start_queue(ndev); + drvr_priv->pub.up = 1; + if (brcmf_cfg80211_up(drvr_priv->pub.config)) { + brcmf_dbg(ERROR, "failed to bring up cfg80211\n"); + return -1; + } + + return ret; +} + +int +brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev, + char *name, u8 *mac_addr, u32 flags, u8 bssidx) +{ + struct brcmf_if *ifp; + int ret = 0, err = 0; + + brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev); + + ifp = drvr_priv->iflist[ifidx]; + if (!ifp) { + ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC); + if (!ifp) + return -ENOMEM; + } + + memset(ifp, 0, sizeof(struct brcmf_if)); + ifp->info = drvr_priv; + drvr_priv->iflist[ifidx] = ifp; + if (mac_addr != NULL) + memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN); + + if (ndev == NULL) { + ifp->state = BRCMF_E_IF_ADD; + ifp->idx = ifidx; + /* + * Delete the existing interface before overwriting it + * in case we missed the BRCMF_E_IF_DEL event. + */ + if (ifp->ndev != NULL) { + brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n", + ifp->ndev->name); + netif_stop_queue(ifp->ndev); + unregister_netdev(ifp->ndev); + free_netdev(ifp->ndev); + } + + /* Allocate netdev, including space for private structure */ + ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", + ether_setup); + if (!ifp->ndev) { + brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); + ret = -ENOMEM; + } + + if (ret == 0) { + memcpy(netdev_priv(ifp->ndev), &drvr_priv, + sizeof(drvr_priv)); + err = brcmf_net_attach(&drvr_priv->pub, ifp->idx); + if (err != 0) { + brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n", + err); + ret = -EOPNOTSUPP; + } else { + brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n", + current->pid, ifp->ndev->name); + ifp->state = 0; + } + } + + if (ret < 0) { + if (ifp->ndev) + free_netdev(ifp->ndev); + + drvr_priv->iflist[ifp->idx] = NULL; + kfree(ifp); + } + } else + ifp->ndev = ndev; + + return 0; +} + +void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx) +{ + struct brcmf_if *ifp; + + brcmf_dbg(TRACE, "idx %d\n", ifidx); + + ifp = drvr_priv->iflist[ifidx]; + if (!ifp) { + brcmf_dbg(ERROR, "Null interface\n"); + return; + } + + ifp->state = BRCMF_E_IF_DEL; + ifp->idx = ifidx; + if (ifp->ndev != NULL) { + netif_stop_queue(ifp->ndev); + unregister_netdev(ifp->ndev); + free_netdev(ifp->ndev); + drvr_priv->iflist[ifidx] = NULL; + kfree(ifp); + } +} + +struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen) +{ + struct brcmf_info *drvr_priv = NULL; + struct net_device *ndev; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Allocate netdev, including space for private structure */ + ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup); + if (!ndev) { + brcmf_dbg(ERROR, "OOM - alloc_netdev\n"); + goto fail; + } + + /* Allocate primary brcmf_info */ + drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC); + if (!drvr_priv) + goto fail; + + /* + * Save the brcmf_info into the priv + */ + memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); + + if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) == + BRCMF_BAD_IF) + goto fail; + + ndev->netdev_ops = NULL; + mutex_init(&drvr_priv->proto_block); + + /* Link to info module */ + drvr_priv->pub.info = drvr_priv; + + /* Link to bus module */ + drvr_priv->pub.bus = bus; + drvr_priv->pub.hdrlen = bus_hdrlen; + + /* Attach and link in the protocol */ + if (brcmf_proto_attach(&drvr_priv->pub) != 0) { + brcmf_dbg(ERROR, "brcmf_prot_attach failed\n"); + goto fail; + } + + /* Attach and link in the cfg80211 */ + drvr_priv->pub.config = + brcmf_cfg80211_attach(ndev, + brcmf_bus_get_device(bus), + &drvr_priv->pub); + if (drvr_priv->pub.config == NULL) { + brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n"); + goto fail; + } + + INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address); + INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list); + + /* + * Save the brcmf_info into the priv + */ + memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv)); + + return &drvr_priv->pub; + +fail: + if (ndev) + free_netdev(ndev); + if (drvr_priv) + brcmf_detach(&drvr_priv->pub); + + return NULL; +} + +int brcmf_bus_start(struct brcmf_pub *drvr) +{ + int ret = -1; + struct brcmf_info *drvr_priv = drvr->info; + /* Room for "event_msgs" + '\0' + bitvec */ + char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; + + brcmf_dbg(TRACE, "\n"); + + /* Bring up the bus */ + ret = brcmf_sdbrcm_bus_init(&drvr_priv->pub); + if (ret != 0) { + brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret); + return ret; + } + + /* If bus is not ready, can't come up */ + if (drvr_priv->pub.busstate != BRCMF_BUS_DATA) { + brcmf_dbg(ERROR, "failed bus is not ready\n"); + return -ENODEV; + } + + brcmf_c_mkiovar("event_msgs", drvr->eventmask, BRCMF_EVENTING_MASK_LEN, + iovbuf, sizeof(iovbuf)); + brcmf_proto_cdc_query_dcmd(drvr, 0, BRCMF_C_GET_VAR, iovbuf, + sizeof(iovbuf)); + memcpy(drvr->eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); + + setbit(drvr->eventmask, BRCMF_E_SET_SSID); + setbit(drvr->eventmask, BRCMF_E_PRUNE); + setbit(drvr->eventmask, BRCMF_E_AUTH); + setbit(drvr->eventmask, BRCMF_E_REASSOC); + setbit(drvr->eventmask, BRCMF_E_REASSOC_IND); + setbit(drvr->eventmask, BRCMF_E_DEAUTH_IND); + setbit(drvr->eventmask, BRCMF_E_DISASSOC_IND); + setbit(drvr->eventmask, BRCMF_E_DISASSOC); + setbit(drvr->eventmask, BRCMF_E_JOIN); + setbit(drvr->eventmask, BRCMF_E_ASSOC_IND); + setbit(drvr->eventmask, BRCMF_E_PSK_SUP); + setbit(drvr->eventmask, BRCMF_E_LINK); + setbit(drvr->eventmask, BRCMF_E_NDIS_LINK); + setbit(drvr->eventmask, BRCMF_E_MIC_ERROR); + setbit(drvr->eventmask, BRCMF_E_PMKID_CACHE); + setbit(drvr->eventmask, BRCMF_E_TXFAIL); + setbit(drvr->eventmask, BRCMF_E_JOIN_START); + setbit(drvr->eventmask, BRCMF_E_SCAN_COMPLETE); + +/* enable dongle roaming event */ + + drvr->pktfilter_count = 1; + /* Setup filter to allow only unicast */ + drvr->pktfilter[0] = "100 0 0 0 0x01 0x00"; + + /* Bus is ready, do any protocol initialization */ + ret = brcmf_proto_init(&drvr_priv->pub); + if (ret < 0) + return ret; + + return 0; +} + +static struct net_device_ops brcmf_netdev_ops_pri = { + .ndo_open = brcmf_netdev_open, + .ndo_stop = brcmf_netdev_stop, + .ndo_get_stats = brcmf_netdev_get_stats, + .ndo_do_ioctl = brcmf_netdev_ioctl_entry, + .ndo_start_xmit = brcmf_netdev_start_xmit, + .ndo_set_mac_address = brcmf_netdev_set_mac_address, + .ndo_set_rx_mode = brcmf_netdev_set_multicast_list +}; + +int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx) +{ + struct brcmf_info *drvr_priv = drvr->info; + struct net_device *ndev; + u8 temp_addr[ETH_ALEN] = { + 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33}; + + brcmf_dbg(TRACE, "ifidx %d\n", ifidx); + + ndev = drvr_priv->iflist[ifidx]->ndev; + ndev->netdev_ops = &brcmf_netdev_ops_pri; + + /* + * We have to use the primary MAC for virtual interfaces + */ + if (ifidx != 0) { + /* for virtual interfaces use the primary MAC */ + memcpy(temp_addr, drvr_priv->pub.mac, ETH_ALEN); + + } + + if (ifidx == 1) { + brcmf_dbg(TRACE, "ACCESS POINT MAC:\n"); + /* ACCESSPOINT INTERFACE CASE */ + temp_addr[0] |= 0X02; /* set bit 2 , + - Locally Administered address */ + + } + ndev->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen; + ndev->ethtool_ops = &brcmf_ethtool_ops; + + drvr_priv->pub.rxsz = ndev->mtu + ndev->hard_header_len + + drvr_priv->pub.hdrlen; + + memcpy(ndev->dev_addr, temp_addr, ETH_ALEN); + + if (register_netdev(ndev) != 0) { + brcmf_dbg(ERROR, "couldn't register the net device\n"); + goto fail; + } + + brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); + + return 0; + +fail: + ndev->netdev_ops = NULL; + return -EBADE; +} + +static void brcmf_bus_detach(struct brcmf_pub *drvr) +{ + struct brcmf_info *drvr_priv; + + brcmf_dbg(TRACE, "Enter\n"); + + if (drvr) { + drvr_priv = drvr->info; + if (drvr_priv) { + /* Stop the protocol module */ + brcmf_proto_stop(&drvr_priv->pub); + + /* Stop the bus module */ + brcmf_sdbrcm_bus_stop(drvr_priv->pub.bus); + } + } +} + +void brcmf_detach(struct brcmf_pub *drvr) +{ + struct brcmf_info *drvr_priv; + + brcmf_dbg(TRACE, "Enter\n"); + + if (drvr) { + drvr_priv = drvr->info; + if (drvr_priv) { + struct brcmf_if *ifp; + int i; + + for (i = 1; i < BRCMF_MAX_IFS; i++) + if (drvr_priv->iflist[i]) + brcmf_del_if(drvr_priv, i); + + ifp = drvr_priv->iflist[0]; + if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) { + rtnl_lock(); + brcmf_netdev_stop(ifp->ndev); + rtnl_unlock(); + unregister_netdev(ifp->ndev); + } + + cancel_work_sync(&drvr_priv->setmacaddr_work); + cancel_work_sync(&drvr_priv->multicast_work); + + brcmf_bus_detach(drvr); + + if (drvr->prot) + brcmf_proto_detach(drvr); + + brcmf_cfg80211_detach(drvr->config); + + free_netdev(ifp->ndev); + kfree(ifp); + kfree(drvr_priv); + } + } +} + +static void __exit brcmf_module_cleanup(void) +{ + brcmf_dbg(TRACE, "Enter\n"); + + brcmf_bus_unregister(); +} + +static int __init brcmf_module_init(void) +{ + int error; + + brcmf_dbg(TRACE, "Enter\n"); + + error = brcmf_bus_register(); + + if (error) { + brcmf_dbg(ERROR, "brcmf_bus_register failed\n"); + goto failed; + } + return 0; + +failed: + return -EINVAL; +} + +module_init(brcmf_module_init); +module_exit(brcmf_module_cleanup); + +int brcmf_os_proto_block(struct brcmf_pub *drvr) +{ + struct brcmf_info *drvr_priv = drvr->info; + + if (drvr_priv) { + mutex_lock(&drvr_priv->proto_block); + return 1; + } + return 0; +} + +int brcmf_os_proto_unblock(struct brcmf_pub *drvr) +{ + struct brcmf_info *drvr_priv = drvr->info; + + if (drvr_priv) { + mutex_unlock(&drvr_priv->proto_block); + return 1; + } + + return 0; +} + +static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv) +{ + return atomic_read(&drvr_priv->pend_8021x_cnt); +} + +#define MAX_WAIT_FOR_8021X_TX 10 + +int brcmf_netdev_wait_pend8021x(struct net_device *ndev) +{ + struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev); + int timeout = 10 * HZ / 1000; + int ntimes = MAX_WAIT_FOR_8021X_TX; + int pend = brcmf_get_pend_8021x_cnt(drvr_priv); + + while (ntimes && pend) { + if (pend) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(timeout); + set_current_state(TASK_RUNNING); + ntimes--; + } + pend = brcmf_get_pend_8021x_cnt(drvr_priv); + } + return pend; +} + +#ifdef BCMDBG +int brcmf_write_to_file(struct brcmf_pub *drvr, const u8 *buf, int size) +{ + int ret = 0; + struct file *fp; + mm_segment_t old_fs; + loff_t pos = 0; + + /* change to KERNEL_DS address limit */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + + /* open file to write */ + fp = filp_open("/tmp/mem_dump", O_WRONLY | O_CREAT, 0640); + if (!fp) { + brcmf_dbg(ERROR, "open file error\n"); + ret = -1; + goto exit; + } + + /* Write buf to file */ + fp->f_op->write(fp, (char __user *)buf, size, &pos); + +exit: + /* free buf before return */ + kfree(buf); + /* close file before return */ + if (fp) + filp_close(fp, current->files); + /* restore previous address limit */ + set_fs(old_fs); + + return ret; +} +#endif /* BCMDBG */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h new file mode 100644 index 000000000000..4ee1ea846f6d --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCMF_PROTO_H_ +#define _BRCMF_PROTO_H_ + +/* + * Exported from the brcmf protocol module (brcmf_cdc) + */ + +/* Linkage, sets prot link and updates hdrlen in pub */ +extern int brcmf_proto_attach(struct brcmf_pub *drvr); + +/* Unlink, frees allocated protocol memory (including brcmf_proto) */ +extern void brcmf_proto_detach(struct brcmf_pub *drvr); + +/* Initialize protocol: sync w/dongle state. + * Sets dongle media info (iswl, drv_version, mac address). + */ +extern int brcmf_proto_init(struct brcmf_pub *drvr); + +/* Stop protocol: sync w/dongle state. */ +extern void brcmf_proto_stop(struct brcmf_pub *drvr); + +/* Add any protocol-specific data header. + * Caller must reserve prot_hdrlen prepend space. + */ +extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, + struct sk_buff *txp); + +/* Remove any protocol-specific data header. */ +extern int brcmf_proto_hdrpull(struct brcmf_pub *, int *ifidx, + struct sk_buff *rxp); + +/* Use protocol to issue command to dongle */ +extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, + struct brcmf_dcmd *dcmd, int len); + +/* Update local copy of dongle statistics */ +extern void brcmf_proto_dstats(struct brcmf_pub *drvr); + +extern int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr); + +extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, + uint cmd, void *buf, uint len); + +#endif /* _BRCMF_PROTO_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c new file mode 100644 index 000000000000..313b8bf592d1 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -0,0 +1,4591 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/types.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/printk.h> +#include <linux/pci_ids.h> +#include <linux/netdevice.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/card.h> +#include <linux/semaphore.h> +#include <linux/firmware.h> +#include <linux/module.h> +#include <asm/unaligned.h> +#include <defs.h> +#include <brcmu_wifi.h> +#include <brcmu_utils.h> +#include <brcm_hw_ids.h> +#include <soc.h> +#include "sdio_host.h" + +#define DCMD_RESP_TIMEOUT 2000 /* In milli second */ + +#ifdef BCMDBG + +#define BRCMF_TRAP_INFO_SIZE 80 + +#define CBUF_LEN (128) + +struct rte_log_le { + __le32 buf; /* Can't be pointer on (64-bit) hosts */ + __le32 buf_size; + __le32 idx; + char *_buf_compat; /* Redundant pointer for backward compat. */ +}; + +struct rte_console { + /* Virtual UART + * When there is no UART (e.g. Quickturn), + * the host should write a complete + * input line directly into cbuf and then write + * the length into vcons_in. + * This may also be used when there is a real UART + * (at risk of conflicting with + * the real UART). vcons_out is currently unused. + */ + uint vcons_in; + uint vcons_out; + + /* Output (logging) buffer + * Console output is written to a ring buffer log_buf at index log_idx. + * The host may read the output when it sees log_idx advance. + * Output will be lost if the output wraps around faster than the host + * polls. + */ + struct rte_log_le log_le; + + /* Console input line buffer + * Characters are read one at a time into cbuf + * until <CR> is received, then + * the buffer is processed as a command line. + * Also used for virtual UART. + */ + uint cbuf_idx; + char cbuf[CBUF_LEN]; +}; + +#endif /* BCMDBG */ +#include <chipcommon.h> + +#include "dhd.h" +#include "dhd_bus.h" +#include "dhd_proto.h" +#include "dhd_dbg.h" +#include <bcmchip.h> + +#define TXQLEN 2048 /* bulk tx queue length */ +#define TXHI (TXQLEN - 256) /* turn on flow control above TXHI */ +#define TXLOW (TXHI - 256) /* turn off flow control below TXLOW */ +#define PRIOMASK 7 + +#define TXRETRIES 2 /* # of retries for tx frames */ + +#define BRCMF_RXBOUND 50 /* Default for max rx frames in + one scheduling */ + +#define BRCMF_TXBOUND 20 /* Default for max tx frames in + one scheduling */ + +#define BRCMF_TXMINMAX 1 /* Max tx frames if rx still pending */ + +#define MEMBLOCK 2048 /* Block size used for downloading + of dongle image */ +#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold + biggest possible glom */ + +#define BRCMF_FIRSTREAD (1 << 6) + + +/* SBSDIO_DEVICE_CTL */ + +/* 1: device will assert busy signal when receiving CMD53 */ +#define SBSDIO_DEVCTL_SETBUSY 0x01 +/* 1: assertion of sdio interrupt is synchronous to the sdio clock */ +#define SBSDIO_DEVCTL_SPI_INTR_SYNC 0x02 +/* 1: mask all interrupts to host except the chipActive (rev 8) */ +#define SBSDIO_DEVCTL_CA_INT_ONLY 0x04 +/* 1: isolate internal sdio signals, put external pads in tri-state; requires + * sdio bus power cycle to clear (rev 9) */ +#define SBSDIO_DEVCTL_PADS_ISO 0x08 +/* Force SD->SB reset mapping (rev 11) */ +#define SBSDIO_DEVCTL_SB_RST_CTL 0x30 +/* Determined by CoreControl bit */ +#define SBSDIO_DEVCTL_RST_CORECTL 0x00 +/* Force backplane reset */ +#define SBSDIO_DEVCTL_RST_BPRESET 0x10 +/* Force no backplane reset */ +#define SBSDIO_DEVCTL_RST_NOBPRESET 0x20 + +/* SBSDIO_FUNC1_CHIPCLKCSR */ + +/* Force ALP request to backplane */ +#define SBSDIO_FORCE_ALP 0x01 +/* Force HT request to backplane */ +#define SBSDIO_FORCE_HT 0x02 +/* Force ILP request to backplane */ +#define SBSDIO_FORCE_ILP 0x04 +/* Make ALP ready (power up xtal) */ +#define SBSDIO_ALP_AVAIL_REQ 0x08 +/* Make HT ready (power up PLL) */ +#define SBSDIO_HT_AVAIL_REQ 0x10 +/* Squelch clock requests from HW */ +#define SBSDIO_FORCE_HW_CLKREQ_OFF 0x20 +/* Status: ALP is ready */ +#define SBSDIO_ALP_AVAIL 0x40 +/* Status: HT is ready */ +#define SBSDIO_HT_AVAIL 0x80 + +#define SBSDIO_AVBITS (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL) +#define SBSDIO_ALPAV(regval) ((regval) & SBSDIO_AVBITS) +#define SBSDIO_HTAV(regval) (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS) +#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval)) + +#define SBSDIO_CLKAV(regval, alponly) \ + (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval))) + +/* direct(mapped) cis space */ + +/* MAPPED common CIS address */ +#define SBSDIO_CIS_BASE_COMMON 0x1000 +/* maximum bytes in one CIS */ +#define SBSDIO_CIS_SIZE_LIMIT 0x200 +/* cis offset addr is < 17 bits */ +#define SBSDIO_CIS_OFT_ADDR_MASK 0x1FFFF + +/* manfid tuple length, include tuple, link bytes */ +#define SBSDIO_CIS_MANFID_TUPLE_LEN 6 + +/* intstatus */ +#define I_SMB_SW0 (1 << 0) /* To SB Mail S/W interrupt 0 */ +#define I_SMB_SW1 (1 << 1) /* To SB Mail S/W interrupt 1 */ +#define I_SMB_SW2 (1 << 2) /* To SB Mail S/W interrupt 2 */ +#define I_SMB_SW3 (1 << 3) /* To SB Mail S/W interrupt 3 */ +#define I_SMB_SW_MASK 0x0000000f /* To SB Mail S/W interrupts mask */ +#define I_SMB_SW_SHIFT 0 /* To SB Mail S/W interrupts shift */ +#define I_HMB_SW0 (1 << 4) /* To Host Mail S/W interrupt 0 */ +#define I_HMB_SW1 (1 << 5) /* To Host Mail S/W interrupt 1 */ +#define I_HMB_SW2 (1 << 6) /* To Host Mail S/W interrupt 2 */ +#define I_HMB_SW3 (1 << 7) /* To Host Mail S/W interrupt 3 */ +#define I_HMB_SW_MASK 0x000000f0 /* To Host Mail S/W interrupts mask */ +#define I_HMB_SW_SHIFT 4 /* To Host Mail S/W interrupts shift */ +#define I_WR_OOSYNC (1 << 8) /* Write Frame Out Of Sync */ +#define I_RD_OOSYNC (1 << 9) /* Read Frame Out Of Sync */ +#define I_PC (1 << 10) /* descriptor error */ +#define I_PD (1 << 11) /* data error */ +#define I_DE (1 << 12) /* Descriptor protocol Error */ +#define I_RU (1 << 13) /* Receive descriptor Underflow */ +#define I_RO (1 << 14) /* Receive fifo Overflow */ +#define I_XU (1 << 15) /* Transmit fifo Underflow */ +#define I_RI (1 << 16) /* Receive Interrupt */ +#define I_BUSPWR (1 << 17) /* SDIO Bus Power Change (rev 9) */ +#define I_XMTDATA_AVAIL (1 << 23) /* bits in fifo */ +#define I_XI (1 << 24) /* Transmit Interrupt */ +#define I_RF_TERM (1 << 25) /* Read Frame Terminate */ +#define I_WF_TERM (1 << 26) /* Write Frame Terminate */ +#define I_PCMCIA_XU (1 << 27) /* PCMCIA Transmit FIFO Underflow */ +#define I_SBINT (1 << 28) /* sbintstatus Interrupt */ +#define I_CHIPACTIVE (1 << 29) /* chip from doze to active state */ +#define I_SRESET (1 << 30) /* CCCR RES interrupt */ +#define I_IOE2 (1U << 31) /* CCCR IOE2 Bit Changed */ +#define I_ERRORS (I_PC | I_PD | I_DE | I_RU | I_RO | I_XU) +#define I_DMA (I_RI | I_XI | I_ERRORS) + +/* corecontrol */ +#define CC_CISRDY (1 << 0) /* CIS Ready */ +#define CC_BPRESEN (1 << 1) /* CCCR RES signal */ +#define CC_F2RDY (1 << 2) /* set CCCR IOR2 bit */ +#define CC_CLRPADSISO (1 << 3) /* clear SDIO pads isolation */ +#define CC_XMTDATAAVAIL_MODE (1 << 4) +#define CC_XMTDATAAVAIL_CTRL (1 << 5) + +/* SDA_FRAMECTRL */ +#define SFC_RF_TERM (1 << 0) /* Read Frame Terminate */ +#define SFC_WF_TERM (1 << 1) /* Write Frame Terminate */ +#define SFC_CRC4WOOS (1 << 2) /* CRC error for write out of sync */ +#define SFC_ABORTALL (1 << 3) /* Abort all in-progress frames */ + +/* HW frame tag */ +#define SDPCM_FRAMETAG_LEN 4 /* 2 bytes len, 2 bytes check val */ + +/* Total length of frame header for dongle protocol */ +#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) +#define SDPCM_RESERVE (SDPCM_HDRLEN + BRCMF_SDALIGN) + +/* + * Software allocation of To SB Mailbox resources + */ + +/* tosbmailbox bits corresponding to intstatus bits */ +#define SMB_NAK (1 << 0) /* Frame NAK */ +#define SMB_INT_ACK (1 << 1) /* Host Interrupt ACK */ +#define SMB_USE_OOB (1 << 2) /* Use OOB Wakeup */ +#define SMB_DEV_INT (1 << 3) /* Miscellaneous Interrupt */ + +/* tosbmailboxdata */ +#define SMB_DATA_VERSION_SHIFT 16 /* host protocol version */ + +/* + * Software allocation of To Host Mailbox resources + */ + +/* intstatus bits */ +#define I_HMB_FC_STATE I_HMB_SW0 /* Flow Control State */ +#define I_HMB_FC_CHANGE I_HMB_SW1 /* Flow Control State Changed */ +#define I_HMB_FRAME_IND I_HMB_SW2 /* Frame Indication */ +#define I_HMB_HOST_INT I_HMB_SW3 /* Miscellaneous Interrupt */ + +/* tohostmailboxdata */ +#define HMB_DATA_NAKHANDLED 1 /* retransmit NAK'd frame */ +#define HMB_DATA_DEVREADY 2 /* talk to host after enable */ +#define HMB_DATA_FC 4 /* per prio flowcontrol update flag */ +#define HMB_DATA_FWREADY 8 /* fw ready for protocol activity */ + +#define HMB_DATA_FCDATA_MASK 0xff000000 +#define HMB_DATA_FCDATA_SHIFT 24 + +#define HMB_DATA_VERSION_MASK 0x00ff0000 +#define HMB_DATA_VERSION_SHIFT 16 + +/* + * Software-defined protocol header + */ + +/* Current protocol version */ +#define SDPCM_PROT_VERSION 4 + +/* SW frame header */ +#define SDPCM_PACKET_SEQUENCE(p) (((u8 *)p)[0] & 0xff) + +#define SDPCM_CHANNEL_MASK 0x00000f00 +#define SDPCM_CHANNEL_SHIFT 8 +#define SDPCM_PACKET_CHANNEL(p) (((u8 *)p)[1] & 0x0f) + +#define SDPCM_NEXTLEN_OFFSET 2 + +/* Data Offset from SOF (HW Tag, SW Tag, Pad) */ +#define SDPCM_DOFFSET_OFFSET 3 /* Data Offset */ +#define SDPCM_DOFFSET_VALUE(p) (((u8 *)p)[SDPCM_DOFFSET_OFFSET] & 0xff) +#define SDPCM_DOFFSET_MASK 0xff000000 +#define SDPCM_DOFFSET_SHIFT 24 +#define SDPCM_FCMASK_OFFSET 4 /* Flow control */ +#define SDPCM_FCMASK_VALUE(p) (((u8 *)p)[SDPCM_FCMASK_OFFSET] & 0xff) +#define SDPCM_WINDOW_OFFSET 5 /* Credit based fc */ +#define SDPCM_WINDOW_VALUE(p) (((u8 *)p)[SDPCM_WINDOW_OFFSET] & 0xff) + +#define SDPCM_SWHEADER_LEN 8 /* SW header is 64 bits */ + +/* logical channel numbers */ +#define SDPCM_CONTROL_CHANNEL 0 /* Control channel Id */ +#define SDPCM_EVENT_CHANNEL 1 /* Asyc Event Indication Channel Id */ +#define SDPCM_DATA_CHANNEL 2 /* Data Xmit/Recv Channel Id */ +#define SDPCM_GLOM_CHANNEL 3 /* For coalesced packets */ +#define SDPCM_TEST_CHANNEL 15 /* Reserved for test/debug packets */ + +#define SDPCM_SEQUENCE_WRAP 256 /* wrap-around val for 8bit frame seq */ + +#define SDPCM_GLOMDESC(p) (((u8 *)p)[1] & 0x80) + +/* + * Shared structure between dongle and the host. + * The structure contains pointers to trap or assert information. + */ +#define SDPCM_SHARED_VERSION 0x0002 +#define SDPCM_SHARED_VERSION_MASK 0x00FF +#define SDPCM_SHARED_ASSERT_BUILT 0x0100 +#define SDPCM_SHARED_ASSERT 0x0200 +#define SDPCM_SHARED_TRAP 0x0400 + +/* Space for header read, limit for data packets */ +#define MAX_HDR_READ (1 << 6) +#define MAX_RX_DATASZ 2048 + +/* Maximum milliseconds to wait for F2 to come up */ +#define BRCMF_WAIT_F2RDY 3000 + +/* Bump up limit on waiting for HT to account for first startup; + * if the image is doing a CRC calculation before programming the PMU + * for HT availability, it could take a couple hundred ms more, so + * max out at a 1 second (1000000us). + */ +#undef PMU_MAX_TRANSITION_DLY +#define PMU_MAX_TRANSITION_DLY 1000000 + +/* Value for ChipClockCSR during initial setup */ +#define BRCMF_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | \ + SBSDIO_ALP_AVAIL_REQ) + +/* Flags for SDH calls */ +#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) + +/* sbimstate */ +#define SBIM_IBE 0x20000 /* inbanderror */ +#define SBIM_TO 0x40000 /* timeout */ +#define SBIM_BY 0x01800000 /* busy (sonics >= 2.3) */ +#define SBIM_RJ 0x02000000 /* reject (sonics >= 2.3) */ + +/* sbtmstatelow */ + +/* reset */ +#define SBTML_RESET 0x0001 +/* reject field */ +#define SBTML_REJ_MASK 0x0006 +/* reject */ +#define SBTML_REJ 0x0002 +/* temporary reject, for error recovery */ +#define SBTML_TMPREJ 0x0004 + +/* Shift to locate the SI control flags in sbtml */ +#define SBTML_SICF_SHIFT 16 + +/* sbtmstatehigh */ +#define SBTMH_SERR 0x0001 /* serror */ +#define SBTMH_INT 0x0002 /* interrupt */ +#define SBTMH_BUSY 0x0004 /* busy */ +#define SBTMH_TO 0x0020 /* timeout (sonics >= 2.3) */ + +/* Shift to locate the SI status flags in sbtmh */ +#define SBTMH_SISF_SHIFT 16 + +/* sbidlow */ +#define SBIDL_INIT 0x80 /* initiator */ + +/* sbidhigh */ +#define SBIDH_RC_MASK 0x000f /* revision code */ +#define SBIDH_RCE_MASK 0x7000 /* revision code extension field */ +#define SBIDH_RCE_SHIFT 8 +#define SBCOREREV(sbidh) \ + ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \ + ((sbidh) & SBIDH_RC_MASK)) +#define SBIDH_CC_MASK 0x8ff0 /* core code */ +#define SBIDH_CC_SHIFT 4 +#define SBIDH_VC_MASK 0xffff0000 /* vendor code */ +#define SBIDH_VC_SHIFT 16 + +/* + * Conversion of 802.1D priority to precedence level + */ +static uint prio2prec(u32 prio) +{ + return (prio == PRIO_8021D_NONE || prio == PRIO_8021D_BE) ? + (prio^2) : prio; +} + +/* + * Core reg address translation. + * Both macro's returns a 32 bits byte address on the backplane bus. + */ +#define CORE_CC_REG(base, field) \ + (base + offsetof(struct chipcregs, field)) +#define CORE_BUS_REG(base, field) \ + (base + offsetof(struct sdpcmd_regs, field)) +#define CORE_SB(base, field) \ + (base + SBCONFIGOFF + offsetof(struct sbconfig, field)) + +/* core registers */ +struct sdpcmd_regs { + u32 corecontrol; /* 0x00, rev8 */ + u32 corestatus; /* rev8 */ + u32 PAD[1]; + u32 biststatus; /* rev8 */ + + /* PCMCIA access */ + u16 pcmciamesportaladdr; /* 0x010, rev8 */ + u16 PAD[1]; + u16 pcmciamesportalmask; /* rev8 */ + u16 PAD[1]; + u16 pcmciawrframebc; /* rev8 */ + u16 PAD[1]; + u16 pcmciaunderflowtimer; /* rev8 */ + u16 PAD[1]; + + /* interrupt */ + u32 intstatus; /* 0x020, rev8 */ + u32 hostintmask; /* rev8 */ + u32 intmask; /* rev8 */ + u32 sbintstatus; /* rev8 */ + u32 sbintmask; /* rev8 */ + u32 funcintmask; /* rev4 */ + u32 PAD[2]; + u32 tosbmailbox; /* 0x040, rev8 */ + u32 tohostmailbox; /* rev8 */ + u32 tosbmailboxdata; /* rev8 */ + u32 tohostmailboxdata; /* rev8 */ + + /* synchronized access to registers in SDIO clock domain */ + u32 sdioaccess; /* 0x050, rev8 */ + u32 PAD[3]; + + /* PCMCIA frame control */ + u8 pcmciaframectrl; /* 0x060, rev8 */ + u8 PAD[3]; + u8 pcmciawatermark; /* rev8 */ + u8 PAD[155]; + + /* interrupt batching control */ + u32 intrcvlazy; /* 0x100, rev8 */ + u32 PAD[3]; + + /* counters */ + u32 cmd52rd; /* 0x110, rev8 */ + u32 cmd52wr; /* rev8 */ + u32 cmd53rd; /* rev8 */ + u32 cmd53wr; /* rev8 */ + u32 abort; /* rev8 */ + u32 datacrcerror; /* rev8 */ + u32 rdoutofsync; /* rev8 */ + u32 wroutofsync; /* rev8 */ + u32 writebusy; /* rev8 */ + u32 readwait; /* rev8 */ + u32 readterm; /* rev8 */ + u32 writeterm; /* rev8 */ + u32 PAD[40]; + u32 clockctlstatus; /* rev8 */ + u32 PAD[7]; + + u32 PAD[128]; /* DMA engines */ + + /* SDIO/PCMCIA CIS region */ + char cis[512]; /* 0x400-0x5ff, rev6 */ + + /* PCMCIA function control registers */ + char pcmciafcr[256]; /* 0x600-6ff, rev6 */ + u16 PAD[55]; + + /* PCMCIA backplane access */ + u16 backplanecsr; /* 0x76E, rev6 */ + u16 backplaneaddr0; /* rev6 */ + u16 backplaneaddr1; /* rev6 */ + u16 backplaneaddr2; /* rev6 */ + u16 backplaneaddr3; /* rev6 */ + u16 backplanedata0; /* rev6 */ + u16 backplanedata1; /* rev6 */ + u16 backplanedata2; /* rev6 */ + u16 backplanedata3; /* rev6 */ + u16 PAD[31]; + + /* sprom "size" & "blank" info */ + u16 spromstatus; /* 0x7BE, rev2 */ + u32 PAD[464]; + + u16 PAD[0x80]; +}; + +#ifdef BCMDBG +/* Device console log buffer state */ +struct brcmf_console { + uint count; /* Poll interval msec counter */ + uint log_addr; /* Log struct address (fixed) */ + struct rte_log_le log_le; /* Log struct (host copy) */ + uint bufsize; /* Size of log buffer */ + u8 *buf; /* Log buffer (host copy) */ + uint last; /* Last buffer read index */ +}; +#endif /* BCMDBG */ + +struct sdpcm_shared { + u32 flags; + u32 trap_addr; + u32 assert_exp_addr; + u32 assert_file_addr; + u32 assert_line; + u32 console_addr; /* Address of struct rte_console */ + u32 msgtrace_addr; + u8 tag[32]; +}; + +struct sdpcm_shared_le { + __le32 flags; + __le32 trap_addr; + __le32 assert_exp_addr; + __le32 assert_file_addr; + __le32 assert_line; + __le32 console_addr; /* Address of struct rte_console */ + __le32 msgtrace_addr; + u8 tag[32]; +}; + + +/* misc chip info needed by some of the routines */ +struct chip_info { + u32 chip; + u32 chiprev; + u32 cccorebase; + u32 ccrev; + u32 cccaps; + u32 buscorebase; /* 32 bits backplane bus address */ + u32 buscorerev; + u32 buscoretype; + u32 ramcorebase; + u32 armcorebase; + u32 pmurev; + u32 ramsize; +}; + +/* Private data for SDIO bus interaction */ +struct brcmf_bus { + struct brcmf_pub *drvr; + + struct brcmf_sdio_dev *sdiodev; /* sdio device handler */ + struct chip_info *ci; /* Chip info struct */ + char *vars; /* Variables (from CIS and/or other) */ + uint varsz; /* Size of variables buffer */ + + u32 ramsize; /* Size of RAM in SOCRAM (bytes) */ + + u32 hostintmask; /* Copy of Host Interrupt Mask */ + u32 intstatus; /* Intstatus bits (events) pending */ + bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ + bool fcstate; /* State of dongle flow-control */ + + uint blocksize; /* Block size of SDIO transfers */ + uint roundup; /* Max roundup limit */ + + struct pktq txq; /* Queue length used for flow-control */ + u8 flowcontrol; /* per prio flow control bitmask */ + u8 tx_seq; /* Transmit sequence number (next) */ + u8 tx_max; /* Maximum transmit sequence allowed */ + + u8 hdrbuf[MAX_HDR_READ + BRCMF_SDALIGN]; + u8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ + u16 nextlen; /* Next Read Len from last header */ + u8 rx_seq; /* Receive sequence number (expected) */ + bool rxskip; /* Skip receive (awaiting NAK ACK) */ + + uint rxbound; /* Rx frames to read before resched */ + uint txbound; /* Tx frames to send before resched */ + uint txminmax; + + struct sk_buff *glomd; /* Packet containing glomming descriptor */ + struct sk_buff *glom; /* Packet chain for glommed superframe */ + uint glomerr; /* Glom packet read errors */ + + u8 *rxbuf; /* Buffer for receiving control packets */ + uint rxblen; /* Allocated length of rxbuf */ + u8 *rxctl; /* Aligned pointer into rxbuf */ + u8 *databuf; /* Buffer for receiving big glom packet */ + u8 *dataptr; /* Aligned pointer into databuf */ + uint rxlen; /* Length of valid data in buffer */ + + u8 sdpcm_ver; /* Bus protocol reported by dongle */ + + bool intr; /* Use interrupts */ + bool poll; /* Use polling */ + bool ipend; /* Device interrupt is pending */ + uint intrcount; /* Count of device interrupt callbacks */ + uint lastintrs; /* Count as of last watchdog timer */ + uint spurious; /* Count of spurious interrupts */ + uint pollrate; /* Ticks between device polls */ + uint polltick; /* Tick counter */ + uint pollcnt; /* Count of active polls */ + +#ifdef BCMDBG + uint console_interval; + struct brcmf_console console; /* Console output polling support */ + uint console_addr; /* Console address from shared struct */ +#endif /* BCMDBG */ + + uint regfails; /* Count of R_REG failures */ + + uint clkstate; /* State of sd and backplane clock(s) */ + bool activity; /* Activity flag for clock down */ + s32 idletime; /* Control for activity timeout */ + s32 idlecount; /* Activity timeout counter */ + s32 idleclock; /* How to set bus driver when idle */ + s32 sd_rxchain; + bool use_rxchain; /* If brcmf should use PKT chains */ + bool sleeping; /* Is SDIO bus sleeping? */ + bool rxflow_mode; /* Rx flow control mode */ + bool rxflow; /* Is rx flow control on */ + bool alp_only; /* Don't use HT clock (ALP only) */ +/* Field to decide if rx of control frames happen in rxbuf or lb-pool */ + bool usebufpool; + + /* Some additional counters */ + uint tx_sderrs; /* Count of tx attempts with sd errors */ + uint fcqueued; /* Tx packets that got queued */ + uint rxrtx; /* Count of rtx requests (NAK to dongle) */ + uint rx_toolong; /* Receive frames too long to receive */ + uint rxc_errors; /* SDIO errors when reading control frames */ + uint rx_hdrfail; /* SDIO errors on header reads */ + uint rx_badhdr; /* Bad received headers (roosync?) */ + uint rx_badseq; /* Mismatched rx sequence number */ + uint fc_rcvd; /* Number of flow-control events received */ + uint fc_xoff; /* Number which turned on flow-control */ + uint fc_xon; /* Number which turned off flow-control */ + uint rxglomfail; /* Failed deglom attempts */ + uint rxglomframes; /* Number of glom frames (superframes) */ + uint rxglompkts; /* Number of packets from glom frames */ + uint f2rxhdrs; /* Number of header reads */ + uint f2rxdata; /* Number of frame data reads */ + uint f2txdata; /* Number of f2 frame writes */ + uint f1regdata; /* Number of f1 register accesses */ + + u8 *ctrl_frame_buf; + u32 ctrl_frame_len; + bool ctrl_frame_stat; + + spinlock_t txqlock; + wait_queue_head_t ctrl_wait; + wait_queue_head_t dcmd_resp_wait; + + struct timer_list timer; + struct completion watchdog_wait; + struct task_struct *watchdog_tsk; + bool wd_timer_valid; + uint save_ms; + + struct task_struct *dpc_tsk; + struct completion dpc_wait; + + struct semaphore sdsem; + + const char *fw_name; + const struct firmware *firmware; + const char *nv_name; + u32 fw_ptr; +}; + +struct sbconfig { + u32 PAD[2]; + u32 sbipsflag; /* initiator port ocp slave flag */ + u32 PAD[3]; + u32 sbtpsflag; /* target port ocp slave flag */ + u32 PAD[11]; + u32 sbtmerrloga; /* (sonics >= 2.3) */ + u32 PAD; + u32 sbtmerrlog; /* (sonics >= 2.3) */ + u32 PAD[3]; + u32 sbadmatch3; /* address match3 */ + u32 PAD; + u32 sbadmatch2; /* address match2 */ + u32 PAD; + u32 sbadmatch1; /* address match1 */ + u32 PAD[7]; + u32 sbimstate; /* initiator agent state */ + u32 sbintvec; /* interrupt mask */ + u32 sbtmstatelow; /* target state */ + u32 sbtmstatehigh; /* target state */ + u32 sbbwa0; /* bandwidth allocation table0 */ + u32 PAD; + u32 sbimconfiglow; /* initiator configuration */ + u32 sbimconfighigh; /* initiator configuration */ + u32 sbadmatch0; /* address match0 */ + u32 PAD; + u32 sbtmconfiglow; /* target configuration */ + u32 sbtmconfighigh; /* target configuration */ + u32 sbbconfig; /* broadcast configuration */ + u32 PAD; + u32 sbbstate; /* broadcast state */ + u32 PAD[3]; + u32 sbactcnfg; /* activate configuration */ + u32 PAD[3]; + u32 sbflagst; /* current sbflags */ + u32 PAD[3]; + u32 sbidlow; /* identification */ + u32 sbidhigh; /* identification */ +}; + +/* clkstate */ +#define CLK_NONE 0 +#define CLK_SDONLY 1 +#define CLK_PENDING 2 /* Not used yet */ +#define CLK_AVAIL 3 + +#ifdef BCMDBG +static int qcount[NUMPRIO]; +static int tx_packets[NUMPRIO]; +#endif /* BCMDBG */ + +#define SDIO_DRIVE_STRENGTH 6 /* in milliamps */ + +#define RETRYCHAN(chan) ((chan) == SDPCM_EVENT_CHANNEL) + +/* Retry count for register access failures */ +static const uint retry_limit = 2; + +/* Limit on rounding up frames */ +static const uint max_roundup = 512; + +#define ALIGNMENT 4 + +static void pkt_align(struct sk_buff *p, int len, int align) +{ + uint datalign; + datalign = (unsigned long)(p->data); + datalign = roundup(datalign, (align)) - datalign; + if (datalign) + skb_pull(p, datalign); + __skb_trim(p, len); +} + +/* To check if there's window offered */ +static bool data_ok(struct brcmf_bus *bus) +{ + return (u8)(bus->tx_max - bus->tx_seq) != 0 && + ((u8)(bus->tx_max - bus->tx_seq) & 0x80) == 0; +} + +/* + * Reads a register in the SDIO hardware block. This block occupies a series of + * adresses on the 32 bit backplane bus. + */ +static void +r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) +{ + *retryvar = 0; + do { + *regvar = brcmf_sdcard_reg_read(bus->sdiodev, + bus->ci->buscorebase + reg_offset, sizeof(u32)); + } while (brcmf_sdcard_regfail(bus->sdiodev) && + (++(*retryvar) <= retry_limit)); + if (*retryvar) { + bus->regfails += (*retryvar-1); + if (*retryvar > retry_limit) { + brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset); + *regvar = 0; + } + } +} + +static void +w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar) +{ + *retryvar = 0; + do { + brcmf_sdcard_reg_write(bus->sdiodev, + bus->ci->buscorebase + reg_offset, + sizeof(u32), regval); + } while (brcmf_sdcard_regfail(bus->sdiodev) && + (++(*retryvar) <= retry_limit)); + if (*retryvar) { + bus->regfails += (*retryvar-1); + if (*retryvar > retry_limit) + brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n", + reg_offset); + } +} + +#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) + +#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) + +/* Packet free applicable unconditionally for sdio and sdspi. + * Conditional if bufpool was present for gspi bus. + */ +static void brcmf_sdbrcm_pktfree2(struct brcmf_bus *bus, struct sk_buff *pkt) +{ + if (bus->usebufpool) + brcmu_pkt_buf_free_skb(pkt); +} + +/* Turn backplane clock on or off */ +static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok) +{ + int err; + u8 clkctl, clkreq, devctl; + unsigned long timeout; + + brcmf_dbg(TRACE, "Enter\n"); + + clkctl = 0; + + if (on) { + /* Request HT Avail */ + clkreq = + bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; + + if ((bus->ci->chip == BCM4329_CHIP_ID) + && (bus->ci->chiprev == 0)) + clkreq |= SBSDIO_FORCE_ALP; + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); + if (err) { + brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); + return -EBADE; + } + + if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID) + && (bus->ci->buscorerev == 9))) { + u32 dummy, retries; + r_sdreg32(bus, &dummy, + offsetof(struct sdpcmd_regs, clockctlstatus), + &retries); + } + + /* Check current status */ + clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (err) { + brcmf_dbg(ERROR, "HT Avail read error: %d\n", err); + return -EBADE; + } + + /* Go to pending and await interrupt if appropriate */ + if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { + /* Allow only clock-available interrupt */ + devctl = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, &err); + if (err) { + brcmf_dbg(ERROR, "Devctl error setting CA: %d\n", + err); + return -EBADE; + } + + devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, devctl, &err); + brcmf_dbg(INFO, "CLKCTL: set PENDING\n"); + bus->clkstate = CLK_PENDING; + + return 0; + } else if (bus->clkstate == CLK_PENDING) { + /* Cancel CA-only interrupt filter */ + devctl = + brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, &err); + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, devctl, &err); + } + + /* Otherwise, wait here (polling) for HT Avail */ + timeout = jiffies + + msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000); + while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { + clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, + &err); + if (time_after(jiffies, timeout)) + break; + else + usleep_range(5000, 10000); + } + if (err) { + brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); + return -EBADE; + } + if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { + brcmf_dbg(ERROR, "HT Avail timeout (%d): clkctl 0x%02x\n", + PMU_MAX_TRANSITION_DLY, clkctl); + return -EBADE; + } + + /* Mark clock available */ + bus->clkstate = CLK_AVAIL; + brcmf_dbg(INFO, "CLKCTL: turned ON\n"); + +#if defined(BCMDBG) + if (bus->alp_only != true) { + if (SBSDIO_ALPONLY(clkctl)) + brcmf_dbg(ERROR, "HT Clock should be on\n"); + } +#endif /* defined (BCMDBG) */ + + bus->activity = true; + } else { + clkreq = 0; + + if (bus->clkstate == CLK_PENDING) { + /* Cancel CA-only interrupt filter */ + devctl = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, &err); + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, devctl, &err); + } + + bus->clkstate = CLK_SDONLY; + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); + brcmf_dbg(INFO, "CLKCTL: turned OFF\n"); + if (err) { + brcmf_dbg(ERROR, "Failed access turning clock off: %d\n", + err); + return -EBADE; + } + } + return 0; +} + +/* Change idle/active SD state */ +static int brcmf_sdbrcm_sdclk(struct brcmf_bus *bus, bool on) +{ + brcmf_dbg(TRACE, "Enter\n"); + + if (on) + bus->clkstate = CLK_SDONLY; + else + bus->clkstate = CLK_NONE; + + return 0; +} + +/* Transition SD and backplane clock readiness */ +static int brcmf_sdbrcm_clkctl(struct brcmf_bus *bus, uint target, bool pendok) +{ +#ifdef BCMDBG + uint oldstate = bus->clkstate; +#endif /* BCMDBG */ + + brcmf_dbg(TRACE, "Enter\n"); + + /* Early exit if we're already there */ + if (bus->clkstate == target) { + if (target == CLK_AVAIL) { + brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); + bus->activity = true; + } + return 0; + } + + switch (target) { + case CLK_AVAIL: + /* Make sure SD clock is available */ + if (bus->clkstate == CLK_NONE) + brcmf_sdbrcm_sdclk(bus, true); + /* Now request HT Avail on the backplane */ + brcmf_sdbrcm_htclk(bus, true, pendok); + brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); + bus->activity = true; + break; + + case CLK_SDONLY: + /* Remove HT request, or bring up SD clock */ + if (bus->clkstate == CLK_NONE) + brcmf_sdbrcm_sdclk(bus, true); + else if (bus->clkstate == CLK_AVAIL) + brcmf_sdbrcm_htclk(bus, false, false); + else + brcmf_dbg(ERROR, "request for %d -> %d\n", + bus->clkstate, target); + brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); + break; + + case CLK_NONE: + /* Make sure to remove HT request */ + if (bus->clkstate == CLK_AVAIL) + brcmf_sdbrcm_htclk(bus, false, false); + /* Now remove the SD clock */ + brcmf_sdbrcm_sdclk(bus, false); + brcmf_sdbrcm_wd_timer(bus, 0); + break; + } +#ifdef BCMDBG + brcmf_dbg(INFO, "%d -> %d\n", oldstate, bus->clkstate); +#endif /* BCMDBG */ + + return 0; +} + +static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep) +{ + uint retries = 0; + + brcmf_dbg(INFO, "request %s (currently %s)\n", + sleep ? "SLEEP" : "WAKE", + bus->sleeping ? "SLEEP" : "WAKE"); + + /* Done if we're already in the requested state */ + if (sleep == bus->sleeping) + return 0; + + /* Going to sleep: set the alarm and turn off the lights... */ + if (sleep) { + /* Don't sleep if something is pending */ + if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq)) + return -EBUSY; + + /* Make sure the controller has the bus up */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + + /* Tell device to start using OOB wakeup */ + w_sdreg32(bus, SMB_USE_OOB, + offsetof(struct sdpcmd_regs, tosbmailbox), &retries); + if (retries > retry_limit) + brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); + + /* Turn off our contribution to the HT clock request */ + brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, + SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); + + /* Isolate the bus */ + if (bus->ci->chip != BCM4329_CHIP_ID) { + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, + SBSDIO_DEVCTL_PADS_ISO, NULL); + } + + /* Change state */ + bus->sleeping = true; + + } else { + /* Waking up: bus power up is ok, set local state */ + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + + /* Force pad isolation off if possible + (in case power never toggled) */ + if ((bus->ci->buscoretype == PCMCIA_CORE_ID) + && (bus->ci->buscorerev >= 10)) + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, 0, NULL); + + /* Make sure the controller has the bus up */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + + /* Send misc interrupt to indicate OOB not needed */ + w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata), + &retries); + if (retries <= retry_limit) + w_sdreg32(bus, SMB_DEV_INT, + offsetof(struct sdpcmd_regs, tosbmailbox), + &retries); + + if (retries > retry_limit) + brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); + + /* Make sure we have SD bus access */ + brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); + + /* Change state */ + bus->sleeping = false; + } + + return 0; +} + +static void bus_wake(struct brcmf_bus *bus) +{ + if (bus->sleeping) + brcmf_sdbrcm_bussleep(bus, false); +} + +static u32 brcmf_sdbrcm_hostmail(struct brcmf_bus *bus) +{ + u32 intstatus = 0; + u32 hmb_data; + u8 fcbits; + uint retries = 0; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Read mailbox data and ack that we did so */ + r_sdreg32(bus, &hmb_data, + offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries); + + if (retries <= retry_limit) + w_sdreg32(bus, SMB_INT_ACK, + offsetof(struct sdpcmd_regs, tosbmailbox), &retries); + bus->f1regdata += 2; + + /* Dongle recomposed rx frames, accept them again */ + if (hmb_data & HMB_DATA_NAKHANDLED) { + brcmf_dbg(INFO, "Dongle reports NAK handled, expect rtx of %d\n", + bus->rx_seq); + if (!bus->rxskip) + brcmf_dbg(ERROR, "unexpected NAKHANDLED!\n"); + + bus->rxskip = false; + intstatus |= I_HMB_FRAME_IND; + } + + /* + * DEVREADY does not occur with gSPI. + */ + if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { + bus->sdpcm_ver = + (hmb_data & HMB_DATA_VERSION_MASK) >> + HMB_DATA_VERSION_SHIFT; + if (bus->sdpcm_ver != SDPCM_PROT_VERSION) + brcmf_dbg(ERROR, "Version mismatch, dongle reports %d, " + "expecting %d\n", + bus->sdpcm_ver, SDPCM_PROT_VERSION); + else + brcmf_dbg(INFO, "Dongle ready, protocol version %d\n", + bus->sdpcm_ver); + } + + /* + * Flow Control has been moved into the RX headers and this out of band + * method isn't used any more. + * remaining backward compatible with older dongles. + */ + if (hmb_data & HMB_DATA_FC) { + fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> + HMB_DATA_FCDATA_SHIFT; + + if (fcbits & ~bus->flowcontrol) + bus->fc_xoff++; + + if (bus->flowcontrol & ~fcbits) + bus->fc_xon++; + + bus->fc_rcvd++; + bus->flowcontrol = fcbits; + } + + /* Shouldn't be any others */ + if (hmb_data & ~(HMB_DATA_DEVREADY | + HMB_DATA_NAKHANDLED | + HMB_DATA_FC | + HMB_DATA_FWREADY | + HMB_DATA_FCDATA_MASK | HMB_DATA_VERSION_MASK)) + brcmf_dbg(ERROR, "Unknown mailbox data content: 0x%02x\n", + hmb_data); + + return intstatus; +} + +static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx) +{ + uint retries = 0; + u16 lastrbc; + u8 hi, lo; + int err; + + brcmf_dbg(ERROR, "%sterminate frame%s\n", + abort ? "abort command, " : "", + rtx ? ", send NAK" : ""); + + if (abort) + brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_FRAMECTRL, + SFC_RF_TERM, &err); + bus->f1regdata++; + + /* Wait until the packet has been flushed (device/FIFO stable) */ + for (lastrbc = retries = 0xffff; retries > 0; retries--) { + hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_RFRAMEBCHI, NULL); + lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_RFRAMEBCLO, NULL); + bus->f1regdata += 2; + + if ((hi == 0) && (lo == 0)) + break; + + if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { + brcmf_dbg(ERROR, "count growing: last 0x%04x now 0x%04x\n", + lastrbc, (hi << 8) + lo); + } + lastrbc = (hi << 8) + lo; + } + + if (!retries) + brcmf_dbg(ERROR, "count never zeroed: last 0x%04x\n", lastrbc); + else + brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries); + + if (rtx) { + bus->rxrtx++; + w_sdreg32(bus, SMB_NAK, + offsetof(struct sdpcmd_regs, tosbmailbox), &retries); + + bus->f1regdata++; + if (retries <= retry_limit) + bus->rxskip = true; + } + + /* Clear partial in any case */ + bus->nextlen = 0; + + /* If we can't reach the device, signal failure */ + if (err || brcmf_sdcard_regfail(bus->sdiodev)) + bus->drvr->busstate = BRCMF_BUS_DOWN; +} + +static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq) +{ + u16 dlen, totlen; + u8 *dptr, num = 0; + + u16 sublen, check; + struct sk_buff *pfirst, *plast, *pnext, *save_pfirst; + + int errcode; + u8 chan, seq, doff, sfdoff; + u8 txmax; + + int ifidx = 0; + bool usechain = bus->use_rxchain; + + /* If packets, issue read(s) and send up packet chain */ + /* Return sequence numbers consumed? */ + + brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom); + + /* If there's a descriptor, generate the packet chain */ + if (bus->glomd) { + pfirst = plast = pnext = NULL; + dlen = (u16) (bus->glomd->len); + dptr = bus->glomd->data; + if (!dlen || (dlen & 1)) { + brcmf_dbg(ERROR, "bad glomd len(%d), ignore descriptor\n", + dlen); + dlen = 0; + } + + for (totlen = num = 0; dlen; num++) { + /* Get (and move past) next length */ + sublen = get_unaligned_le16(dptr); + dlen -= sizeof(u16); + dptr += sizeof(u16); + if ((sublen < SDPCM_HDRLEN) || + ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { + brcmf_dbg(ERROR, "descriptor len %d bad: %d\n", + num, sublen); + pnext = NULL; + break; + } + if (sublen % BRCMF_SDALIGN) { + brcmf_dbg(ERROR, "sublen %d not multiple of %d\n", + sublen, BRCMF_SDALIGN); + usechain = false; + } + totlen += sublen; + + /* For last frame, adjust read len so total + is a block multiple */ + if (!dlen) { + sublen += + (roundup(totlen, bus->blocksize) - totlen); + totlen = roundup(totlen, bus->blocksize); + } + + /* Allocate/chain packet for next subframe */ + pnext = brcmu_pkt_buf_get_skb(sublen + BRCMF_SDALIGN); + if (pnext == NULL) { + brcmf_dbg(ERROR, "bcm_pkt_buf_get_skb failed, num %d len %d\n", + num, sublen); + break; + } + if (!pfirst) { + pfirst = plast = pnext; + } else { + plast->next = pnext; + plast = pnext; + } + + /* Adhere to start alignment requirements */ + pkt_align(pnext, sublen, BRCMF_SDALIGN); + } + + /* If all allocations succeeded, save packet chain + in bus structure */ + if (pnext) { + brcmf_dbg(GLOM, "allocated %d-byte packet chain for %d subframes\n", + totlen, num); + if (BRCMF_GLOM_ON() && bus->nextlen && + totlen != bus->nextlen) { + brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n", + bus->nextlen, totlen, rxseq); + } + bus->glom = pfirst; + pfirst = pnext = NULL; + } else { + if (pfirst) + brcmu_pkt_buf_free_skb(pfirst); + bus->glom = NULL; + num = 0; + } + + /* Done with descriptor packet */ + brcmu_pkt_buf_free_skb(bus->glomd); + bus->glomd = NULL; + bus->nextlen = 0; + } + + /* Ok -- either we just generated a packet chain, + or had one from before */ + if (bus->glom) { + if (BRCMF_GLOM_ON()) { + brcmf_dbg(GLOM, "try superframe read, packet chain:\n"); + for (pnext = bus->glom; pnext; pnext = pnext->next) { + brcmf_dbg(GLOM, " %p: %p len 0x%04x (%d)\n", + pnext, (u8 *) (pnext->data), + pnext->len, pnext->len); + } + } + + pfirst = bus->glom; + dlen = (u16) brcmu_pkttotlen(pfirst); + + /* Do an SDIO read for the superframe. Configurable iovar to + * read directly into the chained packet, or allocate a large + * packet and and copy into the chain. + */ + if (usechain) { + errcode = brcmf_sdcard_recv_buf(bus->sdiodev, + bus->sdiodev->sbwad, + SDIO_FUNC_2, + F2SYNC, (u8 *) pfirst->data, dlen, + pfirst); + } else if (bus->dataptr) { + errcode = brcmf_sdcard_recv_buf(bus->sdiodev, + bus->sdiodev->sbwad, + SDIO_FUNC_2, + F2SYNC, bus->dataptr, dlen, + NULL); + sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen, + bus->dataptr); + if (sublen != dlen) { + brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n", + dlen, sublen); + errcode = -1; + } + pnext = NULL; + } else { + brcmf_dbg(ERROR, "COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", + dlen); + errcode = -1; + } + bus->f2rxdata++; + + /* On failure, kill the superframe, allow a couple retries */ + if (errcode < 0) { + brcmf_dbg(ERROR, "glom read of %d bytes failed: %d\n", + dlen, errcode); + bus->drvr->rx_errors++; + + if (bus->glomerr++ < 3) { + brcmf_sdbrcm_rxfail(bus, true, true); + } else { + bus->glomerr = 0; + brcmf_sdbrcm_rxfail(bus, true, false); + brcmu_pkt_buf_free_skb(bus->glom); + bus->rxglomfail++; + bus->glom = NULL; + } + return 0; + } +#ifdef BCMDBG + if (BRCMF_GLOM_ON()) { + printk(KERN_DEBUG "SUPERFRAME:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + pfirst->data, min_t(int, pfirst->len, 48)); + } +#endif + + /* Validate the superframe header */ + dptr = (u8 *) (pfirst->data); + sublen = get_unaligned_le16(dptr); + check = get_unaligned_le16(dptr + sizeof(u16)); + + chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); + seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); + bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; + if ((bus->nextlen << 4) > MAX_RX_DATASZ) { + brcmf_dbg(INFO, "nextlen too large (%d) seq %d\n", + bus->nextlen, seq); + bus->nextlen = 0; + } + doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); + txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); + + errcode = 0; + if ((u16)~(sublen ^ check)) { + brcmf_dbg(ERROR, "(superframe): HW hdr error: len/check 0x%04x/0x%04x\n", + sublen, check); + errcode = -1; + } else if (roundup(sublen, bus->blocksize) != dlen) { + brcmf_dbg(ERROR, "(superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", + sublen, roundup(sublen, bus->blocksize), + dlen); + errcode = -1; + } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != + SDPCM_GLOM_CHANNEL) { + brcmf_dbg(ERROR, "(superframe): bad channel %d\n", + SDPCM_PACKET_CHANNEL( + &dptr[SDPCM_FRAMETAG_LEN])); + errcode = -1; + } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { + brcmf_dbg(ERROR, "(superframe): got 2nd descriptor?\n"); + errcode = -1; + } else if ((doff < SDPCM_HDRLEN) || + (doff > (pfirst->len - SDPCM_HDRLEN))) { + brcmf_dbg(ERROR, "(superframe): Bad data offset %d: HW %d pkt %d min %d\n", + doff, sublen, pfirst->len, SDPCM_HDRLEN); + errcode = -1; + } + + /* Check sequence number of superframe SW header */ + if (rxseq != seq) { + brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n", + seq, rxseq); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((u8) (txmax - bus->tx_seq) > 0x40) { + brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", + txmax, bus->tx_seq); + txmax = bus->tx_seq + 2; + } + bus->tx_max = txmax; + + /* Remove superframe header, remember offset */ + skb_pull(pfirst, doff); + sfdoff = doff; + + /* Validate all the subframe headers */ + for (num = 0, pnext = pfirst; pnext && !errcode; + num++, pnext = pnext->next) { + dptr = (u8 *) (pnext->data); + dlen = (u16) (pnext->len); + sublen = get_unaligned_le16(dptr); + check = get_unaligned_le16(dptr + sizeof(u16)); + chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); + doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); +#ifdef BCMDBG + if (BRCMF_GLOM_ON()) { + printk(KERN_DEBUG "subframe:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + dptr, 32); + } +#endif + + if ((u16)~(sublen ^ check)) { + brcmf_dbg(ERROR, "(subframe %d): HW hdr error: len/check 0x%04x/0x%04x\n", + num, sublen, check); + errcode = -1; + } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { + brcmf_dbg(ERROR, "(subframe %d): length mismatch: len 0x%04x, expect 0x%04x\n", + num, sublen, dlen); + errcode = -1; + } else if ((chan != SDPCM_DATA_CHANNEL) && + (chan != SDPCM_EVENT_CHANNEL)) { + brcmf_dbg(ERROR, "(subframe %d): bad channel %d\n", + num, chan); + errcode = -1; + } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { + brcmf_dbg(ERROR, "(subframe %d): Bad data offset %d: HW %d min %d\n", + num, doff, sublen, SDPCM_HDRLEN); + errcode = -1; + } + } + + if (errcode) { + /* Terminate frame on error, request + a couple retries */ + if (bus->glomerr++ < 3) { + /* Restore superframe header space */ + skb_push(pfirst, sfdoff); + brcmf_sdbrcm_rxfail(bus, true, true); + } else { + bus->glomerr = 0; + brcmf_sdbrcm_rxfail(bus, true, false); + brcmu_pkt_buf_free_skb(bus->glom); + bus->rxglomfail++; + bus->glom = NULL; + } + bus->nextlen = 0; + return 0; + } + + /* Basic SD framing looks ok - process each packet (header) */ + save_pfirst = pfirst; + bus->glom = NULL; + plast = NULL; + + for (num = 0; pfirst; rxseq++, pfirst = pnext) { + pnext = pfirst->next; + pfirst->next = NULL; + + dptr = (u8 *) (pfirst->data); + sublen = get_unaligned_le16(dptr); + chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); + seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); + doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); + + brcmf_dbg(GLOM, "Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", + num, pfirst, pfirst->data, + pfirst->len, sublen, chan, seq); + + /* precondition: chan == SDPCM_DATA_CHANNEL || + chan == SDPCM_EVENT_CHANNEL */ + + if (rxseq != seq) { + brcmf_dbg(GLOM, "rx_seq %d, expected %d\n", + seq, rxseq); + bus->rx_badseq++; + rxseq = seq; + } +#ifdef BCMDBG + if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { + printk(KERN_DEBUG "Rx Subframe Data:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + dptr, dlen); + } +#endif + + __skb_trim(pfirst, sublen); + skb_pull(pfirst, doff); + + if (pfirst->len == 0) { + brcmu_pkt_buf_free_skb(pfirst); + if (plast) + plast->next = pnext; + else + save_pfirst = pnext; + + continue; + } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, + pfirst) != 0) { + brcmf_dbg(ERROR, "rx protocol error\n"); + bus->drvr->rx_errors++; + brcmu_pkt_buf_free_skb(pfirst); + if (plast) + plast->next = pnext; + else + save_pfirst = pnext; + + continue; + } + + /* this packet will go up, link back into + chain and count it */ + pfirst->next = pnext; + plast = pfirst; + num++; + +#ifdef BCMDBG + if (BRCMF_GLOM_ON()) { + brcmf_dbg(GLOM, "subframe %d to stack, %p (%p/%d) nxt/lnk %p/%p\n", + num, pfirst, pfirst->data, + pfirst->len, pfirst->next, + pfirst->prev); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + pfirst->data, + min_t(int, pfirst->len, 32)); + } +#endif /* BCMDBG */ + } + if (num) { + up(&bus->sdsem); + brcmf_rx_frame(bus->drvr, ifidx, save_pfirst, num); + down(&bus->sdsem); + } + + bus->rxglomframes++; + bus->rxglompkts += num; + } + return num; +} + +static int brcmf_sdbrcm_dcmd_resp_wait(struct brcmf_bus *bus, uint *condition, + bool *pending) +{ + DECLARE_WAITQUEUE(wait, current); + int timeout = msecs_to_jiffies(DCMD_RESP_TIMEOUT); + + /* Wait until control frame is available */ + add_wait_queue(&bus->dcmd_resp_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (!(*condition) && (!signal_pending(current) && timeout)) + timeout = schedule_timeout(timeout); + + if (signal_pending(current)) + *pending = true; + + set_current_state(TASK_RUNNING); + remove_wait_queue(&bus->dcmd_resp_wait, &wait); + + return timeout; +} + +static int brcmf_sdbrcm_dcmd_resp_wake(struct brcmf_bus *bus) +{ + if (waitqueue_active(&bus->dcmd_resp_wait)) + wake_up_interruptible(&bus->dcmd_resp_wait); + + return 0; +} +static void +brcmf_sdbrcm_read_control(struct brcmf_bus *bus, u8 *hdr, uint len, uint doff) +{ + uint rdlen, pad; + + int sdret; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Set rxctl for frame (w/optional alignment) */ + bus->rxctl = bus->rxbuf; + bus->rxctl += BRCMF_FIRSTREAD; + pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN); + if (pad) + bus->rxctl += (BRCMF_SDALIGN - pad); + bus->rxctl -= BRCMF_FIRSTREAD; + + /* Copy the already-read portion over */ + memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD); + if (len <= BRCMF_FIRSTREAD) + goto gotpkt; + + /* Raise rdlen to next SDIO block to avoid tail command */ + rdlen = len - BRCMF_FIRSTREAD; + if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { + pad = bus->blocksize - (rdlen % bus->blocksize); + if ((pad <= bus->roundup) && (pad < bus->blocksize) && + ((len + pad) < bus->drvr->maxctl)) + rdlen += pad; + } else if (rdlen % BRCMF_SDALIGN) { + rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (rdlen & (ALIGNMENT - 1)) + rdlen = roundup(rdlen, ALIGNMENT); + + /* Drop if the read is too big or it exceeds our maximum */ + if ((rdlen + BRCMF_FIRSTREAD) > bus->drvr->maxctl) { + brcmf_dbg(ERROR, "%d-byte control read exceeds %d-byte buffer\n", + rdlen, bus->drvr->maxctl); + bus->drvr->rx_errors++; + brcmf_sdbrcm_rxfail(bus, false, false); + goto done; + } + + if ((len - doff) > bus->drvr->maxctl) { + brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", + len, len - doff, bus->drvr->maxctl); + bus->drvr->rx_errors++; + bus->rx_toolong++; + brcmf_sdbrcm_rxfail(bus, false, false); + goto done; + } + + /* Read remainder of frame body into the rxctl buffer */ + sdret = brcmf_sdcard_recv_buf(bus->sdiodev, + bus->sdiodev->sbwad, + SDIO_FUNC_2, + F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen, + NULL); + bus->f2rxdata++; + + /* Control frame failures need retransmission */ + if (sdret < 0) { + brcmf_dbg(ERROR, "read %d control bytes failed: %d\n", + rdlen, sdret); + bus->rxc_errors++; + brcmf_sdbrcm_rxfail(bus, true, true); + goto done; + } + +gotpkt: + +#ifdef BCMDBG + if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { + printk(KERN_DEBUG "RxCtrl:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, bus->rxctl, len); + } +#endif + + /* Point to valid data and indicate its length */ + bus->rxctl += doff; + bus->rxlen = len - doff; + +done: + /* Awake any waiters */ + brcmf_sdbrcm_dcmd_resp_wake(bus); +} + +/* Pad read to blocksize for efficiency */ +static void brcmf_pad(struct brcmf_bus *bus, u16 *pad, u16 *rdlen) +{ + if (bus->roundup && bus->blocksize && *rdlen > bus->blocksize) { + *pad = bus->blocksize - (*rdlen % bus->blocksize); + if (*pad <= bus->roundup && *pad < bus->blocksize && + *rdlen + *pad + BRCMF_FIRSTREAD < MAX_RX_DATASZ) + *rdlen += *pad; + } else if (*rdlen % BRCMF_SDALIGN) { + *rdlen += BRCMF_SDALIGN - (*rdlen % BRCMF_SDALIGN); + } +} + +static void +brcmf_alloc_pkt_and_read(struct brcmf_bus *bus, u16 rdlen, + struct sk_buff **pkt, u8 **rxbuf) +{ + int sdret; /* Return code from calls */ + + *pkt = brcmu_pkt_buf_get_skb(rdlen + BRCMF_SDALIGN); + if (*pkt == NULL) + return; + + pkt_align(*pkt, rdlen, BRCMF_SDALIGN); + *rxbuf = (u8 *) ((*pkt)->data); + /* Read the entire frame */ + sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, + *rxbuf, rdlen, *pkt); + bus->f2rxdata++; + + if (sdret < 0) { + brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n", + rdlen, sdret); + brcmu_pkt_buf_free_skb(*pkt); + bus->drvr->rx_errors++; + /* Force retry w/normal header read. + * Don't attempt NAK for + * gSPI + */ + brcmf_sdbrcm_rxfail(bus, true, true); + *pkt = NULL; + } +} + +/* Checks the header */ +static int +brcmf_check_rxbuf(struct brcmf_bus *bus, struct sk_buff *pkt, u8 *rxbuf, + u8 rxseq, u16 nextlen, u16 *len) +{ + u16 check; + bool len_consistent; /* Result of comparing readahead len and + len from hw-hdr */ + + memcpy(bus->rxhdr, rxbuf, SDPCM_HDRLEN); + + /* Extract hardware header fields */ + *len = get_unaligned_le16(bus->rxhdr); + check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); + + /* All zeros means readahead info was bad */ + if (!(*len | check)) { + brcmf_dbg(INFO, "(nextlen): read zeros in HW header???\n"); + goto fail; + } + + /* Validate check bytes */ + if ((u16)~(*len ^ check)) { + brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n", + nextlen, *len, check); + bus->rx_badhdr++; + brcmf_sdbrcm_rxfail(bus, false, false); + goto fail; + } + + /* Validate frame length */ + if (*len < SDPCM_HDRLEN) { + brcmf_dbg(ERROR, "(nextlen): HW hdr length invalid: %d\n", + *len); + goto fail; + } + + /* Check for consistency with readahead info */ + len_consistent = (nextlen != (roundup(*len, 16) >> 4)); + if (len_consistent) { + /* Mismatch, force retry w/normal + header (may be >4K) */ + brcmf_dbg(ERROR, "(nextlen): mismatch, nextlen %d len %d rnd %d; expected rxseq %d\n", + nextlen, *len, roundup(*len, 16), + rxseq); + brcmf_sdbrcm_rxfail(bus, true, true); + goto fail; + } + + return 0; + +fail: + brcmf_sdbrcm_pktfree2(bus, pkt); + return -EINVAL; +} + +/* Return true if there may be more frames to read */ +static uint +brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished) +{ + u16 len, check; /* Extracted hardware header fields */ + u8 chan, seq, doff; /* Extracted software header fields */ + u8 fcbits; /* Extracted fcbits from software header */ + + struct sk_buff *pkt; /* Packet for event or data frames */ + u16 pad; /* Number of pad bytes to read */ + u16 rdlen; /* Total number of bytes to read */ + u8 rxseq; /* Next sequence number to expect */ + uint rxleft = 0; /* Remaining number of frames allowed */ + int sdret; /* Return code from calls */ + u8 txmax; /* Maximum tx sequence offered */ + u8 *rxbuf; + int ifidx = 0; + uint rxcount = 0; /* Total frames read */ + + brcmf_dbg(TRACE, "Enter\n"); + + /* Not finished unless we encounter no more frames indication */ + *finished = false; + + for (rxseq = bus->rx_seq, rxleft = maxframes; + !bus->rxskip && rxleft && bus->drvr->busstate != BRCMF_BUS_DOWN; + rxseq++, rxleft--) { + + /* Handle glomming separately */ + if (bus->glom || bus->glomd) { + u8 cnt; + brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n", + bus->glomd, bus->glom); + cnt = brcmf_sdbrcm_rxglom(bus, rxseq); + brcmf_dbg(GLOM, "rxglom returned %d\n", cnt); + rxseq += cnt - 1; + rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; + continue; + } + + /* Try doing single read if we can */ + if (bus->nextlen) { + u16 nextlen = bus->nextlen; + bus->nextlen = 0; + + rdlen = len = nextlen << 4; + brcmf_pad(bus, &pad, &rdlen); + + /* + * After the frame is received we have to + * distinguish whether it is data + * or non-data frame. + */ + brcmf_alloc_pkt_and_read(bus, rdlen, &pkt, &rxbuf); + if (pkt == NULL) { + /* Give up on data, request rtx of events */ + brcmf_dbg(ERROR, "(nextlen): brcmf_alloc_pkt_and_read failed: len %d rdlen %d expected rxseq %d\n", + len, rdlen, rxseq); + continue; + } + + if (brcmf_check_rxbuf(bus, pkt, rxbuf, rxseq, nextlen, + &len) < 0) + continue; + + /* Extract software header fields */ + chan = SDPCM_PACKET_CHANNEL( + &bus->rxhdr[SDPCM_FRAMETAG_LEN]); + seq = SDPCM_PACKET_SEQUENCE( + &bus->rxhdr[SDPCM_FRAMETAG_LEN]); + doff = SDPCM_DOFFSET_VALUE( + &bus->rxhdr[SDPCM_FRAMETAG_LEN]); + txmax = SDPCM_WINDOW_VALUE( + &bus->rxhdr[SDPCM_FRAMETAG_LEN]); + + bus->nextlen = + bus->rxhdr[SDPCM_FRAMETAG_LEN + + SDPCM_NEXTLEN_OFFSET]; + if ((bus->nextlen << 4) > MAX_RX_DATASZ) { + brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", + bus->nextlen, seq); + bus->nextlen = 0; + } + + bus->drvr->rx_readahead_cnt++; + + /* Handle Flow Control */ + fcbits = SDPCM_FCMASK_VALUE( + &bus->rxhdr[SDPCM_FRAMETAG_LEN]); + + if (bus->flowcontrol != fcbits) { + if (~bus->flowcontrol & fcbits) + bus->fc_xoff++; + + if (bus->flowcontrol & ~fcbits) + bus->fc_xon++; + + bus->fc_rcvd++; + bus->flowcontrol = fcbits; + } + + /* Check and update sequence number */ + if (rxseq != seq) { + brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n", + seq, rxseq); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((u8) (txmax - bus->tx_seq) > 0x40) { + brcmf_dbg(ERROR, "got unlikely tx max %d with tx_seq %d\n", + txmax, bus->tx_seq); + txmax = bus->tx_seq + 2; + } + bus->tx_max = txmax; + +#ifdef BCMDBG + if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { + printk(KERN_DEBUG "Rx Data:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + rxbuf, len); + } else if (BRCMF_HDRS_ON()) { + printk(KERN_DEBUG "RxHdr:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + bus->rxhdr, SDPCM_HDRLEN); + } +#endif + + if (chan == SDPCM_CONTROL_CHANNEL) { + brcmf_dbg(ERROR, "(nextlen): readahead on control packet %d?\n", + seq); + /* Force retry w/normal header read */ + bus->nextlen = 0; + brcmf_sdbrcm_rxfail(bus, false, true); + brcmf_sdbrcm_pktfree2(bus, pkt); + continue; + } + + /* Validate data offset */ + if ((doff < SDPCM_HDRLEN) || (doff > len)) { + brcmf_dbg(ERROR, "(nextlen): bad data offset %d: HW len %d min %d\n", + doff, len, SDPCM_HDRLEN); + brcmf_sdbrcm_rxfail(bus, false, false); + brcmf_sdbrcm_pktfree2(bus, pkt); + continue; + } + + /* All done with this one -- now deliver the packet */ + goto deliver; + } + + /* Read frame header (hardware and software) */ + sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, bus->rxhdr, + BRCMF_FIRSTREAD, NULL); + bus->f2rxhdrs++; + + if (sdret < 0) { + brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret); + bus->rx_hdrfail++; + brcmf_sdbrcm_rxfail(bus, true, true); + continue; + } +#ifdef BCMDBG + if (BRCMF_BYTES_ON() || BRCMF_HDRS_ON()) { + printk(KERN_DEBUG "RxHdr:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + bus->rxhdr, SDPCM_HDRLEN); + } +#endif + + /* Extract hardware header fields */ + len = get_unaligned_le16(bus->rxhdr); + check = get_unaligned_le16(bus->rxhdr + sizeof(u16)); + + /* All zeros means no more frames */ + if (!(len | check)) { + *finished = true; + break; + } + + /* Validate check bytes */ + if ((u16) ~(len ^ check)) { + brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n", + len, check); + bus->rx_badhdr++; + brcmf_sdbrcm_rxfail(bus, false, false); + continue; + } + + /* Validate frame length */ + if (len < SDPCM_HDRLEN) { + brcmf_dbg(ERROR, "HW hdr length invalid: %d\n", len); + continue; + } + + /* Extract software header fields */ + chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + + /* Validate data offset */ + if ((doff < SDPCM_HDRLEN) || (doff > len)) { + brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n", + doff, len, SDPCM_HDRLEN, seq); + bus->rx_badhdr++; + brcmf_sdbrcm_rxfail(bus, false, false); + continue; + } + + /* Save the readahead length if there is one */ + bus->nextlen = + bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; + if ((bus->nextlen << 4) > MAX_RX_DATASZ) { + brcmf_dbg(INFO, "(nextlen): got frame w/nextlen too large (%d), seq %d\n", + bus->nextlen, seq); + bus->nextlen = 0; + } + + /* Handle Flow Control */ + fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); + + if (bus->flowcontrol != fcbits) { + if (~bus->flowcontrol & fcbits) + bus->fc_xoff++; + + if (bus->flowcontrol & ~fcbits) + bus->fc_xon++; + + bus->fc_rcvd++; + bus->flowcontrol = fcbits; + } + + /* Check and update sequence number */ + if (rxseq != seq) { + brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq); + bus->rx_badseq++; + rxseq = seq; + } + + /* Check window for sanity */ + if ((u8) (txmax - bus->tx_seq) > 0x40) { + brcmf_dbg(ERROR, "unlikely tx max %d with tx_seq %d\n", + txmax, bus->tx_seq); + txmax = bus->tx_seq + 2; + } + bus->tx_max = txmax; + + /* Call a separate function for control frames */ + if (chan == SDPCM_CONTROL_CHANNEL) { + brcmf_sdbrcm_read_control(bus, bus->rxhdr, len, doff); + continue; + } + + /* precondition: chan is either SDPCM_DATA_CHANNEL, + SDPCM_EVENT_CHANNEL, SDPCM_TEST_CHANNEL or + SDPCM_GLOM_CHANNEL */ + + /* Length to read */ + rdlen = (len > BRCMF_FIRSTREAD) ? (len - BRCMF_FIRSTREAD) : 0; + + /* May pad read to blocksize for efficiency */ + if (bus->roundup && bus->blocksize && + (rdlen > bus->blocksize)) { + pad = bus->blocksize - (rdlen % bus->blocksize); + if ((pad <= bus->roundup) && (pad < bus->blocksize) && + ((rdlen + pad + BRCMF_FIRSTREAD) < MAX_RX_DATASZ)) + rdlen += pad; + } else if (rdlen % BRCMF_SDALIGN) { + rdlen += BRCMF_SDALIGN - (rdlen % BRCMF_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (rdlen & (ALIGNMENT - 1)) + rdlen = roundup(rdlen, ALIGNMENT); + + if ((rdlen + BRCMF_FIRSTREAD) > MAX_RX_DATASZ) { + /* Too long -- skip this frame */ + brcmf_dbg(ERROR, "too long: len %d rdlen %d\n", + len, rdlen); + bus->drvr->rx_errors++; + bus->rx_toolong++; + brcmf_sdbrcm_rxfail(bus, false, false); + continue; + } + + pkt = brcmu_pkt_buf_get_skb(rdlen + + BRCMF_FIRSTREAD + BRCMF_SDALIGN); + if (!pkt) { + /* Give up on data, request rtx of events */ + brcmf_dbg(ERROR, "brcmu_pkt_buf_get_skb failed: rdlen %d chan %d\n", + rdlen, chan); + bus->drvr->rx_dropped++; + brcmf_sdbrcm_rxfail(bus, false, RETRYCHAN(chan)); + continue; + } + + /* Leave room for what we already read, and align remainder */ + skb_pull(pkt, BRCMF_FIRSTREAD); + pkt_align(pkt, rdlen, BRCMF_SDALIGN); + + /* Read the remaining frame data */ + sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, ((u8 *) (pkt->data)), + rdlen, pkt); + bus->f2rxdata++; + + if (sdret < 0) { + brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen, + ((chan == SDPCM_EVENT_CHANNEL) ? "event" + : ((chan == SDPCM_DATA_CHANNEL) ? "data" + : "test")), sdret); + brcmu_pkt_buf_free_skb(pkt); + bus->drvr->rx_errors++; + brcmf_sdbrcm_rxfail(bus, true, RETRYCHAN(chan)); + continue; + } + + /* Copy the already-read portion */ + skb_push(pkt, BRCMF_FIRSTREAD); + memcpy(pkt->data, bus->rxhdr, BRCMF_FIRSTREAD); + +#ifdef BCMDBG + if (BRCMF_BYTES_ON() && BRCMF_DATA_ON()) { + printk(KERN_DEBUG "Rx Data:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + pkt->data, len); + } +#endif + +deliver: + /* Save superframe descriptor and allocate packet frame */ + if (chan == SDPCM_GLOM_CHANNEL) { + if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { + brcmf_dbg(GLOM, "glom descriptor, %d bytes:\n", + len); +#ifdef BCMDBG + if (BRCMF_GLOM_ON()) { + printk(KERN_DEBUG "Glom Data:\n"); + print_hex_dump_bytes("", + DUMP_PREFIX_OFFSET, + pkt->data, len); + } +#endif + __skb_trim(pkt, len); + skb_pull(pkt, SDPCM_HDRLEN); + bus->glomd = pkt; + } else { + brcmf_dbg(ERROR, "%s: glom superframe w/o " + "descriptor!\n", __func__); + brcmf_sdbrcm_rxfail(bus, false, false); + } + continue; + } + + /* Fill in packet len and prio, deliver upward */ + __skb_trim(pkt, len); + skb_pull(pkt, doff); + + if (pkt->len == 0) { + brcmu_pkt_buf_free_skb(pkt); + continue; + } else if (brcmf_proto_hdrpull(bus->drvr, &ifidx, pkt) != 0) { + brcmf_dbg(ERROR, "rx protocol error\n"); + brcmu_pkt_buf_free_skb(pkt); + bus->drvr->rx_errors++; + continue; + } + + /* Unlock during rx call */ + up(&bus->sdsem); + brcmf_rx_frame(bus->drvr, ifidx, pkt, 1); + down(&bus->sdsem); + } + rxcount = maxframes - rxleft; +#ifdef BCMDBG + /* Message if we hit the limit */ + if (!rxleft) + brcmf_dbg(DATA, "hit rx limit of %d frames\n", + maxframes); + else +#endif /* BCMDBG */ + brcmf_dbg(DATA, "processed %d frames\n", rxcount); + /* Back off rxseq if awaiting rtx, update rx_seq */ + if (bus->rxskip) + rxseq--; + bus->rx_seq = rxseq; + + return rxcount; +} + +static int +brcmf_sdbrcm_send_buf(struct brcmf_bus *bus, u32 addr, uint fn, uint flags, + u8 *buf, uint nbytes, struct sk_buff *pkt) +{ + return brcmf_sdcard_send_buf + (bus->sdiodev, addr, fn, flags, buf, nbytes, pkt); +} + +static void +brcmf_sdbrcm_wait_for_event(struct brcmf_bus *bus, bool *lockvar) +{ + up(&bus->sdsem); + wait_event_interruptible_timeout(bus->ctrl_wait, + (*lockvar == false), HZ * 2); + down(&bus->sdsem); + return; +} + +static void +brcmf_sdbrcm_wait_event_wakeup(struct brcmf_bus *bus) +{ + if (waitqueue_active(&bus->ctrl_wait)) + wake_up_interruptible(&bus->ctrl_wait); + return; +} + +/* Writes a HW/SW header into the packet and sends it. */ +/* Assumes: (a) header space already there, (b) caller holds lock */ +static int brcmf_sdbrcm_txpkt(struct brcmf_bus *bus, struct sk_buff *pkt, + uint chan, bool free_pkt) +{ + int ret; + u8 *frame; + u16 len, pad = 0; + u32 swheader; + struct sk_buff *new; + int i; + + brcmf_dbg(TRACE, "Enter\n"); + + frame = (u8 *) (pkt->data); + + /* Add alignment padding, allocate new packet if needed */ + pad = ((unsigned long)frame % BRCMF_SDALIGN); + if (pad) { + if (skb_headroom(pkt) < pad) { + brcmf_dbg(INFO, "insufficient headroom %d for %d pad\n", + skb_headroom(pkt), pad); + bus->drvr->tx_realloc++; + new = brcmu_pkt_buf_get_skb(pkt->len + BRCMF_SDALIGN); + if (!new) { + brcmf_dbg(ERROR, "couldn't allocate new %d-byte packet\n", + pkt->len + BRCMF_SDALIGN); + ret = -ENOMEM; + goto done; + } + + pkt_align(new, pkt->len, BRCMF_SDALIGN); + memcpy(new->data, pkt->data, pkt->len); + if (free_pkt) + brcmu_pkt_buf_free_skb(pkt); + /* free the pkt if canned one is not used */ + free_pkt = true; + pkt = new; + frame = (u8 *) (pkt->data); + /* precondition: (frame % BRCMF_SDALIGN) == 0) */ + pad = 0; + } else { + skb_push(pkt, pad); + frame = (u8 *) (pkt->data); + /* precondition: pad + SDPCM_HDRLEN <= pkt->len */ + memset(frame, 0, pad + SDPCM_HDRLEN); + } + } + /* precondition: pad < BRCMF_SDALIGN */ + + /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ + len = (u16) (pkt->len); + *(__le16 *) frame = cpu_to_le16(len); + *(((__le16 *) frame) + 1) = cpu_to_le16(~len); + + /* Software tag: channel, sequence number, data offset */ + swheader = + ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | + (((pad + + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); + + put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); + put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); + +#ifdef BCMDBG + tx_packets[pkt->priority]++; + if (BRCMF_BYTES_ON() && + (((BRCMF_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || + (BRCMF_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { + printk(KERN_DEBUG "Tx Frame:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, frame, len); + } else if (BRCMF_HDRS_ON()) { + printk(KERN_DEBUG "TxHdr:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + frame, min_t(u16, len, 16)); + } +#endif + + /* Raise len to next SDIO block to eliminate tail command */ + if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { + u16 pad = bus->blocksize - (len % bus->blocksize); + if ((pad <= bus->roundup) && (pad < bus->blocksize)) + len += pad; + } else if (len % BRCMF_SDALIGN) { + len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); + } + + /* Some controllers have trouble with odd bytes -- round to even */ + if (len & (ALIGNMENT - 1)) + len = roundup(len, ALIGNMENT); + + ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, frame, + len, pkt); + bus->f2txdata++; + + if (ret < 0) { + /* On failure, abort the command and terminate the frame */ + brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", + ret); + bus->tx_sderrs++; + + brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, + NULL); + bus->f1regdata++; + + for (i = 0; i < 3; i++) { + u8 hi, lo; + hi = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCHI, + NULL); + lo = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCLO, + NULL); + bus->f1regdata += 2; + if ((hi == 0) && (lo == 0)) + break; + } + + } + if (ret == 0) + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + +done: + /* restore pkt buffer pointer before calling tx complete routine */ + skb_pull(pkt, SDPCM_HDRLEN + pad); + up(&bus->sdsem); + brcmf_txcomplete(bus->drvr, pkt, ret != 0); + down(&bus->sdsem); + + if (free_pkt) + brcmu_pkt_buf_free_skb(pkt); + + return ret; +} + +static uint brcmf_sdbrcm_sendfromq(struct brcmf_bus *bus, uint maxframes) +{ + struct sk_buff *pkt; + u32 intstatus = 0; + uint retries = 0; + int ret = 0, prec_out; + uint cnt = 0; + uint datalen; + u8 tx_prec_map; + + struct brcmf_pub *drvr = bus->drvr; + + brcmf_dbg(TRACE, "Enter\n"); + + tx_prec_map = ~bus->flowcontrol; + + /* Send frames until the limit or some other event */ + for (cnt = 0; (cnt < maxframes) && data_ok(bus); cnt++) { + spin_lock_bh(&bus->txqlock); + pkt = brcmu_pktq_mdeq(&bus->txq, tx_prec_map, &prec_out); + if (pkt == NULL) { + spin_unlock_bh(&bus->txqlock); + break; + } + spin_unlock_bh(&bus->txqlock); + datalen = pkt->len - SDPCM_HDRLEN; + + ret = brcmf_sdbrcm_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, true); + if (ret) + bus->drvr->tx_errors++; + else + bus->drvr->dstats.tx_bytes += datalen; + + /* In poll mode, need to check for other events */ + if (!bus->intr && cnt) { + /* Check device status, signal pending interrupt */ + r_sdreg32(bus, &intstatus, + offsetof(struct sdpcmd_regs, intstatus), + &retries); + bus->f2txdata++; + if (brcmf_sdcard_regfail(bus->sdiodev)) + break; + if (intstatus & bus->hostintmask) + bus->ipend = true; + } + } + + /* Deflow-control stack if needed */ + if (drvr->up && (drvr->busstate == BRCMF_BUS_DATA) && + drvr->txoff && (pktq_len(&bus->txq) < TXLOW)) + brcmf_txflowcontrol(drvr, 0, OFF); + + return cnt; +} + +static bool brcmf_sdbrcm_dpc(struct brcmf_bus *bus) +{ + u32 intstatus, newstatus = 0; + uint retries = 0; + uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ + uint txlimit = bus->txbound; /* Tx frames to send before resched */ + uint framecnt = 0; /* Temporary counter of tx/rx frames */ + bool rxdone = true; /* Flag for no more read data */ + bool resched = false; /* Flag indicating resched wanted */ + + brcmf_dbg(TRACE, "Enter\n"); + + /* Start with leftover status bits */ + intstatus = bus->intstatus; + + down(&bus->sdsem); + + /* If waiting for HTAVAIL, check status */ + if (bus->clkstate == CLK_PENDING) { + int err; + u8 clkctl, devctl = 0; + +#ifdef BCMDBG + /* Check for inconsistent device control */ + devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, &err); + if (err) { + brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); + bus->drvr->busstate = BRCMF_BUS_DOWN; + } +#endif /* BCMDBG */ + + /* Read CSR, if clock on switch to AVAIL, else ignore */ + clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (err) { + brcmf_dbg(ERROR, "error reading CSR: %d\n", + err); + bus->drvr->busstate = BRCMF_BUS_DOWN; + } + + brcmf_dbg(INFO, "DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", + devctl, clkctl); + + if (SBSDIO_HTAV(clkctl)) { + devctl = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, &err); + if (err) { + brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", + err); + bus->drvr->busstate = BRCMF_BUS_DOWN; + } + devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_DEVICE_CTL, devctl, &err); + if (err) { + brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", + err); + bus->drvr->busstate = BRCMF_BUS_DOWN; + } + bus->clkstate = CLK_AVAIL; + } else { + goto clkwait; + } + } + + bus_wake(bus); + + /* Make sure backplane clock is on */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, true); + if (bus->clkstate == CLK_PENDING) + goto clkwait; + + /* Pending interrupt indicates new device status */ + if (bus->ipend) { + bus->ipend = false; + r_sdreg32(bus, &newstatus, + offsetof(struct sdpcmd_regs, intstatus), &retries); + bus->f1regdata++; + if (brcmf_sdcard_regfail(bus->sdiodev)) + newstatus = 0; + newstatus &= bus->hostintmask; + bus->fcstate = !!(newstatus & I_HMB_FC_STATE); + if (newstatus) { + w_sdreg32(bus, newstatus, + offsetof(struct sdpcmd_regs, intstatus), + &retries); + bus->f1regdata++; + } + } + + /* Merge new bits with previous */ + intstatus |= newstatus; + bus->intstatus = 0; + + /* Handle flow-control change: read new state in case our ack + * crossed another change interrupt. If change still set, assume + * FC ON for safety, let next loop through do the debounce. + */ + if (intstatus & I_HMB_FC_CHANGE) { + intstatus &= ~I_HMB_FC_CHANGE; + w_sdreg32(bus, I_HMB_FC_CHANGE, + offsetof(struct sdpcmd_regs, intstatus), &retries); + + r_sdreg32(bus, &newstatus, + offsetof(struct sdpcmd_regs, intstatus), &retries); + bus->f1regdata += 2; + bus->fcstate = + !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); + intstatus |= (newstatus & bus->hostintmask); + } + + /* Handle host mailbox indication */ + if (intstatus & I_HMB_HOST_INT) { + intstatus &= ~I_HMB_HOST_INT; + intstatus |= brcmf_sdbrcm_hostmail(bus); + } + + /* Generally don't ask for these, can get CRC errors... */ + if (intstatus & I_WR_OOSYNC) { + brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n"); + intstatus &= ~I_WR_OOSYNC; + } + + if (intstatus & I_RD_OOSYNC) { + brcmf_dbg(ERROR, "Dongle reports RD_OOSYNC\n"); + intstatus &= ~I_RD_OOSYNC; + } + + if (intstatus & I_SBINT) { + brcmf_dbg(ERROR, "Dongle reports SBINT\n"); + intstatus &= ~I_SBINT; + } + + /* Would be active due to wake-wlan in gSPI */ + if (intstatus & I_CHIPACTIVE) { + brcmf_dbg(INFO, "Dongle reports CHIPACTIVE\n"); + intstatus &= ~I_CHIPACTIVE; + } + + /* Ignore frame indications if rxskip is set */ + if (bus->rxskip) + intstatus &= ~I_HMB_FRAME_IND; + + /* On frame indication, read available frames */ + if (PKT_AVAILABLE()) { + framecnt = brcmf_sdbrcm_readframes(bus, rxlimit, &rxdone); + if (rxdone || bus->rxskip) + intstatus &= ~I_HMB_FRAME_IND; + rxlimit -= min(framecnt, rxlimit); + } + + /* Keep still-pending events for next scheduling */ + bus->intstatus = intstatus; + +clkwait: + if (data_ok(bus) && bus->ctrl_frame_stat && + (bus->clkstate == CLK_AVAIL)) { + int ret, i; + + ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, (u8 *) bus->ctrl_frame_buf, + (u32) bus->ctrl_frame_len, NULL); + + if (ret < 0) { + /* On failure, abort the command and + terminate the frame */ + brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", + ret); + bus->tx_sderrs++; + + brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, + NULL); + bus->f1regdata++; + + for (i = 0; i < 3; i++) { + u8 hi, lo; + hi = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCHI, + NULL); + lo = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCLO, + NULL); + bus->f1regdata += 2; + if ((hi == 0) && (lo == 0)) + break; + } + + } + if (ret == 0) + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + + brcmf_dbg(INFO, "Return_dpc value is : %d\n", ret); + bus->ctrl_frame_stat = false; + brcmf_sdbrcm_wait_event_wakeup(bus); + } + /* Send queued frames (limit 1 if rx may still be pending) */ + else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && + brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit + && data_ok(bus)) { + framecnt = rxdone ? txlimit : min(txlimit, bus->txminmax); + framecnt = brcmf_sdbrcm_sendfromq(bus, framecnt); + txlimit -= framecnt; + } + + /* Resched if events or tx frames are pending, + else await next interrupt */ + /* On failed register access, all bets are off: + no resched or interrupts */ + if ((bus->drvr->busstate == BRCMF_BUS_DOWN) || + brcmf_sdcard_regfail(bus->sdiodev)) { + brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n", + brcmf_sdcard_regfail(bus->sdiodev)); + bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->intstatus = 0; + } else if (bus->clkstate == CLK_PENDING) { + brcmf_dbg(INFO, "rescheduled due to CLK_PENDING awaiting I_CHIPACTIVE interrupt\n"); + resched = true; + } else if (bus->intstatus || bus->ipend || + (!bus->fcstate && brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) + && data_ok(bus)) || PKT_AVAILABLE()) { + resched = true; + } + + bus->dpc_sched = resched; + + /* If we're done for now, turn off clock request. */ + if ((bus->clkstate != CLK_PENDING) + && bus->idletime == BRCMF_IDLE_IMMEDIATE) { + bus->activity = false; + brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); + } + + up(&bus->sdsem); + + return resched; +} + +static int brcmf_sdbrcm_dpc_thread(void *data) +{ + struct brcmf_bus *bus = (struct brcmf_bus *) data; + + allow_signal(SIGTERM); + /* Run until signal received */ + while (1) { + if (kthread_should_stop()) + break; + if (!wait_for_completion_interruptible(&bus->dpc_wait)) { + /* Call bus dpc unless it indicated down + (then clean stop) */ + if (bus->drvr->busstate != BRCMF_BUS_DOWN) { + if (brcmf_sdbrcm_dpc(bus)) + complete(&bus->dpc_wait); + } else { + /* after stopping the bus, exit thread */ + brcmf_sdbrcm_bus_stop(bus); + bus->dpc_tsk = NULL; + break; + } + } else + break; + } + return 0; +} + +int brcmf_sdbrcm_bus_txdata(struct brcmf_bus *bus, struct sk_buff *pkt) +{ + int ret = -EBADE; + uint datalen, prec; + + brcmf_dbg(TRACE, "Enter\n"); + + datalen = pkt->len; + + /* Add space for the header */ + skb_push(pkt, SDPCM_HDRLEN); + /* precondition: IS_ALIGNED((unsigned long)(pkt->data), 2) */ + + prec = prio2prec((pkt->priority & PRIOMASK)); + + /* Check for existing queue, current flow-control, + pending event, or pending clock */ + brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq)); + bus->fcqueued++; + + /* Priority based enq */ + spin_lock_bh(&bus->txqlock); + if (brcmf_c_prec_enq(bus->drvr, &bus->txq, pkt, prec) == false) { + skb_pull(pkt, SDPCM_HDRLEN); + brcmf_txcomplete(bus->drvr, pkt, false); + brcmu_pkt_buf_free_skb(pkt); + brcmf_dbg(ERROR, "out of bus->txq !!!\n"); + ret = -ENOSR; + } else { + ret = 0; + } + spin_unlock_bh(&bus->txqlock); + + if (pktq_len(&bus->txq) >= TXHI) + brcmf_txflowcontrol(bus->drvr, 0, ON); + +#ifdef BCMDBG + if (pktq_plen(&bus->txq, prec) > qcount[prec]) + qcount[prec] = pktq_plen(&bus->txq, prec); +#endif + /* Schedule DPC if needed to send queued packet(s) */ + if (!bus->dpc_sched) { + bus->dpc_sched = true; + if (bus->dpc_tsk) + complete(&bus->dpc_wait); + } + + return ret; +} + +static int +brcmf_sdbrcm_membytes(struct brcmf_bus *bus, bool write, u32 address, u8 *data, + uint size) +{ + int bcmerror = 0; + u32 sdaddr; + uint dsize; + + /* Determine initial transfer parameters */ + sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; + if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) + dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); + else + dsize = size; + + /* Set the backplane window to include the start address */ + bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, address); + if (bcmerror) { + brcmf_dbg(ERROR, "window change failed\n"); + goto xfer_done; + } + + /* Do the transfer(s) */ + while (size) { + brcmf_dbg(INFO, "%s %d bytes at offset 0x%08x in window 0x%08x\n", + write ? "write" : "read", dsize, + sdaddr, address & SBSDIO_SBWINDOW_MASK); + bcmerror = brcmf_sdcard_rwdata(bus->sdiodev, write, + sdaddr, data, dsize); + if (bcmerror) { + brcmf_dbg(ERROR, "membytes transfer failed\n"); + break; + } + + /* Adjust for next transfer (if any) */ + size -= dsize; + if (size) { + data += dsize; + address += dsize; + bcmerror = brcmf_sdcard_set_sbaddr_window(bus->sdiodev, + address); + if (bcmerror) { + brcmf_dbg(ERROR, "window change failed\n"); + break; + } + sdaddr = 0; + dsize = min_t(uint, SBSDIO_SB_OFT_ADDR_LIMIT, size); + } + } + +xfer_done: + /* Return the window to backplane enumeration space for core access */ + if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, bus->sdiodev->sbwad)) + brcmf_dbg(ERROR, "FAILED to set window back to 0x%x\n", + bus->sdiodev->sbwad); + + return bcmerror; +} + +#ifdef BCMDBG +#define CONSOLE_LINE_MAX 192 + +static int brcmf_sdbrcm_readconsole(struct brcmf_bus *bus) +{ + struct brcmf_console *c = &bus->console; + u8 line[CONSOLE_LINE_MAX], ch; + u32 n, idx, addr; + int rv; + + /* Don't do anything until FWREADY updates console address */ + if (bus->console_addr == 0) + return 0; + + /* Read console log struct */ + addr = bus->console_addr + offsetof(struct rte_console, log_le); + rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&c->log_le, + sizeof(c->log_le)); + if (rv < 0) + return rv; + + /* Allocate console buffer (one time only) */ + if (c->buf == NULL) { + c->bufsize = le32_to_cpu(c->log_le.buf_size); + c->buf = kmalloc(c->bufsize, GFP_ATOMIC); + if (c->buf == NULL) + return -ENOMEM; + } + + idx = le32_to_cpu(c->log_le.idx); + + /* Protect against corrupt value */ + if (idx > c->bufsize) + return -EBADE; + + /* Skip reading the console buffer if the index pointer + has not moved */ + if (idx == c->last) + return 0; + + /* Read the console buffer */ + addr = le32_to_cpu(c->log_le.buf); + rv = brcmf_sdbrcm_membytes(bus, false, addr, c->buf, c->bufsize); + if (rv < 0) + return rv; + + while (c->last != idx) { + for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { + if (c->last == idx) { + /* This would output a partial line. + * Instead, back up + * the buffer pointer and output this + * line next time around. + */ + if (c->last >= n) + c->last -= n; + else + c->last = c->bufsize - n; + goto break2; + } + ch = c->buf[c->last]; + c->last = (c->last + 1) % c->bufsize; + if (ch == '\n') + break; + line[n] = ch; + } + + if (n > 0) { + if (line[n - 1] == '\r') + n--; + line[n] = 0; + printk(KERN_DEBUG "CONSOLE: %s\n", line); + } + } +break2: + + return 0; +} +#endif /* BCMDBG */ + +static int brcmf_tx_frame(struct brcmf_bus *bus, u8 *frame, u16 len) +{ + int i; + int ret; + + bus->ctrl_frame_stat = false; + ret = brcmf_sdbrcm_send_buf(bus, bus->sdiodev->sbwad, + SDIO_FUNC_2, F2SYNC, frame, len, NULL); + + if (ret < 0) { + /* On failure, abort the command and terminate the frame */ + brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", + ret); + bus->tx_sderrs++; + + brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); + bus->f1regdata++; + + for (i = 0; i < 3; i++) { + u8 hi, lo; + hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCHI, + NULL); + lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_WFRAMEBCLO, + NULL); + bus->f1regdata += 2; + if (hi == 0 && lo == 0) + break; + } + return ret; + } + + bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; + + return ret; +} + +int +brcmf_sdbrcm_bus_txctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) +{ + u8 *frame; + u16 len; + u32 swheader; + uint retries = 0; + u8 doff = 0; + int ret = -1; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Back the pointer to make a room for bus header */ + frame = msg - SDPCM_HDRLEN; + len = (msglen += SDPCM_HDRLEN); + + /* Add alignment padding (optional for ctl frames) */ + doff = ((unsigned long)frame % BRCMF_SDALIGN); + if (doff) { + frame -= doff; + len += doff; + msglen += doff; + memset(frame, 0, doff + SDPCM_HDRLEN); + } + /* precondition: doff < BRCMF_SDALIGN */ + doff += SDPCM_HDRLEN; + + /* Round send length to next SDIO block */ + if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { + u16 pad = bus->blocksize - (len % bus->blocksize); + if ((pad <= bus->roundup) && (pad < bus->blocksize)) + len += pad; + } else if (len % BRCMF_SDALIGN) { + len += BRCMF_SDALIGN - (len % BRCMF_SDALIGN); + } + + /* Satisfy length-alignment requirements */ + if (len & (ALIGNMENT - 1)) + len = roundup(len, ALIGNMENT); + + /* precondition: IS_ALIGNED((unsigned long)frame, 2) */ + + /* Need to lock here to protect txseq and SDIO tx calls */ + down(&bus->sdsem); + + bus_wake(bus); + + /* Make sure backplane clock is on */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + + /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ + *(__le16 *) frame = cpu_to_le16((u16) msglen); + *(((__le16 *) frame) + 1) = cpu_to_le16(~msglen); + + /* Software tag: channel, sequence number, data offset */ + swheader = + ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & + SDPCM_CHANNEL_MASK) + | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & + SDPCM_DOFFSET_MASK); + put_unaligned_le32(swheader, frame + SDPCM_FRAMETAG_LEN); + put_unaligned_le32(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); + + if (!data_ok(bus)) { + brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n", + bus->tx_max, bus->tx_seq); + bus->ctrl_frame_stat = true; + /* Send from dpc */ + bus->ctrl_frame_buf = frame; + bus->ctrl_frame_len = len; + + brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat); + + if (bus->ctrl_frame_stat == false) { + brcmf_dbg(INFO, "ctrl_frame_stat == false\n"); + ret = 0; + } else { + brcmf_dbg(INFO, "ctrl_frame_stat == true\n"); + ret = -1; + } + } + + if (ret == -1) { +#ifdef BCMDBG + if (BRCMF_BYTES_ON() && BRCMF_CTL_ON()) { + printk(KERN_DEBUG "Tx Frame:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + frame, len); + } else if (BRCMF_HDRS_ON()) { + printk(KERN_DEBUG "TxHdr:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + frame, min_t(u16, len, 16)); + } +#endif + + do { + ret = brcmf_tx_frame(bus, frame, len); + } while (ret < 0 && retries++ < TXRETRIES); + } + + if ((bus->idletime == BRCMF_IDLE_IMMEDIATE) && !bus->dpc_sched) { + bus->activity = false; + brcmf_sdbrcm_clkctl(bus, CLK_NONE, true); + } + + up(&bus->sdsem); + + if (ret) + bus->drvr->tx_ctlerrs++; + else + bus->drvr->tx_ctlpkts++; + + return ret ? -EIO : 0; +} + +int +brcmf_sdbrcm_bus_rxctl(struct brcmf_bus *bus, unsigned char *msg, uint msglen) +{ + int timeleft; + uint rxlen = 0; + bool pending; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Wait until control frame is available */ + timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending); + + down(&bus->sdsem); + rxlen = bus->rxlen; + memcpy(msg, bus->rxctl, min(msglen, rxlen)); + bus->rxlen = 0; + up(&bus->sdsem); + + if (rxlen) { + brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n", + rxlen, msglen); + } else if (timeleft == 0) { + brcmf_dbg(ERROR, "resumed on timeout\n"); + } else if (pending == true) { + brcmf_dbg(CTL, "cancelled\n"); + return -ERESTARTSYS; + } else { + brcmf_dbg(CTL, "resumed for unknown reason?\n"); + } + + if (rxlen) + bus->drvr->rx_ctlpkts++; + else + bus->drvr->rx_ctlerrs++; + + return rxlen ? (int)rxlen : -ETIMEDOUT; +} + +static int brcmf_sdbrcm_downloadvars(struct brcmf_bus *bus, void *arg, int len) +{ + int bcmerror = 0; + + brcmf_dbg(TRACE, "Enter\n"); + + /* Basic sanity checks */ + if (bus->drvr->up) { + bcmerror = -EISCONN; + goto err; + } + if (!len) { + bcmerror = -EOVERFLOW; + goto err; + } + + /* Free the old ones and replace with passed variables */ + kfree(bus->vars); + + bus->vars = kmalloc(len, GFP_ATOMIC); + bus->varsz = bus->vars ? len : 0; + if (bus->vars == NULL) { + bcmerror = -ENOMEM; + goto err; + } + + /* Copy the passed variables, which should include the + terminating double-null */ + memcpy(bus->vars, arg, bus->varsz); +err: + return bcmerror; +} + +static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus) +{ + int bcmerror = 0; + u32 varsize; + u32 varaddr; + u8 *vbuffer; + u32 varsizew; + __le32 varsizew_le; +#ifdef BCMDBG + char *nvram_ularray; +#endif /* BCMDBG */ + + /* Even if there are no vars are to be written, we still + need to set the ramsize. */ + varsize = bus->varsz ? roundup(bus->varsz, 4) : 0; + varaddr = (bus->ramsize - 4) - varsize; + + if (bus->vars) { + vbuffer = kzalloc(varsize, GFP_ATOMIC); + if (!vbuffer) + return -ENOMEM; + + memcpy(vbuffer, bus->vars, bus->varsz); + + /* Write the vars list */ + bcmerror = + brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize); +#ifdef BCMDBG + /* Verify NVRAM bytes */ + brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize); + nvram_ularray = kmalloc(varsize, GFP_ATOMIC); + if (!nvram_ularray) + return -ENOMEM; + + /* Upload image to verify downloaded contents. */ + memset(nvram_ularray, 0xaa, varsize); + + /* Read the vars list to temp buffer for comparison */ + bcmerror = + brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray, + varsize); + if (bcmerror) { + brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n", + bcmerror, varsize, varaddr); + } + /* Compare the org NVRAM with the one read from RAM */ + if (memcmp(vbuffer, nvram_ularray, varsize)) + brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n"); + else + brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n"); + + kfree(nvram_ularray); +#endif /* BCMDBG */ + + kfree(vbuffer); + } + + /* adjust to the user specified RAM */ + brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize); + brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n", + varaddr, varsize); + varsize = ((bus->ramsize - 4) - varaddr); + + /* + * Determine the length token: + * Varsize, converted to words, in lower 16-bits, checksum + * in upper 16-bits. + */ + if (bcmerror) { + varsizew = 0; + varsizew_le = cpu_to_le32(0); + } else { + varsizew = varsize / 4; + varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); + varsizew_le = cpu_to_le32(varsizew); + } + + brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n", + varsize, varsizew); + + /* Write the length token to the last word */ + bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4), + (u8 *)&varsizew_le, 4); + + return bcmerror; +} + +static void +brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase) +{ + u32 regdata; + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbtmstatelow), 4); + if (regdata & SBTML_RESET) + return; + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbtmstatelow), 4); + if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) { + /* + * set target reject and spin until busy is clear + * (preserve core-specific bits) + */ + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbtmstatelow), 4); + brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), + 4, regdata | SBTML_REJ); + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbtmstatelow), 4); + udelay(1); + SPINWAIT((brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbtmstatehigh), 4) & + SBTMH_BUSY), 100000); + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbtmstatehigh), 4); + if (regdata & SBTMH_BUSY) + brcmf_dbg(ERROR, "ARM core still busy\n"); + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbidlow), 4); + if (regdata & SBIDL_INIT) { + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbimstate), 4) | + SBIM_RJ; + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(corebase, sbimstate), 4, + regdata); + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbimstate), 4); + udelay(1); + SPINWAIT((brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbimstate), 4) & + SBIM_BY), 100000); + } + + /* set reset and reject while enabling the clocks */ + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(corebase, sbtmstatelow), 4, + (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | + SBTML_REJ | SBTML_RESET)); + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbtmstatelow), 4); + udelay(10); + + /* clear the initiator reject bit */ + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbidlow), 4); + if (regdata & SBIDL_INIT) { + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbimstate), 4) & + ~SBIM_RJ; + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(corebase, sbimstate), 4, + regdata); + } + } + + /* leave reset and reject asserted */ + brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, + (SBTML_REJ | SBTML_RESET)); + udelay(1); +} + +static void +brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase) +{ + u32 regdata; + + /* + * Must do the disable sequence first to work for + * arbitrary current core state. + */ + brcmf_sdbrcm_chip_disablecore(sdiodev, corebase); + + /* + * Now do the initialization sequence. + * set reset while enabling the clock and + * forcing them on throughout the core + */ + brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, + ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) | + SBTML_RESET); + udelay(1); + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbtmstatehigh), 4); + if (regdata & SBTMH_SERR) + brcmf_sdcard_reg_write(sdiodev, + CORE_SB(corebase, sbtmstatehigh), 4, 0); + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(corebase, sbimstate), 4); + if (regdata & (SBIM_IBE | SBIM_TO)) + brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4, + regdata & ~(SBIM_IBE | SBIM_TO)); + + /* clear reset and allow it to propagate throughout the core */ + brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, + (SICF_FGC << SBTML_SICF_SHIFT) | + (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); + udelay(1); + + /* leave clock enabled */ + brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4, + (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); + udelay(1); +} + +static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter) +{ + uint retries; + u32 regdata; + int bcmerror = 0; + + /* To enter download state, disable ARM and reset SOCRAM. + * To exit download state, simply reset ARM (default is RAM boot). + */ + if (enter) { + bus->alp_only = true; + + brcmf_sdbrcm_chip_disablecore(bus->sdiodev, + bus->ci->armcorebase); + + brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase); + + /* Clear the top bit of memory */ + if (bus->ramsize) { + u32 zeros = 0; + brcmf_sdbrcm_membytes(bus, true, bus->ramsize - 4, + (u8 *)&zeros, 4); + } + } else { + regdata = brcmf_sdcard_reg_read(bus->sdiodev, + CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4); + regdata &= (SBTML_RESET | SBTML_REJ_MASK | + (SICF_CLOCK_EN << SBTML_SICF_SHIFT)); + if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) { + brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n"); + bcmerror = -EBADE; + goto fail; + } + + bcmerror = brcmf_sdbrcm_write_vars(bus); + if (bcmerror) { + brcmf_dbg(ERROR, "no vars written to RAM\n"); + bcmerror = 0; + } + + w_sdreg32(bus, 0xFFFFFFFF, + offsetof(struct sdpcmd_regs, intstatus), &retries); + + brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase); + + /* Allow HT Clock now that the ARM is running. */ + bus->alp_only = false; + + bus->drvr->busstate = BRCMF_BUS_LOAD; + } +fail: + return bcmerror; +} + +static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_bus *bus) +{ + if (bus->firmware->size < bus->fw_ptr + len) + len = bus->firmware->size - bus->fw_ptr; + + memcpy(buf, &bus->firmware->data[bus->fw_ptr], len); + bus->fw_ptr += len; + return len; +} + +MODULE_FIRMWARE(BCM4329_FW_NAME); +MODULE_FIRMWARE(BCM4329_NV_NAME); + +static int brcmf_sdbrcm_download_code_file(struct brcmf_bus *bus) +{ + int offset = 0; + uint len; + u8 *memblock = NULL, *memptr; + int ret; + + brcmf_dbg(INFO, "Enter\n"); + + bus->fw_name = BCM4329_FW_NAME; + ret = request_firmware(&bus->firmware, bus->fw_name, + &bus->sdiodev->func[2]->dev); + if (ret) { + brcmf_dbg(ERROR, "Fail to request firmware %d\n", ret); + return ret; + } + bus->fw_ptr = 0; + + memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC); + if (memblock == NULL) { + ret = -ENOMEM; + goto err; + } + if ((u32)(unsigned long)memblock % BRCMF_SDALIGN) + memptr += (BRCMF_SDALIGN - + ((u32)(unsigned long)memblock % BRCMF_SDALIGN)); + + /* Download image */ + while ((len = + brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus))) { + ret = brcmf_sdbrcm_membytes(bus, true, offset, memptr, len); + if (ret) { + brcmf_dbg(ERROR, "error %d on writing %d membytes at 0x%08x\n", + ret, MEMBLOCK, offset); + goto err; + } + + offset += MEMBLOCK; + } + +err: + kfree(memblock); + + release_firmware(bus->firmware); + bus->fw_ptr = 0; + + return ret; +} + +/* + * ProcessVars:Takes a buffer of "<var>=<value>\n" lines read from a file + * and ending in a NUL. + * Removes carriage returns, empty lines, comment lines, and converts + * newlines to NULs. + * Shortens buffer as needed and pads with NULs. End of buffer is marked + * by two NULs. +*/ + +static uint brcmf_process_nvram_vars(char *varbuf, uint len) +{ + char *dp; + bool findNewline; + int column; + uint buf_len, n; + + dp = varbuf; + + findNewline = false; + column = 0; + + for (n = 0; n < len; n++) { + if (varbuf[n] == 0) + break; + if (varbuf[n] == '\r') + continue; + if (findNewline && varbuf[n] != '\n') + continue; + findNewline = false; + if (varbuf[n] == '#') { + findNewline = true; + continue; + } + if (varbuf[n] == '\n') { + if (column == 0) + continue; + *dp++ = 0; + column = 0; + continue; + } + *dp++ = varbuf[n]; + column++; + } + buf_len = dp - varbuf; + + while (dp < varbuf + n) + *dp++ = 0; + + return buf_len; +} + +static int brcmf_sdbrcm_download_nvram(struct brcmf_bus *bus) +{ + uint len; + char *memblock = NULL; + char *bufp; + int ret; + + bus->nv_name = BCM4329_NV_NAME; + ret = request_firmware(&bus->firmware, bus->nv_name, + &bus->sdiodev->func[2]->dev); + if (ret) { + brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); + return ret; + } + bus->fw_ptr = 0; + + memblock = kmalloc(MEMBLOCK, GFP_ATOMIC); + if (memblock == NULL) { + ret = -ENOMEM; + goto err; + } + + len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus); + + if (len > 0 && len < MEMBLOCK) { + bufp = (char *)memblock; + bufp[len] = 0; + len = brcmf_process_nvram_vars(bufp, len); + bufp += len; + *bufp++ = 0; + if (len) + ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1); + if (ret) + brcmf_dbg(ERROR, "error downloading vars: %d\n", ret); + } else { + brcmf_dbg(ERROR, "error reading nvram file: %d\n", len); + ret = -EIO; + } + +err: + kfree(memblock); + + release_firmware(bus->firmware); + bus->fw_ptr = 0; + + return ret; +} + +static int _brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) +{ + int bcmerror = -1; + + /* Keep arm in reset */ + if (brcmf_sdbrcm_download_state(bus, true)) { + brcmf_dbg(ERROR, "error placing ARM core in reset\n"); + goto err; + } + + /* External image takes precedence if specified */ + if (brcmf_sdbrcm_download_code_file(bus)) { + brcmf_dbg(ERROR, "dongle image file download failed\n"); + goto err; + } + + /* External nvram takes precedence if specified */ + if (brcmf_sdbrcm_download_nvram(bus)) + brcmf_dbg(ERROR, "dongle nvram file download failed\n"); + + /* Take arm out of reset */ + if (brcmf_sdbrcm_download_state(bus, false)) { + brcmf_dbg(ERROR, "error getting out of ARM core reset\n"); + goto err; + } + + bcmerror = 0; + +err: + return bcmerror; +} + +static bool +brcmf_sdbrcm_download_firmware(struct brcmf_bus *bus) +{ + bool ret; + + /* Download the firmware */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + + ret = _brcmf_sdbrcm_download_firmware(bus) == 0; + + brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); + + return ret; +} + +void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus) +{ + u32 local_hostintmask; + u8 saveclk; + uint retries; + int err; + + brcmf_dbg(TRACE, "Enter\n"); + + if (bus->watchdog_tsk) { + send_sig(SIGTERM, bus->watchdog_tsk, 1); + kthread_stop(bus->watchdog_tsk); + bus->watchdog_tsk = NULL; + } + + if (bus->dpc_tsk && bus->dpc_tsk != current) { + send_sig(SIGTERM, bus->dpc_tsk, 1); + kthread_stop(bus->dpc_tsk); + bus->dpc_tsk = NULL; + } + + down(&bus->sdsem); + + bus_wake(bus); + + /* Enable clock for device interrupts */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + + /* Disable and clear interrupts at the chip level also */ + w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); + local_hostintmask = bus->hostintmask; + bus->hostintmask = 0; + + /* Change our idea of bus state */ + bus->drvr->busstate = BRCMF_BUS_DOWN; + + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) + brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); + + /* Turn off the bus (F2), free any pending packets */ + brcmf_dbg(INTR, "disable SDIO interrupts\n"); + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, + SDIO_FUNC_ENABLE_1, NULL); + + /* Clear any pending interrupts now that F2 is disabled */ + w_sdreg32(bus, local_hostintmask, + offsetof(struct sdpcmd_regs, intstatus), &retries); + + /* Turn off the backplane clock (only) */ + brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); + + /* Clear the data packet queues */ + brcmu_pktq_flush(&bus->txq, true, NULL, NULL); + + /* Clear any held glomming stuff */ + if (bus->glomd) + brcmu_pkt_buf_free_skb(bus->glomd); + + if (bus->glom) + brcmu_pkt_buf_free_skb(bus->glom); + + bus->glom = bus->glomd = NULL; + + /* Clear rx control and wake any waiters */ + bus->rxlen = 0; + brcmf_sdbrcm_dcmd_resp_wake(bus); + + /* Reset some F2 state stuff */ + bus->rxskip = false; + bus->tx_seq = bus->rx_seq = 0; + + up(&bus->sdsem); +} + +int brcmf_sdbrcm_bus_init(struct brcmf_pub *drvr) +{ + struct brcmf_bus *bus = drvr->bus; + unsigned long timeout; + uint retries = 0; + u8 ready, enable; + int err, ret = 0; + u8 saveclk; + + brcmf_dbg(TRACE, "Enter\n"); + + /* try to download image and nvram to the dongle */ + if (drvr->busstate == BRCMF_BUS_DOWN) { + if (!(brcmf_sdbrcm_download_firmware(bus))) + return -1; + } + + if (!bus->drvr) + return 0; + + /* Start the watchdog timer */ + bus->drvr->tickcnt = 0; + brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); + + down(&bus->sdsem); + + /* Make sure backplane clock is on, needed to generate F2 interrupt */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + if (bus->clkstate != CLK_AVAIL) + goto exit; + + /* Force clocks on backplane to be sure F2 interrupt propagates */ + saveclk = + brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err); + if (!err) { + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); + } + if (err) { + brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); + goto exit; + } + + /* Enable function 2 (frame transfers) */ + w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, + offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries); + enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, + enable, NULL); + + timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY); + ready = 0; + while (enable != ready) { + ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0, + SDIO_CCCR_IORx, NULL); + if (time_after(jiffies, timeout)) + break; + else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50)) + /* prevent busy waiting if it takes too long */ + msleep_interruptible(20); + } + + brcmf_dbg(INFO, "enable 0x%02x, ready 0x%02x\n", enable, ready); + + /* If F2 successfully enabled, set core and enable interrupts */ + if (ready == enable) { + /* Set up the interrupt mask and enable interrupts */ + bus->hostintmask = HOSTINTMASK; + w_sdreg32(bus, bus->hostintmask, + offsetof(struct sdpcmd_regs, hostintmask), &retries); + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_WATERMARK, 8, &err); + + /* Set bus state according to enable result */ + drvr->busstate = BRCMF_BUS_DATA; + } + + else { + /* Disable F2 again */ + enable = SDIO_FUNC_ENABLE_1; + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, + SDIO_CCCR_IOEx, enable, NULL); + } + + /* Restore previous clock setting */ + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); + + /* If we didn't come up, turn off backplane clock */ + if (drvr->busstate != BRCMF_BUS_DATA) + brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); + +exit: + up(&bus->sdsem); + + return ret; +} + +void brcmf_sdbrcm_isr(void *arg) +{ + struct brcmf_bus *bus = (struct brcmf_bus *) arg; + + brcmf_dbg(TRACE, "Enter\n"); + + if (!bus) { + brcmf_dbg(ERROR, "bus is null pointer, exiting\n"); + return; + } + + if (bus->drvr->busstate == BRCMF_BUS_DOWN) { + brcmf_dbg(ERROR, "bus is down. we have nothing to do\n"); + return; + } + /* Count the interrupt call */ + bus->intrcount++; + bus->ipend = true; + + /* Shouldn't get this interrupt if we're sleeping? */ + if (bus->sleeping) { + brcmf_dbg(ERROR, "INTERRUPT WHILE SLEEPING??\n"); + return; + } + + /* Disable additional interrupts (is this needed now)? */ + if (!bus->intr) + brcmf_dbg(ERROR, "isr w/o interrupt configured!\n"); + + bus->dpc_sched = true; + if (bus->dpc_tsk) + complete(&bus->dpc_wait); +} + +static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_pub *drvr) +{ + struct brcmf_bus *bus; + + brcmf_dbg(TIMER, "Enter\n"); + + bus = drvr->bus; + + /* Ignore the timer if simulating bus down */ + if (bus->sleeping) + return false; + + down(&bus->sdsem); + + /* Poll period: check device if appropriate. */ + if (bus->poll && (++bus->polltick >= bus->pollrate)) { + u32 intstatus = 0; + + /* Reset poll tick */ + bus->polltick = 0; + + /* Check device if no interrupts */ + if (!bus->intr || (bus->intrcount == bus->lastintrs)) { + + if (!bus->dpc_sched) { + u8 devpend; + devpend = brcmf_sdcard_cfg_read(bus->sdiodev, + SDIO_FUNC_0, SDIO_CCCR_INTx, + NULL); + intstatus = + devpend & (INTR_STATUS_FUNC1 | + INTR_STATUS_FUNC2); + } + + /* If there is something, make like the ISR and + schedule the DPC */ + if (intstatus) { + bus->pollcnt++; + bus->ipend = true; + + bus->dpc_sched = true; + if (bus->dpc_tsk) + complete(&bus->dpc_wait); + } + } + + /* Update interrupt tracking */ + bus->lastintrs = bus->intrcount; + } +#ifdef BCMDBG + /* Poll for console output periodically */ + if (drvr->busstate == BRCMF_BUS_DATA && bus->console_interval != 0) { + bus->console.count += BRCMF_WD_POLL_MS; + if (bus->console.count >= bus->console_interval) { + bus->console.count -= bus->console_interval; + /* Make sure backplane clock is on */ + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + if (brcmf_sdbrcm_readconsole(bus) < 0) + /* stop on error */ + bus->console_interval = 0; + } + } +#endif /* BCMDBG */ + + /* On idle timeout clear activity flag and/or turn off clock */ + if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { + if (++bus->idlecount >= bus->idletime) { + bus->idlecount = 0; + if (bus->activity) { + bus->activity = false; + brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); + } else { + brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); + } + } + } + + up(&bus->sdsem); + + return bus->ipend; +} + +static bool brcmf_sdbrcm_chipmatch(u16 chipid) +{ + if (chipid == BCM4329_CHIP_ID) + return true; + return false; +} + +static void brcmf_sdbrcm_release_malloc(struct brcmf_bus *bus) +{ + brcmf_dbg(TRACE, "Enter\n"); + + kfree(bus->rxbuf); + bus->rxctl = bus->rxbuf = NULL; + bus->rxlen = 0; + + kfree(bus->databuf); + bus->databuf = NULL; +} + +static bool brcmf_sdbrcm_probe_malloc(struct brcmf_bus *bus) +{ + brcmf_dbg(TRACE, "Enter\n"); + + if (bus->drvr->maxctl) { + bus->rxblen = + roundup((bus->drvr->maxctl + SDPCM_HDRLEN), + ALIGNMENT) + BRCMF_SDALIGN; + bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); + if (!(bus->rxbuf)) + goto fail; + } + + /* Allocate buffer to receive glomed packet */ + bus->databuf = kmalloc(MAX_DATA_BUF, GFP_ATOMIC); + if (!(bus->databuf)) { + /* release rxbuf which was already located as above */ + if (!bus->rxblen) + kfree(bus->rxbuf); + goto fail; + } + + /* Align the buffer */ + if ((unsigned long)bus->databuf % BRCMF_SDALIGN) + bus->dataptr = bus->databuf + (BRCMF_SDALIGN - + ((unsigned long)bus->databuf % BRCMF_SDALIGN)); + else + bus->dataptr = bus->databuf; + + return true; + +fail: + return false; +} + +/* SDIO Pad drive strength to select value mappings */ +struct sdiod_drive_str { + u8 strength; /* Pad Drive Strength in mA */ + u8 sel; /* Chip-specific select value */ +}; + +/* SDIO Drive Strength to sel value table for PMU Rev 1 */ +static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = { + { + 4, 0x2}, { + 2, 0x3}, { + 1, 0x0}, { + 0, 0x0} + }; + +/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */ +static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = { + { + 12, 0x7}, { + 10, 0x6}, { + 8, 0x5}, { + 6, 0x4}, { + 4, 0x2}, { + 2, 0x1}, { + 0, 0x0} + }; + +/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */ +static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = { + { + 32, 0x7}, { + 26, 0x6}, { + 22, 0x5}, { + 16, 0x4}, { + 12, 0x3}, { + 8, 0x2}, { + 4, 0x1}, { + 0, 0x0} + }; + +#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) + +static char *brcmf_chipname(uint chipid, char *buf, uint len) +{ + const char *fmt; + + fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; + snprintf(buf, len, fmt, chipid); + return buf; +} + +static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus, + u32 drivestrength) { + struct sdiod_drive_str *str_tab = NULL; + u32 str_mask = 0; + u32 str_shift = 0; + char chn[8]; + + if (!(bus->ci->cccaps & CC_CAP_PMU)) + return; + + switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) { + case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1): + str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1; + str_mask = 0x30000000; + str_shift = 28; + break; + case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2): + case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3): + str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2; + str_mask = 0x00003800; + str_shift = 11; + break; + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): + str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3; + str_mask = 0x00003800; + str_shift = 11; + break; + default: + brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", + brcmf_chipname(bus->ci->chip, chn, 8), + bus->ci->chiprev, bus->ci->pmurev); + break; + } + + if (str_tab != NULL) { + u32 drivestrength_sel = 0; + u32 cc_data_temp; + int i; + + for (i = 0; str_tab[i].strength != 0; i++) { + if (drivestrength >= str_tab[i].strength) { + drivestrength_sel = str_tab[i].sel; + break; + } + } + + brcmf_sdcard_reg_write(bus->sdiodev, + CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), + 4, 1); + cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev, + CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4); + cc_data_temp &= ~str_mask; + drivestrength_sel <<= str_shift; + cc_data_temp |= drivestrength_sel; + brcmf_sdcard_reg_write(bus->sdiodev, + CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), + 4, cc_data_temp); + + brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n", + drivestrength, cc_data_temp); + } +} + +static int +brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev, + struct chip_info *ci, u32 regs) +{ + u32 regdata; + + /* + * Get CC core rev + * Chipid is assume to be at offset 0 from regs arg + * For different chiptypes or old sdio hosts w/o chipcommon, + * other ways of recognition should be added here. + */ + ci->cccorebase = regs; + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_CC_REG(ci->cccorebase, chipid), 4); + ci->chip = regdata & CID_ID_MASK; + ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; + + brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev); + + /* Address of cores for new chips should be added here */ + switch (ci->chip) { + case BCM4329_CHIP_ID: + ci->buscorebase = BCM4329_CORE_BUS_BASE; + ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE; + ci->armcorebase = BCM4329_CORE_ARM_BASE; + ci->ramsize = BCM4329_RAMSIZE; + break; + default: + brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip); + return -ENODEV; + } + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(ci->cccorebase, sbidhigh), 4); + ci->ccrev = SBCOREREV(regdata); + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_CC_REG(ci->cccorebase, pmucapabilities), 4); + ci->pmurev = regdata & PCAP_REV_MASK; + + regdata = brcmf_sdcard_reg_read(sdiodev, + CORE_SB(ci->buscorebase, sbidhigh), 4); + ci->buscorerev = SBCOREREV(regdata); + ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT; + + brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n", + ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype); + + /* get chipcommon capabilites */ + ci->cccaps = brcmf_sdcard_reg_read(sdiodev, + CORE_CC_REG(ci->cccorebase, capabilities), 4); + + return 0; +} + +static int +brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs) +{ + struct chip_info *ci; + int err; + u8 clkval, clkset; + + brcmf_dbg(TRACE, "Enter\n"); + + /* alloc chip_info_t */ + ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC); + if (NULL == ci) + return -ENOMEM; + + /* bus/core/clk setup for register access */ + /* Try forcing SDIO core to do ALPAvail request only */ + clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); + if (err) { + brcmf_dbg(ERROR, "error writing for HT off\n"); + goto fail; + } + + /* If register supported, wait for ALPAvail and then force ALP */ + /* This may take up to 15 milliseconds */ + clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, NULL); + if ((clkval & ~SBSDIO_AVBITS) == clkset) { + SPINWAIT(((clkval = + brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, + NULL)), + !SBSDIO_ALPAV(clkval)), + PMU_MAX_TRANSITION_DLY); + if (!SBSDIO_ALPAV(clkval)) { + brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n", + clkval); + err = -EBUSY; + goto fail; + } + clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | + SBSDIO_FORCE_ALP; + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, + clkset, &err); + udelay(65); + } else { + brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n", + clkset, clkval); + err = -EACCES; + goto fail; + } + + /* Also, disable the extra SDIO pull-ups */ + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); + + err = brcmf_sdbrcm_chip_recognition(bus->sdiodev, ci, regs); + if (err) + goto fail; + + /* + * Make sure any on-chip ARM is off (in case strapping is wrong), + * or downloaded code was already running. + */ + brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ci->armcorebase); + + brcmf_sdcard_reg_write(bus->sdiodev, + CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0); + brcmf_sdcard_reg_write(bus->sdiodev, + CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0); + + /* Disable F2 to clear any intermediate frame state on the dongle */ + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, + SDIO_FUNC_ENABLE_1, NULL); + + /* WAR: cmd52 backplane read so core HW will drop ALPReq */ + clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + 0, NULL); + + /* Done with backplane-dependent accesses, can drop clock... */ + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + + bus->ci = ci; + return 0; +fail: + bus->ci = NULL; + kfree(ci); + return err; +} + +static bool +brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva) +{ + u8 clkctl = 0; + int err = 0; + int reg_addr; + u32 reg_val; + + bus->alp_only = true; + + /* Return the window to backplane enumeration space for core access */ + if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE)) + brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n"); + +#ifdef BCMDBG + printk(KERN_DEBUG "F1 signature read @0x18000000=0x%4x\n", + brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4)); + +#endif /* BCMDBG */ + + /* + * Force PLL off until brcmf_sdbrcm_chip_attach() + * programs PLL control regs + */ + + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, + BRCMF_INIT_CLKCTL1, &err); + if (!err) + clkctl = + brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, &err); + + if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { + brcmf_dbg(ERROR, "ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", + err, BRCMF_INIT_CLKCTL1, clkctl); + goto fail; + } + + if (brcmf_sdbrcm_chip_attach(bus, regsva)) { + brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n"); + goto fail; + } + + if (!brcmf_sdbrcm_chipmatch((u16) bus->ci->chip)) { + brcmf_dbg(ERROR, "unsupported chip: 0x%04x\n", bus->ci->chip); + goto fail; + } + + brcmf_sdbrcm_sdiod_drive_strength_init(bus, SDIO_DRIVE_STRENGTH); + + /* Get info on the ARM and SOCRAM cores... */ + brcmf_sdcard_reg_read(bus->sdiodev, + CORE_SB(bus->ci->armcorebase, sbidhigh), 4); + bus->ramsize = bus->ci->ramsize; + if (!(bus->ramsize)) { + brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n"); + goto fail; + } + + /* Set core control so an SDIO reset does a backplane reset */ + reg_addr = bus->ci->buscorebase + + offsetof(struct sdpcmd_regs, corecontrol); + reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32)); + brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32), + reg_val | CC_BPRESEN); + + brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); + + /* Locate an appropriately-aligned portion of hdrbuf */ + bus->rxhdr = (u8 *) roundup((unsigned long)&bus->hdrbuf[0], + BRCMF_SDALIGN); + + /* Set the poll and/or interrupt flags */ + bus->intr = true; + bus->poll = false; + if (bus->poll) + bus->pollrate = 1; + + return true; + +fail: + return false; +} + +static bool brcmf_sdbrcm_probe_init(struct brcmf_bus *bus) +{ + brcmf_dbg(TRACE, "Enter\n"); + + /* Disable F2 to clear any intermediate frame state on the dongle */ + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, + SDIO_FUNC_ENABLE_1, NULL); + + bus->drvr->busstate = BRCMF_BUS_DOWN; + bus->sleeping = false; + bus->rxflow = false; + + /* Done with backplane-dependent accesses, can drop clock... */ + brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, + SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + + /* ...and initialize clock/power states */ + bus->clkstate = CLK_SDONLY; + bus->idletime = BRCMF_IDLE_INTERVAL; + bus->idleclock = BRCMF_IDLE_ACTIVE; + + /* Query the F2 block size, set roundup accordingly */ + bus->blocksize = bus->sdiodev->func[2]->cur_blksize; + bus->roundup = min(max_roundup, bus->blocksize); + + /* bus module does not support packet chaining */ + bus->use_rxchain = false; + bus->sd_rxchain = false; + + return true; +} + +static int +brcmf_sdbrcm_watchdog_thread(void *data) +{ + struct brcmf_bus *bus = (struct brcmf_bus *)data; + + allow_signal(SIGTERM); + /* Run until signal received */ + while (1) { + if (kthread_should_stop()) + break; + if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { + brcmf_sdbrcm_bus_watchdog(bus->drvr); + /* Count the tick for reference */ + bus->drvr->tickcnt++; + } else + break; + } + return 0; +} + +static void +brcmf_sdbrcm_watchdog(unsigned long data) +{ + struct brcmf_bus *bus = (struct brcmf_bus *)data; + + if (bus->watchdog_tsk) { + complete(&bus->watchdog_wait); + /* Reschedule the watchdog */ + if (bus->wd_timer_valid) + mod_timer(&bus->timer, + jiffies + BRCMF_WD_POLL_MS * HZ / 1000); + } +} + +static void +brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus) +{ + brcmf_dbg(TRACE, "Enter\n"); + + kfree(bus->ci); + bus->ci = NULL; +} + +static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus) +{ + brcmf_dbg(TRACE, "Enter\n"); + + if (bus->ci) { + brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); + brcmf_sdbrcm_clkctl(bus, CLK_NONE, false); + brcmf_sdbrcm_chip_detach(bus); + if (bus->vars && bus->varsz) + kfree(bus->vars); + bus->vars = NULL; + } + + brcmf_dbg(TRACE, "Disconnected\n"); +} + +/* Detach and free everything */ +static void brcmf_sdbrcm_release(struct brcmf_bus *bus) +{ + brcmf_dbg(TRACE, "Enter\n"); + + if (bus) { + /* De-register interrupt handler */ + brcmf_sdcard_intr_dereg(bus->sdiodev); + + if (bus->drvr) { + brcmf_detach(bus->drvr); + brcmf_sdbrcm_release_dongle(bus); + bus->drvr = NULL; + } + + brcmf_sdbrcm_release_malloc(bus); + + kfree(bus); + } + + brcmf_dbg(TRACE, "Disconnected\n"); +} + +void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, + u32 regsva, struct brcmf_sdio_dev *sdiodev) +{ + int ret; + struct brcmf_bus *bus; + + /* Init global variables at run-time, not as part of the declaration. + * This is required to support init/de-init of the driver. + * Initialization + * of globals as part of the declaration results in non-deterministic + * behavior since the value of the globals may be different on the + * first time that the driver is initialized vs subsequent + * initializations. + */ + brcmf_c_init(); + + brcmf_dbg(TRACE, "Enter\n"); + + /* We make an assumption about address window mappings: + * regsva == SI_ENUM_BASE*/ + + /* Allocate private bus interface state */ + bus = kzalloc(sizeof(struct brcmf_bus), GFP_ATOMIC); + if (!bus) + goto fail; + + bus->sdiodev = sdiodev; + sdiodev->bus = bus; + bus->txbound = BRCMF_TXBOUND; + bus->rxbound = BRCMF_RXBOUND; + bus->txminmax = BRCMF_TXMINMAX; + bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; + bus->usebufpool = false; /* Use bufpool if allocated, + else use locally malloced rxbuf */ + + /* attempt to attach to the dongle */ + if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) { + brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n"); + goto fail; + } + + spin_lock_init(&bus->txqlock); + init_waitqueue_head(&bus->ctrl_wait); + init_waitqueue_head(&bus->dcmd_resp_wait); + + /* Set up the watchdog timer */ + init_timer(&bus->timer); + bus->timer.data = (unsigned long)bus; + bus->timer.function = brcmf_sdbrcm_watchdog; + + /* Initialize thread based operation and lock */ + sema_init(&bus->sdsem, 1); + + /* Initialize watchdog thread */ + init_completion(&bus->watchdog_wait); + bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread, + bus, "brcmf_watchdog"); + if (IS_ERR(bus->watchdog_tsk)) { + printk(KERN_WARNING + "brcmf_watchdog thread failed to start\n"); + bus->watchdog_tsk = NULL; + } + /* Initialize DPC thread */ + init_completion(&bus->dpc_wait); + bus->dpc_tsk = kthread_run(brcmf_sdbrcm_dpc_thread, + bus, "brcmf_dpc"); + if (IS_ERR(bus->dpc_tsk)) { + printk(KERN_WARNING + "brcmf_dpc thread failed to start\n"); + bus->dpc_tsk = NULL; + } + + /* Attach to the brcmf/OS/network interface */ + bus->drvr = brcmf_attach(bus, SDPCM_RESERVE); + if (!bus->drvr) { + brcmf_dbg(ERROR, "brcmf_attach failed\n"); + goto fail; + } + + /* Allocate buffers */ + if (!(brcmf_sdbrcm_probe_malloc(bus))) { + brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_malloc failed\n"); + goto fail; + } + + if (!(brcmf_sdbrcm_probe_init(bus))) { + brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_init failed\n"); + goto fail; + } + + /* Register interrupt callback, but mask it (not operational yet). */ + brcmf_dbg(INTR, "disable SDIO interrupts (not interested yet)\n"); + ret = brcmf_sdcard_intr_reg(bus->sdiodev); + if (ret != 0) { + brcmf_dbg(ERROR, "FAILED: sdcard_intr_reg returned %d\n", ret); + goto fail; + } + brcmf_dbg(INTR, "registered SDIO interrupt function ok\n"); + + brcmf_dbg(INFO, "completed!!\n"); + + /* if firmware path present try to download and bring up bus */ + ret = brcmf_bus_start(bus->drvr); + if (ret != 0) { + if (ret == -ENOLINK) { + brcmf_dbg(ERROR, "dongle is not responding\n"); + goto fail; + } + } + /* Ok, have the per-port tell the stack we're open for business */ + if (brcmf_net_attach(bus->drvr, 0) != 0) { + brcmf_dbg(ERROR, "Net attach failed!!\n"); + goto fail; + } + + return bus; + +fail: + brcmf_sdbrcm_release(bus); + return NULL; +} + +void brcmf_sdbrcm_disconnect(void *ptr) +{ + struct brcmf_bus *bus = (struct brcmf_bus *)ptr; + + brcmf_dbg(TRACE, "Enter\n"); + + if (bus) + brcmf_sdbrcm_release(bus); + + brcmf_dbg(TRACE, "Disconnected\n"); +} + +struct device *brcmf_bus_get_device(struct brcmf_bus *bus) +{ + return &bus->sdiodev->func[2]->dev; +} + +void +brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick) +{ + /* don't start the wd until fw is loaded */ + if (bus->drvr->busstate == BRCMF_BUS_DOWN) + return; + + /* Totally stop the timer */ + if (!wdtick && bus->wd_timer_valid == true) { + del_timer_sync(&bus->timer); + bus->wd_timer_valid = false; + bus->save_ms = wdtick; + return; + } + + if (wdtick) { + if (bus->save_ms != BRCMF_WD_POLL_MS) { + if (bus->wd_timer_valid == true) + /* Stop timer and restart at new value */ + del_timer_sync(&bus->timer); + + /* Create timer again when watchdog period is + dynamically changed or in the first instance + */ + bus->timer.expires = + jiffies + BRCMF_WD_POLL_MS * HZ / 1000; + add_timer(&bus->timer); + + } else { + /* Re arm the timer, at last watchdog period */ + mod_timer(&bus->timer, + jiffies + BRCMF_WD_POLL_MS * HZ / 1000); + } + + bus->wd_timer_valid = true; + bus->save_ms = wdtick; + } +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h new file mode 100644 index 000000000000..726fa8981113 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_SDH_H_ +#define _BRCM_SDH_H_ + +#include <linux/skbuff.h> + +#define SDIO_FUNC_0 0 +#define SDIO_FUNC_1 1 +#define SDIO_FUNC_2 2 + +#define SDIOD_FBR_SIZE 0x100 + +/* io_en */ +#define SDIO_FUNC_ENABLE_1 0x02 +#define SDIO_FUNC_ENABLE_2 0x04 + +/* io_rdys */ +#define SDIO_FUNC_READY_1 0x02 +#define SDIO_FUNC_READY_2 0x04 + +/* intr_status */ +#define INTR_STATUS_FUNC1 0x2 +#define INTR_STATUS_FUNC2 0x4 + +/* Maximum number of I/O funcs */ +#define SDIOD_MAX_IOFUNCS 7 + +/* as of sdiod rev 0, supports 3 functions */ +#define SBSDIO_NUM_FUNCTION 3 + +/* function 1 miscellaneous registers */ + +/* sprom command and status */ +#define SBSDIO_SPROM_CS 0x10000 +/* sprom info register */ +#define SBSDIO_SPROM_INFO 0x10001 +/* sprom indirect access data byte 0 */ +#define SBSDIO_SPROM_DATA_LOW 0x10002 +/* sprom indirect access data byte 1 */ +#define SBSDIO_SPROM_DATA_HIGH 0x10003 +/* sprom indirect access addr byte 0 */ +#define SBSDIO_SPROM_ADDR_LOW 0x10004 +/* sprom indirect access addr byte 0 */ +#define SBSDIO_SPROM_ADDR_HIGH 0x10005 +/* xtal_pu (gpio) output */ +#define SBSDIO_CHIP_CTRL_DATA 0x10006 +/* xtal_pu (gpio) enable */ +#define SBSDIO_CHIP_CTRL_EN 0x10007 +/* rev < 7, watermark for sdio device */ +#define SBSDIO_WATERMARK 0x10008 +/* control busy signal generation */ +#define SBSDIO_DEVICE_CTL 0x10009 + +/* SB Address Window Low (b15) */ +#define SBSDIO_FUNC1_SBADDRLOW 0x1000A +/* SB Address Window Mid (b23:b16) */ +#define SBSDIO_FUNC1_SBADDRMID 0x1000B +/* SB Address Window High (b31:b24) */ +#define SBSDIO_FUNC1_SBADDRHIGH 0x1000C +/* Frame Control (frame term/abort) */ +#define SBSDIO_FUNC1_FRAMECTRL 0x1000D +/* ChipClockCSR (ALP/HT ctl/status) */ +#define SBSDIO_FUNC1_CHIPCLKCSR 0x1000E +/* SdioPullUp (on cmd, d0-d2) */ +#define SBSDIO_FUNC1_SDIOPULLUP 0x1000F +/* Write Frame Byte Count Low */ +#define SBSDIO_FUNC1_WFRAMEBCLO 0x10019 +/* Write Frame Byte Count High */ +#define SBSDIO_FUNC1_WFRAMEBCHI 0x1001A +/* Read Frame Byte Count Low */ +#define SBSDIO_FUNC1_RFRAMEBCLO 0x1001B +/* Read Frame Byte Count High */ +#define SBSDIO_FUNC1_RFRAMEBCHI 0x1001C + +#define SBSDIO_FUNC1_MISC_REG_START 0x10000 /* f1 misc register start */ +#define SBSDIO_FUNC1_MISC_REG_LIMIT 0x1001C /* f1 misc register end */ + +/* function 1 OCP space */ + +/* sb offset addr is <= 15 bits, 32k */ +#define SBSDIO_SB_OFT_ADDR_MASK 0x07FFF +#define SBSDIO_SB_OFT_ADDR_LIMIT 0x08000 +/* with b15, maps to 32-bit SB access */ +#define SBSDIO_SB_ACCESS_2_4B_FLAG 0x08000 + +/* valid bits in SBSDIO_FUNC1_SBADDRxxx regs */ + +#define SBSDIO_SBADDRLOW_MASK 0x80 /* Valid bits in SBADDRLOW */ +#define SBSDIO_SBADDRMID_MASK 0xff /* Valid bits in SBADDRMID */ +#define SBSDIO_SBADDRHIGH_MASK 0xffU /* Valid bits in SBADDRHIGH */ +/* Address bits from SBADDR regs */ +#define SBSDIO_SBWINDOW_MASK 0xffff8000 + +#define SDIOH_READ 0 /* Read request */ +#define SDIOH_WRITE 1 /* Write request */ + +#define SDIOH_DATA_FIX 0 /* Fixed addressing */ +#define SDIOH_DATA_INC 1 /* Incremental addressing */ + +/* internal return code */ +#define SUCCESS 0 +#define ERROR 1 + +struct brcmf_sdreg { + int func; + int offset; + int value; +}; + +struct brcmf_sdio_dev { + struct sdio_func *func[SDIO_MAX_FUNCS]; + u8 num_funcs; /* Supported funcs on client */ + u32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; + u32 sbwad; /* Save backplane window address */ + bool regfail; /* status of last reg_r/w call */ + void *bus; + atomic_t suspend; /* suspend flag */ + wait_queue_head_t request_byte_wait; + wait_queue_head_t request_word_wait; + wait_queue_head_t request_packet_wait; + wait_queue_head_t request_buffer_wait; + +}; + +/* Register/deregister device interrupt handler. */ +extern int +brcmf_sdcard_intr_reg(struct brcmf_sdio_dev *sdiodev); + +extern int brcmf_sdcard_intr_dereg(struct brcmf_sdio_dev *sdiodev); + +/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). + * fn: function number + * addr: unmodified SDIO-space address + * data: data byte to write + * err: pointer to error code (or NULL) + */ +extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func, + u32 addr, int *err); +extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func, + u32 addr, u8 data, int *err); + +/* Synchronous access to device (client) core registers via CMD53 to F1. + * addr: backplane address (i.e. >= regsva from attach) + * size: register width in bytes (2 or 4) + * data: data for register write + */ +extern u32 +brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size); + +extern u32 +brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size, + u32 data); + +/* Indicate if last reg read/write failed */ +extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev); + +/* Buffer transfer to/from device (client) core via cmd53. + * fn: function number + * addr: backplane address (i.e. >= regsva from attach) + * flags: backplane width, address increment, sync/async + * buf: pointer to memory data buffer + * nbytes: number of bytes to transfer to/from buf + * pkt: pointer to packet associated with buf (if any) + * complete: callback function for command completion (async only) + * handle: handle for completion callback (first arg in callback) + * Returns 0 or error code. + * NOTE: Async operation is not currently supported. + */ +extern int +brcmf_sdcard_send_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); +extern int +brcmf_sdcard_recv_buf(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn, + uint flags, u8 *buf, uint nbytes, struct sk_buff *pkt); + +/* Flags bits */ + +/* Four-byte target (backplane) width (vs. two-byte) */ +#define SDIO_REQ_4BYTE 0x1 +/* Fixed address (FIFO) (vs. incrementing address) */ +#define SDIO_REQ_FIXED 0x2 +/* Async request (vs. sync request) */ +#define SDIO_REQ_ASYNC 0x4 + +/* Read/write to memory block (F1, no FIFO) via CMD53 (sync only). + * rw: read or write (0/1) + * addr: direct SDIO address + * buf: pointer to memory data buffer + * nbytes: number of bytes to transfer to/from buf + * Returns 0 or error code. + */ +extern int brcmf_sdcard_rwdata(struct brcmf_sdio_dev *sdiodev, uint rw, + u32 addr, u8 *buf, uint nbytes); + +/* Issue an abort to the specified function */ +extern int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn); + +/* platform specific/high level functions */ +extern int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev); +extern int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev); + +extern int brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, + u32 address); + +/* attach, return handler on success, NULL if failed. + * The handler shall be provided by all subsequent calls. No local cache + * cfghdl points to the starting address of pci device mapped memory + */ +extern int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev); +extern void brcmf_sdioh_detach(struct brcmf_sdio_dev *sdiodev); + +/* read or write one byte using cmd52 */ +extern int brcmf_sdioh_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, + uint fnc, uint addr, u8 *byte); + +/* read or write 2/4 bytes using cmd53 */ +extern int +brcmf_sdioh_request_word(struct brcmf_sdio_dev *sdiodev, + uint rw, uint fnc, uint addr, + u32 *word, uint nbyte); + +/* read or write any buffer using cmd53 */ +extern int +brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, + uint fix_inc, uint rw, uint fnc_num, + u32 addr, uint regwidth, + u32 buflen, u8 *buffer, struct sk_buff *pkt); + +/* Watchdog timer interface for pm ops */ +extern void brcmf_sdio_wdtmr_enable(struct brcmf_sdio_dev *sdiodev, + bool enable); + +extern void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype, + u32 regsva, struct brcmf_sdio_dev *sdiodev); +extern void brcmf_sdbrcm_disconnect(void *ptr); +extern void brcmf_sdbrcm_isr(void *arg); +#endif /* _BRCM_SDH_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c new file mode 100644 index 000000000000..5eddabe5228a --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -0,0 +1,3868 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +/* Toplevel file. Relies on dhd_linux.c to send commands to the dongle. */ + +#include <linux/kernel.h> +#include <linux/if_arp.h> +#include <linux/sched.h> +#include <linux/kthread.h> +#include <linux/netdevice.h> +#include <linux/bitops.h> +#include <linux/etherdevice.h> +#include <linux/ieee80211.h> +#include <linux/uaccess.h> +#include <net/cfg80211.h> + +#include <brcmu_utils.h> +#include <defs.h> +#include <brcmu_wifi.h> +#include "dhd.h" +#include "wl_cfg80211.h" + +#define BRCMF_ASSOC_PARAMS_FIXED_SIZE \ + (sizeof(struct brcmf_assoc_params_le) - sizeof(u16)) + +static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; + +static u32 brcmf_dbg_level = WL_DBG_ERR; + +static void brcmf_set_drvdata(struct brcmf_cfg80211_dev *dev, void *data) +{ + dev->driver_data = data; +} + +static void *brcmf_get_drvdata(struct brcmf_cfg80211_dev *dev) +{ + void *data = NULL; + + if (dev) + data = dev->driver_data; + return data; +} + +static +struct brcmf_cfg80211_priv *brcmf_priv_get(struct brcmf_cfg80211_dev *cfg_dev) +{ + struct brcmf_cfg80211_iface *ci = brcmf_get_drvdata(cfg_dev); + return ci->cfg_priv; +} + +static bool check_sys_up(struct wiphy *wiphy) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) { + WL_INFO("device is not ready : status (%d)\n", + (int)cfg_priv->status); + return false; + } + return true; +} + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define CHAN5G(_channel, _flags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + (5 * (_channel)), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define RATE_TO_BASE100KBPS(rate) (((rate) * 10) / 2) +#define RATETAB_ENT(_rateid, _flags) \ + { \ + .bitrate = RATE_TO_BASE100KBPS(_rateid), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ + } + +static struct ieee80211_rate __wl_rates[] = { + RATETAB_ENT(BRCM_RATE_1M, 0), + RATETAB_ENT(BRCM_RATE_2M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(BRCM_RATE_5M5, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(BRCM_RATE_11M, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(BRCM_RATE_6M, 0), + RATETAB_ENT(BRCM_RATE_9M, 0), + RATETAB_ENT(BRCM_RATE_12M, 0), + RATETAB_ENT(BRCM_RATE_18M, 0), + RATETAB_ENT(BRCM_RATE_24M, 0), + RATETAB_ENT(BRCM_RATE_36M, 0), + RATETAB_ENT(BRCM_RATE_48M, 0), + RATETAB_ENT(BRCM_RATE_54M, 0), +}; + +#define wl_a_rates (__wl_rates + 4) +#define wl_a_rates_size 8 +#define wl_g_rates (__wl_rates + 0) +#define wl_g_rates_size 12 + +static struct ieee80211_channel __wl_2ghz_channels[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static struct ieee80211_channel __wl_5ghz_a_channels[] = { + CHAN5G(34, 0), CHAN5G(36, 0), + CHAN5G(38, 0), CHAN5G(40, 0), + CHAN5G(42, 0), CHAN5G(44, 0), + CHAN5G(46, 0), CHAN5G(48, 0), + CHAN5G(52, 0), CHAN5G(56, 0), + CHAN5G(60, 0), CHAN5G(64, 0), + CHAN5G(100, 0), CHAN5G(104, 0), + CHAN5G(108, 0), CHAN5G(112, 0), + CHAN5G(116, 0), CHAN5G(120, 0), + CHAN5G(124, 0), CHAN5G(128, 0), + CHAN5G(132, 0), CHAN5G(136, 0), + CHAN5G(140, 0), CHAN5G(149, 0), + CHAN5G(153, 0), CHAN5G(157, 0), + CHAN5G(161, 0), CHAN5G(165, 0), + CHAN5G(184, 0), CHAN5G(188, 0), + CHAN5G(192, 0), CHAN5G(196, 0), + CHAN5G(200, 0), CHAN5G(204, 0), + CHAN5G(208, 0), CHAN5G(212, 0), + CHAN5G(216, 0), +}; + +static struct ieee80211_channel __wl_5ghz_n_channels[] = { + CHAN5G(32, 0), CHAN5G(34, 0), + CHAN5G(36, 0), CHAN5G(38, 0), + CHAN5G(40, 0), CHAN5G(42, 0), + CHAN5G(44, 0), CHAN5G(46, 0), + CHAN5G(48, 0), CHAN5G(50, 0), + CHAN5G(52, 0), CHAN5G(54, 0), + CHAN5G(56, 0), CHAN5G(58, 0), + CHAN5G(60, 0), CHAN5G(62, 0), + CHAN5G(64, 0), CHAN5G(66, 0), + CHAN5G(68, 0), CHAN5G(70, 0), + CHAN5G(72, 0), CHAN5G(74, 0), + CHAN5G(76, 0), CHAN5G(78, 0), + CHAN5G(80, 0), CHAN5G(82, 0), + CHAN5G(84, 0), CHAN5G(86, 0), + CHAN5G(88, 0), CHAN5G(90, 0), + CHAN5G(92, 0), CHAN5G(94, 0), + CHAN5G(96, 0), CHAN5G(98, 0), + CHAN5G(100, 0), CHAN5G(102, 0), + CHAN5G(104, 0), CHAN5G(106, 0), + CHAN5G(108, 0), CHAN5G(110, 0), + CHAN5G(112, 0), CHAN5G(114, 0), + CHAN5G(116, 0), CHAN5G(118, 0), + CHAN5G(120, 0), CHAN5G(122, 0), + CHAN5G(124, 0), CHAN5G(126, 0), + CHAN5G(128, 0), CHAN5G(130, 0), + CHAN5G(132, 0), CHAN5G(134, 0), + CHAN5G(136, 0), CHAN5G(138, 0), + CHAN5G(140, 0), CHAN5G(142, 0), + CHAN5G(144, 0), CHAN5G(145, 0), + CHAN5G(146, 0), CHAN5G(147, 0), + CHAN5G(148, 0), CHAN5G(149, 0), + CHAN5G(150, 0), CHAN5G(151, 0), + CHAN5G(152, 0), CHAN5G(153, 0), + CHAN5G(154, 0), CHAN5G(155, 0), + CHAN5G(156, 0), CHAN5G(157, 0), + CHAN5G(158, 0), CHAN5G(159, 0), + CHAN5G(160, 0), CHAN5G(161, 0), + CHAN5G(162, 0), CHAN5G(163, 0), + CHAN5G(164, 0), CHAN5G(165, 0), + CHAN5G(166, 0), CHAN5G(168, 0), + CHAN5G(170, 0), CHAN5G(172, 0), + CHAN5G(174, 0), CHAN5G(176, 0), + CHAN5G(178, 0), CHAN5G(180, 0), + CHAN5G(182, 0), CHAN5G(184, 0), + CHAN5G(186, 0), CHAN5G(188, 0), + CHAN5G(190, 0), CHAN5G(192, 0), + CHAN5G(194, 0), CHAN5G(196, 0), + CHAN5G(198, 0), CHAN5G(200, 0), + CHAN5G(202, 0), CHAN5G(204, 0), + CHAN5G(206, 0), CHAN5G(208, 0), + CHAN5G(210, 0), CHAN5G(212, 0), + CHAN5G(214, 0), CHAN5G(216, 0), + CHAN5G(218, 0), CHAN5G(220, 0), + CHAN5G(222, 0), CHAN5G(224, 0), + CHAN5G(226, 0), CHAN5G(228, 0), +}; + +static struct ieee80211_supported_band __wl_band_2ghz = { + .band = IEEE80211_BAND_2GHZ, + .channels = __wl_2ghz_channels, + .n_channels = ARRAY_SIZE(__wl_2ghz_channels), + .bitrates = wl_g_rates, + .n_bitrates = wl_g_rates_size, +}; + +static struct ieee80211_supported_band __wl_band_5ghz_a = { + .band = IEEE80211_BAND_5GHZ, + .channels = __wl_5ghz_a_channels, + .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), + .bitrates = wl_a_rates, + .n_bitrates = wl_a_rates_size, +}; + +static struct ieee80211_supported_band __wl_band_5ghz_n = { + .band = IEEE80211_BAND_5GHZ, + .channels = __wl_5ghz_n_channels, + .n_channels = ARRAY_SIZE(__wl_5ghz_n_channels), + .bitrates = wl_a_rates, + .n_bitrates = wl_a_rates_size, +}; + +static const u32 __wl_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_AES_CMAC, +}; + +/* tag_ID/length/value_buffer tuple */ +struct brcmf_tlv { + u8 id; + u8 len; + u8 data[1]; +}; + +/* Quarter dBm units to mW + * Table starts at QDBM_OFFSET, so the first entry is mW for qdBm=153 + * Table is offset so the last entry is largest mW value that fits in + * a u16. + */ + +#define QDBM_OFFSET 153 /* Offset for first entry */ +#define QDBM_TABLE_LEN 40 /* Table size */ + +/* Smallest mW value that will round up to the first table entry, QDBM_OFFSET. + * Value is ( mW(QDBM_OFFSET - 1) + mW(QDBM_OFFSET) ) / 2 + */ +#define QDBM_TABLE_LOW_BOUND 6493 /* Low bound */ + +/* Largest mW value that will round down to the last table entry, + * QDBM_OFFSET + QDBM_TABLE_LEN-1. + * Value is ( mW(QDBM_OFFSET + QDBM_TABLE_LEN - 1) + + * mW(QDBM_OFFSET + QDBM_TABLE_LEN) ) / 2. + */ +#define QDBM_TABLE_HIGH_BOUND 64938 /* High bound */ + +static const u16 nqdBm_to_mW_map[QDBM_TABLE_LEN] = { +/* qdBm: +0 +1 +2 +3 +4 +5 +6 +7 */ +/* 153: */ 6683, 7079, 7499, 7943, 8414, 8913, 9441, 10000, +/* 161: */ 10593, 11220, 11885, 12589, 13335, 14125, 14962, 15849, +/* 169: */ 16788, 17783, 18836, 19953, 21135, 22387, 23714, 25119, +/* 177: */ 26607, 28184, 29854, 31623, 33497, 35481, 37584, 39811, +/* 185: */ 42170, 44668, 47315, 50119, 53088, 56234, 59566, 63096 +}; + +static u16 brcmf_qdbm_to_mw(u8 qdbm) +{ + uint factor = 1; + int idx = qdbm - QDBM_OFFSET; + + if (idx >= QDBM_TABLE_LEN) + /* clamp to max u16 mW value */ + return 0xFFFF; + + /* scale the qdBm index up to the range of the table 0-40 + * where an offset of 40 qdBm equals a factor of 10 mW. + */ + while (idx < 0) { + idx += 40; + factor *= 10; + } + + /* return the mW value scaled down to the correct factor of 10, + * adding in factor/2 to get proper rounding. + */ + return (nqdBm_to_mW_map[idx] + factor / 2) / factor; +} + +static u8 brcmf_mw_to_qdbm(u16 mw) +{ + u8 qdbm; + int offset; + uint mw_uint = mw; + uint boundary; + + /* handle boundary case */ + if (mw_uint <= 1) + return 0; + + offset = QDBM_OFFSET; + + /* move mw into the range of the table */ + while (mw_uint < QDBM_TABLE_LOW_BOUND) { + mw_uint *= 10; + offset -= 40; + } + + for (qdbm = 0; qdbm < QDBM_TABLE_LEN - 1; qdbm++) { + boundary = nqdBm_to_mW_map[qdbm] + (nqdBm_to_mW_map[qdbm + 1] - + nqdBm_to_mW_map[qdbm]) / 2; + if (mw_uint < boundary) + break; + } + + qdbm += (u8) offset; + + return qdbm; +} + +/* function for reading/writing a single u32 from/to the dongle */ +static int +brcmf_exec_dcmd_u32(struct net_device *ndev, u32 cmd, u32 *par) +{ + int err; + __le32 par_le = cpu_to_le32(*par); + + err = brcmf_exec_dcmd(ndev, cmd, &par_le, sizeof(__le32)); + *par = le32_to_cpu(par_le); + + return err; +} + +static void convert_key_from_CPU(struct brcmf_wsec_key *key, + struct brcmf_wsec_key_le *key_le) +{ + key_le->index = cpu_to_le32(key->index); + key_le->len = cpu_to_le32(key->len); + key_le->algo = cpu_to_le32(key->algo); + key_le->flags = cpu_to_le32(key->flags); + key_le->rxiv.hi = cpu_to_le32(key->rxiv.hi); + key_le->rxiv.lo = cpu_to_le16(key->rxiv.lo); + key_le->iv_initialized = cpu_to_le32(key->iv_initialized); + memcpy(key_le->data, key->data, sizeof(key->data)); + memcpy(key_le->ea, key->ea, sizeof(key->ea)); +} + +static int send_key_to_dongle(struct net_device *ndev, + struct brcmf_wsec_key *key) +{ + int err; + struct brcmf_wsec_key_le key_le; + + convert_key_from_CPU(key, &key_le); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, sizeof(key_le)); + if (err) + WL_ERR("WLC_SET_KEY error (%d)\n", err); + return err; +} + +static s32 +brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct wireless_dev *wdev; + s32 infra = 0; + s32 err = 0; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + switch (type) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + WL_ERR("type (%d) : currently we do not support this type\n", + type); + return -EOPNOTSUPP; + case NL80211_IFTYPE_ADHOC: + cfg_priv->conf->mode = WL_MODE_IBSS; + infra = 0; + break; + case NL80211_IFTYPE_STATION: + cfg_priv->conf->mode = WL_MODE_BSS; + infra = 1; + break; + default: + err = -EINVAL; + goto done; + } + + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); + if (err) { + WL_ERR("WLC_SET_INFRA error (%d)\n", err); + err = -EAGAIN; + } else { + wdev = ndev->ieee80211_ptr; + wdev->iftype = type; + } + + WL_INFO("IF Type = %s\n", + (cfg_priv->conf->mode == WL_MODE_IBSS) ? "Adhoc" : "Infra"); + +done: + WL_TRACE("Exit\n"); + + return err; +} + +static s32 brcmf_dev_intvar_set(struct net_device *ndev, s8 *name, s32 val) +{ + s8 buf[BRCMF_DCMD_SMLEN]; + u32 len; + s32 err = 0; + __le32 val_le; + + val_le = cpu_to_le32(val); + len = brcmf_c_mkiovar(name, (char *)(&val_le), sizeof(val_le), buf, + sizeof(buf)); + BUG_ON(!len); + + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, buf, len); + if (err) + WL_ERR("error (%d)\n", err); + + return err; +} + +static s32 +brcmf_dev_intvar_get(struct net_device *ndev, s8 *name, s32 *retval) +{ + union { + s8 buf[BRCMF_DCMD_SMLEN]; + __le32 val; + } var; + u32 len; + u32 data_null; + s32 err = 0; + + len = + brcmf_c_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), + sizeof(var.buf)); + BUG_ON(!len); + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, &var, len); + if (err) + WL_ERR("error (%d)\n", err); + + *retval = le32_to_cpu(var.val); + + return err; +} + +static void brcmf_set_mpc(struct net_device *ndev, int mpc) +{ + s32 err = 0; + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + + if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { + err = brcmf_dev_intvar_set(ndev, "mpc", mpc); + if (err) { + WL_ERR("fail to set mpc\n"); + return; + } + WL_INFO("MPC : %d\n", mpc); + } +} + +static void wl_iscan_prep(struct brcmf_scan_params_le *params_le, + struct brcmf_ssid *ssid) +{ + memcpy(params_le->bssid, ether_bcast, ETH_ALEN); + params_le->bss_type = DOT11_BSSTYPE_ANY; + params_le->scan_type = 0; + params_le->channel_num = 0; + params_le->nprobes = cpu_to_le32(-1); + params_le->active_time = cpu_to_le32(-1); + params_le->passive_time = cpu_to_le32(-1); + params_le->home_time = cpu_to_le32(-1); + if (ssid && ssid->SSID_len) + memcpy(¶ms_le->ssid_le, ssid, sizeof(struct brcmf_ssid)); +} + +static s32 +brcmf_dev_iovar_setbuf(struct net_device *ndev, s8 * iovar, void *param, + s32 paramlen, void *bufptr, s32 buflen) +{ + s32 iolen; + + iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen); + BUG_ON(!iolen); + + return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, bufptr, iolen); +} + +static s32 +brcmf_dev_iovar_getbuf(struct net_device *ndev, s8 * iovar, void *param, + s32 paramlen, void *bufptr, s32 buflen) +{ + s32 iolen; + + iolen = brcmf_c_mkiovar(iovar, param, paramlen, bufptr, buflen); + BUG_ON(!iolen); + + return brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, bufptr, buflen); +} + +static s32 +brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan, + struct brcmf_ssid *ssid, u16 action) +{ + s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE + + offsetof(struct brcmf_iscan_params_le, params_le); + struct brcmf_iscan_params_le *params; + s32 err = 0; + + if (ssid && ssid->SSID_len) + params_size += sizeof(struct brcmf_ssid); + params = kzalloc(params_size, GFP_KERNEL); + if (!params) + return -ENOMEM; + BUG_ON(params_size >= BRCMF_DCMD_SMLEN); + + wl_iscan_prep(¶ms->params_le, ssid); + + params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION); + params->action = cpu_to_le16(action); + params->scan_duration = cpu_to_le16(0); + + err = brcmf_dev_iovar_setbuf(iscan->ndev, "iscan", params, params_size, + iscan->dcmd_buf, BRCMF_DCMD_SMLEN); + if (err) { + if (err == -EBUSY) + WL_INFO("system busy : iscan canceled\n"); + else + WL_ERR("error (%d)\n", err); + } + + kfree(params); + return err; +} + +static s32 brcmf_do_iscan(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct brcmf_ssid ssid; + __le32 passive_scan; + s32 err = 0; + + /* Broadcast scan by default */ + memset(&ssid, 0, sizeof(ssid)); + + iscan->state = WL_ISCAN_STATE_SCANING; + + passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1); + err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan)); + if (err) { + WL_ERR("error (%d)\n", err); + return err; + } + brcmf_set_mpc(ndev, 0); + cfg_priv->iscan_kickstart = true; + err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START); + if (err) { + brcmf_set_mpc(ndev, 1); + cfg_priv->iscan_kickstart = false; + return err; + } + mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + iscan->timer_on = 1; + return err; +} + +static s32 +__brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request, + struct cfg80211_ssid *this_ssid) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct cfg80211_ssid *ssids; + struct brcmf_cfg80211_scan_req *sr = cfg_priv->scan_req_int; + __le32 passive_scan; + bool iscan_req; + bool spec_scan; + s32 err = 0; + u32 SSID_len; + + if (test_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + WL_ERR("Scanning already : status (%lu)\n", cfg_priv->status); + return -EAGAIN; + } + if (test_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status)) { + WL_ERR("Scanning being aborted : status (%lu)\n", + cfg_priv->status); + return -EAGAIN; + } + if (test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { + WL_ERR("Connecting : status (%lu)\n", + cfg_priv->status); + return -EAGAIN; + } + + iscan_req = false; + spec_scan = false; + if (request) { + /* scan bss */ + ssids = request->ssids; + if (cfg_priv->iscan_on && (!ssids || !ssids->ssid_len)) + iscan_req = true; + } else { + /* scan in ibss */ + /* we don't do iscan in ibss */ + ssids = this_ssid; + } + + cfg_priv->scan_request = request; + set_bit(WL_STATUS_SCANNING, &cfg_priv->status); + if (iscan_req) { + err = brcmf_do_iscan(cfg_priv); + if (!err) + return err; + else + goto scan_out; + } else { + WL_SCAN("ssid \"%s\", ssid_len (%d)\n", + ssids->ssid, ssids->ssid_len); + memset(&sr->ssid_le, 0, sizeof(sr->ssid_le)); + SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len); + sr->ssid_le.SSID_len = cpu_to_le32(0); + if (SSID_len) { + memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len); + sr->ssid_le.SSID_len = cpu_to_le32(SSID_len); + spec_scan = true; + } else { + WL_SCAN("Broadcast scan\n"); + } + + passive_scan = cfg_priv->active_scan ? 0 : cpu_to_le32(1); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_PASSIVE_SCAN, + &passive_scan, sizeof(passive_scan)); + if (err) { + WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err); + goto scan_out; + } + brcmf_set_mpc(ndev, 0); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN, &sr->ssid_le, + sizeof(sr->ssid_le)); + if (err) { + if (err == -EBUSY) + WL_INFO("system busy : scan for \"%s\" " + "canceled\n", sr->ssid_le.SSID); + else + WL_ERR("WLC_SCAN error (%d)\n", err); + + brcmf_set_mpc(ndev, 1); + goto scan_out; + } + } + + return 0; + +scan_out: + clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); + cfg_priv->scan_request = NULL; + return err; +} + +static s32 +brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_scan_request *request) +{ + s32 err = 0; + + WL_TRACE("Enter\n"); + + if (!check_sys_up(wiphy)) + return -EIO; + + err = __brcmf_cfg80211_scan(wiphy, ndev, request, NULL); + if (err) + WL_ERR("scan error (%d)\n", err); + + WL_TRACE("Exit\n"); + return err; +} + +static s32 brcmf_set_rts(struct net_device *ndev, u32 rts_threshold) +{ + s32 err = 0; + + err = brcmf_dev_intvar_set(ndev, "rtsthresh", rts_threshold); + if (err) + WL_ERR("Error (%d)\n", err); + + return err; +} + +static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold) +{ + s32 err = 0; + + err = brcmf_dev_intvar_set(ndev, "fragthresh", frag_threshold); + if (err) + WL_ERR("Error (%d)\n", err); + + return err; +} + +static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l) +{ + s32 err = 0; + u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL); + + err = brcmf_exec_dcmd_u32(ndev, cmd, &retry); + if (err) { + WL_ERR("cmd (%d) , error (%d)\n", cmd, err); + return err; + } + return err; +} + +static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg_priv); + s32 err = 0; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD && + (cfg_priv->conf->rts_threshold != wiphy->rts_threshold)) { + cfg_priv->conf->rts_threshold = wiphy->rts_threshold; + err = brcmf_set_rts(ndev, cfg_priv->conf->rts_threshold); + if (!err) + goto done; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD && + (cfg_priv->conf->frag_threshold != wiphy->frag_threshold)) { + cfg_priv->conf->frag_threshold = wiphy->frag_threshold; + err = brcmf_set_frag(ndev, cfg_priv->conf->frag_threshold); + if (!err) + goto done; + } + if (changed & WIPHY_PARAM_RETRY_LONG + && (cfg_priv->conf->retry_long != wiphy->retry_long)) { + cfg_priv->conf->retry_long = wiphy->retry_long; + err = brcmf_set_retry(ndev, cfg_priv->conf->retry_long, true); + if (!err) + goto done; + } + if (changed & WIPHY_PARAM_RETRY_SHORT + && (cfg_priv->conf->retry_short != wiphy->retry_short)) { + cfg_priv->conf->retry_short = wiphy->retry_short; + err = brcmf_set_retry(ndev, cfg_priv->conf->retry_short, false); + if (!err) + goto done; + } + +done: + WL_TRACE("Exit\n"); + return err; +} + +static void *brcmf_read_prof(struct brcmf_cfg80211_priv *cfg_priv, s32 item) +{ + switch (item) { + case WL_PROF_SEC: + return &cfg_priv->profile->sec; + case WL_PROF_BSSID: + return &cfg_priv->profile->bssid; + case WL_PROF_SSID: + return &cfg_priv->profile->ssid; + } + WL_ERR("invalid item (%d)\n", item); + return NULL; +} + +static s32 +brcmf_update_prof(struct brcmf_cfg80211_priv *cfg_priv, + const struct brcmf_event_msg *e, void *data, s32 item) +{ + s32 err = 0; + struct brcmf_ssid *ssid; + + switch (item) { + case WL_PROF_SSID: + ssid = (struct brcmf_ssid *) data; + memset(cfg_priv->profile->ssid.SSID, 0, + sizeof(cfg_priv->profile->ssid.SSID)); + memcpy(cfg_priv->profile->ssid.SSID, + ssid->SSID, ssid->SSID_len); + cfg_priv->profile->ssid.SSID_len = ssid->SSID_len; + break; + case WL_PROF_BSSID: + if (data) + memcpy(cfg_priv->profile->bssid, data, ETH_ALEN); + else + memset(cfg_priv->profile->bssid, 0, ETH_ALEN); + break; + case WL_PROF_SEC: + memcpy(&cfg_priv->profile->sec, data, + sizeof(cfg_priv->profile->sec)); + break; + case WL_PROF_BEACONINT: + cfg_priv->profile->beacon_interval = *(u16 *)data; + break; + case WL_PROF_DTIMPERIOD: + cfg_priv->profile->dtim_period = *(u8 *)data; + break; + default: + WL_ERR("unsupported item (%d)\n", item); + err = -EOPNOTSUPP; + break; + } + + return err; +} + +static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof) +{ + memset(prof, 0, sizeof(*prof)); +} + +static void brcmf_ch_to_chanspec(int ch, struct brcmf_join_params *join_params, + size_t *join_params_size) +{ + u16 chanspec = 0; + + if (ch != 0) { + if (ch <= CH_MAX_2G_CHANNEL) + chanspec |= WL_CHANSPEC_BAND_2G; + else + chanspec |= WL_CHANSPEC_BAND_5G; + + chanspec |= WL_CHANSPEC_BW_20; + chanspec |= WL_CHANSPEC_CTL_SB_NONE; + + *join_params_size += BRCMF_ASSOC_PARAMS_FIXED_SIZE + + sizeof(u16); + + chanspec |= (ch & WL_CHANSPEC_CHAN_MASK); + join_params->params_le.chanspec_list[0] = cpu_to_le16(chanspec); + join_params->params_le.chanspec_num = cpu_to_le32(1); + + WL_CONN("join_params->params.chanspec_list[0]= %#X," + "channel %d, chanspec %#X\n", + chanspec, ch, chanspec); + } +} + +static void brcmf_link_down(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct net_device *ndev = NULL; + s32 err = 0; + + WL_TRACE("Enter\n"); + + if (cfg_priv->link_up) { + ndev = cfg_to_ndev(cfg_priv); + WL_INFO("Call WLC_DISASSOC to stop excess roaming\n "); + err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, NULL, 0); + if (err) + WL_ERR("WLC_DISASSOC failed (%d)\n", err); + cfg_priv->link_up = false; + } + WL_TRACE("Exit\n"); +} + +static s32 +brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_ibss_params *params) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_join_params join_params; + size_t join_params_size = 0; + s32 err = 0; + s32 wsec = 0; + s32 bcnprd; + struct brcmf_ssid ssid; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + if (params->ssid) + WL_CONN("SSID: %s\n", params->ssid); + else { + WL_CONN("SSID: NULL, Not supported\n"); + return -EOPNOTSUPP; + } + + set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + + if (params->bssid) + WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n", + params->bssid[0], params->bssid[1], params->bssid[2], + params->bssid[3], params->bssid[4], params->bssid[5]); + else + WL_CONN("No BSSID specified\n"); + + if (params->channel) + WL_CONN("channel: %d\n", params->channel->center_freq); + else + WL_CONN("no channel specified\n"); + + if (params->channel_fixed) + WL_CONN("fixed channel required\n"); + else + WL_CONN("no fixed channel required\n"); + + if (params->ie && params->ie_len) + WL_CONN("ie len: %d\n", params->ie_len); + else + WL_CONN("no ie specified\n"); + + if (params->beacon_interval) + WL_CONN("beacon interval: %d\n", params->beacon_interval); + else + WL_CONN("no beacon interval specified\n"); + + if (params->basic_rates) + WL_CONN("basic rates: %08X\n", params->basic_rates); + else + WL_CONN("no basic rates specified\n"); + + if (params->privacy) + WL_CONN("privacy required\n"); + else + WL_CONN("no privacy required\n"); + + /* Configure Privacy for starter */ + if (params->privacy) + wsec |= WEP_ENABLED; + + err = brcmf_dev_intvar_set(ndev, "wsec", wsec); + if (err) { + WL_ERR("wsec failed (%d)\n", err); + goto done; + } + + /* Configure Beacon Interval for starter */ + if (params->beacon_interval) + bcnprd = params->beacon_interval; + else + bcnprd = 100; + + err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_BCNPRD, &bcnprd); + if (err) { + WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err); + goto done; + } + + /* Configure required join parameter */ + memset(&join_params, 0, sizeof(struct brcmf_join_params)); + + /* SSID */ + ssid.SSID_len = min_t(u32, params->ssid_len, 32); + memcpy(ssid.SSID, params->ssid, ssid.SSID_len); + memcpy(join_params.ssid_le.SSID, params->ssid, ssid.SSID_len); + join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); + join_params_size = sizeof(join_params.ssid_le); + brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID); + + /* BSSID */ + if (params->bssid) { + memcpy(join_params.params_le.bssid, params->bssid, ETH_ALEN); + join_params_size = sizeof(join_params.ssid_le) + + BRCMF_ASSOC_PARAMS_FIXED_SIZE; + } else { + memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); + } + + brcmf_update_prof(cfg_priv, NULL, + &join_params.params_le.bssid, WL_PROF_BSSID); + + /* Channel */ + if (params->channel) { + u32 target_channel; + + cfg_priv->channel = + ieee80211_frequency_to_channel( + params->channel->center_freq); + if (params->channel_fixed) { + /* adding chanspec */ + brcmf_ch_to_chanspec(cfg_priv->channel, + &join_params, &join_params_size); + } + + /* set channel for starter */ + target_channel = cfg_priv->channel; + err = brcmf_exec_dcmd_u32(ndev, BRCM_SET_CHANNEL, + &target_channel); + if (err) { + WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err); + goto done; + } + } else + cfg_priv->channel = 0; + + cfg_priv->ibss_starter = false; + + + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, + &join_params, join_params_size); + if (err) { + WL_ERR("WLC_SET_SSID failed (%d)\n", err); + goto done; + } + +done: + if (err) + clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + s32 err = 0; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + brcmf_link_down(cfg_priv); + + WL_TRACE("Exit\n"); + + return err; +} + +static s32 brcmf_set_wpa_version(struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_security *sec; + s32 val = 0; + s32 err = 0; + + if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) + val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; + else if (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2) + val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; + else + val = WPA_AUTH_DISABLED; + WL_CONN("setting wpa_auth to 0x%0x\n", val); + err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); + if (err) { + WL_ERR("set wpa_auth failed (%d)\n", err); + return err; + } + sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec->wpa_versions = sme->crypto.wpa_versions; + return err; +} + +static s32 brcmf_set_auth_type(struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_security *sec; + s32 val = 0; + s32 err = 0; + + switch (sme->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + val = 0; + WL_CONN("open system\n"); + break; + case NL80211_AUTHTYPE_SHARED_KEY: + val = 1; + WL_CONN("shared key\n"); + break; + case NL80211_AUTHTYPE_AUTOMATIC: + val = 2; + WL_CONN("automatic\n"); + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + WL_CONN("network eap\n"); + default: + val = 2; + WL_ERR("invalid auth type (%d)\n", sme->auth_type); + break; + } + + err = brcmf_dev_intvar_set(ndev, "auth", val); + if (err) { + WL_ERR("set auth failed (%d)\n", err); + return err; + } + sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec->auth_type = sme->auth_type; + return err; +} + +static s32 +brcmf_set_set_cipher(struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_security *sec; + s32 pval = 0; + s32 gval = 0; + s32 err = 0; + + if (sme->crypto.n_ciphers_pairwise) { + switch (sme->crypto.ciphers_pairwise[0]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + pval = WEP_ENABLED; + break; + case WLAN_CIPHER_SUITE_TKIP: + pval = TKIP_ENABLED; + break; + case WLAN_CIPHER_SUITE_CCMP: + pval = AES_ENABLED; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + pval = AES_ENABLED; + break; + default: + WL_ERR("invalid cipher pairwise (%d)\n", + sme->crypto.ciphers_pairwise[0]); + return -EINVAL; + } + } + if (sme->crypto.cipher_group) { + switch (sme->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + gval = WEP_ENABLED; + break; + case WLAN_CIPHER_SUITE_TKIP: + gval = TKIP_ENABLED; + break; + case WLAN_CIPHER_SUITE_CCMP: + gval = AES_ENABLED; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + gval = AES_ENABLED; + break; + default: + WL_ERR("invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; + } + } + + WL_CONN("pval (%d) gval (%d)\n", pval, gval); + err = brcmf_dev_intvar_set(ndev, "wsec", pval | gval); + if (err) { + WL_ERR("error (%d)\n", err); + return err; + } + + sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; + sec->cipher_group = sme->crypto.cipher_group; + + return err; +} + +static s32 +brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_security *sec; + s32 val = 0; + s32 err = 0; + + if (sme->crypto.n_akm_suites) { + err = brcmf_dev_intvar_get(ndev, "wpa_auth", &val); + if (err) { + WL_ERR("could not get wpa_auth (%d)\n", err); + return err; + } + if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA_AUTH_PSK; + break; + default: + WL_ERR("invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; + } + } else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { + switch (sme->crypto.akm_suites[0]) { + case WLAN_AKM_SUITE_8021X: + val = WPA2_AUTH_UNSPECIFIED; + break; + case WLAN_AKM_SUITE_PSK: + val = WPA2_AUTH_PSK; + break; + default: + WL_ERR("invalid cipher group (%d)\n", + sme->crypto.cipher_group); + return -EINVAL; + } + } + + WL_CONN("setting wpa_auth to %d\n", val); + err = brcmf_dev_intvar_set(ndev, "wpa_auth", val); + if (err) { + WL_ERR("could not set wpa_auth (%d)\n", err); + return err; + } + } + sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + sec->wpa_auth = sme->crypto.akm_suites[0]; + + return err; +} + +static s32 +brcmf_set_wep_sharedkey(struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + struct brcmf_cfg80211_security *sec; + struct brcmf_wsec_key key; + s32 val; + s32 err = 0; + + WL_CONN("key len (%d)\n", sme->key_len); + + if (sme->key_len == 0) + return 0; + + sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + WL_CONN("wpa_versions 0x%x cipher_pairwise 0x%x\n", + sec->wpa_versions, sec->cipher_pairwise); + + if (sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) + return 0; + + if (sec->cipher_pairwise & + (WLAN_CIPHER_SUITE_WEP40 | WLAN_CIPHER_SUITE_WEP104)) { + memset(&key, 0, sizeof(key)); + key.len = (u32) sme->key_len; + key.index = (u32) sme->key_idx; + if (key.len > sizeof(key.data)) { + WL_ERR("Too long key length (%u)\n", key.len); + return -EINVAL; + } + memcpy(key.data, sme->key, key.len); + key.flags = BRCMF_PRIMARY_KEY; + switch (sec->cipher_pairwise) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + break; + default: + WL_ERR("Invalid algorithm (%d)\n", + sme->crypto.ciphers_pairwise[0]); + return -EINVAL; + } + /* Set the new key/index */ + WL_CONN("key length (%d) key index (%d) algo (%d)\n", + key.len, key.index, key.algo); + WL_CONN("key \"%s\"\n", key.data); + err = send_key_to_dongle(ndev, &key); + if (err) + return err; + + if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { + WL_CONN("set auth_type to shared key\n"); + val = 1; /* shared key */ + err = brcmf_dev_intvar_set(ndev, "auth", val); + if (err) { + WL_ERR("set auth failed (%d)\n", err); + return err; + } + } + } + return err; +} + +static s32 +brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_connect_params *sme) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct ieee80211_channel *chan = sme->channel; + struct brcmf_join_params join_params; + size_t join_params_size; + struct brcmf_ssid ssid; + + s32 err = 0; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + if (!sme->ssid) { + WL_ERR("Invalid ssid\n"); + return -EOPNOTSUPP; + } + + set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + + if (chan) { + cfg_priv->channel = + ieee80211_frequency_to_channel(chan->center_freq); + WL_CONN("channel (%d), center_req (%d)\n", + cfg_priv->channel, chan->center_freq); + } else + cfg_priv->channel = 0; + + WL_INFO("ie (%p), ie_len (%zd)\n", sme->ie, sme->ie_len); + + err = brcmf_set_wpa_version(ndev, sme); + if (err) { + WL_ERR("wl_set_wpa_version failed (%d)\n", err); + goto done; + } + + err = brcmf_set_auth_type(ndev, sme); + if (err) { + WL_ERR("wl_set_auth_type failed (%d)\n", err); + goto done; + } + + err = brcmf_set_set_cipher(ndev, sme); + if (err) { + WL_ERR("wl_set_set_cipher failed (%d)\n", err); + goto done; + } + + err = brcmf_set_key_mgmt(ndev, sme); + if (err) { + WL_ERR("wl_set_key_mgmt failed (%d)\n", err); + goto done; + } + + err = brcmf_set_wep_sharedkey(ndev, sme); + if (err) { + WL_ERR("brcmf_set_wep_sharedkey failed (%d)\n", err); + goto done; + } + + memset(&join_params, 0, sizeof(join_params)); + join_params_size = sizeof(join_params.ssid_le); + + ssid.SSID_len = min_t(u32, sizeof(ssid.SSID), sme->ssid_len); + memcpy(&join_params.ssid_le.SSID, sme->ssid, ssid.SSID_len); + memcpy(&ssid.SSID, sme->ssid, ssid.SSID_len); + join_params.ssid_le.SSID_len = cpu_to_le32(ssid.SSID_len); + brcmf_update_prof(cfg_priv, NULL, &ssid, WL_PROF_SSID); + + memcpy(join_params.params_le.bssid, ether_bcast, ETH_ALEN); + + if (ssid.SSID_len < IEEE80211_MAX_SSID_LEN) + WL_CONN("ssid \"%s\", len (%d)\n", + ssid.SSID, ssid.SSID_len); + + brcmf_ch_to_chanspec(cfg_priv->channel, + &join_params, &join_params_size); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SSID, + &join_params, join_params_size); + if (err) + WL_ERR("WLC_SET_SSID failed (%d)\n", err); + +done: + if (err) + clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, + u16 reason_code) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_scb_val_le scbval; + s32 err = 0; + + WL_TRACE("Enter. Reason code = %d\n", reason_code); + if (!check_sys_up(wiphy)) + return -EIO; + + clear_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + + memcpy(&scbval.ea, brcmf_read_prof(cfg_priv, WL_PROF_BSSID), ETH_ALEN); + scbval.val = cpu_to_le32(reason_code); + err = brcmf_exec_dcmd(ndev, BRCMF_C_DISASSOC, &scbval, + sizeof(struct brcmf_scb_val_le)); + if (err) + WL_ERR("error (%d)\n", err); + + cfg_priv->link_up = false; + + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, + enum nl80211_tx_power_setting type, s32 dbm) +{ + + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg_priv); + u16 txpwrmw; + s32 err = 0; + s32 disable = 0; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + switch (type) { + case NL80211_TX_POWER_AUTOMATIC: + break; + case NL80211_TX_POWER_LIMITED: + if (dbm < 0) { + WL_ERR("TX_POWER_LIMITED - dbm is negative\n"); + err = -EINVAL; + goto done; + } + break; + case NL80211_TX_POWER_FIXED: + if (dbm < 0) { + WL_ERR("TX_POWER_FIXED - dbm is negative\n"); + err = -EINVAL; + goto done; + } + break; + } + /* Make sure radio is off or on as far as software is concerned */ + disable = WL_RADIO_SW_DISABLE << 16; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_RADIO, &disable); + if (err) + WL_ERR("WLC_SET_RADIO error (%d)\n", err); + + if (dbm > 0xffff) + txpwrmw = 0xffff; + else + txpwrmw = (u16) dbm; + err = brcmf_dev_intvar_set(ndev, "qtxpower", + (s32) (brcmf_mw_to_qdbm(txpwrmw))); + if (err) + WL_ERR("qtxpower error (%d)\n", err); + cfg_priv->conf->tx_power = dbm; + +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg_priv); + s32 txpwrdbm; + u8 result; + s32 err = 0; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + err = brcmf_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); + if (err) { + WL_ERR("error (%d)\n", err); + goto done; + } + + result = (u8) (txpwrdbm & ~WL_TXPWR_OVERRIDE); + *dbm = (s32) brcmf_qdbm_to_mw(result); + +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_idx, bool unicast, bool multicast) +{ + u32 index; + u32 wsec; + s32 err = 0; + + WL_TRACE("Enter\n"); + WL_CONN("key index (%d)\n", key_idx); + if (!check_sys_up(wiphy)) + return -EIO; + + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec); + if (err) { + WL_ERR("WLC_GET_WSEC error (%d)\n", err); + goto done; + } + + if (wsec & WEP_ENABLED) { + /* Just select a new current key */ + index = key_idx; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_KEY_PRIMARY, + &index); + if (err) + WL_ERR("error (%d)\n", err); + } +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev, + u8 key_idx, const u8 *mac_addr, struct key_params *params) +{ + struct brcmf_wsec_key key; + struct brcmf_wsec_key_le key_le; + s32 err = 0; + + memset(&key, 0, sizeof(key)); + key.index = (u32) key_idx; + /* Instead of bcast for ea address for default wep keys, + driver needs it to be Null */ + if (!is_multicast_ether_addr(mac_addr)) + memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN); + key.len = (u32) params->key_len; + /* check for key index change */ + if (key.len == 0) { + /* key delete */ + err = send_key_to_dongle(ndev, &key); + if (err) + return err; + } else { + if (key.len > sizeof(key.data)) { + WL_ERR("Invalid key length (%d)\n", key.len); + return -EINVAL; + } + + WL_CONN("Setting the key index %d\n", key.index); + memcpy(key.data, params->key, key.len); + + if (params->cipher == WLAN_CIPHER_SUITE_TKIP) { + u8 keybuf[8]; + memcpy(keybuf, &key.data[24], sizeof(keybuf)); + memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); + memcpy(&key.data[16], keybuf, sizeof(keybuf)); + } + + /* if IW_ENCODE_EXT_RX_SEQ_VALID set */ + if (params->seq && params->seq_len == 6) { + /* rx iv */ + u8 *ivptr; + ivptr = (u8 *) params->seq; + key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) | + (ivptr[3] << 8) | ivptr[2]; + key.rxiv.lo = (ivptr[1] << 8) | ivptr[0]; + key.iv_initialized = true; + } + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); + break; + case WLAN_CIPHER_SUITE_TKIP: + key.algo = CRYPTO_ALGO_TKIP; + WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); + break; + default: + WL_ERR("Invalid cipher (0x%x)\n", params->cipher); + return -EINVAL; + } + convert_key_from_CPU(&key, &key_le); + + brcmf_netdev_wait_pend8021x(ndev); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_KEY, &key_le, + sizeof(key_le)); + if (err) { + WL_ERR("WLC_SET_KEY error (%d)\n", err); + return err; + } + } + return err; +} + +static s32 +brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_idx, bool pairwise, const u8 *mac_addr, + struct key_params *params) +{ + struct brcmf_wsec_key key; + s32 val; + s32 wsec; + s32 err = 0; + u8 keybuf[8]; + + WL_TRACE("Enter\n"); + WL_CONN("key index (%d)\n", key_idx); + if (!check_sys_up(wiphy)) + return -EIO; + + if (mac_addr) { + WL_TRACE("Exit"); + return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params); + } + memset(&key, 0, sizeof(key)); + + key.len = (u32) params->key_len; + key.index = (u32) key_idx; + + if (key.len > sizeof(key.data)) { + WL_ERR("Too long key length (%u)\n", key.len); + err = -EINVAL; + goto done; + } + memcpy(key.data, params->key, key.len); + + key.flags = BRCMF_PRIMARY_KEY; + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + key.algo = CRYPTO_ALGO_WEP1; + WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); + break; + case WLAN_CIPHER_SUITE_WEP104: + key.algo = CRYPTO_ALGO_WEP128; + WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); + break; + case WLAN_CIPHER_SUITE_TKIP: + memcpy(keybuf, &key.data[24], sizeof(keybuf)); + memcpy(&key.data[24], &key.data[16], sizeof(keybuf)); + memcpy(&key.data[16], keybuf, sizeof(keybuf)); + key.algo = CRYPTO_ALGO_TKIP; + WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); + break; + case WLAN_CIPHER_SUITE_CCMP: + key.algo = CRYPTO_ALGO_AES_CCM; + WL_CONN("WLAN_CIPHER_SUITE_CCMP\n"); + break; + default: + WL_ERR("Invalid cipher (0x%x)\n", params->cipher); + err = -EINVAL; + goto done; + } + + err = send_key_to_dongle(ndev, &key); /* Set the new key/index */ + if (err) + goto done; + + val = WEP_ENABLED; + err = brcmf_dev_intvar_get(ndev, "wsec", &wsec); + if (err) { + WL_ERR("get wsec error (%d)\n", err); + goto done; + } + wsec &= ~(WEP_ENABLED); + wsec |= val; + err = brcmf_dev_intvar_set(ndev, "wsec", wsec); + if (err) { + WL_ERR("set wsec error (%d)\n", err); + goto done; + } + + val = 1; /* assume shared key. otherwise 0 */ + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val); + if (err) + WL_ERR("WLC_SET_AUTH error (%d)\n", err); +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_idx, bool pairwise, const u8 *mac_addr) +{ + struct brcmf_wsec_key key; + s32 err = 0; + s32 val; + s32 wsec; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + memset(&key, 0, sizeof(key)); + + key.index = (u32) key_idx; + key.flags = BRCMF_PRIMARY_KEY; + key.algo = CRYPTO_ALGO_OFF; + + WL_CONN("key index (%d)\n", key_idx); + + /* Set the new key/index */ + err = send_key_to_dongle(ndev, &key); + if (err) { + if (err == -EINVAL) { + if (key.index >= DOT11_MAX_DEFAULT_KEYS) + /* we ignore this key index in this case */ + WL_ERR("invalid key index (%d)\n", key_idx); + } + /* Ignore this error, may happen during DISASSOC */ + err = -EAGAIN; + goto done; + } + + val = 0; + err = brcmf_dev_intvar_get(ndev, "wsec", &wsec); + if (err) { + WL_ERR("get wsec error (%d)\n", err); + /* Ignore this error, may happen during DISASSOC */ + err = -EAGAIN; + goto done; + } + wsec &= ~(WEP_ENABLED); + wsec |= val; + err = brcmf_dev_intvar_set(ndev, "wsec", wsec); + if (err) { + WL_ERR("set wsec error (%d)\n", err); + /* Ignore this error, may happen during DISASSOC */ + err = -EAGAIN; + goto done; + } + + val = 0; /* assume open key. otherwise 1 */ + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_AUTH, &val); + if (err) { + WL_ERR("WLC_SET_AUTH error (%d)\n", err); + /* Ignore this error, may happen during DISASSOC */ + err = -EAGAIN; + } +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie, + void (*callback) (void *cookie, struct key_params * params)) +{ + struct key_params params; + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_security *sec; + s32 wsec; + s32 err = 0; + + WL_TRACE("Enter\n"); + WL_CONN("key index (%d)\n", key_idx); + if (!check_sys_up(wiphy)) + return -EIO; + + memset(¶ms, 0, sizeof(params)); + + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_WSEC, &wsec); + if (err) { + WL_ERR("WLC_GET_WSEC error (%d)\n", err); + /* Ignore this error, may happen during DISASSOC */ + err = -EAGAIN; + goto done; + } + switch (wsec) { + case WEP_ENABLED: + sec = brcmf_read_prof(cfg_priv, WL_PROF_SEC); + if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { + params.cipher = WLAN_CIPHER_SUITE_WEP40; + WL_CONN("WLAN_CIPHER_SUITE_WEP40\n"); + } else if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP104) { + params.cipher = WLAN_CIPHER_SUITE_WEP104; + WL_CONN("WLAN_CIPHER_SUITE_WEP104\n"); + } + break; + case TKIP_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + WL_CONN("WLAN_CIPHER_SUITE_TKIP\n"); + break; + case AES_ENABLED: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + WL_CONN("WLAN_CIPHER_SUITE_AES_CMAC\n"); + break; + default: + WL_ERR("Invalid algo (0x%x)\n", wsec); + err = -EINVAL; + goto done; + } + callback(cookie, ¶ms); + +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy, + struct net_device *ndev, u8 key_idx) +{ + WL_INFO("Not supported\n"); + + return -EOPNOTSUPP; +} + +static s32 +brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + u8 *mac, struct station_info *sinfo) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct brcmf_scb_val_le scb_val; + int rssi; + s32 rate; + s32 err = 0; + u8 *bssid = brcmf_read_prof(cfg_priv, WL_PROF_BSSID); + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + if (memcmp(mac, bssid, ETH_ALEN)) { + WL_ERR("Wrong Mac address cfg_mac-%X:%X:%X:%X:%X:%X" + "wl_bssid-%X:%X:%X:%X:%X:%X\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + bssid[0], bssid[1], bssid[2], bssid[3], + bssid[4], bssid[5]); + err = -ENOENT; + goto done; + } + + /* Report the current tx rate */ + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_GET_RATE, &rate); + if (err) { + WL_ERR("Could not get rate (%d)\n", err); + } else { + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rate * 5; + WL_CONN("Rate %d Mbps\n", rate / 2); + } + + if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) { + scb_val.val = cpu_to_le32(0); + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_RSSI, &scb_val, + sizeof(struct brcmf_scb_val_le)); + if (err) + WL_ERR("Could not get rssi (%d)\n", err); + + rssi = le32_to_cpu(scb_val.val); + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi; + WL_CONN("RSSI %d dBm\n", rssi); + } + +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, + bool enabled, s32 timeout) +{ + s32 pm; + s32 err = 0; + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + + WL_TRACE("Enter\n"); + + /* + * Powersave enable/disable request is coming from the + * cfg80211 even before the interface is up. In that + * scenario, driver will be storing the power save + * preference in cfg_priv struct to apply this to + * FW later while initializing the dongle + */ + cfg_priv->pwr_save = enabled; + if (!test_bit(WL_STATUS_READY, &cfg_priv->status)) { + + WL_INFO("Device is not ready," + "storing the value in cfg_priv struct\n"); + goto done; + } + + pm = enabled ? PM_FAST : PM_OFF; + WL_INFO("power save %s\n", (pm ? "enabled" : "disabled")); + + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &pm); + if (err) { + if (err == -ENODEV) + WL_ERR("net_device is not ready yet\n"); + else + WL_ERR("error (%d)\n", err); + } +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev, + const u8 *addr, + const struct cfg80211_bitrate_mask *mask) +{ + struct brcm_rateset_le rateset_le; + s32 rate; + s32 val; + s32 err_bg; + s32 err_a; + u32 legacy; + s32 err = 0; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + /* addr param is always NULL. ignore it */ + /* Get current rateset */ + err = brcmf_exec_dcmd(ndev, BRCM_GET_CURR_RATESET, &rateset_le, + sizeof(rateset_le)); + if (err) { + WL_ERR("could not get current rateset (%d)\n", err); + goto done; + } + + legacy = ffs(mask->control[IEEE80211_BAND_2GHZ].legacy & 0xFFFF); + if (!legacy) + legacy = ffs(mask->control[IEEE80211_BAND_5GHZ].legacy & + 0xFFFF); + + val = wl_g_rates[legacy - 1].bitrate * 100000; + + if (val < le32_to_cpu(rateset_le.count)) + /* Select rate by rateset index */ + rate = rateset_le.rates[val] & 0x7f; + else + /* Specified rate in bps */ + rate = val / 500000; + + WL_CONN("rate %d mbps\n", rate / 2); + + /* + * + * Set rate override, + * Since the is a/b/g-blind, both a/bg_rate are enforced. + */ + err_bg = brcmf_dev_intvar_set(ndev, "bg_rate", rate); + err_a = brcmf_dev_intvar_set(ndev, "a_rate", rate); + if (err_bg && err_a) { + WL_ERR("could not set fixed rate (%d) (%d)\n", err_bg, err_a); + err = err_bg | err_a; + } + +done: + WL_TRACE("Exit\n"); + return err; +} + +static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv, + struct brcmf_bss_info *bi) +{ + struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct ieee80211_channel *notify_channel; + struct cfg80211_bss *bss; + struct ieee80211_supported_band *band; + s32 err = 0; + u16 channel; + u32 freq; + u64 notify_timestamp; + u16 notify_capability; + u16 notify_interval; + u8 *notify_ie; + size_t notify_ielen; + s32 notify_signal; + + if (le32_to_cpu(bi->length) > WL_BSS_INFO_MAX) { + WL_ERR("Bss info is larger than buffer. Discarding\n"); + return 0; + } + + channel = bi->ctl_ch ? bi->ctl_ch : + CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); + + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + + freq = ieee80211_channel_to_frequency(channel, band->band); + notify_channel = ieee80211_get_channel(wiphy, freq); + + notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ + notify_capability = le16_to_cpu(bi->capability); + notify_interval = le16_to_cpu(bi->beacon_period); + notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); + notify_ielen = le32_to_cpu(bi->ie_length); + notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; + + WL_CONN("bssid: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", + bi->BSSID[0], bi->BSSID[1], bi->BSSID[2], + bi->BSSID[3], bi->BSSID[4], bi->BSSID[5]); + WL_CONN("Channel: %d(%d)\n", channel, freq); + WL_CONN("Capability: %X\n", notify_capability); + WL_CONN("Beacon interval: %d\n", notify_interval); + WL_CONN("Signal: %d\n", notify_signal); + WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); + + bss = cfg80211_inform_bss(wiphy, notify_channel, (const u8 *)bi->BSSID, + notify_timestamp, notify_capability, notify_interval, notify_ie, + notify_ielen, notify_signal, GFP_KERNEL); + + if (!bss) { + WL_ERR("cfg80211_inform_bss_frame error\n"); + return -EINVAL; + } + + return err; +} + +static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_scan_results *bss_list; + struct brcmf_bss_info *bi = NULL; /* must be initialized */ + s32 err = 0; + int i; + + bss_list = cfg_priv->bss_list; + if (bss_list->version != BRCMF_BSS_INFO_VERSION) { + WL_ERR("Version %d != WL_BSS_INFO_VERSION\n", + bss_list->version); + return -EOPNOTSUPP; + } + WL_SCAN("scanned AP count (%d)\n", bss_list->count); + for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) { + bi = next_bss(bss_list, bi); + err = brcmf_inform_single_bss(cfg_priv, bi); + if (err) + break; + } + return err; +} + +static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, const u8 *bssid) +{ + struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct ieee80211_channel *notify_channel; + struct brcmf_bss_info *bi = NULL; + struct ieee80211_supported_band *band; + u8 *buf = NULL; + s32 err = 0; + u16 channel; + u32 freq; + u64 notify_timestamp; + u16 notify_capability; + u16 notify_interval; + u8 *notify_ie; + size_t notify_ielen; + s32 notify_signal; + + WL_TRACE("Enter\n"); + + buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (buf == NULL) { + err = -ENOMEM; + goto CleanUp; + } + + *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX); + + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX); + if (err) { + WL_ERR("WLC_GET_BSS_INFO failed: %d\n", err); + goto CleanUp; + } + + bi = (struct brcmf_bss_info *)(buf + 4); + + channel = bi->ctl_ch ? bi->ctl_ch : + CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec)); + + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + + freq = ieee80211_channel_to_frequency(channel, band->band); + notify_channel = ieee80211_get_channel(wiphy, freq); + + notify_timestamp = jiffies_to_msecs(jiffies)*1000; /* uSec */ + notify_capability = le16_to_cpu(bi->capability); + notify_interval = le16_to_cpu(bi->beacon_period); + notify_ie = (u8 *)bi + le16_to_cpu(bi->ie_offset); + notify_ielen = le32_to_cpu(bi->ie_length); + notify_signal = (s16)le16_to_cpu(bi->RSSI) * 100; + + WL_CONN("channel: %d(%d)\n", channel, freq); + WL_CONN("capability: %X\n", notify_capability); + WL_CONN("beacon interval: %d\n", notify_interval); + WL_CONN("signal: %d\n", notify_signal); + WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp); + + cfg80211_inform_bss(wiphy, notify_channel, bssid, + notify_timestamp, notify_capability, notify_interval, + notify_ie, notify_ielen, notify_signal, GFP_KERNEL); + +CleanUp: + + kfree(buf); + + WL_TRACE("Exit\n"); + + return err; +} + +static bool brcmf_is_ibssmode(struct brcmf_cfg80211_priv *cfg_priv) +{ + return cfg_priv->conf->mode == WL_MODE_IBSS; +} + +/* + * Traverse a string of 1-byte tag/1-byte length/variable-length value + * triples, returning a pointer to the substring whose first element + * matches tag + */ +static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key) +{ + struct brcmf_tlv *elt; + int totlen; + + elt = (struct brcmf_tlv *) buf; + totlen = buflen; + + /* find tagged parameter */ + while (totlen >= 2) { + int len = elt->len; + + /* validate remaining totlen */ + if ((elt->id == key) && (totlen >= (len + 2))) + return elt; + + elt = (struct brcmf_tlv *) ((u8 *) elt + (len + 2)); + totlen -= (len + 2); + } + + return NULL; +} + +static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_bss_info *bi; + struct brcmf_ssid *ssid; + struct brcmf_tlv *tim; + u16 beacon_interval; + u8 dtim_period; + size_t ie_len; + u8 *ie; + s32 err = 0; + + WL_TRACE("Enter\n"); + if (brcmf_is_ibssmode(cfg_priv)) + return err; + + ssid = (struct brcmf_ssid *)brcmf_read_prof(cfg_priv, WL_PROF_SSID); + + *(__le32 *)cfg_priv->extra_buf = cpu_to_le32(WL_EXTRA_BUF_MAX); + err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCMF_C_GET_BSS_INFO, + cfg_priv->extra_buf, WL_EXTRA_BUF_MAX); + if (err) { + WL_ERR("Could not get bss info %d\n", err); + goto update_bss_info_out; + } + + bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4); + err = brcmf_inform_single_bss(cfg_priv, bi); + if (err) + goto update_bss_info_out; + + ie = ((u8 *)bi) + le16_to_cpu(bi->ie_offset); + ie_len = le32_to_cpu(bi->ie_length); + beacon_interval = le16_to_cpu(bi->beacon_period); + + tim = brcmf_parse_tlvs(ie, ie_len, WLAN_EID_TIM); + if (tim) + dtim_period = tim->data[1]; + else { + /* + * active scan was done so we could not get dtim + * information out of probe response. + * so we speficially query dtim information to dongle. + */ + u32 var; + err = brcmf_dev_intvar_get(cfg_to_ndev(cfg_priv), + "dtim_assoc", &var); + if (err) { + WL_ERR("wl dtim_assoc failed (%d)\n", err); + goto update_bss_info_out; + } + dtim_period = (u8)var; + } + + brcmf_update_prof(cfg_priv, NULL, &beacon_interval, WL_PROF_BEACONINT); + brcmf_update_prof(cfg_priv, NULL, &dtim_period, WL_PROF_DTIMPERIOD); + +update_bss_info_out: + WL_TRACE("Exit"); + return err; +} + +static void brcmf_term_iscan(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + struct brcmf_ssid ssid; + + if (cfg_priv->iscan_on) { + iscan->state = WL_ISCAN_STATE_IDLE; + + if (iscan->timer_on) { + del_timer_sync(&iscan->timer); + iscan->timer_on = 0; + } + + cancel_work_sync(&iscan->work); + + /* Abort iscan running in FW */ + memset(&ssid, 0, sizeof(ssid)); + brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT); + } +} + +static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan, + bool aborted) +{ + struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); + struct net_device *ndev = cfg_to_ndev(cfg_priv); + + if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + WL_ERR("Scan complete while device not scanning\n"); + return; + } + if (cfg_priv->scan_request) { + WL_SCAN("ISCAN Completed scan: %s\n", + aborted ? "Aborted" : "Done"); + cfg80211_scan_done(cfg_priv->scan_request, aborted); + brcmf_set_mpc(ndev, 1); + cfg_priv->scan_request = NULL; + } + cfg_priv->iscan_kickstart = false; +} + +static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan) +{ + if (iscan->state != WL_ISCAN_STATE_IDLE) { + WL_SCAN("wake up iscan\n"); + schedule_work(&iscan->work); + return 0; + } + + return -EIO; +} + +static s32 +brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status, + struct brcmf_scan_results **bss_list) +{ + struct brcmf_iscan_results list; + struct brcmf_scan_results *results; + struct brcmf_scan_results_le *results_le; + struct brcmf_iscan_results *list_buf; + s32 err = 0; + + memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX); + list_buf = (struct brcmf_iscan_results *)iscan->scan_buf; + results = &list_buf->results; + results_le = &list_buf->results_le; + results->buflen = BRCMF_ISCAN_RESULTS_FIXED_SIZE; + results->version = 0; + results->count = 0; + + memset(&list, 0, sizeof(list)); + list.results_le.buflen = cpu_to_le32(WL_ISCAN_BUF_MAX); + err = brcmf_dev_iovar_getbuf(iscan->ndev, "iscanresults", &list, + BRCMF_ISCAN_RESULTS_FIXED_SIZE, + iscan->scan_buf, WL_ISCAN_BUF_MAX); + if (err) { + WL_ERR("error (%d)\n", err); + return err; + } + results->buflen = le32_to_cpu(results_le->buflen); + results->version = le32_to_cpu(results_le->version); + results->count = le32_to_cpu(results_le->count); + WL_SCAN("results->count = %d\n", results_le->count); + WL_SCAN("results->buflen = %d\n", results_le->buflen); + *status = le32_to_cpu(list_buf->status_le); + WL_SCAN("status = %d\n", *status); + *bss_list = results; + + return err; +} + +static s32 brcmf_iscan_done(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + s32 err = 0; + + iscan->state = WL_ISCAN_STATE_IDLE; + brcmf_inform_bss(cfg_priv); + brcmf_notify_iscan_complete(iscan, false); + + return err; +} + +static s32 brcmf_iscan_pending(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + s32 err = 0; + + /* Reschedule the timer */ + mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + iscan->timer_on = 1; + + return err; +} + +static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + s32 err = 0; + + brcmf_inform_bss(cfg_priv); + brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE); + /* Reschedule the timer */ + mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000); + iscan->timer_on = 1; + + return err; +} + +static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_priv->iscan; + s32 err = 0; + + iscan->state = WL_ISCAN_STATE_IDLE; + brcmf_notify_iscan_complete(iscan, true); + + return err; +} + +static void brcmf_cfg80211_iscan_handler(struct work_struct *work) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = + container_of(work, struct brcmf_cfg80211_iscan_ctrl, + work); + struct brcmf_cfg80211_priv *cfg_priv = iscan_to_cfg(iscan); + struct brcmf_cfg80211_iscan_eloop *el = &iscan->el; + u32 status = BRCMF_SCAN_RESULTS_PARTIAL; + + if (iscan->timer_on) { + del_timer_sync(&iscan->timer); + iscan->timer_on = 0; + } + + if (brcmf_get_iscan_results(iscan, &status, &cfg_priv->bss_list)) { + status = BRCMF_SCAN_RESULTS_ABORTED; + WL_ERR("Abort iscan\n"); + } + + el->handler[status](cfg_priv); +} + +static void brcmf_iscan_timer(unsigned long data) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = + (struct brcmf_cfg80211_iscan_ctrl *)data; + + if (iscan) { + iscan->timer_on = 0; + WL_SCAN("timer expired\n"); + brcmf_wakeup_iscan(iscan); + } +} + +static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + + if (cfg_priv->iscan_on) { + iscan->state = WL_ISCAN_STATE_IDLE; + INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler); + } + + return 0; +} + +static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el) +{ + memset(el, 0, sizeof(*el)); + el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done; + el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress; + el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending; + el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted; + el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted; +} + +static s32 brcmf_init_iscan(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg_priv); + int err = 0; + + if (cfg_priv->iscan_on) { + iscan->ndev = cfg_to_ndev(cfg_priv); + brcmf_init_iscan_eloop(&iscan->el); + iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS; + init_timer(&iscan->timer); + iscan->timer.data = (unsigned long) iscan; + iscan->timer.function = brcmf_iscan_timer; + err = brcmf_invoke_iscan(cfg_priv); + if (!err) + iscan->data = cfg_priv; + } + + return err; +} + +static void brcmf_delay(u32 ms) +{ + if (ms < 1000 / HZ) { + cond_resched(); + mdelay(ms); + } else { + msleep(ms); + } +} + +static s32 brcmf_cfg80211_resume(struct wiphy *wiphy) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + + /* + * Check for WL_STATUS_READY before any function call which + * could result is bus access. Don't block the resume for + * any driver error conditions + */ + WL_TRACE("Enter\n"); + + if (test_bit(WL_STATUS_READY, &cfg_priv->status)) + brcmf_invoke_iscan(wiphy_to_cfg(wiphy)); + + WL_TRACE("Exit\n"); + return 0; +} + +static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct net_device *ndev = cfg_to_ndev(cfg_priv); + + WL_TRACE("Enter\n"); + + /* + * Check for WL_STATUS_READY before any function call which + * could result is bus access. Don't block the suspend for + * any driver error conditions + */ + + /* + * While going to suspend if associated with AP disassociate + * from AP to save power while system is in suspended state + */ + if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || + test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && + test_bit(WL_STATUS_READY, &cfg_priv->status)) { + WL_INFO("Disassociating from AP" + " while entering suspend state\n"); + brcmf_link_down(cfg_priv); + + /* + * Make sure WPA_Supplicant receives all the event + * generated due to DISASSOC call to the fw to keep + * the state fw and WPA_Supplicant state consistent + */ + brcmf_delay(500); + } + + set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); + if (test_bit(WL_STATUS_READY, &cfg_priv->status)) + brcmf_term_iscan(cfg_priv); + + if (cfg_priv->scan_request) { + /* Indidate scan abort to cfg80211 layer */ + WL_INFO("Terminating scan in progress\n"); + cfg80211_scan_done(cfg_priv->scan_request, true); + cfg_priv->scan_request = NULL; + } + clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); + clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); + + /* Turn off watchdog timer */ + if (test_bit(WL_STATUS_READY, &cfg_priv->status)) { + WL_INFO("Enable MPC\n"); + brcmf_set_mpc(ndev, 1); + } + + WL_TRACE("Exit\n"); + + return 0; +} + +static __used s32 +brcmf_dev_bufvar_set(struct net_device *ndev, s8 *name, s8 *buf, s32 len) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + u32 buflen; + + buflen = brcmf_c_mkiovar(name, buf, len, cfg_priv->dcmd_buf, + WL_DCMD_LEN_MAX); + BUG_ON(!buflen); + + return brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, cfg_priv->dcmd_buf, + buflen); +} + +static s32 +brcmf_dev_bufvar_get(struct net_device *ndev, s8 *name, s8 *buf, + s32 buf_len) +{ + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + u32 len; + s32 err = 0; + + len = brcmf_c_mkiovar(name, NULL, 0, cfg_priv->dcmd_buf, + WL_DCMD_LEN_MAX); + BUG_ON(!len); + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, cfg_priv->dcmd_buf, + WL_DCMD_LEN_MAX); + if (err) { + WL_ERR("error (%d)\n", err); + return err; + } + memcpy(buf, cfg_priv->dcmd_buf, buf_len); + + return err; +} + +static __used s32 +brcmf_update_pmklist(struct net_device *ndev, + struct brcmf_cfg80211_pmk_list *pmk_list, s32 err) +{ + int i, j; + int pmkid_len; + + pmkid_len = le32_to_cpu(pmk_list->pmkids.npmkid); + + WL_CONN("No of elements %d\n", pmkid_len); + for (i = 0; i < pmkid_len; i++) { + WL_CONN("PMKID[%d]: %pM =\n", i, + &pmk_list->pmkids.pmkid[i].BSSID); + for (j = 0; j < WLAN_PMKID_LEN; j++) + WL_CONN("%02x\n", pmk_list->pmkids.pmkid[i].PMKID[j]); + } + + if (!err) + brcmf_dev_bufvar_set(ndev, "pmkid_info", (char *)pmk_list, + sizeof(*pmk_list)); + + return err; +} + +static s32 +brcmf_cfg80211_set_pmksa(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_pmksa *pmksa) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct pmkid_list *pmkids = &cfg_priv->pmk_list->pmkids; + s32 err = 0; + int i; + int pmkid_len; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + pmkid_len = le32_to_cpu(pmkids->npmkid); + for (i = 0; i < pmkid_len; i++) + if (!memcmp(pmksa->bssid, pmkids->pmkid[i].BSSID, ETH_ALEN)) + break; + if (i < WL_NUM_PMKIDS_MAX) { + memcpy(pmkids->pmkid[i].BSSID, pmksa->bssid, ETH_ALEN); + memcpy(pmkids->pmkid[i].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); + if (i == pmkid_len) { + pmkid_len++; + pmkids->npmkid = cpu_to_le32(pmkid_len); + } + } else + err = -EINVAL; + + WL_CONN("set_pmksa,IW_PMKSA_ADD - PMKID: %pM =\n", + pmkids->pmkid[pmkid_len].BSSID); + for (i = 0; i < WLAN_PMKID_LEN; i++) + WL_CONN("%02x\n", pmkids->pmkid[pmkid_len].PMKID[i]); + + err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); + + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *ndev, + struct cfg80211_pmksa *pmksa) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + struct pmkid_list pmkid; + s32 err = 0; + int i, pmkid_len; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + memcpy(&pmkid.pmkid[0].BSSID, pmksa->bssid, ETH_ALEN); + memcpy(&pmkid.pmkid[0].PMKID, pmksa->pmkid, WLAN_PMKID_LEN); + + WL_CONN("del_pmksa,IW_PMKSA_REMOVE - PMKID: %pM =\n", + &pmkid.pmkid[0].BSSID); + for (i = 0; i < WLAN_PMKID_LEN; i++) + WL_CONN("%02x\n", pmkid.pmkid[0].PMKID[i]); + + pmkid_len = le32_to_cpu(cfg_priv->pmk_list->pmkids.npmkid); + for (i = 0; i < pmkid_len; i++) + if (!memcmp + (pmksa->bssid, &cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, + ETH_ALEN)) + break; + + if ((pmkid_len > 0) + && (i < pmkid_len)) { + memset(&cfg_priv->pmk_list->pmkids.pmkid[i], 0, + sizeof(struct pmkid)); + for (; i < (pmkid_len - 1); i++) { + memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].BSSID, + &cfg_priv->pmk_list->pmkids.pmkid[i + 1].BSSID, + ETH_ALEN); + memcpy(&cfg_priv->pmk_list->pmkids.pmkid[i].PMKID, + &cfg_priv->pmk_list->pmkids.pmkid[i + 1].PMKID, + WLAN_PMKID_LEN); + } + cfg_priv->pmk_list->pmkids.npmkid = cpu_to_le32(pmkid_len - 1); + } else + err = -EINVAL; + + err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); + + WL_TRACE("Exit\n"); + return err; + +} + +static s32 +brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev) +{ + struct brcmf_cfg80211_priv *cfg_priv = wiphy_to_cfg(wiphy); + s32 err = 0; + + WL_TRACE("Enter\n"); + if (!check_sys_up(wiphy)) + return -EIO; + + memset(cfg_priv->pmk_list, 0, sizeof(*cfg_priv->pmk_list)); + err = brcmf_update_pmklist(ndev, cfg_priv->pmk_list, err); + + WL_TRACE("Exit\n"); + return err; + +} + +static struct cfg80211_ops wl_cfg80211_ops = { + .change_virtual_intf = brcmf_cfg80211_change_iface, + .scan = brcmf_cfg80211_scan, + .set_wiphy_params = brcmf_cfg80211_set_wiphy_params, + .join_ibss = brcmf_cfg80211_join_ibss, + .leave_ibss = brcmf_cfg80211_leave_ibss, + .get_station = brcmf_cfg80211_get_station, + .set_tx_power = brcmf_cfg80211_set_tx_power, + .get_tx_power = brcmf_cfg80211_get_tx_power, + .add_key = brcmf_cfg80211_add_key, + .del_key = brcmf_cfg80211_del_key, + .get_key = brcmf_cfg80211_get_key, + .set_default_key = brcmf_cfg80211_config_default_key, + .set_default_mgmt_key = brcmf_cfg80211_config_default_mgmt_key, + .set_power_mgmt = brcmf_cfg80211_set_power_mgmt, + .set_bitrate_mask = brcmf_cfg80211_set_bitrate_mask, + .connect = brcmf_cfg80211_connect, + .disconnect = brcmf_cfg80211_disconnect, + .suspend = brcmf_cfg80211_suspend, + .resume = brcmf_cfg80211_resume, + .set_pmksa = brcmf_cfg80211_set_pmksa, + .del_pmksa = brcmf_cfg80211_del_pmksa, + .flush_pmksa = brcmf_cfg80211_flush_pmksa +}; + +static s32 brcmf_mode_to_nl80211_iftype(s32 mode) +{ + s32 err = 0; + + switch (mode) { + case WL_MODE_BSS: + return NL80211_IFTYPE_STATION; + case WL_MODE_IBSS: + return NL80211_IFTYPE_ADHOC; + default: + return NL80211_IFTYPE_UNSPECIFIED; + } + + return err; +} + +static struct wireless_dev *brcmf_alloc_wdev(s32 sizeof_iface, + struct device *ndev) +{ + struct wireless_dev *wdev; + s32 err = 0; + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (!wdev) + return ERR_PTR(-ENOMEM); + + wdev->wiphy = + wiphy_new(&wl_cfg80211_ops, + sizeof(struct brcmf_cfg80211_priv) + sizeof_iface); + if (!wdev->wiphy) { + WL_ERR("Couldn not allocate wiphy device\n"); + err = -ENOMEM; + goto wiphy_new_out; + } + set_wiphy_dev(wdev->wiphy, ndev); + wdev->wiphy->max_scan_ssids = WL_NUM_SCAN_MAX; + wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; + wdev->wiphy->interface_modes = + BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; /* Set + * it as 11a by default. + * This will be updated with + * 11n phy tables in + * "ifconfig up" + * if phy has 11n capability + */ + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wdev->wiphy->cipher_suites = __wl_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); + wdev->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; /* enable power + * save mode + * by default + */ + err = wiphy_register(wdev->wiphy); + if (err < 0) { + WL_ERR("Couldn not register wiphy device (%d)\n", err); + goto wiphy_register_out; + } + return wdev; + +wiphy_register_out: + wiphy_free(wdev->wiphy); + +wiphy_new_out: + kfree(wdev); + + return ERR_PTR(err); +} + +static void brcmf_free_wdev(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct wireless_dev *wdev = cfg_priv->wdev; + + if (!wdev) { + WL_ERR("wdev is invalid\n"); + return; + } + wiphy_unregister(wdev->wiphy); + wiphy_free(wdev->wiphy); + kfree(wdev); + cfg_priv->wdev = NULL; +} + +static bool brcmf_is_linkup(struct brcmf_cfg80211_priv *cfg_priv, + const struct brcmf_event_msg *e) +{ + u32 event = be32_to_cpu(e->event_type); + u32 status = be32_to_cpu(e->status); + + if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) { + WL_CONN("Processing set ssid\n"); + cfg_priv->link_up = true; + return true; + } + + return false; +} + +static bool brcmf_is_linkdown(struct brcmf_cfg80211_priv *cfg_priv, + const struct brcmf_event_msg *e) +{ + u32 event = be32_to_cpu(e->event_type); + u16 flags = be16_to_cpu(e->flags); + + if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) { + WL_CONN("Processing link down\n"); + return true; + } + return false; +} + +static bool brcmf_is_nonetwork(struct brcmf_cfg80211_priv *cfg_priv, + const struct brcmf_event_msg *e) +{ + u32 event = be32_to_cpu(e->event_type); + u32 status = be32_to_cpu(e->status); + + if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) { + WL_CONN("Processing Link %s & no network found\n", + be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ? + "up" : "down"); + return true; + } + + if (event == BRCMF_E_SET_SSID && status != BRCMF_E_STATUS_SUCCESS) { + WL_CONN("Processing connecting & no network found\n"); + return true; + } + + return false; +} + +static void brcmf_clear_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); + + kfree(conn_info->req_ie); + conn_info->req_ie = NULL; + conn_info->req_ie_len = 0; + kfree(conn_info->resp_ie); + conn_info->resp_ie = NULL; + conn_info->resp_ie_len = 0; +} + +static s32 brcmf_get_assoc_ies(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct net_device *ndev = cfg_to_ndev(cfg_priv); + struct brcmf_cfg80211_assoc_ielen_le *assoc_info; + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); + u32 req_len; + u32 resp_len; + s32 err = 0; + + brcmf_clear_assoc_ies(cfg_priv); + + err = brcmf_dev_bufvar_get(ndev, "assoc_info", cfg_priv->extra_buf, + WL_ASSOC_INFO_MAX); + if (err) { + WL_ERR("could not get assoc info (%d)\n", err); + return err; + } + assoc_info = + (struct brcmf_cfg80211_assoc_ielen_le *)cfg_priv->extra_buf; + req_len = le32_to_cpu(assoc_info->req_len); + resp_len = le32_to_cpu(assoc_info->resp_len); + if (req_len) { + err = brcmf_dev_bufvar_get(ndev, "assoc_req_ies", + cfg_priv->extra_buf, + WL_ASSOC_INFO_MAX); + if (err) { + WL_ERR("could not get assoc req (%d)\n", err); + return err; + } + conn_info->req_ie_len = req_len; + conn_info->req_ie = + kmemdup(cfg_priv->extra_buf, conn_info->req_ie_len, + GFP_KERNEL); + } else { + conn_info->req_ie_len = 0; + conn_info->req_ie = NULL; + } + if (resp_len) { + err = brcmf_dev_bufvar_get(ndev, "assoc_resp_ies", + cfg_priv->extra_buf, + WL_ASSOC_INFO_MAX); + if (err) { + WL_ERR("could not get assoc resp (%d)\n", err); + return err; + } + conn_info->resp_ie_len = resp_len; + conn_info->resp_ie = + kmemdup(cfg_priv->extra_buf, conn_info->resp_ie_len, + GFP_KERNEL); + } else { + conn_info->resp_ie_len = 0; + conn_info->resp_ie = NULL; + } + WL_CONN("req len (%d) resp len (%d)\n", + conn_info->req_ie_len, conn_info->resp_ie_len); + + return err; +} + +static s32 +brcmf_bss_roaming_done(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e) +{ + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); + struct wiphy *wiphy = cfg_to_wiphy(cfg_priv); + struct brcmf_channel_info_le channel_le; + struct ieee80211_channel *notify_channel; + struct ieee80211_supported_band *band; + u32 freq; + s32 err = 0; + u32 target_channel; + + WL_TRACE("Enter\n"); + + brcmf_get_assoc_ies(cfg_priv); + brcmf_update_prof(cfg_priv, NULL, &e->addr, WL_PROF_BSSID); + brcmf_update_bss_info(cfg_priv); + + brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le, + sizeof(channel_le)); + + target_channel = le32_to_cpu(channel_le.target_channel); + WL_CONN("Roamed to channel %d\n", target_channel); + + if (target_channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; + + freq = ieee80211_channel_to_frequency(target_channel, band->band); + notify_channel = ieee80211_get_channel(wiphy, freq); + + cfg80211_roamed(ndev, notify_channel, + (u8 *)brcmf_read_prof(cfg_priv, WL_PROF_BSSID), + conn_info->req_ie, conn_info->req_ie_len, + conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); + WL_CONN("Report roaming result\n"); + + set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_bss_connect_done(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, const struct brcmf_event_msg *e, + bool completed) +{ + struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg_priv); + s32 err = 0; + + WL_TRACE("Enter\n"); + + if (test_and_clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) { + if (completed) { + brcmf_get_assoc_ies(cfg_priv); + brcmf_update_prof(cfg_priv, NULL, &e->addr, + WL_PROF_BSSID); + brcmf_update_bss_info(cfg_priv); + } + cfg80211_connect_result(ndev, + (u8 *)brcmf_read_prof(cfg_priv, + WL_PROF_BSSID), + conn_info->req_ie, + conn_info->req_ie_len, + conn_info->resp_ie, + conn_info->resp_ie_len, + completed ? WLAN_STATUS_SUCCESS : + WLAN_STATUS_AUTH_TIMEOUT, + GFP_KERNEL); + if (completed) + set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + WL_CONN("Report connect result - connection %s\n", + completed ? "succeeded" : "failed"); + } + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_notify_connect_status(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + s32 err = 0; + + if (brcmf_is_linkup(cfg_priv, e)) { + WL_CONN("Linkup\n"); + if (brcmf_is_ibssmode(cfg_priv)) { + brcmf_update_prof(cfg_priv, NULL, (void *)e->addr, + WL_PROF_BSSID); + wl_inform_ibss(cfg_priv, ndev, e->addr); + cfg80211_ibss_joined(ndev, e->addr, GFP_KERNEL); + clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + set_bit(WL_STATUS_CONNECTED, &cfg_priv->status); + } else + brcmf_bss_connect_done(cfg_priv, ndev, e, true); + } else if (brcmf_is_linkdown(cfg_priv, e)) { + WL_CONN("Linkdown\n"); + if (brcmf_is_ibssmode(cfg_priv)) { + clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + if (test_and_clear_bit(WL_STATUS_CONNECTED, + &cfg_priv->status)) + brcmf_link_down(cfg_priv); + } else { + brcmf_bss_connect_done(cfg_priv, ndev, e, false); + if (test_and_clear_bit(WL_STATUS_CONNECTED, + &cfg_priv->status)) { + cfg80211_disconnected(ndev, 0, NULL, 0, + GFP_KERNEL); + brcmf_link_down(cfg_priv); + } + } + brcmf_init_prof(cfg_priv->profile); + } else if (brcmf_is_nonetwork(cfg_priv, e)) { + if (brcmf_is_ibssmode(cfg_priv)) + clear_bit(WL_STATUS_CONNECTING, &cfg_priv->status); + else + brcmf_bss_connect_done(cfg_priv, ndev, e, false); + } + + return err; +} + +static s32 +brcmf_notify_roaming_status(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + s32 err = 0; + u32 event = be32_to_cpu(e->event_type); + u32 status = be32_to_cpu(e->status); + + if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) { + if (test_bit(WL_STATUS_CONNECTED, &cfg_priv->status)) + brcmf_bss_roaming_done(cfg_priv, ndev, e); + else + brcmf_bss_connect_done(cfg_priv, ndev, e, true); + } + + return err; +} + +static s32 +brcmf_notify_mic_status(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + u16 flags = be16_to_cpu(e->flags); + enum nl80211_key_type key_type; + + if (flags & BRCMF_EVENT_MSG_GROUP) + key_type = NL80211_KEYTYPE_GROUP; + else + key_type = NL80211_KEYTYPE_PAIRWISE; + + cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1, + NULL, GFP_KERNEL); + + return 0; +} + +static s32 +brcmf_notify_scan_status(struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + struct brcmf_channel_info_le channel_inform_le; + struct brcmf_scan_results_le *bss_list_le; + u32 len = WL_SCAN_BUF_MAX; + s32 err = 0; + bool scan_abort = false; + u32 scan_channel; + + WL_TRACE("Enter\n"); + + if (cfg_priv->iscan_on && cfg_priv->iscan_kickstart) { + WL_TRACE("Exit\n"); + return brcmf_wakeup_iscan(cfg_to_iscan(cfg_priv)); + } + + if (!test_and_clear_bit(WL_STATUS_SCANNING, &cfg_priv->status)) { + WL_ERR("Scan complete while device not scanning\n"); + scan_abort = true; + err = -EINVAL; + goto scan_done_out; + } + + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_inform_le, + sizeof(channel_inform_le)); + if (err) { + WL_ERR("scan busy (%d)\n", err); + scan_abort = true; + goto scan_done_out; + } + scan_channel = le32_to_cpu(channel_inform_le.scan_channel); + if (scan_channel) + WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel); + cfg_priv->bss_list = cfg_priv->scan_results; + bss_list_le = (struct brcmf_scan_results_le *) cfg_priv->bss_list; + + memset(cfg_priv->scan_results, 0, len); + bss_list_le->buflen = cpu_to_le32(len); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SCAN_RESULTS, + cfg_priv->scan_results, len); + if (err) { + WL_ERR("%s Scan_results error (%d)\n", ndev->name, err); + err = -EINVAL; + scan_abort = true; + goto scan_done_out; + } + cfg_priv->scan_results->buflen = le32_to_cpu(bss_list_le->buflen); + cfg_priv->scan_results->version = le32_to_cpu(bss_list_le->version); + cfg_priv->scan_results->count = le32_to_cpu(bss_list_le->count); + + err = brcmf_inform_bss(cfg_priv); + if (err) { + scan_abort = true; + goto scan_done_out; + } + +scan_done_out: + if (cfg_priv->scan_request) { + WL_SCAN("calling cfg80211_scan_done\n"); + cfg80211_scan_done(cfg_priv->scan_request, scan_abort); + brcmf_set_mpc(ndev, 1); + cfg_priv->scan_request = NULL; + } + + WL_TRACE("Exit\n"); + + return err; +} + +static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf) +{ + conf->mode = (u32)-1; + conf->frag_threshold = (u32)-1; + conf->rts_threshold = (u32)-1; + conf->retry_short = (u32)-1; + conf->retry_long = (u32)-1; + conf->tx_power = -1; +} + +static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el) +{ + memset(el, 0, sizeof(*el)); + el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status; + el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status; + el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status; + el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status; + el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status; +} + +static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) +{ + kfree(cfg_priv->scan_results); + cfg_priv->scan_results = NULL; + kfree(cfg_priv->bss_info); + cfg_priv->bss_info = NULL; + kfree(cfg_priv->conf); + cfg_priv->conf = NULL; + kfree(cfg_priv->profile); + cfg_priv->profile = NULL; + kfree(cfg_priv->scan_req_int); + cfg_priv->scan_req_int = NULL; + kfree(cfg_priv->dcmd_buf); + cfg_priv->dcmd_buf = NULL; + kfree(cfg_priv->extra_buf); + cfg_priv->extra_buf = NULL; + kfree(cfg_priv->iscan); + cfg_priv->iscan = NULL; + kfree(cfg_priv->pmk_list); + cfg_priv->pmk_list = NULL; +} + +static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_priv *cfg_priv) +{ + cfg_priv->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL); + if (!cfg_priv->scan_results) + goto init_priv_mem_out; + cfg_priv->conf = kzalloc(sizeof(*cfg_priv->conf), GFP_KERNEL); + if (!cfg_priv->conf) + goto init_priv_mem_out; + cfg_priv->profile = kzalloc(sizeof(*cfg_priv->profile), GFP_KERNEL); + if (!cfg_priv->profile) + goto init_priv_mem_out; + cfg_priv->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); + if (!cfg_priv->bss_info) + goto init_priv_mem_out; + cfg_priv->scan_req_int = kzalloc(sizeof(*cfg_priv->scan_req_int), + GFP_KERNEL); + if (!cfg_priv->scan_req_int) + goto init_priv_mem_out; + cfg_priv->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL); + if (!cfg_priv->dcmd_buf) + goto init_priv_mem_out; + cfg_priv->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL); + if (!cfg_priv->extra_buf) + goto init_priv_mem_out; + cfg_priv->iscan = kzalloc(sizeof(*cfg_priv->iscan), GFP_KERNEL); + if (!cfg_priv->iscan) + goto init_priv_mem_out; + cfg_priv->pmk_list = kzalloc(sizeof(*cfg_priv->pmk_list), GFP_KERNEL); + if (!cfg_priv->pmk_list) + goto init_priv_mem_out; + + return 0; + +init_priv_mem_out: + brcmf_deinit_priv_mem(cfg_priv); + + return -ENOMEM; +} + +/* +* retrieve first queued event from head +*/ + +static struct brcmf_cfg80211_event_q *brcmf_deq_event( + struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_event_q *e = NULL; + + spin_lock_irq(&cfg_priv->evt_q_lock); + if (!list_empty(&cfg_priv->evt_q_list)) { + e = list_first_entry(&cfg_priv->evt_q_list, + struct brcmf_cfg80211_event_q, evt_q_list); + list_del(&e->evt_q_list); + } + spin_unlock_irq(&cfg_priv->evt_q_lock); + + return e; +} + +/* +** push event to tail of the queue +*/ + +static s32 +brcmf_enq_event(struct brcmf_cfg80211_priv *cfg_priv, u32 event, + const struct brcmf_event_msg *msg) +{ + struct brcmf_cfg80211_event_q *e; + s32 err = 0; + + e = kzalloc(sizeof(struct brcmf_cfg80211_event_q), GFP_KERNEL); + if (!e) + return -ENOMEM; + + e->etype = event; + memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg)); + + spin_lock_irq(&cfg_priv->evt_q_lock); + list_add_tail(&e->evt_q_list, &cfg_priv->evt_q_list); + spin_unlock_irq(&cfg_priv->evt_q_lock); + + return err; +} + +static void brcmf_put_event(struct brcmf_cfg80211_event_q *e) +{ + kfree(e); +} + +static void brcmf_cfg80211_event_handler(struct work_struct *work) +{ + struct brcmf_cfg80211_priv *cfg_priv = + container_of(work, struct brcmf_cfg80211_priv, + event_work); + struct brcmf_cfg80211_event_q *e; + + e = brcmf_deq_event(cfg_priv); + if (unlikely(!e)) { + WL_ERR("event queue empty...\n"); + return; + } + + do { + WL_INFO("event type (%d)\n", e->etype); + if (cfg_priv->el.handler[e->etype]) + cfg_priv->el.handler[e->etype](cfg_priv, + cfg_to_ndev(cfg_priv), + &e->emsg, e->edata); + else + WL_INFO("Unknown Event (%d): ignoring\n", e->etype); + brcmf_put_event(e); + } while ((e = brcmf_deq_event(cfg_priv))); + +} + +static void brcmf_init_eq(struct brcmf_cfg80211_priv *cfg_priv) +{ + spin_lock_init(&cfg_priv->evt_q_lock); + INIT_LIST_HEAD(&cfg_priv->evt_q_list); +} + +static void brcmf_flush_eq(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct brcmf_cfg80211_event_q *e; + + spin_lock_irq(&cfg_priv->evt_q_lock); + while (!list_empty(&cfg_priv->evt_q_list)) { + e = list_first_entry(&cfg_priv->evt_q_list, + struct brcmf_cfg80211_event_q, evt_q_list); + list_del(&e->evt_q_list); + kfree(e); + } + spin_unlock_irq(&cfg_priv->evt_q_lock); +} + +static s32 wl_init_priv(struct brcmf_cfg80211_priv *cfg_priv) +{ + s32 err = 0; + + cfg_priv->scan_request = NULL; + cfg_priv->pwr_save = true; + cfg_priv->iscan_on = true; /* iscan on & off switch. + we enable iscan per default */ + cfg_priv->roam_on = true; /* roam on & off switch. + we enable roam per default */ + + cfg_priv->iscan_kickstart = false; + cfg_priv->active_scan = true; /* we do active scan for + specific scan per default */ + cfg_priv->dongle_up = false; /* dongle is not up yet */ + brcmf_init_eq(cfg_priv); + err = brcmf_init_priv_mem(cfg_priv); + if (err) + return err; + INIT_WORK(&cfg_priv->event_work, brcmf_cfg80211_event_handler); + brcmf_init_eloop_handler(&cfg_priv->el); + mutex_init(&cfg_priv->usr_sync); + err = brcmf_init_iscan(cfg_priv); + if (err) + return err; + brcmf_init_conf(cfg_priv->conf); + brcmf_init_prof(cfg_priv->profile); + brcmf_link_down(cfg_priv); + + return err; +} + +static void wl_deinit_priv(struct brcmf_cfg80211_priv *cfg_priv) +{ + cancel_work_sync(&cfg_priv->event_work); + cfg_priv->dongle_up = false; /* dongle down */ + brcmf_flush_eq(cfg_priv); + brcmf_link_down(cfg_priv); + brcmf_term_iscan(cfg_priv); + brcmf_deinit_priv_mem(cfg_priv); +} + +struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, + struct device *busdev, + void *data) +{ + struct wireless_dev *wdev; + struct brcmf_cfg80211_priv *cfg_priv; + struct brcmf_cfg80211_iface *ci; + struct brcmf_cfg80211_dev *cfg_dev; + s32 err = 0; + + if (!ndev) { + WL_ERR("ndev is invalid\n"); + return NULL; + } + cfg_dev = kzalloc(sizeof(struct brcmf_cfg80211_dev), GFP_KERNEL); + if (!cfg_dev) + return NULL; + + wdev = brcmf_alloc_wdev(sizeof(struct brcmf_cfg80211_iface), busdev); + if (IS_ERR(wdev)) { + kfree(cfg_dev); + return NULL; + } + + wdev->iftype = brcmf_mode_to_nl80211_iftype(WL_MODE_BSS); + cfg_priv = wdev_to_cfg(wdev); + cfg_priv->wdev = wdev; + cfg_priv->pub = data; + ci = (struct brcmf_cfg80211_iface *)&cfg_priv->ci; + ci->cfg_priv = cfg_priv; + ndev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); + wdev->netdev = ndev; + err = wl_init_priv(cfg_priv); + if (err) { + WL_ERR("Failed to init iwm_priv (%d)\n", err); + goto cfg80211_attach_out; + } + brcmf_set_drvdata(cfg_dev, ci); + + return cfg_dev; + +cfg80211_attach_out: + brcmf_free_wdev(cfg_priv); + kfree(cfg_dev); + return NULL; +} + +void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg_dev) +{ + struct brcmf_cfg80211_priv *cfg_priv; + + cfg_priv = brcmf_priv_get(cfg_dev); + + wl_deinit_priv(cfg_priv); + brcmf_free_wdev(cfg_priv); + brcmf_set_drvdata(cfg_dev, NULL); + kfree(cfg_dev); +} + +void +brcmf_cfg80211_event(struct net_device *ndev, + const struct brcmf_event_msg *e, void *data) +{ + u32 event_type = be32_to_cpu(e->event_type); + struct brcmf_cfg80211_priv *cfg_priv = ndev_to_cfg(ndev); + + if (!brcmf_enq_event(cfg_priv, event_type, e)) + schedule_work(&cfg_priv->event_work); +} + +static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype) +{ + s32 infra = 0; + s32 err = 0; + + switch (iftype) { + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_WDS: + WL_ERR("type (%d) : currently we do not support this mode\n", + iftype); + err = -EINVAL; + return err; + case NL80211_IFTYPE_ADHOC: + infra = 0; + break; + case NL80211_IFTYPE_STATION: + infra = 1; + break; + default: + err = -EINVAL; + WL_ERR("invalid type (%d)\n", iftype); + return err; + } + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra); + if (err) { + WL_ERR("WLC_SET_INFRA error (%d)\n", err); + return err; + } + + return 0; +} + +static s32 brcmf_dongle_eventmsg(struct net_device *ndev) +{ + /* Room for "event_msgs" + '\0' + bitvec */ + s8 iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; + s8 eventmask[BRCMF_EVENTING_MASK_LEN]; + s32 err = 0; + + WL_TRACE("Enter\n"); + + /* Setup event_msgs */ + brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, + iovbuf, sizeof(iovbuf)); + err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_VAR, iovbuf, sizeof(iovbuf)); + if (err) { + WL_ERR("Get event_msgs error (%d)\n", err); + goto dongle_eventmsg_out; + } + memcpy(eventmask, iovbuf, BRCMF_EVENTING_MASK_LEN); + + setbit(eventmask, BRCMF_E_SET_SSID); + setbit(eventmask, BRCMF_E_ROAM); + setbit(eventmask, BRCMF_E_PRUNE); + setbit(eventmask, BRCMF_E_AUTH); + setbit(eventmask, BRCMF_E_REASSOC); + setbit(eventmask, BRCMF_E_REASSOC_IND); + setbit(eventmask, BRCMF_E_DEAUTH_IND); + setbit(eventmask, BRCMF_E_DISASSOC_IND); + setbit(eventmask, BRCMF_E_DISASSOC); + setbit(eventmask, BRCMF_E_JOIN); + setbit(eventmask, BRCMF_E_ASSOC_IND); + setbit(eventmask, BRCMF_E_PSK_SUP); + setbit(eventmask, BRCMF_E_LINK); + setbit(eventmask, BRCMF_E_NDIS_LINK); + setbit(eventmask, BRCMF_E_MIC_ERROR); + setbit(eventmask, BRCMF_E_PMKID_CACHE); + setbit(eventmask, BRCMF_E_TXFAIL); + setbit(eventmask, BRCMF_E_JOIN_START); + setbit(eventmask, BRCMF_E_SCAN_COMPLETE); + + brcmf_c_mkiovar("event_msgs", eventmask, BRCMF_EVENTING_MASK_LEN, + iovbuf, sizeof(iovbuf)); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); + if (err) { + WL_ERR("Set event_msgs error (%d)\n", err); + goto dongle_eventmsg_out; + } + +dongle_eventmsg_out: + WL_TRACE("Exit\n"); + return err; +} + +static s32 +brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) +{ + s8 iovbuf[32]; + s32 err = 0; + __le32 roamtrigger[2]; + __le32 roam_delta[2]; + __le32 bcn_to_le; + __le32 roamvar_le; + + /* + * Setup timeout if Beacons are lost and roam is + * off to report link down + */ + if (roamvar) { + bcn_to_le = cpu_to_le32(bcn_timeout); + brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_to_le, + sizeof(bcn_to_le), iovbuf, sizeof(iovbuf)); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, + iovbuf, sizeof(iovbuf)); + if (err) { + WL_ERR("bcn_timeout error (%d)\n", err); + goto dongle_rom_out; + } + } + + /* + * Enable/Disable built-in roaming to allow supplicant + * to take care of roaming + */ + WL_INFO("Internal Roaming = %s\n", roamvar ? "Off" : "On"); + roamvar_le = cpu_to_le32(roamvar); + brcmf_c_mkiovar("roam_off", (char *)&roamvar_le, + sizeof(roamvar_le), iovbuf, sizeof(iovbuf)); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_VAR, iovbuf, sizeof(iovbuf)); + if (err) { + WL_ERR("roam_off error (%d)\n", err); + goto dongle_rom_out; + } + + roamtrigger[0] = cpu_to_le32(WL_ROAM_TRIGGER_LEVEL); + roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_TRIGGER, + (void *)roamtrigger, sizeof(roamtrigger)); + if (err) { + WL_ERR("WLC_SET_ROAM_TRIGGER error (%d)\n", err); + goto dongle_rom_out; + } + + roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA); + roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL); + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_ROAM_DELTA, + (void *)roam_delta, sizeof(roam_delta)); + if (err) { + WL_ERR("WLC_SET_ROAM_DELTA error (%d)\n", err); + goto dongle_rom_out; + } + +dongle_rom_out: + return err; +} + +static s32 +brcmf_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, + s32 scan_unassoc_time, s32 scan_passive_time) +{ + s32 err = 0; + __le32 scan_assoc_tm_le = cpu_to_le32(scan_assoc_time); + __le32 scan_unassoc_tm_le = cpu_to_le32(scan_unassoc_time); + __le32 scan_passive_tm_le = cpu_to_le32(scan_passive_time); + + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_CHANNEL_TIME, + &scan_assoc_tm_le, sizeof(scan_assoc_tm_le)); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFO("Scan assoc time is not supported\n"); + else + WL_ERR("Scan assoc time error (%d)\n", err); + goto dongle_scantime_out; + } + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_UNASSOC_TIME, + &scan_unassoc_tm_le, sizeof(scan_unassoc_tm_le)); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFO("Scan unassoc time is not supported\n"); + else + WL_ERR("Scan unassoc time error (%d)\n", err); + goto dongle_scantime_out; + } + + err = brcmf_exec_dcmd(ndev, BRCMF_C_SET_SCAN_PASSIVE_TIME, + &scan_passive_tm_le, sizeof(scan_passive_tm_le)); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFO("Scan passive time is not supported\n"); + else + WL_ERR("Scan passive time error (%d)\n", err); + goto dongle_scantime_out; + } + +dongle_scantime_out: + return err; +} + +static s32 wl_update_wiphybands(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct wiphy *wiphy; + s32 phy_list; + s8 phy; + s32 err = 0; + + err = brcmf_exec_dcmd(cfg_to_ndev(cfg_priv), BRCM_GET_PHYLIST, + &phy_list, sizeof(phy_list)); + if (err) { + WL_ERR("error (%d)\n", err); + return err; + } + + phy = ((char *)&phy_list)[1]; + WL_INFO("%c phy\n", phy); + if (phy == 'n' || phy == 'a') { + wiphy = cfg_to_wiphy(cfg_priv); + wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_n; + } + + return err; +} + +static s32 brcmf_dongle_probecap(struct brcmf_cfg80211_priv *cfg_priv) +{ + return wl_update_wiphybands(cfg_priv); +} + +static s32 brcmf_config_dongle(struct brcmf_cfg80211_priv *cfg_priv) +{ + struct net_device *ndev; + struct wireless_dev *wdev; + s32 power_mode; + s32 err = 0; + + if (cfg_priv->dongle_up) + return err; + + ndev = cfg_to_ndev(cfg_priv); + wdev = ndev->ieee80211_ptr; + + brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME, + WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME); + + err = brcmf_dongle_eventmsg(ndev); + if (err) + goto default_conf_out; + + power_mode = cfg_priv->pwr_save ? PM_FAST : PM_OFF; + err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_PM, &power_mode); + if (err) + goto default_conf_out; + WL_INFO("power save set to %s\n", + (power_mode ? "enabled" : "disabled")); + + err = brcmf_dongle_roam(ndev, (cfg_priv->roam_on ? 0 : 1), + WL_BEACON_TIMEOUT); + if (err) + goto default_conf_out; + err = brcmf_dongle_mode(ndev, wdev->iftype); + if (err && err != -EINPROGRESS) + goto default_conf_out; + err = brcmf_dongle_probecap(cfg_priv); + if (err) + goto default_conf_out; + + /* -EINPROGRESS: Call commit handler */ + +default_conf_out: + + cfg_priv->dongle_up = true; + + return err; + +} + +static int brcmf_debugfs_add_netdev_params(struct brcmf_cfg80211_priv *cfg_priv) +{ + char buf[10+IFNAMSIZ]; + struct dentry *fd; + s32 err = 0; + + sprintf(buf, "netdev:%s", cfg_to_ndev(cfg_priv)->name); + cfg_priv->debugfsdir = debugfs_create_dir(buf, + cfg_to_wiphy(cfg_priv)->debugfsdir); + + fd = debugfs_create_u16("beacon_int", S_IRUGO, cfg_priv->debugfsdir, + (u16 *)&cfg_priv->profile->beacon_interval); + if (!fd) { + err = -ENOMEM; + goto err_out; + } + + fd = debugfs_create_u8("dtim_period", S_IRUGO, cfg_priv->debugfsdir, + (u8 *)&cfg_priv->profile->dtim_period); + if (!fd) { + err = -ENOMEM; + goto err_out; + } + +err_out: + return err; +} + +static void brcmf_debugfs_remove_netdev(struct brcmf_cfg80211_priv *cfg_priv) +{ + debugfs_remove_recursive(cfg_priv->debugfsdir); + cfg_priv->debugfsdir = NULL; +} + +static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_priv *cfg_priv) +{ + s32 err = 0; + + set_bit(WL_STATUS_READY, &cfg_priv->status); + + brcmf_debugfs_add_netdev_params(cfg_priv); + + err = brcmf_config_dongle(cfg_priv); + if (err) + return err; + + brcmf_invoke_iscan(cfg_priv); + + return err; +} + +static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_priv *cfg_priv) +{ + /* + * While going down, if associated with AP disassociate + * from AP to save power + */ + if ((test_bit(WL_STATUS_CONNECTED, &cfg_priv->status) || + test_bit(WL_STATUS_CONNECTING, &cfg_priv->status)) && + test_bit(WL_STATUS_READY, &cfg_priv->status)) { + WL_INFO("Disassociating from AP"); + brcmf_link_down(cfg_priv); + + /* Make sure WPA_Supplicant receives all the event + generated due to DISASSOC call to the fw to keep + the state fw and WPA_Supplicant state consistent + */ + brcmf_delay(500); + } + + set_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); + brcmf_term_iscan(cfg_priv); + if (cfg_priv->scan_request) { + cfg80211_scan_done(cfg_priv->scan_request, true); + /* May need to perform this to cover rmmod */ + /* wl_set_mpc(cfg_to_ndev(wl), 1); */ + cfg_priv->scan_request = NULL; + } + clear_bit(WL_STATUS_READY, &cfg_priv->status); + clear_bit(WL_STATUS_SCANNING, &cfg_priv->status); + clear_bit(WL_STATUS_SCAN_ABORTING, &cfg_priv->status); + + brcmf_debugfs_remove_netdev(cfg_priv); + + return 0; +} + +s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev) +{ + struct brcmf_cfg80211_priv *cfg_priv; + s32 err = 0; + + cfg_priv = brcmf_priv_get(cfg_dev); + mutex_lock(&cfg_priv->usr_sync); + err = __brcmf_cfg80211_up(cfg_priv); + mutex_unlock(&cfg_priv->usr_sync); + + return err; +} + +s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev) +{ + struct brcmf_cfg80211_priv *cfg_priv; + s32 err = 0; + + cfg_priv = brcmf_priv_get(cfg_dev); + mutex_lock(&cfg_priv->usr_sync); + err = __brcmf_cfg80211_down(cfg_priv); + mutex_unlock(&cfg_priv->usr_sync); + + return err; +} + +static __used s32 brcmf_add_ie(struct brcmf_cfg80211_priv *cfg_priv, + u8 t, u8 l, u8 *v) +{ + struct brcmf_cfg80211_ie *ie = &cfg_priv->ie; + s32 err = 0; + + if (ie->offset + l + 2 > WL_TLV_INFO_MAX) { + WL_ERR("ei crosses buffer boundary\n"); + return -ENOSPC; + } + ie->buf[ie->offset] = t; + ie->buf[ie->offset + 1] = l; + memcpy(&ie->buf[ie->offset + 2], v, l); + ie->offset += l + 2; + + return err; +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h new file mode 100644 index 000000000000..62dc46144ede --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _wl_cfg80211_h_ +#define _wl_cfg80211_h_ + +struct brcmf_cfg80211_conf; +struct brcmf_cfg80211_iface; +struct brcmf_cfg80211_priv; +struct brcmf_cfg80211_security; +struct brcmf_cfg80211_ibss; + +#define WL_DBG_NONE 0 +#define WL_DBG_CONN (1 << 5) +#define WL_DBG_SCAN (1 << 4) +#define WL_DBG_TRACE (1 << 3) +#define WL_DBG_INFO (1 << 1) +#define WL_DBG_ERR (1 << 0) +#define WL_DBG_MASK ((WL_DBG_INFO | WL_DBG_ERR | WL_DBG_TRACE) | \ + (WL_DBG_SCAN) | (WL_DBG_CONN)) + +#define WL_ERR(fmt, args...) \ +do { \ + if (brcmf_dbg_level & WL_DBG_ERR) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "ERROR @%s : " fmt, \ + __func__, ##args); \ + } \ + } \ +} while (0) + +#if (defined BCMDBG) +#define WL_INFO(fmt, args...) \ +do { \ + if (brcmf_dbg_level & WL_DBG_INFO) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "INFO @%s : " fmt, \ + __func__, ##args); \ + } \ + } \ +} while (0) + +#define WL_TRACE(fmt, args...) \ +do { \ + if (brcmf_dbg_level & WL_DBG_TRACE) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "TRACE @%s : " fmt, \ + __func__, ##args); \ + } \ + } \ +} while (0) + +#define WL_SCAN(fmt, args...) \ +do { \ + if (brcmf_dbg_level & WL_DBG_SCAN) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "SCAN @%s : " fmt, \ + __func__, ##args); \ + } \ + } \ +} while (0) + +#define WL_CONN(fmt, args...) \ +do { \ + if (brcmf_dbg_level & WL_DBG_CONN) { \ + if (net_ratelimit()) { \ + printk(KERN_ERR "CONN @%s : " fmt, \ + __func__, ##args); \ + } \ + } \ +} while (0) + +#else /* (defined BCMDBG) */ +#define WL_INFO(fmt, args...) +#define WL_TRACE(fmt, args...) +#define WL_SCAN(fmt, args...) +#define WL_CONN(fmt, args...) +#endif /* (defined BCMDBG) */ + +#define WL_NUM_SCAN_MAX 1 +#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used + * for 2.6.33 kernel + * or later + */ +#define WL_SCAN_BUF_MAX (1024 * 8) +#define WL_TLV_INFO_MAX 1024 +#define WL_BSS_INFO_MAX 2048 +#define WL_ASSOC_INFO_MAX 512 /* + * needs to grab assoc info from dongle to + * report it to cfg80211 through "connect" + * event + */ +#define WL_DCMD_LEN_MAX 1024 +#define WL_EXTRA_BUF_MAX 2048 +#define WL_ISCAN_BUF_MAX 2048 /* + * the buf length can be BRCMF_DCMD_MAXLEN + * to reduce iteration + */ +#define WL_ISCAN_TIMER_INTERVAL_MS 3000 +#define WL_SCAN_ERSULTS_LAST (BRCMF_SCAN_RESULTS_NO_MEM+1) +#define WL_AP_MAX 256 /* virtually unlimitted as long + * as kernel memory allows + */ + +#define WL_ROAM_TRIGGER_LEVEL -75 +#define WL_ROAM_DELTA 20 +#define WL_BEACON_TIMEOUT 3 + +#define WL_SCAN_CHANNEL_TIME 40 +#define WL_SCAN_UNASSOC_TIME 40 +#define WL_SCAN_PASSIVE_TIME 120 + +/* dongle status */ +enum wl_status { + WL_STATUS_READY, + WL_STATUS_SCANNING, + WL_STATUS_SCAN_ABORTING, + WL_STATUS_CONNECTING, + WL_STATUS_CONNECTED +}; + +/* wi-fi mode */ +enum wl_mode { + WL_MODE_BSS, + WL_MODE_IBSS, + WL_MODE_AP +}; + +/* dongle profile list */ +enum wl_prof_list { + WL_PROF_MODE, + WL_PROF_SSID, + WL_PROF_SEC, + WL_PROF_IBSS, + WL_PROF_BAND, + WL_PROF_BSSID, + WL_PROF_ACT, + WL_PROF_BEACONINT, + WL_PROF_DTIMPERIOD +}; + +/* dongle iscan state */ +enum wl_iscan_state { + WL_ISCAN_STATE_IDLE, + WL_ISCAN_STATE_SCANING +}; + +/* dongle configuration */ +struct brcmf_cfg80211_conf { + u32 mode; /* adhoc , infrastructure or ap */ + u32 frag_threshold; + u32 rts_threshold; + u32 retry_short; + u32 retry_long; + s32 tx_power; + struct ieee80211_channel channel; +}; + +/* cfg80211 main event loop */ +struct brcmf_cfg80211_event_loop { + s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_priv *cfg_priv, + struct net_device *ndev, + const struct brcmf_event_msg *e, + void *data); +}; + +/* representing interface of cfg80211 plane */ +struct brcmf_cfg80211_iface { + struct brcmf_cfg80211_priv *cfg_priv; +}; + +struct brcmf_cfg80211_dev { + void *driver_data; /* to store cfg80211 object information */ +}; + +/* basic structure of scan request */ +struct brcmf_cfg80211_scan_req { + struct brcmf_ssid_le ssid_le; +}; + +/* basic structure of information element */ +struct brcmf_cfg80211_ie { + u16 offset; + u8 buf[WL_TLV_INFO_MAX]; +}; + +/* event queue for cfg80211 main event */ +struct brcmf_cfg80211_event_q { + struct list_head evt_q_list; + u32 etype; + struct brcmf_event_msg emsg; + s8 edata[1]; +}; + +/* security information with currently associated ap */ +struct brcmf_cfg80211_security { + u32 wpa_versions; + u32 auth_type; + u32 cipher_pairwise; + u32 cipher_group; + u32 wpa_auth; +}; + +/* ibss information for currently joined ibss network */ +struct brcmf_cfg80211_ibss { + u8 beacon_interval; /* in millisecond */ + u8 atim; /* in millisecond */ + s8 join_only; + u8 band; + u8 channel; +}; + +/* dongle profile */ +struct brcmf_cfg80211_profile { + u32 mode; + struct brcmf_ssid ssid; + u8 bssid[ETH_ALEN]; + u16 beacon_interval; + u8 dtim_period; + struct brcmf_cfg80211_security sec; + struct brcmf_cfg80211_ibss ibss; + s32 band; +}; + +/* dongle iscan event loop */ +struct brcmf_cfg80211_iscan_eloop { + s32 (*handler[WL_SCAN_ERSULTS_LAST]) + (struct brcmf_cfg80211_priv *cfg_priv); +}; + +/* dongle iscan controller */ +struct brcmf_cfg80211_iscan_ctrl { + struct net_device *ndev; + struct timer_list timer; + u32 timer_ms; + u32 timer_on; + s32 state; + struct work_struct work; + struct brcmf_cfg80211_iscan_eloop el; + void *data; + s8 dcmd_buf[BRCMF_DCMD_SMLEN]; + s8 scan_buf[WL_ISCAN_BUF_MAX]; +}; + +/* association inform */ +struct brcmf_cfg80211_connect_info { + u8 *req_ie; + s32 req_ie_len; + u8 *resp_ie; + s32 resp_ie_len; +}; + +/* assoc ie length */ +struct brcmf_cfg80211_assoc_ielen_le { + __le32 req_len; + __le32 resp_len; +}; + +/* wpa2 pmk list */ +struct brcmf_cfg80211_pmk_list { + struct pmkid_list pmkids; + struct pmkid foo[MAXPMKID - 1]; +}; + +/* dongle private data of cfg80211 interface */ +struct brcmf_cfg80211_priv { + struct wireless_dev *wdev; /* representing wl cfg80211 device */ + struct brcmf_cfg80211_conf *conf; /* dongle configuration */ + struct cfg80211_scan_request *scan_request; /* scan request + object */ + struct brcmf_cfg80211_event_loop el; /* main event loop */ + struct list_head evt_q_list; /* used for event queue */ + spinlock_t evt_q_lock; /* for event queue synchronization */ + struct mutex usr_sync; /* maily for dongle up/down synchronization */ + struct brcmf_scan_results *bss_list; /* bss_list holding scanned + ap information */ + struct brcmf_scan_results *scan_results; + struct brcmf_cfg80211_scan_req *scan_req_int; /* scan request object + for internal purpose */ + struct wl_cfg80211_bss_info *bss_info; /* bss information for + cfg80211 layer */ + struct brcmf_cfg80211_ie ie; /* information element object for + internal purpose */ + struct brcmf_cfg80211_profile *profile; /* holding dongle profile */ + struct brcmf_cfg80211_iscan_ctrl *iscan; /* iscan controller */ + struct brcmf_cfg80211_connect_info conn_info; /* association info */ + struct brcmf_cfg80211_pmk_list *pmk_list; /* wpa2 pmk list */ + struct work_struct event_work; /* event handler work struct */ + unsigned long status; /* current dongle status */ + void *pub; + u32 channel; /* current channel */ + bool iscan_on; /* iscan on/off switch */ + bool iscan_kickstart; /* indicate iscan already started */ + bool active_scan; /* current scan mode */ + bool ibss_starter; /* indicates this sta is ibss starter */ + bool link_up; /* link/connection up flag */ + bool pwr_save; /* indicate whether dongle to support + power save mode */ + bool dongle_up; /* indicate whether dongle up or not */ + bool roam_on; /* on/off switch for dongle self-roaming */ + bool scan_tried; /* indicates if first scan attempted */ + u8 *dcmd_buf; /* dcmd buffer */ + u8 *extra_buf; /* maily to grab assoc information */ + struct dentry *debugfsdir; + u8 ci[0] __aligned(NETDEV_ALIGN); +}; + +static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_priv *w) +{ + return w->wdev->wiphy; +} + +static inline struct brcmf_cfg80211_priv *wiphy_to_cfg(struct wiphy *w) +{ + return (struct brcmf_cfg80211_priv *)(wiphy_priv(w)); +} + +static inline struct brcmf_cfg80211_priv *wdev_to_cfg(struct wireless_dev *wd) +{ + return (struct brcmf_cfg80211_priv *)(wdev_priv(wd)); +} + +static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_priv *cfg) +{ + return cfg->wdev->netdev; +} + +static inline struct brcmf_cfg80211_priv *ndev_to_cfg(struct net_device *ndev) +{ + return wdev_to_cfg(ndev->ieee80211_ptr); +} + +#define iscan_to_cfg(i) ((struct brcmf_cfg80211_priv *)(i->data)) +#define cfg_to_iscan(w) (w->iscan) + +static inline struct +brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg) +{ + return &cfg->conn_info; +} + +static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list, + struct brcmf_bss_info *bss) +{ + return bss = bss ? + (struct brcmf_bss_info *)((unsigned long)bss + + le32_to_cpu(bss->length)) : + list->bss_info; +} + +extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev, + struct device *busdev, + void *data); +extern void brcmf_cfg80211_detach(struct brcmf_cfg80211_dev *cfg); + +/* event handler from dongle */ +extern void brcmf_cfg80211_event(struct net_device *ndev, + const struct brcmf_event_msg *e, void *data); +extern s32 brcmf_cfg80211_up(struct brcmf_cfg80211_dev *cfg_dev); +extern s32 brcmf_cfg80211_down(struct brcmf_cfg80211_dev *cfg_dev); + +#endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/brcm80211/brcmsmac/Makefile new file mode 100644 index 000000000000..c2eb2d0af386 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile @@ -0,0 +1,51 @@ +# +# Makefile fragment for Broadcom 802.11n Networking Device Driver +# +# Copyright (c) 2010 Broadcom Corporation +# +# 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. + +ccflags-y := \ + -D__CHECK_ENDIAN__ \ + -Idrivers/net/wireless/brcm80211/brcmsmac \ + -Idrivers/net/wireless/brcm80211/brcmsmac/phy \ + -Idrivers/net/wireless/brcm80211/include + +BRCMSMAC_OFILES := \ + mac80211_if.o \ + ucode_loader.o \ + ampdu.o \ + antsel.o \ + channel.o \ + main.o \ + phy_shim.o \ + pmu.o \ + rate.o \ + stf.o \ + aiutils.o \ + phy/phy_cmn.o \ + phy/phy_lcn.o \ + phy/phy_n.o \ + phy/phytbl_lcn.o \ + phy/phytbl_n.o \ + phy/phy_qmath.o \ + otp.o \ + srom.o \ + dma.o \ + nicpci.o \ + brcms_trace_events.o + +MODULEPFX := brcmsmac + +obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o +$(MODULEPFX)-objs = $(BRCMSMAC_OFILES) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c new file mode 100644 index 000000000000..025fa0eb6f47 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c @@ -0,0 +1,2079 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + * + * File contents: support functions for PCI/PCIe + */ + +#include <linux/delay.h> +#include <linux/pci.h> + +#include <defs.h> +#include <chipcommon.h> +#include <brcmu_utils.h> +#include <brcm_hw_ids.h> +#include <soc.h> +#include "types.h" +#include "pub.h" +#include "pmu.h" +#include "srom.h" +#include "nicpci.h" +#include "aiutils.h" + +/* slow_clk_ctl */ + /* slow clock source mask */ +#define SCC_SS_MASK 0x00000007 + /* source of slow clock is LPO */ +#define SCC_SS_LPO 0x00000000 + /* source of slow clock is crystal */ +#define SCC_SS_XTAL 0x00000001 + /* source of slow clock is PCI */ +#define SCC_SS_PCI 0x00000002 + /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define SCC_LF 0x00000200 + /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */ +#define SCC_LP 0x00000400 + /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */ +#define SCC_FS 0x00000800 + /* IgnorePllOffReq, 1/0: + * power logic ignores/honors PLL clock disable requests from core + */ +#define SCC_IP 0x00001000 + /* XtalControlEn, 1/0: + * power logic does/doesn't disable crystal when appropriate + */ +#define SCC_XC 0x00002000 + /* XtalPU (RO), 1/0: crystal running/disabled */ +#define SCC_XP 0x00004000 + /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define SCC_CD_MASK 0xffff0000 +#define SCC_CD_SHIFT 16 + +/* system_clk_ctl */ + /* ILPen: Enable Idle Low Power */ +#define SYCC_IE 0x00000001 + /* ALPen: Enable Active Low Power */ +#define SYCC_AE 0x00000002 + /* ForcePLLOn */ +#define SYCC_FP 0x00000004 + /* Force ALP (or HT if ALPen is not set */ +#define SYCC_AR 0x00000008 + /* Force HT */ +#define SYCC_HR 0x00000010 + /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ +#define SYCC_CD_MASK 0xffff0000 +#define SYCC_CD_SHIFT 16 + +#define CST4329_SPROM_OTP_SEL_MASK 0x00000003 + /* OTP is powered up, use def. CIS, no SPROM */ +#define CST4329_DEFCIS_SEL 0 + /* OTP is powered up, SPROM is present */ +#define CST4329_SPROM_SEL 1 + /* OTP is powered up, no SPROM */ +#define CST4329_OTP_SEL 2 + /* OTP is powered down, SPROM is present */ +#define CST4329_OTP_PWRDN 3 + +#define CST4329_SPI_SDIO_MODE_MASK 0x00000004 +#define CST4329_SPI_SDIO_MODE_SHIFT 2 + +/* 43224 chip-specific ChipControl register bits */ +#define CCTRL43224_GPIO_TOGGLE 0x8000 + /* 12 mA drive strength */ +#define CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 + /* 12 mA drive strength for later 43224s */ +#define CCTRL_43224B0_12MA_LED_DRIVE 0xF0 + +/* 43236 Chip specific ChipStatus register bits */ +#define CST43236_SFLASH_MASK 0x00000040 +#define CST43236_OTP_MASK 0x00000080 +#define CST43236_HSIC_MASK 0x00000100 /* USB/HSIC */ +#define CST43236_BP_CLK 0x00000200 /* 120/96Mbps */ +#define CST43236_BOOT_MASK 0x00001800 +#define CST43236_BOOT_SHIFT 11 +#define CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ +#define CST43236_BOOT_FROM_ROM 1 /* boot from ROM */ +#define CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */ +#define CST43236_BOOT_FROM_INVALID 3 + +/* 4331 chip-specific ChipControl register bits */ + /* 0 disable */ +#define CCTRL4331_BT_COEXIST (1<<0) + /* 0 SECI is disabled (JTAG functional) */ +#define CCTRL4331_SECI (1<<1) + /* 0 disable */ +#define CCTRL4331_EXT_LNA (1<<2) + /* sprom/gpio13-15 mux */ +#define CCTRL4331_SPROM_GPIO13_15 (1<<3) + /* 0 ext pa disable, 1 ext pa enabled */ +#define CCTRL4331_EXTPA_EN (1<<4) + /* set drive out GPIO_CLK on sprom_cs pin */ +#define CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) + /* use sprom_cs pin as PCIE mdio interface */ +#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) + /* aband extpa will be at gpio2/5 and sprom_dout */ +#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) + /* override core control on pipe_AuxClkEnable */ +#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) + /* override core control on pipe_AuxPowerDown */ +#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) + /* pcie_auxclkenable */ +#define CCTRL4331_PCIE_AUXCLKEN (1<<10) + /* pcie_pipe_pllpowerdown */ +#define CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) + /* enable bt_shd0 at gpio4 */ +#define CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) + /* enable bt_shd1 at gpio5 */ +#define CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) + +/* 4331 Chip specific ChipStatus register bits */ + /* crystal frequency 20/40Mhz */ +#define CST4331_XTAL_FREQ 0x00000001 +#define CST4331_SPROM_PRESENT 0x00000002 +#define CST4331_OTP_PRESENT 0x00000004 +#define CST4331_LDO_RF 0x00000008 +#define CST4331_LDO_PAR 0x00000010 + +/* 4319 chip-specific ChipStatus register bits */ +#define CST4319_SPI_CPULESSUSB 0x00000001 +#define CST4319_SPI_CLK_POL 0x00000002 +#define CST4319_SPI_CLK_PH 0x00000008 + /* gpio [7:6], SDIO CIS selection */ +#define CST4319_SPROM_OTP_SEL_MASK 0x000000c0 +#define CST4319_SPROM_OTP_SEL_SHIFT 6 + /* use default CIS, OTP is powered up */ +#define CST4319_DEFCIS_SEL 0x00000000 + /* use SPROM, OTP is powered up */ +#define CST4319_SPROM_SEL 0x00000040 + /* use OTP, OTP is powered up */ +#define CST4319_OTP_SEL 0x00000080 + /* use SPROM, OTP is powered down */ +#define CST4319_OTP_PWRDN 0x000000c0 + /* gpio [8], sdio/usb mode */ +#define CST4319_SDIO_USB_MODE 0x00000100 +#define CST4319_REMAP_SEL_MASK 0x00000600 +#define CST4319_ILPDIV_EN 0x00000800 +#define CST4319_XTAL_PD_POL 0x00001000 +#define CST4319_LPO_SEL 0x00002000 +#define CST4319_RES_INIT_MODE 0x0000c000 + /* PALDO is configured with external PNP */ +#define CST4319_PALDO_EXTPNP 0x00010000 +#define CST4319_CBUCK_MODE_MASK 0x00060000 +#define CST4319_CBUCK_MODE_BURST 0x00020000 +#define CST4319_CBUCK_MODE_LPBURST 0x00060000 +#define CST4319_RCAL_VALID 0x01000000 +#define CST4319_RCAL_VALUE_MASK 0x3e000000 +#define CST4319_RCAL_VALUE_SHIFT 25 + +/* 4336 chip-specific ChipStatus register bits */ +#define CST4336_SPI_MODE_MASK 0x00000001 +#define CST4336_SPROM_PRESENT 0x00000002 +#define CST4336_OTP_PRESENT 0x00000004 +#define CST4336_ARMREMAP_0 0x00000008 +#define CST4336_ILPDIV_EN_MASK 0x00000010 +#define CST4336_ILPDIV_EN_SHIFT 4 +#define CST4336_XTAL_PD_POL_MASK 0x00000020 +#define CST4336_XTAL_PD_POL_SHIFT 5 +#define CST4336_LPO_SEL_MASK 0x00000040 +#define CST4336_LPO_SEL_SHIFT 6 +#define CST4336_RES_INIT_MODE_MASK 0x00000180 +#define CST4336_RES_INIT_MODE_SHIFT 7 +#define CST4336_CBUCK_MODE_MASK 0x00000600 +#define CST4336_CBUCK_MODE_SHIFT 9 + +/* 4313 chip-specific ChipStatus register bits */ +#define CST4313_SPROM_PRESENT 1 +#define CST4313_OTP_PRESENT 2 +#define CST4313_SPROM_OTP_SEL_MASK 0x00000002 +#define CST4313_SPROM_OTP_SEL_SHIFT 0 + +/* 4313 Chip specific ChipControl register bits */ + /* 12 mA drive strengh for later 4313 */ +#define CCTRL_4313_12MA_LED_DRIVE 0x00000007 + +/* Manufacturer Ids */ +#define MFGID_ARM 0x43b +#define MFGID_BRCM 0x4bf +#define MFGID_MIPS 0x4a7 + +/* Enumeration ROM registers */ +#define ER_EROMENTRY 0x000 +#define ER_REMAPCONTROL 0xe00 +#define ER_REMAPSELECT 0xe04 +#define ER_MASTERSELECT 0xe10 +#define ER_ITCR 0xf00 +#define ER_ITIP 0xf04 + +/* Erom entries */ +#define ER_TAG 0xe +#define ER_TAG1 0x6 +#define ER_VALID 1 +#define ER_CI 0 +#define ER_MP 2 +#define ER_ADD 4 +#define ER_END 0xe +#define ER_BAD 0xffffffff + +/* EROM CompIdentA */ +#define CIA_MFG_MASK 0xfff00000 +#define CIA_MFG_SHIFT 20 +#define CIA_CID_MASK 0x000fff00 +#define CIA_CID_SHIFT 8 +#define CIA_CCL_MASK 0x000000f0 +#define CIA_CCL_SHIFT 4 + +/* EROM CompIdentB */ +#define CIB_REV_MASK 0xff000000 +#define CIB_REV_SHIFT 24 +#define CIB_NSW_MASK 0x00f80000 +#define CIB_NSW_SHIFT 19 +#define CIB_NMW_MASK 0x0007c000 +#define CIB_NMW_SHIFT 14 +#define CIB_NSP_MASK 0x00003e00 +#define CIB_NSP_SHIFT 9 +#define CIB_NMP_MASK 0x000001f0 +#define CIB_NMP_SHIFT 4 + +/* EROM AddrDesc */ +#define AD_ADDR_MASK 0xfffff000 +#define AD_SP_MASK 0x00000f00 +#define AD_SP_SHIFT 8 +#define AD_ST_MASK 0x000000c0 +#define AD_ST_SHIFT 6 +#define AD_ST_SLAVE 0x00000000 +#define AD_ST_BRIDGE 0x00000040 +#define AD_ST_SWRAP 0x00000080 +#define AD_ST_MWRAP 0x000000c0 +#define AD_SZ_MASK 0x00000030 +#define AD_SZ_SHIFT 4 +#define AD_SZ_4K 0x00000000 +#define AD_SZ_8K 0x00000010 +#define AD_SZ_16K 0x00000020 +#define AD_SZ_SZD 0x00000030 +#define AD_AG32 0x00000008 +#define AD_ADDR_ALIGN 0x00000fff +#define AD_SZ_BASE 0x00001000 /* 4KB */ + +/* EROM SizeDesc */ +#define SD_SZ_MASK 0xfffff000 +#define SD_SG32 0x00000008 +#define SD_SZ_ALIGN 0x00000fff + +/* PCI config space bit 4 for 4306c0 slow clock source */ +#define PCI_CFG_GPIO_SCS 0x10 +/* PCI config space GPIO 14 for Xtal power-up */ +#define PCI_CFG_GPIO_XTAL 0x40 +/* PCI config space GPIO 15 for PLL power-down */ +#define PCI_CFG_GPIO_PLL 0x80 + +/* power control defines */ +#define PLL_DELAY 150 /* us pll on delay */ +#define FREF_DELAY 200 /* us fref change delay */ +#define XTAL_ON_DELAY 1000 /* us crystal power-on delay */ + +/* resetctrl */ +#define AIRC_RESET 1 + +#define NOREV -1 /* Invalid rev */ + +/* GPIO Based LED powersave defines */ +#define DEFAULT_GPIO_ONTIME 10 /* Default: 10% on */ +#define DEFAULT_GPIO_OFFTIME 90 /* Default: 10% on */ + +/* When Srom support present, fields in sromcontrol */ +#define SRC_START 0x80000000 +#define SRC_BUSY 0x80000000 +#define SRC_OPCODE 0x60000000 +#define SRC_OP_READ 0x00000000 +#define SRC_OP_WRITE 0x20000000 +#define SRC_OP_WRDIS 0x40000000 +#define SRC_OP_WREN 0x60000000 +#define SRC_OTPSEL 0x00000010 +#define SRC_LOCK 0x00000008 +#define SRC_SIZE_MASK 0x00000006 +#define SRC_SIZE_1K 0x00000000 +#define SRC_SIZE_4K 0x00000002 +#define SRC_SIZE_16K 0x00000004 +#define SRC_SIZE_SHIFT 1 +#define SRC_PRESENT 0x00000001 + +/* External PA enable mask */ +#define GPIO_CTRL_EPA_EN_MASK 0x40 + +#define DEFAULT_GPIOTIMERVAL \ + ((DEFAULT_GPIO_ONTIME << GPIO_ONTIME_SHIFT) | DEFAULT_GPIO_OFFTIME) + +#define BADIDX (SI_MAXCORES + 1) + +/* Newer chips can access PCI/PCIE and CC core without requiring to change + * PCI BAR0 WIN + */ +#define SI_FAST(si) (((si)->pub.buscoretype == PCIE_CORE_ID) || \ + (((si)->pub.buscoretype == PCI_CORE_ID) && \ + (si)->pub.buscorerev >= 13)) + +#define CCREGS_FAST(si) (((char __iomem *)((si)->curmap) + \ + PCI_16KB0_CCREGS_OFFSET)) + +#define IS_SIM(chippkg) \ + ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) + +/* + * Macros to disable/restore function core(D11, ENET, ILINE20, etc) interrupts + * before after core switching to avoid invalid register accesss inside ISR. + */ +#define INTR_OFF(si, intr_val) \ + if ((si)->intrsoff_fn && \ + (si)->coreid[(si)->curidx] == (si)->dev_coreid) \ + intr_val = (*(si)->intrsoff_fn)((si)->intr_arg) + +#define INTR_RESTORE(si, intr_val) \ + if ((si)->intrsrestore_fn && \ + (si)->coreid[(si)->curidx] == (si)->dev_coreid) \ + (*(si)->intrsrestore_fn)((si)->intr_arg, intr_val) + +#define PCI(si) ((si)->pub.buscoretype == PCI_CORE_ID) +#define PCIE(si) ((si)->pub.buscoretype == PCIE_CORE_ID) + +#define PCI_FORCEHT(si) (PCIE(si) && (si->pub.chip == BCM4716_CHIP_ID)) + +#ifdef BCMDBG +#define SI_MSG(args) printk args +#else +#define SI_MSG(args) +#endif /* BCMDBG */ + +#define GOODCOREADDR(x, b) \ + (((x) >= (b)) && ((x) < ((b) + SI_MAXCORES * SI_CORE_SIZE)) && \ + IS_ALIGNED((x), SI_CORE_SIZE)) + +#define PCIEREGS(si) ((__iomem char *)((si)->curmap) + \ + PCI_16KB0_PCIREGS_OFFSET) + +struct aidmp { + u32 oobselina30; /* 0x000 */ + u32 oobselina74; /* 0x004 */ + u32 PAD[6]; + u32 oobselinb30; /* 0x020 */ + u32 oobselinb74; /* 0x024 */ + u32 PAD[6]; + u32 oobselinc30; /* 0x040 */ + u32 oobselinc74; /* 0x044 */ + u32 PAD[6]; + u32 oobselind30; /* 0x060 */ + u32 oobselind74; /* 0x064 */ + u32 PAD[38]; + u32 oobselouta30; /* 0x100 */ + u32 oobselouta74; /* 0x104 */ + u32 PAD[6]; + u32 oobseloutb30; /* 0x120 */ + u32 oobseloutb74; /* 0x124 */ + u32 PAD[6]; + u32 oobseloutc30; /* 0x140 */ + u32 oobseloutc74; /* 0x144 */ + u32 PAD[6]; + u32 oobseloutd30; /* 0x160 */ + u32 oobseloutd74; /* 0x164 */ + u32 PAD[38]; + u32 oobsynca; /* 0x200 */ + u32 oobseloutaen; /* 0x204 */ + u32 PAD[6]; + u32 oobsyncb; /* 0x220 */ + u32 oobseloutben; /* 0x224 */ + u32 PAD[6]; + u32 oobsyncc; /* 0x240 */ + u32 oobseloutcen; /* 0x244 */ + u32 PAD[6]; + u32 oobsyncd; /* 0x260 */ + u32 oobseloutden; /* 0x264 */ + u32 PAD[38]; + u32 oobaextwidth; /* 0x300 */ + u32 oobainwidth; /* 0x304 */ + u32 oobaoutwidth; /* 0x308 */ + u32 PAD[5]; + u32 oobbextwidth; /* 0x320 */ + u32 oobbinwidth; /* 0x324 */ + u32 oobboutwidth; /* 0x328 */ + u32 PAD[5]; + u32 oobcextwidth; /* 0x340 */ + u32 oobcinwidth; /* 0x344 */ + u32 oobcoutwidth; /* 0x348 */ + u32 PAD[5]; + u32 oobdextwidth; /* 0x360 */ + u32 oobdinwidth; /* 0x364 */ + u32 oobdoutwidth; /* 0x368 */ + u32 PAD[37]; + u32 ioctrlset; /* 0x400 */ + u32 ioctrlclear; /* 0x404 */ + u32 ioctrl; /* 0x408 */ + u32 PAD[61]; + u32 iostatus; /* 0x500 */ + u32 PAD[127]; + u32 ioctrlwidth; /* 0x700 */ + u32 iostatuswidth; /* 0x704 */ + u32 PAD[62]; + u32 resetctrl; /* 0x800 */ + u32 resetstatus; /* 0x804 */ + u32 resetreadid; /* 0x808 */ + u32 resetwriteid; /* 0x80c */ + u32 PAD[60]; + u32 errlogctrl; /* 0x900 */ + u32 errlogdone; /* 0x904 */ + u32 errlogstatus; /* 0x908 */ + u32 errlogaddrlo; /* 0x90c */ + u32 errlogaddrhi; /* 0x910 */ + u32 errlogid; /* 0x914 */ + u32 errloguser; /* 0x918 */ + u32 errlogflags; /* 0x91c */ + u32 PAD[56]; + u32 intstatus; /* 0xa00 */ + u32 PAD[127]; + u32 config; /* 0xe00 */ + u32 PAD[63]; + u32 itcr; /* 0xf00 */ + u32 PAD[3]; + u32 itipooba; /* 0xf10 */ + u32 itipoobb; /* 0xf14 */ + u32 itipoobc; /* 0xf18 */ + u32 itipoobd; /* 0xf1c */ + u32 PAD[4]; + u32 itipoobaout; /* 0xf30 */ + u32 itipoobbout; /* 0xf34 */ + u32 itipoobcout; /* 0xf38 */ + u32 itipoobdout; /* 0xf3c */ + u32 PAD[4]; + u32 itopooba; /* 0xf50 */ + u32 itopoobb; /* 0xf54 */ + u32 itopoobc; /* 0xf58 */ + u32 itopoobd; /* 0xf5c */ + u32 PAD[4]; + u32 itopoobain; /* 0xf70 */ + u32 itopoobbin; /* 0xf74 */ + u32 itopoobcin; /* 0xf78 */ + u32 itopoobdin; /* 0xf7c */ + u32 PAD[4]; + u32 itopreset; /* 0xf90 */ + u32 PAD[15]; + u32 peripherialid4; /* 0xfd0 */ + u32 peripherialid5; /* 0xfd4 */ + u32 peripherialid6; /* 0xfd8 */ + u32 peripherialid7; /* 0xfdc */ + u32 peripherialid0; /* 0xfe0 */ + u32 peripherialid1; /* 0xfe4 */ + u32 peripherialid2; /* 0xfe8 */ + u32 peripherialid3; /* 0xfec */ + u32 componentid0; /* 0xff0 */ + u32 componentid1; /* 0xff4 */ + u32 componentid2; /* 0xff8 */ + u32 componentid3; /* 0xffc */ +}; + +/* EROM parsing */ + +static u32 +get_erom_ent(struct si_pub *sih, u32 __iomem **eromptr, u32 mask, u32 match) +{ + u32 ent; + uint inv = 0, nom = 0; + + while (true) { + ent = R_REG(*eromptr); + (*eromptr)++; + + if (mask == 0) + break; + + if ((ent & ER_VALID) == 0) { + inv++; + continue; + } + + if (ent == (ER_END | ER_VALID)) + break; + + if ((ent & mask) == match) + break; + + nom++; + } + + return ent; +} + +static u32 +get_asd(struct si_pub *sih, u32 __iomem **eromptr, uint sp, uint ad, uint st, + u32 *addrl, u32 *addrh, u32 *sizel, u32 *sizeh) +{ + u32 asd, sz, szd; + + asd = get_erom_ent(sih, eromptr, ER_VALID, ER_VALID); + if (((asd & ER_TAG1) != ER_ADD) || + (((asd & AD_SP_MASK) >> AD_SP_SHIFT) != sp) || + ((asd & AD_ST_MASK) != st)) { + /* This is not what we want, "push" it back */ + (*eromptr)--; + return 0; + } + *addrl = asd & AD_ADDR_MASK; + if (asd & AD_AG32) + *addrh = get_erom_ent(sih, eromptr, 0, 0); + else + *addrh = 0; + *sizeh = 0; + sz = asd & AD_SZ_MASK; + if (sz == AD_SZ_SZD) { + szd = get_erom_ent(sih, eromptr, 0, 0); + *sizel = szd & SD_SZ_MASK; + if (szd & SD_SG32) + *sizeh = get_erom_ent(sih, eromptr, 0, 0); + } else + *sizel = AD_SZ_BASE << (sz >> AD_SZ_SHIFT); + + return asd; +} + +static void ai_hwfixup(struct si_info *sii) +{ +} + +/* parse the enumeration rom to identify all cores */ +static void ai_scan(struct si_pub *sih, struct chipcregs __iomem *cc) +{ + struct si_info *sii = (struct si_info *)sih; + + u32 erombase; + u32 __iomem *eromptr, *eromlim; + void __iomem *regs = cc; + + erombase = R_REG(&cc->eromptr); + + /* Set wrappers address */ + sii->curwrap = (void *)((unsigned long)cc + SI_CORE_SIZE); + + /* Now point the window at the erom */ + pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, erombase); + eromptr = regs; + eromlim = eromptr + (ER_REMAPCONTROL / sizeof(u32)); + + while (eromptr < eromlim) { + u32 cia, cib, cid, mfg, crev, nmw, nsw, nmp, nsp; + u32 mpd, asd, addrl, addrh, sizel, sizeh; + u32 __iomem *base; + uint i, j, idx; + bool br; + + br = false; + + /* Grok a component */ + cia = get_erom_ent(sih, &eromptr, ER_TAG, ER_CI); + if (cia == (ER_END | ER_VALID)) { + /* Found END of erom */ + ai_hwfixup(sii); + return; + } + base = eromptr - 1; + cib = get_erom_ent(sih, &eromptr, 0, 0); + + if ((cib & ER_TAG) != ER_CI) { + /* CIA not followed by CIB */ + goto error; + } + + cid = (cia & CIA_CID_MASK) >> CIA_CID_SHIFT; + mfg = (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; + crev = (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; + nmw = (cib & CIB_NMW_MASK) >> CIB_NMW_SHIFT; + nsw = (cib & CIB_NSW_MASK) >> CIB_NSW_SHIFT; + nmp = (cib & CIB_NMP_MASK) >> CIB_NMP_SHIFT; + nsp = (cib & CIB_NSP_MASK) >> CIB_NSP_SHIFT; + + if (((mfg == MFGID_ARM) && (cid == DEF_AI_COMP)) || (nsp == 0)) + continue; + if ((nmw + nsw == 0)) { + /* A component which is not a core */ + if (cid == OOB_ROUTER_CORE_ID) { + asd = get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, + &addrl, &addrh, &sizel, &sizeh); + if (asd != 0) + sii->oob_router = addrl; + } + continue; + } + + idx = sii->numcores; +/* sii->eromptr[idx] = base; */ + sii->cia[idx] = cia; + sii->cib[idx] = cib; + sii->coreid[idx] = cid; + + for (i = 0; i < nmp; i++) { + mpd = get_erom_ent(sih, &eromptr, ER_VALID, ER_VALID); + if ((mpd & ER_TAG) != ER_MP) { + /* Not enough MP entries for component */ + goto error; + } + } + + /* First Slave Address Descriptor should be port 0: + * the main register space for the core + */ + asd = + get_asd(sih, &eromptr, 0, 0, AD_ST_SLAVE, &addrl, &addrh, + &sizel, &sizeh); + if (asd == 0) { + /* Try again to see if it is a bridge */ + asd = + get_asd(sih, &eromptr, 0, 0, AD_ST_BRIDGE, &addrl, + &addrh, &sizel, &sizeh); + if (asd != 0) + br = true; + else if ((addrh != 0) || (sizeh != 0) + || (sizel != SI_CORE_SIZE)) { + /* First Slave ASD for core malformed */ + goto error; + } + } + sii->coresba[idx] = addrl; + sii->coresba_size[idx] = sizel; + /* Get any more ASDs in port 0 */ + j = 1; + do { + asd = + get_asd(sih, &eromptr, 0, j, AD_ST_SLAVE, &addrl, + &addrh, &sizel, &sizeh); + if ((asd != 0) && (j == 1) && (sizel == SI_CORE_SIZE)) { + sii->coresba2[idx] = addrl; + sii->coresba2_size[idx] = sizel; + } + j++; + } while (asd != 0); + + /* Go through the ASDs for other slave ports */ + for (i = 1; i < nsp; i++) { + j = 0; + do { + asd = + get_asd(sih, &eromptr, i, j++, AD_ST_SLAVE, + &addrl, &addrh, &sizel, &sizeh); + } while (asd != 0); + if (j == 0) { + /* SP has no address descriptors */ + goto error; + } + } + + /* Now get master wrappers */ + for (i = 0; i < nmw; i++) { + asd = + get_asd(sih, &eromptr, i, 0, AD_ST_MWRAP, &addrl, + &addrh, &sizel, &sizeh); + if (asd == 0) { + /* Missing descriptor for MW */ + goto error; + } + if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { + /* Master wrapper %d is not 4KB */ + goto error; + } + if (i == 0) + sii->wrapba[idx] = addrl; + } + + /* And finally slave wrappers */ + for (i = 0; i < nsw; i++) { + uint fwp = (nsp == 1) ? 0 : 1; + asd = + get_asd(sih, &eromptr, fwp + i, 0, AD_ST_SWRAP, + &addrl, &addrh, &sizel, &sizeh); + if (asd == 0) { + /* Missing descriptor for SW */ + goto error; + } + if ((sizeh != 0) || (sizel != SI_CORE_SIZE)) { + /* Slave wrapper is not 4KB */ + goto error; + } + if ((nmw == 0) && (i == 0)) + sii->wrapba[idx] = addrl; + } + + /* Don't record bridges */ + if (br) + continue; + + /* Done with core */ + sii->numcores++; + } + + error: + /* Reached end of erom without finding END */ + sii->numcores = 0; + return; +} + +/* + * This function changes the logical "focus" to the indicated core. + * Return the current core's virtual address. Since each core starts with the + * same set of registers (BIST, clock control, etc), the returned address + * contains the first register of this 'common' register block (not to be + * confused with 'common core'). + */ +void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx) +{ + struct si_info *sii = (struct si_info *)sih; + u32 addr = sii->coresba[coreidx]; + u32 wrap = sii->wrapba[coreidx]; + + if (coreidx >= sii->numcores) + return NULL; + + /* point bar0 window */ + pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, addr); + /* point bar0 2nd 4KB window */ + pci_write_config_dword(sii->pbus, PCI_BAR0_WIN2, wrap); + sii->curidx = coreidx; + + return sii->curmap; +} + +/* Return the number of address spaces in current core */ +int ai_numaddrspaces(struct si_pub *sih) +{ + return 2; +} + +/* Return the address of the nth address space in the current core */ +u32 ai_addrspace(struct si_pub *sih, uint asidx) +{ + struct si_info *sii; + uint cidx; + + sii = (struct si_info *)sih; + cidx = sii->curidx; + + if (asidx == 0) + return sii->coresba[cidx]; + else if (asidx == 1) + return sii->coresba2[cidx]; + else { + /* Need to parse the erom again to find addr space */ + return 0; + } +} + +/* Return the size of the nth address space in the current core */ +u32 ai_addrspacesize(struct si_pub *sih, uint asidx) +{ + struct si_info *sii; + uint cidx; + + sii = (struct si_info *)sih; + cidx = sii->curidx; + + if (asidx == 0) + return sii->coresba_size[cidx]; + else if (asidx == 1) + return sii->coresba2_size[cidx]; + else { + /* Need to parse the erom again to find addr */ + return 0; + } +} + +uint ai_flag(struct si_pub *sih) +{ + struct si_info *sii; + struct aidmp *ai; + + sii = (struct si_info *)sih; + ai = sii->curwrap; + + return R_REG(&ai->oobselouta30) & 0x1f; +} + +void ai_setint(struct si_pub *sih, int siflag) +{ +} + +uint ai_corevendor(struct si_pub *sih) +{ + struct si_info *sii; + u32 cia; + + sii = (struct si_info *)sih; + cia = sii->cia[sii->curidx]; + return (cia & CIA_MFG_MASK) >> CIA_MFG_SHIFT; +} + +uint ai_corerev(struct si_pub *sih) +{ + struct si_info *sii; + u32 cib; + + sii = (struct si_info *)sih; + cib = sii->cib[sii->curidx]; + return (cib & CIB_REV_MASK) >> CIB_REV_SHIFT; +} + +bool ai_iscoreup(struct si_pub *sih) +{ + struct si_info *sii; + struct aidmp *ai; + + sii = (struct si_info *)sih; + ai = sii->curwrap; + + return (((R_REG(&ai->ioctrl) & (SICF_FGC | SICF_CLOCK_EN)) == + SICF_CLOCK_EN) + && ((R_REG(&ai->resetctrl) & AIRC_RESET) == 0)); +} + +void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val) +{ + struct si_info *sii; + struct aidmp *ai; + u32 w; + + sii = (struct si_info *)sih; + + ai = sii->curwrap; + + if (mask || val) { + w = ((R_REG(&ai->ioctrl) & ~mask) | val); + W_REG(&ai->ioctrl, w); + } +} + +u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val) +{ + struct si_info *sii; + struct aidmp *ai; + u32 w; + + sii = (struct si_info *)sih; + ai = sii->curwrap; + + if (mask || val) { + w = ((R_REG(&ai->ioctrl) & ~mask) | val); + W_REG(&ai->ioctrl, w); + } + + return R_REG(&ai->ioctrl); +} + +/* return true if PCIE capability exists in the pci config space */ +static bool ai_ispcie(struct si_info *sii) +{ + u8 cap_ptr; + + cap_ptr = + pcicore_find_pci_capability(sii->pbus, PCI_CAP_ID_EXP, NULL, + NULL); + if (!cap_ptr) + return false; + + return true; +} + +static bool ai_buscore_prep(struct si_info *sii) +{ + /* kludge to enable the clock on the 4306 which lacks a slowclock */ + if (!ai_ispcie(sii)) + ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON); + return true; +} + +u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val) +{ + struct si_info *sii; + struct aidmp *ai; + u32 w; + + sii = (struct si_info *)sih; + ai = sii->curwrap; + + if (mask || val) { + w = ((R_REG(&ai->iostatus) & ~mask) | val); + W_REG(&ai->iostatus, w); + } + + return R_REG(&ai->iostatus); +} + +static bool +ai_buscore_setup(struct si_info *sii, u32 savewin, uint *origidx) +{ + bool pci, pcie; + uint i; + uint pciidx, pcieidx, pcirev, pcierev; + struct chipcregs __iomem *cc; + + cc = ai_setcoreidx(&sii->pub, SI_CC_IDX); + + /* get chipcommon rev */ + sii->pub.ccrev = (int)ai_corerev(&sii->pub); + + /* get chipcommon chipstatus */ + if (sii->pub.ccrev >= 11) + sii->pub.chipst = R_REG(&cc->chipstatus); + + /* get chipcommon capabilites */ + sii->pub.cccaps = R_REG(&cc->capabilities); + /* get chipcommon extended capabilities */ + + if (sii->pub.ccrev >= 35) + sii->pub.cccaps_ext = R_REG(&cc->capabilities_ext); + + /* get pmu rev and caps */ + if (sii->pub.cccaps & CC_CAP_PMU) { + sii->pub.pmucaps = R_REG(&cc->pmucapabilities); + sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; + } + + /* figure out bus/orignal core idx */ + sii->pub.buscoretype = NODEV_CORE_ID; + sii->pub.buscorerev = NOREV; + sii->pub.buscoreidx = BADIDX; + + pci = pcie = false; + pcirev = pcierev = NOREV; + pciidx = pcieidx = BADIDX; + + for (i = 0; i < sii->numcores; i++) { + uint cid, crev; + + ai_setcoreidx(&sii->pub, i); + cid = ai_coreid(&sii->pub); + crev = ai_corerev(&sii->pub); + + if (cid == PCI_CORE_ID) { + pciidx = i; + pcirev = crev; + pci = true; + } else if (cid == PCIE_CORE_ID) { + pcieidx = i; + pcierev = crev; + pcie = true; + } + + /* find the core idx before entering this func. */ + if ((savewin && (savewin == sii->coresba[i])) || + (cc == sii->regs[i])) + *origidx = i; + } + + if (pci && pcie) { + if (ai_ispcie(sii)) + pci = false; + else + pcie = false; + } + if (pci) { + sii->pub.buscoretype = PCI_CORE_ID; + sii->pub.buscorerev = pcirev; + sii->pub.buscoreidx = pciidx; + } else if (pcie) { + sii->pub.buscoretype = PCIE_CORE_ID; + sii->pub.buscorerev = pcierev; + sii->pub.buscoreidx = pcieidx; + } + + /* fixup necessary chip/core configurations */ + if (SI_FAST(sii)) { + if (!sii->pch) { + sii->pch = pcicore_init(&sii->pub, sii->pbus, + (__iomem void *)PCIEREGS(sii)); + if (sii->pch == NULL) + return false; + } + } + if (ai_pci_fixcfg(&sii->pub)) { + /* si_doattach: si_pci_fixcfg failed */ + return false; + } + + /* return to the original core */ + ai_setcoreidx(&sii->pub, *origidx); + + return true; +} + +/* + * get boardtype and boardrev + */ +static __used void ai_nvram_process(struct si_info *sii) +{ + uint w = 0; + + /* do a pci config read to get subsystem id and subvendor id */ + pci_read_config_dword(sii->pbus, PCI_SUBSYSTEM_VENDOR_ID, &w); + + sii->pub.boardvendor = w & 0xffff; + sii->pub.boardtype = (w >> 16) & 0xffff; + sii->pub.boardflags = getintvar(&sii->pub, BRCMS_SROM_BOARDFLAGS); +} + +static struct si_info *ai_doattach(struct si_info *sii, + void __iomem *regs, struct pci_dev *pbus) +{ + struct si_pub *sih = &sii->pub; + u32 w, savewin; + struct chipcregs __iomem *cc; + uint socitype; + uint origidx; + + memset((unsigned char *) sii, 0, sizeof(struct si_info)); + + savewin = 0; + + sih->buscoreidx = BADIDX; + + sii->curmap = regs; + sii->pbus = pbus; + + /* find Chipcommon address */ + pci_read_config_dword(sii->pbus, PCI_BAR0_WIN, &savewin); + if (!GOODCOREADDR(savewin, SI_ENUM_BASE)) + savewin = SI_ENUM_BASE; + + pci_write_config_dword(sii->pbus, PCI_BAR0_WIN, + SI_ENUM_BASE); + cc = (struct chipcregs __iomem *) regs; + + /* bus/core/clk setup for register access */ + if (!ai_buscore_prep(sii)) + return NULL; + + /* + * ChipID recognition. + * We assume we can read chipid at offset 0 from the regs arg. + * If we add other chiptypes (or if we need to support old sdio + * hosts w/o chipcommon), some way of recognizing them needs to + * be added here. + */ + w = R_REG(&cc->chipid); + socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; + /* Might as wll fill in chip id rev & pkg */ + sih->chip = w & CID_ID_MASK; + sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; + sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; + + sih->issim = false; + + /* scan for cores */ + if (socitype == SOCI_AI) { + SI_MSG(("Found chip type AI (0x%08x)\n", w)); + /* pass chipc address instead of original core base */ + ai_scan(&sii->pub, cc); + } else { + /* Found chip of unknown type */ + return NULL; + } + /* no cores found, bail out */ + if (sii->numcores == 0) + return NULL; + + /* bus/core/clk setup */ + origidx = SI_CC_IDX; + if (!ai_buscore_setup(sii, savewin, &origidx)) + goto exit; + + /* Init nvram from sprom/otp if they exist */ + if (srom_var_init(&sii->pub, cc)) + goto exit; + + ai_nvram_process(sii); + + /* === NVRAM, clock is ready === */ + cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0); + W_REG(&cc->gpiopullup, 0); + W_REG(&cc->gpiopulldown, 0); + ai_setcoreidx(sih, origidx); + + /* PMU specific initializations */ + if (sih->cccaps & CC_CAP_PMU) { + u32 xtalfreq; + si_pmu_init(sih); + si_pmu_chip_init(sih); + + xtalfreq = si_pmu_measure_alpclk(sih); + si_pmu_pll_init(sih, xtalfreq); + si_pmu_res_init(sih); + si_pmu_swreg_init(sih); + } + + /* setup the GPIO based LED powersave register */ + w = getintvar(sih, BRCMS_SROM_LEDDC); + if (w == 0) + w = DEFAULT_GPIOTIMERVAL; + ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, gpiotimerval), + ~0, w); + + if (PCIE(sii)) + pcicore_attach(sii->pch, SI_DOATTACH); + + if (sih->chip == BCM43224_CHIP_ID) { + /* + * enable 12 mA drive strenth for 43224 and + * set chipControl register bit 15 + */ + if (sih->chiprev == 0) { + SI_MSG(("Applying 43224A0 WARs\n")); + ai_corereg(sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol), + CCTRL43224_GPIO_TOGGLE, + CCTRL43224_GPIO_TOGGLE); + si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE, + CCTRL_43224A0_12MA_LED_DRIVE); + } + if (sih->chiprev >= 1) { + SI_MSG(("Applying 43224B0+ WARs\n")); + si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE, + CCTRL_43224B0_12MA_LED_DRIVE); + } + } + + if (sih->chip == BCM4313_CHIP_ID) { + /* + * enable 12 mA drive strenth for 4313 and + * set chipControl register bit 1 + */ + SI_MSG(("Applying 4313 WARs\n")); + si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE, + CCTRL_4313_12MA_LED_DRIVE); + } + + return sii; + + exit: + if (sii->pch) + pcicore_deinit(sii->pch); + sii->pch = NULL; + + return NULL; +} + +/* + * Allocate a si handle. + * devid - pci device id (used to determine chip#) + * osh - opaque OS handle + * regs - virtual address of initial core registers + */ +struct si_pub * +ai_attach(void __iomem *regs, struct pci_dev *sdh) +{ + struct si_info *sii; + + /* alloc struct si_info */ + sii = kmalloc(sizeof(struct si_info), GFP_ATOMIC); + if (sii == NULL) + return NULL; + + if (ai_doattach(sii, regs, sdh) == NULL) { + kfree(sii); + return NULL; + } + + return (struct si_pub *) sii; +} + +/* may be called with core in reset */ +void ai_detach(struct si_pub *sih) +{ + struct si_info *sii; + + struct si_pub *si_local = NULL; + memcpy(&si_local, &sih, sizeof(struct si_pub **)); + + sii = (struct si_info *)sih; + + if (sii == NULL) + return; + + if (sii->pch) + pcicore_deinit(sii->pch); + sii->pch = NULL; + + srom_free_vars(sih); + kfree(sii); +} + +/* register driver interrupt disabling and restoring callback functions */ +void +ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn, + void *intrsrestore_fn, + void *intrsenabled_fn, void *intr_arg) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + sii->intr_arg = intr_arg; + sii->intrsoff_fn = (u32 (*)(void *)) intrsoff_fn; + sii->intrsrestore_fn = (void (*) (void *, u32)) intrsrestore_fn; + sii->intrsenabled_fn = (bool (*)(void *)) intrsenabled_fn; + /* save current core id. when this function called, the current core + * must be the core which provides driver functions(il, et, wl, etc.) + */ + sii->dev_coreid = sii->coreid[sii->curidx]; +} + +void ai_deregister_intr_callback(struct si_pub *sih) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + sii->intrsoff_fn = NULL; +} + +uint ai_coreid(struct si_pub *sih) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + return sii->coreid[sii->curidx]; +} + +uint ai_coreidx(struct si_pub *sih) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + return sii->curidx; +} + +bool ai_backplane64(struct si_pub *sih) +{ + return (sih->cccaps & CC_CAP_BKPLN64) != 0; +} + +/* return index of coreid or BADIDX if not found */ +uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit) +{ + struct si_info *sii; + uint found; + uint i; + + sii = (struct si_info *)sih; + + found = 0; + + for (i = 0; i < sii->numcores; i++) + if (sii->coreid[i] == coreid) { + if (found == coreunit) + return i; + found++; + } + + return BADIDX; +} + +/* + * This function changes logical "focus" to the indicated core; + * must be called with interrupts off. + * Moreover, callers should keep interrupts off during switching + * out of and back to d11 core. + */ +void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit) +{ + uint idx; + + idx = ai_findcoreidx(sih, coreid, coreunit); + if (idx >= SI_MAXCORES) + return NULL; + + return ai_setcoreidx(sih, idx); +} + +/* Turn off interrupt as required by ai_setcore, before switch core */ +void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, uint *origidx, + uint *intr_val) +{ + void __iomem *cc; + struct si_info *sii; + + sii = (struct si_info *)sih; + + if (SI_FAST(sii)) { + /* Overloading the origidx variable to remember the coreid, + * this works because the core ids cannot be confused with + * core indices. + */ + *origidx = coreid; + if (coreid == CC_CORE_ID) + return CCREGS_FAST(sii); + else if (coreid == sih->buscoretype) + return PCIEREGS(sii); + } + INTR_OFF(sii, *intr_val); + *origidx = sii->curidx; + cc = ai_setcore(sih, coreid, 0); + return cc; +} + +/* restore coreidx and restore interrupt */ +void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + if (SI_FAST(sii) + && ((coreid == CC_CORE_ID) || (coreid == sih->buscoretype))) + return; + + ai_setcoreidx(sih, coreid); + INTR_RESTORE(sii, intr_val); +} + +void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val) +{ + struct si_info *sii = (struct si_info *)sih; + u32 *w = (u32 *) sii->curwrap; + W_REG(w + (offset / 4), val); + return; +} + +/* + * Switch to 'coreidx', issue a single arbitrary 32bit register mask&set + * operation, switch back to the original core, and return the new value. + * + * When using the silicon backplane, no fiddling with interrupts or core + * switches is needed. + * + * Also, when using pci/pcie, we can optimize away the core switching for pci + * registers and (on newer pci cores) chipcommon registers. + */ +uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, + uint val) +{ + uint origidx = 0; + u32 __iomem *r = NULL; + uint w; + uint intr_val = 0; + bool fast = false; + struct si_info *sii; + + sii = (struct si_info *)sih; + + if (coreidx >= SI_MAXCORES) + return 0; + + /* + * If pci/pcie, we can get at pci/pcie regs + * and on newer cores to chipc + */ + if ((sii->coreid[coreidx] == CC_CORE_ID) && SI_FAST(sii)) { + /* Chipc registers are mapped at 12KB */ + fast = true; + r = (u32 __iomem *)((__iomem char *)sii->curmap + + PCI_16KB0_CCREGS_OFFSET + regoff); + } else if (sii->pub.buscoreidx == coreidx) { + /* + * pci registers are at either in the last 2KB of + * an 8KB window or, in pcie and pci rev 13 at 8KB + */ + fast = true; + if (SI_FAST(sii)) + r = (u32 __iomem *)((__iomem char *)sii->curmap + + PCI_16KB0_PCIREGS_OFFSET + regoff); + else + r = (u32 __iomem *)((__iomem char *)sii->curmap + + ((regoff >= SBCONFIGOFF) ? + PCI_BAR0_PCISBR_OFFSET : + PCI_BAR0_PCIREGS_OFFSET) + regoff); + } + + if (!fast) { + INTR_OFF(sii, intr_val); + + /* save current core index */ + origidx = ai_coreidx(&sii->pub); + + /* switch core */ + r = (u32 __iomem *) ((unsigned char __iomem *) + ai_setcoreidx(&sii->pub, coreidx) + regoff); + } + + /* mask and set */ + if (mask || val) { + w = (R_REG(r) & ~mask) | val; + W_REG(r, w); + } + + /* readback */ + w = R_REG(r); + + if (!fast) { + /* restore core index */ + if (origidx != coreidx) + ai_setcoreidx(&sii->pub, origidx); + + INTR_RESTORE(sii, intr_val); + } + + return w; +} + +void ai_core_disable(struct si_pub *sih, u32 bits) +{ + struct si_info *sii; + u32 dummy; + struct aidmp *ai; + + sii = (struct si_info *)sih; + + ai = sii->curwrap; + + /* if core is already in reset, just return */ + if (R_REG(&ai->resetctrl) & AIRC_RESET) + return; + + W_REG(&ai->ioctrl, bits); + dummy = R_REG(&ai->ioctrl); + udelay(10); + + W_REG(&ai->resetctrl, AIRC_RESET); + udelay(1); +} + +/* reset and re-enable a core + * inputs: + * bits - core specific bits that are set during and after reset sequence + * resetbits - core specific bits that are set only during reset sequence + */ +void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits) +{ + struct si_info *sii; + struct aidmp *ai; + u32 dummy; + + sii = (struct si_info *)sih; + ai = sii->curwrap; + + /* + * Must do the disable sequence first to work + * for arbitrary current core state. + */ + ai_core_disable(sih, (bits | resetbits)); + + /* + * Now do the initialization sequence. + */ + W_REG(&ai->ioctrl, (bits | SICF_FGC | SICF_CLOCK_EN)); + dummy = R_REG(&ai->ioctrl); + W_REG(&ai->resetctrl, 0); + udelay(1); + + W_REG(&ai->ioctrl, (bits | SICF_CLOCK_EN)); + dummy = R_REG(&ai->ioctrl); + udelay(1); +} + +/* return the slow clock source - LPO, XTAL, or PCI */ +static uint ai_slowclk_src(struct si_info *sii) +{ + struct chipcregs __iomem *cc; + u32 val; + + if (sii->pub.ccrev < 6) { + pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, + &val); + if (val & PCI_CFG_GPIO_SCS) + return SCC_SS_PCI; + return SCC_SS_XTAL; + } else if (sii->pub.ccrev < 10) { + cc = (struct chipcregs __iomem *) + ai_setcoreidx(&sii->pub, sii->curidx); + return R_REG(&cc->slow_clk_ctl) & SCC_SS_MASK; + } else /* Insta-clock */ + return SCC_SS_XTAL; +} + +/* +* return the ILP (slowclock) min or max frequency +* precondition: we've established the chip has dynamic clk control +*/ +static uint ai_slowclk_freq(struct si_info *sii, bool max_freq, + struct chipcregs __iomem *cc) +{ + u32 slowclk; + uint div; + + slowclk = ai_slowclk_src(sii); + if (sii->pub.ccrev < 6) { + if (slowclk == SCC_SS_PCI) + return max_freq ? (PCIMAXFREQ / 64) + : (PCIMINFREQ / 64); + else + return max_freq ? (XTALMAXFREQ / 32) + : (XTALMINFREQ / 32); + } else if (sii->pub.ccrev < 10) { + div = 4 * + (((R_REG(&cc->slow_clk_ctl) & SCC_CD_MASK) >> + SCC_CD_SHIFT) + 1); + if (slowclk == SCC_SS_LPO) + return max_freq ? LPOMAXFREQ : LPOMINFREQ; + else if (slowclk == SCC_SS_XTAL) + return max_freq ? (XTALMAXFREQ / div) + : (XTALMINFREQ / div); + else if (slowclk == SCC_SS_PCI) + return max_freq ? (PCIMAXFREQ / div) + : (PCIMINFREQ / div); + } else { + /* Chipc rev 10 is InstaClock */ + div = R_REG(&cc->system_clk_ctl) >> SYCC_CD_SHIFT; + div = 4 * (div + 1); + return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div); + } + return 0; +} + +static void +ai_clkctl_setdelay(struct si_info *sii, struct chipcregs __iomem *cc) +{ + uint slowmaxfreq, pll_delay, slowclk; + uint pll_on_delay, fref_sel_delay; + + pll_delay = PLL_DELAY; + + /* + * If the slow clock is not sourced by the xtal then + * add the xtal_on_delay since the xtal will also be + * powered down by dynamic clk control logic. + */ + + slowclk = ai_slowclk_src(sii); + if (slowclk != SCC_SS_XTAL) + pll_delay += XTAL_ON_DELAY; + + /* Starting with 4318 it is ILP that is used for the delays */ + slowmaxfreq = + ai_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? false : true, cc); + + pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; + fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; + + W_REG(&cc->pll_on_delay, pll_on_delay); + W_REG(&cc->fref_sel_delay, fref_sel_delay); +} + +/* initialize power control delay registers */ +void ai_clkctl_init(struct si_pub *sih) +{ + struct si_info *sii; + uint origidx = 0; + struct chipcregs __iomem *cc; + bool fast; + + if (!(sih->cccaps & CC_CAP_PWR_CTL)) + return; + + sii = (struct si_info *)sih; + fast = SI_FAST(sii); + if (!fast) { + origidx = sii->curidx; + cc = (struct chipcregs __iomem *) + ai_setcore(sih, CC_CORE_ID, 0); + if (cc == NULL) + return; + } else { + cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); + if (cc == NULL) + return; + } + + /* set all Instaclk chip ILP to 1 MHz */ + if (sih->ccrev >= 10) + SET_REG(&cc->system_clk_ctl, SYCC_CD_MASK, + (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); + + ai_clkctl_setdelay(sii, cc); + + if (!fast) + ai_setcoreidx(sih, origidx); +} + +/* + * return the value suitable for writing to the + * dot11 core FAST_PWRUP_DELAY register + */ +u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) +{ + struct si_info *sii; + uint origidx = 0; + struct chipcregs __iomem *cc; + uint slowminfreq; + u16 fpdelay; + uint intr_val = 0; + bool fast; + + sii = (struct si_info *)sih; + if (sih->cccaps & CC_CAP_PMU) { + INTR_OFF(sii, intr_val); + fpdelay = si_pmu_fast_pwrup_delay(sih); + INTR_RESTORE(sii, intr_val); + return fpdelay; + } + + if (!(sih->cccaps & CC_CAP_PWR_CTL)) + return 0; + + fast = SI_FAST(sii); + fpdelay = 0; + if (!fast) { + origidx = sii->curidx; + INTR_OFF(sii, intr_val); + cc = (struct chipcregs __iomem *) + ai_setcore(sih, CC_CORE_ID, 0); + if (cc == NULL) + goto done; + } else { + cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); + if (cc == NULL) + goto done; + } + + slowminfreq = ai_slowclk_freq(sii, false, cc); + fpdelay = (((R_REG(&cc->pll_on_delay) + 2) * 1000000) + + (slowminfreq - 1)) / slowminfreq; + + done: + if (!fast) { + ai_setcoreidx(sih, origidx); + INTR_RESTORE(sii, intr_val); + } + return fpdelay; +} + +/* turn primary xtal and/or pll off/on */ +int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) +{ + struct si_info *sii; + u32 in, out, outen; + + sii = (struct si_info *)sih; + + /* pcie core doesn't have any mapping to control the xtal pu */ + if (PCIE(sii)) + return -1; + + pci_read_config_dword(sii->pbus, PCI_GPIO_IN, &in); + pci_read_config_dword(sii->pbus, PCI_GPIO_OUT, &out); + pci_read_config_dword(sii->pbus, PCI_GPIO_OUTEN, &outen); + + /* + * Avoid glitching the clock if GPRS is already using it. + * We can't actually read the state of the PLLPD so we infer it + * by the value of XTAL_PU which *is* readable via gpioin. + */ + if (on && (in & PCI_CFG_GPIO_XTAL)) + return 0; + + if (what & XTAL) + outen |= PCI_CFG_GPIO_XTAL; + if (what & PLL) + outen |= PCI_CFG_GPIO_PLL; + + if (on) { + /* turn primary xtal on */ + if (what & XTAL) { + out |= PCI_CFG_GPIO_XTAL; + if (what & PLL) + out |= PCI_CFG_GPIO_PLL; + pci_write_config_dword(sii->pbus, + PCI_GPIO_OUT, out); + pci_write_config_dword(sii->pbus, + PCI_GPIO_OUTEN, outen); + udelay(XTAL_ON_DELAY); + } + + /* turn pll on */ + if (what & PLL) { + out &= ~PCI_CFG_GPIO_PLL; + pci_write_config_dword(sii->pbus, + PCI_GPIO_OUT, out); + mdelay(2); + } + } else { + if (what & XTAL) + out &= ~PCI_CFG_GPIO_XTAL; + if (what & PLL) + out |= PCI_CFG_GPIO_PLL; + pci_write_config_dword(sii->pbus, + PCI_GPIO_OUT, out); + pci_write_config_dword(sii->pbus, + PCI_GPIO_OUTEN, outen); + } + + return 0; +} + +/* clk control mechanism through chipcommon, no policy checking */ +static bool _ai_clkctl_cc(struct si_info *sii, uint mode) +{ + uint origidx = 0; + struct chipcregs __iomem *cc; + u32 scc; + uint intr_val = 0; + bool fast = SI_FAST(sii); + + /* chipcommon cores prior to rev6 don't support dynamic clock control */ + if (sii->pub.ccrev < 6) + return false; + + if (!fast) { + INTR_OFF(sii, intr_val); + origidx = sii->curidx; + cc = (struct chipcregs __iomem *) + ai_setcore(&sii->pub, CC_CORE_ID, 0); + } else { + cc = (struct chipcregs __iomem *) CCREGS_FAST(sii); + if (cc == NULL) + goto done; + } + + if (!(sii->pub.cccaps & CC_CAP_PWR_CTL) && (sii->pub.ccrev < 20)) + goto done; + + switch (mode) { + case CLK_FAST: /* FORCEHT, fast (pll) clock */ + if (sii->pub.ccrev < 10) { + /* + * don't forget to force xtal back + * on before we clear SCC_DYN_XTAL.. + */ + ai_clkctl_xtal(&sii->pub, XTAL, ON); + SET_REG(&cc->slow_clk_ctl, + (SCC_XC | SCC_FS | SCC_IP), SCC_IP); + } else if (sii->pub.ccrev < 20) { + OR_REG(&cc->system_clk_ctl, SYCC_HR); + } else { + OR_REG(&cc->clk_ctl_st, CCS_FORCEHT); + } + + /* wait for the PLL */ + if (sii->pub.cccaps & CC_CAP_PMU) { + u32 htavail = CCS_HTAVAIL; + SPINWAIT(((R_REG(&cc->clk_ctl_st) & htavail) + == 0), PMU_MAX_TRANSITION_DLY); + } else { + udelay(PLL_DELAY); + } + break; + + case CLK_DYNAMIC: /* enable dynamic clock control */ + if (sii->pub.ccrev < 10) { + scc = R_REG(&cc->slow_clk_ctl); + scc &= ~(SCC_FS | SCC_IP | SCC_XC); + if ((scc & SCC_SS_MASK) != SCC_SS_XTAL) + scc |= SCC_XC; + W_REG(&cc->slow_clk_ctl, scc); + + /* + * for dynamic control, we have to + * release our xtal_pu "force on" + */ + if (scc & SCC_XC) + ai_clkctl_xtal(&sii->pub, XTAL, OFF); + } else if (sii->pub.ccrev < 20) { + /* Instaclock */ + AND_REG(&cc->system_clk_ctl, ~SYCC_HR); + } else { + AND_REG(&cc->clk_ctl_st, ~CCS_FORCEHT); + } + break; + + default: + break; + } + + done: + if (!fast) { + ai_setcoreidx(&sii->pub, origidx); + INTR_RESTORE(sii, intr_val); + } + return mode == CLK_FAST; +} + +/* + * clock control policy function throught chipcommon + * + * set dynamic clk control mode (forceslow, forcefast, dynamic) + * returns true if we are forcing fast clock + * this is a wrapper over the next internal function + * to allow flexible policy settings for outside caller + */ +bool ai_clkctl_cc(struct si_pub *sih, uint mode) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + + /* chipcommon cores prior to rev6 don't support dynamic clock control */ + if (sih->ccrev < 6) + return false; + + if (PCI_FORCEHT(sii)) + return mode == CLK_FAST; + + return _ai_clkctl_cc(sii, mode); +} + +/* Build device path */ +int ai_devpath(struct si_pub *sih, char *path, int size) +{ + int slen; + + if (!path || size <= 0) + return -1; + + slen = snprintf(path, (size_t) size, "pci/%u/%u/", + ((struct si_info *)sih)->pbus->bus->number, + PCI_SLOT(((struct pci_dev *) + (((struct si_info *)(sih))->pbus))->devfn)); + + if (slen < 0 || slen >= size) { + path[0] = '\0'; + return -1; + } + + return 0; +} + +void ai_pci_up(struct si_pub *sih) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + + if (PCI_FORCEHT(sii)) + _ai_clkctl_cc(sii, CLK_FAST); + + if (PCIE(sii)) + pcicore_up(sii->pch, SI_PCIUP); + +} + +/* Unconfigure and/or apply various WARs when system is going to sleep mode */ +void ai_pci_sleep(struct si_pub *sih) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + + pcicore_sleep(sii->pch); +} + +/* Unconfigure and/or apply various WARs when going down */ +void ai_pci_down(struct si_pub *sih) +{ + struct si_info *sii; + + sii = (struct si_info *)sih; + + /* release FORCEHT since chip is going to "down" state */ + if (PCI_FORCEHT(sii)) + _ai_clkctl_cc(sii, CLK_DYNAMIC); + + pcicore_down(sii->pch, SI_PCIDOWN); +} + +/* + * Configure the pci core for pci client (NIC) action + * coremask is the bitvec of cores by index to be enabled. + */ +void ai_pci_setup(struct si_pub *sih, uint coremask) +{ + struct si_info *sii; + struct sbpciregs __iomem *regs = NULL; + u32 siflag = 0, w; + uint idx = 0; + + sii = (struct si_info *)sih; + + if (PCI(sii)) { + /* get current core index */ + idx = sii->curidx; + + /* we interrupt on this backplane flag number */ + siflag = ai_flag(sih); + + /* switch over to pci core */ + regs = ai_setcoreidx(sih, sii->pub.buscoreidx); + } + + /* + * Enable sb->pci interrupts. Assume + * PCI rev 2.3 support was added in pci core rev 6 and things changed.. + */ + if (PCIE(sii) || (PCI(sii) && ((sii->pub.buscorerev) >= 6))) { + /* pci config write to set this core bit in PCIIntMask */ + pci_read_config_dword(sii->pbus, PCI_INT_MASK, &w); + w |= (coremask << PCI_SBIM_SHIFT); + pci_write_config_dword(sii->pbus, PCI_INT_MASK, w); + } else { + /* set sbintvec bit for our flag number */ + ai_setint(sih, siflag); + } + + if (PCI(sii)) { + pcicore_pci_setup(sii->pch, regs); + + /* switch back to previous core */ + ai_setcoreidx(sih, idx); + } +} + +/* + * Fixup SROMless PCI device's configuration. + * The current core may be changed upon return. + */ +int ai_pci_fixcfg(struct si_pub *sih) +{ + uint origidx; + void __iomem *regs = NULL; + struct si_info *sii = (struct si_info *)sih; + + /* Fixup PI in SROM shadow area to enable the correct PCI core access */ + /* save the current index */ + origidx = ai_coreidx(&sii->pub); + + /* check 'pi' is correct and fix it if not */ + regs = ai_setcore(&sii->pub, sii->pub.buscoretype, 0); + if (sii->pub.buscoretype == PCIE_CORE_ID) + pcicore_fixcfg_pcie(sii->pch, + (struct sbpcieregs __iomem *)regs); + else if (sii->pub.buscoretype == PCI_CORE_ID) + pcicore_fixcfg_pci(sii->pch, (struct sbpciregs __iomem *)regs); + + /* restore the original index */ + ai_setcoreidx(&sii->pub, origidx); + + pcicore_hwup(sii->pch); + return 0; +} + +/* mask&set gpiocontrol bits */ +u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority) +{ + uint regoff; + + regoff = offsetof(struct chipcregs, gpiocontrol); + return ai_corereg(sih, SI_CC_IDX, regoff, mask, val); +} + +void ai_chipcontrl_epa4331(struct si_pub *sih, bool on) +{ + struct si_info *sii; + struct chipcregs __iomem *cc; + uint origidx; + u32 val; + + sii = (struct si_info *)sih; + origidx = ai_coreidx(sih); + + cc = (struct chipcregs __iomem *) ai_setcore(sih, CC_CORE_ID, 0); + + val = R_REG(&cc->chipcontrol); + + if (on) { + if (sih->chippkg == 9 || sih->chippkg == 0xb) + /* Ext PA Controls for 4331 12x9 Package */ + W_REG(&cc->chipcontrol, val | + CCTRL4331_EXTPA_EN | + CCTRL4331_EXTPA_ON_GPIO2_5); + else + /* Ext PA Controls for 4331 12x12 Package */ + W_REG(&cc->chipcontrol, + val | CCTRL4331_EXTPA_EN); + } else { + val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); + W_REG(&cc->chipcontrol, val); + } + + ai_setcoreidx(sih, origidx); +} + +/* Enable BT-COEX & Ex-PA for 4313 */ +void ai_epa_4313war(struct si_pub *sih) +{ + struct si_info *sii; + struct chipcregs __iomem *cc; + uint origidx; + + sii = (struct si_info *)sih; + origidx = ai_coreidx(sih); + + cc = ai_setcore(sih, CC_CORE_ID, 0); + + /* EPA Fix */ + W_REG(&cc->gpiocontrol, + R_REG(&cc->gpiocontrol) | GPIO_CTRL_EPA_EN_MASK); + + ai_setcoreidx(sih, origidx); +} + +/* check if the device is removed */ +bool ai_deviceremoved(struct si_pub *sih) +{ + u32 w; + struct si_info *sii; + + sii = (struct si_info *)sih; + + pci_read_config_dword(sii->pbus, PCI_VENDOR_ID, &w); + if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM) + return true; + + return false; +} + +bool ai_is_sprom_available(struct si_pub *sih) +{ + if (sih->ccrev >= 31) { + struct si_info *sii; + uint origidx; + struct chipcregs __iomem *cc; + u32 sromctrl; + + if ((sih->cccaps & CC_CAP_SROM) == 0) + return false; + + sii = (struct si_info *)sih; + origidx = sii->curidx; + cc = ai_setcoreidx(sih, SI_CC_IDX); + sromctrl = R_REG(&cc->sromcontrol); + ai_setcoreidx(sih, origidx); + return sromctrl & SRC_PRESENT; + } + + switch (sih->chip) { + case BCM4313_CHIP_ID: + return (sih->chipst & CST4313_SPROM_PRESENT) != 0; + default: + return true; + } +} + +bool ai_is_otp_disabled(struct si_pub *sih) +{ + switch (sih->chip) { + case BCM4313_CHIP_ID: + return (sih->chipst & CST4313_OTP_PRESENT) == 0; + /* These chips always have their OTP on */ + case BCM43224_CHIP_ID: + case BCM43225_CHIP_ID: + default: + return false; + } +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h new file mode 100644 index 000000000000..106a7424a7cd --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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 _BRCM_AIUTILS_H_ +#define _BRCM_AIUTILS_H_ + +#include "types.h" + +/* + * SOC Interconnect Address Map. + * All regions may not exist on all chips. + */ +/* each core gets 4Kbytes for registers */ +#define SI_CORE_SIZE 0x1000 +/* + * Max cores (this is arbitrary, for software + * convenience and could be changed if we + * make any larger chips + */ +#define SI_MAXCORES 16 + +/* Client Mode sb2pcitranslation2 size in bytes */ +#define SI_PCI_DMA_SZ 0x40000000 + +/* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */ +#define SI_PCIE_DMA_H32 0x80000000 + +/* core codes */ +#define NODEV_CORE_ID 0x700 /* Invalid coreid */ +#define CC_CORE_ID 0x800 /* chipcommon core */ +#define ILINE20_CORE_ID 0x801 /* iline20 core */ +#define SRAM_CORE_ID 0x802 /* sram core */ +#define SDRAM_CORE_ID 0x803 /* sdram core */ +#define PCI_CORE_ID 0x804 /* pci core */ +#define MIPS_CORE_ID 0x805 /* mips core */ +#define ENET_CORE_ID 0x806 /* enet mac core */ +#define CODEC_CORE_ID 0x807 /* v90 codec core */ +#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ +#define ADSL_CORE_ID 0x809 /* ADSL core */ +#define ILINE100_CORE_ID 0x80a /* iline100 core */ +#define IPSEC_CORE_ID 0x80b /* ipsec core */ +#define UTOPIA_CORE_ID 0x80c /* utopia core */ +#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ +#define SOCRAM_CORE_ID 0x80e /* internal memory core */ +#define MEMC_CORE_ID 0x80f /* memc sdram core */ +#define OFDM_CORE_ID 0x810 /* OFDM phy core */ +#define EXTIF_CORE_ID 0x811 /* external interface core */ +#define D11_CORE_ID 0x812 /* 802.11 MAC core */ +#define APHY_CORE_ID 0x813 /* 802.11a phy core */ +#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ +#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ +#define MIPS33_CORE_ID 0x816 /* mips3302 core */ +#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ +#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ +#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ +#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ +#define SDIOH_CORE_ID 0x81b /* sdio host core */ +#define ROBO_CORE_ID 0x81c /* roboswitch core */ +#define ATA100_CORE_ID 0x81d /* parallel ATA core */ +#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ +#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ +#define PCIE_CORE_ID 0x820 /* pci express core */ +#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ +#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ +#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ +#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ +#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ +#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ +#define PMU_CORE_ID 0x827 /* PMU core */ +#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ +#define SDIOD_CORE_ID 0x829 /* SDIO device core */ +#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ +#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ +#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ +#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ +#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ +#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ +#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ +#define SC_CORE_ID 0x831 /* shared common core */ +#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ +#define SPIH_CORE_ID 0x833 /* SPI host core */ +#define I2S_CORE_ID 0x834 /* I2S core */ +#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ +#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ +#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ +#define DEF_AI_COMP 0xfff /* Default component, in ai chips it + * maps all unused address ranges + */ + +/* chipcommon being the first core: */ +#define SI_CC_IDX 0 + +/* SOC Interconnect types (aka chip types) */ +#define SOCI_AI 1 + +/* Common core control flags */ +#define SICF_BIST_EN 0x8000 +#define SICF_PME_EN 0x4000 +#define SICF_CORE_BITS 0x3ffc +#define SICF_FGC 0x0002 +#define SICF_CLOCK_EN 0x0001 + +/* Common core status flags */ +#define SISF_BIST_DONE 0x8000 +#define SISF_BIST_ERROR 0x4000 +#define SISF_GATED_CLK 0x2000 +#define SISF_DMA64 0x1000 +#define SISF_CORE_BITS 0x0fff + +/* A register that is common to all cores to + * communicate w/PMU regarding clock control. + */ +#define SI_CLK_CTL_ST 0x1e0 /* clock control and status */ + +/* clk_ctl_st register */ +#define CCS_FORCEALP 0x00000001 /* force ALP request */ +#define CCS_FORCEHT 0x00000002 /* force HT request */ +#define CCS_FORCEILP 0x00000004 /* force ILP request */ +#define CCS_ALPAREQ 0x00000008 /* ALP Avail Request */ +#define CCS_HTAREQ 0x00000010 /* HT Avail Request */ +#define CCS_FORCEHWREQOFF 0x00000020 /* Force HW Clock Request Off */ +#define CCS_ERSRC_REQ_MASK 0x00000700 /* external resource requests */ +#define CCS_ERSRC_REQ_SHIFT 8 +#define CCS_ALPAVAIL 0x00010000 /* ALP is available */ +#define CCS_HTAVAIL 0x00020000 /* HT is available */ +#define CCS_BP_ON_APL 0x00040000 /* RO: running on ALP clock */ +#define CCS_BP_ON_HT 0x00080000 /* RO: running on HT clock */ +#define CCS_ERSRC_STS_MASK 0x07000000 /* external resource status */ +#define CCS_ERSRC_STS_SHIFT 24 + +/* HT avail in chipc and pcmcia on 4328a0 */ +#define CCS0_HTAVAIL 0x00010000 +/* ALP avail in chipc and pcmcia on 4328a0 */ +#define CCS0_ALPAVAIL 0x00020000 + +/* Not really related to SOC Interconnect, but a couple of software + * conventions for the use the flash space: + */ + +/* Minumum amount of flash we support */ +#define FLASH_MIN 0x00020000 /* Minimum flash size */ + +#define CC_SROM_OTP 0x800 /* SROM/OTP address space */ + +/* gpiotimerval */ +#define GPIO_ONTIME_SHIFT 16 + +/* Fields in clkdiv */ +#define CLKD_OTP 0x000f0000 +#define CLKD_OTP_SHIFT 16 + +/* Package IDs */ +#define BCM4717_PKG_ID 9 /* 4717 package id */ +#define BCM4718_PKG_ID 10 /* 4718 package id */ +#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ + +/* these are router chips */ +#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */ +#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */ +#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */ + +/* dynamic clock control defines */ +#define LPOMINFREQ 25000 /* low power oscillator min */ +#define LPOMAXFREQ 43000 /* low power oscillator max */ +#define XTALMINFREQ 19800000 /* 20 MHz - 1% */ +#define XTALMAXFREQ 20200000 /* 20 MHz + 1% */ +#define PCIMINFREQ 25000000 /* 25 MHz */ +#define PCIMAXFREQ 34000000 /* 33 MHz + fudge */ + +#define ILP_DIV_5MHZ 0 /* ILP = 5 MHz */ +#define ILP_DIV_1MHZ 4 /* ILP = 1 MHz */ + +/* clkctl xtal what flags */ +#define XTAL 0x1 /* primary crystal oscillator (2050) */ +#define PLL 0x2 /* main chip pll */ + +/* clkctl clk mode */ +#define CLK_FAST 0 /* force fast (pll) clock */ +#define CLK_DYNAMIC 2 /* enable dynamic clock control */ + +/* GPIO usage priorities */ +#define GPIO_DRV_PRIORITY 0 /* Driver */ +#define GPIO_APP_PRIORITY 1 /* Application */ +#define GPIO_HI_PRIORITY 2 /* Highest priority. Ignore GPIO + * reservation + */ + +/* GPIO pull up/down */ +#define GPIO_PULLUP 0 +#define GPIO_PULLDN 1 + +/* GPIO event regtype */ +#define GPIO_REGEVT 0 /* GPIO register event */ +#define GPIO_REGEVT_INTMSK 1 /* GPIO register event int mask */ +#define GPIO_REGEVT_INTPOL 2 /* GPIO register event int polarity */ + +/* device path */ +#define SI_DEVPATH_BUFSZ 16 /* min buffer size in bytes */ + +/* SI routine enumeration: to be used by update function with multiple hooks */ +#define SI_DOATTACH 1 +#define SI_PCIDOWN 2 +#define SI_PCIUP 3 + +/* + * Data structure to export all chip specific common variables + * public (read-only) portion of aiutils handle returned by si_attach() + */ +struct si_pub { + uint buscoretype; /* PCI_CORE_ID, PCIE_CORE_ID, PCMCIA_CORE_ID */ + uint buscorerev; /* buscore rev */ + uint buscoreidx; /* buscore index */ + int ccrev; /* chip common core rev */ + u32 cccaps; /* chip common capabilities */ + u32 cccaps_ext; /* chip common capabilities extension */ + int pmurev; /* pmu core rev */ + u32 pmucaps; /* pmu capabilities */ + uint boardtype; /* board type */ + uint boardvendor; /* board vendor */ + uint boardflags; /* board flags */ + uint boardflags2; /* board flags2 */ + uint chip; /* chip number */ + uint chiprev; /* chip revision */ + uint chippkg; /* chip package option */ + u32 chipst; /* chip status */ + bool issim; /* chip is in simulation or emulation */ + uint socirev; /* SOC interconnect rev */ + bool pci_pr32414; + +}; + +struct pci_dev; + +struct gpioh_item { + void *arg; + bool level; + void (*handler) (u32 stat, void *arg); + u32 event; + struct gpioh_item *next; +}; + +/* misc si info needed by some of the routines */ +struct si_info { + struct si_pub pub; /* back plane public state (must be first) */ + struct pci_dev *pbus; /* handle to pci bus */ + uint dev_coreid; /* the core provides driver functions */ + void *intr_arg; /* interrupt callback function arg */ + u32 (*intrsoff_fn) (void *intr_arg); /* turns chip interrupts off */ + /* restore chip interrupts */ + void (*intrsrestore_fn) (void *intr_arg, u32 arg); + /* check if interrupts are enabled */ + bool (*intrsenabled_fn) (void *intr_arg); + + struct pcicore_info *pch; /* PCI/E core handle */ + + struct list_head var_list; /* list of srom variables */ + + void __iomem *curmap; /* current regs va */ + void __iomem *regs[SI_MAXCORES]; /* other regs va */ + + uint curidx; /* current core index */ + uint numcores; /* # discovered cores */ + uint coreid[SI_MAXCORES]; /* id of each core */ + u32 coresba[SI_MAXCORES]; /* backplane address of each core */ + void *regs2[SI_MAXCORES]; /* 2nd virtual address per core (usbh20) */ + u32 coresba2[SI_MAXCORES]; /* 2nd phys address per core (usbh20) */ + u32 coresba_size[SI_MAXCORES]; /* backplane address space size */ + u32 coresba2_size[SI_MAXCORES]; /* second address space size */ + + void *curwrap; /* current wrapper va */ + void *wrappers[SI_MAXCORES]; /* other cores wrapper va */ + u32 wrapba[SI_MAXCORES]; /* address of controlling wrapper */ + + u32 cia[SI_MAXCORES]; /* erom cia entry for each core */ + u32 cib[SI_MAXCORES]; /* erom cia entry for each core */ + u32 oob_router; /* oob router registers for axi */ +}; + +/* + * Many of the routines below take an 'sih' handle as their first arg. + * Allocate this by calling si_attach(). Free it by calling si_detach(). + * At any one time, the sih is logically focused on one particular si core + * (the "current core"). + * Use si_setcore() or si_setcoreidx() to change the association to another core + */ + + +/* AMBA Interconnect exported externs */ +extern uint ai_flag(struct si_pub *sih); +extern void ai_setint(struct si_pub *sih, int siflag); +extern uint ai_coreidx(struct si_pub *sih); +extern uint ai_corevendor(struct si_pub *sih); +extern uint ai_corerev(struct si_pub *sih); +extern bool ai_iscoreup(struct si_pub *sih); +extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val); +extern void ai_core_cflags_wo(struct si_pub *sih, u32 mask, u32 val); +extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val); +extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, + uint val); +extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits); +extern void ai_core_disable(struct si_pub *sih, u32 bits); +extern int ai_numaddrspaces(struct si_pub *sih); +extern u32 ai_addrspace(struct si_pub *sih, uint asidx); +extern u32 ai_addrspacesize(struct si_pub *sih, uint asidx); +extern void ai_write_wrap_reg(struct si_pub *sih, u32 offset, u32 val); + +/* === exported functions === */ +extern struct si_pub *ai_attach(void __iomem *regs, struct pci_dev *sdh); +extern void ai_detach(struct si_pub *sih); +extern uint ai_coreid(struct si_pub *sih); +extern uint ai_corerev(struct si_pub *sih); +extern uint ai_corereg(struct si_pub *sih, uint coreidx, uint regoff, uint mask, + uint val); +extern void ai_write_wrapperreg(struct si_pub *sih, u32 offset, u32 val); +extern u32 ai_core_cflags(struct si_pub *sih, u32 mask, u32 val); +extern u32 ai_core_sflags(struct si_pub *sih, u32 mask, u32 val); +extern bool ai_iscoreup(struct si_pub *sih); +extern uint ai_findcoreidx(struct si_pub *sih, uint coreid, uint coreunit); +extern void __iomem *ai_setcoreidx(struct si_pub *sih, uint coreidx); +extern void __iomem *ai_setcore(struct si_pub *sih, uint coreid, uint coreunit); +extern void __iomem *ai_switch_core(struct si_pub *sih, uint coreid, + uint *origidx, uint *intr_val); +extern void ai_restore_core(struct si_pub *sih, uint coreid, uint intr_val); +extern void ai_core_reset(struct si_pub *sih, u32 bits, u32 resetbits); +extern void ai_core_disable(struct si_pub *sih, u32 bits); +extern u32 ai_alp_clock(struct si_pub *sih); +extern u32 ai_ilp_clock(struct si_pub *sih); +extern void ai_pci_setup(struct si_pub *sih, uint coremask); +extern void ai_setint(struct si_pub *sih, int siflag); +extern bool ai_backplane64(struct si_pub *sih); +extern void ai_register_intr_callback(struct si_pub *sih, void *intrsoff_fn, + void *intrsrestore_fn, + void *intrsenabled_fn, void *intr_arg); +extern void ai_deregister_intr_callback(struct si_pub *sih); +extern void ai_clkctl_init(struct si_pub *sih); +extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih); +extern bool ai_clkctl_cc(struct si_pub *sih, uint mode); +extern int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on); +extern bool ai_deviceremoved(struct si_pub *sih); +extern u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, + u8 priority); + +/* OTP status */ +extern bool ai_is_otp_disabled(struct si_pub *sih); + +/* SPROM availability */ +extern bool ai_is_sprom_available(struct si_pub *sih); + +/* + * Build device path. Path size must be >= SI_DEVPATH_BUFSZ. + * The returned path is NULL terminated and has trailing '/'. + * Return 0 on success, nonzero otherwise. + */ +extern int ai_devpath(struct si_pub *sih, char *path, int size); + +extern void ai_pci_sleep(struct si_pub *sih); +extern void ai_pci_down(struct si_pub *sih); +extern void ai_pci_up(struct si_pub *sih); +extern int ai_pci_fixcfg(struct si_pub *sih); + +extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on); +/* Enable Ex-PA for 4313 */ +extern void ai_epa_4313war(struct si_pub *sih); + +#endif /* _BRCM_AIUTILS_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c new file mode 100644 index 000000000000..7f27dbdb6b60 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -0,0 +1,1241 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 <net/mac80211.h> + +#include "rate.h" +#include "scb.h" +#include "phy/phy_hal.h" +#include "antsel.h" +#include "main.h" +#include "ampdu.h" + +/* max number of mpdus in an ampdu */ +#define AMPDU_MAX_MPDU 32 +/* max number of mpdus in an ampdu to a legacy */ +#define AMPDU_NUM_MPDU_LEGACY 16 +/* max Tx ba window size (in pdu) */ +#define AMPDU_TX_BA_MAX_WSIZE 64 +/* default Tx ba window size (in pdu) */ +#define AMPDU_TX_BA_DEF_WSIZE 64 +/* default Rx ba window size (in pdu) */ +#define AMPDU_RX_BA_DEF_WSIZE 64 +/* max Rx ba window size (in pdu) */ +#define AMPDU_RX_BA_MAX_WSIZE 64 +/* max dur of tx ampdu (in msec) */ +#define AMPDU_MAX_DUR 5 +/* default tx retry limit */ +#define AMPDU_DEF_RETRY_LIMIT 5 +/* default tx retry limit at reg rate */ +#define AMPDU_DEF_RR_RETRY_LIMIT 2 +/* default weight of ampdu in txfifo */ +#define AMPDU_DEF_TXPKT_WEIGHT 2 +/* default ffpld reserved bytes */ +#define AMPDU_DEF_FFPLD_RSVD 2048 +/* # of inis to be freed on detach */ +#define AMPDU_INI_FREE 10 +/* max # of mpdus released at a time */ +#define AMPDU_SCB_MAX_RELEASE 20 + +#define NUM_FFPLD_FIFO 4 /* number of fifo concerned by pre-loading */ +#define FFPLD_TX_MAX_UNFL 200 /* default value of the average number of ampdu + * without underflows + */ +#define FFPLD_MPDU_SIZE 1800 /* estimate of maximum mpdu size */ +#define FFPLD_MAX_MCS 23 /* we don't deal with mcs 32 */ +#define FFPLD_PLD_INCR 1000 /* increments in bytes */ +#define FFPLD_MAX_AMPDU_CNT 5000 /* maximum number of ampdu we + * accumulate between resets. + */ + +#define AMPDU_DELIMITER_LEN 4 + +/* max allowed number of mpdus in an ampdu (2 streams) */ +#define AMPDU_NUM_MPDU 16 + +#define TX_SEQ_TO_INDEX(seq) ((seq) % AMPDU_TX_BA_MAX_WSIZE) + +/* max possible overhead per mpdu in the ampdu; 3 is for roundup if needed */ +#define AMPDU_MAX_MPDU_OVERHEAD (FCS_LEN + DOT11_ICV_AES_LEN +\ + AMPDU_DELIMITER_LEN + 3\ + + DOT11_A4_HDR_LEN + DOT11_QOS_LEN + DOT11_IV_MAX_LEN) + +/* modulo add/sub, bound = 2^k */ +#define MODADD_POW2(x, y, bound) (((x) + (y)) & ((bound) - 1)) +#define MODSUB_POW2(x, y, bound) (((x) - (y)) & ((bound) - 1)) + +/* structure to hold tx fifo information and pre-loading state + * counters specific to tx underflows of ampdus + * some counters might be redundant with the ones in wlc or ampdu structures. + * This allows to maintain a specific state independently of + * how often and/or when the wlc counters are updated. + * + * ampdu_pld_size: number of bytes to be pre-loaded + * mcs2ampdu_table: per-mcs max # of mpdus in an ampdu + * prev_txfunfl: num of underflows last read from the HW macstats counter + * accum_txfunfl: num of underflows since we modified pld params + * accum_txampdu: num of tx ampdu since we modified pld params + * prev_txampdu: previous reading of tx ampdu + * dmaxferrate: estimated dma avg xfer rate in kbits/sec + */ +struct brcms_fifo_info { + u16 ampdu_pld_size; + u8 mcs2ampdu_table[FFPLD_MAX_MCS + 1]; + u16 prev_txfunfl; + u32 accum_txfunfl; + u32 accum_txampdu; + u32 prev_txampdu; + u32 dmaxferrate; +}; + +/* AMPDU module specific state + * + * wlc: pointer to main wlc structure + * scb_handle: scb cubby handle to retrieve data from scb + * ini_enable: per-tid initiator enable/disable of ampdu + * ba_tx_wsize: Tx ba window size (in pdu) + * ba_rx_wsize: Rx ba window size (in pdu) + * retry_limit: mpdu transmit retry limit + * rr_retry_limit: mpdu transmit retry limit at regular rate + * retry_limit_tid: per-tid mpdu transmit retry limit + * rr_retry_limit_tid: per-tid mpdu transmit retry limit at regular rate + * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec + * max_pdu: max pdus allowed in ampdu + * dur: max duration of an ampdu (in msec) + * txpkt_weight: weight of ampdu in txfifo; reduces rate lag + * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes + * ffpld_rsvd: number of bytes to reserve for preload + * max_txlen: max size of ampdu per mcs, bw and sgi + * mfbr: enable multiple fallback rate + * tx_max_funl: underflows should be kept such that + * (tx_max_funfl*underflows) < tx frames + * fifo_tb: table of fifo infos + */ +struct ampdu_info { + struct brcms_c_info *wlc; + int scb_handle; + u8 ini_enable[AMPDU_MAX_SCB_TID]; + u8 ba_tx_wsize; + u8 ba_rx_wsize; + u8 retry_limit; + u8 rr_retry_limit; + u8 retry_limit_tid[AMPDU_MAX_SCB_TID]; + u8 rr_retry_limit_tid[AMPDU_MAX_SCB_TID]; + u8 mpdu_density; + s8 max_pdu; + u8 dur; + u8 txpkt_weight; + u8 rx_factor; + u32 ffpld_rsvd; + u32 max_txlen[MCS_TABLE_SIZE][2][2]; + bool mfbr; + u32 tx_max_funl; + struct brcms_fifo_info fifo_tb[NUM_FFPLD_FIFO]; +}; + +/* used for flushing ampdu packets */ +struct cb_del_ampdu_pars { + struct ieee80211_sta *sta; + u16 tid; +}; + +static void brcms_c_scb_ampdu_update_max_txlen(struct ampdu_info *ampdu, u8 dur) +{ + u32 rate, mcs; + + for (mcs = 0; mcs < MCS_TABLE_SIZE; mcs++) { + /* rate is in Kbps; dur is in msec ==> len = (rate * dur) / 8 */ + /* 20MHz, No SGI */ + rate = mcs_2_rate(mcs, false, false); + ampdu->max_txlen[mcs][0][0] = (rate * dur) >> 3; + /* 40 MHz, No SGI */ + rate = mcs_2_rate(mcs, true, false); + ampdu->max_txlen[mcs][1][0] = (rate * dur) >> 3; + /* 20MHz, SGI */ + rate = mcs_2_rate(mcs, false, true); + ampdu->max_txlen[mcs][0][1] = (rate * dur) >> 3; + /* 40 MHz, SGI */ + rate = mcs_2_rate(mcs, true, true); + ampdu->max_txlen[mcs][1][1] = (rate * dur) >> 3; + } +} + +static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu) +{ + if (BRCMS_PHY_11N_CAP(ampdu->wlc->band)) + return true; + else + return false; +} + +static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on) +{ + struct brcms_c_info *wlc = ampdu->wlc; + + wlc->pub->_ampdu = false; + + if (on) { + if (!(wlc->pub->_n_enab & SUPPORT_11N)) { + wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not " + "nmode enabled\n", wlc->pub->unit); + return -ENOTSUPP; + } + if (!brcms_c_ampdu_cap(ampdu)) { + wiphy_err(ampdu->wlc->wiphy, "wl%d: device not " + "ampdu capable\n", wlc->pub->unit); + return -ENOTSUPP; + } + wlc->pub->_ampdu = on; + } + + return 0; +} + +static void brcms_c_ffpld_init(struct ampdu_info *ampdu) +{ + int i, j; + struct brcms_fifo_info *fifo; + + for (j = 0; j < NUM_FFPLD_FIFO; j++) { + fifo = (ampdu->fifo_tb + j); + fifo->ampdu_pld_size = 0; + for (i = 0; i <= FFPLD_MAX_MCS; i++) + fifo->mcs2ampdu_table[i] = 255; + fifo->dmaxferrate = 0; + fifo->accum_txampdu = 0; + fifo->prev_txfunfl = 0; + fifo->accum_txfunfl = 0; + + } +} + +struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc) +{ + struct ampdu_info *ampdu; + int i; + + ampdu = kzalloc(sizeof(struct ampdu_info), GFP_ATOMIC); + if (!ampdu) + return NULL; + + ampdu->wlc = wlc; + + for (i = 0; i < AMPDU_MAX_SCB_TID; i++) + ampdu->ini_enable[i] = true; + /* Disable ampdu for VO by default */ + ampdu->ini_enable[PRIO_8021D_VO] = false; + ampdu->ini_enable[PRIO_8021D_NC] = false; + + /* Disable ampdu for BK by default since not enough fifo space */ + ampdu->ini_enable[PRIO_8021D_NONE] = false; + ampdu->ini_enable[PRIO_8021D_BK] = false; + + ampdu->ba_tx_wsize = AMPDU_TX_BA_DEF_WSIZE; + ampdu->ba_rx_wsize = AMPDU_RX_BA_DEF_WSIZE; + ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY; + ampdu->max_pdu = AUTO; + ampdu->dur = AMPDU_MAX_DUR; + ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT; + + ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD; + /* + * bump max ampdu rcv size to 64k for all 11n + * devices except 4321A0 and 4321A1 + */ + if (BRCMS_ISNPHY(wlc->band) && NREV_LT(wlc->band->phyrev, 2)) + ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_32K; + else + ampdu->rx_factor = IEEE80211_HT_MAX_AMPDU_64K; + ampdu->retry_limit = AMPDU_DEF_RETRY_LIMIT; + ampdu->rr_retry_limit = AMPDU_DEF_RR_RETRY_LIMIT; + + for (i = 0; i < AMPDU_MAX_SCB_TID; i++) { + ampdu->retry_limit_tid[i] = ampdu->retry_limit; + ampdu->rr_retry_limit_tid[i] = ampdu->rr_retry_limit; + } + + brcms_c_scb_ampdu_update_max_txlen(ampdu, ampdu->dur); + ampdu->mfbr = false; + /* try to set ampdu to the default value */ + brcms_c_ampdu_set(ampdu, wlc->pub->_ampdu); + + ampdu->tx_max_funl = FFPLD_TX_MAX_UNFL; + brcms_c_ffpld_init(ampdu); + + return ampdu; +} + +void brcms_c_ampdu_detach(struct ampdu_info *ampdu) +{ + kfree(ampdu); +} + +static void brcms_c_scb_ampdu_update_config(struct ampdu_info *ampdu, + struct scb *scb) +{ + struct scb_ampdu *scb_ampdu = &scb->scb_ampdu; + int i; + + scb_ampdu->max_pdu = AMPDU_NUM_MPDU; + + /* go back to legacy size if some preloading is occurring */ + for (i = 0; i < NUM_FFPLD_FIFO; i++) { + if (ampdu->fifo_tb[i].ampdu_pld_size > FFPLD_PLD_INCR) + scb_ampdu->max_pdu = AMPDU_NUM_MPDU_LEGACY; + } + + /* apply user override */ + if (ampdu->max_pdu != AUTO) + scb_ampdu->max_pdu = (u8) ampdu->max_pdu; + + scb_ampdu->release = min_t(u8, scb_ampdu->max_pdu, + AMPDU_SCB_MAX_RELEASE); + + if (scb_ampdu->max_rx_ampdu_bytes) + scb_ampdu->release = min_t(u8, scb_ampdu->release, + scb_ampdu->max_rx_ampdu_bytes / 1600); + + scb_ampdu->release = min(scb_ampdu->release, + ampdu->fifo_tb[TX_AC_BE_FIFO]. + mcs2ampdu_table[FFPLD_MAX_MCS]); +} + +static void brcms_c_scb_ampdu_update_config_all(struct ampdu_info *ampdu) +{ + brcms_c_scb_ampdu_update_config(ampdu, &du->wlc->pri_scb); +} + +static void brcms_c_ffpld_calc_mcs2ampdu_table(struct ampdu_info *ampdu, int f) +{ + int i; + u32 phy_rate, dma_rate, tmp; + u8 max_mpdu; + struct brcms_fifo_info *fifo = (ampdu->fifo_tb + f); + + /* recompute the dma rate */ + /* note : we divide/multiply by 100 to avoid integer overflows */ + max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], + AMPDU_NUM_MPDU_LEGACY); + phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false); + dma_rate = + (((phy_rate / 100) * + (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size)) + / (max_mpdu * FFPLD_MPDU_SIZE)) * 100; + fifo->dmaxferrate = dma_rate; + + /* fill up the mcs2ampdu table; do not recalc the last mcs */ + dma_rate = dma_rate >> 7; + for (i = 0; i < FFPLD_MAX_MCS; i++) { + /* shifting to keep it within integer range */ + phy_rate = mcs_2_rate(i, true, false) >> 7; + if (phy_rate > dma_rate) { + tmp = ((fifo->ampdu_pld_size * phy_rate) / + ((phy_rate - dma_rate) * FFPLD_MPDU_SIZE)) + 1; + tmp = min_t(u32, tmp, 255); + fifo->mcs2ampdu_table[i] = (u8) tmp; + } + } +} + +/* evaluate the dma transfer rate using the tx underflows as feedback. + * If necessary, increase tx fifo preloading. If not enough, + * decrease maximum ampdu size for each mcs till underflows stop + * Return 1 if pre-loading not active, -1 if not an underflow event, + * 0 if pre-loading module took care of the event. + */ +static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid) +{ + struct ampdu_info *ampdu = wlc->ampdu; + u32 phy_rate = mcs_2_rate(FFPLD_MAX_MCS, true, false); + u32 txunfl_ratio; + u8 max_mpdu; + u32 current_ampdu_cnt = 0; + u16 max_pld_size; + u32 new_txunfl; + struct brcms_fifo_info *fifo = (ampdu->fifo_tb + fid); + uint xmtfifo_sz; + u16 cur_txunfl; + + /* return if we got here for a different reason than underflows */ + cur_txunfl = brcms_b_read_shm(wlc->hw, + M_UCODE_MACSTAT + + offsetof(struct macstat, txfunfl[fid])); + new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl); + if (new_txunfl == 0) { + BCMMSG(wlc->wiphy, "TX status FRAG set but no tx underflows\n"); + return -1; + } + fifo->prev_txfunfl = cur_txunfl; + + if (!ampdu->tx_max_funl) + return 1; + + /* check if fifo is big enough */ + if (brcms_b_xmtfifo_sz_get(wlc->hw, fid, &xmtfifo_sz)) + return -1; + + if ((TXFIFO_SIZE_UNIT * (u32) xmtfifo_sz) <= ampdu->ffpld_rsvd) + return 1; + + max_pld_size = TXFIFO_SIZE_UNIT * xmtfifo_sz - ampdu->ffpld_rsvd; + fifo->accum_txfunfl += new_txunfl; + + /* we need to wait for at least 10 underflows */ + if (fifo->accum_txfunfl < 10) + return 0; + + BCMMSG(wlc->wiphy, "ampdu_count %d tx_underflows %d\n", + current_ampdu_cnt, fifo->accum_txfunfl); + + /* + compute the current ratio of tx unfl per ampdu. + When the current ampdu count becomes too + big while the ratio remains small, we reset + the current count in order to not + introduce too big of a latency in detecting a + large amount of tx underflows later. + */ + + txunfl_ratio = current_ampdu_cnt / fifo->accum_txfunfl; + + if (txunfl_ratio > ampdu->tx_max_funl) { + if (current_ampdu_cnt >= FFPLD_MAX_AMPDU_CNT) + fifo->accum_txfunfl = 0; + + return 0; + } + max_mpdu = min_t(u8, fifo->mcs2ampdu_table[FFPLD_MAX_MCS], + AMPDU_NUM_MPDU_LEGACY); + + /* In case max value max_pdu is already lower than + the fifo depth, there is nothing more we can do. + */ + + if (fifo->ampdu_pld_size >= max_mpdu * FFPLD_MPDU_SIZE) { + fifo->accum_txfunfl = 0; + return 0; + } + + if (fifo->ampdu_pld_size < max_pld_size) { + + /* increment by TX_FIFO_PLD_INC bytes */ + fifo->ampdu_pld_size += FFPLD_PLD_INCR; + if (fifo->ampdu_pld_size > max_pld_size) + fifo->ampdu_pld_size = max_pld_size; + + /* update scb release size */ + brcms_c_scb_ampdu_update_config_all(ampdu); + + /* + * compute a new dma xfer rate for max_mpdu @ max mcs. + * This is the minimum dma rate that can achieve no + * underflow condition for the current mpdu size. + * + * note : we divide/multiply by 100 to avoid integer overflows + */ + fifo->dmaxferrate = + (((phy_rate / 100) * + (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size)) + / (max_mpdu * FFPLD_MPDU_SIZE)) * 100; + + BCMMSG(wlc->wiphy, "DMA estimated transfer rate %d; " + "pre-load size %d\n", + fifo->dmaxferrate, fifo->ampdu_pld_size); + } else { + + /* decrease ampdu size */ + if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] > 1) { + if (fifo->mcs2ampdu_table[FFPLD_MAX_MCS] == 255) + fifo->mcs2ampdu_table[FFPLD_MAX_MCS] = + AMPDU_NUM_MPDU_LEGACY - 1; + else + fifo->mcs2ampdu_table[FFPLD_MAX_MCS] -= 1; + + /* recompute the table */ + brcms_c_ffpld_calc_mcs2ampdu_table(ampdu, fid); + + /* update scb release size */ + brcms_c_scb_ampdu_update_config_all(ampdu); + } + } + fifo->accum_txfunfl = 0; + return 0; +} + +void +brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, + u8 ba_wsize, /* negotiated ba window size (in pdu) */ + uint max_rx_ampdu_bytes) /* from ht_cap in beacon */ +{ + struct scb_ampdu *scb_ampdu; + struct scb_ampdu_tid_ini *ini; + struct ampdu_info *ampdu = wlc->ampdu; + struct scb *scb = &wlc->pri_scb; + scb_ampdu = &scb->scb_ampdu; + + if (!ampdu->ini_enable[tid]) { + wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n", + __func__, tid); + return; + } + + ini = &scb_ampdu->ini[tid]; + ini->tid = tid; + ini->scb = scb_ampdu->scb; + ini->ba_wsize = ba_wsize; + scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes; +} + +int +brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi, + struct sk_buff **pdu, int prec) +{ + struct brcms_c_info *wlc; + struct sk_buff *p, *pkt[AMPDU_MAX_MPDU]; + u8 tid, ndelim; + int err = 0; + u8 preamble_type = BRCMS_GF_PREAMBLE; + u8 fbr_preamble_type = BRCMS_GF_PREAMBLE; + u8 rts_preamble_type = BRCMS_LONG_PREAMBLE; + u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE; + + bool rr = true, fbr = false; + uint i, count = 0, fifo, seg_cnt = 0; + u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0; + u32 ampdu_len, max_ampdu_bytes = 0; + struct d11txh *txh = NULL; + u8 *plcp; + struct ieee80211_hdr *h; + struct scb *scb; + struct scb_ampdu *scb_ampdu; + struct scb_ampdu_tid_ini *ini; + u8 mcs = 0; + bool use_rts = false, use_cts = false; + u32 rspec = 0, rspec_fallback = 0; + u32 rts_rspec = 0, rts_rspec_fallback = 0; + u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ; + struct ieee80211_rts *rts; + u8 rr_retry_limit; + struct brcms_fifo_info *f; + bool fbr_iscck; + struct ieee80211_tx_info *tx_info; + u16 qlen; + struct wiphy *wiphy; + + wlc = ampdu->wlc; + wiphy = wlc->wiphy; + p = *pdu; + + tid = (u8) (p->priority); + + f = ampdu->fifo_tb + prio2fifo[tid]; + + scb = &wlc->pri_scb; + scb_ampdu = &scb->scb_ampdu; + ini = &scb_ampdu->ini[tid]; + + /* Let pressure continue to build ... */ + qlen = pktq_plen(&qi->q, prec); + if (ini->tx_in_transit > 0 && + qlen < min(scb_ampdu->max_pdu, ini->ba_wsize)) + /* Collect multiple MPDU's to be sent in the next AMPDU */ + return -EBUSY; + + /* at this point we intend to transmit an AMPDU */ + rr_retry_limit = ampdu->rr_retry_limit_tid[tid]; + ampdu_len = 0; + dma_len = 0; + while (p) { + struct ieee80211_tx_rate *txrate; + + tx_info = IEEE80211_SKB_CB(p); + txrate = tx_info->status.rates; + + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + err = brcms_c_prep_pdu(wlc, p, &fifo); + } else { + wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__); + *pdu = NULL; + err = 0; + break; + } + + if (err) { + if (err == -EBUSY) { + wiphy_err(wiphy, "wl%d: sendampdu: " + "prep_xdu retry; seq 0x%x\n", + wlc->pub->unit, seq); + *pdu = p; + break; + } + + /* error in the packet; reject it */ + wiphy_err(wiphy, "wl%d: sendampdu: prep_xdu " + "rejected; seq 0x%x\n", wlc->pub->unit, seq); + *pdu = NULL; + break; + } + + /* pkt is good to be aggregated */ + txh = (struct d11txh *) p->data; + plcp = (u8 *) (txh + 1); + h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN); + seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT; + index = TX_SEQ_TO_INDEX(seq); + + /* check mcl fields and test whether it can be agg'd */ + mcl = le16_to_cpu(txh->MacTxControlLow); + mcl &= ~TXC_AMPDU_MASK; + fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3); + txh->PreloadSize = 0; /* always default to 0 */ + + /* Handle retry limits */ + if (txrate[0].count <= rr_retry_limit) { + txrate[0].count++; + rr = true; + fbr = false; + } else { + fbr = true; + rr = false; + txrate[1].count++; + } + + /* extract the length info */ + len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) + : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback); + + /* retrieve null delimiter count */ + ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; + seg_cnt += 1; + + BCMMSG(wlc->wiphy, "wl%d: mpdu %d plcp_len %d\n", + wlc->pub->unit, count, len); + + /* + * aggregateable mpdu. For ucode/hw agg, + * test whether need to break or change the epoch + */ + if (count == 0) { + mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT); + /* refill the bits since might be a retx mpdu */ + mcl |= TXC_STARTMSDU; + rts = (struct ieee80211_rts *)&txh->rts_frame; + + if (ieee80211_is_rts(rts->frame_control)) { + mcl |= TXC_SENDRTS; + use_rts = true; + } + if (ieee80211_is_cts(rts->frame_control)) { + mcl |= TXC_SENDCTS; + use_cts = true; + } + } else { + mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT); + mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS); + } + + len = roundup(len, 4); + ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN); + + dma_len += (u16) brcmu_pkttotlen(p); + + BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d" + " seg_cnt %d null delim %d\n", + wlc->pub->unit, ampdu_len, seg_cnt, ndelim); + + txh->MacTxControlLow = cpu_to_le16(mcl); + + /* this packet is added */ + pkt[count++] = p; + + /* patch the first MPDU */ + if (count == 1) { + u8 plcp0, plcp3, is40, sgi; + struct ieee80211_sta *sta; + + sta = tx_info->control.sta; + + if (rr) { + plcp0 = plcp[0]; + plcp3 = plcp[3]; + } else { + plcp0 = txh->FragPLCPFallback[0]; + plcp3 = txh->FragPLCPFallback[3]; + + } + is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0; + sgi = plcp3_issgi(plcp3) ? 1 : 0; + mcs = plcp0 & ~MIMO_PLCP_40MHZ; + max_ampdu_bytes = + min(scb_ampdu->max_rx_ampdu_bytes, + ampdu->max_txlen[mcs][is40][sgi]); + + if (is40) + mimo_ctlchbw = + CHSPEC_SB_UPPER(wlc_phy_chanspec_get( + wlc->band->pi)) + ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ; + + /* rebuild the rspec and rspec_fallback */ + rspec = RSPEC_MIMORATE; + rspec |= plcp[0] & ~MIMO_PLCP_40MHZ; + if (plcp[0] & MIMO_PLCP_40MHZ) + rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT); + + if (fbr_iscck) /* CCK */ + rspec_fallback = cck_rspec(cck_phy2mac_rate + (txh->FragPLCPFallback[0])); + else { /* MIMO */ + rspec_fallback = RSPEC_MIMORATE; + rspec_fallback |= + txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ; + if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ) + rspec_fallback |= + (PHY_TXC1_BW_40MHZ << + RSPEC_BW_SHIFT); + } + + if (use_rts || use_cts) { + rts_rspec = + brcms_c_rspec_to_rts_rspec(wlc, + rspec, false, mimo_ctlchbw); + rts_rspec_fallback = + brcms_c_rspec_to_rts_rspec(wlc, + rspec_fallback, false, mimo_ctlchbw); + } + } + + /* if (first mpdu for host agg) */ + /* test whether to add more */ + if ((mcs_2_rate(mcs, true, false) >= f->dmaxferrate) && + (count == f->mcs2ampdu_table[mcs])) { + BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping" + " ampdu at %d for mcs %d\n", + wlc->pub->unit, count, mcs); + break; + } + + if (count == scb_ampdu->max_pdu) + break; + + /* + * check to see if the next pkt is + * a candidate for aggregation + */ + p = pktq_ppeek(&qi->q, prec); + /* tx_info must be checked with current p */ + tx_info = IEEE80211_SKB_CB(p); + + if (p) { + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && + ((u8) (p->priority) == tid)) { + + plen = brcmu_pkttotlen(p) + + AMPDU_MAX_MPDU_OVERHEAD; + plen = max(scb_ampdu->min_len, plen); + + if ((plen + ampdu_len) > max_ampdu_bytes) { + p = NULL; + continue; + } + + /* + * check if there are enough + * descriptors available + */ + if (*wlc->core->txavail[fifo] <= seg_cnt + 1) { + wiphy_err(wiphy, "%s: No fifo space " + "!!\n", __func__); + p = NULL; + continue; + } + p = brcmu_pktq_pdeq(&qi->q, prec); + } else { + p = NULL; + } + } + } /* end while(p) */ + + ini->tx_in_transit += count; + + if (count) { + /* patch up the last txh */ + txh = (struct d11txh *) pkt[count - 1]->data; + mcl = le16_to_cpu(txh->MacTxControlLow); + mcl &= ~TXC_AMPDU_MASK; + mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT); + txh->MacTxControlLow = cpu_to_le16(mcl); + + /* remove the null delimiter after last mpdu */ + ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM]; + txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0; + ampdu_len -= ndelim * AMPDU_DELIMITER_LEN; + + /* remove the pad len from last mpdu */ + fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0); + len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) + : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback); + ampdu_len -= roundup(len, 4) - len; + + /* patch up the first txh & plcp */ + txh = (struct d11txh *) pkt[0]->data; + plcp = (u8 *) (txh + 1); + + BRCMS_SET_MIMO_PLCP_LEN(plcp, ampdu_len); + /* mark plcp to indicate ampdu */ + BRCMS_SET_MIMO_PLCP_AMPDU(plcp); + + /* reset the mixed mode header durations */ + if (txh->MModeLen) { + u16 mmodelen = + brcms_c_calc_lsig_len(wlc, rspec, ampdu_len); + txh->MModeLen = cpu_to_le16(mmodelen); + preamble_type = BRCMS_MM_PREAMBLE; + } + if (txh->MModeFbrLen) { + u16 mmfbrlen = + brcms_c_calc_lsig_len(wlc, rspec_fallback, + ampdu_len); + txh->MModeFbrLen = cpu_to_le16(mmfbrlen); + fbr_preamble_type = BRCMS_MM_PREAMBLE; + } + + /* set the preload length */ + if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) { + dma_len = min(dma_len, f->ampdu_pld_size); + txh->PreloadSize = cpu_to_le16(dma_len); + } else + txh->PreloadSize = 0; + + mch = le16_to_cpu(txh->MacTxControlHigh); + + /* update RTS dur fields */ + if (use_rts || use_cts) { + u16 durid; + rts = (struct ieee80211_rts *)&txh->rts_frame; + if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) == + TXC_PREAMBLE_RTS_MAIN_SHORT) + rts_preamble_type = BRCMS_SHORT_PREAMBLE; + + if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) == + TXC_PREAMBLE_RTS_FB_SHORT) + rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE; + + durid = + brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec, + rspec, rts_preamble_type, + preamble_type, ampdu_len, + true); + rts->duration = cpu_to_le16(durid); + durid = brcms_c_compute_rtscts_dur(wlc, use_cts, + rts_rspec_fallback, + rspec_fallback, + rts_fbr_preamble_type, + fbr_preamble_type, + ampdu_len, true); + txh->RTSDurFallback = cpu_to_le16(durid); + /* set TxFesTimeNormal */ + txh->TxFesTimeNormal = rts->duration; + /* set fallback rate version of TxFesTimeNormal */ + txh->TxFesTimeFallback = txh->RTSDurFallback; + } + + /* set flag and plcp for fallback rate */ + if (fbr) { + mch |= TXC_AMPDU_FBR; + txh->MacTxControlHigh = cpu_to_le16(mch); + BRCMS_SET_MIMO_PLCP_AMPDU(plcp); + BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback); + } + + BCMMSG(wlc->wiphy, "wl%d: count %d ampdu_len %d\n", + wlc->pub->unit, count, ampdu_len); + + /* inform rate_sel if it this is a rate probe pkt */ + frameid = le16_to_cpu(txh->TxFrameID); + if (frameid & TXFID_RATE_PROBE_MASK) + wiphy_err(wiphy, "%s: XXX what to do with " + "TXFID_RATE_PROBE_MASK!?\n", __func__); + + for (i = 0; i < count; i++) + brcms_c_txfifo(wlc, fifo, pkt[i], i == (count - 1), + ampdu->txpkt_weight); + + } + /* endif (count) */ + return err; +} + +static void +brcms_c_ampdu_rate_status(struct brcms_c_info *wlc, + struct ieee80211_tx_info *tx_info, + struct tx_status *txs, u8 mcs) +{ + struct ieee80211_tx_rate *txrate = tx_info->status.rates; + int i; + + /* clear the rest of the rates */ + for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) { + txrate[i].idx = -1; + txrate[i].count = 0; + } +} + +static void +brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb, + struct sk_buff *p, struct tx_status *txs, + u32 s1, u32 s2) +{ + struct scb_ampdu *scb_ampdu; + struct brcms_c_info *wlc = ampdu->wlc; + struct scb_ampdu_tid_ini *ini; + u8 bitmap[8], queue, tid; + struct d11txh *txh; + u8 *plcp; + struct ieee80211_hdr *h; + u16 seq, start_seq = 0, bindex, index, mcl; + u8 mcs = 0; + bool ba_recd = false, ack_recd = false; + u8 suc_mpdu = 0, tot_mpdu = 0; + uint supr_status; + bool update_rate = true, retry = true, tx_error = false; + u16 mimoantsel = 0; + u8 antselid = 0; + u8 retry_limit, rr_retry_limit; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p); + struct wiphy *wiphy = wlc->wiphy; + +#ifdef BCMDBG + u8 hole[AMPDU_MAX_MPDU]; + memset(hole, 0, sizeof(hole)); +#endif + + scb_ampdu = &scb->scb_ampdu; + tid = (u8) (p->priority); + + ini = &scb_ampdu->ini[tid]; + retry_limit = ampdu->retry_limit_tid[tid]; + rr_retry_limit = ampdu->rr_retry_limit_tid[tid]; + memset(bitmap, 0, sizeof(bitmap)); + queue = txs->frameid & TXFID_QUEUE_MASK; + supr_status = txs->status & TX_STATUS_SUPR_MASK; + + if (txs->status & TX_STATUS_ACK_RCV) { + if (TX_STATUS_SUPR_UF == supr_status) + update_rate = false; + + WARN_ON(!(txs->status & TX_STATUS_INTERMEDIATE)); + start_seq = txs->sequence >> SEQNUM_SHIFT; + bitmap[0] = (txs->status & TX_STATUS_BA_BMAP03_MASK) >> + TX_STATUS_BA_BMAP03_SHIFT; + + WARN_ON(s1 & TX_STATUS_INTERMEDIATE); + WARN_ON(!(s1 & TX_STATUS_AMPDU)); + + bitmap[0] |= + (s1 & TX_STATUS_BA_BMAP47_MASK) << + TX_STATUS_BA_BMAP47_SHIFT; + bitmap[1] = (s1 >> 8) & 0xff; + bitmap[2] = (s1 >> 16) & 0xff; + bitmap[3] = (s1 >> 24) & 0xff; + + bitmap[4] = s2 & 0xff; + bitmap[5] = (s2 >> 8) & 0xff; + bitmap[6] = (s2 >> 16) & 0xff; + bitmap[7] = (s2 >> 24) & 0xff; + + ba_recd = true; + } else { + if (supr_status) { + update_rate = false; + if (supr_status == TX_STATUS_SUPR_BADCH) { + wiphy_err(wiphy, "%s: Pkt tx suppressed, " + "illegal channel possibly %d\n", + __func__, CHSPEC_CHANNEL( + wlc->default_bss->chanspec)); + } else { + if (supr_status != TX_STATUS_SUPR_FRAG) + wiphy_err(wiphy, "%s:" + "supr_status 0x%x\n", + __func__, supr_status); + } + /* no need to retry for badch; will fail again */ + if (supr_status == TX_STATUS_SUPR_BADCH || + supr_status == TX_STATUS_SUPR_EXPTIME) { + retry = false; + } else if (supr_status == TX_STATUS_SUPR_EXPTIME) { + /* TX underflow: + * try tuning pre-loading or ampdu size + */ + } else if (supr_status == TX_STATUS_SUPR_FRAG) { + /* + * if there were underflows, but pre-loading + * is not active, notify rate adaptation. + */ + if (brcms_c_ffpld_check_txfunfl(wlc, + prio2fifo[tid]) > 0) + tx_error = true; + } + } else if (txs->phyerr) { + update_rate = false; + wiphy_err(wiphy, "wl%d: ampdu tx phy " + "error (0x%x)\n", wlc->pub->unit, + txs->phyerr); + + if (brcm_msg_level & LOG_ERROR_VAL) { + brcmu_prpkt("txpkt (AMPDU)", p); + brcms_c_print_txdesc((struct d11txh *) p->data); + } + brcms_c_print_txstatus(txs); + } + } + + /* loop through all pkts and retry if not acked */ + while (p) { + tx_info = IEEE80211_SKB_CB(p); + txh = (struct d11txh *) p->data; + mcl = le16_to_cpu(txh->MacTxControlLow); + plcp = (u8 *) (txh + 1); + h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN); + seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT; + + if (tot_mpdu == 0) { + mcs = plcp[0] & MIMO_PLCP_MCS_MASK; + mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel); + } + + index = TX_SEQ_TO_INDEX(seq); + ack_recd = false; + if (ba_recd) { + bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX); + BCMMSG(wlc->wiphy, "tid %d seq %d," + " start_seq %d, bindex %d set %d, index %d\n", + tid, seq, start_seq, bindex, + isset(bitmap, bindex), index); + /* if acked then clear bit and free packet */ + if ((bindex < AMPDU_TX_BA_MAX_WSIZE) + && isset(bitmap, bindex)) { + ini->tx_in_transit--; + ini->txretry[index] = 0; + + /* + * ampdu_ack_len: + * number of acked aggregated frames + */ + /* ampdu_len: number of aggregated frames */ + brcms_c_ampdu_rate_status(wlc, tx_info, txs, + mcs); + tx_info->flags |= IEEE80211_TX_STAT_ACK; + tx_info->flags |= IEEE80211_TX_STAT_AMPDU; + tx_info->status.ampdu_ack_len = + tx_info->status.ampdu_len = 1; + + skb_pull(p, D11_PHY_HDR_LEN); + skb_pull(p, D11_TXH_LEN); + + ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, + p); + ack_recd = true; + suc_mpdu++; + } + } + /* either retransmit or send bar if ack not recd */ + if (!ack_recd) { + struct ieee80211_tx_rate *txrate = + tx_info->status.rates; + if (retry && (txrate[0].count < (int)retry_limit)) { + ini->txretry[index]++; + ini->tx_in_transit--; + /* + * Use high prededence for retransmit to + * give some punch + */ + /* brcms_c_txq_enq(wlc, scb, p, + * BRCMS_PRIO_TO_PREC(tid)); */ + brcms_c_txq_enq(wlc, scb, p, + BRCMS_PRIO_TO_HI_PREC(tid)); + } else { + /* Retry timeout */ + ini->tx_in_transit--; + ieee80211_tx_info_clear_status(tx_info); + tx_info->status.ampdu_ack_len = 0; + tx_info->status.ampdu_len = 1; + tx_info->flags |= + IEEE80211_TX_STAT_AMPDU_NO_BACK; + skb_pull(p, D11_PHY_HDR_LEN); + skb_pull(p, D11_TXH_LEN); + wiphy_err(wiphy, "%s: BA Timeout, seq %d, in_" + "transit %d\n", "AMPDU status", seq, + ini->tx_in_transit); + ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, + p); + } + } + tot_mpdu++; + + /* break out if last packet of ampdu */ + if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) == + TXC_AMPDU_LAST) + break; + + p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED); + } + brcms_c_send_q(wlc); + + /* update rate state */ + antselid = brcms_c_antsel_antsel2id(wlc->asi, mimoantsel); + + brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight); +} + +void +brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, + struct sk_buff *p, struct tx_status *txs) +{ + struct scb_ampdu *scb_ampdu; + struct brcms_c_info *wlc = ampdu->wlc; + struct scb_ampdu_tid_ini *ini; + u32 s1 = 0, s2 = 0; + struct ieee80211_tx_info *tx_info; + + tx_info = IEEE80211_SKB_CB(p); + + /* BMAC_NOTE: For the split driver, second level txstatus comes later + * So if the ACK was received then wait for the second level else just + * call the first one + */ + if (txs->status & TX_STATUS_ACK_RCV) { + u8 status_delay = 0; + + /* wait till the next 8 bytes of txstatus is available */ + while (((s1 = R_REG(&wlc->regs->frmtxstatus)) & TXS_V) == 0) { + udelay(1); + status_delay++; + if (status_delay > 10) + return; /* error condition */ + } + + s2 = R_REG(&wlc->regs->frmtxstatus2); + } + + if (scb) { + scb_ampdu = &scb->scb_ampdu; + ini = &scb_ampdu->ini[p->priority]; + brcms_c_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2); + } else { + /* loop through all pkts and free */ + u8 queue = txs->frameid & TXFID_QUEUE_MASK; + struct d11txh *txh; + u16 mcl; + while (p) { + tx_info = IEEE80211_SKB_CB(p); + txh = (struct d11txh *) p->data; + mcl = le16_to_cpu(txh->MacTxControlLow); + brcmu_pkt_buf_free_skb(p); + /* break out if last packet of ampdu */ + if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) == + TXC_AMPDU_LAST) + break; + p = dma_getnexttxp(wlc->hw->di[queue], + DMA_RANGE_TRANSMITTED); + } + brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight); + } +} + +void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc) +{ + char template[T_RAM_ACCESS_SZ * 2]; + + /* driver needs to write the ta in the template; ta is at offset 16 */ + memset(template, 0, sizeof(template)); + memcpy(template, wlc->pub->cur_etheraddr, ETH_ALEN); + brcms_b_write_template_ram(wlc->hw, (T_BA_TPL_BASE + 16), + (T_RAM_ACCESS_SZ * 2), + template); +} + +bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid) +{ + return wlc->ampdu->ini_enable[tid]; +} + +void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu) +{ + struct brcms_c_info *wlc = ampdu->wlc; + + /* + * Extend ucode internal watchdog timer to + * match larger received frames + */ + if ((ampdu->rx_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) == + IEEE80211_HT_MAX_AMPDU_64K) { + brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_MAX); + brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_MAX); + } else { + brcms_b_write_shm(wlc->hw, M_MIMO_MAXSYM, MIMO_MAXSYM_DEF); + brcms_b_write_shm(wlc->hw, M_WATCHDOG_8TU, WATCHDOG_8TU_DEF); + } +} + +/* + * callback function that helps flushing ampdu packets from a priority queue + */ +static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu); + struct cb_del_ampdu_pars *ampdu_pars = + (struct cb_del_ampdu_pars *)arg_a; + bool rc; + + rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false; + rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL || + tx_info->control.sta == ampdu_pars->sta); + rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid); + return rc; +} + +/* + * callback function that helps invalidating ampdu packets in a DMA queue + */ +static void dma_cb_fn_ampdu(void *txi, void *arg_a) +{ + struct ieee80211_sta *sta = arg_a; + struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi; + + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && + (tx_info->control.sta == sta || sta == NULL)) + tx_info->control.sta = NULL; +} + +/* + * When a remote party is no longer available for ampdu communication, any + * pending tx ampdu packets in the driver have to be flushed. + */ +void brcms_c_ampdu_flush(struct brcms_c_info *wlc, + struct ieee80211_sta *sta, u16 tid) +{ + struct brcms_txq_info *qi = wlc->pkt_queue; + struct pktq *pq = &qi->q; + int prec; + struct cb_del_ampdu_pars ampdu_pars; + + ampdu_pars.sta = sta; + ampdu_pars.tid = tid; + for (prec = 0; prec < pq->num_prec; prec++) + brcmu_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt, + (void *)&du_pars); + brcms_c_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu); +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h new file mode 100644 index 000000000000..421f4ba7c63c --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_AMPDU_H_ +#define _BRCM_AMPDU_H_ + +extern struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc); +extern void brcms_c_ampdu_detach(struct ampdu_info *ampdu); +extern int brcms_c_sendampdu(struct ampdu_info *ampdu, + struct brcms_txq_info *qi, + struct sk_buff **aggp, int prec); +extern void brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb, + struct sk_buff *p, struct tx_status *txs); +extern void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc); +extern void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu); + +#endif /* _BRCM_AMPDU_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/antsel.c b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c new file mode 100644 index 000000000000..a47ce25cb9a2 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 <net/mac80211.h> + +#include "types.h" +#include "main.h" +#include "phy_shim.h" +#include "antsel.h" + +#define ANT_SELCFG_AUTO 0x80 /* bit indicates antenna sel AUTO */ +#define ANT_SELCFG_MASK 0x33 /* antenna configuration mask */ +#define ANT_SELCFG_TX_UNICAST 0 /* unicast tx antenna configuration */ +#define ANT_SELCFG_RX_UNICAST 1 /* unicast rx antenna configuration */ +#define ANT_SELCFG_TX_DEF 2 /* default tx antenna configuration */ +#define ANT_SELCFG_RX_DEF 3 /* default rx antenna configuration */ + +/* useful macros */ +#define BRCMS_ANTSEL_11N_0(ant) ((((ant) & ANT_SELCFG_MASK) >> 4) & 0xf) +#define BRCMS_ANTSEL_11N_1(ant) (((ant) & ANT_SELCFG_MASK) & 0xf) +#define BRCMS_ANTIDX_11N(ant) (((BRCMS_ANTSEL_11N_0(ant)) << 2) +\ + (BRCMS_ANTSEL_11N_1(ant))) +#define BRCMS_ANT_ISAUTO_11N(ant) (((ant) & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO) +#define BRCMS_ANTSEL_11N(ant) ((ant) & ANT_SELCFG_MASK) + +/* antenna switch */ +/* defines for no boardlevel antenna diversity */ +#define ANT_SELCFG_DEF_2x2 0x01 /* default antenna configuration */ + +/* 2x3 antdiv defines and tables for GPIO communication */ +#define ANT_SELCFG_NUM_2x3 3 +#define ANT_SELCFG_DEF_2x3 0x01 /* default antenna configuration */ + +/* 2x4 antdiv rev4 defines and tables for GPIO communication */ +#define ANT_SELCFG_NUM_2x4 4 +#define ANT_SELCFG_DEF_2x4 0x02 /* default antenna configuration */ + +static const u16 mimo_2x4_div_antselpat_tbl[] = { + 0, 0, 0x9, 0xa, /* ant0: 0 ant1: 2,3 */ + 0, 0, 0x5, 0x6, /* ant0: 1 ant1: 2,3 */ + 0, 0, 0, 0, /* n.a. */ + 0, 0, 0, 0 /* n.a. */ +}; + +static const u8 mimo_2x4_div_antselid_tbl[16] = { + 0, 0, 0, 0, 0, 2, 3, 0, + 0, 0, 1, 0, 0, 0, 0, 0 /* pat to antselid */ +}; + +static const u16 mimo_2x3_div_antselpat_tbl[] = { + 16, 0, 1, 16, /* ant0: 0 ant1: 1,2 */ + 16, 16, 16, 16, /* n.a. */ + 16, 2, 16, 16, /* ant0: 2 ant1: 1 */ + 16, 16, 16, 16 /* n.a. */ +}; + +static const u8 mimo_2x3_div_antselid_tbl[16] = { + 0, 1, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 /* pat to antselid */ +}; + +/* boardlevel antenna selection: init antenna selection structure */ +static void +brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel, + bool auto_sel) +{ + if (asi->antsel_type == ANTSEL_2x3) { + u8 antcfg_def = ANT_SELCFG_DEF_2x3 | + ((asi->antsel_avail && auto_sel) ? ANT_SELCFG_AUTO : 0); + antsel->ant_config[ANT_SELCFG_TX_DEF] = antcfg_def; + antsel->ant_config[ANT_SELCFG_TX_UNICAST] = antcfg_def; + antsel->ant_config[ANT_SELCFG_RX_DEF] = antcfg_def; + antsel->ant_config[ANT_SELCFG_RX_UNICAST] = antcfg_def; + antsel->num_antcfg = ANT_SELCFG_NUM_2x3; + + } else if (asi->antsel_type == ANTSEL_2x4) { + + antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x4; + antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x4; + antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x4; + antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x4; + antsel->num_antcfg = ANT_SELCFG_NUM_2x4; + + } else { /* no antenna selection available */ + + antsel->ant_config[ANT_SELCFG_TX_DEF] = ANT_SELCFG_DEF_2x2; + antsel->ant_config[ANT_SELCFG_TX_UNICAST] = ANT_SELCFG_DEF_2x2; + antsel->ant_config[ANT_SELCFG_RX_DEF] = ANT_SELCFG_DEF_2x2; + antsel->ant_config[ANT_SELCFG_RX_UNICAST] = ANT_SELCFG_DEF_2x2; + antsel->num_antcfg = 0; + } +} + +struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) +{ + struct antsel_info *asi; + struct si_pub *sih = wlc->hw->sih; + + asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC); + if (!asi) + return NULL; + + asi->wlc = wlc; + asi->pub = wlc->pub; + asi->antsel_type = ANTSEL_NA; + asi->antsel_avail = false; + asi->antsel_antswitch = (u8) getintvar(sih, BRCMS_SROM_ANTSWITCH); + + if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) { + switch (asi->antsel_antswitch) { + case ANTSWITCH_TYPE_1: + case ANTSWITCH_TYPE_2: + case ANTSWITCH_TYPE_3: + /* 4321/2 board with 2x3 switch logic */ + asi->antsel_type = ANTSEL_2x3; + /* Antenna selection availability */ + if (((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) || + ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 7)) { + asi->antsel_avail = true; + } else if ( + (u16) getintvar(sih, BRCMS_SROM_AA2G) == 3 || + (u16) getintvar(sih, BRCMS_SROM_AA5G) == 3) { + asi->antsel_avail = false; + } else { + asi->antsel_avail = false; + wiphy_err(wlc->wiphy, "antsel_attach: 2o3 " + "board cfg invalid\n"); + } + + break; + default: + break; + } + } else if ((asi->pub->sromrev == 4) && + ((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) && + ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 0)) { + /* hack to match old 4321CB2 cards with 2of3 antenna switch */ + asi->antsel_type = ANTSEL_2x3; + asi->antsel_avail = true; + } else if (asi->pub->boardflags2 & BFL2_2X4_DIV) { + asi->antsel_type = ANTSEL_2x4; + asi->antsel_avail = true; + } + + /* Set the antenna selection type for the low driver */ + brcms_b_antsel_type_set(wlc->hw, asi->antsel_type); + + /* Init (auto/manual) antenna selection */ + brcms_c_antsel_init_cfg(asi, &asi->antcfg_11n, true); + brcms_c_antsel_init_cfg(asi, &asi->antcfg_cur, true); + + return asi; +} + +void brcms_c_antsel_detach(struct antsel_info *asi) +{ + kfree(asi); +} + +/* + * boardlevel antenna selection: + * convert ant_cfg to mimo_antsel (ucode interface) + */ +static u16 brcms_c_antsel_antcfg2antsel(struct antsel_info *asi, u8 ant_cfg) +{ + u8 idx = BRCMS_ANTIDX_11N(BRCMS_ANTSEL_11N(ant_cfg)); + u16 mimo_antsel = 0; + + if (asi->antsel_type == ANTSEL_2x4) { + /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ + mimo_antsel = (mimo_2x4_div_antselpat_tbl[idx] & 0xf); + return mimo_antsel; + + } else if (asi->antsel_type == ANTSEL_2x3) { + /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ + mimo_antsel = (mimo_2x3_div_antselpat_tbl[idx] & 0xf); + return mimo_antsel; + } + + return mimo_antsel; +} + +/* boardlevel antenna selection: ucode interface control */ +static int brcms_c_antsel_cfgupd(struct antsel_info *asi, + struct brcms_antselcfg *antsel) +{ + struct brcms_c_info *wlc = asi->wlc; + u8 ant_cfg; + u16 mimo_antsel; + + /* 1) Update TX antconfig for all frames that are not unicast data + * (aka default TX) + */ + ant_cfg = antsel->ant_config[ANT_SELCFG_TX_DEF]; + mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg); + brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_TXDFLT, mimo_antsel); + /* + * Update driver stats for currently selected + * default tx/rx antenna config + */ + asi->antcfg_cur.ant_config[ANT_SELCFG_TX_DEF] = ant_cfg; + + /* 2) Update RX antconfig for all frames that are not unicast data + * (aka default RX) + */ + ant_cfg = antsel->ant_config[ANT_SELCFG_RX_DEF]; + mimo_antsel = brcms_c_antsel_antcfg2antsel(asi, ant_cfg); + brcms_b_write_shm(wlc->hw, M_MIMO_ANTSEL_RXDFLT, mimo_antsel); + /* + * Update driver stats for currently selected + * default tx/rx antenna config + */ + asi->antcfg_cur.ant_config[ANT_SELCFG_RX_DEF] = ant_cfg; + + return 0; +} + +void brcms_c_antsel_init(struct antsel_info *asi) +{ + if ((asi->antsel_type == ANTSEL_2x3) || + (asi->antsel_type == ANTSEL_2x4)) + brcms_c_antsel_cfgupd(asi, &asi->antcfg_11n); +} + +/* boardlevel antenna selection: convert id to ant_cfg */ +static u8 brcms_c_antsel_id2antcfg(struct antsel_info *asi, u8 id) +{ + u8 antcfg = ANT_SELCFG_DEF_2x2; + + if (asi->antsel_type == ANTSEL_2x4) { + /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ + antcfg = (((id & 0x2) << 3) | ((id & 0x1) + 2)); + return antcfg; + + } else if (asi->antsel_type == ANTSEL_2x3) { + /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ + antcfg = (((id & 0x02) << 4) | ((id & 0x1) + 1)); + return antcfg; + } + + return antcfg; +} + +void +brcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef, bool sel, + u8 antselid, u8 fbantselid, u8 *antcfg, + u8 *fbantcfg) +{ + u8 ant; + + /* if use default, assign it and return */ + if (usedef) { + *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_DEF]; + *fbantcfg = *antcfg; + return; + } + + if (!sel) { + *antcfg = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; + *fbantcfg = *antcfg; + + } else { + ant = asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; + if ((ant & ANT_SELCFG_AUTO) == ANT_SELCFG_AUTO) { + *antcfg = brcms_c_antsel_id2antcfg(asi, antselid); + *fbantcfg = brcms_c_antsel_id2antcfg(asi, fbantselid); + } else { + *antcfg = + asi->antcfg_11n.ant_config[ANT_SELCFG_TX_UNICAST]; + *fbantcfg = *antcfg; + } + } + return; +} + +/* boardlevel antenna selection: convert mimo_antsel (ucode interface) to id */ +u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel) +{ + u8 antselid = 0; + + if (asi->antsel_type == ANTSEL_2x4) { + /* 2x4 antenna diversity board, 4 cfgs: 0-2 0-3 1-2 1-3 */ + antselid = mimo_2x4_div_antselid_tbl[(antsel & 0xf)]; + return antselid; + + } else if (asi->antsel_type == ANTSEL_2x3) { + /* 2x3 antenna selection, 3 cfgs: 0-1 0-2 2-1 */ + antselid = mimo_2x3_div_antselid_tbl[(antsel & 0xf)]; + return antselid; + } + + return antselid; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/antsel.h b/drivers/net/wireless/brcm80211/brcmsmac/antsel.h new file mode 100644 index 000000000000..97ea3881a8ec --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/antsel.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_ANTSEL_H_ +#define _BRCM_ANTSEL_H_ + +extern struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc); +extern void brcms_c_antsel_detach(struct antsel_info *asi); +extern void brcms_c_antsel_init(struct antsel_info *asi); +extern void brcms_c_antsel_antcfg_get(struct antsel_info *asi, bool usedef, + bool sel, + u8 id, u8 fbid, u8 *antcfg, + u8 *fbantcfg); +extern u8 brcms_c_antsel_antsel2id(struct antsel_info *asi, u16 antsel); + +#endif /* _BRCM_ANTSEL_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c new file mode 100644 index 000000000000..52fc9eeb5fa5 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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/module.h> /* bug in tracepoint.h, it should include this */ + +#ifndef __CHECKER__ +#include "mac80211_if.h" +#define CREATE_TRACE_POINTS +#include "brcms_trace_events.h" +#endif diff --git a/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h new file mode 100644 index 000000000000..27dd73eef56d --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM brcmsmac + +#if !defined(__TRACE_BRCMSMAC_H) || defined(TRACE_HEADER_MULTI_READ) + +#define __TRACE_BRCMSMAC_H + +#include <linux/tracepoint.h> +#include "mac80211_if.h" + +#ifndef CONFIG_BRCMDBG +#undef TRACE_EVENT +#define TRACE_EVENT(name, proto, ...) \ +static inline void trace_ ## name(proto) {} +#endif + +/* + * We define a tracepoint, its arguments, its printk format and its + * 'fast binary record' layout. + */ +TRACE_EVENT(brcms_timer, + /* TPPROTO is the prototype of the function called by this tracepoint */ + TP_PROTO(struct brcms_timer *t), + /* + * TPARGS(firstarg, p) are the parameters names, same as found in the + * prototype. + */ + TP_ARGS(t), + /* + * Fast binary tracing: define the trace record via TP_STRUCT__entry(). + * You can think about it like a regular C structure local variable + * definition. + */ + TP_STRUCT__entry( + __field(uint, ms) + __field(uint, set) + __field(uint, periodic) + ), + TP_fast_assign( + __entry->ms = t->ms; + __entry->set = t->set; + __entry->periodic = t->periodic; + ), + TP_printk( + "ms=%u set=%u periodic=%u", + __entry->ms, __entry->set, __entry->periodic + ) +); + +TRACE_EVENT(brcms_dpc, + TP_PROTO(unsigned long data), + TP_ARGS(data), + TP_STRUCT__entry( + __field(unsigned long, data) + ), + TP_fast_assign( + __entry->data = data; + ), + TP_printk( + "data=%p", + (void *)__entry->data + ) +); + +#endif /* __TRACE_BRCMSMAC_H */ + +#ifdef CONFIG_BRCMDBG + +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE brcms_trace_events + +#include <trace/define_trace.h> + +#endif /* CONFIG_BRCMDBG */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c new file mode 100644 index 000000000000..89ad1b7dab8f --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -0,0 +1,1591 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/types.h> +#include <net/mac80211.h> + +#include <defs.h> +#include "pub.h" +#include "phy/phy_hal.h" +#include "main.h" +#include "stf.h" +#include "channel.h" + +/* QDB() macro takes a dB value and converts to a quarter dB value */ +#define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR) + +#define LOCALE_CHAN_01_11 (1<<0) +#define LOCALE_CHAN_12_13 (1<<1) +#define LOCALE_CHAN_14 (1<<2) +#define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */ +#define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */ +#define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */ +#define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */ +#define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */ +#define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */ +#define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */ +#define LOCALE_SET_5G_MID3 (1<<10) /* 128 */ +#define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */ +#define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */ +#define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */ +#define LOCALE_CHAN_52_140_ALL (1<<14) +#define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */ + +#define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \ + LOCALE_SET_5G_LOW2 | \ + LOCALE_SET_5G_LOW3) +#define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3) +#define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2) +#define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \ + LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1) +#define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3) +#define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4 + +#define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \ + LOCALE_CHAN_12_13 | \ + LOCALE_CHAN_14) + +#define LOCALE_RADAR_SET_NONE 0 +#define LOCALE_RADAR_SET_1 1 + +#define LOCALE_RESTRICTED_NONE 0 +#define LOCALE_RESTRICTED_SET_2G_SHORT 1 +#define LOCALE_RESTRICTED_CHAN_165 2 +#define LOCALE_CHAN_ALL_5G 3 +#define LOCALE_RESTRICTED_JAPAN_LEGACY 4 +#define LOCALE_RESTRICTED_11D_2G 5 +#define LOCALE_RESTRICTED_11D_5G 6 +#define LOCALE_RESTRICTED_LOW_HI 7 +#define LOCALE_RESTRICTED_12_13_14 8 + +#define LOCALE_2G_IDX_i 0 +#define LOCALE_5G_IDX_11 0 +#define LOCALE_MIMO_IDX_bn 0 +#define LOCALE_MIMO_IDX_11n 0 + +/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */ +#define BRCMS_MAXPWR_TBL_SIZE 6 +/* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */ +#define BRCMS_MAXPWR_MIMO_TBL_SIZE 14 + +/* power level in group of 2.4GHz band channels: + * maxpwr[0] - CCK channels [1] + * maxpwr[1] - CCK channels [2-10] + * maxpwr[2] - CCK channels [11-14] + * maxpwr[3] - OFDM channels [1] + * maxpwr[4] - OFDM channels [2-10] + * maxpwr[5] - OFDM channels [11-14] + */ + +/* maxpwr mapping to 5GHz band channels: + * maxpwr[0] - channels [34-48] + * maxpwr[1] - channels [52-60] + * maxpwr[2] - channels [62-64] + * maxpwr[3] - channels [100-140] + * maxpwr[4] - channels [149-165] + */ +#define BAND_5G_PWR_LVLS 5 /* 5 power levels for 5G */ + +#define LC(id) LOCALE_MIMO_IDX_ ## id + +#define LC_2G(id) LOCALE_2G_IDX_ ## id + +#define LC_5G(id) LOCALE_5G_IDX_ ## id + +#define LOCALES(band2, band5, mimo2, mimo5) \ + {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)} + +/* macro to get 2.4 GHz channel group index for tx power */ +#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2)) +#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5)) + +/* macro to get 5 GHz channel group index for tx power */ +#define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \ + (((c) < 62) ? 1 : \ + (((c) < 100) ? 2 : \ + (((c) < 149) ? 3 : 4)))) + +#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU) + +struct brcms_cm_band { + /* struct locale_info flags */ + u8 locale_flags; + /* List of valid channels in the country */ + struct brcms_chanvec valid_channels; + /* List of restricted use channels */ + const struct brcms_chanvec *restricted_channels; + /* List of radar sensitive channels */ + const struct brcms_chanvec *radar_channels; + u8 PAD[8]; +}; + + /* locale per-channel tx power limits for MIMO frames + * maxpwr arrays are index by channel for 2.4 GHz limits, and + * by sub-band for 5 GHz limits using CHANNEL_POWER_IDX_5G(channel) + */ +struct locale_mimo_info { + /* tx 20 MHz power limits, qdBm units */ + s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE]; + /* tx 40 MHz power limits, qdBm units */ + s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE]; + u8 flags; +}; + +/* Country names and abbreviations with locale defined from ISO 3166 */ +struct country_info { + const u8 locale_2G; /* 2.4G band locale */ + const u8 locale_5G; /* 5G band locale */ + const u8 locale_mimo_2G; /* 2.4G mimo info */ + const u8 locale_mimo_5G; /* 5G mimo info */ +}; + +struct brcms_cm_info { + struct brcms_pub *pub; + struct brcms_c_info *wlc; + char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */ + uint srom_regrev; /* Regulatory Rev for the SROM ccode */ + const struct country_info *country; /* current country def */ + char ccode[BRCM_CNTRY_BUF_SZ]; /* current internal Country Code */ + uint regrev; /* current Regulatory Revision */ + char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */ + /* per-band state (one per phy/radio) */ + struct brcms_cm_band bandstate[MAXBANDS]; + /* quiet channels currently for radar sensitivity or 11h support */ + /* channels on which we cannot transmit */ + struct brcms_chanvec quiet_channels; +}; + +/* locale channel and power info. */ +struct locale_info { + u32 valid_channels; + /* List of radar sensitive channels */ + u8 radar_channels; + /* List of channels used only if APs are detected */ + u8 restricted_channels; + /* Max tx pwr in qdBm for each sub-band */ + s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE]; + /* Country IE advertised max tx pwr in dBm per sub-band */ + s8 pub_maxpwr[BAND_5G_PWR_LVLS]; + u8 flags; +}; + +/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */ + +/* + * Some common channel sets + */ + +/* No channels */ +static const struct brcms_chanvec chanvec_none = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +/* All 2.4 GHz HW channels */ +static const struct brcms_chanvec chanvec_all_2G = { + {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +/* All 5 GHz HW channels */ +static const struct brcms_chanvec chanvec_all_5G = { + {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11, + 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11, + 0x11, 0x11, 0x11, 0x01} +}; + +/* + * Radar channel sets + */ + +/* Channels 52 - 64, 100 - 140 */ +static const struct brcms_chanvec radar_set1 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */ + 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */ + 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */ + 0x00, 0x00, 0x00, 0x00} +}; + +/* + * Restricted channel sets + */ + +/* Channels 34, 38, 42, 46 */ +static const struct brcms_chanvec restricted_set_japan_legacy = { + {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +/* Channels 12, 13 */ +static const struct brcms_chanvec restricted_set_2g_short = { + {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +/* Channel 165 */ +static const struct brcms_chanvec restricted_chan_165 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +/* Channels 36 - 48 & 149 - 165 */ +static const struct brcms_chanvec restricted_low_hi = { + {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +/* Channels 12 - 14 */ +static const struct brcms_chanvec restricted_set_12_13_14 = { + {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +/* global memory to provide working buffer for expanded locale */ + +static const struct brcms_chanvec *g_table_radar_set[] = { + &chanvec_none, + &radar_set1 +}; + +static const struct brcms_chanvec *g_table_restricted_chan[] = { + &chanvec_none, /* restricted_set_none */ + &restricted_set_2g_short, + &restricted_chan_165, + &chanvec_all_5G, + &restricted_set_japan_legacy, + &chanvec_all_2G, /* restricted_set_11d_2G */ + &chanvec_all_5G, /* restricted_set_11d_5G */ + &restricted_low_hi, + &restricted_set_12_13_14 +}; + +static const struct brcms_chanvec locale_2g_01_11 = { + {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_2g_12_13 = { + {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_2g_14 = { + {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_LOW_JP1 = { + {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_LOW_JP2 = { + {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_LOW1 = { + {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_LOW2 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_LOW3 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_MID1 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_MID2 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_MID3 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_HIGH1 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_HIGH2 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_HIGH3 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_52_140_ALL = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_chanvec locale_5g_HIGH4 = { + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, + 0x11, 0x11, 0x11, 0x11} +}; + +static const struct brcms_chanvec *g_table_locale_base[] = { + &locale_2g_01_11, + &locale_2g_12_13, + &locale_2g_14, + &locale_5g_LOW_JP1, + &locale_5g_LOW_JP2, + &locale_5g_LOW1, + &locale_5g_LOW2, + &locale_5g_LOW3, + &locale_5g_MID1, + &locale_5g_MID2, + &locale_5g_MID3, + &locale_5g_HIGH1, + &locale_5g_HIGH2, + &locale_5g_HIGH3, + &locale_5g_52_140_ALL, + &locale_5g_HIGH4 +}; + +static void brcms_c_locale_add_channels(struct brcms_chanvec *target, + const struct brcms_chanvec *channels) +{ + u8 i; + for (i = 0; i < sizeof(struct brcms_chanvec); i++) + target->vec[i] |= channels->vec[i]; +} + +static void brcms_c_locale_get_channels(const struct locale_info *locale, + struct brcms_chanvec *channels) +{ + u8 i; + + memset(channels, 0, sizeof(struct brcms_chanvec)); + + for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) { + if (locale->valid_channels & (1 << i)) + brcms_c_locale_add_channels(channels, + g_table_locale_base[i]); + } +} + +/* + * Locale Definitions - 2.4 GHz + */ +static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */ + LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13, + LOCALE_RADAR_SET_NONE, + LOCALE_RESTRICTED_SET_2G_SHORT, + {QDB(19), QDB(19), QDB(19), + QDB(19), QDB(19), QDB(19)}, + {20, 20, 20, 0}, + BRCMS_EIRP +}; + +/* + * Locale Definitions - 5 GHz + */ +static const struct locale_info locale_11 = { + /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */ + LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165, + LOCALE_RADAR_SET_1, + LOCALE_RESTRICTED_NONE, + {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)}, + {23, 23, 23, 30, 30}, + BRCMS_EIRP | BRCMS_DFS_EU +}; + +static const struct locale_info *g_locale_2g_table[] = { + &locale_i +}; + +static const struct locale_info *g_locale_5g_table[] = { + &locale_11 +}; + +/* + * MIMO Locale Definitions - 2.4 GHz + */ +static const struct locale_mimo_info locale_bn = { + {QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), + QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), + QDB(13), QDB(13), QDB(13)}, + {0, 0, QDB(13), QDB(13), QDB(13), + QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), + QDB(13), 0, 0}, + 0 +}; + +static const struct locale_mimo_info *g_mimo_2g_table[] = { + &locale_bn +}; + +/* + * MIMO Locale Definitions - 5 GHz + */ +static const struct locale_mimo_info locale_11n = { + { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)}, + {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)}, + 0 +}; + +static const struct locale_mimo_info *g_mimo_5g_table[] = { + &locale_11n +}; + +static const struct { + char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */ + struct country_info country; +} cntry_locales[] = { + { + "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */ +}; + +#ifdef SUPPORT_40MHZ +/* 20MHz channel info for 40MHz pairing support */ +struct chan20_info { + u8 sb; + u8 adj_sbs; +}; + +/* indicates adjacent channels that are allowed for a 40 Mhz channel and + * those that permitted by the HT + */ +struct chan20_info chan20_info[] = { + /* 11b/11g */ +/* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, +/* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, +/* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, +/* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, +/* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, +/* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 11 */ {12, (CH_LOWER_SB)}, +/* 12 */ {13, (CH_LOWER_SB)}, +/* 13 */ {14, (CH_LOWER_SB)}, + +/* 11a japan high */ +/* 14 */ {34, (CH_UPPER_SB)}, +/* 15 */ {38, (CH_LOWER_SB)}, +/* 16 */ {42, (CH_LOWER_SB)}, +/* 17 */ {46, (CH_LOWER_SB)}, + +/* 11a usa low */ +/* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)}, + +/* 11a Europe */ +/* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 36 */ {140, (CH_LOWER_SB)}, + +/* 11a usa high, ref5 only */ +/* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */ +/* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)}, +/* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)}, +/* 41 */ {165, (CH_LOWER_SB)}, + +/* 11a japan */ +/* 42 */ {184, (CH_UPPER_SB)}, +/* 43 */ {188, (CH_LOWER_SB)}, +/* 44 */ {192, (CH_UPPER_SB)}, +/* 45 */ {196, (CH_LOWER_SB)}, +/* 46 */ {200, (CH_UPPER_SB)}, +/* 47 */ {204, (CH_LOWER_SB)}, +/* 48 */ {208, (CH_UPPER_SB)}, +/* 49 */ {212, (CH_LOWER_SB)}, +/* 50 */ {216, (CH_LOWER_SB)} +}; +#endif /* SUPPORT_40MHZ */ + +static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx) +{ + if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) + return NULL; /* error condition */ + + return g_locale_2g_table[locale_idx]; +} + +static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx) +{ + if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) + return NULL; /* error condition */ + + return g_locale_5g_table[locale_idx]; +} + +static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx) +{ + if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) + return NULL; + + return g_mimo_2g_table[locale_idx]; +} + +static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx) +{ + if (locale_idx >= ARRAY_SIZE(g_mimo_5g_table)) + return NULL; + + return g_mimo_5g_table[locale_idx]; +} + +static int +brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode, + char *mapped_ccode, uint *mapped_regrev) +{ + return false; +} + +/* Lookup a country info structure from a null terminated country + * abbreviation and regrev directly with no translation. + */ +static const struct country_info * +brcms_c_country_lookup_direct(const char *ccode, uint regrev) +{ + uint size, i; + + /* Should just return 0 for single locale driver. */ + /* Keep it this way in case we add more locales. (for now anyway) */ + + /* + * all other country def arrays are for regrev == 0, so if + * regrev is non-zero, fail + */ + if (regrev > 0) + return NULL; + + /* find matched table entry from country code */ + size = ARRAY_SIZE(cntry_locales); + for (i = 0; i < size; i++) { + if (strcmp(ccode, cntry_locales[i].abbrev) == 0) + return &cntry_locales[i].country; + } + return NULL; +} + +static const struct country_info * +brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode, + char *mapped_ccode, uint *mapped_regrev) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + const struct country_info *country; + uint srom_regrev = wlc_cm->srom_regrev; + const char *srom_ccode = wlc_cm->srom_ccode; + int mapped; + + /* check for currently supported ccode size */ + if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) { + wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for " + "match\n", wlc->pub->unit, __func__, ccode); + return NULL; + } + + /* default mapping is the given ccode and regrev 0 */ + strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ); + *mapped_regrev = 0; + + /* If the desired country code matches the srom country code, + * then the mapped country is the srom regulatory rev. + * Otherwise look for an aggregate mapping. + */ + if (!strcmp(srom_ccode, ccode)) { + *mapped_regrev = srom_regrev; + mapped = 0; + wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__); + } else { + mapped = + brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode, + mapped_regrev); + } + + /* find the matching built-in country definition */ + country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev); + + /* if there is not an exact rev match, default to rev zero */ + if (country == NULL && *mapped_regrev != 0) { + *mapped_regrev = 0; + country = + brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev); + } + + return country; +} + +/* Lookup a country info structure from a null terminated country code + * The lookup is case sensitive. + */ +static const struct country_info * +brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode) +{ + const struct country_info *country; + char mapped_ccode[BRCM_CNTRY_BUF_SZ]; + uint mapped_regrev; + + /* + * map the country code to a built-in country code, regrev, and + * country_info struct + */ + country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode, + &mapped_regrev); + + return country; +} + +/* + * reset the quiet channels vector to the union + * of the restricted and radar channel sets + */ +static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + uint i, j; + struct brcms_band *band; + const struct brcms_chanvec *chanvec; + + memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec)); + + band = wlc->band; + for (i = 0; i < wlc->pub->_nbands; + i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) { + + /* initialize quiet channels for restricted channels */ + chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels; + for (j = 0; j < sizeof(struct brcms_chanvec); j++) + wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j]; + + } +} + +/* Is the channel valid for the current locale and current band? */ +static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + + return ((val < MAXCHANNEL) && + isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec, + val)); +} + +/* Is the channel valid for the current locale and specified band? */ +static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm, + uint bandunit, uint val) +{ + return ((val < MAXCHANNEL) + && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val)); +} + +/* Is the channel valid for the current locale? (but don't consider channels not + * available due to bandlocking) + */ +static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + + return brcms_c_valid_channel20(wlc->cmi, val) || + (!wlc->bandlocked + && brcms_c_valid_channel20_in_band(wlc->cmi, + OTHERBANDUNIT(wlc), val)); +} + +/* JP, J1 - J10 are Japan ccodes */ +static bool brcms_c_japan_ccode(const char *ccode) +{ + return (ccode[0] == 'J' && + (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9'))); +} + +/* Returns true if currently set country is Japan or variant */ +static bool brcms_c_japan(struct brcms_c_info *wlc) +{ + return brcms_c_japan_ccode(wlc->cmi->country_abbrev); +} + +static void +brcms_c_channel_min_txpower_limits_with_local_constraint( + struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr, + u8 local_constraint_qdbm) +{ + int j; + + /* CCK Rates */ + for (j = 0; j < WL_TX_POWER_CCK_NUM; j++) + txpwr->cck[j] = min(txpwr->cck[j], local_constraint_qdbm); + + /* 20 MHz Legacy OFDM SISO */ + for (j = 0; j < WL_TX_POWER_OFDM_NUM; j++) + txpwr->ofdm[j] = min(txpwr->ofdm[j], local_constraint_qdbm); + + /* 20 MHz Legacy OFDM CDD */ + for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) + txpwr->ofdm_cdd[j] = + min(txpwr->ofdm_cdd[j], local_constraint_qdbm); + + /* 40 MHz Legacy OFDM SISO */ + for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) + txpwr->ofdm_40_siso[j] = + min(txpwr->ofdm_40_siso[j], local_constraint_qdbm); + + /* 40 MHz Legacy OFDM CDD */ + for (j = 0; j < BRCMS_NUM_RATES_OFDM; j++) + txpwr->ofdm_40_cdd[j] = + min(txpwr->ofdm_40_cdd[j], local_constraint_qdbm); + + /* 20MHz MCS 0-7 SISO */ + for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) + txpwr->mcs_20_siso[j] = + min(txpwr->mcs_20_siso[j], local_constraint_qdbm); + + /* 20MHz MCS 0-7 CDD */ + for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) + txpwr->mcs_20_cdd[j] = + min(txpwr->mcs_20_cdd[j], local_constraint_qdbm); + + /* 20MHz MCS 0-7 STBC */ + for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) + txpwr->mcs_20_stbc[j] = + min(txpwr->mcs_20_stbc[j], local_constraint_qdbm); + + /* 20MHz MCS 8-15 MIMO */ + for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++) + txpwr->mcs_20_mimo[j] = + min(txpwr->mcs_20_mimo[j], local_constraint_qdbm); + + /* 40MHz MCS 0-7 SISO */ + for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) + txpwr->mcs_40_siso[j] = + min(txpwr->mcs_40_siso[j], local_constraint_qdbm); + + /* 40MHz MCS 0-7 CDD */ + for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) + txpwr->mcs_40_cdd[j] = + min(txpwr->mcs_40_cdd[j], local_constraint_qdbm); + + /* 40MHz MCS 0-7 STBC */ + for (j = 0; j < BRCMS_NUM_RATES_MCS_1_STREAM; j++) + txpwr->mcs_40_stbc[j] = + min(txpwr->mcs_40_stbc[j], local_constraint_qdbm); + + /* 40MHz MCS 8-15 MIMO */ + for (j = 0; j < BRCMS_NUM_RATES_MCS_2_STREAM; j++) + txpwr->mcs_40_mimo[j] = + min(txpwr->mcs_40_mimo[j], local_constraint_qdbm); + + /* 40MHz MCS 32 */ + txpwr->mcs32 = min(txpwr->mcs32, local_constraint_qdbm); + +} + +/* Update the radio state (enable/disable) and tx power targets + * based on a new set of channel/regulatory information + */ +static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + uint chan; + struct txpwr_limits txpwr; + + /* search for the existence of any valid channel */ + for (chan = 0; chan < MAXCHANNEL; chan++) { + if (brcms_c_valid_channel20_db(wlc->cmi, chan)) + break; + } + if (chan == MAXCHANNEL) + chan = INVCHANNEL; + + /* + * based on the channel search above, set or + * clear WL_RADIO_COUNTRY_DISABLE. + */ + if (chan == INVCHANNEL) { + /* + * country/locale with no valid channels, set + * the radio disable bit + */ + mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); + wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" " + "nbands %d bandlocked %d\n", wlc->pub->unit, + __func__, wlc_cm->country_abbrev, wlc->pub->_nbands, + wlc->bandlocked); + } else if (mboolisset(wlc->pub->radio_disabled, + WL_RADIO_COUNTRY_DISABLE)) { + /* + * country/locale with valid channel, clear + * the radio disable bit + */ + mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); + } + + /* + * Now that the country abbreviation is set, if the radio supports 2G, + * then set channel 14 restrictions based on the new locale. + */ + if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G) + wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi, + brcms_c_japan(wlc) ? true : + false); + + if (wlc->pub->up && chan != INVCHANNEL) { + brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr); + brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm, + &txpwr, BRCMS_TXPWR_MAX); + wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec); + } +} + +static int +brcms_c_channels_init(struct brcms_cm_info *wlc_cm, + const struct country_info *country) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + uint i, j; + struct brcms_band *band; + const struct locale_info *li; + struct brcms_chanvec sup_chan; + const struct locale_mimo_info *li_mimo; + + band = wlc->band; + for (i = 0; i < wlc->pub->_nbands; + i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) { + + li = (band->bandtype == BRCM_BAND_5G) ? + brcms_c_get_locale_5g(country->locale_5G) : + brcms_c_get_locale_2g(country->locale_2G); + wlc_cm->bandstate[band->bandunit].locale_flags = li->flags; + li_mimo = (band->bandtype == BRCM_BAND_5G) ? + brcms_c_get_mimo_5g(country->locale_mimo_5G) : + brcms_c_get_mimo_2g(country->locale_mimo_2G); + + /* merge the mimo non-mimo locale flags */ + wlc_cm->bandstate[band->bandunit].locale_flags |= + li_mimo->flags; + + wlc_cm->bandstate[band->bandunit].restricted_channels = + g_table_restricted_chan[li->restricted_channels]; + wlc_cm->bandstate[band->bandunit].radar_channels = + g_table_radar_set[li->radar_channels]; + + /* + * set the channel availability, masking out the channels + * that may not be supported on this phy. + */ + wlc_phy_chanspec_band_validch(band->pi, band->bandtype, + &sup_chan); + brcms_c_locale_get_channels(li, + &wlc_cm->bandstate[band->bandunit]. + valid_channels); + for (j = 0; j < sizeof(struct brcms_chanvec); j++) + wlc_cm->bandstate[band->bandunit].valid_channels. + vec[j] &= sup_chan.vec[j]; + } + + brcms_c_quiet_channels_reset(wlc_cm); + brcms_c_channels_commit(wlc_cm); + + return 0; +} + +/* + * set the driver's current country and regulatory information + * using a country code as the source. Look up built in country + * information found with the country code. + */ +static void +brcms_c_set_country_common(struct brcms_cm_info *wlc_cm, + const char *country_abbrev, + const char *ccode, uint regrev, + const struct country_info *country) +{ + const struct locale_info *locale; + struct brcms_c_info *wlc = wlc_cm->wlc; + char prev_country_abbrev[BRCM_CNTRY_BUF_SZ]; + + /* save current country state */ + wlc_cm->country = country; + + memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ); + strncpy(prev_country_abbrev, wlc_cm->country_abbrev, + BRCM_CNTRY_BUF_SZ - 1); + + strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1); + strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1); + wlc_cm->regrev = regrev; + + if ((wlc->pub->_n_enab & SUPPORT_11N) != + wlc->protection->nmode_user) + brcms_c_set_nmode(wlc); + + brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); + brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); + /* set or restore gmode as required by regulatory */ + locale = brcms_c_get_locale_2g(country->locale_2G); + if (locale && (locale->flags & BRCMS_NO_OFDM)) + brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false); + else + brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); + + brcms_c_channels_init(wlc_cm, country); + + return; +} + +static int +brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm, + const char *country_abbrev, + const char *ccode, int regrev) +{ + const struct country_info *country; + char mapped_ccode[BRCM_CNTRY_BUF_SZ]; + uint mapped_regrev; + + /* if regrev is -1, lookup the mapped country code, + * otherwise use the ccode and regrev directly + */ + if (regrev == -1) { + /* + * map the country code to a built-in country + * code, regrev, and country_info + */ + country = + brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode, + &mapped_regrev); + } else { + /* find the matching built-in country definition */ + country = brcms_c_country_lookup_direct(ccode, regrev); + strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ); + mapped_regrev = regrev; + } + + if (country == NULL) + return -EINVAL; + + /* set the driver state for the country */ + brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode, + mapped_regrev, country); + + return 0; +} + +/* + * set the driver's current country and regulatory information using + * a country code as the source. Lookup built in country information + * found with the country code. + */ +static int +brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode) +{ + char country_abbrev[BRCM_CNTRY_BUF_SZ]; + strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ); + return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1); +} + +struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) +{ + struct brcms_cm_info *wlc_cm; + char country_abbrev[BRCM_CNTRY_BUF_SZ]; + const struct country_info *country; + struct brcms_pub *pub = wlc->pub; + char *ccode; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + + wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC); + if (wlc_cm == NULL) + return NULL; + wlc_cm->pub = pub; + wlc_cm->wlc = wlc; + wlc->cmi = wlc_cm; + + /* store the country code for passing up as a regulatory hint */ + ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE); + if (ccode) + strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1); + + /* + * internal country information which must match + * regulatory constraints in firmware + */ + memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ); + strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1); + country = brcms_c_country_lookup(wlc, country_abbrev); + + /* save default country for exiting 11d regulatory mode */ + strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1); + + /* initialize autocountry_default to driver default */ + strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1); + + brcms_c_set_countrycode(wlc_cm, country_abbrev); + + return wlc_cm; +} + +void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm) +{ + kfree(wlc_cm); +} + +u8 +brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm, + uint bandunit) +{ + return wlc_cm->bandstate[bandunit].locale_flags; +} + +static bool +brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec) +{ + return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) && + CHSPEC_IS40(chspec) ? + (isset(wlc_cm->quiet_channels.vec, + lower_20_sb(CHSPEC_CHANNEL(chspec))) || + isset(wlc_cm->quiet_channels.vec, + upper_20_sb(CHSPEC_CHANNEL(chspec)))) : + isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec)); +} + +void +brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, + u8 local_constraint_qdbm) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + struct txpwr_limits txpwr; + + brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr); + + brcms_c_channel_min_txpower_limits_with_local_constraint( + wlc_cm, &txpwr, local_constraint_qdbm + ); + + brcms_b_set_chanspec(wlc->hw, chanspec, + (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0), + &txpwr); +} + +#ifdef POWER_DBG +static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr) +{ + int i; + char buf[80]; + char fraction[4][4] = { " ", ".25", ".5 ", ".75" }; + + sprintf(buf, "CCK "); + for (i = 0; i < BRCMS_NUM_RATES_CCK; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "20 MHz OFDM SISO "); + for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "20 MHz OFDM CDD "); + for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "40 MHz OFDM SISO "); + for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->ofdm_40_siso[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "40 MHz OFDM CDD "); + for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->ofdm_40_cdd[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "20 MHz MCS0-7 SISO "); + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs_20_siso[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "20 MHz MCS0-7 CDD "); + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs_20_cdd[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "20 MHz MCS0-7 STBC "); + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs_20_stbc[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "20 MHz MCS8-15 SDM "); + for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs_20_mimo[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "40 MHz MCS0-7 SISO "); + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs_40_siso[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "40 MHz MCS0-7 CDD "); + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs_40_cdd[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "40 MHz MCS0-7 STBC "); + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs_40_stbc[i] % + BRCMS_TXPWR_DB_FACTOR]); + printk(KERN_DEBUG "%s\n", buf); + + sprintf(buf, "40 MHz MCS8-15 SDM "); + for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) + sprintf(buf[strlen(buf)], " %2d%s", + txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs_40_mimo[i] % + BRCMS_TXPWR_DB_FACTOR]); + } + printk(KERN_DEBUG "%s\n", buf); + + printk(KERN_DEBUG "MCS32 %2d%s\n", + txpwr->mcs32 / BRCMS_TXPWR_DB_FACTOR, + fraction[txpwr->mcs32 % BRCMS_TXPWR_DB_FACTOR]); +} +#endif /* POWER_DBG */ + +void +brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, + struct txpwr_limits *txpwr) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + uint i; + uint chan; + int maxpwr; + int delta; + const struct country_info *country; + struct brcms_band *band; + const struct locale_info *li; + int conducted_max = BRCMS_TXPWR_MAX; + int conducted_ofdm_max = BRCMS_TXPWR_MAX; + const struct locale_mimo_info *li_mimo; + int maxpwr20, maxpwr40; + int maxpwr_idx; + uint j; + + memset(txpwr, 0, sizeof(struct txpwr_limits)); + + if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) { + country = brcms_c_country_lookup(wlc, wlc->autocountry_default); + if (country == NULL) + return; + } else { + country = wlc_cm->country; + } + + chan = CHSPEC_CHANNEL(chanspec); + band = wlc->bandstate[chspec_bandunit(chanspec)]; + li = (band->bandtype == BRCM_BAND_5G) ? + brcms_c_get_locale_5g(country->locale_5G) : + brcms_c_get_locale_2g(country->locale_2G); + + li_mimo = (band->bandtype == BRCM_BAND_5G) ? + brcms_c_get_mimo_5g(country->locale_mimo_5G) : + brcms_c_get_mimo_2g(country->locale_mimo_2G); + + if (li->flags & BRCMS_EIRP) { + delta = band->antgain; + } else { + delta = 0; + if (band->antgain > QDB(6)) + delta = band->antgain - QDB(6); /* Excess over 6 dB */ + } + + if (li == &locale_i) { + conducted_max = QDB(22); + conducted_ofdm_max = QDB(22); + } + + /* CCK txpwr limits for 2.4G band */ + if (band->bandtype == BRCM_BAND_2G) { + maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)]; + + maxpwr = maxpwr - delta; + maxpwr = max(maxpwr, 0); + maxpwr = min(maxpwr, conducted_max); + + for (i = 0; i < BRCMS_NUM_RATES_CCK; i++) + txpwr->cck[i] = (u8) maxpwr; + } + + /* OFDM txpwr limits for 2.4G or 5G bands */ + if (band->bandtype == BRCM_BAND_2G) + maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)]; + else + maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)]; + + maxpwr = maxpwr - delta; + maxpwr = max(maxpwr, 0); + maxpwr = min(maxpwr, conducted_ofdm_max); + + /* Keep OFDM lmit below CCK limit */ + if (band->bandtype == BRCM_BAND_2G) + maxpwr = min_t(int, maxpwr, txpwr->cck[0]); + + for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) + txpwr->ofdm[i] = (u8) maxpwr; + + for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) { + /* + * OFDM 40 MHz SISO has the same power as the corresponding + * MCS0-7 rate unless overriden by the locale specific code. + * We set this value to 0 as a flag (presumably 0 dBm isn't + * a possibility) and then copy the MCS0-7 value to the 40 MHz + * value if it wasn't explicitly set. + */ + txpwr->ofdm_40_siso[i] = 0; + + txpwr->ofdm_cdd[i] = (u8) maxpwr; + + txpwr->ofdm_40_cdd[i] = 0; + } + + /* MIMO/HT specific limits */ + if (li_mimo->flags & BRCMS_EIRP) { + delta = band->antgain; + } else { + delta = 0; + if (band->antgain > QDB(6)) + delta = band->antgain - QDB(6); /* Excess over 6 dB */ + } + + if (band->bandtype == BRCM_BAND_2G) + maxpwr_idx = (chan - 1); + else + maxpwr_idx = CHANNEL_POWER_IDX_5G(chan); + + maxpwr20 = li_mimo->maxpwr20[maxpwr_idx]; + maxpwr40 = li_mimo->maxpwr40[maxpwr_idx]; + + maxpwr20 = maxpwr20 - delta; + maxpwr20 = max(maxpwr20, 0); + maxpwr40 = maxpwr40 - delta; + maxpwr40 = max(maxpwr40, 0); + + /* Fill in the MCS 0-7 (SISO) rates */ + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { + + /* + * 20 MHz has the same power as the corresponding OFDM rate + * unless overriden by the locale specific code. + */ + txpwr->mcs_20_siso[i] = txpwr->ofdm[i]; + txpwr->mcs_40_siso[i] = 0; + } + + /* Fill in the MCS 0-7 CDD rates */ + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { + txpwr->mcs_20_cdd[i] = (u8) maxpwr20; + txpwr->mcs_40_cdd[i] = (u8) maxpwr40; + } + + /* + * These locales have SISO expressed in the + * table and override CDD later + */ + if (li_mimo == &locale_bn) { + if (li_mimo == &locale_bn) { + maxpwr20 = QDB(16); + maxpwr40 = 0; + + if (chan >= 3 && chan <= 11) + maxpwr40 = QDB(16); + } + + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { + txpwr->mcs_20_siso[i] = (u8) maxpwr20; + txpwr->mcs_40_siso[i] = (u8) maxpwr40; + } + } + + /* Fill in the MCS 0-7 STBC rates */ + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { + txpwr->mcs_20_stbc[i] = 0; + txpwr->mcs_40_stbc[i] = 0; + } + + /* Fill in the MCS 8-15 SDM rates */ + for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++) { + txpwr->mcs_20_mimo[i] = (u8) maxpwr20; + txpwr->mcs_40_mimo[i] = (u8) maxpwr40; + } + + /* Fill in MCS32 */ + txpwr->mcs32 = (u8) maxpwr40; + + for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) { + if (txpwr->ofdm_40_cdd[i] == 0) + txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j]; + if (i == 0) { + i = i + 1; + if (txpwr->ofdm_40_cdd[i] == 0) + txpwr->ofdm_40_cdd[i] = txpwr->mcs_40_cdd[j]; + } + } + + /* + * Copy the 40 MHZ MCS 0-7 CDD value to the 40 MHZ MCS 0-7 SISO + * value if it wasn't provided explicitly. + */ + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { + if (txpwr->mcs_40_siso[i] == 0) + txpwr->mcs_40_siso[i] = txpwr->mcs_40_cdd[i]; + } + + for (i = 0, j = 0; i < BRCMS_NUM_RATES_OFDM; i++, j++) { + if (txpwr->ofdm_40_siso[i] == 0) + txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j]; + if (i == 0) { + i = i + 1; + if (txpwr->ofdm_40_siso[i] == 0) + txpwr->ofdm_40_siso[i] = txpwr->mcs_40_siso[j]; + } + } + + /* + * Copy the 20 and 40 MHz MCS0-7 CDD values to the corresponding + * STBC values if they weren't provided explicitly. + */ + for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++) { + if (txpwr->mcs_20_stbc[i] == 0) + txpwr->mcs_20_stbc[i] = txpwr->mcs_20_cdd[i]; + + if (txpwr->mcs_40_stbc[i] == 0) + txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i]; + } + +#ifdef POWER_DBG + wlc_phy_txpower_limits_dump(txpwr); +#endif + return; +} + +/* + * Verify the chanspec is using a legal set of parameters, i.e. that the + * chanspec specified a band, bw, ctl_sb and channel and that the + * combination could be legal given any set of circumstances. + * RETURNS: true is the chanspec is malformed, false if it looks good. + */ +static bool brcms_c_chspec_malformed(u16 chanspec) +{ + /* must be 2G or 5G band */ + if (!CHSPEC_IS5G(chanspec) && !CHSPEC_IS2G(chanspec)) + return true; + /* must be 20 or 40 bandwidth */ + if (!CHSPEC_IS40(chanspec) && !CHSPEC_IS20(chanspec)) + return true; + + /* 20MHZ b/w must have no ctl sb, 40 must have a ctl sb */ + if (CHSPEC_IS20(chanspec)) { + if (!CHSPEC_SB_NONE(chanspec)) + return true; + } else if (!CHSPEC_SB_UPPER(chanspec) && !CHSPEC_SB_LOWER(chanspec)) { + return true; + } + + return false; +} + +/* + * Validate the chanspec for this locale, for 40MHZ we need to also + * check that the sidebands are valid 20MZH channels in this locale + * and they are also a legal HT combination + */ +static bool +brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec, + bool dualband) +{ + struct brcms_c_info *wlc = wlc_cm->wlc; + u8 channel = CHSPEC_CHANNEL(chspec); + + /* check the chanspec */ + if (brcms_c_chspec_malformed(chspec)) { + wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n", + wlc->pub->unit, chspec); + return false; + } + + if (CHANNEL_BANDUNIT(wlc_cm->wlc, channel) != + chspec_bandunit(chspec)) + return false; + + /* Check a 20Mhz channel */ + if (CHSPEC_IS20(chspec)) { + if (dualband) + return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi, + channel); + else + return brcms_c_valid_channel20(wlc_cm->wlc->cmi, + channel); + } +#ifdef SUPPORT_40MHZ + /* + * We know we are now checking a 40MHZ channel, so we should + * only be here for NPHYS + */ + if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) { + u8 upper_sideband = 0, idx; + u8 num_ch20_entries = + sizeof(chan20_info) / sizeof(struct chan20_info); + + if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec))) + return false; + + if (dualband) { + if (!brcms_c_valid_channel20_db(wlc->cmi, + lower_20_sb(channel)) || + !brcms_c_valid_channel20_db(wlc->cmi, + upper_20_sb(channel))) + return false; + } else { + if (!brcms_c_valid_channel20(wlc->cmi, + lower_20_sb(channel)) || + !brcms_c_valid_channel20(wlc->cmi, + upper_20_sb(channel))) + return false; + } + + /* find the lower sideband info in the sideband array */ + for (idx = 0; idx < num_ch20_entries; idx++) { + if (chan20_info[idx].sb == lower_20_sb(channel)) + upper_sideband = chan20_info[idx].adj_sbs; + } + /* check that the lower sideband allows an upper sideband */ + if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) == + (CH_UPPER_SB | CH_EWA_VALID)) + return true; + return false; + } +#endif /* 40 MHZ */ + + return false; +} + +bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec) +{ + return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true); +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.h b/drivers/net/wireless/brcm80211/brcmsmac/channel.h new file mode 100644 index 000000000000..808cb4fbfbe7 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_CHANNEL_H_ +#define _BRCM_CHANNEL_H_ + +/* conversion for phy txpwr calculations that use .25 dB units */ +#define BRCMS_TXPWR_DB_FACTOR 4 + +/* bits for locale_info flags */ +#define BRCMS_PEAK_CONDUCTED 0x00 /* Peak for locals */ +#define BRCMS_EIRP 0x01 /* Flag for EIRP */ +#define BRCMS_DFS_TPC 0x02 /* Flag for DFS TPC */ +#define BRCMS_NO_OFDM 0x04 /* Flag for No OFDM */ +#define BRCMS_NO_40MHZ 0x08 /* Flag for No MIMO 40MHz */ +#define BRCMS_NO_MIMO 0x10 /* Flag for No MIMO, 20 or 40 MHz */ +#define BRCMS_RADAR_TYPE_EU 0x20 /* Flag for EU */ +#define BRCMS_DFS_FCC BRCMS_DFS_TPC /* Flag for DFS FCC */ + +#define BRCMS_DFS_EU (BRCMS_DFS_TPC | BRCMS_RADAR_TYPE_EU) /* Flag for DFS EU */ + +extern struct brcms_cm_info * +brcms_c_channel_mgr_attach(struct brcms_c_info *wlc); + +extern void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm); + +extern u8 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm, + uint bandunit); + +extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, + u16 chspec); + +extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, + u16 chanspec, + struct txpwr_limits *txpwr); +extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, + u16 chanspec, + u8 local_constraint_qdbm); + +#endif /* _WLC_CHANNEL_H */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/d11.h b/drivers/net/wireless/brcm80211/brcmsmac/d11.h new file mode 100644 index 000000000000..ed51616abc85 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/d11.h @@ -0,0 +1,1898 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_D11_H_ +#define _BRCM_D11_H_ + +#include <linux/ieee80211.h> + +#include <defs.h> +#include "pub.h" +#include "dma.h" + +/* RX FIFO numbers */ +#define RX_FIFO 0 /* data and ctl frames */ +#define RX_TXSTATUS_FIFO 3 /* RX fifo for tx status packages */ + +/* TX FIFO numbers using WME Access Category */ +#define TX_AC_BK_FIFO 0 /* Background TX FIFO */ +#define TX_AC_BE_FIFO 1 /* Best-Effort TX FIFO */ +#define TX_AC_VI_FIFO 2 /* Video TX FIFO */ +#define TX_AC_VO_FIFO 3 /* Voice TX FIFO */ +#define TX_BCMC_FIFO 4 /* Broadcast/Multicast TX FIFO */ +#define TX_ATIM_FIFO 5 /* TX fifo for ATIM window info */ + +/* Addr is byte address used by SW; offset is word offset used by uCode */ + +/* Per AC TX limit settings */ +#define M_AC_TXLMT_BASE_ADDR (0x180 * 2) +#define M_AC_TXLMT_ADDR(_ac) (M_AC_TXLMT_BASE_ADDR + (2 * (_ac))) + +/* Legacy TX FIFO numbers */ +#define TX_DATA_FIFO TX_AC_BE_FIFO +#define TX_CTL_FIFO TX_AC_VO_FIFO + +#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ + +struct intctrlregs { + u32 intstatus; + u32 intmask; +}; + +/* PIO structure, + * support two PIO format: 2 bytes access and 4 bytes access + * basic FIFO register set is per channel(transmit or receive) + * a pair of channels is defined for convenience + */ +/* 2byte-wide pio register set per channel(xmt or rcv) */ +struct pio2regs { + u16 fifocontrol; + u16 fifodata; + u16 fifofree; /* only valid in xmt channel, not in rcv channel */ + u16 PAD; +}; + +/* a pair of pio channels(tx and rx) */ +struct pio2regp { + struct pio2regs tx; + struct pio2regs rx; +}; + +/* 4byte-wide pio register set per channel(xmt or rcv) */ +struct pio4regs { + u32 fifocontrol; + u32 fifodata; +}; + +/* a pair of pio channels(tx and rx) */ +struct pio4regp { + struct pio4regs tx; + struct pio4regs rx; +}; + +/* read: 32-bit register that can be read as 32-bit or as 2 16-bit + * write: only low 16b-it half can be written + */ +union pmqreg { + u32 pmqhostdata; /* read only! */ + struct { + u16 pmqctrlstatus; /* read/write */ + u16 PAD; + } w; +}; + +struct fifo64 { + struct dma64regs dmaxmt; /* dma tx */ + struct pio4regs piotx; /* pio tx */ + struct dma64regs dmarcv; /* dma rx */ + struct pio4regs piorx; /* pio rx */ +}; + +/* + * Host Interface Registers + */ +struct d11regs { + /* Device Control ("semi-standard host registers") */ + u32 PAD[3]; /* 0x0 - 0x8 */ + u32 biststatus; /* 0xC */ + u32 biststatus2; /* 0x10 */ + u32 PAD; /* 0x14 */ + u32 gptimer; /* 0x18 */ + u32 usectimer; /* 0x1c *//* for corerev >= 26 */ + + /* Interrupt Control *//* 0x20 */ + struct intctrlregs intctrlregs[8]; + + u32 PAD[40]; /* 0x60 - 0xFC */ + + u32 intrcvlazy[4]; /* 0x100 - 0x10C */ + + u32 PAD[4]; /* 0x110 - 0x11c */ + + u32 maccontrol; /* 0x120 */ + u32 maccommand; /* 0x124 */ + u32 macintstatus; /* 0x128 */ + u32 macintmask; /* 0x12C */ + + /* Transmit Template Access */ + u32 tplatewrptr; /* 0x130 */ + u32 tplatewrdata; /* 0x134 */ + u32 PAD[2]; /* 0x138 - 0x13C */ + + /* PMQ registers */ + union pmqreg pmqreg; /* 0x140 */ + u32 pmqpatl; /* 0x144 */ + u32 pmqpath; /* 0x148 */ + u32 PAD; /* 0x14C */ + + u32 chnstatus; /* 0x150 */ + u32 psmdebug; /* 0x154 */ + u32 phydebug; /* 0x158 */ + u32 machwcap; /* 0x15C */ + + /* Extended Internal Objects */ + u32 objaddr; /* 0x160 */ + u32 objdata; /* 0x164 */ + u32 PAD[2]; /* 0x168 - 0x16c */ + + u32 frmtxstatus; /* 0x170 */ + u32 frmtxstatus2; /* 0x174 */ + u32 PAD[2]; /* 0x178 - 0x17c */ + + /* TSF host access */ + u32 tsf_timerlow; /* 0x180 */ + u32 tsf_timerhigh; /* 0x184 */ + u32 tsf_cfprep; /* 0x188 */ + u32 tsf_cfpstart; /* 0x18c */ + u32 tsf_cfpmaxdur32; /* 0x190 */ + u32 PAD[3]; /* 0x194 - 0x19c */ + + u32 maccontrol1; /* 0x1a0 */ + u32 machwcap1; /* 0x1a4 */ + u32 PAD[14]; /* 0x1a8 - 0x1dc */ + + /* Clock control and hardware workarounds*/ + u32 clk_ctl_st; /* 0x1e0 */ + u32 hw_war; + u32 d11_phypllctl; /* the phypll request/avail bits are + * moved to clk_ctl_st + */ + u32 PAD[5]; /* 0x1ec - 0x1fc */ + + /* 0x200-0x37F dma/pio registers */ + struct fifo64 fifo64regs[6]; + + /* FIFO diagnostic port access */ + struct dma32diag dmafifo; /* 0x380 - 0x38C */ + + u32 aggfifocnt; /* 0x390 */ + u32 aggfifodata; /* 0x394 */ + u32 PAD[16]; /* 0x398 - 0x3d4 */ + u16 radioregaddr; /* 0x3d8 */ + u16 radioregdata; /* 0x3da */ + + /* + * time delay between the change on rf disable input and + * radio shutdown + */ + u32 rfdisabledly; /* 0x3DC */ + + /* PHY register access */ + u16 phyversion; /* 0x3e0 - 0x0 */ + u16 phybbconfig; /* 0x3e2 - 0x1 */ + u16 phyadcbias; /* 0x3e4 - 0x2 Bphy only */ + u16 phyanacore; /* 0x3e6 - 0x3 pwwrdwn on aphy */ + u16 phyrxstatus0; /* 0x3e8 - 0x4 */ + u16 phyrxstatus1; /* 0x3ea - 0x5 */ + u16 phycrsth; /* 0x3ec - 0x6 */ + u16 phytxerror; /* 0x3ee - 0x7 */ + u16 phychannel; /* 0x3f0 - 0x8 */ + u16 PAD[1]; /* 0x3f2 - 0x9 */ + u16 phytest; /* 0x3f4 - 0xa */ + u16 phy4waddr; /* 0x3f6 - 0xb */ + u16 phy4wdatahi; /* 0x3f8 - 0xc */ + u16 phy4wdatalo; /* 0x3fa - 0xd */ + u16 phyregaddr; /* 0x3fc - 0xe */ + u16 phyregdata; /* 0x3fe - 0xf */ + + /* IHR *//* 0x400 - 0x7FE */ + + /* RXE Block */ + u16 PAD[3]; /* 0x400 - 0x406 */ + u16 rcv_fifo_ctl; /* 0x406 */ + u16 PAD; /* 0x408 - 0x40a */ + u16 rcv_frm_cnt; /* 0x40a */ + u16 PAD[4]; /* 0x40a - 0x414 */ + u16 rssi; /* 0x414 */ + u16 PAD[5]; /* 0x414 - 0x420 */ + u16 rcm_ctl; /* 0x420 */ + u16 rcm_mat_data; /* 0x422 */ + u16 rcm_mat_mask; /* 0x424 */ + u16 rcm_mat_dly; /* 0x426 */ + u16 rcm_cond_mask_l; /* 0x428 */ + u16 rcm_cond_mask_h; /* 0x42A */ + u16 rcm_cond_dly; /* 0x42C */ + u16 PAD[1]; /* 0x42E */ + u16 ext_ihr_addr; /* 0x430 */ + u16 ext_ihr_data; /* 0x432 */ + u16 rxe_phyrs_2; /* 0x434 */ + u16 rxe_phyrs_3; /* 0x436 */ + u16 phy_mode; /* 0x438 */ + u16 rcmta_ctl; /* 0x43a */ + u16 rcmta_size; /* 0x43c */ + u16 rcmta_addr0; /* 0x43e */ + u16 rcmta_addr1; /* 0x440 */ + u16 rcmta_addr2; /* 0x442 */ + u16 PAD[30]; /* 0x444 - 0x480 */ + + /* PSM Block *//* 0x480 - 0x500 */ + + u16 PAD; /* 0x480 */ + u16 psm_maccontrol_h; /* 0x482 */ + u16 psm_macintstatus_l; /* 0x484 */ + u16 psm_macintstatus_h; /* 0x486 */ + u16 psm_macintmask_l; /* 0x488 */ + u16 psm_macintmask_h; /* 0x48A */ + u16 PAD; /* 0x48C */ + u16 psm_maccommand; /* 0x48E */ + u16 psm_brc; /* 0x490 */ + u16 psm_phy_hdr_param; /* 0x492 */ + u16 psm_postcard; /* 0x494 */ + u16 psm_pcard_loc_l; /* 0x496 */ + u16 psm_pcard_loc_h; /* 0x498 */ + u16 psm_gpio_in; /* 0x49A */ + u16 psm_gpio_out; /* 0x49C */ + u16 psm_gpio_oe; /* 0x49E */ + + u16 psm_bred_0; /* 0x4A0 */ + u16 psm_bred_1; /* 0x4A2 */ + u16 psm_bred_2; /* 0x4A4 */ + u16 psm_bred_3; /* 0x4A6 */ + u16 psm_brcl_0; /* 0x4A8 */ + u16 psm_brcl_1; /* 0x4AA */ + u16 psm_brcl_2; /* 0x4AC */ + u16 psm_brcl_3; /* 0x4AE */ + u16 psm_brpo_0; /* 0x4B0 */ + u16 psm_brpo_1; /* 0x4B2 */ + u16 psm_brpo_2; /* 0x4B4 */ + u16 psm_brpo_3; /* 0x4B6 */ + u16 psm_brwk_0; /* 0x4B8 */ + u16 psm_brwk_1; /* 0x4BA */ + u16 psm_brwk_2; /* 0x4BC */ + u16 psm_brwk_3; /* 0x4BE */ + + u16 psm_base_0; /* 0x4C0 */ + u16 psm_base_1; /* 0x4C2 */ + u16 psm_base_2; /* 0x4C4 */ + u16 psm_base_3; /* 0x4C6 */ + u16 psm_base_4; /* 0x4C8 */ + u16 psm_base_5; /* 0x4CA */ + u16 psm_base_6; /* 0x4CC */ + u16 psm_pc_reg_0; /* 0x4CE */ + u16 psm_pc_reg_1; /* 0x4D0 */ + u16 psm_pc_reg_2; /* 0x4D2 */ + u16 psm_pc_reg_3; /* 0x4D4 */ + u16 PAD[0xD]; /* 0x4D6 - 0x4DE */ + u16 psm_corectlsts; /* 0x4f0 *//* Corerev >= 13 */ + u16 PAD[0x7]; /* 0x4f2 - 0x4fE */ + + /* TXE0 Block *//* 0x500 - 0x580 */ + u16 txe_ctl; /* 0x500 */ + u16 txe_aux; /* 0x502 */ + u16 txe_ts_loc; /* 0x504 */ + u16 txe_time_out; /* 0x506 */ + u16 txe_wm_0; /* 0x508 */ + u16 txe_wm_1; /* 0x50A */ + u16 txe_phyctl; /* 0x50C */ + u16 txe_status; /* 0x50E */ + u16 txe_mmplcp0; /* 0x510 */ + u16 txe_mmplcp1; /* 0x512 */ + u16 txe_phyctl1; /* 0x514 */ + + u16 PAD[0x05]; /* 0x510 - 0x51E */ + + /* Transmit control */ + u16 xmtfifodef; /* 0x520 */ + u16 xmtfifo_frame_cnt; /* 0x522 *//* Corerev >= 16 */ + u16 xmtfifo_byte_cnt; /* 0x524 *//* Corerev >= 16 */ + u16 xmtfifo_head; /* 0x526 *//* Corerev >= 16 */ + u16 xmtfifo_rd_ptr; /* 0x528 *//* Corerev >= 16 */ + u16 xmtfifo_wr_ptr; /* 0x52A *//* Corerev >= 16 */ + u16 xmtfifodef1; /* 0x52C *//* Corerev >= 16 */ + + u16 PAD[0x09]; /* 0x52E - 0x53E */ + + u16 xmtfifocmd; /* 0x540 */ + u16 xmtfifoflush; /* 0x542 */ + u16 xmtfifothresh; /* 0x544 */ + u16 xmtfifordy; /* 0x546 */ + u16 xmtfifoprirdy; /* 0x548 */ + u16 xmtfiforqpri; /* 0x54A */ + u16 xmttplatetxptr; /* 0x54C */ + u16 PAD; /* 0x54E */ + u16 xmttplateptr; /* 0x550 */ + u16 smpl_clct_strptr; /* 0x552 *//* Corerev >= 22 */ + u16 smpl_clct_stpptr; /* 0x554 *//* Corerev >= 22 */ + u16 smpl_clct_curptr; /* 0x556 *//* Corerev >= 22 */ + u16 PAD[0x04]; /* 0x558 - 0x55E */ + u16 xmttplatedatalo; /* 0x560 */ + u16 xmttplatedatahi; /* 0x562 */ + + u16 PAD[2]; /* 0x564 - 0x566 */ + + u16 xmtsel; /* 0x568 */ + u16 xmttxcnt; /* 0x56A */ + u16 xmttxshmaddr; /* 0x56C */ + + u16 PAD[0x09]; /* 0x56E - 0x57E */ + + /* TXE1 Block */ + u16 PAD[0x40]; /* 0x580 - 0x5FE */ + + /* TSF Block */ + u16 PAD[0X02]; /* 0x600 - 0x602 */ + u16 tsf_cfpstrt_l; /* 0x604 */ + u16 tsf_cfpstrt_h; /* 0x606 */ + u16 PAD[0X05]; /* 0x608 - 0x610 */ + u16 tsf_cfppretbtt; /* 0x612 */ + u16 PAD[0XD]; /* 0x614 - 0x62C */ + u16 tsf_clk_frac_l; /* 0x62E */ + u16 tsf_clk_frac_h; /* 0x630 */ + u16 PAD[0X14]; /* 0x632 - 0x658 */ + u16 tsf_random; /* 0x65A */ + u16 PAD[0x05]; /* 0x65C - 0x664 */ + /* GPTimer 2 registers */ + u16 tsf_gpt2_stat; /* 0x666 */ + u16 tsf_gpt2_ctr_l; /* 0x668 */ + u16 tsf_gpt2_ctr_h; /* 0x66A */ + u16 tsf_gpt2_val_l; /* 0x66C */ + u16 tsf_gpt2_val_h; /* 0x66E */ + u16 tsf_gptall_stat; /* 0x670 */ + u16 PAD[0x07]; /* 0x672 - 0x67E */ + + /* IFS Block */ + u16 ifs_sifs_rx_tx_tx; /* 0x680 */ + u16 ifs_sifs_nav_tx; /* 0x682 */ + u16 ifs_slot; /* 0x684 */ + u16 PAD; /* 0x686 */ + u16 ifs_ctl; /* 0x688 */ + u16 PAD[0x3]; /* 0x68a - 0x68F */ + u16 ifsstat; /* 0x690 */ + u16 ifsmedbusyctl; /* 0x692 */ + u16 iftxdur; /* 0x694 */ + u16 PAD[0x3]; /* 0x696 - 0x69b */ + /* EDCF support in dot11macs */ + u16 ifs_aifsn; /* 0x69c */ + u16 ifs_ctl1; /* 0x69e */ + + /* slow clock registers */ + u16 scc_ctl; /* 0x6a0 */ + u16 scc_timer_l; /* 0x6a2 */ + u16 scc_timer_h; /* 0x6a4 */ + u16 scc_frac; /* 0x6a6 */ + u16 scc_fastpwrup_dly; /* 0x6a8 */ + u16 scc_per; /* 0x6aa */ + u16 scc_per_frac; /* 0x6ac */ + u16 scc_cal_timer_l; /* 0x6ae */ + u16 scc_cal_timer_h; /* 0x6b0 */ + u16 PAD; /* 0x6b2 */ + + u16 PAD[0x26]; + + /* NAV Block */ + u16 nav_ctl; /* 0x700 */ + u16 navstat; /* 0x702 */ + u16 PAD[0x3e]; /* 0x702 - 0x77E */ + + /* WEP/PMQ Block *//* 0x780 - 0x7FE */ + u16 PAD[0x20]; /* 0x780 - 0x7BE */ + + u16 wepctl; /* 0x7C0 */ + u16 wepivloc; /* 0x7C2 */ + u16 wepivkey; /* 0x7C4 */ + u16 wepwkey; /* 0x7C6 */ + + u16 PAD[4]; /* 0x7C8 - 0x7CE */ + u16 pcmctl; /* 0X7D0 */ + u16 pcmstat; /* 0X7D2 */ + u16 PAD[6]; /* 0x7D4 - 0x7DE */ + + u16 pmqctl; /* 0x7E0 */ + u16 pmqstatus; /* 0x7E2 */ + u16 pmqpat0; /* 0x7E4 */ + u16 pmqpat1; /* 0x7E6 */ + u16 pmqpat2; /* 0x7E8 */ + + u16 pmqdat; /* 0x7EA */ + u16 pmqdator; /* 0x7EC */ + u16 pmqhst; /* 0x7EE */ + u16 pmqpath0; /* 0x7F0 */ + u16 pmqpath1; /* 0x7F2 */ + u16 pmqpath2; /* 0x7F4 */ + u16 pmqdath; /* 0x7F6 */ + + u16 PAD[0x04]; /* 0x7F8 - 0x7FE */ + + /* SHM *//* 0x800 - 0xEFE */ + u16 PAD[0x380]; /* 0x800 - 0xEFE */ +}; + +#define PIHR_BASE 0x0400 /* byte address of packed IHR region */ + +/* biststatus */ +#define BT_DONE (1U << 31) /* bist done */ +#define BT_B2S (1 << 30) /* bist2 ram summary bit */ + +/* intstatus and intmask */ +#define I_PC (1 << 10) /* pci descriptor error */ +#define I_PD (1 << 11) /* pci data error */ +#define I_DE (1 << 12) /* descriptor protocol error */ +#define I_RU (1 << 13) /* receive descriptor underflow */ +#define I_RO (1 << 14) /* receive fifo overflow */ +#define I_XU (1 << 15) /* transmit fifo underflow */ +#define I_RI (1 << 16) /* receive interrupt */ +#define I_XI (1 << 24) /* transmit interrupt */ + +/* interrupt receive lazy */ +#define IRL_TO_MASK 0x00ffffff /* timeout */ +#define IRL_FC_MASK 0xff000000 /* frame count */ +#define IRL_FC_SHIFT 24 /* frame count */ + +/*== maccontrol register ==*/ +#define MCTL_GMODE (1U << 31) +#define MCTL_DISCARD_PMQ (1 << 30) +#define MCTL_WAKE (1 << 26) +#define MCTL_HPS (1 << 25) +#define MCTL_PROMISC (1 << 24) +#define MCTL_KEEPBADFCS (1 << 23) +#define MCTL_KEEPCONTROL (1 << 22) +#define MCTL_PHYLOCK (1 << 21) +#define MCTL_BCNS_PROMISC (1 << 20) +#define MCTL_LOCK_RADIO (1 << 19) +#define MCTL_AP (1 << 18) +#define MCTL_INFRA (1 << 17) +#define MCTL_BIGEND (1 << 16) +#define MCTL_GPOUT_SEL_MASK (3 << 14) +#define MCTL_GPOUT_SEL_SHIFT 14 +#define MCTL_EN_PSMDBG (1 << 13) +#define MCTL_IHR_EN (1 << 10) +#define MCTL_SHM_UPPER (1 << 9) +#define MCTL_SHM_EN (1 << 8) +#define MCTL_PSM_JMP_0 (1 << 2) +#define MCTL_PSM_RUN (1 << 1) +#define MCTL_EN_MAC (1 << 0) + +/*== maccommand register ==*/ +#define MCMD_BCN0VLD (1 << 0) +#define MCMD_BCN1VLD (1 << 1) +#define MCMD_DIRFRMQVAL (1 << 2) +#define MCMD_CCA (1 << 3) +#define MCMD_BG_NOISE (1 << 4) +#define MCMD_SKIP_SHMINIT (1 << 5) /* only used for simulation */ +#define MCMD_SAMPLECOLL MCMD_SKIP_SHMINIT /* reuse for sample collect */ + +/*== macintstatus/macintmask ==*/ +/* gracefully suspended */ +#define MI_MACSSPNDD (1 << 0) +/* beacon template available */ +#define MI_BCNTPL (1 << 1) +/* TBTT indication */ +#define MI_TBTT (1 << 2) +/* beacon successfully tx'd */ +#define MI_BCNSUCCESS (1 << 3) +/* beacon canceled (IBSS) */ +#define MI_BCNCANCLD (1 << 4) +/* end of ATIM-window (IBSS) */ +#define MI_ATIMWINEND (1 << 5) +/* PMQ entries available */ +#define MI_PMQ (1 << 6) +/* non-specific gen-stat bits that are set by PSM */ +#define MI_NSPECGEN_0 (1 << 7) +/* non-specific gen-stat bits that are set by PSM */ +#define MI_NSPECGEN_1 (1 << 8) +/* MAC level Tx error */ +#define MI_MACTXERR (1 << 9) +/* non-specific gen-stat bits that are set by PSM */ +#define MI_NSPECGEN_3 (1 << 10) +/* PHY Tx error */ +#define MI_PHYTXERR (1 << 11) +/* Power Management Event */ +#define MI_PME (1 << 12) +/* General-purpose timer0 */ +#define MI_GP0 (1 << 13) +/* General-purpose timer1 */ +#define MI_GP1 (1 << 14) +/* (ORed) DMA-interrupts */ +#define MI_DMAINT (1 << 15) +/* MAC has completed a TX FIFO Suspend/Flush */ +#define MI_TXSTOP (1 << 16) +/* MAC has completed a CCA measurement */ +#define MI_CCA (1 << 17) +/* MAC has collected background noise samples */ +#define MI_BG_NOISE (1 << 18) +/* MBSS DTIM TBTT indication */ +#define MI_DTIM_TBTT (1 << 19) +/* Probe response queue needs attention */ +#define MI_PRQ (1 << 20) +/* Radio/PHY has been powered back up. */ +#define MI_PWRUP (1 << 21) +#define MI_RESERVED3 (1 << 22) +#define MI_RESERVED2 (1 << 23) +#define MI_RESERVED1 (1 << 25) +/* MAC detected change on RF Disable input*/ +#define MI_RFDISABLE (1 << 28) +/* MAC has completed a TX */ +#define MI_TFS (1 << 29) +/* A phy status change wrt G mode */ +#define MI_PHYCHANGED (1 << 30) +/* general purpose timeout */ +#define MI_TO (1U << 31) + +/* Mac capabilities registers */ +/*== machwcap ==*/ +#define MCAP_TKIPMIC 0x80000000 /* TKIP MIC hardware present */ + +/*== pmqhost data ==*/ +/* data entry of head pmq entry */ +#define PMQH_DATA_MASK 0xffff0000 +/* PM entry for BSS config */ +#define PMQH_BSSCFG 0x00100000 +/* PM Mode OFF: power save off */ +#define PMQH_PMOFF 0x00010000 +/* PM Mode ON: power save on */ +#define PMQH_PMON 0x00020000 +/* Dis-associated or De-authenticated */ +#define PMQH_DASAT 0x00040000 +/* ATIM not acknowledged */ +#define PMQH_ATIMFAIL 0x00080000 +/* delete head entry */ +#define PMQH_DEL_ENTRY 0x00000001 +/* delete head entry to cur read pointer -1 */ +#define PMQH_DEL_MULT 0x00000002 +/* pmq overflow indication */ +#define PMQH_OFLO 0x00000004 +/* entries are present in pmq */ +#define PMQH_NOT_EMPTY 0x00000008 + +/*== phydebug ==*/ +/* phy is asserting carrier sense */ +#define PDBG_CRS (1 << 0) +/* phy is taking xmit byte from mac this cycle */ +#define PDBG_TXA (1 << 1) +/* mac is instructing the phy to transmit a frame */ +#define PDBG_TXF (1 << 2) +/* phy is signalling a transmit Error to the mac */ +#define PDBG_TXE (1 << 3) +/* phy detected the end of a valid frame preamble */ +#define PDBG_RXF (1 << 4) +/* phy detected the end of a valid PLCP header */ +#define PDBG_RXS (1 << 5) +/* rx start not asserted */ +#define PDBG_RXFRG (1 << 6) +/* mac is taking receive byte from phy this cycle */ +#define PDBG_RXV (1 << 7) +/* RF portion of the radio is disabled */ +#define PDBG_RFD (1 << 16) + +/*== objaddr register ==*/ +#define OBJADDR_SEL_MASK 0x000F0000 +#define OBJADDR_UCM_SEL 0x00000000 +#define OBJADDR_SHM_SEL 0x00010000 +#define OBJADDR_SCR_SEL 0x00020000 +#define OBJADDR_IHR_SEL 0x00030000 +#define OBJADDR_RCMTA_SEL 0x00040000 +#define OBJADDR_SRCHM_SEL 0x00060000 +#define OBJADDR_WINC 0x01000000 +#define OBJADDR_RINC 0x02000000 +#define OBJADDR_AUTO_INC 0x03000000 + +#define WEP_PCMADDR 0x07d4 +#define WEP_PCMDATA 0x07d6 + +/*== frmtxstatus ==*/ +#define TXS_V (1 << 0) /* valid bit */ +#define TXS_STATUS_MASK 0xffff +#define TXS_FID_MASK 0xffff0000 +#define TXS_FID_SHIFT 16 + +/*== frmtxstatus2 ==*/ +#define TXS_SEQ_MASK 0xffff +#define TXS_PTX_MASK 0xff0000 +#define TXS_PTX_SHIFT 16 +#define TXS_MU_MASK 0x01000000 +#define TXS_MU_SHIFT 24 + +/*== clk_ctl_st ==*/ +#define CCS_ERSRC_REQ_D11PLL 0x00000100 /* d11 core pll request */ +#define CCS_ERSRC_REQ_PHYPLL 0x00000200 /* PHY pll request */ +#define CCS_ERSRC_AVAIL_D11PLL 0x01000000 /* d11 core pll available */ +#define CCS_ERSRC_AVAIL_PHYPLL 0x02000000 /* PHY pll available */ + +/* HT Cloclk Ctrl and Clock Avail for 4313 */ +#define CCS_ERSRC_REQ_HT 0x00000010 /* HT avail request */ +#define CCS_ERSRC_AVAIL_HT 0x00020000 /* HT clock available */ + +/* tsf_cfprep register */ +#define CFPREP_CBI_MASK 0xffffffc0 +#define CFPREP_CBI_SHIFT 6 +#define CFPREP_CFPP 0x00000001 + +/* tx fifo sizes values are in terms of 256 byte blocks */ +#define TXFIFOCMD_RESET_MASK (1 << 15) /* reset */ +#define TXFIFOCMD_FIFOSEL_SHIFT 8 /* fifo */ +#define TXFIFO_FIFOTOP_SHIFT 8 /* fifo start */ + +#define TXFIFO_START_BLK16 65 /* Base address + 32 * 512 B/P */ +#define TXFIFO_START_BLK 6 /* Base address + 6 * 256 B */ +#define TXFIFO_SIZE_UNIT 256 /* one unit corresponds to 256 bytes */ +#define MBSS16_TEMPLMEM_MINBLKS 65 /* one unit corresponds to 256 bytes */ + +/*== phy versions (PhyVersion:Revision field) ==*/ +/* analog block version */ +#define PV_AV_MASK 0xf000 +/* analog block version bitfield offset */ +#define PV_AV_SHIFT 12 +/* phy type */ +#define PV_PT_MASK 0x0f00 +/* phy type bitfield offset */ +#define PV_PT_SHIFT 8 +/* phy version */ +#define PV_PV_MASK 0x000f +#define PHY_TYPE(v) ((v & PV_PT_MASK) >> PV_PT_SHIFT) + +/*== phy types (PhyVersion:PhyType field) ==*/ +#define PHY_TYPE_N 4 /* N-Phy value */ +#define PHY_TYPE_SSN 6 /* SSLPN-Phy value */ +#define PHY_TYPE_LCN 8 /* LCN-Phy value */ +#define PHY_TYPE_LCNXN 9 /* LCNXN-Phy value */ +#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ + +/*== analog types (PhyVersion:AnalogType field) ==*/ +#define ANA_11N_013 5 + +/* 802.11a PLCP header def */ +struct ofdm_phy_hdr { + u8 rlpt[3]; /* rate, length, parity, tail */ + u16 service; + u8 pad; +} __packed; + +#define D11A_PHY_HDR_GRATE(phdr) ((phdr)->rlpt[0] & 0x0f) +#define D11A_PHY_HDR_GRES(phdr) (((phdr)->rlpt[0] >> 4) & 0x01) +#define D11A_PHY_HDR_GLENGTH(phdr) (((u32 *)((phdr)->rlpt) >> 5) & 0x0fff) +#define D11A_PHY_HDR_GPARITY(phdr) (((phdr)->rlpt[3] >> 1) & 0x01) +#define D11A_PHY_HDR_GTAIL(phdr) (((phdr)->rlpt[3] >> 2) & 0x3f) + +/* rate encoded per 802.11a-1999 sec 17.3.4.1 */ +#define D11A_PHY_HDR_SRATE(phdr, rate) \ + ((phdr)->rlpt[0] = ((phdr)->rlpt[0] & 0xf0) | ((rate) & 0xf)) +/* set reserved field to zero */ +#define D11A_PHY_HDR_SRES(phdr) ((phdr)->rlpt[0] &= 0xef) +/* length is number of octets in PSDU */ +#define D11A_PHY_HDR_SLENGTH(phdr, length) \ + (*(u32 *)((phdr)->rlpt) = *(u32 *)((phdr)->rlpt) | \ + (((length) & 0x0fff) << 5)) +/* set the tail to all zeros */ +#define D11A_PHY_HDR_STAIL(phdr) ((phdr)->rlpt[3] &= 0x03) + +#define D11A_PHY_HDR_LEN_L 3 /* low-rate part of PLCP header */ +#define D11A_PHY_HDR_LEN_R 2 /* high-rate part of PLCP header */ + +#define D11A_PHY_TX_DELAY (2) /* 2.1 usec */ + +#define D11A_PHY_HDR_TIME (4) /* low-rate part of PLCP header */ +#define D11A_PHY_PRE_TIME (16) +#define D11A_PHY_PREHDR_TIME (D11A_PHY_PRE_TIME + D11A_PHY_HDR_TIME) + +/* 802.11b PLCP header def */ +struct cck_phy_hdr { + u8 signal; + u8 service; + u16 length; + u16 crc; +} __packed; + +#define D11B_PHY_HDR_LEN 6 + +#define D11B_PHY_TX_DELAY (3) /* 3.4 usec */ + +#define D11B_PHY_LHDR_TIME (D11B_PHY_HDR_LEN << 3) +#define D11B_PHY_LPRE_TIME (144) +#define D11B_PHY_LPREHDR_TIME (D11B_PHY_LPRE_TIME + D11B_PHY_LHDR_TIME) + +#define D11B_PHY_SHDR_TIME (D11B_PHY_LHDR_TIME >> 1) +#define D11B_PHY_SPRE_TIME (D11B_PHY_LPRE_TIME >> 1) +#define D11B_PHY_SPREHDR_TIME (D11B_PHY_SPRE_TIME + D11B_PHY_SHDR_TIME) + +#define D11B_PLCP_SIGNAL_LOCKED (1 << 2) +#define D11B_PLCP_SIGNAL_LE (1 << 7) + +#define MIMO_PLCP_MCS_MASK 0x7f /* mcs index */ +#define MIMO_PLCP_40MHZ 0x80 /* 40 Hz frame */ +#define MIMO_PLCP_AMPDU 0x08 /* ampdu */ + +#define BRCMS_GET_CCK_PLCP_LEN(plcp) (plcp[4] + (plcp[5] << 8)) +#define BRCMS_GET_MIMO_PLCP_LEN(plcp) (plcp[1] + (plcp[2] << 8)) +#define BRCMS_SET_MIMO_PLCP_LEN(plcp, len) \ + do { \ + plcp[1] = len & 0xff; \ + plcp[2] = ((len >> 8) & 0xff); \ + } while (0); + +#define BRCMS_SET_MIMO_PLCP_AMPDU(plcp) (plcp[3] |= MIMO_PLCP_AMPDU) +#define BRCMS_CLR_MIMO_PLCP_AMPDU(plcp) (plcp[3] &= ~MIMO_PLCP_AMPDU) +#define BRCMS_IS_MIMO_PLCP_AMPDU(plcp) (plcp[3] & MIMO_PLCP_AMPDU) + +/* + * The dot11a PLCP header is 5 bytes. To simplify the software (so that we + * don't need e.g. different tx DMA headers for 11a and 11b), the PLCP header + * has padding added in the ucode. + */ +#define D11_PHY_HDR_LEN 6 + +/* TX DMA buffer header */ +struct d11txh { + __le16 MacTxControlLow; /* 0x0 */ + __le16 MacTxControlHigh; /* 0x1 */ + __le16 MacFrameControl; /* 0x2 */ + __le16 TxFesTimeNormal; /* 0x3 */ + __le16 PhyTxControlWord; /* 0x4 */ + __le16 PhyTxControlWord_1; /* 0x5 */ + __le16 PhyTxControlWord_1_Fbr; /* 0x6 */ + __le16 PhyTxControlWord_1_Rts; /* 0x7 */ + __le16 PhyTxControlWord_1_FbrRts; /* 0x8 */ + __le16 MainRates; /* 0x9 */ + __le16 XtraFrameTypes; /* 0xa */ + u8 IV[16]; /* 0x0b - 0x12 */ + u8 TxFrameRA[6]; /* 0x13 - 0x15 */ + __le16 TxFesTimeFallback; /* 0x16 */ + u8 RTSPLCPFallback[6]; /* 0x17 - 0x19 */ + __le16 RTSDurFallback; /* 0x1a */ + u8 FragPLCPFallback[6]; /* 0x1b - 1d */ + __le16 FragDurFallback; /* 0x1e */ + __le16 MModeLen; /* 0x1f */ + __le16 MModeFbrLen; /* 0x20 */ + __le16 TstampLow; /* 0x21 */ + __le16 TstampHigh; /* 0x22 */ + __le16 ABI_MimoAntSel; /* 0x23 */ + __le16 PreloadSize; /* 0x24 */ + __le16 AmpduSeqCtl; /* 0x25 */ + __le16 TxFrameID; /* 0x26 */ + __le16 TxStatus; /* 0x27 */ + __le16 MaxNMpdus; /* 0x28 */ + __le16 MaxABytes_MRT; /* 0x29 */ + __le16 MaxABytes_FBR; /* 0x2a */ + __le16 MinMBytes; /* 0x2b */ + u8 RTSPhyHeader[D11_PHY_HDR_LEN]; /* 0x2c - 0x2e */ + struct ieee80211_rts rts_frame; /* 0x2f - 0x36 */ + u16 PAD; /* 0x37 */ +} __packed; + +#define D11_TXH_LEN 112 /* bytes */ + +/* Frame Types */ +#define FT_CCK 0 +#define FT_OFDM 1 +#define FT_HT 2 +#define FT_N 3 + +/* + * Position of MPDU inside A-MPDU; indicated with bits 10:9 + * of MacTxControlLow + */ +#define TXC_AMPDU_SHIFT 9 /* shift for ampdu settings */ +#define TXC_AMPDU_NONE 0 /* Regular MPDU, not an A-MPDU */ +#define TXC_AMPDU_FIRST 1 /* first MPDU of an A-MPDU */ +#define TXC_AMPDU_MIDDLE 2 /* intermediate MPDU of an A-MPDU */ +#define TXC_AMPDU_LAST 3 /* last (or single) MPDU of an A-MPDU */ + +/*== MacTxControlLow ==*/ +#define TXC_AMIC 0x8000 +#define TXC_SENDCTS 0x0800 +#define TXC_AMPDU_MASK 0x0600 +#define TXC_BW_40 0x0100 +#define TXC_FREQBAND_5G 0x0080 +#define TXC_DFCS 0x0040 +#define TXC_IGNOREPMQ 0x0020 +#define TXC_HWSEQ 0x0010 +#define TXC_STARTMSDU 0x0008 +#define TXC_SENDRTS 0x0004 +#define TXC_LONGFRAME 0x0002 +#define TXC_IMMEDACK 0x0001 + +/*== MacTxControlHigh ==*/ +/* RTS fallback preamble type 1 = SHORT 0 = LONG */ +#define TXC_PREAMBLE_RTS_FB_SHORT 0x8000 +/* RTS main rate preamble type 1 = SHORT 0 = LONG */ +#define TXC_PREAMBLE_RTS_MAIN_SHORT 0x4000 +/* + * Main fallback rate preamble type + * 1 = SHORT for OFDM/GF for MIMO + * 0 = LONG for CCK/MM for MIMO + */ +#define TXC_PREAMBLE_DATA_FB_SHORT 0x2000 + +/* TXC_PREAMBLE_DATA_MAIN is in PhyTxControl bit 5 */ +/* use fallback rate for this AMPDU */ +#define TXC_AMPDU_FBR 0x1000 +#define TXC_SECKEY_MASK 0x0FF0 +#define TXC_SECKEY_SHIFT 4 +/* Use alternate txpwr defined at loc. M_ALT_TXPWR_IDX */ +#define TXC_ALT_TXPWR 0x0008 +#define TXC_SECTYPE_MASK 0x0007 +#define TXC_SECTYPE_SHIFT 0 + +/* Null delimiter for Fallback rate */ +#define AMPDU_FBR_NULL_DELIM 5 /* Location of Null delimiter count for AMPDU */ + +/* PhyTxControl for Mimophy */ +#define PHY_TXC_PWR_MASK 0xFC00 +#define PHY_TXC_PWR_SHIFT 10 +#define PHY_TXC_ANT_MASK 0x03C0 /* bit 6, 7, 8, 9 */ +#define PHY_TXC_ANT_SHIFT 6 +#define PHY_TXC_ANT_0_1 0x00C0 /* auto, last rx */ +#define PHY_TXC_LCNPHY_ANT_LAST 0x0000 +#define PHY_TXC_ANT_3 0x0200 /* virtual antenna 3 */ +#define PHY_TXC_ANT_2 0x0100 /* virtual antenna 2 */ +#define PHY_TXC_ANT_1 0x0080 /* virtual antenna 1 */ +#define PHY_TXC_ANT_0 0x0040 /* virtual antenna 0 */ +#define PHY_TXC_SHORT_HDR 0x0010 + +#define PHY_TXC_OLD_ANT_0 0x0000 +#define PHY_TXC_OLD_ANT_1 0x0100 +#define PHY_TXC_OLD_ANT_LAST 0x0300 + +/* PhyTxControl_1 for Mimophy */ +#define PHY_TXC1_BW_MASK 0x0007 +#define PHY_TXC1_BW_10MHZ 0 +#define PHY_TXC1_BW_10MHZ_UP 1 +#define PHY_TXC1_BW_20MHZ 2 +#define PHY_TXC1_BW_20MHZ_UP 3 +#define PHY_TXC1_BW_40MHZ 4 +#define PHY_TXC1_BW_40MHZ_DUP 5 +#define PHY_TXC1_MODE_SHIFT 3 +#define PHY_TXC1_MODE_MASK 0x0038 +#define PHY_TXC1_MODE_SISO 0 +#define PHY_TXC1_MODE_CDD 1 +#define PHY_TXC1_MODE_STBC 2 +#define PHY_TXC1_MODE_SDM 3 + +/* PhyTxControl for HTphy that are different from Mimophy */ +#define PHY_TXC_HTANT_MASK 0x3fC0 /* bits 6-13 */ + +/* XtraFrameTypes */ +#define XFTS_RTS_FT_SHIFT 2 +#define XFTS_FBRRTS_FT_SHIFT 4 +#define XFTS_CHANNEL_SHIFT 8 + +/* Antenna diversity bit in ant_wr_settle */ +#define PHY_AWS_ANTDIV 0x2000 + +/* IFS ctl */ +#define IFS_USEEDCF (1 << 2) + +/* IFS ctl1 */ +#define IFS_CTL1_EDCRS (1 << 3) +#define IFS_CTL1_EDCRS_20L (1 << 4) +#define IFS_CTL1_EDCRS_40 (1 << 5) + +/* ABI_MimoAntSel */ +#define ABI_MAS_ADDR_BMP_IDX_MASK 0x0f00 +#define ABI_MAS_ADDR_BMP_IDX_SHIFT 8 +#define ABI_MAS_FBR_ANT_PTN_MASK 0x00f0 +#define ABI_MAS_FBR_ANT_PTN_SHIFT 4 +#define ABI_MAS_MRT_ANT_PTN_MASK 0x000f + +/* tx status packet */ +struct tx_status { + u16 framelen; + u16 PAD; + u16 frameid; + u16 status; + u16 lasttxtime; + u16 sequence; + u16 phyerr; + u16 ackphyrxsh; +} __packed; + +#define TXSTATUS_LEN 16 + +/* status field bit definitions */ +#define TX_STATUS_FRM_RTX_MASK 0xF000 +#define TX_STATUS_FRM_RTX_SHIFT 12 +#define TX_STATUS_RTS_RTX_MASK 0x0F00 +#define TX_STATUS_RTS_RTX_SHIFT 8 +#define TX_STATUS_MASK 0x00FE +#define TX_STATUS_PMINDCTD (1 << 7) /* PM mode indicated to AP */ +#define TX_STATUS_INTERMEDIATE (1 << 6) /* intermediate or 1st ampdu pkg */ +#define TX_STATUS_AMPDU (1 << 5) /* AMPDU status */ +#define TX_STATUS_SUPR_MASK 0x1C /* suppress status bits (4:2) */ +#define TX_STATUS_SUPR_SHIFT 2 +#define TX_STATUS_ACK_RCV (1 << 1) /* ACK received */ +#define TX_STATUS_VALID (1 << 0) /* Tx status valid */ +#define TX_STATUS_NO_ACK 0 + +/* suppress status reason codes */ +#define TX_STATUS_SUPR_PMQ (1 << 2) /* PMQ entry */ +#define TX_STATUS_SUPR_FLUSH (2 << 2) /* flush request */ +#define TX_STATUS_SUPR_FRAG (3 << 2) /* previous frag failure */ +#define TX_STATUS_SUPR_TBTT (3 << 2) /* SHARED: Probe resp supr for TBTT */ +#define TX_STATUS_SUPR_BADCH (4 << 2) /* channel mismatch */ +#define TX_STATUS_SUPR_EXPTIME (5 << 2) /* lifetime expiry */ +#define TX_STATUS_SUPR_UF (6 << 2) /* underflow */ + +/* Unexpected tx status for rate update */ +#define TX_STATUS_UNEXP(status) \ + ((((status) & TX_STATUS_INTERMEDIATE) != 0) && \ + TX_STATUS_UNEXP_AMPDU(status)) + +/* Unexpected tx status for A-MPDU rate update */ +#define TX_STATUS_UNEXP_AMPDU(status) \ + ((((status) & TX_STATUS_SUPR_MASK) != 0) && \ + (((status) & TX_STATUS_SUPR_MASK) != TX_STATUS_SUPR_EXPTIME)) + +#define TX_STATUS_BA_BMAP03_MASK 0xF000 /* ba bitmap 0:3 in 1st pkg */ +#define TX_STATUS_BA_BMAP03_SHIFT 12 /* ba bitmap 0:3 in 1st pkg */ +#define TX_STATUS_BA_BMAP47_MASK 0x001E /* ba bitmap 4:7 in 2nd pkg */ +#define TX_STATUS_BA_BMAP47_SHIFT 3 /* ba bitmap 4:7 in 2nd pkg */ + +/* RXE (Receive Engine) */ + +/* RCM_CTL */ +#define RCM_INC_MASK_H 0x0080 +#define RCM_INC_MASK_L 0x0040 +#define RCM_INC_DATA 0x0020 +#define RCM_INDEX_MASK 0x001F +#define RCM_SIZE 15 + +#define RCM_MAC_OFFSET 0 /* current MAC address */ +#define RCM_BSSID_OFFSET 3 /* current BSSID address */ +#define RCM_F_BSSID_0_OFFSET 6 /* foreign BSS CFP tracking */ +#define RCM_F_BSSID_1_OFFSET 9 /* foreign BSS CFP tracking */ +#define RCM_F_BSSID_2_OFFSET 12 /* foreign BSS CFP tracking */ + +#define RCM_WEP_TA0_OFFSET 16 +#define RCM_WEP_TA1_OFFSET 19 +#define RCM_WEP_TA2_OFFSET 22 +#define RCM_WEP_TA3_OFFSET 25 + +/* PSM Block */ + +/* psm_phy_hdr_param bits */ +#define MAC_PHY_RESET 1 +#define MAC_PHY_CLOCK_EN 2 +#define MAC_PHY_FORCE_CLK 4 + +/* WEP Block */ + +/* WEP_WKEY */ +#define WKEY_START (1 << 8) +#define WKEY_SEL_MASK 0x1F + +/* WEP data formats */ + +/* the number of RCMTA entries */ +#define RCMTA_SIZE 50 + +#define M_ADDR_BMP_BLK (0x37e * 2) +#define M_ADDR_BMP_BLK_SZ 12 + +#define ADDR_BMP_RA (1 << 0) /* Receiver Address (RA) */ +#define ADDR_BMP_TA (1 << 1) /* Transmitter Address (TA) */ +#define ADDR_BMP_BSSID (1 << 2) /* BSSID */ +#define ADDR_BMP_AP (1 << 3) /* Infra-BSS Access Point */ +#define ADDR_BMP_STA (1 << 4) /* Infra-BSS Station */ +#define ADDR_BMP_RESERVED1 (1 << 5) +#define ADDR_BMP_RESERVED2 (1 << 6) +#define ADDR_BMP_RESERVED3 (1 << 7) +#define ADDR_BMP_BSS_IDX_MASK (3 << 8) /* BSS control block index */ +#define ADDR_BMP_BSS_IDX_SHIFT 8 + +#define WSEC_MAX_RCMTA_KEYS 54 + +/* max keys in M_TKMICKEYS_BLK */ +#define WSEC_MAX_TKMIC_ENGINE_KEYS 12 /* 8 + 4 default */ + +/* max RXE match registers */ +#define WSEC_MAX_RXE_KEYS 4 + +/* SECKINDXALGO (Security Key Index & Algorithm Block) word format */ +/* SKL (Security Key Lookup) */ +#define SKL_ALGO_MASK 0x0007 +#define SKL_ALGO_SHIFT 0 +#define SKL_KEYID_MASK 0x0008 +#define SKL_KEYID_SHIFT 3 +#define SKL_INDEX_MASK 0x03F0 +#define SKL_INDEX_SHIFT 4 +#define SKL_GRP_ALGO_MASK 0x1c00 +#define SKL_GRP_ALGO_SHIFT 10 + +/* additional bits defined for IBSS group key support */ +#define SKL_IBSS_INDEX_MASK 0x01F0 +#define SKL_IBSS_INDEX_SHIFT 4 +#define SKL_IBSS_KEYID1_MASK 0x0600 +#define SKL_IBSS_KEYID1_SHIFT 9 +#define SKL_IBSS_KEYID2_MASK 0x1800 +#define SKL_IBSS_KEYID2_SHIFT 11 +#define SKL_IBSS_KEYALGO_MASK 0xE000 +#define SKL_IBSS_KEYALGO_SHIFT 13 + +#define WSEC_MODE_OFF 0 +#define WSEC_MODE_HW 1 +#define WSEC_MODE_SW 2 + +#define WSEC_ALGO_OFF 0 +#define WSEC_ALGO_WEP1 1 +#define WSEC_ALGO_TKIP 2 +#define WSEC_ALGO_AES 3 +#define WSEC_ALGO_WEP128 4 +#define WSEC_ALGO_AES_LEGACY 5 +#define WSEC_ALGO_NALG 6 + +#define AES_MODE_NONE 0 +#define AES_MODE_CCM 1 + +/* WEP_CTL (Rev 0) */ +#define WECR0_KEYREG_SHIFT 0 +#define WECR0_KEYREG_MASK 0x7 +#define WECR0_DECRYPT (1 << 3) +#define WECR0_IVINLINE (1 << 4) +#define WECR0_WEPALG_SHIFT 5 +#define WECR0_WEPALG_MASK (0x7 << 5) +#define WECR0_WKEYSEL_SHIFT 8 +#define WECR0_WKEYSEL_MASK (0x7 << 8) +#define WECR0_WKEYSTART (1 << 11) +#define WECR0_WEPINIT (1 << 14) +#define WECR0_ICVERR (1 << 15) + +/* Frame template map byte offsets */ +#define T_ACTS_TPL_BASE (0) +#define T_NULL_TPL_BASE (0xc * 2) +#define T_QNULL_TPL_BASE (0x1c * 2) +#define T_RR_TPL_BASE (0x2c * 2) +#define T_BCN0_TPL_BASE (0x34 * 2) +#define T_PRS_TPL_BASE (0x134 * 2) +#define T_BCN1_TPL_BASE (0x234 * 2) +#define T_TX_FIFO_TXRAM_BASE (T_ACTS_TPL_BASE + \ + (TXFIFO_START_BLK * TXFIFO_SIZE_UNIT)) + +#define T_BA_TPL_BASE T_QNULL_TPL_BASE /* template area for BA */ + +#define T_RAM_ACCESS_SZ 4 /* template ram is 4 byte access only */ + +/* Shared Mem byte offsets */ + +/* Location where the ucode expects the corerev */ +#define M_MACHW_VER (0x00b * 2) + +/* Location where the ucode expects the MAC capabilities */ +#define M_MACHW_CAP_L (0x060 * 2) +#define M_MACHW_CAP_H (0x061 * 2) + +/* WME shared memory */ +#define M_EDCF_STATUS_OFF (0x007 * 2) +#define M_TXF_CUR_INDEX (0x018 * 2) +#define M_EDCF_QINFO (0x120 * 2) + +/* PS-mode related parameters */ +#define M_DOT11_SLOT (0x008 * 2) +#define M_DOT11_DTIMPERIOD (0x009 * 2) +#define M_NOSLPZNATDTIM (0x026 * 2) + +/* Beacon-related parameters */ +#define M_BCN0_FRM_BYTESZ (0x00c * 2) /* Bcn 0 template length */ +#define M_BCN1_FRM_BYTESZ (0x00d * 2) /* Bcn 1 template length */ +#define M_BCN_TXTSF_OFFSET (0x00e * 2) +#define M_TIMBPOS_INBEACON (0x00f * 2) +#define M_SFRMTXCNTFBRTHSD (0x022 * 2) +#define M_LFRMTXCNTFBRTHSD (0x023 * 2) +#define M_BCN_PCTLWD (0x02a * 2) +#define M_BCN_LI (0x05b * 2) /* beacon listen interval */ + +/* MAX Rx Frame len */ +#define M_MAXRXFRM_LEN (0x010 * 2) + +/* ACK/CTS related params */ +#define M_RSP_PCTLWD (0x011 * 2) + +/* Hardware Power Control */ +#define M_TXPWR_N (0x012 * 2) +#define M_TXPWR_TARGET (0x013 * 2) +#define M_TXPWR_MAX (0x014 * 2) +#define M_TXPWR_CUR (0x019 * 2) + +/* Rx-related parameters */ +#define M_RX_PAD_DATA_OFFSET (0x01a * 2) + +/* WEP Shared mem data */ +#define M_SEC_DEFIVLOC (0x01e * 2) +#define M_SEC_VALNUMSOFTMCHTA (0x01f * 2) +#define M_PHYVER (0x028 * 2) +#define M_PHYTYPE (0x029 * 2) +#define M_SECRXKEYS_PTR (0x02b * 2) +#define M_TKMICKEYS_PTR (0x059 * 2) +#define M_SECKINDXALGO_BLK (0x2ea * 2) +#define M_SECKINDXALGO_BLK_SZ 54 +#define M_SECPSMRXTAMCH_BLK (0x2fa * 2) +#define M_TKIP_TSC_TTAK (0x18c * 2) +#define D11_MAX_KEY_SIZE 16 + +#define M_MAX_ANTCNT (0x02e * 2) /* antenna swap threshold */ + +/* Probe response related parameters */ +#define M_SSIDLEN (0x024 * 2) +#define M_PRB_RESP_FRM_LEN (0x025 * 2) +#define M_PRS_MAXTIME (0x03a * 2) +#define M_SSID (0xb0 * 2) +#define M_CTXPRS_BLK (0xc0 * 2) +#define C_CTX_PCTLWD_POS (0x4 * 2) + +/* Delta between OFDM and CCK power in CCK power boost mode */ +#define M_OFDM_OFFSET (0x027 * 2) + +/* TSSI for last 4 11b/g CCK packets transmitted */ +#define M_B_TSSI_0 (0x02c * 2) +#define M_B_TSSI_1 (0x02d * 2) + +/* Host flags to turn on ucode options */ +#define M_HOST_FLAGS1 (0x02f * 2) +#define M_HOST_FLAGS2 (0x030 * 2) +#define M_HOST_FLAGS3 (0x031 * 2) +#define M_HOST_FLAGS4 (0x03c * 2) +#define M_HOST_FLAGS5 (0x06a * 2) +#define M_HOST_FLAGS_SZ 16 + +#define M_RADAR_REG (0x033 * 2) + +/* TSSI for last 4 11a OFDM packets transmitted */ +#define M_A_TSSI_0 (0x034 * 2) +#define M_A_TSSI_1 (0x035 * 2) + +/* noise interference measurement */ +#define M_NOISE_IF_COUNT (0x034 * 2) +#define M_NOISE_IF_TIMEOUT (0x035 * 2) + +#define M_RF_RX_SP_REG1 (0x036 * 2) + +/* TSSI for last 4 11g OFDM packets transmitted */ +#define M_G_TSSI_0 (0x038 * 2) +#define M_G_TSSI_1 (0x039 * 2) + +/* Background noise measure */ +#define M_JSSI_0 (0x44 * 2) +#define M_JSSI_1 (0x45 * 2) +#define M_JSSI_AUX (0x46 * 2) + +#define M_CUR_2050_RADIOCODE (0x47 * 2) + +/* TX fifo sizes */ +#define M_FIFOSIZE0 (0x4c * 2) +#define M_FIFOSIZE1 (0x4d * 2) +#define M_FIFOSIZE2 (0x4e * 2) +#define M_FIFOSIZE3 (0x4f * 2) +#define D11_MAX_TX_FRMS 32 /* max frames allowed in tx fifo */ + +/* Current channel number plus upper bits */ +#define M_CURCHANNEL (0x50 * 2) +#define D11_CURCHANNEL_5G 0x0100; +#define D11_CURCHANNEL_40 0x0200; +#define D11_CURCHANNEL_MAX 0x00FF; + +/* last posted frameid on the bcmc fifo */ +#define M_BCMC_FID (0x54 * 2) +#define INVALIDFID 0xffff + +/* extended beacon phyctl bytes for 11N */ +#define M_BCN_PCTL1WD (0x058 * 2) + +/* idle busy ratio to duty_cycle requirement */ +#define M_TX_IDLE_BUSY_RATIO_X_16_CCK (0x52 * 2) +#define M_TX_IDLE_BUSY_RATIO_X_16_OFDM (0x5A * 2) + +/* CW RSSI for LCNPHY */ +#define M_LCN_RSSI_0 0x1332 +#define M_LCN_RSSI_1 0x1338 +#define M_LCN_RSSI_2 0x133e +#define M_LCN_RSSI_3 0x1344 + +/* SNR for LCNPHY */ +#define M_LCN_SNR_A_0 0x1334 +#define M_LCN_SNR_B_0 0x1336 + +#define M_LCN_SNR_A_1 0x133a +#define M_LCN_SNR_B_1 0x133c + +#define M_LCN_SNR_A_2 0x1340 +#define M_LCN_SNR_B_2 0x1342 + +#define M_LCN_SNR_A_3 0x1346 +#define M_LCN_SNR_B_3 0x1348 + +#define M_LCN_LAST_RESET (81*2) +#define M_LCN_LAST_LOC (63*2) +#define M_LCNPHY_RESET_STATUS (4902) +#define M_LCNPHY_DSC_TIME (0x98d*2) +#define M_LCNPHY_RESET_CNT_DSC (0x98b*2) +#define M_LCNPHY_RESET_CNT (0x98c*2) + +/* Rate table offsets */ +#define M_RT_DIRMAP_A (0xe0 * 2) +#define M_RT_BBRSMAP_A (0xf0 * 2) +#define M_RT_DIRMAP_B (0x100 * 2) +#define M_RT_BBRSMAP_B (0x110 * 2) + +/* Rate table entry offsets */ +#define M_RT_PRS_PLCP_POS 10 +#define M_RT_PRS_DUR_POS 16 +#define M_RT_OFDM_PCTL1_POS 18 + +#define M_20IN40_IQ (0x380 * 2) + +/* SHM locations where ucode stores the current power index */ +#define M_CURR_IDX1 (0x384 * 2) +#define M_CURR_IDX2 (0x387 * 2) + +#define M_BSCALE_ANT0 (0x5e * 2) +#define M_BSCALE_ANT1 (0x5f * 2) + +/* Antenna Diversity Testing */ +#define M_MIMO_ANTSEL_RXDFLT (0x63 * 2) +#define M_ANTSEL_CLKDIV (0x61 * 2) +#define M_MIMO_ANTSEL_TXDFLT (0x64 * 2) + +#define M_MIMO_MAXSYM (0x5d * 2) +#define MIMO_MAXSYM_DEF 0x8000 /* 32k */ +#define MIMO_MAXSYM_MAX 0xffff /* 64k */ + +#define M_WATCHDOG_8TU (0x1e * 2) +#define WATCHDOG_8TU_DEF 5 +#define WATCHDOG_8TU_MAX 10 + +/* Manufacturing Test Variables */ +/* PER test mode */ +#define M_PKTENG_CTRL (0x6c * 2) +/* IFS for TX mode */ +#define M_PKTENG_IFS (0x6d * 2) +/* Lower word of tx frmcnt/rx lostcnt */ +#define M_PKTENG_FRMCNT_LO (0x6e * 2) +/* Upper word of tx frmcnt/rx lostcnt */ +#define M_PKTENG_FRMCNT_HI (0x6f * 2) + +/* Index variation in vbat ripple */ +#define M_LCN_PWR_IDX_MAX (0x67 * 2) /* highest index read by ucode */ +#define M_LCN_PWR_IDX_MIN (0x66 * 2) /* lowest index read by ucode */ + +/* M_PKTENG_CTRL bit definitions */ +#define M_PKTENG_MODE_TX 0x0001 +#define M_PKTENG_MODE_TX_RIFS 0x0004 +#define M_PKTENG_MODE_TX_CTS 0x0008 +#define M_PKTENG_MODE_RX 0x0002 +#define M_PKTENG_MODE_RX_WITH_ACK 0x0402 +#define M_PKTENG_MODE_MASK 0x0003 +/* TX frames indicated in the frmcnt reg */ +#define M_PKTENG_FRMCNT_VLD 0x0100 + +/* Sample Collect parameters (bitmap and type) */ +/* Trigger bitmap for sample collect */ +#define M_SMPL_COL_BMP (0x37d * 2) +/* Sample collect type */ +#define M_SMPL_COL_CTL (0x3b2 * 2) + +#define ANTSEL_CLKDIV_4MHZ 6 +#define MIMO_ANTSEL_BUSY 0x4000 /* bit 14 (busy) */ +#define MIMO_ANTSEL_SEL 0x8000 /* bit 15 write the value */ +#define MIMO_ANTSEL_WAIT 50 /* 50us wait */ +#define MIMO_ANTSEL_OVERRIDE 0x8000 /* flag */ + +struct shm_acparams { + u16 txop; + u16 cwmin; + u16 cwmax; + u16 cwcur; + u16 aifs; + u16 bslots; + u16 reggap; + u16 status; + u16 rsvd[8]; +} __packed; +#define M_EDCF_QLEN (16 * 2) + +#define WME_STATUS_NEWAC (1 << 8) + +/* M_HOST_FLAGS */ +#define MHFMAX 5 /* Number of valid hostflag half-word (u16) */ +#define MHF1 0 /* Hostflag 1 index */ +#define MHF2 1 /* Hostflag 2 index */ +#define MHF3 2 /* Hostflag 3 index */ +#define MHF4 3 /* Hostflag 4 index */ +#define MHF5 4 /* Hostflag 5 index */ + +/* Flags in M_HOST_FLAGS */ +/* Enable ucode antenna diversity help */ +#define MHF1_ANTDIV 0x0001 +/* Enable EDCF access control */ +#define MHF1_EDCF 0x0100 +#define MHF1_IQSWAP_WAR 0x0200 +/* Disable Slow clock request, for corerev < 11 */ +#define MHF1_FORCEFASTCLK 0x0400 + +/* Flags in M_HOST_FLAGS2 */ + +/* Flush BCMC FIFO immediately */ +#define MHF2_TXBCMC_NOW 0x0040 +/* Enable ucode/hw power control */ +#define MHF2_HWPWRCTL 0x0080 +#define MHF2_NPHY40MHZ_WAR 0x0800 + +/* Flags in M_HOST_FLAGS3 */ +/* enabled mimo antenna selection */ +#define MHF3_ANTSEL_EN 0x0001 +/* antenna selection mode: 0: 2x3, 1: 2x4 */ +#define MHF3_ANTSEL_MODE 0x0002 +#define MHF3_RESERVED1 0x0004 +#define MHF3_RESERVED2 0x0008 +#define MHF3_NPHY_MLADV_WAR 0x0010 + +/* Flags in M_HOST_FLAGS4 */ +/* force bphy Tx on core 0 (board level WAR) */ +#define MHF4_BPHY_TXCORE0 0x0080 +/* for 4313A0 FEM boards */ +#define MHF4_EXTPA_ENABLE 0x4000 + +/* Flags in M_HOST_FLAGS5 */ +#define MHF5_4313_GPIOCTRL 0x0001 +#define MHF5_RESERVED1 0x0002 +#define MHF5_RESERVED2 0x0004 +/* Radio power setting for ucode */ +#define M_RADIO_PWR (0x32 * 2) + +/* phy noise recorded by ucode right after tx */ +#define M_PHY_NOISE (0x037 * 2) +#define PHY_NOISE_MASK 0x00ff + +/* + * Receive Frame Data Header for 802.11b DCF-only frames + * + * RxFrameSize: Actual byte length of the frame data received + * PAD: padding (not used) + * PhyRxStatus_0: PhyRxStatus 15:0 + * PhyRxStatus_1: PhyRxStatus 31:16 + * PhyRxStatus_2: PhyRxStatus 47:32 + * PhyRxStatus_3: PhyRxStatus 63:48 + * PhyRxStatus_4: PhyRxStatus 79:64 + * PhyRxStatus_5: PhyRxStatus 95:80 + * RxStatus1: MAC Rx Status + * RxStatus2: extended MAC Rx status + * RxTSFTime: RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY + * RxChan: gain code, channel radio code, and phy type + */ +struct d11rxhdr_le { + __le16 RxFrameSize; + u16 PAD; + __le16 PhyRxStatus_0; + __le16 PhyRxStatus_1; + __le16 PhyRxStatus_2; + __le16 PhyRxStatus_3; + __le16 PhyRxStatus_4; + __le16 PhyRxStatus_5; + __le16 RxStatus1; + __le16 RxStatus2; + __le16 RxTSFTime; + __le16 RxChan; +} __packed; + +struct d11rxhdr { + u16 RxFrameSize; + u16 PAD; + u16 PhyRxStatus_0; + u16 PhyRxStatus_1; + u16 PhyRxStatus_2; + u16 PhyRxStatus_3; + u16 PhyRxStatus_4; + u16 PhyRxStatus_5; + u16 RxStatus1; + u16 RxStatus2; + u16 RxTSFTime; + u16 RxChan; +} __packed; + +/* PhyRxStatus_0: */ +/* NPHY only: CCK, OFDM, preN, N */ +#define PRXS0_FT_MASK 0x0003 +/* NPHY only: clip count adjustment steps by AGC */ +#define PRXS0_CLIP_MASK 0x000C +#define PRXS0_CLIP_SHIFT 2 +/* PHY received a frame with unsupported rate */ +#define PRXS0_UNSRATE 0x0010 +/* GPHY: rx ant, NPHY: upper sideband */ +#define PRXS0_RXANT_UPSUBBAND 0x0020 +/* CCK frame only: lost crs during cck frame reception */ +#define PRXS0_LCRS 0x0040 +/* Short Preamble */ +#define PRXS0_SHORTH 0x0080 +/* PLCP violation */ +#define PRXS0_PLCPFV 0x0100 +/* PLCP header integrity check failed */ +#define PRXS0_PLCPHCF 0x0200 +/* legacy PHY gain control */ +#define PRXS0_GAIN_CTL 0x4000 +/* NPHY: Antennas used for received frame, bitmask */ +#define PRXS0_ANTSEL_MASK 0xF000 +#define PRXS0_ANTSEL_SHIFT 0x12 + +/* subfield PRXS0_FT_MASK */ +#define PRXS0_CCK 0x0000 +/* valid only for G phy, use rxh->RxChan for A phy */ +#define PRXS0_OFDM 0x0001 +#define PRXS0_PREN 0x0002 +#define PRXS0_STDN 0x0003 + +/* subfield PRXS0_ANTSEL_MASK */ +#define PRXS0_ANTSEL_0 0x0 /* antenna 0 is used */ +#define PRXS0_ANTSEL_1 0x2 /* antenna 1 is used */ +#define PRXS0_ANTSEL_2 0x4 /* antenna 2 is used */ +#define PRXS0_ANTSEL_3 0x8 /* antenna 3 is used */ + +/* PhyRxStatus_1: */ +#define PRXS1_JSSI_MASK 0x00FF +#define PRXS1_JSSI_SHIFT 0 +#define PRXS1_SQ_MASK 0xFF00 +#define PRXS1_SQ_SHIFT 8 + +/* nphy PhyRxStatus_1: */ +#define PRXS1_nphy_PWR0_MASK 0x00FF +#define PRXS1_nphy_PWR1_MASK 0xFF00 + +/* HTPHY Rx Status defines */ +/* htphy PhyRxStatus_0: those bit are overlapped with PhyRxStatus_0 */ +#define PRXS0_BAND 0x0400 /* 0 = 2.4G, 1 = 5G */ +#define PRXS0_RSVD 0x0800 /* reserved; set to 0 */ +#define PRXS0_UNUSED 0xF000 /* unused and not defined; set to 0 */ + +/* htphy PhyRxStatus_1: */ +/* core enables for {3..0}, 0=disabled, 1=enabled */ +#define PRXS1_HTPHY_CORE_MASK 0x000F +/* antenna configation */ +#define PRXS1_HTPHY_ANTCFG_MASK 0x00F0 +/* Mixmode PLCP Length low byte mask */ +#define PRXS1_HTPHY_MMPLCPLenL_MASK 0xFF00 + +/* htphy PhyRxStatus_2: */ +/* Mixmode PLCP Length high byte maskw */ +#define PRXS2_HTPHY_MMPLCPLenH_MASK 0x000F +/* Mixmode PLCP rate mask */ +#define PRXS2_HTPHY_MMPLCH_RATE_MASK 0x00F0 +/* Rx power on core 0 */ +#define PRXS2_HTPHY_RXPWR_ANT0 0xFF00 + +/* htphy PhyRxStatus_3: */ +/* Rx power on core 1 */ +#define PRXS3_HTPHY_RXPWR_ANT1 0x00FF +/* Rx power on core 2 */ +#define PRXS3_HTPHY_RXPWR_ANT2 0xFF00 + +/* htphy PhyRxStatus_4: */ +/* Rx power on core 3 */ +#define PRXS4_HTPHY_RXPWR_ANT3 0x00FF +/* Coarse frequency offset */ +#define PRXS4_HTPHY_CFO 0xFF00 + +/* htphy PhyRxStatus_5: */ +/* Fine frequency offset */ +#define PRXS5_HTPHY_FFO 0x00FF +/* Advance Retard */ +#define PRXS5_HTPHY_AR 0xFF00 + +#define HTPHY_MMPLCPLen(rxs) \ + ((((rxs)->PhyRxStatus_1 & PRXS1_HTPHY_MMPLCPLenL_MASK) >> 8) | \ + (((rxs)->PhyRxStatus_2 & PRXS2_HTPHY_MMPLCPLenH_MASK) << 8)) +/* Get Rx power on core 0 */ +#define HTPHY_RXPWR_ANT0(rxs) \ + ((((rxs)->PhyRxStatus_2) & PRXS2_HTPHY_RXPWR_ANT0) >> 8) +/* Get Rx power on core 1 */ +#define HTPHY_RXPWR_ANT1(rxs) \ + (((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT1) +/* Get Rx power on core 2 */ +#define HTPHY_RXPWR_ANT2(rxs) \ + ((((rxs)->PhyRxStatus_3) & PRXS3_HTPHY_RXPWR_ANT2) >> 8) + +/* ucode RxStatus1: */ +#define RXS_BCNSENT 0x8000 +#define RXS_SECKINDX_MASK 0x07e0 +#define RXS_SECKINDX_SHIFT 5 +#define RXS_DECERR (1 << 4) +#define RXS_DECATMPT (1 << 3) +/* PAD bytes to make IP data 4 bytes aligned */ +#define RXS_PBPRES (1 << 2) +#define RXS_RESPFRAMETX (1 << 1) +#define RXS_FCSERR (1 << 0) + +/* ucode RxStatus2: */ +#define RXS_AMSDU_MASK 1 +#define RXS_AGGTYPE_MASK 0x6 +#define RXS_AGGTYPE_SHIFT 1 +#define RXS_PHYRXST_VALID (1 << 8) +#define RXS_RXANT_MASK 0x3 +#define RXS_RXANT_SHIFT 12 + +/* RxChan */ +#define RXS_CHAN_40 0x1000 +#define RXS_CHAN_5G 0x0800 +#define RXS_CHAN_ID_MASK 0x07f8 +#define RXS_CHAN_ID_SHIFT 3 +#define RXS_CHAN_PHYTYPE_MASK 0x0007 +#define RXS_CHAN_PHYTYPE_SHIFT 0 + +/* Index of attenuations used during ucode power control. */ +#define M_PWRIND_BLKS (0x184 * 2) +#define M_PWRIND_MAP0 (M_PWRIND_BLKS + 0x0) +#define M_PWRIND_MAP1 (M_PWRIND_BLKS + 0x2) +#define M_PWRIND_MAP2 (M_PWRIND_BLKS + 0x4) +#define M_PWRIND_MAP3 (M_PWRIND_BLKS + 0x6) +/* M_PWRIND_MAP(core) macro */ +#define M_PWRIND_MAP(core) (M_PWRIND_BLKS + ((core)<<1)) + +/* PSM SHM variable offsets */ +#define M_PSM_SOFT_REGS 0x0 +#define M_BOM_REV_MAJOR (M_PSM_SOFT_REGS + 0x0) +#define M_BOM_REV_MINOR (M_PSM_SOFT_REGS + 0x2) +#define M_UCODE_DBGST (M_PSM_SOFT_REGS + 0x40) /* ucode debug status code */ +#define M_UCODE_MACSTAT (M_PSM_SOFT_REGS + 0xE0) /* macstat counters */ + +#define M_AGING_THRSH (0x3e * 2) /* max time waiting for medium before tx */ +#define M_MBURST_SIZE (0x40 * 2) /* max frames in a frameburst */ +#define M_MBURST_TXOP (0x41 * 2) /* max frameburst TXOP in unit of us */ +#define M_SYNTHPU_DLY (0x4a * 2) /* pre-wakeup for synthpu, default: 500 */ +#define M_PRETBTT (0x4b * 2) + +/* offset to the target txpwr */ +#define M_ALT_TXPWR_IDX (M_PSM_SOFT_REGS + (0x3b * 2)) +#define M_PHY_TX_FLT_PTR (M_PSM_SOFT_REGS + (0x3d * 2)) +#define M_CTS_DURATION (M_PSM_SOFT_REGS + (0x5c * 2)) +#define M_LP_RCCAL_OVR (M_PSM_SOFT_REGS + (0x6b * 2)) + +/* PKTENG Rx Stats Block */ +#define M_RXSTATS_BLK_PTR (M_PSM_SOFT_REGS + (0x65 * 2)) + +/* ucode debug status codes */ +/* not valid really */ +#define DBGST_INACTIVE 0 +/* after zeroing SHM, before suspending at init */ +#define DBGST_INIT 1 +/* "normal" state */ +#define DBGST_ACTIVE 2 +/* suspended */ +#define DBGST_SUSPENDED 3 +/* asleep (PS mode) */ +#define DBGST_ASLEEP 4 + +/* Scratch Reg defs */ +enum _ePsmScratchPadRegDefinitions { + S_RSV0 = 0, + S_RSV1, + S_RSV2, + + /* offset 0x03: scratch registers for Dot11-contants */ + S_DOT11_CWMIN, /* CW-minimum */ + S_DOT11_CWMAX, /* CW-maximum */ + S_DOT11_CWCUR, /* CW-current */ + S_DOT11_SRC_LMT, /* short retry count limit */ + S_DOT11_LRC_LMT, /* long retry count limit */ + S_DOT11_DTIMCOUNT, /* DTIM-count */ + + /* offset 0x09: Tx-side scratch registers */ + S_SEQ_NUM, /* hardware sequence number reg */ + S_SEQ_NUM_FRAG, /* seq num for frags (at the start of MSDU) */ + S_FRMRETX_CNT, /* frame retx count */ + S_SSRC, /* Station short retry count */ + S_SLRC, /* Station long retry count */ + S_EXP_RSP, /* Expected response frame */ + S_OLD_BREM, /* Remaining backoff ctr */ + S_OLD_CWWIN, /* saved-off CW-cur */ + S_TXECTL, /* TXE-Ctl word constructed in scr-pad */ + S_CTXTST, /* frm type-subtype as read from Tx-descr */ + + /* offset 0x13: Rx-side scratch registers */ + S_RXTST, /* Type and subtype in Rxframe */ + + /* Global state register */ + S_STREG, /* state storage actual bit maps below */ + + S_TXPWR_SUM, /* Tx power control: accumulator */ + S_TXPWR_ITER, /* Tx power control: iteration */ + S_RX_FRMTYPE, /* Rate and PHY type for frames */ + S_THIS_AGG, /* Size of this AGG (A-MSDU) */ + + S_KEYINDX, + S_RXFRMLEN, /* Receive MPDU length in bytes */ + + /* offset 0x1B: Receive TSF time stored in SCR */ + S_RXTSFTMRVAL_WD3, /* TSF value at the start of rx */ + S_RXTSFTMRVAL_WD2, /* TSF value at the start of rx */ + S_RXTSFTMRVAL_WD1, /* TSF value at the start of rx */ + S_RXTSFTMRVAL_WD0, /* TSF value at the start of rx */ + S_RXSSN, /* Received start seq number for A-MPDU BA */ + S_RXQOSFLD, /* Rx-QoS field (if present) */ + + /* offset 0x21: Scratch pad regs used in microcode as temp storage */ + S_TMP0, /* stmp0 */ + S_TMP1, /* stmp1 */ + S_TMP2, /* stmp2 */ + S_TMP3, /* stmp3 */ + S_TMP4, /* stmp4 */ + S_TMP5, /* stmp5 */ + S_PRQPENALTY_CTR, /* Probe response queue penalty counter */ + S_ANTCNT, /* unsuccessful attempts on current ant. */ + S_SYMBOL, /* flag for possible symbol ctl frames */ + S_RXTP, /* rx frame type */ + S_STREG2, /* extra state storage */ + S_STREG3, /* even more extra state storage */ + S_STREG4, /* ... */ + S_STREG5, /* remember to initialize it to zero */ + + S_ADJPWR_IDX, + S_CUR_PTR, /* Temp pointer for A-MPDU re-Tx SHM table */ + S_REVID4, /* 0x33 */ + S_INDX, /* 0x34 */ + S_ADDR0, /* 0x35 */ + S_ADDR1, /* 0x36 */ + S_ADDR2, /* 0x37 */ + S_ADDR3, /* 0x38 */ + S_ADDR4, /* 0x39 */ + S_ADDR5, /* 0x3A */ + S_TMP6, /* 0x3B */ + S_KEYINDX_BU, /* Backup for Key index */ + S_MFGTEST_TMP0, /* Temp regs used for RX test calculations */ + S_RXESN, /* Received end sequence number for A-MPDU BA */ + S_STREG6, /* 0x3F */ +}; + +#define S_BEACON_INDX S_OLD_BREM +#define S_PRS_INDX S_OLD_CWWIN +#define S_PHYTYPE S_SSRC +#define S_PHYVER S_SLRC + +/* IHR SLOW_CTRL values */ +#define SLOW_CTRL_PDE (1 << 0) +#define SLOW_CTRL_FD (1 << 8) + +/* ucode mac statistic counters in shared memory */ +struct macstat { + u16 txallfrm; /* 0x80 */ + u16 txrtsfrm; /* 0x82 */ + u16 txctsfrm; /* 0x84 */ + u16 txackfrm; /* 0x86 */ + u16 txdnlfrm; /* 0x88 */ + u16 txbcnfrm; /* 0x8a */ + u16 txfunfl[8]; /* 0x8c - 0x9b */ + u16 txtplunfl; /* 0x9c */ + u16 txphyerr; /* 0x9e */ + u16 pktengrxducast; /* 0xa0 */ + u16 pktengrxdmcast; /* 0xa2 */ + u16 rxfrmtoolong; /* 0xa4 */ + u16 rxfrmtooshrt; /* 0xa6 */ + u16 rxinvmachdr; /* 0xa8 */ + u16 rxbadfcs; /* 0xaa */ + u16 rxbadplcp; /* 0xac */ + u16 rxcrsglitch; /* 0xae */ + u16 rxstrt; /* 0xb0 */ + u16 rxdfrmucastmbss; /* 0xb2 */ + u16 rxmfrmucastmbss; /* 0xb4 */ + u16 rxcfrmucast; /* 0xb6 */ + u16 rxrtsucast; /* 0xb8 */ + u16 rxctsucast; /* 0xba */ + u16 rxackucast; /* 0xbc */ + u16 rxdfrmocast; /* 0xbe */ + u16 rxmfrmocast; /* 0xc0 */ + u16 rxcfrmocast; /* 0xc2 */ + u16 rxrtsocast; /* 0xc4 */ + u16 rxctsocast; /* 0xc6 */ + u16 rxdfrmmcast; /* 0xc8 */ + u16 rxmfrmmcast; /* 0xca */ + u16 rxcfrmmcast; /* 0xcc */ + u16 rxbeaconmbss; /* 0xce */ + u16 rxdfrmucastobss; /* 0xd0 */ + u16 rxbeaconobss; /* 0xd2 */ + u16 rxrsptmout; /* 0xd4 */ + u16 bcntxcancl; /* 0xd6 */ + u16 PAD; + u16 rxf0ovfl; /* 0xda */ + u16 rxf1ovfl; /* 0xdc */ + u16 rxf2ovfl; /* 0xde */ + u16 txsfovfl; /* 0xe0 */ + u16 pmqovfl; /* 0xe2 */ + u16 rxcgprqfrm; /* 0xe4 */ + u16 rxcgprsqovfl; /* 0xe6 */ + u16 txcgprsfail; /* 0xe8 */ + u16 txcgprssuc; /* 0xea */ + u16 prs_timeout; /* 0xec */ + u16 rxnack; + u16 frmscons; + u16 txnack; + u16 txglitch_nack; + u16 txburst; /* 0xf6 # tx bursts */ + u16 bphy_rxcrsglitch; /* bphy rx crs glitch */ + u16 phywatchdog; /* 0xfa # of phy watchdog events */ + u16 PAD; + u16 bphy_badplcp; /* bphy bad plcp */ +}; + +/* dot11 core-specific control flags */ +#define SICF_PCLKE 0x0004 /* PHY clock enable */ +#define SICF_PRST 0x0008 /* PHY reset */ +#define SICF_MPCLKE 0x0010 /* MAC PHY clockcontrol enable */ +#define SICF_FREF 0x0020 /* PLL FreqRefSelect */ +/* NOTE: the following bw bits only apply when the core is attached + * to a NPHY + */ +#define SICF_BWMASK 0x00c0 /* phy clock mask (b6 & b7) */ +#define SICF_BW40 0x0080 /* 40MHz BW (160MHz phyclk) */ +#define SICF_BW20 0x0040 /* 20MHz BW (80MHz phyclk) */ +#define SICF_BW10 0x0000 /* 10MHz BW (40MHz phyclk) */ +#define SICF_GMODE 0x2000 /* gmode enable */ + +/* dot11 core-specific status flags */ +#define SISF_2G_PHY 0x0001 /* 2.4G capable phy */ +#define SISF_5G_PHY 0x0002 /* 5G capable phy */ +#define SISF_FCLKA 0x0004 /* FastClkAvailable */ +#define SISF_DB_PHY 0x0008 /* Dualband phy */ + +/* === End of MAC reg, Beginning of PHY(b/a/g/n) reg === */ +/* radio and LPPHY regs are separated */ + +#define BPHY_REG_OFT_BASE 0x0 +/* offsets for indirect access to bphy registers */ +#define BPHY_BB_CONFIG 0x01 +#define BPHY_ADCBIAS 0x02 +#define BPHY_ANACORE 0x03 +#define BPHY_PHYCRSTH 0x06 +#define BPHY_TEST 0x0a +#define BPHY_PA_TX_TO 0x10 +#define BPHY_SYNTH_DC_TO 0x11 +#define BPHY_PA_TX_TIME_UP 0x12 +#define BPHY_RX_FLTR_TIME_UP 0x13 +#define BPHY_TX_POWER_OVERRIDE 0x14 +#define BPHY_RF_OVERRIDE 0x15 +#define BPHY_RF_TR_LOOKUP1 0x16 +#define BPHY_RF_TR_LOOKUP2 0x17 +#define BPHY_COEFFS 0x18 +#define BPHY_PLL_OUT 0x19 +#define BPHY_REFRESH_MAIN 0x1a +#define BPHY_REFRESH_TO0 0x1b +#define BPHY_REFRESH_TO1 0x1c +#define BPHY_RSSI_TRESH 0x20 +#define BPHY_IQ_TRESH_HH 0x21 +#define BPHY_IQ_TRESH_H 0x22 +#define BPHY_IQ_TRESH_L 0x23 +#define BPHY_IQ_TRESH_LL 0x24 +#define BPHY_GAIN 0x25 +#define BPHY_LNA_GAIN_RANGE 0x26 +#define BPHY_JSSI 0x27 +#define BPHY_TSSI_CTL 0x28 +#define BPHY_TSSI 0x29 +#define BPHY_TR_LOSS_CTL 0x2a +#define BPHY_LO_LEAKAGE 0x2b +#define BPHY_LO_RSSI_ACC 0x2c +#define BPHY_LO_IQMAG_ACC 0x2d +#define BPHY_TX_DC_OFF1 0x2e +#define BPHY_TX_DC_OFF2 0x2f +#define BPHY_PEAK_CNT_THRESH 0x30 +#define BPHY_FREQ_OFFSET 0x31 +#define BPHY_DIVERSITY_CTL 0x32 +#define BPHY_PEAK_ENERGY_LO 0x33 +#define BPHY_PEAK_ENERGY_HI 0x34 +#define BPHY_SYNC_CTL 0x35 +#define BPHY_TX_PWR_CTRL 0x36 +#define BPHY_TX_EST_PWR 0x37 +#define BPHY_STEP 0x38 +#define BPHY_WARMUP 0x39 +#define BPHY_LMS_CFF_READ 0x3a +#define BPHY_LMS_COEFF_I 0x3b +#define BPHY_LMS_COEFF_Q 0x3c +#define BPHY_SIG_POW 0x3d +#define BPHY_RFDC_CANCEL_CTL 0x3e +#define BPHY_HDR_TYPE 0x40 +#define BPHY_SFD_TO 0x41 +#define BPHY_SFD_CTL 0x42 +#define BPHY_DEBUG 0x43 +#define BPHY_RX_DELAY_COMP 0x44 +#define BPHY_CRS_DROP_TO 0x45 +#define BPHY_SHORT_SFD_NZEROS 0x46 +#define BPHY_DSSS_COEFF1 0x48 +#define BPHY_DSSS_COEFF2 0x49 +#define BPHY_CCK_COEFF1 0x4a +#define BPHY_CCK_COEFF2 0x4b +#define BPHY_TR_CORR 0x4c +#define BPHY_ANGLE_SCALE 0x4d +#define BPHY_TX_PWR_BASE_IDX 0x4e +#define BPHY_OPTIONAL_MODES2 0x4f +#define BPHY_CCK_LMS_STEP 0x50 +#define BPHY_BYPASS 0x51 +#define BPHY_CCK_DELAY_LONG 0x52 +#define BPHY_CCK_DELAY_SHORT 0x53 +#define BPHY_PPROC_CHAN_DELAY 0x54 +#define BPHY_DDFS_ENABLE 0x58 +#define BPHY_PHASE_SCALE 0x59 +#define BPHY_FREQ_CONTROL 0x5a +#define BPHY_LNA_GAIN_RANGE_10 0x5b +#define BPHY_LNA_GAIN_RANGE_32 0x5c +#define BPHY_OPTIONAL_MODES 0x5d +#define BPHY_RX_STATUS2 0x5e +#define BPHY_RX_STATUS3 0x5f +#define BPHY_DAC_CONTROL 0x60 +#define BPHY_ANA11G_FILT_CTRL 0x62 +#define BPHY_REFRESH_CTRL 0x64 +#define BPHY_RF_OVERRIDE2 0x65 +#define BPHY_SPUR_CANCEL_CTRL 0x66 +#define BPHY_FINE_DIGIGAIN_CTRL 0x67 +#define BPHY_RSSI_LUT 0x88 +#define BPHY_RSSI_LUT_END 0xa7 +#define BPHY_TSSI_LUT 0xa8 +#define BPHY_TSSI_LUT_END 0xc7 +#define BPHY_TSSI2PWR_LUT 0x380 +#define BPHY_TSSI2PWR_LUT_END 0x39f +#define BPHY_LOCOMP_LUT 0x3a0 +#define BPHY_LOCOMP_LUT_END 0x3bf +#define BPHY_TXGAIN_LUT 0x3c0 +#define BPHY_TXGAIN_LUT_END 0x3ff + +/* Bits in BB_CONFIG: */ +#define PHY_BBC_ANT_MASK 0x0180 +#define PHY_BBC_ANT_SHIFT 7 +#define BB_DARWIN 0x1000 +#define BBCFG_RESETCCA 0x4000 +#define BBCFG_RESETRX 0x8000 + +/* Bits in phytest(0x0a): */ +#define TST_DDFS 0x2000 +#define TST_TXFILT1 0x0800 +#define TST_UNSCRAM 0x0400 +#define TST_CARR_SUPP 0x0200 +#define TST_DC_COMP_LOOP 0x0100 +#define TST_LOOPBACK 0x0080 +#define TST_TXFILT0 0x0040 +#define TST_TXTEST_ENABLE 0x0020 +#define TST_TXTEST_RATE 0x0018 +#define TST_TXTEST_PHASE 0x0007 + +/* phytest txTestRate values */ +#define TST_TXTEST_RATE_1MBPS 0 +#define TST_TXTEST_RATE_2MBPS 1 +#define TST_TXTEST_RATE_5_5MBPS 2 +#define TST_TXTEST_RATE_11MBPS 3 +#define TST_TXTEST_RATE_SHIFT 3 + +#define SHM_BYT_CNT 0x2 /* IHR location */ +#define MAX_BYT_CNT 0x600 /* Maximum frame len */ + +struct d11cnt { + u32 txfrag; + u32 txmulti; + u32 txfail; + u32 txretry; + u32 txretrie; + u32 rxdup; + u32 txrts; + u32 txnocts; + u32 txnoack; + u32 rxfrag; + u32 rxmulti; + u32 rxcrc; + u32 txfrmsnt; + u32 rxundec; +}; + +#endif /* _BRCM_D11_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c new file mode 100644 index 000000000000..b56a30297c26 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -0,0 +1,1425 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/skbuff.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#include <brcmu_utils.h> +#include <aiutils.h> +#include "types.h" +#include "dma.h" + +/* + * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within + * a contiguous 8kB physical address. + */ +#define D64RINGALIGN_BITS 13 +#define D64MAXRINGSZ (1 << D64RINGALIGN_BITS) +#define D64RINGALIGN (1 << D64RINGALIGN_BITS) + +#define D64MAXDD (D64MAXRINGSZ / sizeof(struct dma64desc)) + +/* transmit channel control */ +#define D64_XC_XE 0x00000001 /* transmit enable */ +#define D64_XC_SE 0x00000002 /* transmit suspend request */ +#define D64_XC_LE 0x00000004 /* loopback enable */ +#define D64_XC_FL 0x00000010 /* flush request */ +#define D64_XC_PD 0x00000800 /* parity check disable */ +#define D64_XC_AE 0x00030000 /* address extension bits */ +#define D64_XC_AE_SHIFT 16 + +/* transmit descriptor table pointer */ +#define D64_XP_LD_MASK 0x00000fff /* last valid descriptor */ + +/* transmit channel status */ +#define D64_XS0_CD_MASK 0x00001fff /* current descriptor pointer */ +#define D64_XS0_XS_MASK 0xf0000000 /* transmit state */ +#define D64_XS0_XS_SHIFT 28 +#define D64_XS0_XS_DISABLED 0x00000000 /* disabled */ +#define D64_XS0_XS_ACTIVE 0x10000000 /* active */ +#define D64_XS0_XS_IDLE 0x20000000 /* idle wait */ +#define D64_XS0_XS_STOPPED 0x30000000 /* stopped */ +#define D64_XS0_XS_SUSP 0x40000000 /* suspend pending */ + +#define D64_XS1_AD_MASK 0x00001fff /* active descriptor */ +#define D64_XS1_XE_MASK 0xf0000000 /* transmit errors */ +#define D64_XS1_XE_SHIFT 28 +#define D64_XS1_XE_NOERR 0x00000000 /* no error */ +#define D64_XS1_XE_DPE 0x10000000 /* descriptor protocol error */ +#define D64_XS1_XE_DFU 0x20000000 /* data fifo underrun */ +#define D64_XS1_XE_DTE 0x30000000 /* data transfer error */ +#define D64_XS1_XE_DESRE 0x40000000 /* descriptor read error */ +#define D64_XS1_XE_COREE 0x50000000 /* core error */ + +/* receive channel control */ +/* receive enable */ +#define D64_RC_RE 0x00000001 +/* receive frame offset */ +#define D64_RC_RO_MASK 0x000000fe +#define D64_RC_RO_SHIFT 1 +/* direct fifo receive (pio) mode */ +#define D64_RC_FM 0x00000100 +/* separate rx header descriptor enable */ +#define D64_RC_SH 0x00000200 +/* overflow continue */ +#define D64_RC_OC 0x00000400 +/* parity check disable */ +#define D64_RC_PD 0x00000800 +/* address extension bits */ +#define D64_RC_AE 0x00030000 +#define D64_RC_AE_SHIFT 16 + +/* flags for dma controller */ +/* partity enable */ +#define DMA_CTRL_PEN (1 << 0) +/* rx overflow continue */ +#define DMA_CTRL_ROC (1 << 1) +/* allow rx scatter to multiple descriptors */ +#define DMA_CTRL_RXMULTI (1 << 2) +/* Unframed Rx/Tx data */ +#define DMA_CTRL_UNFRAMED (1 << 3) + +/* receive descriptor table pointer */ +#define D64_RP_LD_MASK 0x00000fff /* last valid descriptor */ + +/* receive channel status */ +#define D64_RS0_CD_MASK 0x00001fff /* current descriptor pointer */ +#define D64_RS0_RS_MASK 0xf0000000 /* receive state */ +#define D64_RS0_RS_SHIFT 28 +#define D64_RS0_RS_DISABLED 0x00000000 /* disabled */ +#define D64_RS0_RS_ACTIVE 0x10000000 /* active */ +#define D64_RS0_RS_IDLE 0x20000000 /* idle wait */ +#define D64_RS0_RS_STOPPED 0x30000000 /* stopped */ +#define D64_RS0_RS_SUSP 0x40000000 /* suspend pending */ + +#define D64_RS1_AD_MASK 0x0001ffff /* active descriptor */ +#define D64_RS1_RE_MASK 0xf0000000 /* receive errors */ +#define D64_RS1_RE_SHIFT 28 +#define D64_RS1_RE_NOERR 0x00000000 /* no error */ +#define D64_RS1_RE_DPO 0x10000000 /* descriptor protocol error */ +#define D64_RS1_RE_DFU 0x20000000 /* data fifo overflow */ +#define D64_RS1_RE_DTE 0x30000000 /* data transfer error */ +#define D64_RS1_RE_DESRE 0x40000000 /* descriptor read error */ +#define D64_RS1_RE_COREE 0x50000000 /* core error */ + +/* fifoaddr */ +#define D64_FA_OFF_MASK 0xffff /* offset */ +#define D64_FA_SEL_MASK 0xf0000 /* select */ +#define D64_FA_SEL_SHIFT 16 +#define D64_FA_SEL_XDD 0x00000 /* transmit dma data */ +#define D64_FA_SEL_XDP 0x10000 /* transmit dma pointers */ +#define D64_FA_SEL_RDD 0x40000 /* receive dma data */ +#define D64_FA_SEL_RDP 0x50000 /* receive dma pointers */ +#define D64_FA_SEL_XFD 0x80000 /* transmit fifo data */ +#define D64_FA_SEL_XFP 0x90000 /* transmit fifo pointers */ +#define D64_FA_SEL_RFD 0xc0000 /* receive fifo data */ +#define D64_FA_SEL_RFP 0xd0000 /* receive fifo pointers */ +#define D64_FA_SEL_RSD 0xe0000 /* receive frame status data */ +#define D64_FA_SEL_RSP 0xf0000 /* receive frame status pointers */ + +/* descriptor control flags 1 */ +#define D64_CTRL_COREFLAGS 0x0ff00000 /* core specific flags */ +#define D64_CTRL1_EOT ((u32)1 << 28) /* end of descriptor table */ +#define D64_CTRL1_IOC ((u32)1 << 29) /* interrupt on completion */ +#define D64_CTRL1_EOF ((u32)1 << 30) /* end of frame */ +#define D64_CTRL1_SOF ((u32)1 << 31) /* start of frame */ + +/* descriptor control flags 2 */ +/* buffer byte count. real data len must <= 16KB */ +#define D64_CTRL2_BC_MASK 0x00007fff +/* address extension bits */ +#define D64_CTRL2_AE 0x00030000 +#define D64_CTRL2_AE_SHIFT 16 +/* parity bit */ +#define D64_CTRL2_PARITY 0x00040000 + +/* control flags in the range [27:20] are core-specific and not defined here */ +#define D64_CTRL_CORE_MASK 0x0ff00000 + +#define D64_RX_FRM_STS_LEN 0x0000ffff /* frame length mask */ +#define D64_RX_FRM_STS_OVFL 0x00800000 /* RxOverFlow */ +#define D64_RX_FRM_STS_DSCRCNT 0x0f000000 /* no. of descriptors used - 1 */ +#define D64_RX_FRM_STS_DATATYPE 0xf0000000 /* core-dependent data type */ + +/* + * packet headroom necessary to accommodate the largest header + * in the system, (i.e TXOFF). By doing, we avoid the need to + * allocate an extra buffer for the header when bridging to WL. + * There is a compile time check in wlc.c which ensure that this + * value is at least as big as TXOFF. This value is used in + * dma_rxfill(). + */ + +#define BCMEXTRAHDROOM 172 + +/* debug/trace */ +#ifdef BCMDBG +#define DMA_ERROR(args) \ + do { \ + if (!(*di->msg_level & 1)) \ + ; \ + else \ + printk args; \ + } while (0) +#define DMA_TRACE(args) \ + do { \ + if (!(*di->msg_level & 2)) \ + ; \ + else \ + printk args; \ + } while (0) +#else +#define DMA_ERROR(args) +#define DMA_TRACE(args) +#endif /* BCMDBG */ + +#define DMA_NONE(args) + +#define MAXNAMEL 8 /* 8 char names */ + +/* macros to convert between byte offsets and indexes */ +#define B2I(bytes, type) ((bytes) / sizeof(type)) +#define I2B(index, type) ((index) * sizeof(type)) + +#define PCI32ADDR_HIGH 0xc0000000 /* address[31:30] */ +#define PCI32ADDR_HIGH_SHIFT 30 /* address[31:30] */ + +#define PCI64ADDR_HIGH 0x80000000 /* address[63] */ +#define PCI64ADDR_HIGH_SHIFT 31 /* address[63] */ + +/* + * DMA Descriptor + * Descriptors are only read by the hardware, never written back. + */ +struct dma64desc { + __le32 ctrl1; /* misc control bits & bufcount */ + __le32 ctrl2; /* buffer count and address extension */ + __le32 addrlow; /* memory address of the date buffer, bits 31:0 */ + __le32 addrhigh; /* memory address of the date buffer, bits 63:32 */ +}; + +/* dma engine software state */ +struct dma_info { + struct dma_pub dma; /* exported structure */ + uint *msg_level; /* message level pointer */ + char name[MAXNAMEL]; /* callers name for diag msgs */ + + struct pci_dev *pbus; /* bus handle */ + + bool dma64; /* this dma engine is operating in 64-bit mode */ + bool addrext; /* this dma engine supports DmaExtendedAddrChanges */ + + /* 64-bit dma tx engine registers */ + struct dma64regs __iomem *d64txregs; + /* 64-bit dma rx engine registers */ + struct dma64regs __iomem *d64rxregs; + /* pointer to dma64 tx descriptor ring */ + struct dma64desc *txd64; + /* pointer to dma64 rx descriptor ring */ + struct dma64desc *rxd64; + + u16 dmadesc_align; /* alignment requirement for dma descriptors */ + + u16 ntxd; /* # tx descriptors tunable */ + u16 txin; /* index of next descriptor to reclaim */ + u16 txout; /* index of next descriptor to post */ + /* pointer to parallel array of pointers to packets */ + struct sk_buff **txp; + /* Aligned physical address of descriptor ring */ + dma_addr_t txdpa; + /* Original physical address of descriptor ring */ + dma_addr_t txdpaorig; + u16 txdalign; /* #bytes added to alloc'd mem to align txd */ + u32 txdalloc; /* #bytes allocated for the ring */ + u32 xmtptrbase; /* When using unaligned descriptors, the ptr register + * is not just an index, it needs all 13 bits to be + * an offset from the addr register. + */ + + u16 nrxd; /* # rx descriptors tunable */ + u16 rxin; /* index of next descriptor to reclaim */ + u16 rxout; /* index of next descriptor to post */ + /* pointer to parallel array of pointers to packets */ + struct sk_buff **rxp; + /* Aligned physical address of descriptor ring */ + dma_addr_t rxdpa; + /* Original physical address of descriptor ring */ + dma_addr_t rxdpaorig; + u16 rxdalign; /* #bytes added to alloc'd mem to align rxd */ + u32 rxdalloc; /* #bytes allocated for the ring */ + u32 rcvptrbase; /* Base for ptr reg when using unaligned descriptors */ + + /* tunables */ + unsigned int rxbufsize; /* rx buffer size in bytes, not including + * the extra headroom + */ + uint rxextrahdrroom; /* extra rx headroom, reverseved to assist upper + * stack, e.g. some rx pkt buffers will be + * bridged to tx side without byte copying. + * The extra headroom needs to be large enough + * to fit txheader needs. Some dongle driver may + * not need it. + */ + uint nrxpost; /* # rx buffers to keep posted */ + unsigned int rxoffset; /* rxcontrol offset */ + /* add to get dma address of descriptor ring, low 32 bits */ + uint ddoffsetlow; + /* high 32 bits */ + uint ddoffsethigh; + /* add to get dma address of data buffer, low 32 bits */ + uint dataoffsetlow; + /* high 32 bits */ + uint dataoffsethigh; + /* descriptor base need to be aligned or not */ + bool aligndesc_4k; +}; + +/* + * default dma message level (if input msg_level + * pointer is null in dma_attach()) + */ +static uint dma_msg_level; + +/* Check for odd number of 1's */ +static u32 parity32(__le32 data) +{ + /* no swap needed for counting 1's */ + u32 par_data = *(u32 *)&data; + + par_data ^= par_data >> 16; + par_data ^= par_data >> 8; + par_data ^= par_data >> 4; + par_data ^= par_data >> 2; + par_data ^= par_data >> 1; + + return par_data & 1; +} + +static bool dma64_dd_parity(struct dma64desc *dd) +{ + return parity32(dd->addrlow ^ dd->addrhigh ^ dd->ctrl1 ^ dd->ctrl2); +} + +/* descriptor bumping functions */ + +static uint xxd(uint x, uint n) +{ + return x & (n - 1); /* faster than %, but n must be power of 2 */ +} + +static uint txd(struct dma_info *di, uint x) +{ + return xxd(x, di->ntxd); +} + +static uint rxd(struct dma_info *di, uint x) +{ + return xxd(x, di->nrxd); +} + +static uint nexttxd(struct dma_info *di, uint i) +{ + return txd(di, i + 1); +} + +static uint prevtxd(struct dma_info *di, uint i) +{ + return txd(di, i - 1); +} + +static uint nextrxd(struct dma_info *di, uint i) +{ + return txd(di, i + 1); +} + +static uint ntxdactive(struct dma_info *di, uint h, uint t) +{ + return txd(di, t-h); +} + +static uint nrxdactive(struct dma_info *di, uint h, uint t) +{ + return rxd(di, t-h); +} + +static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) +{ + uint dmactrlflags = di->dma.dmactrlflags; + + if (di == NULL) { + DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name)); + return 0; + } + + dmactrlflags &= ~mask; + dmactrlflags |= flags; + + /* If trying to enable parity, check if parity is actually supported */ + if (dmactrlflags & DMA_CTRL_PEN) { + u32 control; + + control = R_REG(&di->d64txregs->control); + W_REG(&di->d64txregs->control, + control | D64_XC_PD); + if (R_REG(&di->d64txregs->control) & D64_XC_PD) + /* We *can* disable it so it is supported, + * restore control register + */ + W_REG(&di->d64txregs->control, + control); + else + /* Not supported, don't allow it to be enabled */ + dmactrlflags &= ~DMA_CTRL_PEN; + } + + di->dma.dmactrlflags = dmactrlflags; + + return dmactrlflags; +} + +static bool _dma64_addrext(struct dma64regs __iomem *dma64regs) +{ + u32 w; + OR_REG(&dma64regs->control, D64_XC_AE); + w = R_REG(&dma64regs->control); + AND_REG(&dma64regs->control, ~D64_XC_AE); + return (w & D64_XC_AE) == D64_XC_AE; +} + +/* + * return true if this dma engine supports DmaExtendedAddrChanges, + * otherwise false + */ +static bool _dma_isaddrext(struct dma_info *di) +{ + /* DMA64 supports full 32- or 64-bit operation. AE is always valid */ + + /* not all tx or rx channel are available */ + if (di->d64txregs != NULL) { + if (!_dma64_addrext(di->d64txregs)) + DMA_ERROR(("%s: _dma_isaddrext: DMA64 tx doesn't have " + "AE set\n", di->name)); + return true; + } else if (di->d64rxregs != NULL) { + if (!_dma64_addrext(di->d64rxregs)) + DMA_ERROR(("%s: _dma_isaddrext: DMA64 rx doesn't have " + "AE set\n", di->name)); + return true; + } + + return false; +} + +static bool _dma_descriptor_align(struct dma_info *di) +{ + u32 addrl; + + /* Check to see if the descriptors need to be aligned on 4K/8K or not */ + if (di->d64txregs != NULL) { + W_REG(&di->d64txregs->addrlow, 0xff0); + addrl = R_REG(&di->d64txregs->addrlow); + if (addrl != 0) + return false; + } else if (di->d64rxregs != NULL) { + W_REG(&di->d64rxregs->addrlow, 0xff0); + addrl = R_REG(&di->d64rxregs->addrlow); + if (addrl != 0) + return false; + } + return true; +} + +/* + * Descriptor table must start at the DMA hardware dictated alignment, so + * allocated memory must be large enough to support this requirement. + */ +static void *dma_alloc_consistent(struct pci_dev *pdev, uint size, + u16 align_bits, uint *alloced, + dma_addr_t *pap) +{ + if (align_bits) { + u16 align = (1 << align_bits); + if (!IS_ALIGNED(PAGE_SIZE, align)) + size += align; + *alloced = size; + } + return pci_alloc_consistent(pdev, size, pap); +} + +static +u8 dma_align_sizetobits(uint size) +{ + u8 bitpos = 0; + while (size >>= 1) + bitpos++; + return bitpos; +} + +/* This function ensures that the DMA descriptor ring will not get allocated + * across Page boundary. If the allocation is done across the page boundary + * at the first time, then it is freed and the allocation is done at + * descriptor ring size aligned location. This will ensure that the ring will + * not cross page boundary + */ +static void *dma_ringalloc(struct dma_info *di, u32 boundary, uint size, + u16 *alignbits, uint *alloced, + dma_addr_t *descpa) +{ + void *va; + u32 desc_strtaddr; + u32 alignbytes = 1 << *alignbits; + + va = dma_alloc_consistent(di->pbus, size, *alignbits, alloced, descpa); + + if (NULL == va) + return NULL; + + desc_strtaddr = (u32) roundup((unsigned long)va, alignbytes); + if (((desc_strtaddr + size - 1) & boundary) != (desc_strtaddr + & boundary)) { + *alignbits = dma_align_sizetobits(size); + pci_free_consistent(di->pbus, size, va, *descpa); + va = dma_alloc_consistent(di->pbus, size, *alignbits, + alloced, descpa); + } + return va; +} + +static bool dma64_alloc(struct dma_info *di, uint direction) +{ + u16 size; + uint ddlen; + void *va; + uint alloced = 0; + u16 align; + u16 align_bits; + + ddlen = sizeof(struct dma64desc); + + size = (direction == DMA_TX) ? (di->ntxd * ddlen) : (di->nrxd * ddlen); + align_bits = di->dmadesc_align; + align = (1 << align_bits); + + if (direction == DMA_TX) { + va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits, + &alloced, &di->txdpaorig); + if (va == NULL) { + DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(ntxd)" + " failed\n", di->name)); + return false; + } + align = (1 << align_bits); + di->txd64 = (struct dma64desc *) + roundup((unsigned long)va, align); + di->txdalign = (uint) ((s8 *)di->txd64 - (s8 *) va); + di->txdpa = di->txdpaorig + di->txdalign; + di->txdalloc = alloced; + } else { + va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits, + &alloced, &di->rxdpaorig); + if (va == NULL) { + DMA_ERROR(("%s: dma64_alloc: DMA_ALLOC_CONSISTENT(nrxd)" + " failed\n", di->name)); + return false; + } + align = (1 << align_bits); + di->rxd64 = (struct dma64desc *) + roundup((unsigned long)va, align); + di->rxdalign = (uint) ((s8 *)di->rxd64 - (s8 *) va); + di->rxdpa = di->rxdpaorig + di->rxdalign; + di->rxdalloc = alloced; + } + + return true; +} + +static bool _dma_alloc(struct dma_info *di, uint direction) +{ + return dma64_alloc(di, direction); +} + +struct dma_pub *dma_attach(char *name, struct si_pub *sih, + void __iomem *dmaregstx, void __iomem *dmaregsrx, + uint ntxd, uint nrxd, + uint rxbufsize, int rxextheadroom, + uint nrxpost, uint rxoffset, uint *msg_level) +{ + struct dma_info *di; + uint size; + + /* allocate private info structure */ + di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC); + if (di == NULL) + return NULL; + + di->msg_level = msg_level ? msg_level : &dma_msg_level; + + + di->dma64 = ((ai_core_sflags(sih, 0, 0) & SISF_DMA64) == SISF_DMA64); + + /* init dma reg pointer */ + di->d64txregs = (struct dma64regs __iomem *) dmaregstx; + di->d64rxregs = (struct dma64regs __iomem *) dmaregsrx; + + /* + * Default flags (which can be changed by the driver calling + * dma_ctrlflags before enable): For backwards compatibility + * both Rx Overflow Continue and Parity are DISABLED. + */ + _dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0); + + DMA_TRACE(("%s: dma_attach: %s flags 0x%x ntxd %d nrxd %d " + "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d " + "dmaregstx %p dmaregsrx %p\n", name, "DMA64", + di->dma.dmactrlflags, ntxd, nrxd, rxbufsize, + rxextheadroom, nrxpost, rxoffset, dmaregstx, dmaregsrx)); + + /* make a private copy of our callers name */ + strncpy(di->name, name, MAXNAMEL); + di->name[MAXNAMEL - 1] = '\0'; + + di->pbus = ((struct si_info *)sih)->pbus; + + /* save tunables */ + di->ntxd = (u16) ntxd; + di->nrxd = (u16) nrxd; + + /* the actual dma size doesn't include the extra headroom */ + di->rxextrahdrroom = + (rxextheadroom == -1) ? BCMEXTRAHDROOM : rxextheadroom; + if (rxbufsize > BCMEXTRAHDROOM) + di->rxbufsize = (u16) (rxbufsize - di->rxextrahdrroom); + else + di->rxbufsize = (u16) rxbufsize; + + di->nrxpost = (u16) nrxpost; + di->rxoffset = (u8) rxoffset; + + /* + * figure out the DMA physical address offset for dd and data + * PCI/PCIE: they map silicon backplace address to zero + * based memory, need offset + * Other bus: use zero SI_BUS BIGENDIAN kludge: use sdram + * swapped region for data buffer, not descriptor + */ + di->ddoffsetlow = 0; + di->dataoffsetlow = 0; + /* add offset for pcie with DMA64 bus */ + di->ddoffsetlow = 0; + di->ddoffsethigh = SI_PCIE_DMA_H32; + di->dataoffsetlow = di->ddoffsetlow; + di->dataoffsethigh = di->ddoffsethigh; + /* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */ + if ((ai_coreid(sih) == SDIOD_CORE_ID) + && ((ai_corerev(sih) > 0) && (ai_corerev(sih) <= 2))) + di->addrext = 0; + else if ((ai_coreid(sih) == I2S_CORE_ID) && + ((ai_corerev(sih) == 0) || (ai_corerev(sih) == 1))) + di->addrext = 0; + else + di->addrext = _dma_isaddrext(di); + + /* does the descriptor need to be aligned and if yes, on 4K/8K or not */ + di->aligndesc_4k = _dma_descriptor_align(di); + if (di->aligndesc_4k) { + di->dmadesc_align = D64RINGALIGN_BITS; + if ((ntxd < D64MAXDD / 2) && (nrxd < D64MAXDD / 2)) + /* for smaller dd table, HW relax alignment reqmnt */ + di->dmadesc_align = D64RINGALIGN_BITS - 1; + } else { + di->dmadesc_align = 4; /* 16 byte alignment */ + } + + DMA_NONE(("DMA descriptor align_needed %d, align %d\n", + di->aligndesc_4k, di->dmadesc_align)); + + /* allocate tx packet pointer vector */ + if (ntxd) { + size = ntxd * sizeof(void *); + di->txp = kzalloc(size, GFP_ATOMIC); + if (di->txp == NULL) + goto fail; + } + + /* allocate rx packet pointer vector */ + if (nrxd) { + size = nrxd * sizeof(void *); + di->rxp = kzalloc(size, GFP_ATOMIC); + if (di->rxp == NULL) + goto fail; + } + + /* + * allocate transmit descriptor ring, only need ntxd descriptors + * but it must be aligned + */ + if (ntxd) { + if (!_dma_alloc(di, DMA_TX)) + goto fail; + } + + /* + * allocate receive descriptor ring, only need nrxd descriptors + * but it must be aligned + */ + if (nrxd) { + if (!_dma_alloc(di, DMA_RX)) + goto fail; + } + + if ((di->ddoffsetlow != 0) && !di->addrext) { + if (di->txdpa > SI_PCI_DMA_SZ) { + DMA_ERROR(("%s: dma_attach: txdpa 0x%x: addrext not " + "supported\n", di->name, (u32)di->txdpa)); + goto fail; + } + if (di->rxdpa > SI_PCI_DMA_SZ) { + DMA_ERROR(("%s: dma_attach: rxdpa 0x%x: addrext not " + "supported\n", di->name, (u32)di->rxdpa)); + goto fail; + } + } + + DMA_TRACE(("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x " + "dataoffsethigh " "0x%x addrext %d\n", di->ddoffsetlow, + di->ddoffsethigh, di->dataoffsetlow, di->dataoffsethigh, + di->addrext)); + + return (struct dma_pub *) di; + + fail: + dma_detach((struct dma_pub *)di); + return NULL; +} + +static inline void +dma64_dd_upd(struct dma_info *di, struct dma64desc *ddring, + dma_addr_t pa, uint outidx, u32 *flags, u32 bufcount) +{ + u32 ctrl2 = bufcount & D64_CTRL2_BC_MASK; + + /* PCI bus with big(>1G) physical address, use address extension */ + if ((di->dataoffsetlow == 0) || !(pa & PCI32ADDR_HIGH)) { + ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow); + ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh); + ddring[outidx].ctrl1 = cpu_to_le32(*flags); + ddring[outidx].ctrl2 = cpu_to_le32(ctrl2); + } else { + /* address extension for 32-bit PCI */ + u32 ae; + + ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT; + pa &= ~PCI32ADDR_HIGH; + + ctrl2 |= (ae << D64_CTRL2_AE_SHIFT) & D64_CTRL2_AE; + ddring[outidx].addrlow = cpu_to_le32(pa + di->dataoffsetlow); + ddring[outidx].addrhigh = cpu_to_le32(di->dataoffsethigh); + ddring[outidx].ctrl1 = cpu_to_le32(*flags); + ddring[outidx].ctrl2 = cpu_to_le32(ctrl2); + } + if (di->dma.dmactrlflags & DMA_CTRL_PEN) { + if (dma64_dd_parity(&ddring[outidx])) + ddring[outidx].ctrl2 = + cpu_to_le32(ctrl2 | D64_CTRL2_PARITY); + } +} + +/* !! may be called with core in reset */ +void dma_detach(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + + DMA_TRACE(("%s: dma_detach\n", di->name)); + + /* free dma descriptor rings */ + if (di->txd64) + pci_free_consistent(di->pbus, di->txdalloc, + ((s8 *)di->txd64 - di->txdalign), + (di->txdpaorig)); + if (di->rxd64) + pci_free_consistent(di->pbus, di->rxdalloc, + ((s8 *)di->rxd64 - di->rxdalign), + (di->rxdpaorig)); + + /* free packet pointer vectors */ + kfree(di->txp); + kfree(di->rxp); + + /* free our private info structure */ + kfree(di); + +} + +/* initialize descriptor table base address */ +static void +_dma_ddtable_init(struct dma_info *di, uint direction, dma_addr_t pa) +{ + if (!di->aligndesc_4k) { + if (direction == DMA_TX) + di->xmtptrbase = pa; + else + di->rcvptrbase = pa; + } + + if ((di->ddoffsetlow == 0) + || !(pa & PCI32ADDR_HIGH)) { + if (direction == DMA_TX) { + W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow); + W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh); + } else { + W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow); + W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh); + } + } else { + /* DMA64 32bits address extension */ + u32 ae; + + /* shift the high bit(s) from pa to ae */ + ae = (pa & PCI32ADDR_HIGH) >> PCI32ADDR_HIGH_SHIFT; + pa &= ~PCI32ADDR_HIGH; + + if (direction == DMA_TX) { + W_REG(&di->d64txregs->addrlow, pa + di->ddoffsetlow); + W_REG(&di->d64txregs->addrhigh, di->ddoffsethigh); + SET_REG(&di->d64txregs->control, + D64_XC_AE, (ae << D64_XC_AE_SHIFT)); + } else { + W_REG(&di->d64rxregs->addrlow, pa + di->ddoffsetlow); + W_REG(&di->d64rxregs->addrhigh, di->ddoffsethigh); + SET_REG(&di->d64rxregs->control, + D64_RC_AE, (ae << D64_RC_AE_SHIFT)); + } + } +} + +static void _dma_rxenable(struct dma_info *di) +{ + uint dmactrlflags = di->dma.dmactrlflags; + u32 control; + + DMA_TRACE(("%s: dma_rxenable\n", di->name)); + + control = + (R_REG(&di->d64rxregs->control) & D64_RC_AE) | + D64_RC_RE; + + if ((dmactrlflags & DMA_CTRL_PEN) == 0) + control |= D64_RC_PD; + + if (dmactrlflags & DMA_CTRL_ROC) + control |= D64_RC_OC; + + W_REG(&di->d64rxregs->control, + ((di->rxoffset << D64_RC_RO_SHIFT) | control)); +} + +void dma_rxinit(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + + DMA_TRACE(("%s: dma_rxinit\n", di->name)); + + if (di->nrxd == 0) + return; + + di->rxin = di->rxout = 0; + + /* clear rx descriptor ring */ + memset(di->rxd64, '\0', di->nrxd * sizeof(struct dma64desc)); + + /* DMA engine with out alignment requirement requires table to be inited + * before enabling the engine + */ + if (!di->aligndesc_4k) + _dma_ddtable_init(di, DMA_RX, di->rxdpa); + + _dma_rxenable(di); + + if (di->aligndesc_4k) + _dma_ddtable_init(di, DMA_RX, di->rxdpa); +} + +static struct sk_buff *dma64_getnextrxp(struct dma_info *di, bool forceall) +{ + uint i, curr; + struct sk_buff *rxp; + dma_addr_t pa; + + i = di->rxin; + + /* return if no packets posted */ + if (i == di->rxout) + return NULL; + + curr = + B2I(((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) - + di->rcvptrbase) & D64_RS0_CD_MASK, struct dma64desc); + + /* ignore curr if forceall */ + if (!forceall && (i == curr)) + return NULL; + + /* get the packet pointer that corresponds to the rx descriptor */ + rxp = di->rxp[i]; + di->rxp[i] = NULL; + + pa = le32_to_cpu(di->rxd64[i].addrlow) - di->dataoffsetlow; + + /* clear this packet from the descriptor ring */ + pci_unmap_single(di->pbus, pa, di->rxbufsize, PCI_DMA_FROMDEVICE); + + di->rxd64[i].addrlow = cpu_to_le32(0xdeadbeef); + di->rxd64[i].addrhigh = cpu_to_le32(0xdeadbeef); + + di->rxin = nextrxd(di, i); + + return rxp; +} + +static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall) +{ + if (di->nrxd == 0) + return NULL; + + return dma64_getnextrxp(di, forceall); +} + +/* + * !! rx entry routine + * returns a pointer to the next frame received, or NULL if there are no more + * if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is + * supported with pkts chain + * otherwise, it's treated as giant pkt and will be tossed. + * The DMA scattering starts with normal DMA header, followed by first + * buffer data. After it reaches the max size of buffer, the data continues + * in next DMA descriptor buffer WITHOUT DMA header + */ +struct sk_buff *dma_rx(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + struct sk_buff *p, *head, *tail; + uint len; + uint pkt_len; + int resid = 0; + + next_frame: + head = _dma_getnextrxp(di, false); + if (head == NULL) + return NULL; + + len = le16_to_cpu(*(__le16 *) (head->data)); + DMA_TRACE(("%s: dma_rx len %d\n", di->name, len)); + dma_spin_for_len(len, head); + + /* set actual length */ + pkt_len = min((di->rxoffset + len), di->rxbufsize); + __skb_trim(head, pkt_len); + resid = len - (di->rxbufsize - di->rxoffset); + + /* check for single or multi-buffer rx */ + if (resid > 0) { + tail = head; + while ((resid > 0) && (p = _dma_getnextrxp(di, false))) { + tail->next = p; + pkt_len = min_t(uint, resid, di->rxbufsize); + __skb_trim(p, pkt_len); + + tail = p; + resid -= di->rxbufsize; + } + +#ifdef BCMDBG + if (resid > 0) { + uint cur; + cur = + B2I(((R_REG(&di->d64rxregs->status0) & + D64_RS0_CD_MASK) - + di->rcvptrbase) & D64_RS0_CD_MASK, + struct dma64desc); + DMA_ERROR(("dma_rx, rxin %d rxout %d, hw_curr %d\n", + di->rxin, di->rxout, cur)); + } +#endif /* BCMDBG */ + + if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) { + DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n", + di->name, len)); + brcmu_pkt_buf_free_skb(head); + di->dma.rxgiants++; + goto next_frame; + } + } + + return head; +} + +static bool dma64_rxidle(struct dma_info *di) +{ + DMA_TRACE(("%s: dma_rxidle\n", di->name)); + + if (di->nrxd == 0) + return true; + + return ((R_REG(&di->d64rxregs->status0) & D64_RS0_CD_MASK) == + (R_REG(&di->d64rxregs->ptr) & D64_RS0_CD_MASK)); +} + +/* + * post receive buffers + * return false is refill failed completely and ring is empty this will stall + * the rx dma and user might want to call rxfill again asap. This unlikely + * happens on memory-rich NIC, but often on memory-constrained dongle + */ +bool dma_rxfill(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + struct sk_buff *p; + u16 rxin, rxout; + u32 flags = 0; + uint n; + uint i; + dma_addr_t pa; + uint extra_offset = 0; + bool ring_empty; + + ring_empty = false; + + /* + * Determine how many receive buffers we're lacking + * from the full complement, allocate, initialize, + * and post them, then update the chip rx lastdscr. + */ + + rxin = di->rxin; + rxout = di->rxout; + + n = di->nrxpost - nrxdactive(di, rxin, rxout); + + DMA_TRACE(("%s: dma_rxfill: post %d\n", di->name, n)); + + if (di->rxbufsize > BCMEXTRAHDROOM) + extra_offset = di->rxextrahdrroom; + + for (i = 0; i < n; i++) { + /* + * the di->rxbufsize doesn't include the extra headroom, + * we need to add it to the size to be allocated + */ + p = brcmu_pkt_buf_get_skb(di->rxbufsize + extra_offset); + + if (p == NULL) { + DMA_ERROR(("%s: dma_rxfill: out of rxbufs\n", + di->name)); + if (i == 0 && dma64_rxidle(di)) { + DMA_ERROR(("%s: rxfill64: ring is empty !\n", + di->name)); + ring_empty = true; + } + di->dma.rxnobuf++; + break; + } + /* reserve an extra headroom, if applicable */ + if (extra_offset) + skb_pull(p, extra_offset); + + /* Do a cached write instead of uncached write since DMA_MAP + * will flush the cache. + */ + *(u32 *) (p->data) = 0; + + pa = pci_map_single(di->pbus, p->data, + di->rxbufsize, PCI_DMA_FROMDEVICE); + + /* save the free packet pointer */ + di->rxp[rxout] = p; + + /* reset flags for each descriptor */ + flags = 0; + if (rxout == (di->nrxd - 1)) + flags = D64_CTRL1_EOT; + + dma64_dd_upd(di, di->rxd64, pa, rxout, &flags, + di->rxbufsize); + rxout = nextrxd(di, rxout); + } + + di->rxout = rxout; + + /* update the chip lastdscr pointer */ + W_REG(&di->d64rxregs->ptr, + di->rcvptrbase + I2B(rxout, struct dma64desc)); + + return ring_empty; +} + +void dma_rxreclaim(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + struct sk_buff *p; + + DMA_TRACE(("%s: dma_rxreclaim\n", di->name)); + + while ((p = _dma_getnextrxp(di, true))) + brcmu_pkt_buf_free_skb(p); +} + +void dma_counterreset(struct dma_pub *pub) +{ + /* reset all software counters */ + pub->rxgiants = 0; + pub->rxnobuf = 0; + pub->txnobuf = 0; +} + +/* get the address of the var in order to change later */ +unsigned long dma_getvar(struct dma_pub *pub, const char *name) +{ + struct dma_info *di = (struct dma_info *)pub; + + if (!strcmp(name, "&txavail")) + return (unsigned long)&(di->dma.txavail); + return 0; +} + +/* 64-bit DMA functions */ + +void dma_txinit(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + u32 control = D64_XC_XE; + + DMA_TRACE(("%s: dma_txinit\n", di->name)); + + if (di->ntxd == 0) + return; + + di->txin = di->txout = 0; + di->dma.txavail = di->ntxd - 1; + + /* clear tx descriptor ring */ + memset(di->txd64, '\0', (di->ntxd * sizeof(struct dma64desc))); + + /* DMA engine with out alignment requirement requires table to be inited + * before enabling the engine + */ + if (!di->aligndesc_4k) + _dma_ddtable_init(di, DMA_TX, di->txdpa); + + if ((di->dma.dmactrlflags & DMA_CTRL_PEN) == 0) + control |= D64_XC_PD; + OR_REG(&di->d64txregs->control, control); + + /* DMA engine with alignment requirement requires table to be inited + * before enabling the engine + */ + if (di->aligndesc_4k) + _dma_ddtable_init(di, DMA_TX, di->txdpa); +} + +void dma_txsuspend(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + + DMA_TRACE(("%s: dma_txsuspend\n", di->name)); + + if (di->ntxd == 0) + return; + + OR_REG(&di->d64txregs->control, D64_XC_SE); +} + +void dma_txresume(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + + DMA_TRACE(("%s: dma_txresume\n", di->name)); + + if (di->ntxd == 0) + return; + + AND_REG(&di->d64txregs->control, ~D64_XC_SE); +} + +bool dma_txsuspended(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + + return (di->ntxd == 0) || + ((R_REG(&di->d64txregs->control) & D64_XC_SE) == + D64_XC_SE); +} + +void dma_txreclaim(struct dma_pub *pub, enum txd_range range) +{ + struct dma_info *di = (struct dma_info *)pub; + struct sk_buff *p; + + DMA_TRACE(("%s: dma_txreclaim %s\n", di->name, + (range == DMA_RANGE_ALL) ? "all" : + ((range == + DMA_RANGE_TRANSMITTED) ? "transmitted" : + "transferred"))); + + if (di->txin == di->txout) + return; + + while ((p = dma_getnexttxp(pub, range))) { + /* For unframed data, we don't have any packets to free */ + if (!(di->dma.dmactrlflags & DMA_CTRL_UNFRAMED)) + brcmu_pkt_buf_free_skb(p); + } +} + +bool dma_txreset(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + u32 status; + + if (di->ntxd == 0) + return true; + + /* suspend tx DMA first */ + W_REG(&di->d64txregs->control, D64_XC_SE); + SPINWAIT(((status = + (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK)) + != D64_XS0_XS_DISABLED) && (status != D64_XS0_XS_IDLE) + && (status != D64_XS0_XS_STOPPED), 10000); + + W_REG(&di->d64txregs->control, 0); + SPINWAIT(((status = + (R_REG(&di->d64txregs->status0) & D64_XS0_XS_MASK)) + != D64_XS0_XS_DISABLED), 10000); + + /* wait for the last transaction to complete */ + udelay(300); + + return status == D64_XS0_XS_DISABLED; +} + +bool dma_rxreset(struct dma_pub *pub) +{ + struct dma_info *di = (struct dma_info *)pub; + u32 status; + + if (di->nrxd == 0) + return true; + + W_REG(&di->d64rxregs->control, 0); + SPINWAIT(((status = + (R_REG(&di->d64rxregs->status0) & D64_RS0_RS_MASK)) + != D64_RS0_RS_DISABLED), 10000); + + return status == D64_RS0_RS_DISABLED; +} + +/* + * !! tx entry routine + * WARNING: call must check the return value for error. + * the error(toss frames) could be fatal and cause many subsequent hard + * to debug problems + */ +int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit) +{ + struct dma_info *di = (struct dma_info *)pub; + struct sk_buff *p, *next; + unsigned char *data; + uint len; + u16 txout; + u32 flags = 0; + dma_addr_t pa; + + DMA_TRACE(("%s: dma_txfast\n", di->name)); + + txout = di->txout; + + /* + * Walk the chain of packet buffers + * allocating and initializing transmit descriptor entries. + */ + for (p = p0; p; p = next) { + data = p->data; + len = p->len; + next = p->next; + + /* return nonzero if out of tx descriptors */ + if (nexttxd(di, txout) == di->txin) + goto outoftxd; + + if (len == 0) + continue; + + /* get physical address of buffer start */ + pa = pci_map_single(di->pbus, data, len, PCI_DMA_TODEVICE); + + flags = 0; + if (p == p0) + flags |= D64_CTRL1_SOF; + + /* With a DMA segment list, Descriptor table is filled + * using the segment list instead of looping over + * buffers in multi-chain DMA. Therefore, EOF for SGLIST + * is when end of segment list is reached. + */ + if (next == NULL) + flags |= (D64_CTRL1_IOC | D64_CTRL1_EOF); + if (txout == (di->ntxd - 1)) + flags |= D64_CTRL1_EOT; + + dma64_dd_upd(di, di->txd64, pa, txout, &flags, len); + + txout = nexttxd(di, txout); + } + + /* if last txd eof not set, fix it */ + if (!(flags & D64_CTRL1_EOF)) + di->txd64[prevtxd(di, txout)].ctrl1 = + cpu_to_le32(flags | D64_CTRL1_IOC | D64_CTRL1_EOF); + + /* save the packet */ + di->txp[prevtxd(di, txout)] = p0; + + /* bump the tx descriptor index */ + di->txout = txout; + + /* kick the chip */ + if (commit) + W_REG(&di->d64txregs->ptr, + di->xmtptrbase + I2B(txout, struct dma64desc)); + + /* tx flow control */ + di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1; + + return 0; + + outoftxd: + DMA_ERROR(("%s: dma_txfast: out of txds !!!\n", di->name)); + brcmu_pkt_buf_free_skb(p0); + di->dma.txavail = 0; + di->dma.txnobuf++; + return -1; +} + +/* + * Reclaim next completed txd (txds if using chained buffers) in the range + * specified and return associated packet. + * If range is DMA_RANGE_TRANSMITTED, reclaim descriptors that have be + * transmitted as noted by the hardware "CurrDescr" pointer. + * If range is DMA_RANGE_TRANSFERED, reclaim descriptors that have be + * transferred by the DMA as noted by the hardware "ActiveDescr" pointer. + * If range is DMA_RANGE_ALL, reclaim all txd(s) posted to the ring and + * return associated packet regardless of the value of hardware pointers. + */ +struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range) +{ + struct dma_info *di = (struct dma_info *)pub; + u16 start, end, i; + u16 active_desc; + struct sk_buff *txp; + + DMA_TRACE(("%s: dma_getnexttxp %s\n", di->name, + (range == DMA_RANGE_ALL) ? "all" : + ((range == + DMA_RANGE_TRANSMITTED) ? "transmitted" : + "transferred"))); + + if (di->ntxd == 0) + return NULL; + + txp = NULL; + + start = di->txin; + if (range == DMA_RANGE_ALL) + end = di->txout; + else { + struct dma64regs __iomem *dregs = di->d64txregs; + + end = (u16) (B2I(((R_REG(&dregs->status0) & + D64_XS0_CD_MASK) - + di->xmtptrbase) & D64_XS0_CD_MASK, + struct dma64desc)); + + if (range == DMA_RANGE_TRANSFERED) { + active_desc = + (u16) (R_REG(&dregs->status1) & + D64_XS1_AD_MASK); + active_desc = + (active_desc - di->xmtptrbase) & D64_XS0_CD_MASK; + active_desc = B2I(active_desc, struct dma64desc); + if (end != active_desc) + end = prevtxd(di, active_desc); + } + } + + if ((start == 0) && (end > di->txout)) + goto bogus; + + for (i = start; i != end && !txp; i = nexttxd(di, i)) { + dma_addr_t pa; + uint size; + + pa = le32_to_cpu(di->txd64[i].addrlow) - di->dataoffsetlow; + + size = + (le32_to_cpu(di->txd64[i].ctrl2) & + D64_CTRL2_BC_MASK); + + di->txd64[i].addrlow = cpu_to_le32(0xdeadbeef); + di->txd64[i].addrhigh = cpu_to_le32(0xdeadbeef); + + txp = di->txp[i]; + di->txp[i] = NULL; + + pci_unmap_single(di->pbus, pa, size, PCI_DMA_TODEVICE); + } + + di->txin = i; + + /* tx flow control */ + di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1; + + return txp; + + bogus: + DMA_NONE(("dma_getnexttxp: bogus curr: start %d end %d txout %d " + "force %d\n", start, end, di->txout, forceall)); + return NULL; +} + +/* + * Mac80211 initiated actions sometimes require packets in the DMA queue to be + * modified. The modified portion of the packet is not under control of the DMA + * engine. This function calls a caller-supplied function for each packet in + * the caller specified dma chain. + */ +void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc) + (void *pkt, void *arg_a), void *arg_a) +{ + struct dma_info *di = (struct dma_info *) dmah; + uint i = di->txin; + uint end = di->txout; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + + while (i != end) { + skb = (struct sk_buff *)di->txp[i]; + if (skb != NULL) { + tx_info = (struct ieee80211_tx_info *)skb->cb; + (callback_fnc)(tx_info, arg_a); + } + i = nexttxd(di, i); + } +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.h b/drivers/net/wireless/brcm80211/brcmsmac/dma.h new file mode 100644 index 000000000000..ebc5bc546f3b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_DMA_H_ +#define _BRCM_DMA_H_ + +#include <linux/delay.h> +#include "types.h" /* forward structure declarations */ + +/* map/unmap direction */ +#define DMA_TX 1 /* TX direction for DMA */ +#define DMA_RX 2 /* RX direction for DMA */ + +/* DMA structure: + * support two DMA engines: 32 bits address or 64 bit addressing + * basic DMA register set is per channel(transmit or receive) + * a pair of channels is defined for convenience + */ + +/* 32 bits addressing */ + +struct dma32diag { /* diag access */ + u32 fifoaddr; /* diag address */ + u32 fifodatalow; /* low 32bits of data */ + u32 fifodatahigh; /* high 32bits of data */ + u32 pad; /* reserved */ +}; + +/* 64 bits addressing */ + +/* dma registers per channel(xmt or rcv) */ +struct dma64regs { + u32 control; /* enable, et al */ + u32 ptr; /* last descriptor posted to chip */ + u32 addrlow; /* desc ring base address low 32-bits (8K aligned) */ + u32 addrhigh; /* desc ring base address bits 63:32 (8K aligned) */ + u32 status0; /* current descriptor, xmt state */ + u32 status1; /* active descriptor, xmt error */ +}; + +/* range param for dma_getnexttxp() and dma_txreclaim */ +enum txd_range { + DMA_RANGE_ALL = 1, + DMA_RANGE_TRANSMITTED, + DMA_RANGE_TRANSFERED +}; + +/* + * Exported data structure (read-only) + */ +/* export structure */ +struct dma_pub { + uint txavail; /* # free tx descriptors */ + uint dmactrlflags; /* dma control flags */ + + /* rx error counters */ + uint rxgiants; /* rx giant frames */ + uint rxnobuf; /* rx out of dma descriptors */ + /* tx error counters */ + uint txnobuf; /* tx out of dma descriptors */ +}; + +extern struct dma_pub *dma_attach(char *name, struct si_pub *sih, + void __iomem *dmaregstx, void __iomem *dmaregsrx, + uint ntxd, uint nrxd, + uint rxbufsize, int rxextheadroom, + uint nrxpost, uint rxoffset, uint *msg_level); + +void dma_rxinit(struct dma_pub *pub); +struct sk_buff *dma_rx(struct dma_pub *pub); +bool dma_rxfill(struct dma_pub *pub); +bool dma_rxreset(struct dma_pub *pub); +bool dma_txreset(struct dma_pub *pub); +void dma_txinit(struct dma_pub *pub); +int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit); +void dma_txsuspend(struct dma_pub *pub); +bool dma_txsuspended(struct dma_pub *pub); +void dma_txresume(struct dma_pub *pub); +void dma_txreclaim(struct dma_pub *pub, enum txd_range range); +void dma_rxreclaim(struct dma_pub *pub); +void dma_detach(struct dma_pub *pub); +unsigned long dma_getvar(struct dma_pub *pub, const char *name); +struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range); +void dma_counterreset(struct dma_pub *pub); + +void dma_walk_packets(struct dma_pub *dmah, void (*callback_fnc) + (void *pkt, void *arg_a), void *arg_a); + +/* + * DMA(Bug) on bcm47xx chips seems to declare that the packet is ready, but + * the packet length is not updated yet (by DMA) on the expected time. + * Workaround is to hold processor till DMA updates the length, and stay off + * the bus to allow DMA update the length in buffer + */ +static inline void dma_spin_for_len(uint len, struct sk_buff *head) +{ +#if defined(CONFIG_BCM47XX) + if (!len) { + while (!(len = *(u16 *) KSEG1ADDR(head->data))) + udelay(1); + + *(u16 *) (head->data) = cpu_to_le16((u16) len); + } +#endif /* defined(CONFIG_BCM47XX) */ +} + +#endif /* _BRCM_DMA_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c new file mode 100644 index 000000000000..ac8d02bd34f2 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -0,0 +1,1696 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +#define __UNDEF_NO_VERSION__ + +#include <linux/etherdevice.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/firmware.h> +#include <linux/interrupt.h> +#include <net/mac80211.h> +#include <defs.h> +#include "nicpci.h" +#include "phy/phy_int.h" +#include "d11.h" +#include "channel.h" +#include "scb.h" +#include "pub.h" +#include "ucode_loader.h" +#include "mac80211_if.h" +#include "main.h" + +#define N_TX_QUEUES 4 /* #tx queues on mac80211<->driver interface */ + +/* Flags we support */ +#define MAC_FILTERS (FIF_PROMISC_IN_BSS | \ + FIF_ALLMULTI | \ + FIF_FCSFAIL | \ + FIF_PLCPFAIL | \ + FIF_CONTROL | \ + FIF_OTHER_BSS | \ + FIF_BCN_PRBRESP_PROMISC) + +#define CHAN2GHZ(channel, freqency, chflags) { \ + .band = IEEE80211_BAND_2GHZ, \ + .center_freq = (freqency), \ + .hw_value = (channel), \ + .flags = chflags, \ + .max_antenna_gain = 0, \ + .max_power = 19, \ +} + +#define CHAN5GHZ(channel, chflags) { \ + .band = IEEE80211_BAND_5GHZ, \ + .center_freq = 5000 + 5*(channel), \ + .hw_value = (channel), \ + .flags = chflags, \ + .max_antenna_gain = 0, \ + .max_power = 21, \ +} + +#define RATE(rate100m, _flags) { \ + .bitrate = (rate100m), \ + .flags = (_flags), \ + .hw_value = (rate100m / 5), \ +} + +struct firmware_hdr { + __le32 offset; + __le32 len; + __le32 idx; +}; + +static const char * const brcms_firmwares[MAX_FW_IMAGES] = { + "brcm/bcm43xx", + NULL +}; + +static int n_adapters_found; + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver."); +MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); +MODULE_LICENSE("Dual BSD/GPL"); + +/* recognized PCI IDs */ +static DEFINE_PCI_DEVICE_TABLE(brcms_pci_id_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, /* 43225 2G */ + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, /* 43224 DUAL */ + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, /* 4313 DUAL */ + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, /* 43224 Ven */ + {0} +}; + +MODULE_DEVICE_TABLE(pci, brcms_pci_id_table); + +#ifdef BCMDBG +static int msglevel = 0xdeadbeef; +module_param(msglevel, int, 0); +#endif /* BCMDBG */ + +static struct ieee80211_channel brcms_2ghz_chantable[] = { + CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS), + CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS), + CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS), + CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS), + CHAN2GHZ(5, 2432, 0), + CHAN2GHZ(6, 2437, 0), + CHAN2GHZ(7, 2442, 0), + CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS), + CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS), + CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS), + CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS), + CHAN2GHZ(12, 2467, + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_HT40PLUS), + CHAN2GHZ(13, 2472, + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_HT40PLUS), + CHAN2GHZ(14, 2484, + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) +}; + +static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = { + /* UNII-1 */ + CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS), + /* UNII-2 */ + CHAN5GHZ(52, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(56, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(60, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(64, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + /* MID */ + CHAN5GHZ(100, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(104, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(108, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(112, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(116, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(120, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(124, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(128, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(132, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(136, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(140, + IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS | + IEEE80211_CHAN_NO_HT40MINUS), + /* UNII-3 */ + CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS), + CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS), + CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS) +}; + +/* + * The rate table is used for both 2.4G and 5G rates. The + * latter being a subset as it does not support CCK rates. + */ +static struct ieee80211_rate legacy_ratetable[] = { + RATE(10, 0), + RATE(20, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(55, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(110, IEEE80211_RATE_SHORT_PREAMBLE), + RATE(60, 0), + RATE(90, 0), + RATE(120, 0), + RATE(180, 0), + RATE(240, 0), + RATE(360, 0), + RATE(480, 0), + RATE(540, 0), +}; + +static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = { + .band = IEEE80211_BAND_2GHZ, + .channels = brcms_2ghz_chantable, + .n_channels = ARRAY_SIZE(brcms_2ghz_chantable), + .bitrates = legacy_ratetable, + .n_bitrates = ARRAY_SIZE(legacy_ratetable), + .ht_cap = { + /* from include/linux/ieee80211.h */ + .cap = IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT, + .ht_supported = true, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ampdu_density = AMPDU_DEF_MPDU_DENSITY, + .mcs = { + /* placeholders for now */ + .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, + .rx_highest = cpu_to_le16(500), + .tx_params = IEEE80211_HT_MCS_TX_DEFINED} + } +}; + +static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = { + .band = IEEE80211_BAND_5GHZ, + .channels = brcms_5ghz_nphy_chantable, + .n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable), + .bitrates = legacy_ratetable + BRCMS_LEGACY_5G_RATE_OFFSET, + .n_bitrates = ARRAY_SIZE(legacy_ratetable) - + BRCMS_LEGACY_5G_RATE_OFFSET, + .ht_cap = { + .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */ + .ht_supported = true, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ampdu_density = AMPDU_DEF_MPDU_DENSITY, + .mcs = { + /* placeholders for now */ + .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0}, + .rx_highest = cpu_to_le16(500), + .tx_params = IEEE80211_HT_MCS_TX_DEFINED} + } +}; + +/* flags the given rate in rateset as requested */ +static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br) +{ + u32 i; + + for (i = 0; i < rs->count; i++) { + if (rate != (rs->rates[i] & 0x7f)) + continue; + + if (is_br) + rs->rates[i] |= BRCMS_RATE_FLAG; + else + rs->rates[i] &= BRCMS_RATE_MASK; + return; + } +} + +static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + struct brcms_info *wl = hw->priv; + + spin_lock_bh(&wl->lock); + if (!wl->pub->up) { + wiphy_err(wl->wiphy, "ops->tx called while down\n"); + kfree_skb(skb); + goto done; + } + brcms_c_sendpkt_mac80211(wl->wlc, skb, hw); + done: + spin_unlock_bh(&wl->lock); +} + +static int brcms_ops_start(struct ieee80211_hw *hw) +{ + struct brcms_info *wl = hw->priv; + bool blocked; + + ieee80211_wake_queues(hw); + spin_lock_bh(&wl->lock); + blocked = brcms_rfkill_set_hw_state(wl); + spin_unlock_bh(&wl->lock); + if (!blocked) + wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); + + return 0; +} + +static void brcms_ops_stop(struct ieee80211_hw *hw) +{ + ieee80211_stop_queues(hw); +} + +static int +brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct brcms_info *wl; + int err; + + /* Just STA for now */ + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_MESH_POINT && + vif->type != NL80211_IFTYPE_STATION && + vif->type != NL80211_IFTYPE_WDS && + vif->type != NL80211_IFTYPE_ADHOC) { + wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only" + " STA for now\n", __func__, vif->type); + return -EOPNOTSUPP; + } + + wl = hw->priv; + spin_lock_bh(&wl->lock); + if (!wl->pub->up) + err = brcms_up(wl); + else + err = -ENODEV; + spin_unlock_bh(&wl->lock); + + if (err != 0) + wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__, + err); + + return err; +} + +static void +brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct brcms_info *wl; + + wl = hw->priv; + + /* put driver in down state */ + spin_lock_bh(&wl->lock); + brcms_down(wl); + spin_unlock_bh(&wl->lock); +} + +static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) +{ + struct ieee80211_conf *conf = &hw->conf; + struct brcms_info *wl = hw->priv; + int err = 0; + int new_int; + struct wiphy *wiphy = hw->wiphy; + + spin_lock_bh(&wl->lock); + if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) { + brcms_c_set_beacon_listen_interval(wl->wlc, + conf->listen_interval); + } + if (changed & IEEE80211_CONF_CHANGE_MONITOR) + wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n", + __func__, conf->flags & IEEE80211_CONF_MONITOR ? + "true" : "false"); + if (changed & IEEE80211_CONF_CHANGE_PS) + wiphy_err(wiphy, "%s: change power-save mode: %s (implement)\n", + __func__, conf->flags & IEEE80211_CONF_PS ? + "true" : "false"); + + if (changed & IEEE80211_CONF_CHANGE_POWER) { + err = brcms_c_set_tx_power(wl->wlc, conf->power_level); + if (err < 0) { + wiphy_err(wiphy, "%s: Error setting power_level\n", + __func__); + goto config_out; + } + new_int = brcms_c_get_tx_power(wl->wlc); + if (new_int != conf->power_level) + wiphy_err(wiphy, "%s: Power level req != actual, %d %d" + "\n", __func__, conf->power_level, + new_int); + } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + if (conf->channel_type == NL80211_CHAN_HT20 || + conf->channel_type == NL80211_CHAN_NO_HT) + err = brcms_c_set_channel(wl->wlc, + conf->channel->hw_value); + else + err = -ENOTSUPP; + } + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + err = brcms_c_set_rate_limit(wl->wlc, + conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); + + config_out: + spin_unlock_bh(&wl->lock); + return err; +} + +static void +brcms_ops_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct brcms_info *wl = hw->priv; + struct wiphy *wiphy = hw->wiphy; + + if (changed & BSS_CHANGED_ASSOC) { + /* association status changed (associated/disassociated) + * also implies a change in the AID. + */ + wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME, + __func__, info->assoc ? "" : "dis"); + spin_lock_bh(&wl->lock); + brcms_c_associate_upd(wl->wlc, info->assoc); + spin_unlock_bh(&wl->lock); + } + if (changed & BSS_CHANGED_ERP_SLOT) { + s8 val; + + /* slot timing changed */ + if (info->use_short_slot) + val = 1; + else + val = 0; + spin_lock_bh(&wl->lock); + brcms_c_set_shortslot_override(wl->wlc, val); + spin_unlock_bh(&wl->lock); + } + + if (changed & BSS_CHANGED_HT) { + /* 802.11n parameters changed */ + u16 mode = info->ht_operation_mode; + + spin_lock_bh(&wl->lock); + brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_CFG, + mode & IEEE80211_HT_OP_MODE_PROTECTION); + brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_NONGF, + mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + brcms_c_protection_upd(wl->wlc, BRCMS_PROT_N_OBSS, + mode & IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT); + spin_unlock_bh(&wl->lock); + } + if (changed & BSS_CHANGED_BASIC_RATES) { + struct ieee80211_supported_band *bi; + u32 br_mask, i; + u16 rate; + struct brcm_rateset rs; + int error; + + /* retrieve the current rates */ + spin_lock_bh(&wl->lock); + brcms_c_get_current_rateset(wl->wlc, &rs); + spin_unlock_bh(&wl->lock); + + br_mask = info->basic_rates; + bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)]; + for (i = 0; i < bi->n_bitrates; i++) { + /* convert to internal rate value */ + rate = (bi->bitrates[i].bitrate << 1) / 10; + + /* set/clear basic rate flag */ + brcms_set_basic_rate(&rs, rate, br_mask & 1); + br_mask >>= 1; + } + + /* update the rate set */ + spin_lock_bh(&wl->lock); + error = brcms_c_set_rateset(wl->wlc, &rs); + spin_unlock_bh(&wl->lock); + if (error) + wiphy_err(wiphy, "changing basic rates failed: %d\n", + error); + } + if (changed & BSS_CHANGED_BEACON_INT) { + /* Beacon interval changed */ + spin_lock_bh(&wl->lock); + brcms_c_set_beacon_period(wl->wlc, info->beacon_int); + spin_unlock_bh(&wl->lock); + } + if (changed & BSS_CHANGED_BSSID) { + /* BSSID changed, for whatever reason (IBSS and managed mode) */ + spin_lock_bh(&wl->lock); + brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid); + spin_unlock_bh(&wl->lock); + } + if (changed & BSS_CHANGED_BEACON) + /* Beacon data changed, retrieve new beacon (beaconing modes) */ + wiphy_err(wiphy, "%s: beacon changed\n", __func__); + + if (changed & BSS_CHANGED_BEACON_ENABLED) { + /* Beaconing should be enabled/disabled (beaconing modes) */ + wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__, + info->enable_beacon ? "true" : "false"); + } + + if (changed & BSS_CHANGED_CQM) { + /* Connection quality monitor config changed */ + wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d " + " (implement)\n", __func__, info->cqm_rssi_thold, + info->cqm_rssi_hyst); + } + + if (changed & BSS_CHANGED_IBSS) { + /* IBSS join status changed */ + wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__, + info->ibss_joined ? "true" : "false"); + } + + if (changed & BSS_CHANGED_ARP_FILTER) { + /* Hardware ARP filter address list or state changed */ + wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d" + " (implement)\n", __func__, info->arp_filter_enabled ? + "true" : "false", info->arp_addr_cnt); + } + + if (changed & BSS_CHANGED_QOS) { + /* + * QoS for this association was enabled/disabled. + * Note that it is only ever disabled for station mode. + */ + wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__, + info->qos ? "true" : "false"); + } + return; +} + +static void +brcms_ops_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, u64 multicast) +{ + struct brcms_info *wl = hw->priv; + struct wiphy *wiphy = hw->wiphy; + + changed_flags &= MAC_FILTERS; + *total_flags &= MAC_FILTERS; + if (changed_flags & FIF_PROMISC_IN_BSS) + wiphy_err(wiphy, "FIF_PROMISC_IN_BSS\n"); + if (changed_flags & FIF_ALLMULTI) + wiphy_err(wiphy, "FIF_ALLMULTI\n"); + if (changed_flags & FIF_FCSFAIL) + wiphy_err(wiphy, "FIF_FCSFAIL\n"); + if (changed_flags & FIF_PLCPFAIL) + wiphy_err(wiphy, "FIF_PLCPFAIL\n"); + if (changed_flags & FIF_CONTROL) + wiphy_err(wiphy, "FIF_CONTROL\n"); + if (changed_flags & FIF_OTHER_BSS) + wiphy_err(wiphy, "FIF_OTHER_BSS\n"); + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + spin_lock_bh(&wl->lock); + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) { + wl->pub->mac80211_state |= MAC80211_PROMISC_BCNS; + brcms_c_mac_bcn_promisc_change(wl->wlc, 1); + } else { + brcms_c_mac_bcn_promisc_change(wl->wlc, 0); + wl->pub->mac80211_state &= ~MAC80211_PROMISC_BCNS; + } + spin_unlock_bh(&wl->lock); + } + return; +} + +static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw) +{ + struct brcms_info *wl = hw->priv; + spin_lock_bh(&wl->lock); + brcms_c_scan_start(wl->wlc); + spin_unlock_bh(&wl->lock); + return; +} + +static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw) +{ + struct brcms_info *wl = hw->priv; + spin_lock_bh(&wl->lock); + brcms_c_scan_stop(wl->wlc); + spin_unlock_bh(&wl->lock); + return; +} + +static int +brcms_ops_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct brcms_info *wl = hw->priv; + + spin_lock_bh(&wl->lock); + brcms_c_wme_setparams(wl->wlc, queue, params, true); + spin_unlock_bh(&wl->lock); + + return 0; +} + +static int +brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct brcms_info *wl = hw->priv; + struct scb *scb = &wl->wlc->pri_scb; + + brcms_c_init_scb(scb); + + wl->pub->global_ampdu = &(scb->scb_ampdu); + wl->pub->global_ampdu->scb = scb; + wl->pub->global_ampdu->max_pdu = 16; + + sta->ht_cap.ht_supported = true; + sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY; + sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD | + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT; + + /* + * minstrel_ht initiates addBA on our behalf by calling + * ieee80211_start_tx_ba_session() + */ + return 0; +} + +static int +brcms_ops_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 brcms_info *wl = hw->priv; + struct scb *scb = &wl->wlc->pri_scb; + int status; + + if (WARN_ON(scb->magic != SCB_MAGIC)) + return -EIDRM; + switch (action) { + case IEEE80211_AMPDU_RX_START: + break; + case IEEE80211_AMPDU_RX_STOP: + break; + case IEEE80211_AMPDU_TX_START: + spin_lock_bh(&wl->lock); + status = brcms_c_aggregatable(wl->wlc, tid); + spin_unlock_bh(&wl->lock); + if (!status) { + wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n", + tid); + return -EINVAL; + } + ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + + case IEEE80211_AMPDU_TX_STOP: + spin_lock_bh(&wl->lock); + brcms_c_ampdu_flush(wl->wlc, sta, tid); + spin_unlock_bh(&wl->lock); + ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + /* + * BA window size from ADDBA response ('buf_size') defines how + * many outstanding MPDUs are allowed for the BA stream by + * recipient and traffic class. 'ampdu_factor' gives maximum + * AMPDU size. + */ + spin_lock_bh(&wl->lock); + brcms_c_ampdu_tx_operational(wl->wlc, tid, buf_size, + (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + + sta->ht_cap.ampdu_factor)) - 1); + spin_unlock_bh(&wl->lock); + /* Power save wakeup */ + break; + default: + wiphy_err(wl->wiphy, "%s: Invalid command, ignoring\n", + __func__); + } + + return 0; +} + +static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw) +{ + struct brcms_info *wl = hw->priv; + bool blocked; + + spin_lock_bh(&wl->lock); + blocked = brcms_c_check_radio_disabled(wl->wlc); + spin_unlock_bh(&wl->lock); + + wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); +} + +static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop) +{ + struct brcms_info *wl = hw->priv; + + no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); + + /* wait for packet queue and dma fifos to run empty */ + spin_lock_bh(&wl->lock); + brcms_c_wait_for_tx_completion(wl->wlc, drop); + spin_unlock_bh(&wl->lock); +} + +static const struct ieee80211_ops brcms_ops = { + .tx = brcms_ops_tx, + .start = brcms_ops_start, + .stop = brcms_ops_stop, + .add_interface = brcms_ops_add_interface, + .remove_interface = brcms_ops_remove_interface, + .config = brcms_ops_config, + .bss_info_changed = brcms_ops_bss_info_changed, + .configure_filter = brcms_ops_configure_filter, + .sw_scan_start = brcms_ops_sw_scan_start, + .sw_scan_complete = brcms_ops_sw_scan_complete, + .conf_tx = brcms_ops_conf_tx, + .sta_add = brcms_ops_sta_add, + .ampdu_action = brcms_ops_ampdu_action, + .rfkill_poll = brcms_ops_rfkill_poll, + .flush = brcms_ops_flush, +}; + +/* + * is called in brcms_pci_probe() context, therefore no locking required. + */ +static int brcms_set_hint(struct brcms_info *wl, char *abbrev) +{ + return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev); +} + +void brcms_dpc(unsigned long data) +{ + struct brcms_info *wl; + + wl = (struct brcms_info *) data; + + spin_lock_bh(&wl->lock); + + /* call the common second level interrupt handler */ + if (wl->pub->up) { + if (wl->resched) { + unsigned long flags; + + spin_lock_irqsave(&wl->isr_lock, flags); + brcms_c_intrsupd(wl->wlc); + spin_unlock_irqrestore(&wl->isr_lock, flags); + } + + wl->resched = brcms_c_dpc(wl->wlc, true); + } + + /* brcms_c_dpc() may bring the driver down */ + if (!wl->pub->up) + goto done; + + /* re-schedule dpc */ + if (wl->resched) + tasklet_schedule(&wl->tasklet); + else + /* re-enable interrupts */ + brcms_intrson(wl); + + done: + spin_unlock_bh(&wl->lock); +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev) +{ + int status; + struct device *device = &pdev->dev; + char fw_name[100]; + int i; + + memset(&wl->fw, 0, sizeof(struct brcms_firmware)); + for (i = 0; i < MAX_FW_IMAGES; i++) { + if (brcms_firmwares[i] == NULL) + break; + sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i], + UCODE_LOADER_API_VER); + status = request_firmware(&wl->fw.fw_bin[i], fw_name, device); + if (status) { + wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", + KBUILD_MODNAME, fw_name); + return status; + } + sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i], + UCODE_LOADER_API_VER); + status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device); + if (status) { + wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n", + KBUILD_MODNAME, fw_name); + return status; + } + wl->fw.hdr_num_entries[i] = + wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr)); + } + wl->fw.fw_cnt = i; + return brcms_ucode_data_init(wl, &wl->ucode); +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +static void brcms_release_fw(struct brcms_info *wl) +{ + int i; + for (i = 0; i < MAX_FW_IMAGES; i++) { + release_firmware(wl->fw.fw_bin[i]); + release_firmware(wl->fw.fw_hdr[i]); + } +} + +/** + * This function frees the WL per-device resources. + * + * This function frees resources owned by the WL device pointed to + * by the wl parameter. + * + * precondition: can both be called locked and unlocked + * + */ +static void brcms_free(struct brcms_info *wl) +{ + struct brcms_timer *t, *next; + + /* free ucode data */ + if (wl->fw.fw_cnt) + brcms_ucode_data_free(&wl->ucode); + if (wl->irq) + free_irq(wl->irq, wl); + + /* kill dpc */ + tasklet_kill(&wl->tasklet); + + if (wl->pub) + brcms_c_module_unregister(wl->pub, "linux", wl); + + /* free common resources */ + if (wl->wlc) { + brcms_c_detach(wl->wlc); + wl->wlc = NULL; + wl->pub = NULL; + } + + /* virtual interface deletion is deferred so we cannot spinwait */ + + /* wait for all pending callbacks to complete */ + while (atomic_read(&wl->callbacks) > 0) + schedule(); + + /* free timers */ + for (t = wl->timers; t; t = next) { + next = t->next; +#ifdef BCMDBG + kfree(t->name); +#endif + kfree(t); + } + + /* + * unregister_netdev() calls get_stats() which may read chip + * registers so we cannot unmap the chip registers until + * after calling unregister_netdev() . + */ + if (wl->regsva) + iounmap(wl->regsva); + + wl->regsva = NULL; +} + +/* +* called from both kernel as from this kernel module. +* precondition: perimeter lock is not acquired. +*/ +static void brcms_remove(struct pci_dev *pdev) +{ + struct brcms_info *wl; + struct ieee80211_hw *hw; + int status; + + hw = pci_get_drvdata(pdev); + wl = hw->priv; + if (!wl) { + pr_err("wl: brcms_remove: pci_get_drvdata failed\n"); + return; + } + + spin_lock_bh(&wl->lock); + status = brcms_c_chipmatch(pdev->vendor, pdev->device); + spin_unlock_bh(&wl->lock); + if (!status) { + wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch " + "failed\n"); + return; + } + if (wl->wlc) { + wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false); + wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy); + ieee80211_unregister_hw(hw); + spin_lock_bh(&wl->lock); + brcms_down(wl); + spin_unlock_bh(&wl->lock); + } + pci_disable_device(pdev); + + brcms_free(wl); + + pci_set_drvdata(pdev, NULL); + ieee80211_free_hw(hw); +} + +static irqreturn_t brcms_isr(int irq, void *dev_id) +{ + struct brcms_info *wl; + bool ours, wantdpc; + + wl = (struct brcms_info *) dev_id; + + spin_lock(&wl->isr_lock); + + /* call common first level interrupt handler */ + ours = brcms_c_isr(wl->wlc, &wantdpc); + if (ours) { + /* if more to do... */ + if (wantdpc) { + + /* ...and call the second level interrupt handler */ + /* schedule dpc */ + tasklet_schedule(&wl->tasklet); + } + } + + spin_unlock(&wl->isr_lock); + + return IRQ_RETVAL(ours); +} + +/* + * is called in brcms_pci_probe() context, therefore no locking required. + */ +static int ieee_hw_rate_init(struct ieee80211_hw *hw) +{ + struct brcms_info *wl = hw->priv; + struct brcms_c_info *wlc = wl->wlc; + struct ieee80211_supported_band *band; + int has_5g = 0; + u16 phy_type; + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + + phy_type = brcms_c_get_phy_type(wl->wlc, 0); + if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) { + band = &wlc->bandstate[BAND_2G_INDEX]->band; + *band = brcms_band_2GHz_nphy_template; + if (phy_type == PHY_TYPE_LCN) { + /* Single stream */ + band->ht_cap.mcs.rx_mask[1] = 0; + band->ht_cap.mcs.rx_highest = cpu_to_le16(72); + } + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band; + } else { + return -EPERM; + } + + /* Assume all bands use the same phy. True for 11n devices. */ + if (wl->pub->_nbands > 1) { + has_5g++; + if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) { + band = &wlc->bandstate[BAND_5G_INDEX]->band; + *band = brcms_band_5GHz_nphy_template; + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = band; + } else { + return -EPERM; + } + } + return 0; +} + +/* + * is called in brcms_pci_probe() context, therefore no locking required. + */ +static int ieee_hw_init(struct ieee80211_hw *hw) +{ + hw->flags = IEEE80211_HW_SIGNAL_DBM + /* | IEEE80211_HW_CONNECTION_MONITOR What is this? */ + | IEEE80211_HW_REPORTS_TX_ACK_STATUS + | IEEE80211_HW_AMPDU_AGGREGATION; + + hw->extra_tx_headroom = brcms_c_get_header_len(); + hw->queues = N_TX_QUEUES; + hw->max_rates = 2; /* Primary rate and 1 fallback rate */ + + /* channel change time is dependent on chip and band */ + hw->channel_change_time = 7 * 1000; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + + hw->rate_control_algorithm = "minstrel_ht"; + + hw->sta_data_size = 0; + return ieee_hw_rate_init(hw); +} + +/** + * attach to the WL device. + * + * Attach to the WL device identified by vendor and device parameters. + * regs is a host accessible memory address pointing to WL device registers. + * + * brcms_attach is not defined as static because in the case where no bus + * is defined, wl_attach will never be called, and thus, gcc will issue + * a warning that this function is defined but not used if we declare + * it as static. + * + * + * is called in brcms_pci_probe() context, therefore no locking required. + */ +static struct brcms_info *brcms_attach(u16 vendor, u16 device, + resource_size_t regs, + struct pci_dev *btparam, uint irq) +{ + struct brcms_info *wl = NULL; + int unit, err; + struct ieee80211_hw *hw; + u8 perm[ETH_ALEN]; + + unit = n_adapters_found; + err = 0; + + if (unit < 0) + return NULL; + + /* allocate private info */ + hw = pci_get_drvdata(btparam); /* btparam == pdev */ + if (hw != NULL) + wl = hw->priv; + if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL)) + return NULL; + wl->wiphy = hw->wiphy; + + atomic_set(&wl->callbacks, 0); + + /* setup the bottom half handler */ + tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); + + wl->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ); + if (wl->regsva == NULL) { + wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit); + goto fail; + } + spin_lock_init(&wl->lock); + spin_lock_init(&wl->isr_lock); + + /* prepare ucode */ + if (brcms_request_fw(wl, btparam) < 0) { + wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " + "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); + brcms_release_fw(wl); + brcms_remove(btparam); + return NULL; + } + + /* common load-time initialization */ + wl->wlc = brcms_c_attach(wl, vendor, device, unit, false, + wl->regsva, btparam, &err); + brcms_release_fw(wl); + if (!wl->wlc) { + wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n", + KBUILD_MODNAME, err); + goto fail; + } + wl->pub = brcms_c_pub(wl->wlc); + + wl->pub->ieee_hw = hw; + + /* disable mpc */ + brcms_c_set_radio_mpc(wl->wlc, false); + + /* register our interrupt handler */ + if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { + wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit); + goto fail; + } + wl->irq = irq; + + /* register module */ + brcms_c_module_register(wl->pub, "linux", wl, NULL); + + if (ieee_hw_init(hw)) { + wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit, + __func__); + goto fail; + } + + memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN); + if (WARN_ON(!is_valid_ether_addr(perm))) + goto fail; + SET_IEEE80211_PERM_ADDR(hw, perm); + + err = ieee80211_register_hw(hw); + if (err) + wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" + "%d\n", __func__, err); + + if (wl->pub->srom_ccode[0]) + err = brcms_set_hint(wl, wl->pub->srom_ccode); + else + err = brcms_set_hint(wl, "US"); + if (err) + wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n", + __func__, err); + + n_adapters_found++; + return wl; + +fail: + brcms_free(wl); + return NULL; +} + + + +/** + * determines if a device is a WL device, and if so, attaches it. + * + * This function determines if a device pointed to by pdev is a WL device, + * and if so, performs a brcms_attach() on it. + * + * Perimeter lock is initialized in the course of this function. + */ +static int __devinit +brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc; + struct brcms_info *wl; + struct ieee80211_hw *hw; + u32 val; + + dev_info(&pdev->dev, "bus %d slot %d func %d irq %d\n", + pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), pdev->irq); + + if ((pdev->vendor != PCI_VENDOR_ID_BROADCOM) || + ((pdev->device != 0x0576) && + ((pdev->device & 0xff00) != 0x4300) && + ((pdev->device & 0xff00) != 0x4700) && + ((pdev->device < 43000) || (pdev->device > 43999)))) + return -ENODEV; + + rc = pci_enable_device(pdev); + if (rc) { + pr_err("%s: Cannot enable device %d-%d_%d\n", + __func__, pdev->bus->number, PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); + return -ENODEV; + } + pci_set_master(pdev); + + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + + hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops); + if (!hw) { + pr_err("%s: ieee80211_alloc_hw failed\n", __func__); + return -ENOMEM; + } + + SET_IEEE80211_DEV(hw, &pdev->dev); + + pci_set_drvdata(pdev, hw); + + memset(hw->priv, 0, sizeof(*wl)); + + wl = brcms_attach(pdev->vendor, pdev->device, + pci_resource_start(pdev, 0), pdev, + pdev->irq); + + if (!wl) { + pr_err("%s: %s: brcms_attach failed!\n", KBUILD_MODNAME, + __func__); + return -ENODEV; + } + return 0; +} + +static int brcms_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct brcms_info *wl; + struct ieee80211_hw *hw; + + hw = pci_get_drvdata(pdev); + wl = hw->priv; + if (!wl) { + wiphy_err(wl->wiphy, + "brcms_suspend: pci_get_drvdata failed\n"); + return -ENODEV; + } + + /* only need to flag hw is down for proper resume */ + spin_lock_bh(&wl->lock); + wl->pub->hw_up = false; + spin_unlock_bh(&wl->lock); + + pci_save_state(pdev); + pci_disable_device(pdev); + return pci_set_power_state(pdev, PCI_D3hot); +} + +static int brcms_resume(struct pci_dev *pdev) +{ + struct brcms_info *wl; + struct ieee80211_hw *hw; + int err = 0; + u32 val; + + hw = pci_get_drvdata(pdev); + wl = hw->priv; + if (!wl) { + wiphy_err(wl->wiphy, + "wl: brcms_resume: pci_get_drvdata failed\n"); + return -ENODEV; + } + + err = pci_set_power_state(pdev, PCI_D0); + if (err) + return err; + + pci_restore_state(pdev); + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_set_master(pdev); + + pci_read_config_dword(pdev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); + + /* + * done. driver will be put in up state + * in brcms_ops_add_interface() call. + */ + return err; +} + +static struct pci_driver brcms_pci_driver = { + .name = KBUILD_MODNAME, + .probe = brcms_pci_probe, + .suspend = brcms_suspend, + .resume = brcms_resume, + .remove = __devexit_p(brcms_remove), + .id_table = brcms_pci_id_table, +}; + +/** + * This is the main entry point for the WL driver. + * + * This function determines if a device pointed to by pdev is a WL device, + * and if so, performs a brcms_attach() on it. + * + */ +static int __init brcms_module_init(void) +{ + int error = -ENODEV; + +#ifdef BCMDBG + if (msglevel != 0xdeadbeef) + brcm_msg_level = msglevel; +#endif /* BCMDBG */ + + error = pci_register_driver(&brcms_pci_driver); + if (!error) + return 0; + + + + return error; +} + +/** + * This function unloads the WL driver from the system. + * + * This function unconditionally unloads the WL driver module from the + * system. + * + */ +static void __exit brcms_module_exit(void) +{ + pci_unregister_driver(&brcms_pci_driver); + +} + +module_init(brcms_module_init); +module_exit(brcms_module_exit); + +/* + * precondition: perimeter lock has been acquired + */ +void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, + bool state, int prio) +{ + wiphy_err(wl->wiphy, "Shouldn't be here %s\n", __func__); +} + +/* + * precondition: perimeter lock has been acquired + */ +void brcms_init(struct brcms_info *wl) +{ + BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit); + brcms_reset(wl); + + brcms_c_init(wl->wlc); +} + +/* + * precondition: perimeter lock has been acquired + */ +uint brcms_reset(struct brcms_info *wl) +{ + BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit); + brcms_c_reset(wl->wlc); + + /* dpc will not be rescheduled */ + wl->resched = 0; + + return 0; +} + +/* + * These are interrupt on/off entry points. Disable interrupts + * during interrupt state transition. + */ +void brcms_intrson(struct brcms_info *wl) +{ + unsigned long flags; + + spin_lock_irqsave(&wl->isr_lock, flags); + brcms_c_intrson(wl->wlc); + spin_unlock_irqrestore(&wl->isr_lock, flags); +} + +u32 brcms_intrsoff(struct brcms_info *wl) +{ + unsigned long flags; + u32 status; + + spin_lock_irqsave(&wl->isr_lock, flags); + status = brcms_c_intrsoff(wl->wlc); + spin_unlock_irqrestore(&wl->isr_lock, flags); + return status; +} + +void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask) +{ + unsigned long flags; + + spin_lock_irqsave(&wl->isr_lock, flags); + brcms_c_intrsrestore(wl->wlc, macintmask); + spin_unlock_irqrestore(&wl->isr_lock, flags); +} + +/* + * precondition: perimeter lock has been acquired + */ +int brcms_up(struct brcms_info *wl) +{ + int error = 0; + + if (wl->pub->up) + return 0; + + error = brcms_c_up(wl->wlc); + + return error; +} + +/* + * precondition: perimeter lock has been acquired + */ +void brcms_down(struct brcms_info *wl) +{ + uint callbacks, ret_val = 0; + + /* call common down function */ + ret_val = brcms_c_down(wl->wlc); + callbacks = atomic_read(&wl->callbacks) - ret_val; + + /* wait for down callbacks to complete */ + spin_unlock_bh(&wl->lock); + + /* For HIGH_only driver, it's important to actually schedule other work, + * not just spin wait since everything runs at schedule level + */ + SPINWAIT((atomic_read(&wl->callbacks) > callbacks), 100 * 1000); + + spin_lock_bh(&wl->lock); +} + +/* +* precondition: perimeter lock is not acquired + */ +static void _brcms_timer(struct work_struct *work) +{ + struct brcms_timer *t = container_of(work, struct brcms_timer, + dly_wrk.work); + + spin_lock_bh(&t->wl->lock); + + if (t->set) { + if (t->periodic) { + atomic_inc(&t->wl->callbacks); + ieee80211_queue_delayed_work(t->wl->pub->ieee_hw, + &t->dly_wrk, + msecs_to_jiffies(t->ms)); + } else { + t->set = false; + } + + t->fn(t->arg); + } + + atomic_dec(&t->wl->callbacks); + + spin_unlock_bh(&t->wl->lock); +} + +/* + * Adds a timer to the list. Caller supplies a timer function. + * Is called from wlc. + * + * precondition: perimeter lock has been acquired + */ +struct brcms_timer *brcms_init_timer(struct brcms_info *wl, + void (*fn) (void *arg), + void *arg, const char *name) +{ + struct brcms_timer *t; + + t = kzalloc(sizeof(struct brcms_timer), GFP_ATOMIC); + if (!t) + return NULL; + + INIT_DELAYED_WORK(&t->dly_wrk, _brcms_timer); + t->wl = wl; + t->fn = fn; + t->arg = arg; + t->next = wl->timers; + wl->timers = t; + +#ifdef BCMDBG + t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC); + if (t->name) + strcpy(t->name, name); +#endif + + return t; +} + +/* + * adds only the kernel timer since it's going to be more accurate + * as well as it's easier to make it periodic + * + * precondition: perimeter lock has been acquired + */ +void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic) +{ + struct ieee80211_hw *hw = t->wl->pub->ieee_hw; + +#ifdef BCMDBG + if (t->set) + wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n", + __func__, t->name, periodic); +#endif + t->ms = ms; + t->periodic = (bool) periodic; + t->set = true; + + atomic_inc(&t->wl->callbacks); + + ieee80211_queue_delayed_work(hw, &t->dly_wrk, msecs_to_jiffies(ms)); +} + +/* + * return true if timer successfully deleted, false if still pending + * + * precondition: perimeter lock has been acquired + */ +bool brcms_del_timer(struct brcms_timer *t) +{ + if (t->set) { + t->set = false; + if (!cancel_delayed_work(&t->dly_wrk)) + return false; + + atomic_dec(&t->wl->callbacks); + } + + return true; +} + +/* + * precondition: perimeter lock has been acquired + */ +void brcms_free_timer(struct brcms_timer *t) +{ + struct brcms_info *wl = t->wl; + struct brcms_timer *tmp; + + /* delete the timer in case it is active */ + brcms_del_timer(t); + + if (wl->timers == t) { + wl->timers = wl->timers->next; +#ifdef BCMDBG + kfree(t->name); +#endif + kfree(t); + return; + + } + + tmp = wl->timers; + while (tmp) { + if (tmp->next == t) { + tmp->next = t->next; +#ifdef BCMDBG + kfree(t->name); +#endif + kfree(t); + return; + } + tmp = tmp->next; + } + +} + +/* + * precondition: perimeter lock has been acquired + */ +int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx) +{ + int i, entry; + const u8 *pdata; + struct firmware_hdr *hdr; + for (i = 0; i < wl->fw.fw_cnt; i++) { + hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data; + for (entry = 0; entry < wl->fw.hdr_num_entries[i]; + entry++, hdr++) { + u32 len = le32_to_cpu(hdr->len); + if (le32_to_cpu(hdr->idx) == idx) { + pdata = wl->fw.fw_bin[i]->data + + le32_to_cpu(hdr->offset); + *pbuf = kmalloc(len, GFP_ATOMIC); + if (*pbuf == NULL) + goto fail; + + memcpy(*pbuf, pdata, len); + return 0; + } + } + } + wiphy_err(wl->wiphy, "ERROR: ucode buf tag:%d can not be found!\n", + idx); + *pbuf = NULL; +fail: + return -ENODATA; +} + +/* + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx) +{ + int i, entry; + const u8 *pdata; + struct firmware_hdr *hdr; + for (i = 0; i < wl->fw.fw_cnt; i++) { + hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data; + for (entry = 0; entry < wl->fw.hdr_num_entries[i]; + entry++, hdr++) { + if (le32_to_cpu(hdr->idx) == idx) { + pdata = wl->fw.fw_bin[i]->data + + le32_to_cpu(hdr->offset); + if (le32_to_cpu(hdr->len) != 4) { + wiphy_err(wl->wiphy, + "ERROR: fw hdr len\n"); + return -ENOMSG; + } + *n_bytes = le32_to_cpu(*((__le32 *) pdata)); + return 0; + } + } + } + wiphy_err(wl->wiphy, "ERROR: ucode tag:%d can not be found!\n", idx); + return -ENOMSG; +} + +/* + * precondition: can both be called locked and unlocked + */ +void brcms_ucode_free_buf(void *p) +{ + kfree(p); +} + +/* + * checks validity of all firmware images loaded from user space + * + * Precondition: Since this function is called in brcms_pci_probe() context, + * no locking is required. + */ +int brcms_check_firmwares(struct brcms_info *wl) +{ + int i; + int entry; + int rc = 0; + const struct firmware *fw; + const struct firmware *fw_hdr; + struct firmware_hdr *ucode_hdr; + for (i = 0; i < MAX_FW_IMAGES && rc == 0; i++) { + fw = wl->fw.fw_bin[i]; + fw_hdr = wl->fw.fw_hdr[i]; + if (fw == NULL && fw_hdr == NULL) { + break; + } else if (fw == NULL || fw_hdr == NULL) { + wiphy_err(wl->wiphy, "%s: invalid bin/hdr fw\n", + __func__); + rc = -EBADF; + } else if (fw_hdr->size % sizeof(struct firmware_hdr)) { + wiphy_err(wl->wiphy, "%s: non integral fw hdr file " + "size %zu/%zu\n", __func__, fw_hdr->size, + sizeof(struct firmware_hdr)); + rc = -EBADF; + } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) { + wiphy_err(wl->wiphy, "%s: out of bounds fw file size " + "%zu\n", __func__, fw->size); + rc = -EBADF; + } else { + /* check if ucode section overruns firmware image */ + ucode_hdr = (struct firmware_hdr *)fw_hdr->data; + for (entry = 0; entry < wl->fw.hdr_num_entries[i] && + !rc; entry++, ucode_hdr++) { + if (le32_to_cpu(ucode_hdr->offset) + + le32_to_cpu(ucode_hdr->len) > + fw->size) { + wiphy_err(wl->wiphy, + "%s: conflicting bin/hdr\n", + __func__); + rc = -EBADF; + } + } + } + } + if (rc == 0 && wl->fw.fw_cnt != i) { + wiphy_err(wl->wiphy, "%s: invalid fw_cnt=%d\n", __func__, + wl->fw.fw_cnt); + rc = -EBADF; + } + return rc; +} + +/* + * precondition: perimeter lock has been acquired + */ +bool brcms_rfkill_set_hw_state(struct brcms_info *wl) +{ + bool blocked = brcms_c_check_radio_disabled(wl->wlc); + + spin_unlock_bh(&wl->lock); + wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, blocked); + if (blocked) + wiphy_rfkill_start_polling(wl->pub->ieee_hw->wiphy); + spin_lock_bh(&wl->lock); + return blocked; +} + +/* + * precondition: perimeter lock has been acquired + */ +void brcms_msleep(struct brcms_info *wl, uint ms) +{ + spin_unlock_bh(&wl->lock); + msleep(ms); + spin_lock_bh(&wl->lock); +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h new file mode 100644 index 000000000000..177f0e44e4b6 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_MAC80211_IF_H_ +#define _BRCM_MAC80211_IF_H_ + +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> + +#include "ucode_loader.h" +/* + * Starting index for 5G rates in the + * legacy rate table. + */ +#define BRCMS_LEGACY_5G_RATE_OFFSET 4 + +/* softmac ioctl definitions */ +#define BRCMS_SET_SHORTSLOT_OVERRIDE 146 + +struct brcms_timer { + struct delayed_work dly_wrk; + struct brcms_info *wl; + void (*fn) (void *); /* function called upon expiration */ + void *arg; /* fixed argument provided to called function */ + uint ms; + bool periodic; + bool set; /* indicates if timer is active */ + struct brcms_timer *next; /* for freeing on unload */ +#ifdef BCMDBG + char *name; /* Description of the timer */ +#endif +}; + +struct brcms_if { + uint subunit; /* WDS/BSS unit */ + struct pci_dev *pci_dev; +}; + +#define MAX_FW_IMAGES 4 +struct brcms_firmware { + u32 fw_cnt; + const struct firmware *fw_bin[MAX_FW_IMAGES]; + const struct firmware *fw_hdr[MAX_FW_IMAGES]; + u32 hdr_num_entries[MAX_FW_IMAGES]; +}; + +struct brcms_info { + struct brcms_pub *pub; /* pointer to public wlc state */ + struct brcms_c_info *wlc; /* pointer to private common data */ + u32 magic; + + int irq; + + spinlock_t lock; /* per-device perimeter lock */ + spinlock_t isr_lock; /* per-device ISR synchronization lock */ + + /* regsva for unmap in brcms_free() */ + void __iomem *regsva; /* opaque chip registers virtual address */ + + /* timer related fields */ + atomic_t callbacks; /* # outstanding callback functions */ + struct brcms_timer *timers; /* timer cleanup queue */ + + struct tasklet_struct tasklet; /* dpc tasklet */ + bool resched; /* dpc needs to be and is rescheduled */ + struct brcms_firmware fw; + struct wiphy *wiphy; + struct brcms_ucode ucode; +}; + +/* misc callbacks */ +extern void brcms_init(struct brcms_info *wl); +extern uint brcms_reset(struct brcms_info *wl); +extern void brcms_intrson(struct brcms_info *wl); +extern u32 brcms_intrsoff(struct brcms_info *wl); +extern void brcms_intrsrestore(struct brcms_info *wl, u32 macintmask); +extern int brcms_up(struct brcms_info *wl); +extern void brcms_down(struct brcms_info *wl); +extern void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif, + bool state, int prio); +extern bool brcms_rfkill_set_hw_state(struct brcms_info *wl); + +/* timer functions */ +extern struct brcms_timer *brcms_init_timer(struct brcms_info *wl, + void (*fn) (void *arg), void *arg, + const char *name); +extern void brcms_free_timer(struct brcms_timer *timer); +extern void brcms_add_timer(struct brcms_timer *timer, uint ms, int periodic); +extern bool brcms_del_timer(struct brcms_timer *timer); +extern void brcms_msleep(struct brcms_info *wl, uint ms); +extern void brcms_dpc(unsigned long data); +extern void brcms_timer(struct brcms_timer *t); + +#endif /* _BRCM_MAC80211_IF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c new file mode 100644 index 000000000000..510e9bb52287 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -0,0 +1,8775 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/pci_ids.h> +#include <linux/if_ether.h> +#include <net/mac80211.h> +#include <brcm_hw_ids.h> +#include <aiutils.h> +#include <chipcommon.h> +#include "rate.h" +#include "scb.h" +#include "phy/phy_hal.h" +#include "channel.h" +#include "antsel.h" +#include "stf.h" +#include "ampdu.h" +#include "mac80211_if.h" +#include "ucode_loader.h" +#include "main.h" + +/* + * Indication for txflowcontrol that all priority bits in + * TXQ_STOP_FOR_PRIOFC_MASK are to be considered. + */ +#define ALLPRIO -1 + +/* + * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL. + */ +#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1) + +/* watchdog timer, in unit of ms */ +#define TIMER_INTERVAL_WATCHDOG 1000 +/* radio monitor timer, in unit of ms */ +#define TIMER_INTERVAL_RADIOCHK 800 + +/* Max MPC timeout, in unit of watchdog */ +#ifndef BRCMS_MPC_MAX_DELAYCNT +#define BRCMS_MPC_MAX_DELAYCNT 10 +#endif + +/* Min MPC timeout, in unit of watchdog */ +#define BRCMS_MPC_MIN_DELAYCNT 1 +#define BRCMS_MPC_THRESHOLD 3 /* MPC count threshold level */ + +/* beacon interval, in unit of 1024TU */ +#define BEACON_INTERVAL_DEFAULT 100 +/* DTIM interval, in unit of beacon interval */ +#define DTIM_INTERVAL_DEFAULT 3 + +/* Scale down delays to accommodate QT slow speed */ +/* beacon interval, in unit of 1024TU */ +#define BEACON_INTERVAL_DEF_QT 20 +/* DTIM interval, in unit of beacon interval */ +#define DTIM_INTERVAL_DEF_QT 1 + +#define TBTT_ALIGN_LEEWAY_US 100 /* min leeway before first TBTT in us */ + +/* n-mode support capability */ +/* 2x2 includes both 1x1 & 2x2 devices + * reserved #define 2 for future when we want to separate 1x1 & 2x2 and + * control it independently + */ +#define WL_11N_2x2 1 +#define WL_11N_3x3 3 +#define WL_11N_4x4 4 + +/* define 11n feature disable flags */ +#define WLFEATURE_DISABLE_11N 0x00000001 +#define WLFEATURE_DISABLE_11N_STBC_TX 0x00000002 +#define WLFEATURE_DISABLE_11N_STBC_RX 0x00000004 +#define WLFEATURE_DISABLE_11N_SGI_TX 0x00000008 +#define WLFEATURE_DISABLE_11N_SGI_RX 0x00000010 +#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020 +#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040 +#define WLFEATURE_DISABLE_11N_GF 0x00000080 + +#define EDCF_ACI_MASK 0x60 +#define EDCF_ACI_SHIFT 5 +#define EDCF_ECWMIN_MASK 0x0f +#define EDCF_ECWMAX_SHIFT 4 +#define EDCF_AIFSN_MASK 0x0f +#define EDCF_AIFSN_MAX 15 +#define EDCF_ECWMAX_MASK 0xf0 + +#define EDCF_AC_BE_TXOP_STA 0x0000 +#define EDCF_AC_BK_TXOP_STA 0x0000 +#define EDCF_AC_VO_ACI_STA 0x62 +#define EDCF_AC_VO_ECW_STA 0x32 +#define EDCF_AC_VI_ACI_STA 0x42 +#define EDCF_AC_VI_ECW_STA 0x43 +#define EDCF_AC_BK_ECW_STA 0xA4 +#define EDCF_AC_VI_TXOP_STA 0x005e +#define EDCF_AC_VO_TXOP_STA 0x002f +#define EDCF_AC_BE_ACI_STA 0x03 +#define EDCF_AC_BE_ECW_STA 0xA4 +#define EDCF_AC_BK_ACI_STA 0x27 +#define EDCF_AC_VO_TXOP_AP 0x002f + +#define EDCF_TXOP2USEC(txop) ((txop) << 5) +#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1) + +#define APHY_SYMBOL_TIME 4 +#define APHY_PREAMBLE_TIME 16 +#define APHY_SIGNAL_TIME 4 +#define APHY_SIFS_TIME 16 +#define APHY_SERVICE_NBITS 16 +#define APHY_TAIL_NBITS 6 +#define BPHY_SIFS_TIME 10 +#define BPHY_PLCP_SHORT_TIME 96 + +#define PREN_PREAMBLE 24 +#define PREN_MM_EXT 12 +#define PREN_PREAMBLE_EXT 4 + +#define DOT11_MAC_HDR_LEN 24 +#define DOT11_ACK_LEN 10 +#define DOT11_BA_LEN 4 +#define DOT11_OFDM_SIGNAL_EXTENSION 6 +#define DOT11_MIN_FRAG_LEN 256 +#define DOT11_RTS_LEN 16 +#define DOT11_CTS_LEN 10 +#define DOT11_BA_BITMAP_LEN 128 +#define DOT11_MIN_BEACON_PERIOD 1 +#define DOT11_MAX_BEACON_PERIOD 0xFFFF +#define DOT11_MAXNUMFRAGS 16 +#define DOT11_MAX_FRAG_LEN 2346 + +#define BPHY_PLCP_TIME 192 +#define RIFS_11N_TIME 2 + +#define WME_VER 1 +#define WME_SUBTYPE_PARAM_IE 1 +#define WME_TYPE 2 +#define WME_OUI "\x00\x50\xf2" + +#define AC_BE 0 +#define AC_BK 1 +#define AC_VI 2 +#define AC_VO 3 + +#define BCN_TMPL_LEN 512 /* length of the BCN template area */ + +/* brcms_bss_info flag bit values */ +#define BRCMS_BSS_HT 0x0020 /* BSS is HT (MIMO) capable */ + +/* Flags used in brcms_c_txq_info.stopped */ +/* per prio flow control bits */ +#define TXQ_STOP_FOR_PRIOFC_MASK 0x000000FF +/* stop txq enqueue for packet drain */ +#define TXQ_STOP_FOR_PKT_DRAIN 0x00000100 +/* stop txq enqueue for ampdu flow control */ +#define TXQ_STOP_FOR_AMPDU_FLOW_CNTRL 0x00000200 + +#define BRCMS_HWRXOFF 38 /* chip rx buffer offset */ + +/* Find basic rate for a given rate */ +static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec) +{ + if (is_mcs_rate(rspec)) + return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK] + .leg_ofdm]; + return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK]; +} + +static u16 frametype(u32 rspec, u8 mimoframe) +{ + if (is_mcs_rate(rspec)) + return mimoframe; + return is_cck_rate(rspec) ? FT_CCK : FT_OFDM; +} + +/* rfdisable delay timer 500 ms, runs of ALP clock */ +#define RFDISABLE_DEFAULT 10000000 + +#define BRCMS_TEMPSENSE_PERIOD 10 /* 10 second timeout */ + +/* precedences numbers for wlc queues. These are twice as may levels as + * 802.1D priorities. + * Odd numbers are used for HI priority traffic at same precedence levels + * These constants are used ONLY by wlc_prio2prec_map. Do not use them + * elsewhere. + */ +#define _BRCMS_PREC_NONE 0 /* None = - */ +#define _BRCMS_PREC_BK 2 /* BK - Background */ +#define _BRCMS_PREC_BE 4 /* BE - Best-effort */ +#define _BRCMS_PREC_EE 6 /* EE - Excellent-effort */ +#define _BRCMS_PREC_CL 8 /* CL - Controlled Load */ +#define _BRCMS_PREC_VI 10 /* Vi - Video */ +#define _BRCMS_PREC_VO 12 /* Vo - Voice */ +#define _BRCMS_PREC_NC 14 /* NC - Network Control */ + +/* The BSS is generating beacons in HW */ +#define BRCMS_BSSCFG_HW_BCN 0x20 + +#define SYNTHPU_DLY_APHY_US 3700 /* a phy synthpu_dly time in us */ +#define SYNTHPU_DLY_BPHY_US 1050 /* b/g phy synthpu_dly time in us */ +#define SYNTHPU_DLY_NPHY_US 2048 /* n phy REV3 synthpu_dly time in us */ +#define SYNTHPU_DLY_LPPHY_US 300 /* lpphy synthpu_dly time in us */ + +#define SYNTHPU_DLY_PHY_US_QT 100 /* QT synthpu_dly time in us */ + +#define ANTCNT 10 /* vanilla M_MAX_ANTCNT value */ + +/* Per-AC retry limit register definitions; uses defs.h bitfield macros */ +#define EDCF_SHORT_S 0 +#define EDCF_SFB_S 4 +#define EDCF_LONG_S 8 +#define EDCF_LFB_S 12 +#define EDCF_SHORT_M BITFIELD_MASK(4) +#define EDCF_SFB_M BITFIELD_MASK(4) +#define EDCF_LONG_M BITFIELD_MASK(4) +#define EDCF_LFB_M BITFIELD_MASK(4) + +#define RETRY_SHORT_DEF 7 /* Default Short retry Limit */ +#define RETRY_SHORT_MAX 255 /* Maximum Short retry Limit */ +#define RETRY_LONG_DEF 4 /* Default Long retry count */ +#define RETRY_SHORT_FB 3 /* Short count for fallback rate */ +#define RETRY_LONG_FB 2 /* Long count for fallback rate */ + +#define APHY_CWMIN 15 +#define PHY_CWMAX 1023 + +#define EDCF_AIFSN_MIN 1 + +#define FRAGNUM_MASK 0xF + +#define APHY_SLOT_TIME 9 +#define BPHY_SLOT_TIME 20 + +#define WL_SPURAVOID_OFF 0 +#define WL_SPURAVOID_ON1 1 +#define WL_SPURAVOID_ON2 2 + +/* invalid core flags, use the saved coreflags */ +#define BRCMS_USE_COREFLAGS 0xffffffff + +/* values for PLCPHdr_override */ +#define BRCMS_PLCP_AUTO -1 +#define BRCMS_PLCP_SHORT 0 +#define BRCMS_PLCP_LONG 1 + +/* values for g_protection_override and n_protection_override */ +#define BRCMS_PROTECTION_AUTO -1 +#define BRCMS_PROTECTION_OFF 0 +#define BRCMS_PROTECTION_ON 1 +#define BRCMS_PROTECTION_MMHDR_ONLY 2 +#define BRCMS_PROTECTION_CTS_ONLY 3 + +/* values for g_protection_control and n_protection_control */ +#define BRCMS_PROTECTION_CTL_OFF 0 +#define BRCMS_PROTECTION_CTL_LOCAL 1 +#define BRCMS_PROTECTION_CTL_OVERLAP 2 + +/* values for n_protection */ +#define BRCMS_N_PROTECTION_OFF 0 +#define BRCMS_N_PROTECTION_OPTIONAL 1 +#define BRCMS_N_PROTECTION_20IN40 2 +#define BRCMS_N_PROTECTION_MIXEDMODE 3 + +/* values for band specific 40MHz capabilities */ +#define BRCMS_N_BW_20ALL 0 +#define BRCMS_N_BW_40ALL 1 +#define BRCMS_N_BW_20IN2G_40IN5G 2 + +/* bitflags for SGI support (sgi_rx iovar) */ +#define BRCMS_N_SGI_20 0x01 +#define BRCMS_N_SGI_40 0x02 + +/* defines used by the nrate iovar */ +/* MSC in use,indicates b0-6 holds an mcs */ +#define NRATE_MCS_INUSE 0x00000080 +/* rate/mcs value */ +#define NRATE_RATE_MASK 0x0000007f +/* stf mode mask: siso, cdd, stbc, sdm */ +#define NRATE_STF_MASK 0x0000ff00 +/* stf mode shift */ +#define NRATE_STF_SHIFT 8 +/* bit indicates override both rate & mode */ +#define NRATE_OVERRIDE 0x80000000 +/* bit indicate to override mcs only */ +#define NRATE_OVERRIDE_MCS_ONLY 0x40000000 +#define NRATE_SGI_MASK 0x00800000 /* sgi mode */ +#define NRATE_SGI_SHIFT 23 /* sgi mode */ +#define NRATE_LDPC_CODING 0x00400000 /* bit indicates adv coding in use */ +#define NRATE_LDPC_SHIFT 22 /* ldpc shift */ + +#define NRATE_STF_SISO 0 /* stf mode SISO */ +#define NRATE_STF_CDD 1 /* stf mode CDD */ +#define NRATE_STF_STBC 2 /* stf mode STBC */ +#define NRATE_STF_SDM 3 /* stf mode SDM */ + +#define MAX_DMA_SEGS 4 + +/* Max # of entries in Tx FIFO based on 4kb page size */ +#define NTXD 256 +/* Max # of entries in Rx FIFO based on 4kb page size */ +#define NRXD 256 + +/* try to keep this # rbufs posted to the chip */ +#define NRXBUFPOST 32 + +/* data msg txq hiwat mark */ +#define BRCMS_DATAHIWAT 50 + +/* bounded rx loops */ +#define RXBND 8 /* max # frames to process in brcms_c_recv() */ +#define TXSBND 8 /* max # tx status to process in wlc_txstatus() */ + +/* + * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL. + */ +#define SSID_FMT_BUF_LEN ((4 * IEEE80211_MAX_SSID_LEN) + 1) + +/* brcmu_format_flags() bit description structure */ +struct brcms_c_bit_desc { + u32 bit; + const char *name; +}; + +/* + * The following table lists the buffer memory allocated to xmt fifos in HW. + * the size is in units of 256bytes(one block), total size is HW dependent + * ucode has default fifo partition, sw can overwrite if necessary + * + * This is documented in twiki under the topic UcodeTxFifo. Please ensure + * the twiki is updated before making changes. + */ + +/* Starting corerev for the fifo size table */ +#define XMTFIFOTBL_STARTREV 20 + +struct d11init { + __le16 addr; + __le16 size; + __le32 value; +}; + +struct edcf_acparam { + u8 ACI; + u8 ECW; + u16 TXOP; +} __packed; + +const u8 prio2fifo[NUMPRIO] = { + TX_AC_BE_FIFO, /* 0 BE AC_BE Best Effort */ + TX_AC_BK_FIFO, /* 1 BK AC_BK Background */ + TX_AC_BK_FIFO, /* 2 -- AC_BK Background */ + TX_AC_BE_FIFO, /* 3 EE AC_BE Best Effort */ + TX_AC_VI_FIFO, /* 4 CL AC_VI Video */ + TX_AC_VI_FIFO, /* 5 VI AC_VI Video */ + TX_AC_VO_FIFO, /* 6 VO AC_VO Voice */ + TX_AC_VO_FIFO /* 7 NC AC_VO Voice */ +}; + +/* debug/trace */ +uint brcm_msg_level = +#if defined(BCMDBG) + LOG_ERROR_VAL; +#else + 0; +#endif /* BCMDBG */ + +/* TX FIFO number to WME/802.1E Access Category */ +static const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE }; + +/* WME/802.1E Access Category to TX FIFO number */ +static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 }; + +/* 802.1D Priority to precedence queue mapping */ +const u8 wlc_prio2prec_map[] = { + _BRCMS_PREC_BE, /* 0 BE - Best-effort */ + _BRCMS_PREC_BK, /* 1 BK - Background */ + _BRCMS_PREC_NONE, /* 2 None = - */ + _BRCMS_PREC_EE, /* 3 EE - Excellent-effort */ + _BRCMS_PREC_CL, /* 4 CL - Controlled Load */ + _BRCMS_PREC_VI, /* 5 Vi - Video */ + _BRCMS_PREC_VO, /* 6 Vo - Voice */ + _BRCMS_PREC_NC, /* 7 NC - Network Control */ +}; + +static const u16 xmtfifo_sz[][NFIFO] = { + /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */ + {20, 192, 192, 21, 17, 5}, + /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */ + {9, 58, 22, 14, 14, 5}, + /* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */ + {20, 192, 192, 21, 17, 5}, + /* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */ + {20, 192, 192, 21, 17, 5}, + /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */ + {9, 58, 22, 14, 14, 5}, +}; + +static const u8 acbitmap2maxprio[] = { + PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK, + PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, + PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, + PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO +}; + +#ifdef BCMDBG +static const char * const fifo_names[] = { + "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" }; +#else +static const char fifo_names[6][0]; +#endif + +#ifdef BCMDBG +/* pointer to most recently allocated wl/wlc */ +static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL); +#endif + +/* currently the best mechanism for determining SIFS is the band in use */ +static u16 get_sifs(struct brcms_band *band) +{ + return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME : + BPHY_SIFS_TIME; +} + +/* + * Detect Card removed. + * Even checking an sbconfig register read will not false trigger when the core + * is in reset it breaks CF address mechanism. Accessing gphy phyversion will + * cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible + * reg with fixed 0/1 pattern (some platforms return all 0). + * If clocks are present, call the sb routine which will figure out if the + * device is removed. + */ +static bool brcms_deviceremoved(struct brcms_c_info *wlc) +{ + if (!wlc->hw->clk) + return ai_deviceremoved(wlc->hw->sih); + return (R_REG(&wlc->hw->regs->maccontrol) & + (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN; +} + +/* sum the individual fifo tx pending packet counts */ +static s16 brcms_txpktpendtot(struct brcms_c_info *wlc) +{ + return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] + + wlc->core->txpktpend[2] + wlc->core->txpktpend[3]; +} + +static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc) +{ + return wlc->pub->_nbands > 1 && !wlc->bandlocked; +} + +static int brcms_chspec_bw(u16 chanspec) +{ + if (CHSPEC_IS40(chanspec)) + return BRCMS_40_MHZ; + if (CHSPEC_IS20(chanspec)) + return BRCMS_20_MHZ; + + return BRCMS_10_MHZ; +} + +/* + * return true if Minimum Power Consumption should + * be entered, false otherwise + */ +static bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc) +{ + return false; +} + +static bool brcms_c_ismpc(struct brcms_c_info *wlc) +{ + return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc)); +} + +static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg) +{ + if (cfg == NULL) + return; + + kfree(cfg->current_bss); + kfree(cfg); +} + +static void brcms_c_detach_mfree(struct brcms_c_info *wlc) +{ + if (wlc == NULL) + return; + + brcms_c_bsscfg_mfree(wlc->bsscfg); + kfree(wlc->pub); + kfree(wlc->modulecb); + kfree(wlc->default_bss); + kfree(wlc->protection); + kfree(wlc->stf); + kfree(wlc->bandstate[0]); + kfree(wlc->corestate->macstat_snapshot); + kfree(wlc->corestate); + kfree(wlc->hw->bandstate[0]); + kfree(wlc->hw); + + /* free the wlc */ + kfree(wlc); + wlc = NULL; +} + +static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit) +{ + struct brcms_bss_cfg *cfg; + + cfg = kzalloc(sizeof(struct brcms_bss_cfg), GFP_ATOMIC); + if (cfg == NULL) + goto fail; + + cfg->current_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC); + if (cfg->current_bss == NULL) + goto fail; + + return cfg; + + fail: + brcms_c_bsscfg_mfree(cfg); + return NULL; +} + +static struct brcms_c_info * +brcms_c_attach_malloc(uint unit, uint *err, uint devid) +{ + struct brcms_c_info *wlc; + + wlc = kzalloc(sizeof(struct brcms_c_info), GFP_ATOMIC); + if (wlc == NULL) { + *err = 1002; + goto fail; + } + + /* allocate struct brcms_c_pub state structure */ + wlc->pub = kzalloc(sizeof(struct brcms_pub), GFP_ATOMIC); + if (wlc->pub == NULL) { + *err = 1003; + goto fail; + } + wlc->pub->wlc = wlc; + + /* allocate struct brcms_hardware state structure */ + + wlc->hw = kzalloc(sizeof(struct brcms_hardware), GFP_ATOMIC); + if (wlc->hw == NULL) { + *err = 1005; + goto fail; + } + wlc->hw->wlc = wlc; + + wlc->hw->bandstate[0] = + kzalloc(sizeof(struct brcms_hw_band) * MAXBANDS, GFP_ATOMIC); + if (wlc->hw->bandstate[0] == NULL) { + *err = 1006; + goto fail; + } else { + int i; + + for (i = 1; i < MAXBANDS; i++) + wlc->hw->bandstate[i] = (struct brcms_hw_band *) + ((unsigned long)wlc->hw->bandstate[0] + + (sizeof(struct brcms_hw_band) * i)); + } + + wlc->modulecb = + kzalloc(sizeof(struct modulecb) * BRCMS_MAXMODULES, GFP_ATOMIC); + if (wlc->modulecb == NULL) { + *err = 1009; + goto fail; + } + + wlc->default_bss = kzalloc(sizeof(struct brcms_bss_info), GFP_ATOMIC); + if (wlc->default_bss == NULL) { + *err = 1010; + goto fail; + } + + wlc->bsscfg = brcms_c_bsscfg_malloc(unit); + if (wlc->bsscfg == NULL) { + *err = 1011; + goto fail; + } + + wlc->protection = kzalloc(sizeof(struct brcms_protection), + GFP_ATOMIC); + if (wlc->protection == NULL) { + *err = 1016; + goto fail; + } + + wlc->stf = kzalloc(sizeof(struct brcms_stf), GFP_ATOMIC); + if (wlc->stf == NULL) { + *err = 1017; + goto fail; + } + + wlc->bandstate[0] = + kzalloc(sizeof(struct brcms_band)*MAXBANDS, GFP_ATOMIC); + if (wlc->bandstate[0] == NULL) { + *err = 1025; + goto fail; + } else { + int i; + + for (i = 1; i < MAXBANDS; i++) + wlc->bandstate[i] = (struct brcms_band *) + ((unsigned long)wlc->bandstate[0] + + (sizeof(struct brcms_band)*i)); + } + + wlc->corestate = kzalloc(sizeof(struct brcms_core), GFP_ATOMIC); + if (wlc->corestate == NULL) { + *err = 1026; + goto fail; + } + + wlc->corestate->macstat_snapshot = + kzalloc(sizeof(struct macstat), GFP_ATOMIC); + if (wlc->corestate->macstat_snapshot == NULL) { + *err = 1027; + goto fail; + } + + return wlc; + + fail: + brcms_c_detach_mfree(wlc); + return NULL; +} + +/* + * Update the slot timing for standard 11b/g (20us slots) + * or shortslot 11g (9us slots) + * The PSM needs to be suspended for this call. + */ +static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw, + bool shortslot) +{ + struct d11regs __iomem *regs; + + regs = wlc_hw->regs; + + if (shortslot) { + /* 11g short slot: 11a timing */ + W_REG(®s->ifs_slot, 0x0207); /* APHY_SLOT_TIME */ + brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME); + } else { + /* 11g long slot: 11b timing */ + W_REG(®s->ifs_slot, 0x0212); /* BPHY_SLOT_TIME */ + brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME); + } +} + +/* + * calculate frame duration of a given rate and length, return + * time in usec unit + */ +uint +brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec, + u8 preamble_type, uint mac_len) +{ + uint nsyms, dur = 0, Ndps, kNdps; + uint rate = rspec2rate(ratespec); + + if (rate == 0) { + wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n", + wlc->pub->unit); + rate = BRCM_RATE_1M; + } + + BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n", + wlc->pub->unit, ratespec, preamble_type, mac_len); + + if (is_mcs_rate(ratespec)) { + uint mcs = ratespec & RSPEC_RATE_MASK; + int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec); + + dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT); + if (preamble_type == BRCMS_MM_PREAMBLE) + dur += PREN_MM_EXT; + /* 1000Ndbps = kbps * 4 */ + kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec), + rspec_issgi(ratespec)) * 4; + + if (rspec_stc(ratespec) == 0) + nsyms = + CEIL((APHY_SERVICE_NBITS + 8 * mac_len + + APHY_TAIL_NBITS) * 1000, kNdps); + else + /* STBC needs to have even number of symbols */ + nsyms = + 2 * + CEIL((APHY_SERVICE_NBITS + 8 * mac_len + + APHY_TAIL_NBITS) * 1000, 2 * kNdps); + + dur += APHY_SYMBOL_TIME * nsyms; + if (wlc->band->bandtype == BRCM_BAND_2G) + dur += DOT11_OFDM_SIGNAL_EXTENSION; + } else if (is_ofdm_rate(rate)) { + dur = APHY_PREAMBLE_TIME; + dur += APHY_SIGNAL_TIME; + /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */ + Ndps = rate * 2; + /* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */ + nsyms = + CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS), + Ndps); + dur += APHY_SYMBOL_TIME * nsyms; + if (wlc->band->bandtype == BRCM_BAND_2G) + dur += DOT11_OFDM_SIGNAL_EXTENSION; + } else { + /* + * calc # bits * 2 so factor of 2 in rate (1/2 mbps) + * will divide out + */ + mac_len = mac_len * 8 * 2; + /* calc ceiling of bits/rate = microseconds of air time */ + dur = (mac_len + rate - 1) / rate; + if (preamble_type & BRCMS_SHORT_PREAMBLE) + dur += BPHY_PLCP_SHORT_TIME; + else + dur += BPHY_PLCP_TIME; + } + return dur; +} + +static void brcms_c_write_inits(struct brcms_hardware *wlc_hw, + const struct d11init *inits) +{ + int i; + u8 __iomem *base; + u8 __iomem *addr; + u16 size; + u32 value; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + base = (u8 __iomem *)wlc_hw->regs; + + for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) { + size = le16_to_cpu(inits[i].size); + addr = base + le16_to_cpu(inits[i].addr); + value = le32_to_cpu(inits[i].value); + if (size == 2) + W_REG((u16 __iomem *)addr, value); + else if (size == 4) + W_REG((u32 __iomem *)addr, value); + else + break; + } +} + +static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs) +{ + u8 idx; + u16 addr[] = { + M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4, + M_HOST_FLAGS5 + }; + + for (idx = 0; idx < MHFMAX; idx++) + brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]); +} + +static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw) +{ + struct wiphy *wiphy = wlc_hw->wlc->wiphy; + struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; + + /* init microcode host flags */ + brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs); + + /* do band-specific ucode IHR, SHM, and SCR inits */ + if (D11REV_IS(wlc_hw->corerev, 23)) { + if (BRCMS_ISNPHY(wlc_hw->band)) + brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16); + else + wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" + " %d\n", __func__, wlc_hw->unit, + wlc_hw->corerev); + } else { + if (D11REV_IS(wlc_hw->corerev, 24)) { + if (BRCMS_ISLCNPHY(wlc_hw->band)) + brcms_c_write_inits(wlc_hw, + ucode->d11lcn0bsinitvals24); + else + wiphy_err(wiphy, "%s: wl%d: unsupported phy in" + " core rev %d\n", __func__, + wlc_hw->unit, wlc_hw->corerev); + } else { + wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); + } + } +} + +static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk) +{ + BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk); + + wlc_hw->phyclk = clk; + + if (OFF == clk) { /* clear gmode bit, put phy into reset */ + + ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC | SICF_GMODE), + (SICF_PRST | SICF_FGC)); + udelay(1); + ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_PRST); + udelay(1); + + } else { /* take phy out of reset */ + + ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_FGC), SICF_FGC); + udelay(1); + ai_core_cflags(wlc_hw->sih, (SICF_FGC), 0); + udelay(1); + + } +} + +/* low-level band switch utility routine */ +static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit) +{ + BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, + bandunit); + + wlc_hw->band = wlc_hw->bandstate[bandunit]; + + /* + * BMAC_NOTE: + * until we eliminate need for wlc->band refs in low level code + */ + wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit]; + + /* set gmode core flag */ + if (wlc_hw->sbclk && !wlc_hw->noreset) + ai_core_cflags(wlc_hw->sih, SICF_GMODE, + ((bandunit == 0) ? SICF_GMODE : 0)); +} + +/* switch to new band but leave it inactive */ +static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + u32 macintmask; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); + + WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0); + + /* disable interrupts */ + macintmask = brcms_intrsoff(wlc->wl); + + /* radio off */ + wlc_phy_switch_radio(wlc_hw->band->pi, OFF); + + brcms_b_core_phy_clk(wlc_hw, OFF); + + brcms_c_setxband(wlc_hw, bandunit); + + return macintmask; +} + +/* process an individual struct tx_status */ +static bool +brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) +{ + struct sk_buff *p; + uint queue; + struct d11txh *txh; + struct scb *scb = NULL; + bool free_pdu; + int tx_rts, tx_frame_count, tx_rts_count; + uint totlen, supr_status; + bool lastframe; + struct ieee80211_hdr *h; + u16 mcl; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *txrate; + int i; + + /* discard intermediate indications for ucode with one legitimate case: + * e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, + * but the subsequent tx of DATA failed. so it will start rts/cts + * from the beginning (resetting the rts transmission count) + */ + if (!(txs->status & TX_STATUS_AMPDU) + && (txs->status & TX_STATUS_INTERMEDIATE)) { + wiphy_err(wlc->wiphy, "%s: INTERMEDIATE but not AMPDU\n", + __func__); + return false; + } + + queue = txs->frameid & TXFID_QUEUE_MASK; + if (queue >= NFIFO) { + p = NULL; + goto fatal; + } + + p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED); + if (p == NULL) + goto fatal; + + txh = (struct d11txh *) (p->data); + mcl = le16_to_cpu(txh->MacTxControlLow); + + if (txs->phyerr) { + if (brcm_msg_level & LOG_ERROR_VAL) { + wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n", + txs->phyerr, txh->MainRates); + brcms_c_print_txdesc(txh); + } + brcms_c_print_txstatus(txs); + } + + if (txs->frameid != le16_to_cpu(txh->TxFrameID)) + goto fatal; + tx_info = IEEE80211_SKB_CB(p); + h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); + + if (tx_info->control.sta) + scb = &wlc->pri_scb; + + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs); + return false; + } + + supr_status = txs->status & TX_STATUS_SUPR_MASK; + if (supr_status == TX_STATUS_SUPR_BADCH) + BCMMSG(wlc->wiphy, + "%s: Pkt tx suppressed, possibly channel %d\n", + __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec)); + + tx_rts = le16_to_cpu(txh->MacTxControlLow) & TXC_SENDRTS; + tx_frame_count = + (txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT; + tx_rts_count = + (txs->status & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT; + + lastframe = !ieee80211_has_morefrags(h->frame_control); + + if (!lastframe) { + wiphy_err(wlc->wiphy, "Not last frame!\n"); + } else { + /* + * Set information to be consumed by Minstrel ht. + * + * The "fallback limit" is the number of tx attempts a given + * MPDU is sent at the "primary" rate. Tx attempts beyond that + * limit are sent at the "secondary" rate. + * A 'short frame' does not exceed RTS treshold. + */ + u16 sfbl, /* Short Frame Rate Fallback Limit */ + lfbl, /* Long Frame Rate Fallback Limit */ + fbl; + + if (queue < AC_COUNT) { + sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]], + EDCF_SFB); + lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]], + EDCF_LFB); + } else { + sfbl = wlc->SFBL; + lfbl = wlc->LFBL; + } + + txrate = tx_info->status.rates; + if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + fbl = lfbl; + else + fbl = sfbl; + + ieee80211_tx_info_clear_status(tx_info); + + if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) { + /* + * rate selection requested a fallback rate + * and we used it + */ + txrate[0].count = fbl; + txrate[1].count = tx_frame_count - fbl; + } else { + /* + * rate selection did not request fallback rate, or + * we didn't need it + */ + txrate[0].count = tx_frame_count; + /* + * rc80211_minstrel.c:minstrel_tx_status() expects + * unused rates to be marked with idx = -1 + */ + txrate[1].idx = -1; + txrate[1].count = 0; + } + + /* clear the rest of the rates */ + for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) { + txrate[i].idx = -1; + txrate[i].count = 0; + } + + if (txs->status & TX_STATUS_ACK_RCV) + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } + + totlen = brcmu_pkttotlen(p); + free_pdu = true; + + brcms_c_txfifo_complete(wlc, queue, 1); + + if (lastframe) { + p->next = NULL; + p->prev = NULL; + /* remove PLCP & Broadcom tx descriptor header */ + skb_pull(p, D11_PHY_HDR_LEN); + skb_pull(p, D11_TXH_LEN); + ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p); + } else { + wiphy_err(wlc->wiphy, "%s: Not last frame => not calling " + "tx_status\n", __func__); + } + + return false; + + fatal: + if (p) + brcmu_pkt_buf_free_skb(p); + + return true; + +} + +/* process tx completion events in BMAC + * Return true if more tx status need to be processed. false otherwise. + */ +static bool +brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal) +{ + bool morepending = false; + struct brcms_c_info *wlc = wlc_hw->wlc; + struct d11regs __iomem *regs; + struct tx_status txstatus, *txs; + u32 s1, s2; + uint n = 0; + /* + * Param 'max_tx_num' indicates max. # tx status to process before + * break out. + */ + uint max_tx_num = bound ? TXSBND : -1; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); + + txs = &txstatus; + regs = wlc_hw->regs; + *fatal = false; + while (!(*fatal) + && (s1 = R_REG(®s->frmtxstatus)) & TXS_V) { + + if (s1 == 0xffffffff) { + wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", + wlc_hw->unit, __func__); + return morepending; + } + + s2 = R_REG(®s->frmtxstatus2); + + txs->status = s1 & TXS_STATUS_MASK; + txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT; + txs->sequence = s2 & TXS_SEQ_MASK; + txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT; + txs->lasttxtime = 0; + + *fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs); + + /* !give others some time to run! */ + if (++n >= max_tx_num) + break; + } + + if (*fatal) + return 0; + + if (n >= max_tx_num) + morepending = true; + + if (!pktq_empty(&wlc->pkt_queue->q)) + brcms_c_send_q(wlc); + + return morepending; +} + +static void brcms_c_tbtt(struct brcms_c_info *wlc) +{ + if (!wlc->bsscfg->BSS) + /* + * DirFrmQ is now valid...defer setting until end + * of ATIM window + */ + wlc->qvalid |= MCMD_DIRFRMQVAL; +} + +/* set initial host flags value */ +static void +brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + + memset(mhfs, 0, MHFMAX * sizeof(u16)); + + mhfs[MHF2] |= mhf2_init; + + /* prohibit use of slowclock on multifunction boards */ + if (wlc_hw->boardflags & BFL_NOPLLDOWN) + mhfs[MHF1] |= MHF1_FORCEFASTCLK; + + if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) { + mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR; + mhfs[MHF1] |= MHF1_IQSWAP_WAR; + } +} + +static struct dma64regs __iomem * +dmareg(struct brcms_hardware *hw, uint direction, uint fifonum) +{ + if (direction == DMA_TX) + return &(hw->regs->fifo64regs[fifonum].dmaxmt); + return &(hw->regs->fifo64regs[fifonum].dmarcv); +} + +static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme) +{ + uint i; + char name[8]; + /* + * ucode host flag 2 needed for pio mode, independent of band and fifo + */ + u16 pio_mhf2 = 0; + struct brcms_hardware *wlc_hw = wlc->hw; + uint unit = wlc_hw->unit; + struct wiphy *wiphy = wlc->wiphy; + + /* name and offsets for dma_attach */ + snprintf(name, sizeof(name), "wl%d", unit); + + if (wlc_hw->di[0] == NULL) { /* Init FIFOs */ + int dma_attach_err = 0; + + /* + * FIFO 0 + * TX: TX_AC_BK_FIFO (TX AC Background data packets) + * RX: RX_FIFO (RX data packets) + */ + wlc_hw->di[0] = dma_attach(name, wlc_hw->sih, + (wme ? dmareg(wlc_hw, DMA_TX, 0) : + NULL), dmareg(wlc_hw, DMA_RX, 0), + (wme ? NTXD : 0), NRXD, + RXBUFSZ, -1, NRXBUFPOST, + BRCMS_HWRXOFF, &brcm_msg_level); + dma_attach_err |= (NULL == wlc_hw->di[0]); + + /* + * FIFO 1 + * TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets) + * (legacy) TX_DATA_FIFO (TX data packets) + * RX: UNUSED + */ + wlc_hw->di[1] = dma_attach(name, wlc_hw->sih, + dmareg(wlc_hw, DMA_TX, 1), NULL, + NTXD, 0, 0, -1, 0, 0, + &brcm_msg_level); + dma_attach_err |= (NULL == wlc_hw->di[1]); + + /* + * FIFO 2 + * TX: TX_AC_VI_FIFO (TX AC Video data packets) + * RX: UNUSED + */ + wlc_hw->di[2] = dma_attach(name, wlc_hw->sih, + dmareg(wlc_hw, DMA_TX, 2), NULL, + NTXD, 0, 0, -1, 0, 0, + &brcm_msg_level); + dma_attach_err |= (NULL == wlc_hw->di[2]); + /* + * FIFO 3 + * TX: TX_AC_VO_FIFO (TX AC Voice data packets) + * (legacy) TX_CTL_FIFO (TX control & mgmt packets) + */ + wlc_hw->di[3] = dma_attach(name, wlc_hw->sih, + dmareg(wlc_hw, DMA_TX, 3), + NULL, NTXD, 0, 0, -1, + 0, 0, &brcm_msg_level); + dma_attach_err |= (NULL == wlc_hw->di[3]); +/* Cleaner to leave this as if with AP defined */ + + if (dma_attach_err) { + wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed" + "\n", unit); + return false; + } + + /* get pointer to dma engine tx flow control variable */ + for (i = 0; i < NFIFO; i++) + if (wlc_hw->di[i]) + wlc_hw->txavail[i] = + (uint *) dma_getvar(wlc_hw->di[i], + "&txavail"); + } + + /* initial ucode host flags */ + brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2); + + return true; +} + +static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw) +{ + uint j; + + for (j = 0; j < NFIFO; j++) { + if (wlc_hw->di[j]) { + dma_detach(wlc_hw->di[j]); + wlc_hw->di[j] = NULL; + } + } +} + +/* + * Initialize brcms_c_info default values ... + * may get overrides later in this function + * BMAC_NOTES, move low out and resolve the dangling ones + */ +static void brcms_b_info_init(struct brcms_hardware *wlc_hw) +{ + struct brcms_c_info *wlc = wlc_hw->wlc; + + /* set default sw macintmask value */ + wlc->defmacintmask = DEF_MACINTMASK; + + /* various 802.11g modes */ + wlc_hw->shortslot = false; + + wlc_hw->SFBL = RETRY_SHORT_FB; + wlc_hw->LFBL = RETRY_LONG_FB; + + /* default mac retry limits */ + wlc_hw->SRL = RETRY_SHORT_DEF; + wlc_hw->LRL = RETRY_LONG_DEF; + wlc_hw->chanspec = ch20mhz_chspec(1); +} + +static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw) +{ + /* delay before first read of ucode state */ + udelay(40); + + /* wait until ucode is no longer asleep */ + SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) == + DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly); +} + +/* control chip clock to save power, enable dynamic clock or force fast clock */ +static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) +{ + if (wlc_hw->sih->cccaps & CC_CAP_PMU) { + /* new chips with PMU, CCS_FORCEHT will distribute the HT clock + * on backplane, but mac core will still run on ALP(not HT) when + * it enters powersave mode, which means the FCA bit may not be + * set. Should wakeup mac if driver wants it to run on HT. + */ + + if (wlc_hw->clk) { + if (mode == CLK_FAST) { + OR_REG(&wlc_hw->regs->clk_ctl_st, + CCS_FORCEHT); + + udelay(64); + + SPINWAIT(((R_REG + (&wlc_hw->regs-> + clk_ctl_st) & CCS_HTAVAIL) == 0), + PMU_MAX_TRANSITION_DLY); + WARN_ON(!(R_REG + (&wlc_hw->regs-> + clk_ctl_st) & CCS_HTAVAIL)); + } else { + if ((wlc_hw->sih->pmurev == 0) && + (R_REG + (&wlc_hw->regs-> + clk_ctl_st) & (CCS_FORCEHT | CCS_HTAREQ))) + SPINWAIT(((R_REG + (&wlc_hw->regs-> + clk_ctl_st) & CCS_HTAVAIL) + == 0), + PMU_MAX_TRANSITION_DLY); + AND_REG(&wlc_hw->regs->clk_ctl_st, + ~CCS_FORCEHT); + } + } + wlc_hw->forcefastclk = (mode == CLK_FAST); + } else { + + /* old chips w/o PMU, force HT through cc, + * then use FCA to verify mac is running fast clock + */ + + wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode); + + /* check fast clock is available (if core is not in reset) */ + if (wlc_hw->forcefastclk && wlc_hw->clk) + WARN_ON(!(ai_core_sflags(wlc_hw->sih, 0, 0) & + SISF_FCLKA)); + + /* + * keep the ucode wake bit on if forcefastclk is on since we + * do not want ucode to put us back to slow clock when it dozes + * for PM mode. Code below matches the wake override bit with + * current forcefastclk state. Only setting bit in wake_override + * instead of waking ucode immediately since old code had this + * behavior. Older code set wlc->forcefastclk but only had the + * wake happen if the wakup_ucode work (protected by an up + * check) was executed just below. + */ + if (wlc_hw->forcefastclk) + mboolset(wlc_hw->wake_override, + BRCMS_WAKE_OVERRIDE_FORCEFAST); + else + mboolclr(wlc_hw->wake_override, + BRCMS_WAKE_OVERRIDE_FORCEFAST); + } +} + +/* set or clear ucode host flag bits + * it has an optimization for no-change write + * it only writes through shared memory when the core has clock; + * pre-CLK changes should use wlc_write_mhf to get around the optimization + * + * + * bands values are: BRCM_BAND_AUTO <--- Current band only + * BRCM_BAND_5G <--- 5G band only + * BRCM_BAND_2G <--- 2G band only + * BRCM_BAND_ALL <--- All bands + */ +void +brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val, + int bands) +{ + u16 save; + u16 addr[MHFMAX] = { + M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4, + M_HOST_FLAGS5 + }; + struct brcms_hw_band *band; + + if ((val & ~mask) || idx >= MHFMAX) + return; /* error condition */ + + switch (bands) { + /* Current band only or all bands, + * then set the band to current band + */ + case BRCM_BAND_AUTO: + case BRCM_BAND_ALL: + band = wlc_hw->band; + break; + case BRCM_BAND_5G: + band = wlc_hw->bandstate[BAND_5G_INDEX]; + break; + case BRCM_BAND_2G: + band = wlc_hw->bandstate[BAND_2G_INDEX]; + break; + default: + band = NULL; /* error condition */ + } + + if (band) { + save = band->mhfs[idx]; + band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val; + + /* optimization: only write through if changed, and + * changed band is the current band + */ + if (wlc_hw->clk && (band->mhfs[idx] != save) + && (band == wlc_hw->band)) + brcms_b_write_shm(wlc_hw, addr[idx], + (u16) band->mhfs[idx]); + } + + if (bands == BRCM_BAND_ALL) { + wlc_hw->bandstate[0]->mhfs[idx] = + (wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val; + wlc_hw->bandstate[1]->mhfs[idx] = + (wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val; + } +} + +/* set the maccontrol register to desired reset state and + * initialize the sw cache of the register + */ +static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw) +{ + /* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */ + wlc_hw->maccontrol = 0; + wlc_hw->suspended_fifos = 0; + wlc_hw->wake_override = 0; + wlc_hw->mute_override = 0; + brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE); +} + +/* + * write the software state of maccontrol and + * overrides to the maccontrol register + */ +static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw) +{ + u32 maccontrol = wlc_hw->maccontrol; + + /* OR in the wake bit if overridden */ + if (wlc_hw->wake_override) + maccontrol |= MCTL_WAKE; + + /* set AP and INFRA bits for mute if needed */ + if (wlc_hw->mute_override) { + maccontrol &= ~(MCTL_AP); + maccontrol |= MCTL_INFRA; + } + + W_REG(&wlc_hw->regs->maccontrol, maccontrol); +} + +/* set or clear maccontrol bits */ +void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val) +{ + u32 maccontrol; + u32 new_maccontrol; + + if (val & ~mask) + return; /* error condition */ + maccontrol = wlc_hw->maccontrol; + new_maccontrol = (maccontrol & ~mask) | val; + + /* if the new maccontrol value is the same as the old, nothing to do */ + if (new_maccontrol == maccontrol) + return; + + /* something changed, cache the new value */ + wlc_hw->maccontrol = new_maccontrol; + + /* write the new values with overrides applied */ + brcms_c_mctrl_write(wlc_hw); +} + +void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw, + u32 override_bit) +{ + if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) { + mboolset(wlc_hw->wake_override, override_bit); + return; + } + + mboolset(wlc_hw->wake_override, override_bit); + + brcms_c_mctrl_write(wlc_hw); + brcms_b_wait_for_wake(wlc_hw); +} + +void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw, + u32 override_bit) +{ + mboolclr(wlc_hw->wake_override, override_bit); + + if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) + return; + + brcms_c_mctrl_write(wlc_hw); +} + +/* When driver needs ucode to stop beaconing, it has to make sure that + * MCTL_AP is clear and MCTL_INFRA is set + * Mode MCTL_AP MCTL_INFRA + * AP 1 1 + * STA 0 1 <--- This will ensure no beacons + * IBSS 0 0 + */ +static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw) +{ + wlc_hw->mute_override = 1; + + /* if maccontrol already has AP == 0 and INFRA == 1 without this + * override, then there is no change to write + */ + if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA) + return; + + brcms_c_mctrl_write(wlc_hw); +} + +/* Clear the override on AP and INFRA bits */ +static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw) +{ + if (wlc_hw->mute_override == 0) + return; + + wlc_hw->mute_override = 0; + + /* if maccontrol already has AP == 0 and INFRA == 1 without this + * override, then there is no change to write + */ + if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA) + return; + + brcms_c_mctrl_write(wlc_hw); +} + +/* + * Write a MAC address to the given match reg offset in the RXE match engine. + */ +static void +brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset, + const u8 *addr) +{ + struct d11regs __iomem *regs; + u16 mac_l; + u16 mac_m; + u16 mac_h; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n", + wlc_hw->unit); + + regs = wlc_hw->regs; + mac_l = addr[0] | (addr[1] << 8); + mac_m = addr[2] | (addr[3] << 8); + mac_h = addr[4] | (addr[5] << 8); + + /* enter the MAC addr into the RXE match registers */ + W_REG(®s->rcm_ctl, RCM_INC_DATA | match_reg_offset); + W_REG(®s->rcm_mat_data, mac_l); + W_REG(®s->rcm_mat_data, mac_m); + W_REG(®s->rcm_mat_data, mac_h); + +} + +void +brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len, + void *buf) +{ + struct d11regs __iomem *regs; + u32 word; + __le32 word_le; + __be32 word_be; + bool be_bit; + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + regs = wlc_hw->regs; + W_REG(®s->tplatewrptr, offset); + + /* if MCTL_BIGEND bit set in mac control register, + * the chip swaps data in fifo, as well as data in + * template ram + */ + be_bit = (R_REG(®s->maccontrol) & MCTL_BIGEND) != 0; + + while (len > 0) { + memcpy(&word, buf, sizeof(u32)); + + if (be_bit) { + word_be = cpu_to_be32(word); + word = *(u32 *)&word_be; + } else { + word_le = cpu_to_le32(word); + word = *(u32 *)&word_le; + } + + W_REG(®s->tplatewrdata, word); + + buf = (u8 *) buf + sizeof(u32); + len -= sizeof(u32); + } +} + +static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin) +{ + wlc_hw->band->CWmin = newmin; + + W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMIN); + (void)R_REG(&wlc_hw->regs->objaddr); + W_REG(&wlc_hw->regs->objdata, newmin); +} + +static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax) +{ + wlc_hw->band->CWmax = newmax; + + W_REG(&wlc_hw->regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_CWMAX); + (void)R_REG(&wlc_hw->regs->objaddr); + W_REG(&wlc_hw->regs->objdata, newmax); +} + +void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw) +{ + bool fastclk; + + /* request FAST clock if not on */ + fastclk = wlc_hw->forcefastclk; + if (!fastclk) + brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + + wlc_phy_bw_state_set(wlc_hw->band->pi, bw); + + brcms_b_phy_reset(wlc_hw); + wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi)); + + /* restore the clk */ + if (!fastclk) + brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); +} + +static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw) +{ + u16 v; + struct brcms_c_info *wlc = wlc_hw->wlc; + /* update SYNTHPU_DLY */ + + if (BRCMS_ISLCNPHY(wlc->band)) + v = SYNTHPU_DLY_LPPHY_US; + else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3))) + v = SYNTHPU_DLY_NPHY_US; + else + v = SYNTHPU_DLY_BPHY_US; + + brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v); +} + +static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw) +{ + u16 phyctl; + u16 phytxant = wlc_hw->bmac_phytxant; + u16 mask = PHY_TXC_ANT_MASK; + + /* set the Probe Response frame phy control word */ + phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS); + phyctl = (phyctl & ~mask) | phytxant; + brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl); + + /* set the Response (ACK/CTS) frame phy control word */ + phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD); + phyctl = (phyctl & ~mask) | phytxant; + brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl); +} + +static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw, + u8 rate) +{ + uint i; + u8 plcp_rate = 0; + struct plcp_signal_rate_lookup { + u8 rate; + u8 signal_rate; + }; + /* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */ + const struct plcp_signal_rate_lookup rate_lookup[] = { + {BRCM_RATE_6M, 0xB}, + {BRCM_RATE_9M, 0xF}, + {BRCM_RATE_12M, 0xA}, + {BRCM_RATE_18M, 0xE}, + {BRCM_RATE_24M, 0x9}, + {BRCM_RATE_36M, 0xD}, + {BRCM_RATE_48M, 0x8}, + {BRCM_RATE_54M, 0xC} + }; + + for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) { + if (rate == rate_lookup[i].rate) { + plcp_rate = rate_lookup[i].signal_rate; + break; + } + } + + /* Find the SHM pointer to the rate table entry by looking in the + * Direct-map Table + */ + return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2)); +} + +static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw) +{ + u8 rate; + u8 rates[8] = { + BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M, + BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M + }; + u16 entry_ptr; + u16 pctl1; + uint i; + + if (!BRCMS_PHY_11N_CAP(wlc_hw->band)) + return; + + /* walk the phy rate table and update the entries */ + for (i = 0; i < ARRAY_SIZE(rates); i++) { + rate = rates[i]; + + entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate); + + /* read the SHM Rate Table entry OFDM PCTL1 values */ + pctl1 = + brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS); + + /* modify the value */ + pctl1 &= ~PHY_TXC1_MODE_MASK; + pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT); + + /* Update the SHM Rate Table entry OFDM PCTL1 values */ + brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS, + pctl1); + } +} + +/* band-specific init */ +static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + + BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, + wlc_hw->band->bandunit); + + brcms_c_ucode_bsinit(wlc_hw); + + wlc_phy_init(wlc_hw->band->pi, chanspec); + + brcms_c_ucode_txant_set(wlc_hw); + + /* + * cwmin is band-specific, update hardware + * with value for current band + */ + brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin); + brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax); + + brcms_b_update_slot_timing(wlc_hw, + wlc_hw->band->bandtype == BRCM_BAND_5G ? + true : wlc_hw->shortslot); + + /* write phytype and phyvers */ + brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype); + brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev); + + /* + * initialize the txphyctl1 rate table since + * shmem is shared between bands + */ + brcms_upd_ofdm_pctl1_table(wlc_hw); + + brcms_b_upd_synthpu(wlc_hw); +} + +/* Perform a soft reset of the PHY PLL */ +void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw) +{ + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + ai_corereg(wlc_hw->sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_addr), ~0, 0); + udelay(1); + ai_corereg(wlc_hw->sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_data), 0x4, 0); + udelay(1); + ai_corereg(wlc_hw->sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_data), 0x4, 4); + udelay(1); + ai_corereg(wlc_hw->sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_data), 0x4, 0); + udelay(1); +} + +/* light way to turn on phy clock without reset for NPHY only + * refer to brcms_b_core_phy_clk for full version + */ +void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk) +{ + /* support(necessary for NPHY and HYPHY) only */ + if (!BRCMS_ISNPHY(wlc_hw->band)) + return; + + if (ON == clk) + ai_core_cflags(wlc_hw->sih, SICF_FGC, SICF_FGC); + else + ai_core_cflags(wlc_hw->sih, SICF_FGC, 0); + +} + +void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk) +{ + if (ON == clk) + ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, SICF_MPCLKE); + else + ai_core_cflags(wlc_hw->sih, SICF_MPCLKE, 0); +} + +void brcms_b_phy_reset(struct brcms_hardware *wlc_hw) +{ + struct brcms_phy_pub *pih = wlc_hw->band->pi; + u32 phy_bw_clkbits; + bool phy_in_reset = false; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + if (pih == NULL) + return; + + phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi); + + /* Specific reset sequence required for NPHY rev 3 and 4 */ + if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) && + NREV_LE(wlc_hw->band->phyrev, 4)) { + /* Set the PHY bandwidth */ + ai_core_cflags(wlc_hw->sih, SICF_BWMASK, phy_bw_clkbits); + + udelay(1); + + /* Perform a soft reset of the PHY PLL */ + brcms_b_core_phypll_reset(wlc_hw); + + /* reset the PHY */ + ai_core_cflags(wlc_hw->sih, (SICF_PRST | SICF_PCLKE), + (SICF_PRST | SICF_PCLKE)); + phy_in_reset = true; + } else { + ai_core_cflags(wlc_hw->sih, + (SICF_PRST | SICF_PCLKE | SICF_BWMASK), + (SICF_PRST | SICF_PCLKE | phy_bw_clkbits)); + } + + udelay(2); + brcms_b_core_phy_clk(wlc_hw, ON); + + if (pih) + wlc_phy_anacore(pih, ON); +} + +/* switch to and initialize new band */ +static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit, + u16 chanspec) { + struct brcms_c_info *wlc = wlc_hw->wlc; + u32 macintmask; + + /* Enable the d11 core before accessing it */ + if (!ai_iscoreup(wlc_hw->sih)) { + ai_core_reset(wlc_hw->sih, 0, 0); + brcms_c_mctrl_reset(wlc_hw); + } + + macintmask = brcms_c_setband_inact(wlc, bandunit); + + if (!wlc_hw->up) + return; + + brcms_b_core_phy_clk(wlc_hw, ON); + + /* band-specific initializations */ + brcms_b_bsinit(wlc, chanspec); + + /* + * If there are any pending software interrupt bits, + * then replace these with a harmless nonzero value + * so brcms_c_dpc() will re-enable interrupts when done. + */ + if (wlc->macintstatus) + wlc->macintstatus = MI_DMAINT; + + /* restore macintmask */ + brcms_intrsrestore(wlc->wl, macintmask); + + /* ucode should still be suspended.. */ + WARN_ON((R_REG(&wlc_hw->regs->maccontrol) & MCTL_EN_MAC) != 0); +} + +static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw) +{ + + /* reject unsupported corerev */ + if (!CONF_HAS(D11CONF, wlc_hw->corerev)) { + wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n", + wlc_hw->corerev); + return false; + } + + return true; +} + +/* Validate some board info parameters */ +static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw) +{ + uint boardrev = wlc_hw->boardrev; + + /* 4 bits each for board type, major, minor, and tiny version */ + uint brt = (boardrev & 0xf000) >> 12; + uint b0 = (boardrev & 0xf00) >> 8; + uint b1 = (boardrev & 0xf0) >> 4; + uint b2 = boardrev & 0xf; + + /* voards from other vendors are always considered valid */ + if (wlc_hw->sih->boardvendor != PCI_VENDOR_ID_BROADCOM) + return true; + + /* do some boardrev sanity checks when boardvendor is Broadcom */ + if (boardrev == 0) + return false; + + if (boardrev <= 0xff) + return true; + + if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9) + || (b2 > 9)) + return false; + + return true; +} + +static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw) +{ + enum brcms_srom_id var_id = BRCMS_SROM_MACADDR; + char *macaddr; + + /* If macaddr exists, use it (Sromrev4, CIS, ...). */ + macaddr = getvar(wlc_hw->sih, var_id); + if (macaddr != NULL) + return macaddr; + + if (wlc_hw->_nbands > 1) + var_id = BRCMS_SROM_ET1MACADDR; + else + var_id = BRCMS_SROM_IL0MACADDR; + + macaddr = getvar(wlc_hw->sih, var_id); + if (macaddr == NULL) + wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr " + "getvar(%d) not found\n", wlc_hw->unit, var_id); + + return macaddr; +} + +/* power both the pll and external oscillator on/off */ +static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want) +{ + BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want); + + /* + * dont power down if plldown is false or + * we must poll hw radio disable + */ + if (!want && wlc_hw->pllreq) + return; + + if (wlc_hw->sih) + ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want); + + wlc_hw->sbclk = want; + if (!wlc_hw->sbclk) { + wlc_hw->clk = false; + if (wlc_hw->band && wlc_hw->band->pi) + wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); + } +} + +/* + * Return true if radio is disabled, otherwise false. + * hw radio disable signal is an external pin, users activate it asynchronously + * this function could be called when driver is down and w/o clock + * it operates on different registers depending on corerev and boardflag. + */ +static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw) +{ + bool v, clk, xtal; + u32 resetbits = 0, flags = 0; + + xtal = wlc_hw->sbclk; + if (!xtal) + brcms_b_xtal(wlc_hw, ON); + + /* may need to take core out of reset first */ + clk = wlc_hw->clk; + if (!clk) { + /* + * mac no longer enables phyclk automatically when driver + * accesses phyreg throughput mac. This can be skipped since + * only mac reg is accessed below + */ + flags |= SICF_PCLKE; + + /* + * AI chip doesn't restore bar0win2 on + * hibernation/resume, need sw fixup + */ + if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || + (wlc_hw->sih->chip == BCM43225_CHIP_ID)) + wlc_hw->regs = (struct d11regs __iomem *) + ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); + ai_core_reset(wlc_hw->sih, flags, resetbits); + brcms_c_mctrl_reset(wlc_hw); + } + + v = ((R_REG(&wlc_hw->regs->phydebug) & PDBG_RFD) != 0); + + /* put core back into reset */ + if (!clk) + ai_core_disable(wlc_hw->sih, 0); + + if (!xtal) + brcms_b_xtal(wlc_hw, OFF); + + return v; +} + +static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo) +{ + struct dma_pub *di = wlc_hw->di[fifo]; + return dma_rxreset(di); +} + +/* d11 core reset + * ensure fask clock during reset + * reset dma + * reset d11(out of reset) + * reset phy(out of reset) + * clear software macintstatus for fresh new start + * one testing hack wlc_hw->noreset will bypass the d11/phy reset + */ +void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) +{ + struct d11regs __iomem *regs; + uint i; + bool fastclk; + u32 resetbits = 0; + + if (flags == BRCMS_USE_COREFLAGS) + flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0); + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + regs = wlc_hw->regs; + + /* request FAST clock if not on */ + fastclk = wlc_hw->forcefastclk; + if (!fastclk) + brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + + /* reset the dma engines except first time thru */ + if (ai_iscoreup(wlc_hw->sih)) { + for (i = 0; i < NFIFO; i++) + if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i]))) + wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: " + "dma_txreset[%d]: cannot stop dma\n", + wlc_hw->unit, __func__, i); + + if ((wlc_hw->di[RX_FIFO]) + && (!wlc_dma_rxreset(wlc_hw, RX_FIFO))) + wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset" + "[%d]: cannot stop dma\n", + wlc_hw->unit, __func__, RX_FIFO); + } + /* if noreset, just stop the psm and return */ + if (wlc_hw->noreset) { + wlc_hw->wlc->macintstatus = 0; /* skip wl_dpc after down */ + brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0); + return; + } + + /* + * mac no longer enables phyclk automatically when driver accesses + * phyreg throughput mac, AND phy_reset is skipped at early stage when + * band->pi is invalid. need to enable PHY CLK + */ + flags |= SICF_PCLKE; + + /* + * reset the core + * In chips with PMU, the fastclk request goes through d11 core + * reg 0x1e0, which is cleared by the core_reset. have to re-request it. + * + * This adds some delay and we can optimize it by also requesting + * fastclk through chipcommon during this period if necessary. But + * that has to work coordinate with other driver like mips/arm since + * they may touch chipcommon as well. + */ + wlc_hw->clk = false; + ai_core_reset(wlc_hw->sih, flags, resetbits); + wlc_hw->clk = true; + if (wlc_hw->band && wlc_hw->band->pi) + wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true); + + brcms_c_mctrl_reset(wlc_hw); + + if (wlc_hw->sih->cccaps & CC_CAP_PMU) + brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + + brcms_b_phy_reset(wlc_hw); + + /* turn on PHY_PLL */ + brcms_b_core_phypll_ctl(wlc_hw, true); + + /* clear sw intstatus */ + wlc_hw->wlc->macintstatus = 0; + + /* restore the clk setting */ + if (!fastclk) + brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); +} + +/* txfifo sizes needs to be modified(increased) since the newer cores + * have more memory. + */ +static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw) +{ + struct d11regs __iomem *regs = wlc_hw->regs; + u16 fifo_nu; + u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk; + u16 txfifo_def, txfifo_def1; + u16 txfifo_cmd; + + /* tx fifos start at TXFIFO_START_BLK from the Base address */ + txfifo_startblk = TXFIFO_START_BLK; + + /* sequence of operations: reset fifo, set fifo size, reset fifo */ + for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) { + + txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu]; + txfifo_def = (txfifo_startblk & 0xff) | + (((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT); + txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) | + ((((txfifo_endblk - + 1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT); + txfifo_cmd = + TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT); + + W_REG(®s->xmtfifocmd, txfifo_cmd); + W_REG(®s->xmtfifodef, txfifo_def); + W_REG(®s->xmtfifodef1, txfifo_def1); + + W_REG(®s->xmtfifocmd, txfifo_cmd); + + txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu]; + } + /* + * need to propagate to shm location to be in sync since ucode/hw won't + * do this + */ + brcms_b_write_shm(wlc_hw, M_FIFOSIZE0, + wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]); + brcms_b_write_shm(wlc_hw, M_FIFOSIZE1, + wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]); + brcms_b_write_shm(wlc_hw, M_FIFOSIZE2, + ((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw-> + xmtfifo_sz[TX_AC_BK_FIFO])); + brcms_b_write_shm(wlc_hw, M_FIFOSIZE3, + ((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw-> + xmtfifo_sz[TX_BCMC_FIFO])); +} + +/* This function is used for changing the tsf frac register + * If spur avoidance mode is off, the mac freq will be 80/120/160Mhz + * If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz + * If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz + * HTPHY Formula is 2^26/freq(MHz) e.g. + * For spuron2 - 126MHz -> 2^26/126 = 532610.0 + * - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x2082 + * For spuron: 123MHz -> 2^26/123 = 545600.5 + * - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x5341 + * For spur off: 120MHz -> 2^26/120 = 559240.5 + * - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x8889 + */ + +void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode) +{ + struct d11regs __iomem *regs = wlc_hw->regs; + + if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || + (wlc_hw->sih->chip == BCM43225_CHIP_ID)) { + if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */ + W_REG(®s->tsf_clk_frac_l, 0x2082); + W_REG(®s->tsf_clk_frac_h, 0x8); + } else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */ + W_REG(®s->tsf_clk_frac_l, 0x5341); + W_REG(®s->tsf_clk_frac_h, 0x8); + } else { /* 120Mhz */ + W_REG(®s->tsf_clk_frac_l, 0x8889); + W_REG(®s->tsf_clk_frac_h, 0x8); + } + } else if (BRCMS_ISLCNPHY(wlc_hw->band)) { + if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */ + W_REG(®s->tsf_clk_frac_l, 0x7CE0); + W_REG(®s->tsf_clk_frac_h, 0xC); + } else { /* 80Mhz */ + W_REG(®s->tsf_clk_frac_l, 0xCCCD); + W_REG(®s->tsf_clk_frac_h, 0xC); + } + } +} + +/* Initialize GPIOs that are controlled by D11 core */ +static void brcms_c_gpio_init(struct brcms_c_info *wlc) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + struct d11regs __iomem *regs; + u32 gc, gm; + + regs = wlc_hw->regs; + + /* use GPIO select 0 to get all gpio signals from the gpio out reg */ + brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0); + + /* + * Common GPIO setup: + * G0 = LED 0 = WLAN Activity + * G1 = LED 1 = WLAN 2.4 GHz Radio State + * G2 = LED 2 = WLAN 5 GHz Radio State + * G4 = radio disable input (HI enabled, LO disabled) + */ + + gc = gm = 0; + + /* Allocate GPIOs for mimo antenna diversity feature */ + if (wlc_hw->antsel_type == ANTSEL_2x3) { + /* Enable antenna diversity, use 2x3 mode */ + brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN, + MHF3_ANTSEL_EN, BRCM_BAND_ALL); + brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, + MHF3_ANTSEL_MODE, BRCM_BAND_ALL); + + /* init superswitch control */ + wlc_phy_antsel_init(wlc_hw->band->pi, false); + + } else if (wlc_hw->antsel_type == ANTSEL_2x4) { + gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13); + /* + * The board itself is powered by these GPIOs + * (when not sending pattern) so set them high + */ + OR_REG(®s->psm_gpio_oe, + (BOARD_GPIO_12 | BOARD_GPIO_13)); + OR_REG(®s->psm_gpio_out, + (BOARD_GPIO_12 | BOARD_GPIO_13)); + + /* Enable antenna diversity, use 2x4 mode */ + brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN, + MHF3_ANTSEL_EN, BRCM_BAND_ALL); + brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0, + BRCM_BAND_ALL); + + /* Configure the desired clock to be 4Mhz */ + brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV, + ANTSEL_CLKDIV_4MHZ); + } + + /* + * gpio 9 controls the PA. ucode is responsible + * for wiggling out and oe + */ + if (wlc_hw->boardflags & BFL_PACTRL) + gm |= gc |= BOARD_GPIO_PACTRL; + + /* apply to gpiocontrol register */ + ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY); +} + +static void brcms_ucode_write(struct brcms_hardware *wlc_hw, + const __le32 ucode[], const size_t nbytes) +{ + struct d11regs __iomem *regs = wlc_hw->regs; + uint i; + uint count; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + count = (nbytes / sizeof(u32)); + + W_REG(®s->objaddr, (OBJADDR_AUTO_INC | OBJADDR_UCM_SEL)); + (void)R_REG(®s->objaddr); + for (i = 0; i < count; i++) + W_REG(®s->objdata, le32_to_cpu(ucode[i])); + +} + +static void brcms_ucode_download(struct brcms_hardware *wlc_hw) +{ + struct brcms_c_info *wlc; + struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; + + wlc = wlc_hw->wlc; + + if (wlc_hw->ucode_loaded) + return; + + if (D11REV_IS(wlc_hw->corerev, 23)) { + if (BRCMS_ISNPHY(wlc_hw->band)) { + brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo, + ucode->bcm43xx_16_mimosz); + wlc_hw->ucode_loaded = true; + } else + wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in " + "corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); + } else if (D11REV_IS(wlc_hw->corerev, 24)) { + if (BRCMS_ISLCNPHY(wlc_hw->band)) { + brcms_ucode_write(wlc_hw, ucode->bcm43xx_24_lcn, + ucode->bcm43xx_24_lcnsz); + wlc_hw->ucode_loaded = true; + } else { + wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in " + "corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); + } + } +} + +void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant) +{ + /* update sw state */ + wlc_hw->bmac_phytxant = phytxant; + + /* push to ucode if up */ + if (!wlc_hw->up) + return; + brcms_c_ucode_txant_set(wlc_hw); + +} + +u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw) +{ + return (u16) wlc_hw->wlc->stf->txant; +} + +void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type) +{ + wlc_hw->antsel_type = antsel_type; + + /* Update the antsel type for phy module to use */ + wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type); +} + +static void brcms_c_fatal_error(struct brcms_c_info *wlc) +{ + wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n", + wlc->pub->unit); + brcms_init(wlc->wl); +} + +static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw) +{ + bool fatal = false; + uint unit; + uint intstatus, idx; + struct d11regs __iomem *regs = wlc_hw->regs; + struct wiphy *wiphy = wlc_hw->wlc->wiphy; + + unit = wlc_hw->unit; + + for (idx = 0; idx < NFIFO; idx++) { + /* read intstatus register and ignore any non-error bits */ + intstatus = + R_REG(®s->intctrlregs[idx].intstatus) & I_ERRORS; + if (!intstatus) + continue; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n", + unit, idx, intstatus); + + if (intstatus & I_RO) { + wiphy_err(wiphy, "wl%d: fifo %d: receive fifo " + "overflow\n", unit, idx); + fatal = true; + } + + if (intstatus & I_PC) { + wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n", + unit, idx); + fatal = true; + } + + if (intstatus & I_PD) { + wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit, + idx); + fatal = true; + } + + if (intstatus & I_DE) { + wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol " + "error\n", unit, idx); + fatal = true; + } + + if (intstatus & I_RU) + wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor " + "underflow\n", idx, unit); + + if (intstatus & I_XU) { + wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo " + "underflow\n", idx, unit); + fatal = true; + } + + if (fatal) { + brcms_c_fatal_error(wlc_hw->wlc); /* big hammer */ + break; + } else + W_REG(®s->intctrlregs[idx].intstatus, + intstatus); + } +} + +void brcms_c_intrson(struct brcms_c_info *wlc) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + wlc->macintmask = wlc->defmacintmask; + W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); +} + +/* + * callback for siutils.c, which has only wlc handler, no wl they both check + * up, not only because there is no need to off/restore d11 interrupt but also + * because per-port code may require sync with valid interrupt. + */ +static u32 brcms_c_wlintrsoff(struct brcms_c_info *wlc) +{ + if (!wlc->hw->up) + return 0; + + return brcms_intrsoff(wlc->wl); +} + +static void brcms_c_wlintrsrestore(struct brcms_c_info *wlc, u32 macintmask) +{ + if (!wlc->hw->up) + return; + + brcms_intrsrestore(wlc->wl, macintmask); +} + +u32 brcms_c_intrsoff(struct brcms_c_info *wlc) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + u32 macintmask; + + if (!wlc_hw->clk) + return 0; + + macintmask = wlc->macintmask; /* isr can still happen */ + + W_REG(&wlc_hw->regs->macintmask, 0); + (void)R_REG(&wlc_hw->regs->macintmask); /* sync readback */ + udelay(1); /* ensure int line is no longer driven */ + wlc->macintmask = 0; + + /* return previous macintmask; resolve race between us and our isr */ + return wlc->macintstatus ? 0 : macintmask; +} + +void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + if (!wlc_hw->clk) + return; + + wlc->macintmask = macintmask; + W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); +} + +static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw, + uint tx_fifo) +{ + u8 fifo = 1 << tx_fifo; + + /* Two clients of this code, 11h Quiet period and scanning. */ + + /* only suspend if not already suspended */ + if ((wlc_hw->suspended_fifos & fifo) == fifo) + return; + + /* force the core awake only if not already */ + if (wlc_hw->suspended_fifos == 0) + brcms_c_ucode_wake_override_set(wlc_hw, + BRCMS_WAKE_OVERRIDE_TXFIFO); + + wlc_hw->suspended_fifos |= fifo; + + if (wlc_hw->di[tx_fifo]) { + /* + * Suspending AMPDU transmissions in the middle can cause + * underflow which may result in mismatch between ucode and + * driver so suspend the mac before suspending the FIFO + */ + if (BRCMS_PHY_11N_CAP(wlc_hw->band)) + brcms_c_suspend_mac_and_wait(wlc_hw->wlc); + + dma_txsuspend(wlc_hw->di[tx_fifo]); + + if (BRCMS_PHY_11N_CAP(wlc_hw->band)) + brcms_c_enable_mac(wlc_hw->wlc); + } +} + +static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw, + uint tx_fifo) +{ + /* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case + * but need to be done here for PIO otherwise the watchdog will catch + * the inconsistency and fire + */ + /* Two clients of this code, 11h Quiet period and scanning. */ + if (wlc_hw->di[tx_fifo]) + dma_txresume(wlc_hw->di[tx_fifo]); + + /* allow core to sleep again */ + if (wlc_hw->suspended_fifos == 0) + return; + else { + wlc_hw->suspended_fifos &= ~(1 << tx_fifo); + if (wlc_hw->suspended_fifos == 0) + brcms_c_ucode_wake_override_clear(wlc_hw, + BRCMS_WAKE_OVERRIDE_TXFIFO); + } +} + +static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags) +{ + static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; + + if (on) { + /* suspend tx fifos */ + brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO); + brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO); + brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO); + brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO); + + /* zero the address match register so we do not send ACKs */ + brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, + null_ether_addr); + } else { + /* resume tx fifos */ + brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO); + brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO); + brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO); + brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO); + + /* Restore address */ + brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, + wlc_hw->etheraddr); + } + + wlc_phy_mute_upd(wlc_hw->band->pi, on, flags); + + if (on) + brcms_c_ucode_mute_override_set(wlc_hw); + else + brcms_c_ucode_mute_override_clear(wlc_hw); +} + +/* + * Read and clear macintmask and macintstatus and intstatus registers. + * This routine should be called with interrupts off + * Return: + * -1 if brcms_deviceremoved(wlc) evaluates to true; + * 0 if the interrupt is not for us, or we are in some special cases; + * device interrupt status bits otherwise. + */ +static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + struct d11regs __iomem *regs = wlc_hw->regs; + u32 macintstatus; + + /* macintstatus includes a DMA interrupt summary bit */ + macintstatus = R_REG(®s->macintstatus); + + BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit, + macintstatus); + + /* detect cardbus removed, in power down(suspend) and in reset */ + if (brcms_deviceremoved(wlc)) + return -1; + + /* brcms_deviceremoved() succeeds even when the core is still resetting, + * handle that case here. + */ + if (macintstatus == 0xffffffff) + return 0; + + /* defer unsolicited interrupts */ + macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask); + + /* if not for us */ + if (macintstatus == 0) + return 0; + + /* interrupts are already turned off for CFE build + * Caution: For CFE Turning off the interrupts again has some undesired + * consequences + */ + /* turn off the interrupts */ + W_REG(®s->macintmask, 0); + (void)R_REG(®s->macintmask); /* sync readback */ + wlc->macintmask = 0; + + /* clear device interrupts */ + W_REG(®s->macintstatus, macintstatus); + + /* MI_DMAINT is indication of non-zero intstatus */ + if (macintstatus & MI_DMAINT) + /* + * only fifo interrupt enabled is I_RI in + * RX_FIFO. If MI_DMAINT is set, assume it + * is set and clear the interrupt. + */ + W_REG(®s->intctrlregs[RX_FIFO].intstatus, + DEF_RXINTMASK); + + return macintstatus; +} + +/* Update wlc->macintstatus and wlc->intstatus[]. */ +/* Return true if they are updated successfully. false otherwise */ +bool brcms_c_intrsupd(struct brcms_c_info *wlc) +{ + u32 macintstatus; + + /* read and clear macintstatus and intstatus registers */ + macintstatus = wlc_intstatus(wlc, false); + + /* device is removed */ + if (macintstatus == 0xffffffff) + return false; + + /* update interrupt status in software */ + wlc->macintstatus |= macintstatus; + + return true; +} + +/* + * First-level interrupt processing. + * Return true if this was our interrupt, false otherwise. + * *wantdpc will be set to true if further brcms_c_dpc() processing is required, + * false otherwise. + */ +bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + u32 macintstatus; + + *wantdpc = false; + + if (!wlc_hw->up || !wlc->macintmask) + return false; + + /* read and clear macintstatus and intstatus registers */ + macintstatus = wlc_intstatus(wlc, true); + + if (macintstatus == 0xffffffff) + wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code" + " path\n"); + + /* it is not for us */ + if (macintstatus == 0) + return false; + + *wantdpc = true; + + /* save interrupt status bits */ + wlc->macintstatus = macintstatus; + + return true; + +} + +void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + struct d11regs __iomem *regs = wlc_hw->regs; + u32 mc, mi; + struct wiphy *wiphy = wlc->wiphy; + + BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, + wlc_hw->band->bandunit); + + /* + * Track overlapping suspend requests + */ + wlc_hw->mac_suspend_depth++; + if (wlc_hw->mac_suspend_depth > 1) + return; + + /* force the core awake */ + brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND); + + mc = R_REG(®s->maccontrol); + + if (mc == 0xffffffff) { + wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, + __func__); + brcms_down(wlc->wl); + return; + } + WARN_ON(mc & MCTL_PSM_JMP_0); + WARN_ON(!(mc & MCTL_PSM_RUN)); + WARN_ON(!(mc & MCTL_EN_MAC)); + + mi = R_REG(®s->macintstatus); + if (mi == 0xffffffff) { + wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, + __func__); + brcms_down(wlc->wl); + return; + } + WARN_ON(mi & MI_MACSSPNDD); + + brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0); + + SPINWAIT(!(R_REG(®s->macintstatus) & MI_MACSSPNDD), + BRCMS_MAX_MAC_SUSPEND); + + if (!(R_REG(®s->macintstatus) & MI_MACSSPNDD)) { + wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS" + " and MI_MACSSPNDD is still not on.\n", + wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND); + wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, " + "psm_brc 0x%04x\n", wlc_hw->unit, + R_REG(®s->psmdebug), + R_REG(®s->phydebug), + R_REG(®s->psm_brc)); + } + + mc = R_REG(®s->maccontrol); + if (mc == 0xffffffff) { + wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, + __func__); + brcms_down(wlc->wl); + return; + } + WARN_ON(mc & MCTL_PSM_JMP_0); + WARN_ON(!(mc & MCTL_PSM_RUN)); + WARN_ON(mc & MCTL_EN_MAC); +} + +void brcms_c_enable_mac(struct brcms_c_info *wlc) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + struct d11regs __iomem *regs = wlc_hw->regs; + u32 mc, mi; + + BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit, + wlc->band->bandunit); + + /* + * Track overlapping suspend requests + */ + wlc_hw->mac_suspend_depth--; + if (wlc_hw->mac_suspend_depth > 0) + return; + + mc = R_REG(®s->maccontrol); + WARN_ON(mc & MCTL_PSM_JMP_0); + WARN_ON(mc & MCTL_EN_MAC); + WARN_ON(!(mc & MCTL_PSM_RUN)); + + brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC); + W_REG(®s->macintstatus, MI_MACSSPNDD); + + mc = R_REG(®s->maccontrol); + WARN_ON(mc & MCTL_PSM_JMP_0); + WARN_ON(!(mc & MCTL_EN_MAC)); + WARN_ON(!(mc & MCTL_PSM_RUN)); + + mi = R_REG(®s->macintstatus); + WARN_ON(mi & MI_MACSSPNDD); + + brcms_c_ucode_wake_override_clear(wlc_hw, + BRCMS_WAKE_OVERRIDE_MACSUSPEND); +} + +void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode) +{ + wlc_hw->hw_stf_ss_opmode = stf_mode; + + if (wlc_hw->clk) + brcms_upd_ofdm_pctl1_table(wlc_hw); +} + +static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw) +{ + struct d11regs __iomem *regs; + u32 w, val; + struct wiphy *wiphy = wlc_hw->wlc->wiphy; + + BCMMSG(wiphy, "wl%d\n", wlc_hw->unit); + + regs = wlc_hw->regs; + + /* Validate dchip register access */ + + W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); + (void)R_REG(®s->objaddr); + w = R_REG(®s->objdata); + + /* Can we write and read back a 32bit register? */ + W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); + (void)R_REG(®s->objaddr); + W_REG(®s->objdata, (u32) 0xaa5555aa); + + W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); + (void)R_REG(®s->objaddr); + val = R_REG(®s->objdata); + if (val != (u32) 0xaa5555aa) { + wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, " + "expected 0xaa5555aa\n", wlc_hw->unit, val); + return false; + } + + W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); + (void)R_REG(®s->objaddr); + W_REG(®s->objdata, (u32) 0x55aaaa55); + + W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); + (void)R_REG(®s->objaddr); + val = R_REG(®s->objdata); + if (val != (u32) 0x55aaaa55) { + wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, " + "expected 0x55aaaa55\n", wlc_hw->unit, val); + return false; + } + + W_REG(®s->objaddr, OBJADDR_SHM_SEL | 0); + (void)R_REG(®s->objaddr); + W_REG(®s->objdata, w); + + /* clear CFPStart */ + W_REG(®s->tsf_cfpstart, 0); + + w = R_REG(®s->maccontrol); + if ((w != (MCTL_IHR_EN | MCTL_WAKE)) && + (w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) { + wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = " + "0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w, + (MCTL_IHR_EN | MCTL_WAKE), + (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE)); + return false; + } + + return true; +} + +#define PHYPLL_WAIT_US 100000 + +void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) +{ + struct d11regs __iomem *regs; + u32 tmp; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + tmp = 0; + regs = wlc_hw->regs; + + if (on) { + if ((wlc_hw->sih->chip == BCM4313_CHIP_ID)) { + OR_REG(®s->clk_ctl_st, + (CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL | + CCS_ERSRC_REQ_PHYPLL)); + SPINWAIT((R_REG(®s->clk_ctl_st) & + (CCS_ERSRC_AVAIL_HT)) != (CCS_ERSRC_AVAIL_HT), + PHYPLL_WAIT_US); + + tmp = R_REG(®s->clk_ctl_st); + if ((tmp & (CCS_ERSRC_AVAIL_HT)) != + (CCS_ERSRC_AVAIL_HT)) + wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY" + " PLL failed\n", __func__); + } else { + OR_REG(®s->clk_ctl_st, + (CCS_ERSRC_REQ_D11PLL | CCS_ERSRC_REQ_PHYPLL)); + SPINWAIT((R_REG(®s->clk_ctl_st) & + (CCS_ERSRC_AVAIL_D11PLL | + CCS_ERSRC_AVAIL_PHYPLL)) != + (CCS_ERSRC_AVAIL_D11PLL | + CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US); + + tmp = R_REG(®s->clk_ctl_st); + if ((tmp & + (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) + != + (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL)) + wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on " + "PHY PLL failed\n", __func__); + } + } else { + /* + * Since the PLL may be shared, other cores can still + * be requesting it; so we'll deassert the request but + * not wait for status to comply. + */ + AND_REG(®s->clk_ctl_st, ~CCS_ERSRC_REQ_PHYPLL); + tmp = R_REG(®s->clk_ctl_st); + } +} + +static void brcms_c_coredisable(struct brcms_hardware *wlc_hw) +{ + bool dev_gone; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + dev_gone = brcms_deviceremoved(wlc_hw->wlc); + + if (dev_gone) + return; + + if (wlc_hw->noreset) + return; + + /* radio off */ + wlc_phy_switch_radio(wlc_hw->band->pi, OFF); + + /* turn off analog core */ + wlc_phy_anacore(wlc_hw->band->pi, OFF); + + /* turn off PHYPLL to save power */ + brcms_b_core_phypll_ctl(wlc_hw, false); + + wlc_hw->clk = false; + ai_core_disable(wlc_hw->sih, 0); + wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); +} + +static void brcms_c_flushqueues(struct brcms_c_info *wlc) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + uint i; + + /* free any posted tx packets */ + for (i = 0; i < NFIFO; i++) + if (wlc_hw->di[i]) { + dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL); + wlc->core->txpktpend[i] = 0; + BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i); + } + + /* free any posted rx packets */ + dma_rxreclaim(wlc_hw->di[RX_FIFO]); +} + +static u16 +brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel) +{ + struct d11regs __iomem *regs = wlc_hw->regs; + u16 __iomem *objdata_lo = (u16 __iomem *)®s->objdata; + u16 __iomem *objdata_hi = objdata_lo + 1; + u16 v; + + W_REG(®s->objaddr, sel | (offset >> 2)); + (void)R_REG(®s->objaddr); + if (offset & 2) + v = R_REG(objdata_hi); + else + v = R_REG(objdata_lo); + + return v; +} + +static void +brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v, + u32 sel) +{ + struct d11regs __iomem *regs = wlc_hw->regs; + u16 __iomem *objdata_lo = (u16 __iomem *)®s->objdata; + u16 __iomem *objdata_hi = objdata_lo + 1; + + W_REG(®s->objaddr, sel | (offset >> 2)); + (void)R_REG(®s->objaddr); + if (offset & 2) + W_REG(objdata_hi, v); + else + W_REG(objdata_lo, v); +} + +/* + * Read a single u16 from shared memory. + * SHM 'offset' needs to be an even address + */ +u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset) +{ + return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL); +} + +/* + * Write a single u16 to shared memory. + * SHM 'offset' needs to be an even address + */ +void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v) +{ + brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL); +} + +/* + * Copy a buffer to shared memory of specified type . + * SHM 'offset' needs to be an even address and + * Buffer length 'len' must be an even number of bytes + * 'sel' selects the type of memory + */ +void +brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset, + const void *buf, int len, u32 sel) +{ + u16 v; + const u8 *p = (const u8 *)buf; + int i; + + if (len <= 0 || (offset & 1) || (len & 1)) + return; + + for (i = 0; i < len; i += 2) { + v = p[i] | (p[i + 1] << 8); + brcms_b_write_objmem(wlc_hw, offset + i, v, sel); + } +} + +/* + * Copy a piece of shared memory of specified type to a buffer . + * SHM 'offset' needs to be an even address and + * Buffer length 'len' must be an even number of bytes + * 'sel' selects the type of memory + */ +void +brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf, + int len, u32 sel) +{ + u16 v; + u8 *p = (u8 *) buf; + int i; + + if (len <= 0 || (offset & 1) || (len & 1)) + return; + + for (i = 0; i < len; i += 2) { + v = brcms_b_read_objmem(wlc_hw, offset + i, sel); + p[i] = v & 0xFF; + p[i + 1] = (v >> 8) & 0xFF; + } +} + +/* Copy a buffer to shared memory. + * SHM 'offset' needs to be an even address and + * Buffer length 'len' must be an even number of bytes + */ +static void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset, + const void *buf, int len) +{ + brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL); +} + +static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, + u16 SRL, u16 LRL) +{ + wlc_hw->SRL = SRL; + wlc_hw->LRL = LRL; + + /* write retry limit to SCR, shouldn't need to suspend */ + if (wlc_hw->up) { + W_REG(&wlc_hw->regs->objaddr, + OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); + (void)R_REG(&wlc_hw->regs->objaddr); + W_REG(&wlc_hw->regs->objdata, wlc_hw->SRL); + W_REG(&wlc_hw->regs->objaddr, + OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); + (void)R_REG(&wlc_hw->regs->objaddr); + W_REG(&wlc_hw->regs->objdata, wlc_hw->LRL); + } +} + +static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, u32 req_bit) +{ + if (set) { + if (mboolisset(wlc_hw->pllreq, req_bit)) + return; + + mboolset(wlc_hw->pllreq, req_bit); + + if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) { + if (!wlc_hw->sbclk) + brcms_b_xtal(wlc_hw, ON); + } + } else { + if (!mboolisset(wlc_hw->pllreq, req_bit)) + return; + + mboolclr(wlc_hw->pllreq, req_bit); + + if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) { + if (wlc_hw->sbclk) + brcms_b_xtal(wlc_hw, OFF); + } + } +} + +static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail) +{ + wlc_hw->antsel_avail = antsel_avail; +} + +/* + * conditions under which the PM bit should be set in outgoing frames + * and STAY_AWAKE is meaningful + */ +static bool brcms_c_ps_allowed(struct brcms_c_info *wlc) +{ + struct brcms_bss_cfg *cfg = wlc->bsscfg; + + /* disallow PS when one of the following global conditions meets */ + if (!wlc->pub->associated) + return false; + + /* disallow PS when one of these meets when not scanning */ + if (wlc->monitor) + return false; + + if (cfg->associated) { + /* + * disallow PS when one of the following + * bsscfg specific conditions meets + */ + if (!cfg->BSS) + return false; + + return false; + } + + return true; +} + +static void brcms_c_statsupd(struct brcms_c_info *wlc) +{ + int i; + struct macstat macstats; +#ifdef BCMDBG + u16 delta; + u16 rxf0ovfl; + u16 txfunfl[NFIFO]; +#endif /* BCMDBG */ + + /* if driver down, make no sense to update stats */ + if (!wlc->pub->up) + return; + +#ifdef BCMDBG + /* save last rx fifo 0 overflow count */ + rxf0ovfl = wlc->core->macstat_snapshot->rxf0ovfl; + + /* save last tx fifo underflow count */ + for (i = 0; i < NFIFO; i++) + txfunfl[i] = wlc->core->macstat_snapshot->txfunfl[i]; +#endif /* BCMDBG */ + + /* Read mac stats from contiguous shared memory */ + brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, &macstats, + sizeof(struct macstat), OBJADDR_SHM_SEL); + +#ifdef BCMDBG + /* check for rx fifo 0 overflow */ + delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl); + if (delta) + wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n", + wlc->pub->unit, delta); + + /* check for tx fifo underflows */ + for (i = 0; i < NFIFO; i++) { + delta = + (u16) (wlc->core->macstat_snapshot->txfunfl[i] - + txfunfl[i]); + if (delta) + wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!" + "\n", wlc->pub->unit, delta, i); + } +#endif /* BCMDBG */ + + /* merge counters from dma module */ + for (i = 0; i < NFIFO; i++) { + if (wlc->hw->di[i]) + dma_counterreset(wlc->hw->di[i]); + } +} + +static void brcms_b_reset(struct brcms_hardware *wlc_hw) +{ + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + /* reset the core */ + if (!brcms_deviceremoved(wlc_hw->wlc)) + brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); + + /* purge the dma rings */ + brcms_c_flushqueues(wlc_hw->wlc); +} + +void brcms_c_reset(struct brcms_c_info *wlc) +{ + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + + /* slurp up hw mac counters before core reset */ + brcms_c_statsupd(wlc); + + /* reset our snapshot of macstat counters */ + memset((char *)wlc->core->macstat_snapshot, 0, + sizeof(struct macstat)); + + brcms_b_reset(wlc->hw); +} + +/* Return the channel the driver should initialize during brcms_c_init. + * the channel may have to be changed from the currently configured channel + * if other configurations are in conflict (bandlocked, 11n mode disabled, + * invalid channel for current country, etc.) + */ +static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc) +{ + u16 chanspec = + 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE | + WL_CHANSPEC_BAND_2G; + + return chanspec; +} + +void brcms_c_init_scb(struct scb *scb) +{ + int i; + + memset(scb, 0, sizeof(struct scb)); + scb->flags = SCB_WMECAP | SCB_HTCAP; + for (i = 0; i < NUMPRIO; i++) { + scb->seqnum[i] = 0; + scb->seqctl[i] = 0xFFFF; + } + + scb->seqctl_nonqos = 0xFFFF; + scb->magic = SCB_MAGIC; +} + +/* d11 core init + * reset PSM + * download ucode/PCM + * let ucode run to suspended + * download ucode inits + * config other core registers + * init dma + */ +static void brcms_b_coreinit(struct brcms_c_info *wlc) +{ + struct brcms_hardware *wlc_hw = wlc->hw; + struct d11regs __iomem *regs; + u32 sflags; + uint bcnint_us; + uint i = 0; + bool fifosz_fixup = false; + int err = 0; + u16 buf[NFIFO]; + struct wiphy *wiphy = wlc->wiphy; + struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode; + + regs = wlc_hw->regs; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); + + /* reset PSM */ + brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE)); + + brcms_ucode_download(wlc_hw); + /* + * FIFOSZ fixup. driver wants to controls the fifo allocation. + */ + fifosz_fixup = true; + + /* let the PSM run to the suspended state, set mode to BSS STA */ + W_REG(®s->macintstatus, -1); + brcms_b_mctrl(wlc_hw, ~0, + (MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE)); + + /* wait for ucode to self-suspend after auto-init */ + SPINWAIT(((R_REG(®s->macintstatus) & MI_MACSSPNDD) == 0), + 1000 * 1000); + if ((R_REG(®s->macintstatus) & MI_MACSSPNDD) == 0) + wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-" + "suspend!\n", wlc_hw->unit); + + brcms_c_gpio_init(wlc); + + sflags = ai_core_sflags(wlc_hw->sih, 0, 0); + + if (D11REV_IS(wlc_hw->corerev, 23)) { + if (BRCMS_ISNPHY(wlc_hw->band)) + brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16); + else + wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" + " %d\n", __func__, wlc_hw->unit, + wlc_hw->corerev); + } else if (D11REV_IS(wlc_hw->corerev, 24)) { + if (BRCMS_ISLCNPHY(wlc_hw->band)) + brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24); + else + wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev" + " %d\n", __func__, wlc_hw->unit, + wlc_hw->corerev); + } else { + wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n", + __func__, wlc_hw->unit, wlc_hw->corerev); + } + + /* For old ucode, txfifo sizes needs to be modified(increased) */ + if (fifosz_fixup == true) + brcms_b_corerev_fifofixup(wlc_hw); + + /* check txfifo allocations match between ucode and driver */ + buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0); + if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) { + i = TX_AC_BE_FIFO; + err = -1; + } + buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1); + if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) { + i = TX_AC_VI_FIFO; + err = -1; + } + buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2); + buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff; + buf[TX_AC_BK_FIFO] &= 0xff; + if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) { + i = TX_AC_BK_FIFO; + err = -1; + } + if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) { + i = TX_AC_VO_FIFO; + err = -1; + } + buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3); + buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff; + buf[TX_BCMC_FIFO] &= 0xff; + if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) { + i = TX_BCMC_FIFO; + err = -1; + } + if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) { + i = TX_ATIM_FIFO; + err = -1; + } + if (err != 0) + wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d" + " driver size %d index %d\n", buf[i], + wlc_hw->xmtfifo_sz[i], i); + + /* make sure we can still talk to the mac */ + WARN_ON(R_REG(®s->maccontrol) == 0xffffffff); + + /* band-specific inits done by wlc_bsinit() */ + + /* Set up frame burst size and antenna swap threshold init values */ + brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST); + brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT); + + /* enable one rx interrupt per received frame */ + W_REG(®s->intrcvlazy[0], (1 << IRL_FC_SHIFT)); + + /* set the station mode (BSS STA) */ + brcms_b_mctrl(wlc_hw, + (MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP), + (MCTL_INFRA | MCTL_DISCARD_PMQ)); + + /* set up Beacon interval */ + bcnint_us = 0x8000 << 10; + W_REG(®s->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT)); + W_REG(®s->tsf_cfpstart, bcnint_us); + W_REG(®s->macintstatus, MI_GP1); + + /* write interrupt mask */ + W_REG(®s->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK); + + /* allow the MAC to control the PHY clock (dynamic on/off) */ + brcms_b_macphyclk_set(wlc_hw, ON); + + /* program dynamic clock control fast powerup delay register */ + wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih); + W_REG(®s->scc_fastpwrup_dly, wlc->fastpwrup_dly); + + /* tell the ucode the corerev */ + brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev); + + /* tell the ucode MAC capabilities */ + brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L, + (u16) (wlc_hw->machwcap & 0xffff)); + brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H, + (u16) ((wlc_hw-> + machwcap >> 16) & 0xffff)); + + /* write retry limits to SCR, this done after PSM init */ + W_REG(®s->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT); + (void)R_REG(®s->objaddr); + W_REG(®s->objdata, wlc_hw->SRL); + W_REG(®s->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT); + (void)R_REG(®s->objaddr); + W_REG(®s->objdata, wlc_hw->LRL); + + /* write rate fallback retry limits */ + brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL); + brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL); + + AND_REG(®s->ifs_ctl, 0x0FFF); + W_REG(®s->ifs_aifsn, EDCF_AIFSN_MIN); + + /* init the tx dma engines */ + for (i = 0; i < NFIFO; i++) { + if (wlc_hw->di[i]) + dma_txinit(wlc_hw->di[i]); + } + + /* init the rx dma engine(s) and post receive buffers */ + dma_rxinit(wlc_hw->di[RX_FIFO]); + dma_rxfill(wlc_hw->di[RX_FIFO]); +} + +void +static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec, + bool mute) { + u32 macintmask; + bool fastclk; + struct brcms_c_info *wlc = wlc_hw->wlc; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + /* request FAST clock if not on */ + fastclk = wlc_hw->forcefastclk; + if (!fastclk) + brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + + /* disable interrupts */ + macintmask = brcms_intrsoff(wlc->wl); + + /* set up the specified band and chanspec */ + brcms_c_setxband(wlc_hw, chspec_bandunit(chanspec)); + wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec); + + /* do one-time phy inits and calibration */ + wlc_phy_cal_init(wlc_hw->band->pi); + + /* core-specific initialization */ + brcms_b_coreinit(wlc); + + /* suspend the tx fifos and mute the phy for preism cac time */ + if (mute) + brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM); + + /* band-specific inits */ + brcms_b_bsinit(wlc, chanspec); + + /* restore macintmask */ + brcms_intrsrestore(wlc->wl, macintmask); + + /* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac + * is suspended and brcms_c_enable_mac() will clear this override bit. + */ + mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND); + + /* + * initialize mac_suspend_depth to 1 to match ucode + * initial suspended state + */ + wlc_hw->mac_suspend_depth = 1; + + /* restore the clk */ + if (!fastclk) + brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); +} + +static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc, + u16 chanspec) +{ + /* Save our copy of the chanspec */ + wlc->chanspec = chanspec; + + /* Set the chanspec and power limits for this locale */ + brcms_c_channel_set_chanspec(wlc->cmi, chanspec, BRCMS_TXPWR_MAX); + + if (wlc->stf->ss_algosel_auto) + brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel, + chanspec); + + brcms_c_stf_ss_update(wlc, wlc->band); +} + +static void +brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs) +{ + brcms_c_rateset_default(rs, NULL, wlc->band->phytype, + wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL, + (bool) (wlc->pub->_n_enab & SUPPORT_11N), + brcms_chspec_bw(wlc->default_bss->chanspec), + wlc->stf->txstreams); +} + +/* derive wlc->band->basic_rate[] table from 'rateset' */ +static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc, + struct brcms_c_rateset *rateset) +{ + u8 rate; + u8 mandatory; + u8 cck_basic = 0; + u8 ofdm_basic = 0; + u8 *br = wlc->band->basic_rate; + uint i; + + /* incoming rates are in 500kbps units as in 802.11 Supported Rates */ + memset(br, 0, BRCM_MAXRATE + 1); + + /* For each basic rate in the rates list, make an entry in the + * best basic lookup. + */ + for (i = 0; i < rateset->count; i++) { + /* only make an entry for a basic rate */ + if (!(rateset->rates[i] & BRCMS_RATE_FLAG)) + continue; + + /* mask off basic bit */ + rate = (rateset->rates[i] & BRCMS_RATE_MASK); + + if (rate > BRCM_MAXRATE) { + wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: " + "invalid rate 0x%X in rate set\n", + rateset->rates[i]); + continue; + } + + br[rate] = rate; + } + + /* The rate lookup table now has non-zero entries for each + * basic rate, equal to the basic rate: br[basicN] = basicN + * + * To look up the best basic rate corresponding to any + * particular rate, code can use the basic_rate table + * like this + * + * basic_rate = wlc->band->basic_rate[tx_rate] + * + * Make sure there is a best basic rate entry for + * every rate by walking up the table from low rates + * to high, filling in holes in the lookup table + */ + + for (i = 0; i < wlc->band->hw_rateset.count; i++) { + rate = wlc->band->hw_rateset.rates[i]; + + if (br[rate] != 0) { + /* This rate is a basic rate. + * Keep track of the best basic rate so far by + * modulation type. + */ + if (is_ofdm_rate(rate)) + ofdm_basic = rate; + else + cck_basic = rate; + + continue; + } + + /* This rate is not a basic rate so figure out the + * best basic rate less than this rate and fill in + * the hole in the table + */ + + br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic; + + if (br[rate] != 0) + continue; + + if (is_ofdm_rate(rate)) { + /* + * In 11g and 11a, the OFDM mandatory rates + * are 6, 12, and 24 Mbps + */ + if (rate >= BRCM_RATE_24M) + mandatory = BRCM_RATE_24M; + else if (rate >= BRCM_RATE_12M) + mandatory = BRCM_RATE_12M; + else + mandatory = BRCM_RATE_6M; + } else { + /* In 11b, all CCK rates are mandatory 1 - 11 Mbps */ + mandatory = rate; + } + + br[rate] = mandatory; + } +} + +static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc, + u16 chanspec) +{ + struct brcms_c_rateset default_rateset; + uint parkband; + uint i, band_order[2]; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + /* + * We might have been bandlocked during down and the chip + * power-cycled (hibernate). Figure out the right band to park on + */ + if (wlc->bandlocked || wlc->pub->_nbands == 1) { + /* updated in brcms_c_bandlock() */ + parkband = wlc->band->bandunit; + band_order[0] = band_order[1] = parkband; + } else { + /* park on the band of the specified chanspec */ + parkband = chspec_bandunit(chanspec); + + /* order so that parkband initialize last */ + band_order[0] = parkband ^ 1; + band_order[1] = parkband; + } + + /* make each band operational, software state init */ + for (i = 0; i < wlc->pub->_nbands; i++) { + uint j = band_order[i]; + + wlc->band = wlc->bandstate[j]; + + brcms_default_rateset(wlc, &default_rateset); + + /* fill in hw_rate */ + brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset, + false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK, + (bool) (wlc->pub->_n_enab & SUPPORT_11N)); + + /* init basic rate lookup */ + brcms_c_rate_lookup_init(wlc, &default_rateset); + } + + /* sync up phy/radio chanspec */ + brcms_c_set_phy_chanspec(wlc, chanspec); +} + +static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc) +{ + if (wlc->bcnmisc_monitor) + brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC); + else + brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0); +} + +void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc) +{ + wlc->bcnmisc_monitor = promisc; + brcms_c_mac_bcn_promisc(wlc); +} + +/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */ +static void brcms_c_mac_promisc(struct brcms_c_info *wlc) +{ + u32 promisc_bits = 0; + + /* + * promiscuous mode just sets MCTL_PROMISC + * Note: APs get all BSS traffic without the need to set + * the MCTL_PROMISC bit since all BSS data traffic is + * directed at the AP + */ + if (wlc->pub->promisc) + promisc_bits |= MCTL_PROMISC; + + /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL + * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is + * handled in brcms_c_mac_bcn_promisc() + */ + if (wlc->monitor) + promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL; + + brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits); +} + +/* + * ucode, hwmac update + * Channel dependent updates for ucode and hw + */ +static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc) +{ + /* enable or disable any active IBSSs depending on whether or not + * we are on the home channel + */ + if (wlc->home_chanspec == wlc_phy_chanspec_get(wlc->band->pi)) { + if (wlc->pub->associated) { + /* + * BMAC_NOTE: This is something that should be fixed + * in ucode inits. I think that the ucode inits set + * up the bcn templates and shm values with a bogus + * beacon. This should not be done in the inits. If + * ucode needs to set up a beacon for testing, the + * test routines should write it down, not expect the + * inits to populate a bogus beacon. + */ + if (BRCMS_PHY_11N_CAP(wlc->band)) + brcms_b_write_shm(wlc->hw, + M_BCN_TXTSF_OFFSET, 0); + } + } else { + /* disable an active IBSS if we are not on the home channel */ + } + + /* update the various promisc bits */ + brcms_c_mac_bcn_promisc(wlc); + brcms_c_mac_promisc(wlc); +} + +static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate, + u8 basic_rate) +{ + u8 phy_rate, index; + u8 basic_phy_rate, basic_index; + u16 dir_table, basic_table; + u16 basic_ptr; + + /* Shared memory address for the table we are reading */ + dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B; + + /* Shared memory address for the table we are writing */ + basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B; + + /* + * for a given rate, the LS-nibble of the PLCP SIGNAL field is + * the index into the rate table. + */ + phy_rate = rate_info[rate] & BRCMS_RATE_MASK; + basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK; + index = phy_rate & 0xf; + basic_index = basic_phy_rate & 0xf; + + /* Find the SHM pointer to the ACK rate entry by looking in the + * Direct-map Table + */ + basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2)); + + /* Update the SHM BSS-basic-rate-set mapping table with the pointer + * to the correct basic rate for the given incoming rate + */ + brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr); +} + +static const struct brcms_c_rateset * +brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc) +{ + const struct brcms_c_rateset *rs_dflt; + + if (BRCMS_PHY_11N_CAP(wlc->band)) { + if (wlc->band->bandtype == BRCM_BAND_5G) + rs_dflt = &ofdm_mimo_rates; + else + rs_dflt = &cck_ofdm_mimo_rates; + } else if (wlc->band->gmode) + rs_dflt = &cck_ofdm_rates; + else + rs_dflt = &cck_rates; + + return rs_dflt; +} + +static void brcms_c_set_ratetable(struct brcms_c_info *wlc) +{ + const struct brcms_c_rateset *rs_dflt; + struct brcms_c_rateset rs; + u8 rate, basic_rate; + uint i; + + rs_dflt = brcms_c_rateset_get_hwrs(wlc); + + brcms_c_rateset_copy(rs_dflt, &rs); + brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams); + + /* walk the phy rate table and update SHM basic rate lookup table */ + for (i = 0; i < rs.count; i++) { + rate = rs.rates[i] & BRCMS_RATE_MASK; + + /* for a given rate brcms_basic_rate returns the rate at + * which a response ACK/CTS should be sent. + */ + basic_rate = brcms_basic_rate(wlc, rate); + if (basic_rate == 0) + /* This should only happen if we are using a + * restricted rateset. + */ + basic_rate = rs.rates[0] & BRCMS_RATE_MASK; + + brcms_c_write_rate_shm(wlc, rate, basic_rate); + } +} + +/* band-specific init */ +static void brcms_c_bsinit(struct brcms_c_info *wlc) +{ + BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", + wlc->pub->unit, wlc->band->bandunit); + + /* write ucode ACK/CTS rate table */ + brcms_c_set_ratetable(wlc); + + /* update some band specific mac configuration */ + brcms_c_ucode_mac_upd(wlc); + + /* init antenna selection */ + brcms_c_antsel_init(wlc->asi); + +} + +/* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */ +static int +brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM, + bool writeToShm) +{ + int idle_busy_ratio_x_16 = 0; + uint offset = + isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM : + M_TX_IDLE_BUSY_RATIO_X_16_CCK; + if (duty_cycle > 100 || duty_cycle < 0) { + wiphy_err(wlc->wiphy, "wl%d: duty cycle value off limit\n", + wlc->pub->unit); + return -EINVAL; + } + if (duty_cycle) + idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle; + /* Only write to shared memory when wl is up */ + if (writeToShm) + brcms_b_write_shm(wlc->hw, offset, (u16) idle_busy_ratio_x_16); + + if (isOFDM) + wlc->tx_duty_cycle_ofdm = (u16) duty_cycle; + else + wlc->tx_duty_cycle_cck = (u16) duty_cycle; + + return 0; +} + +/* + * Initialize the base precedence map for dequeueing + * from txq based on WME settings + */ +static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc) +{ + wlc->tx_prec_map = BRCMS_PREC_BMP_ALL; + memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16)); + + wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK; + wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE; + wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI; + wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO; +} + +static void +brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc, + struct brcms_txq_info *qi, bool on, int prio) +{ + /* transmit flowcontrol is not yet implemented */ +} + +static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc) +{ + struct brcms_txq_info *qi; + + for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) { + if (qi->stopped) { + brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO); + qi->stopped = 0; + } + } +} + +/* push sw hps and wake state through hardware */ +static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc) +{ + u32 v1, v2; + bool hps; + bool awake_before; + + hps = brcms_c_ps_allowed(wlc); + + BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps); + + v1 = R_REG(&wlc->regs->maccontrol); + v2 = MCTL_WAKE; + if (hps) + v2 |= MCTL_HPS; + + brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2); + + awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0)); + + if (!awake_before) + brcms_b_wait_for_wake(wlc->hw); +} + +/* + * Write this BSS config's MAC address to core. + * Updates RXE match engine. + */ +static int brcms_c_set_mac(struct brcms_bss_cfg *bsscfg) +{ + int err = 0; + struct brcms_c_info *wlc = bsscfg->wlc; + + /* enter the MAC addr into the RXE match registers */ + brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, bsscfg->cur_etheraddr); + + brcms_c_ampdu_macaddr_upd(wlc); + + return err; +} + +/* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl). + * Updates RXE match engine. + */ +static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg) +{ + /* we need to update BSSID in RXE match registers */ + brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID); +} + +static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot) +{ + wlc_hw->shortslot = shortslot; + + if (wlc_hw->band->bandtype == BRCM_BAND_2G && wlc_hw->up) { + brcms_c_suspend_mac_and_wait(wlc_hw->wlc); + brcms_b_update_slot_timing(wlc_hw, shortslot); + brcms_c_enable_mac(wlc_hw->wlc); + } +} + +/* + * Suspend the the MAC and update the slot timing + * for standard 11b/g (20us slots) or shortslot 11g (9us slots). + */ +static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot) +{ + /* use the override if it is set */ + if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO) + shortslot = (wlc->shortslot_override == BRCMS_SHORTSLOT_ON); + + if (wlc->shortslot == shortslot) + return; + + wlc->shortslot = shortslot; + + brcms_b_set_shortslot(wlc->hw, shortslot); +} + +static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec) +{ + if (wlc->home_chanspec != chanspec) { + wlc->home_chanspec = chanspec; + + if (wlc->bsscfg->associated) + wlc->bsscfg->current_bss->chanspec = chanspec; + } +} + +void +brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec, + bool mute, struct txpwr_limits *txpwr) +{ + uint bandunit; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec); + + wlc_hw->chanspec = chanspec; + + /* Switch bands if necessary */ + if (wlc_hw->_nbands > 1) { + bandunit = chspec_bandunit(chanspec); + if (wlc_hw->band->bandunit != bandunit) { + /* brcms_b_setband disables other bandunit, + * use light band switch if not up yet + */ + if (wlc_hw->up) { + wlc_phy_chanspec_radio_set(wlc_hw-> + bandstate[bandunit]-> + pi, chanspec); + brcms_b_setband(wlc_hw, bandunit, chanspec); + } else { + brcms_c_setxband(wlc_hw, bandunit); + } + } + } + + wlc_phy_initcal_enable(wlc_hw->band->pi, !mute); + + if (!wlc_hw->up) { + if (wlc_hw->clk) + wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, + chanspec); + wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec); + } else { + wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec); + wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec); + + /* Update muting of the channel */ + brcms_b_mute(wlc_hw, mute, 0); + } +} + +/* switch to and initialize new band */ +static void brcms_c_setband(struct brcms_c_info *wlc, + uint bandunit) +{ + wlc->band = wlc->bandstate[bandunit]; + + if (!wlc->pub->up) + return; + + /* wait for at least one beacon before entering sleeping state */ + brcms_c_set_ps_ctrl(wlc); + + /* band-specific initializations */ + brcms_c_bsinit(wlc); +} + +static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec) +{ + uint bandunit; + bool switchband = false; + u16 old_chanspec = wlc->chanspec; + + if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) { + wiphy_err(wlc->wiphy, "wl%d: %s: Bad channel %d\n", + wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec)); + return; + } + + /* Switch bands if necessary */ + if (wlc->pub->_nbands > 1) { + bandunit = chspec_bandunit(chanspec); + if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) { + switchband = true; + if (wlc->bandlocked) { + wiphy_err(wlc->wiphy, "wl%d: %s: chspec %d " + "band is locked!\n", + wlc->pub->unit, __func__, + CHSPEC_CHANNEL(chanspec)); + return; + } + /* + * should the setband call come after the + * brcms_b_chanspec() ? if the setband updates + * (brcms_c_bsinit) use low level calls to inspect and + * set state, the state inspected may be from the wrong + * band, or the following brcms_b_set_chanspec() may + * undo the work. + */ + brcms_c_setband(wlc, bandunit); + } + } + + /* sync up phy/radio chanspec */ + brcms_c_set_phy_chanspec(wlc, chanspec); + + /* init antenna selection */ + if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) { + brcms_c_antsel_init(wlc->asi); + + /* Fix the hardware rateset based on bw. + * Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz + */ + brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset, + wlc->band->mimo_cap_40 ? brcms_chspec_bw(chanspec) : 0); + } + + /* update some mac configuration since chanspec changed */ + brcms_c_ucode_mac_upd(wlc); +} + +/* + * This function changes the phytxctl for beacon based on current + * beacon ratespec AND txant setting as per this table: + * ratespec CCK ant = wlc->stf->txant + * OFDM ant = 3 + */ +void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, + u32 bcn_rspec) +{ + u16 phyctl; + u16 phytxant = wlc->stf->phytxant; + u16 mask = PHY_TXC_ANT_MASK; + + /* for non-siso rates or default setting, use the available chains */ + if (BRCMS_PHY_11N_CAP(wlc->band)) + phytxant = brcms_c_stf_phytxchain_sel(wlc, bcn_rspec); + + phyctl = brcms_b_read_shm(wlc->hw, M_BCN_PCTLWD); + phyctl = (phyctl & ~mask) | phytxant; + brcms_b_write_shm(wlc->hw, M_BCN_PCTLWD, phyctl); +} + +/* + * centralized protection config change function to simplify debugging, no + * consistency checking this should be called only on changes to avoid overhead + * in periodic function + */ +void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val) +{ + BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val); + + switch (idx) { + case BRCMS_PROT_G_SPEC: + wlc->protection->_g = (bool) val; + break; + case BRCMS_PROT_G_OVR: + wlc->protection->g_override = (s8) val; + break; + case BRCMS_PROT_G_USER: + wlc->protection->gmode_user = (u8) val; + break; + case BRCMS_PROT_OVERLAP: + wlc->protection->overlap = (s8) val; + break; + case BRCMS_PROT_N_USER: + wlc->protection->nmode_user = (s8) val; + break; + case BRCMS_PROT_N_CFG: + wlc->protection->n_cfg = (s8) val; + break; + case BRCMS_PROT_N_CFG_OVR: + wlc->protection->n_cfg_override = (s8) val; + break; + case BRCMS_PROT_N_NONGF: + wlc->protection->nongf = (bool) val; + break; + case BRCMS_PROT_N_NONGF_OVR: + wlc->protection->nongf_override = (s8) val; + break; + case BRCMS_PROT_N_PAM_OVR: + wlc->protection->n_pam_override = (s8) val; + break; + case BRCMS_PROT_N_OBSS: + wlc->protection->n_obss = (bool) val; + break; + + default: + break; + } + +} + +static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val) +{ + if (wlc->pub->up) { + brcms_c_update_beacon(wlc); + brcms_c_update_probe_resp(wlc, true); + } +} + +static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val) +{ + wlc->stf->ldpc = val; + + if (wlc->pub->up) { + brcms_c_update_beacon(wlc); + brcms_c_update_probe_resp(wlc, true); + wlc_phy_ldpc_override_set(wlc->band->pi, (val ? true : false)); + } +} + +void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, + const struct ieee80211_tx_queue_params *params, + bool suspend) +{ + int i; + struct shm_acparams acp_shm; + u16 *shm_entry; + + /* Only apply params if the core is out of reset and has clocks */ + if (!wlc->clk) { + wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit, + __func__); + return; + } + + memset((char *)&acp_shm, 0, sizeof(struct shm_acparams)); + /* fill in shm ac params struct */ + acp_shm.txop = params->txop; + /* convert from units of 32us to us for ucode */ + wlc->edcf_txop[aci & 0x3] = acp_shm.txop = + EDCF_TXOP2USEC(acp_shm.txop); + acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK); + + if (aci == AC_VI && acp_shm.txop == 0 + && acp_shm.aifs < EDCF_AIFSN_MAX) + acp_shm.aifs++; + + if (acp_shm.aifs < EDCF_AIFSN_MIN + || acp_shm.aifs > EDCF_AIFSN_MAX) { + wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad " + "aifs %d\n", wlc->pub->unit, acp_shm.aifs); + } else { + acp_shm.cwmin = params->cw_min; + acp_shm.cwmax = params->cw_max; + acp_shm.cwcur = acp_shm.cwmin; + acp_shm.bslots = + R_REG(&wlc->regs->tsf_random) & acp_shm.cwcur; + acp_shm.reggap = acp_shm.bslots + acp_shm.aifs; + /* Indicate the new params to the ucode */ + acp_shm.status = brcms_b_read_shm(wlc->hw, (M_EDCF_QINFO + + wme_ac2fifo[aci] * + M_EDCF_QLEN + + M_EDCF_STATUS_OFF)); + acp_shm.status |= WME_STATUS_NEWAC; + + /* Fill in shm acparam table */ + shm_entry = (u16 *) &acp_shm; + for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2) + brcms_b_write_shm(wlc->hw, + M_EDCF_QINFO + + wme_ac2fifo[aci] * M_EDCF_QLEN + i, + *shm_entry++); + } + + if (suspend) { + brcms_c_suspend_mac_and_wait(wlc); + brcms_c_enable_mac(wlc); + } +} + +void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend) +{ + u16 aci; + int i_ac; + struct ieee80211_tx_queue_params txq_pars; + static const struct edcf_acparam default_edcf_acparams[] = { + {EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA, EDCF_AC_BE_TXOP_STA}, + {EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA, EDCF_AC_BK_TXOP_STA}, + {EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA, EDCF_AC_VI_TXOP_STA}, + {EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA, EDCF_AC_VO_TXOP_STA} + }; /* ucode needs these parameters during its initialization */ + const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0]; + + for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) { + /* find out which ac this set of params applies to */ + aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT; + + /* fill in shm ac params struct */ + txq_pars.txop = edcf_acp->TXOP; + txq_pars.aifs = edcf_acp->ACI; + + /* CWmin = 2^(ECWmin) - 1 */ + txq_pars.cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK); + /* CWmax = 2^(ECWmax) - 1 */ + txq_pars.cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK) + >> EDCF_ECWMAX_SHIFT); + brcms_c_wme_setparams(wlc, aci, &txq_pars, suspend); + } + + if (suspend) { + brcms_c_suspend_mac_and_wait(wlc); + brcms_c_enable_mac(wlc); + } +} + +/* maintain LED behavior in down state */ +static void brcms_c_down_led_upd(struct brcms_c_info *wlc) +{ + /* + * maintain LEDs while in down state, turn on sbclk if + * not available yet. Turn on sbclk if necessary + */ + brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_FLIP); + brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_FLIP); +} + +static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc) +{ + /* Don't start the timer if HWRADIO feature is disabled */ + if (wlc->radio_monitor) + return; + + wlc->radio_monitor = true; + brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_RADIO_MON); + brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true); +} + +static void brcms_c_radio_disable(struct brcms_c_info *wlc) +{ + if (!wlc->pub->up) { + brcms_c_down_led_upd(wlc); + return; + } + + brcms_c_radio_monitor_start(wlc); + brcms_down(wlc->wl); +} + +static void brcms_c_radio_enable(struct brcms_c_info *wlc) +{ + if (wlc->pub->up) + return; + + if (brcms_deviceremoved(wlc)) + return; + + brcms_up(wlc->wl); +} + +static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc) +{ + if (!wlc->radio_monitor) + return true; + + wlc->radio_monitor = false; + brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_RADIO_MON); + return brcms_del_timer(wlc->radio_timer); +} + +/* read hwdisable state and propagate to wlc flag */ +static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc) +{ + if (wlc->pub->hw_off) + return; + + if (brcms_b_radio_read_hwdisabled(wlc->hw)) + mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE); + else + mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE); +} + +/* + * centralized radio disable/enable function, + * invoke radio enable/disable after updating hwradio status + */ +static void brcms_c_radio_upd(struct brcms_c_info *wlc) +{ + if (wlc->pub->radio_disabled) + brcms_c_radio_disable(wlc); + else + brcms_c_radio_enable(wlc); +} + +/* update hwradio status and return it */ +bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc) +{ + brcms_c_radio_hwdisable_upd(wlc); + + return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ? + true : false; +} + +/* periodical query hw radio button while driver is "down" */ +static void brcms_c_radio_timer(void *arg) +{ + struct brcms_c_info *wlc = (struct brcms_c_info *) arg; + + if (brcms_deviceremoved(wlc)) { + wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, + __func__); + brcms_down(wlc->wl); + return; + } + + /* cap mpc off count */ + if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT) + wlc->mpc_offcnt++; + + brcms_c_radio_hwdisable_upd(wlc); + brcms_c_radio_upd(wlc); +} + +/* common low-level watchdog code */ +static void brcms_b_watchdog(void *arg) +{ + struct brcms_c_info *wlc = (struct brcms_c_info *) arg; + struct brcms_hardware *wlc_hw = wlc->hw; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); + + if (!wlc_hw->up) + return; + + /* increment second count */ + wlc_hw->now++; + + /* Check for FIFO error interrupts */ + brcms_b_fifoerrors(wlc_hw); + + /* make sure RX dma has buffers */ + dma_rxfill(wlc->hw->di[RX_FIFO]); + + wlc_phy_watchdog(wlc_hw->band->pi); +} + +static void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc) +{ + bool mpc_radio, radio_state; + + /* + * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled + * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio + * monitor also when WL_RADIO_MPC_DISABLE is the only reason that + * the radio is going down. + */ + if (!wlc->mpc) { + if (!wlc->pub->radio_disabled) + return; + mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE); + brcms_c_radio_upd(wlc); + if (!wlc->pub->radio_disabled) + brcms_c_radio_monitor_stop(wlc); + return; + } + + /* + * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in + * wlc->pub->radio_disabled to go ON, always call radio_upd + * synchronously to go OFF, postpone radio_upd to later when + * context is safe(e.g. watchdog) + */ + radio_state = + (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF : + ON); + mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON; + + if (radio_state == ON && mpc_radio == OFF) + wlc->mpc_delay_off = wlc->mpc_dlycnt; + else if (radio_state == OFF && mpc_radio == ON) { + mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE); + brcms_c_radio_upd(wlc); + if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD) + wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT; + else + wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; + } + /* + * Below logic is meant to capture the transition from mpc off + * to mpc on for reasons other than wlc->mpc_delay_off keeping + * the mpc off. In that case reset wlc->mpc_delay_off to + * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off + */ + if ((wlc->prev_non_delay_mpc == false) && + (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off) + wlc->mpc_delay_off = wlc->mpc_dlycnt; + + wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc); +} + +/* common watchdog code */ +static void brcms_c_watchdog(void *arg) +{ + struct brcms_c_info *wlc = (struct brcms_c_info *) arg; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + + if (!wlc->pub->up) + return; + + if (brcms_deviceremoved(wlc)) { + wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit, + __func__); + brcms_down(wlc->wl); + return; + } + + /* increment second count */ + wlc->pub->now++; + + /* delay radio disable */ + if (wlc->mpc_delay_off) { + if (--wlc->mpc_delay_off == 0) { + mboolset(wlc->pub->radio_disabled, + WL_RADIO_MPC_DISABLE); + if (wlc->mpc && brcms_c_ismpc(wlc)) + wlc->mpc_offcnt = 0; + } + } + + /* mpc sync */ + brcms_c_radio_mpc_upd(wlc); + /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */ + brcms_c_radio_hwdisable_upd(wlc); + brcms_c_radio_upd(wlc); + /* if radio is disable, driver may be down, quit here */ + if (wlc->pub->radio_disabled) + return; + + brcms_b_watchdog(wlc); + + /* + * occasionally sample mac stat counters to + * detect 16-bit counter wrap + */ + if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0) + brcms_c_statsupd(wlc); + + if (BRCMS_ISNPHY(wlc->band) && + ((wlc->pub->now - wlc->tempsense_lasttime) >= + BRCMS_TEMPSENSE_PERIOD)) { + wlc->tempsense_lasttime = wlc->pub->now; + brcms_c_tempsense_upd(wlc); + } +} + +static void brcms_c_watchdog_by_timer(void *arg) +{ + brcms_c_watchdog(arg); +} + +static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit) +{ + wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer, + wlc, "watchdog"); + if (!wlc->wdtimer) { + wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for wdtimer " + "failed\n", unit); + goto fail; + } + + wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer, + wlc, "radio"); + if (!wlc->radio_timer) { + wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for radio_timer " + "failed\n", unit); + goto fail; + } + + return true; + + fail: + return false; +} + +/* + * Initialize brcms_c_info default values ... + * may get overrides later in this function + */ +static void brcms_c_info_init(struct brcms_c_info *wlc, int unit) +{ + int i; + + /* Save our copy of the chanspec */ + wlc->chanspec = ch20mhz_chspec(1); + + /* various 802.11g modes */ + wlc->shortslot = false; + wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO; + + brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO); + brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false); + + brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR, + BRCMS_PROTECTION_AUTO); + brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF); + brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR, + BRCMS_PROTECTION_AUTO); + brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false); + brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO); + + brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP, + BRCMS_PROTECTION_CTL_OVERLAP); + + /* 802.11g draft 4.0 NonERP elt advertisement */ + wlc->include_legacy_erp = true; + + wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF; + wlc->stf->txant = ANT_TX_DEF; + + wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT; + + wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN; + for (i = 0; i < NFIFO; i++) + wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN; + wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN; + + /* default rate fallback retry limits */ + wlc->SFBL = RETRY_SHORT_FB; + wlc->LFBL = RETRY_LONG_FB; + + /* default mac retry limits */ + wlc->SRL = RETRY_SHORT_DEF; + wlc->LRL = RETRY_LONG_DEF; + + /* WME QoS mode is Auto by default */ + wlc->pub->_ampdu = AMPDU_AGG_HOST; + wlc->pub->bcmerror = 0; + + /* initialize mpc delay */ + wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; +} + +static uint brcms_c_attach_module(struct brcms_c_info *wlc) +{ + uint err = 0; + uint unit; + unit = wlc->pub->unit; + + wlc->asi = brcms_c_antsel_attach(wlc); + if (wlc->asi == NULL) { + wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach " + "failed\n", unit); + err = 44; + goto fail; + } + + wlc->ampdu = brcms_c_ampdu_attach(wlc); + if (wlc->ampdu == NULL) { + wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach " + "failed\n", unit); + err = 50; + goto fail; + } + + if ((brcms_c_stf_attach(wlc) != 0)) { + wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach " + "failed\n", unit); + err = 68; + goto fail; + } + fail: + return err; +} + +struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc) +{ + return wlc->pub; +} + +/* low level attach + * run backplane attach, init nvram + * run phy attach + * initialize software state for each core and band + * put the whole chip in reset(driver down state), no clock + */ +static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, + uint unit, bool piomode, void __iomem *regsva, + struct pci_dev *btparam) +{ + struct brcms_hardware *wlc_hw; + struct d11regs __iomem *regs; + char *macaddr = NULL; + uint err = 0; + uint j; + bool wme = false; + struct shared_phy_params sha_params; + struct wiphy *wiphy = wlc->wiphy; + + BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor, + device); + + wme = true; + + wlc_hw = wlc->hw; + wlc_hw->wlc = wlc; + wlc_hw->unit = unit; + wlc_hw->band = wlc_hw->bandstate[0]; + wlc_hw->_piomode = piomode; + + /* populate struct brcms_hardware with default values */ + brcms_b_info_init(wlc_hw); + + /* + * Do the hardware portion of the attach. Also initialize software + * state that depends on the particular hardware we are running. + */ + wlc_hw->sih = ai_attach(regsva, btparam); + if (wlc_hw->sih == NULL) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n", + unit); + err = 11; + goto fail; + } + + /* verify again the device is supported */ + if (!brcms_c_chipmatch(vendor, device)) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported " + "vendor/device (0x%x/0x%x)\n", + unit, vendor, device); + err = 12; + goto fail; + } + + wlc_hw->vendorid = vendor; + wlc_hw->deviceid = device; + + /* set bar0 window to point at D11 core */ + wlc_hw->regs = (struct d11regs __iomem *) + ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); + wlc_hw->corerev = ai_corerev(wlc_hw->sih); + + regs = wlc_hw->regs; + + wlc->regs = wlc_hw->regs; + + /* validate chip, chiprev and corerev */ + if (!brcms_c_isgoodchip(wlc_hw)) { + err = 13; + goto fail; + } + + /* initialize power control registers */ + ai_clkctl_init(wlc_hw->sih); + + /* request fastclock and force fastclock for the rest of attach + * bring the d11 core out of reset. + * For PMU chips, the first wlc_clkctl_clk is no-op since core-clk + * is still false; But it will be called again inside wlc_corereset, + * after d11 is out of reset. + */ + brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); + + if (!brcms_b_validate_chip_access(wlc_hw)) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access " + "failed\n", unit); + err = 14; + goto fail; + } + + /* get the board rev, used just below */ + j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV); + /* promote srom boardrev of 0xFF to 1 */ + if (j == BOARDREV_PROMOTABLE) + j = BOARDREV_PROMOTED; + wlc_hw->boardrev = (u16) j; + if (!brcms_c_validboardtype(wlc_hw)) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom " + "board type (0x%x)" " or revision level (0x%x)\n", + unit, wlc_hw->sih->boardtype, wlc_hw->boardrev); + err = 15; + goto fail; + } + wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV); + wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih, + BRCMS_SROM_BOARDFLAGS); + wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih, + BRCMS_SROM_BOARDFLAGS2); + + if (wlc_hw->boardflags & BFL_NOPLLDOWN) + brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED); + + /* check device id(srom, nvram etc.) to set bands */ + if (wlc_hw->deviceid == BCM43224_D11N_ID || + wlc_hw->deviceid == BCM43224_D11N_ID_VEN1) + /* Dualband boards */ + wlc_hw->_nbands = 2; + else + wlc_hw->_nbands = 1; + + if ((wlc_hw->sih->chip == BCM43225_CHIP_ID)) + wlc_hw->_nbands = 1; + + /* BMAC_NOTE: remove init of pub values when brcms_c_attach() + * unconditionally does the init of these values + */ + wlc->vendorid = wlc_hw->vendorid; + wlc->deviceid = wlc_hw->deviceid; + wlc->pub->sih = wlc_hw->sih; + wlc->pub->corerev = wlc_hw->corerev; + wlc->pub->sromrev = wlc_hw->sromrev; + wlc->pub->boardrev = wlc_hw->boardrev; + wlc->pub->boardflags = wlc_hw->boardflags; + wlc->pub->boardflags2 = wlc_hw->boardflags2; + wlc->pub->_nbands = wlc_hw->_nbands; + + wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc); + + if (wlc_hw->physhim == NULL) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach " + "failed\n", unit); + err = 25; + goto fail; + } + + /* pass all the parameters to wlc_phy_shared_attach in one struct */ + sha_params.sih = wlc_hw->sih; + sha_params.physhim = wlc_hw->physhim; + sha_params.unit = unit; + sha_params.corerev = wlc_hw->corerev; + sha_params.vid = wlc_hw->vendorid; + sha_params.did = wlc_hw->deviceid; + sha_params.chip = wlc_hw->sih->chip; + sha_params.chiprev = wlc_hw->sih->chiprev; + sha_params.chippkg = wlc_hw->sih->chippkg; + sha_params.sromrev = wlc_hw->sromrev; + sha_params.boardtype = wlc_hw->sih->boardtype; + sha_params.boardrev = wlc_hw->boardrev; + sha_params.boardvendor = wlc_hw->sih->boardvendor; + sha_params.boardflags = wlc_hw->boardflags; + sha_params.boardflags2 = wlc_hw->boardflags2; + sha_params.buscorerev = wlc_hw->sih->buscorerev; + + /* alloc and save pointer to shared phy state area */ + wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params); + if (!wlc_hw->phy_sh) { + err = 16; + goto fail; + } + + /* initialize software state for each core and band */ + for (j = 0; j < wlc_hw->_nbands; j++) { + /* + * band0 is always 2.4Ghz + * band1, if present, is 5Ghz + */ + + brcms_c_setxband(wlc_hw, j); + + wlc_hw->band->bandunit = j; + wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G; + wlc->band->bandunit = j; + wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G; + wlc->core->coreidx = ai_coreidx(wlc_hw->sih); + + wlc_hw->machwcap = R_REG(®s->machwcap); + wlc_hw->machwcap_backup = wlc_hw->machwcap; + + /* init tx fifo size */ + wlc_hw->xmtfifo_sz = + xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)]; + + /* Get a phy for this band */ + wlc_hw->band->pi = + wlc_phy_attach(wlc_hw->phy_sh, regs, + wlc_hw->band->bandtype, + wlc->wiphy); + if (wlc_hw->band->pi == NULL) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_" + "attach failed\n", unit); + err = 17; + goto fail; + } + + wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap); + + wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype, + &wlc_hw->band->phyrev, + &wlc_hw->band->radioid, + &wlc_hw->band->radiorev); + wlc_hw->band->abgphy_encore = + wlc_phy_get_encore(wlc_hw->band->pi); + wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi); + wlc_hw->band->core_flags = + wlc_phy_get_coreflags(wlc_hw->band->pi); + + /* verify good phy_type & supported phy revision */ + if (BRCMS_ISNPHY(wlc_hw->band)) { + if (NCONF_HAS(wlc_hw->band->phyrev)) + goto good_phy; + else + goto bad_phy; + } else if (BRCMS_ISLCNPHY(wlc_hw->band)) { + if (LCNCONF_HAS(wlc_hw->band->phyrev)) + goto good_phy; + else + goto bad_phy; + } else { + bad_phy: + wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported " + "phy type/rev (%d/%d)\n", unit, + wlc_hw->band->phytype, wlc_hw->band->phyrev); + err = 18; + goto fail; + } + + good_phy: + /* + * BMAC_NOTE: wlc->band->pi should not be set below and should + * be done in the high level attach. However we can not make + * that change until all low level access is changed to + * wlc_hw->band->pi. Instead do the wlc->band->pi init below, + * keeping wlc_hw->band->pi as well for incremental update of + * low level fns, and cut over low only init when all fns + * updated. + */ + wlc->band->pi = wlc_hw->band->pi; + wlc->band->phytype = wlc_hw->band->phytype; + wlc->band->phyrev = wlc_hw->band->phyrev; + wlc->band->radioid = wlc_hw->band->radioid; + wlc->band->radiorev = wlc_hw->band->radiorev; + + /* default contention windows size limits */ + wlc_hw->band->CWmin = APHY_CWMIN; + wlc_hw->band->CWmax = PHY_CWMAX; + + if (!brcms_b_attach_dmapio(wlc, j, wme)) { + err = 19; + goto fail; + } + } + + /* disable core to match driver "down" state */ + brcms_c_coredisable(wlc_hw); + + /* Match driver "down" state */ + ai_pci_down(wlc_hw->sih); + + /* register sb interrupt callback functions */ + ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff, + (void *)brcms_c_wlintrsrestore, NULL, wlc); + + /* turn off pll and xtal to match driver "down" state */ + brcms_b_xtal(wlc_hw, OFF); + + /* ******************************************************************* + * The hardware is in the DOWN state at this point. D11 core + * or cores are in reset with clocks off, and the board PLLs + * are off if possible. + * + * Beyond this point, wlc->sbclk == false and chip registers + * should not be touched. + ********************************************************************* + */ + + /* init etheraddr state variables */ + macaddr = brcms_c_get_macaddr(wlc_hw); + if (macaddr == NULL) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n", + unit); + err = 21; + goto fail; + } + if (!mac_pton(macaddr, wlc_hw->etheraddr) || + is_broadcast_ether_addr(wlc_hw->etheraddr) || + is_zero_ether_addr(wlc_hw->etheraddr)) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n", + unit, macaddr); + err = 22; + goto fail; + } + + BCMMSG(wlc->wiphy, + "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n", + wlc_hw->deviceid, wlc_hw->_nbands, + wlc_hw->sih->boardtype, macaddr); + + return err; + + fail: + wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit, + err); + return err; +} + +static void brcms_c_attach_antgain_init(struct brcms_c_info *wlc) +{ + uint unit; + unit = wlc->pub->unit; + + if ((wlc->band->antgain == -1) && (wlc->pub->sromrev == 1)) { + /* default antenna gain for srom rev 1 is 2 dBm (8 qdbm) */ + wlc->band->antgain = 8; + } else if (wlc->band->antgain == -1) { + wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in" + " srom, using 2dB\n", unit, __func__); + wlc->band->antgain = 8; + } else { + s8 gain, fract; + /* Older sroms specified gain in whole dbm only. In order + * be able to specify qdbm granularity and remain backward + * compatible the whole dbms are now encoded in only + * low 6 bits and remaining qdbms are encoded in the hi 2 bits. + * 6 bit signed number ranges from -32 - 31. + * + * Examples: + * 0x1 = 1 db, + * 0xc1 = 1.75 db (1 + 3 quarters), + * 0x3f = -1 (-1 + 0 quarters), + * 0x7f = -.75 (-1 + 1 quarters) = -3 qdbm. + * 0xbf = -.50 (-1 + 2 quarters) = -2 qdbm. + */ + gain = wlc->band->antgain & 0x3f; + gain <<= 2; /* Sign extend */ + gain >>= 2; + fract = (wlc->band->antgain & 0xc0) >> 6; + wlc->band->antgain = 4 * gain + fract; + } +} + +static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc) +{ + int aa; + uint unit; + int bandtype; + struct si_pub *sih = wlc->hw->sih; + + unit = wlc->pub->unit; + bandtype = wlc->band->bandtype; + + /* get antennas available */ + if (bandtype == BRCM_BAND_5G) + aa = (s8) getintvar(sih, BRCMS_SROM_AA5G); + else + aa = (s8) getintvar(sih, BRCMS_SROM_AA2G); + + if ((aa < 1) || (aa > 15)) { + wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in" + " srom (0x%x), using 3\n", unit, __func__, aa); + aa = 3; + } + + /* reset the defaults if we have a single antenna */ + if (aa == 1) { + wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0; + wlc->stf->txant = ANT_TX_FORCE_0; + } else if (aa == 2) { + wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1; + wlc->stf->txant = ANT_TX_FORCE_1; + } else { + } + + /* Compute Antenna Gain */ + if (bandtype == BRCM_BAND_5G) + wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1); + else + wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0); + + brcms_c_attach_antgain_init(wlc); + + return true; +} + +static void brcms_c_bss_default_init(struct brcms_c_info *wlc) +{ + u16 chanspec; + struct brcms_band *band; + struct brcms_bss_info *bi = wlc->default_bss; + + /* init default and target BSS with some sane initial values */ + memset((char *)(bi), 0, sizeof(struct brcms_bss_info)); + bi->beacon_period = BEACON_INTERVAL_DEFAULT; + + /* fill the default channel as the first valid channel + * starting from the 2G channels + */ + chanspec = ch20mhz_chspec(1); + wlc->home_chanspec = bi->chanspec = chanspec; + + /* find the band of our default channel */ + band = wlc->band; + if (wlc->pub->_nbands > 1 && + band->bandunit != chspec_bandunit(chanspec)) + band = wlc->bandstate[OTHERBANDUNIT(wlc)]; + + /* init bss rates to the band specific default rate set */ + brcms_c_rateset_default(&bi->rateset, NULL, band->phytype, + band->bandtype, false, BRCMS_RATE_MASK_FULL, + (bool) (wlc->pub->_n_enab & SUPPORT_11N), + brcms_chspec_bw(chanspec), wlc->stf->txstreams); + + if (wlc->pub->_n_enab & SUPPORT_11N) + bi->flags |= BRCMS_BSS_HT; +} + +static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc) +{ + struct brcms_txq_info *qi, *p; + + qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC); + if (qi != NULL) { + /* + * Have enough room for control packets along with HI watermark + * Also, add room to txq for total psq packets if all the SCBs + * leave PS mode. The watermark for flowcontrol to OS packets + * will remain the same + */ + brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT, + 2 * BRCMS_DATAHIWAT + PKTQ_LEN_DEFAULT); + + /* add this queue to the the global list */ + p = wlc->tx_queues; + if (p == NULL) { + wlc->tx_queues = qi; + } else { + while (p->next != NULL) + p = p->next; + p->next = qi; + } + } + return qi; +} + +static void brcms_c_txq_free(struct brcms_c_info *wlc, + struct brcms_txq_info *qi) +{ + struct brcms_txq_info *p; + + if (qi == NULL) + return; + + /* remove the queue from the linked list */ + p = wlc->tx_queues; + if (p == qi) + wlc->tx_queues = p->next; + else { + while (p != NULL && p->next != qi) + p = p->next; + if (p != NULL) + p->next = p->next->next; + } + + kfree(qi); +} + +static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap) +{ + uint i; + struct brcms_band *band; + + for (i = 0; i < wlc->pub->_nbands; i++) { + band = wlc->bandstate[i]; + if (band->bandtype == BRCM_BAND_5G) { + if ((bwcap == BRCMS_N_BW_40ALL) + || (bwcap == BRCMS_N_BW_20IN2G_40IN5G)) + band->mimo_cap_40 = true; + else + band->mimo_cap_40 = false; + } else { + if (bwcap == BRCMS_N_BW_40ALL) + band->mimo_cap_40 = true; + else + band->mimo_cap_40 = false; + } + } +} + +static void brcms_c_timers_deinit(struct brcms_c_info *wlc) +{ + /* free timer state */ + if (wlc->wdtimer) { + brcms_free_timer(wlc->wdtimer); + wlc->wdtimer = NULL; + } + if (wlc->radio_timer) { + brcms_free_timer(wlc->radio_timer); + wlc->radio_timer = NULL; + } +} + +static void brcms_c_detach_module(struct brcms_c_info *wlc) +{ + if (wlc->asi) { + brcms_c_antsel_detach(wlc->asi); + wlc->asi = NULL; + } + + if (wlc->ampdu) { + brcms_c_ampdu_detach(wlc->ampdu); + wlc->ampdu = NULL; + } + + brcms_c_stf_detach(wlc); +} + +/* + * low level detach + */ +static int brcms_b_detach(struct brcms_c_info *wlc) +{ + uint i; + struct brcms_hw_band *band; + struct brcms_hardware *wlc_hw = wlc->hw; + int callbacks; + + callbacks = 0; + + if (wlc_hw->sih) { + /* + * detach interrupt sync mechanism since interrupt is disabled + * and per-port interrupt object may has been freed. this must + * be done before sb core switch + */ + ai_deregister_intr_callback(wlc_hw->sih); + ai_pci_sleep(wlc_hw->sih); + } + + brcms_b_detach_dmapio(wlc_hw); + + band = wlc_hw->band; + for (i = 0; i < wlc_hw->_nbands; i++) { + if (band->pi) { + /* Detach this band's phy */ + wlc_phy_detach(band->pi); + band->pi = NULL; + } + band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)]; + } + + /* Free shared phy state */ + kfree(wlc_hw->phy_sh); + + wlc_phy_shim_detach(wlc_hw->physhim); + + if (wlc_hw->sih) { + ai_detach(wlc_hw->sih); + wlc_hw->sih = NULL; + } + + return callbacks; + +} + +/* + * Return a count of the number of driver callbacks still pending. + * + * General policy is that brcms_c_detach can only dealloc/free software states. + * It can NOT touch hardware registers since the d11core may be in reset and + * clock may not be available. + * One exception is sb register access, which is possible if crystal is turned + * on after "down" state, driver should avoid software timer with the exception + * of radio_monitor. + */ +uint brcms_c_detach(struct brcms_c_info *wlc) +{ + uint callbacks = 0; + + if (wlc == NULL) + return 0; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + + callbacks += brcms_b_detach(wlc); + + /* delete software timers */ + if (!brcms_c_radio_monitor_stop(wlc)) + callbacks++; + + brcms_c_channel_mgr_detach(wlc->cmi); + + brcms_c_timers_deinit(wlc); + + brcms_c_detach_module(wlc); + + + while (wlc->tx_queues != NULL) + brcms_c_txq_free(wlc, wlc->tx_queues); + + brcms_c_detach_mfree(wlc); + return callbacks; +} + +/* update state that depends on the current value of "ap" */ +static void brcms_c_ap_upd(struct brcms_c_info *wlc) +{ + /* STA-BSS; short capable */ + wlc->PLCPHdr_override = BRCMS_PLCP_SHORT; + + /* fixup mpc */ + wlc->mpc = true; +} + +/* Initialize just the hardware when coming out of POR or S3/S5 system states */ +static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) +{ + if (wlc_hw->wlc->pub->hw_up) + return; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + /* + * Enable pll and xtal, initialize the power control registers, + * and force fastclock for the remainder of brcms_c_up(). + */ + brcms_b_xtal(wlc_hw, ON); + ai_clkctl_init(wlc_hw->sih); + brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + + ai_pci_fixcfg(wlc_hw->sih); + + /* + * AI chip doesn't restore bar0win2 on + * hibernation/resume, need sw fixup + */ + if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) || + (wlc_hw->sih->chip == BCM43225_CHIP_ID)) + wlc_hw->regs = (struct d11regs __iomem *) + ai_setcore(wlc_hw->sih, D11_CORE_ID, 0); + + /* + * Inform phy that a POR reset has occurred so + * it does a complete phy init + */ + wlc_phy_por_inform(wlc_hw->band->pi); + + wlc_hw->ucode_loaded = false; + wlc_hw->wlc->pub->hw_up = true; + + if ((wlc_hw->boardflags & BFL_FEM) + && (wlc_hw->sih->chip == BCM4313_CHIP_ID)) { + if (! + (wlc_hw->boardrev >= 0x1250 + && (wlc_hw->boardflags & BFL_FEM_BT))) + ai_epa_4313war(wlc_hw->sih); + } +} + +static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) +{ + uint coremask; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + /* + * Enable pll and xtal, initialize the power control registers, + * and force fastclock for the remainder of brcms_c_up(). + */ + brcms_b_xtal(wlc_hw, ON); + ai_clkctl_init(wlc_hw->sih); + brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + + /* + * Configure pci/pcmcia here instead of in brcms_c_attach() + * to allow mfg hotswap: down, hotswap (chip power cycle), up. + */ + coremask = (1 << wlc_hw->wlc->core->coreidx); + + ai_pci_setup(wlc_hw->sih, coremask); + + /* + * Need to read the hwradio status here to cover the case where the + * system is loaded with the hw radio disabled. We do not want to + * bring the driver up in this case. + */ + if (brcms_b_radio_read_hwdisabled(wlc_hw)) { + /* put SB PCI in down state again */ + ai_pci_down(wlc_hw->sih); + brcms_b_xtal(wlc_hw, OFF); + return -ENOMEDIUM; + } + + ai_pci_up(wlc_hw->sih); + + /* reset the d11 core */ + brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); + + return 0; +} + +static int brcms_b_up_finish(struct brcms_hardware *wlc_hw) +{ + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + wlc_hw->up = true; + wlc_phy_hw_state_upd(wlc_hw->band->pi, true); + + /* FULLY enable dynamic power control and d11 core interrupt */ + brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); + brcms_intrson(wlc_hw->wlc->wl); + return 0; +} + +/* + * Write WME tunable parameters for retransmit/max rate + * from wlc struct to ucode + */ +static void brcms_c_wme_retries_write(struct brcms_c_info *wlc) +{ + int ac; + + /* Need clock to do this */ + if (!wlc->clk) + return; + + for (ac = 0; ac < AC_COUNT; ac++) + brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac), + wlc->wme_retries[ac]); +} + +/* make interface operational */ +int brcms_c_up(struct brcms_c_info *wlc) +{ + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + + /* HW is turned off so don't try to access it */ + if (wlc->pub->hw_off || brcms_deviceremoved(wlc)) + return -ENOMEDIUM; + + if (!wlc->pub->hw_up) { + brcms_b_hw_up(wlc->hw); + wlc->pub->hw_up = true; + } + + if ((wlc->pub->boardflags & BFL_FEM) + && (wlc->pub->sih->chip == BCM4313_CHIP_ID)) { + if (wlc->pub->boardrev >= 0x1250 + && (wlc->pub->boardflags & BFL_FEM_BT)) + brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL, + MHF5_4313_GPIOCTRL, BRCM_BAND_ALL); + else + brcms_b_mhf(wlc->hw, MHF4, MHF4_EXTPA_ENABLE, + MHF4_EXTPA_ENABLE, BRCM_BAND_ALL); + } + + /* + * Need to read the hwradio status here to cover the case where the + * system is loaded with the hw radio disabled. We do not want to bring + * the driver up in this case. If radio is disabled, abort up, lower + * power, start radio timer and return 0(for NDIS) don't call + * radio_update to avoid looping brcms_c_up. + * + * brcms_b_up_prep() returns either 0 or -BCME_RADIOOFF only + */ + if (!wlc->pub->radio_disabled) { + int status = brcms_b_up_prep(wlc->hw); + if (status == -ENOMEDIUM) { + if (!mboolisset + (wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) { + struct brcms_bss_cfg *bsscfg = wlc->bsscfg; + mboolset(wlc->pub->radio_disabled, + WL_RADIO_HW_DISABLE); + + if (bsscfg->enable && bsscfg->BSS) + wiphy_err(wlc->wiphy, "wl%d: up" + ": rfdisable -> " + "bsscfg_disable()\n", + wlc->pub->unit); + } + } + } + + if (wlc->pub->radio_disabled) { + brcms_c_radio_monitor_start(wlc); + return 0; + } + + /* brcms_b_up_prep has done brcms_c_corereset(). so clk is on, set it */ + wlc->clk = true; + + brcms_c_radio_monitor_stop(wlc); + + /* Set EDCF hostflags */ + brcms_b_mhf(wlc->hw, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL); + + brcms_init(wlc->wl); + wlc->pub->up = true; + + if (wlc->bandinit_pending) { + brcms_c_suspend_mac_and_wait(wlc); + brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec); + wlc->bandinit_pending = false; + brcms_c_enable_mac(wlc); + } + + brcms_b_up_finish(wlc->hw); + + /* Program the TX wme params with the current settings */ + brcms_c_wme_retries_write(wlc); + + /* start one second watchdog timer */ + brcms_add_timer(wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true); + wlc->WDarmed = true; + + /* ensure antenna config is up to date */ + brcms_c_stf_phy_txant_upd(wlc); + /* ensure LDPC config is in sync */ + brcms_c_ht_update_ldpc(wlc, wlc->stf->ldpc); + + return 0; +} + +static uint brcms_c_down_del_timer(struct brcms_c_info *wlc) +{ + uint callbacks = 0; + + return callbacks; +} + +static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw) +{ + bool dev_gone; + uint callbacks = 0; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + if (!wlc_hw->up) + return callbacks; + + dev_gone = brcms_deviceremoved(wlc_hw->wlc); + + /* disable interrupts */ + if (dev_gone) + wlc_hw->wlc->macintmask = 0; + else { + /* now disable interrupts */ + brcms_intrsoff(wlc_hw->wlc->wl); + + /* ensure we're running on the pll clock again */ + brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + } + /* down phy at the last of this stage */ + callbacks += wlc_phy_down(wlc_hw->band->pi); + + return callbacks; +} + +static int brcms_b_down_finish(struct brcms_hardware *wlc_hw) +{ + uint callbacks = 0; + bool dev_gone; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + + if (!wlc_hw->up) + return callbacks; + + wlc_hw->up = false; + wlc_phy_hw_state_upd(wlc_hw->band->pi, false); + + dev_gone = brcms_deviceremoved(wlc_hw->wlc); + + if (dev_gone) { + wlc_hw->sbclk = false; + wlc_hw->clk = false; + wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false); + + /* reclaim any posted packets */ + brcms_c_flushqueues(wlc_hw->wlc); + } else { + + /* Reset and disable the core */ + if (ai_iscoreup(wlc_hw->sih)) { + if (R_REG(&wlc_hw->regs->maccontrol) & + MCTL_EN_MAC) + brcms_c_suspend_mac_and_wait(wlc_hw->wlc); + callbacks += brcms_reset(wlc_hw->wlc->wl); + brcms_c_coredisable(wlc_hw); + } + + /* turn off primary xtal and pll */ + if (!wlc_hw->noreset) { + ai_pci_down(wlc_hw->sih); + brcms_b_xtal(wlc_hw, OFF); + } + } + + return callbacks; +} + +/* + * Mark the interface nonoperational, stop the software mechanisms, + * disable the hardware, free any transient buffer state. + * Return a count of the number of driver callbacks still pending. + */ +uint brcms_c_down(struct brcms_c_info *wlc) +{ + + uint callbacks = 0; + int i; + bool dev_gone = false; + struct brcms_txq_info *qi; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + + /* check if we are already in the going down path */ + if (wlc->going_down) { + wiphy_err(wlc->wiphy, "wl%d: %s: Driver going down so return" + "\n", wlc->pub->unit, __func__); + return 0; + } + if (!wlc->pub->up) + return callbacks; + + /* in between, mpc could try to bring down again.. */ + wlc->going_down = true; + + callbacks += brcms_b_bmac_down_prep(wlc->hw); + + dev_gone = brcms_deviceremoved(wlc); + + /* Call any registered down handlers */ + for (i = 0; i < BRCMS_MAXMODULES; i++) { + if (wlc->modulecb[i].down_fn) + callbacks += + wlc->modulecb[i].down_fn(wlc->modulecb[i].hdl); + } + + /* cancel the watchdog timer */ + if (wlc->WDarmed) { + if (!brcms_del_timer(wlc->wdtimer)) + callbacks++; + wlc->WDarmed = false; + } + /* cancel all other timers */ + callbacks += brcms_c_down_del_timer(wlc); + + wlc->pub->up = false; + + wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL); + + /* clear txq flow control */ + brcms_c_txflowcontrol_reset(wlc); + + /* flush tx queues */ + for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) + brcmu_pktq_flush(&qi->q, true, NULL, NULL); + + callbacks += brcms_b_down_finish(wlc->hw); + + /* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */ + wlc->clk = false; + + wlc->going_down = false; + return callbacks; +} + +/* Set the current gmode configuration */ +int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) +{ + int ret = 0; + uint i; + struct brcms_c_rateset rs; + /* Default to 54g Auto */ + /* Advertise and use shortslot (-1/0/1 Auto/Off/On) */ + s8 shortslot = BRCMS_SHORTSLOT_AUTO; + bool shortslot_restrict = false; /* Restrict association to stations + * that support shortslot + */ + bool ofdm_basic = false; /* Make 6, 12, and 24 basic rates */ + /* Advertise and use short preambles (-1/0/1 Auto/Off/On) */ + int preamble = BRCMS_PLCP_LONG; + bool preamble_restrict = false; /* Restrict association to stations + * that support short preambles + */ + struct brcms_band *band; + + /* if N-support is enabled, allow Gmode set as long as requested + * Gmode is not GMODE_LEGACY_B + */ + if ((wlc->pub->_n_enab & SUPPORT_11N) && gmode == GMODE_LEGACY_B) + return -ENOTSUPP; + + /* verify that we are dealing with 2G band and grab the band pointer */ + if (wlc->band->bandtype == BRCM_BAND_2G) + band = wlc->band; + else if ((wlc->pub->_nbands > 1) && + (wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == BRCM_BAND_2G)) + band = wlc->bandstate[OTHERBANDUNIT(wlc)]; + else + return -EINVAL; + + /* Legacy or bust when no OFDM is supported by regulatory */ + if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) & + BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B)) + return -EINVAL; + + /* update configuration value */ + if (config == true) + brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); + + /* Clear rateset override */ + memset(&rs, 0, sizeof(struct brcms_c_rateset)); + + switch (gmode) { + case GMODE_LEGACY_B: + shortslot = BRCMS_SHORTSLOT_OFF; + brcms_c_rateset_copy(&gphy_legacy_rates, &rs); + + break; + + case GMODE_LRS: + break; + + case GMODE_AUTO: + /* Accept defaults */ + break; + + case GMODE_ONLY: + ofdm_basic = true; + preamble = BRCMS_PLCP_SHORT; + preamble_restrict = true; + break; + + case GMODE_PERFORMANCE: + shortslot = BRCMS_SHORTSLOT_ON; + shortslot_restrict = true; + ofdm_basic = true; + preamble = BRCMS_PLCP_SHORT; + preamble_restrict = true; + break; + + default: + /* Error */ + wiphy_err(wlc->wiphy, "wl%d: %s: invalid gmode %d\n", + wlc->pub->unit, __func__, gmode); + return -ENOTSUPP; + } + + band->gmode = gmode; + + wlc->shortslot_override = shortslot; + + /* Use the default 11g rateset */ + if (!rs.count) + brcms_c_rateset_copy(&cck_ofdm_rates, &rs); + + if (ofdm_basic) { + for (i = 0; i < rs.count; i++) { + if (rs.rates[i] == BRCM_RATE_6M + || rs.rates[i] == BRCM_RATE_12M + || rs.rates[i] == BRCM_RATE_24M) + rs.rates[i] |= BRCMS_RATE_FLAG; + } + } + + /* Set default bss rateset */ + wlc->default_bss->rateset.count = rs.count; + memcpy(wlc->default_bss->rateset.rates, rs.rates, + sizeof(wlc->default_bss->rateset.rates)); + + return ret; +} + +int brcms_c_set_nmode(struct brcms_c_info *wlc) +{ + uint i; + s32 nmode = AUTO; + + if (wlc->stf->txstreams == WL_11N_3x3) + nmode = WL_11N_3x3; + else + nmode = WL_11N_2x2; + + /* force GMODE_AUTO if NMODE is ON */ + brcms_c_set_gmode(wlc, GMODE_AUTO, true); + if (nmode == WL_11N_3x3) + wlc->pub->_n_enab = SUPPORT_HT; + else + wlc->pub->_n_enab = SUPPORT_11N; + wlc->default_bss->flags |= BRCMS_BSS_HT; + /* add the mcs rates to the default and hw ratesets */ + brcms_c_rateset_mcs_build(&wlc->default_bss->rateset, + wlc->stf->txstreams); + for (i = 0; i < wlc->pub->_nbands; i++) + memcpy(wlc->bandstate[i]->hw_rateset.mcs, + wlc->default_bss->rateset.mcs, MCSSET_LEN); + + return 0; +} + +static int +brcms_c_set_internal_rateset(struct brcms_c_info *wlc, + struct brcms_c_rateset *rs_arg) +{ + struct brcms_c_rateset rs, new; + uint bandunit; + + memcpy(&rs, rs_arg, sizeof(struct brcms_c_rateset)); + + /* check for bad count value */ + if ((rs.count == 0) || (rs.count > BRCMS_NUMRATES)) + return -EINVAL; + + /* try the current band */ + bandunit = wlc->band->bandunit; + memcpy(&new, &rs, sizeof(struct brcms_c_rateset)); + if (brcms_c_rate_hwrs_filter_sort_validate + (&new, &wlc->bandstate[bandunit]->hw_rateset, true, + wlc->stf->txstreams)) + goto good; + + /* try the other band */ + if (brcms_is_mband_unlocked(wlc)) { + bandunit = OTHERBANDUNIT(wlc); + memcpy(&new, &rs, sizeof(struct brcms_c_rateset)); + if (brcms_c_rate_hwrs_filter_sort_validate(&new, + &wlc-> + bandstate[bandunit]-> + hw_rateset, true, + wlc->stf->txstreams)) + goto good; + } + + return -EBADE; + + good: + /* apply new rateset */ + memcpy(&wlc->default_bss->rateset, &new, + sizeof(struct brcms_c_rateset)); + memcpy(&wlc->bandstate[bandunit]->defrateset, &new, + sizeof(struct brcms_c_rateset)); + return 0; +} + +static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc) +{ + u8 r; + bool war = false; + + if (wlc->bsscfg->associated) + r = wlc->bsscfg->current_bss->rateset.rates[0]; + else + r = wlc->default_bss->rateset.rates[0]; + + wlc_phy_ofdm_rateset_war(wlc->band->pi, war); +} + +int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel) +{ + u16 chspec = ch20mhz_chspec(channel); + + if (channel < 0 || channel > MAXCHANNEL) + return -EINVAL; + + if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec)) + return -EINVAL; + + + if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) { + if (wlc->band->bandunit != chspec_bandunit(chspec)) + wlc->bandinit_pending = true; + else + wlc->bandinit_pending = false; + } + + wlc->default_bss->chanspec = chspec; + /* brcms_c_BSSinit() will sanitize the rateset before + * using it.. */ + if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) { + brcms_c_set_home_chanspec(wlc, chspec); + brcms_c_suspend_mac_and_wait(wlc); + brcms_c_set_chanspec(wlc, chspec); + brcms_c_enable_mac(wlc); + } + return 0; +} + +int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl) +{ + int ac; + + if (srl < 1 || srl > RETRY_SHORT_MAX || + lrl < 1 || lrl > RETRY_SHORT_MAX) + return -EINVAL; + + wlc->SRL = srl; + wlc->LRL = lrl; + + brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL); + + for (ac = 0; ac < AC_COUNT; ac++) { + wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], + EDCF_SHORT, wlc->SRL); + wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac], + EDCF_LONG, wlc->LRL); + } + brcms_c_wme_retries_write(wlc); + + return 0; +} + +void brcms_c_get_current_rateset(struct brcms_c_info *wlc, + struct brcm_rateset *currs) +{ + struct brcms_c_rateset *rs; + + if (wlc->pub->associated) + rs = &wlc->bsscfg->current_bss->rateset; + else + rs = &wlc->default_bss->rateset; + + /* Copy only legacy rateset section */ + currs->count = rs->count; + memcpy(&currs->rates, &rs->rates, rs->count); +} + +int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs) +{ + struct brcms_c_rateset internal_rs; + int bcmerror; + + if (rs->count > BRCMS_NUMRATES) + return -ENOBUFS; + + memset(&internal_rs, 0, sizeof(struct brcms_c_rateset)); + + /* Copy only legacy rateset section */ + internal_rs.count = rs->count; + memcpy(&internal_rs.rates, &rs->rates, internal_rs.count); + + /* merge rateset coming in with the current mcsset */ + if (wlc->pub->_n_enab & SUPPORT_11N) { + struct brcms_bss_info *mcsset_bss; + if (wlc->bsscfg->associated) + mcsset_bss = wlc->bsscfg->current_bss; + else + mcsset_bss = wlc->default_bss; + memcpy(internal_rs.mcs, &mcsset_bss->rateset.mcs[0], + MCSSET_LEN); + } + + bcmerror = brcms_c_set_internal_rateset(wlc, &internal_rs); + if (!bcmerror) + brcms_c_ofdm_rateset_war(wlc); + + return bcmerror; +} + +int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period) +{ + if (period < DOT11_MIN_BEACON_PERIOD || + period > DOT11_MAX_BEACON_PERIOD) + return -EINVAL; + + wlc->default_bss->beacon_period = period; + return 0; +} + +u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx) +{ + return wlc->band->phytype; +} + +void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override) +{ + wlc->shortslot_override = sslot_override; + + /* + * shortslot is an 11g feature, so no more work if we are + * currently on the 5G band + */ + if (wlc->band->bandtype == BRCM_BAND_5G) + return; + + if (wlc->pub->up && wlc->pub->associated) { + /* let watchdog or beacon processing update shortslot */ + } else if (wlc->pub->up) { + /* unassociated shortslot is off */ + brcms_c_switch_shortslot(wlc, false); + } else { + /* driver is down, so just update the brcms_c_info + * value */ + if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO) + wlc->shortslot = false; + else + wlc->shortslot = + (wlc->shortslot_override == + BRCMS_SHORTSLOT_ON); + } +} + +/* + * register watchdog and down handlers. + */ +int brcms_c_module_register(struct brcms_pub *pub, + const char *name, struct brcms_info *hdl, + int (*d_fn)(void *handle)) +{ + struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc; + int i; + + /* find an empty entry and just add, no duplication check! */ + for (i = 0; i < BRCMS_MAXMODULES; i++) { + if (wlc->modulecb[i].name[0] == '\0') { + strncpy(wlc->modulecb[i].name, name, + sizeof(wlc->modulecb[i].name) - 1); + wlc->modulecb[i].hdl = hdl; + wlc->modulecb[i].down_fn = d_fn; + return 0; + } + } + + return -ENOSR; +} + +/* unregister module callbacks */ +int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, + struct brcms_info *hdl) +{ + struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc; + int i; + + if (wlc == NULL) + return -ENODATA; + + for (i = 0; i < BRCMS_MAXMODULES; i++) { + if (!strcmp(wlc->modulecb[i].name, name) && + (wlc->modulecb[i].hdl == hdl)) { + memset(&wlc->modulecb[i], 0, sizeof(struct modulecb)); + return 0; + } + } + + /* table not found! */ + return -ENODATA; +} + +#ifdef BCMDBG +static const char * const supr_reason[] = { + "None", "PMQ Entry", "Flush request", + "Previous frag failure", "Channel mismatch", + "Lifetime Expiry", "Underflow" +}; + +static void brcms_c_print_txs_status(u16 s) +{ + printk(KERN_DEBUG "[15:12] %d frame attempts\n", + (s & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT); + printk(KERN_DEBUG " [11:8] %d rts attempts\n", + (s & TX_STATUS_RTS_RTX_MASK) >> TX_STATUS_RTS_RTX_SHIFT); + printk(KERN_DEBUG " [7] %d PM mode indicated\n", + ((s & TX_STATUS_PMINDCTD) ? 1 : 0)); + printk(KERN_DEBUG " [6] %d intermediate status\n", + ((s & TX_STATUS_INTERMEDIATE) ? 1 : 0)); + printk(KERN_DEBUG " [5] %d AMPDU\n", + (s & TX_STATUS_AMPDU) ? 1 : 0); + printk(KERN_DEBUG " [4:2] %d Frame Suppressed Reason (%s)\n", + ((s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT), + supr_reason[(s & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT]); + printk(KERN_DEBUG " [1] %d acked\n", + ((s & TX_STATUS_ACK_RCV) ? 1 : 0)); +} +#endif /* BCMDBG */ + +void brcms_c_print_txstatus(struct tx_status *txs) +{ +#if defined(BCMDBG) + u16 s = txs->status; + u16 ackphyrxsh = txs->ackphyrxsh; + + printk(KERN_DEBUG "\ntxpkt (MPDU) Complete\n"); + + printk(KERN_DEBUG "FrameID: %04x ", txs->frameid); + printk(KERN_DEBUG "TxStatus: %04x", s); + printk(KERN_DEBUG "\n"); + + brcms_c_print_txs_status(s); + + printk(KERN_DEBUG "LastTxTime: %04x ", txs->lasttxtime); + printk(KERN_DEBUG "Seq: %04x ", txs->sequence); + printk(KERN_DEBUG "PHYTxStatus: %04x ", txs->phyerr); + printk(KERN_DEBUG "RxAckRSSI: %04x ", + (ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT); + printk(KERN_DEBUG "RxAckSQ: %04x", + (ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); + printk(KERN_DEBUG "\n"); +#endif /* defined(BCMDBG) */ +} + +bool brcms_c_chipmatch(u16 vendor, u16 device) +{ + if (vendor != PCI_VENDOR_ID_BROADCOM) { + pr_err("chipmatch: unknown vendor id %04x\n", vendor); + return false; + } + + if (device == BCM43224_D11N_ID_VEN1) + return true; + if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID)) + return true; + if (device == BCM4313_D11N2G_ID) + return true; + if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID)) + return true; + + pr_err("chipmatch: unknown device id %04x\n", device); + return false; +} + +#if defined(BCMDBG) +void brcms_c_print_txdesc(struct d11txh *txh) +{ + u16 mtcl = le16_to_cpu(txh->MacTxControlLow); + u16 mtch = le16_to_cpu(txh->MacTxControlHigh); + u16 mfc = le16_to_cpu(txh->MacFrameControl); + u16 tfest = le16_to_cpu(txh->TxFesTimeNormal); + u16 ptcw = le16_to_cpu(txh->PhyTxControlWord); + u16 ptcw_1 = le16_to_cpu(txh->PhyTxControlWord_1); + u16 ptcw_1_Fbr = le16_to_cpu(txh->PhyTxControlWord_1_Fbr); + u16 ptcw_1_Rts = le16_to_cpu(txh->PhyTxControlWord_1_Rts); + u16 ptcw_1_FbrRts = le16_to_cpu(txh->PhyTxControlWord_1_FbrRts); + u16 mainrates = le16_to_cpu(txh->MainRates); + u16 xtraft = le16_to_cpu(txh->XtraFrameTypes); + u8 *iv = txh->IV; + u8 *ra = txh->TxFrameRA; + u16 tfestfb = le16_to_cpu(txh->TxFesTimeFallback); + u8 *rtspfb = txh->RTSPLCPFallback; + u16 rtsdfb = le16_to_cpu(txh->RTSDurFallback); + u8 *fragpfb = txh->FragPLCPFallback; + u16 fragdfb = le16_to_cpu(txh->FragDurFallback); + u16 mmodelen = le16_to_cpu(txh->MModeLen); + u16 mmodefbrlen = le16_to_cpu(txh->MModeFbrLen); + u16 tfid = le16_to_cpu(txh->TxFrameID); + u16 txs = le16_to_cpu(txh->TxStatus); + u16 mnmpdu = le16_to_cpu(txh->MaxNMpdus); + u16 mabyte = le16_to_cpu(txh->MaxABytes_MRT); + u16 mabyte_f = le16_to_cpu(txh->MaxABytes_FBR); + u16 mmbyte = le16_to_cpu(txh->MinMBytes); + + u8 *rtsph = txh->RTSPhyHeader; + struct ieee80211_rts rts = txh->rts_frame; + char hexbuf[256]; + + /* add plcp header along with txh descriptor */ + printk(KERN_DEBUG "Raw TxDesc + plcp header:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, + txh, sizeof(struct d11txh) + 48); + + printk(KERN_DEBUG "TxCtlLow: %04x ", mtcl); + printk(KERN_DEBUG "TxCtlHigh: %04x ", mtch); + printk(KERN_DEBUG "FC: %04x ", mfc); + printk(KERN_DEBUG "FES Time: %04x\n", tfest); + printk(KERN_DEBUG "PhyCtl: %04x%s ", ptcw, + (ptcw & PHY_TXC_SHORT_HDR) ? " short" : ""); + printk(KERN_DEBUG "PhyCtl_1: %04x ", ptcw_1); + printk(KERN_DEBUG "PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr); + printk(KERN_DEBUG "PhyCtl_1_Rts: %04x ", ptcw_1_Rts); + printk(KERN_DEBUG "PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts); + printk(KERN_DEBUG "MainRates: %04x ", mainrates); + printk(KERN_DEBUG "XtraFrameTypes: %04x ", xtraft); + printk(KERN_DEBUG "\n"); + + brcmu_format_hex(hexbuf, iv, sizeof(txh->IV)); + printk(KERN_DEBUG "SecIV: %s\n", hexbuf); + brcmu_format_hex(hexbuf, ra, sizeof(txh->TxFrameRA)); + printk(KERN_DEBUG "RA: %s\n", hexbuf); + + printk(KERN_DEBUG "Fb FES Time: %04x ", tfestfb); + brcmu_format_hex(hexbuf, rtspfb, sizeof(txh->RTSPLCPFallback)); + printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf); + printk(KERN_DEBUG "RTS DUR: %04x ", rtsdfb); + brcmu_format_hex(hexbuf, fragpfb, sizeof(txh->FragPLCPFallback)); + printk(KERN_DEBUG "PLCP: %s ", hexbuf); + printk(KERN_DEBUG "DUR: %04x", fragdfb); + printk(KERN_DEBUG "\n"); + + printk(KERN_DEBUG "MModeLen: %04x ", mmodelen); + printk(KERN_DEBUG "MModeFbrLen: %04x\n", mmodefbrlen); + + printk(KERN_DEBUG "FrameID: %04x\n", tfid); + printk(KERN_DEBUG "TxStatus: %04x\n", txs); + + printk(KERN_DEBUG "MaxNumMpdu: %04x\n", mnmpdu); + printk(KERN_DEBUG "MaxAggbyte: %04x\n", mabyte); + printk(KERN_DEBUG "MaxAggbyte_fb: %04x\n", mabyte_f); + printk(KERN_DEBUG "MinByte: %04x\n", mmbyte); + + brcmu_format_hex(hexbuf, rtsph, sizeof(txh->RTSPhyHeader)); + printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf); + brcmu_format_hex(hexbuf, (u8 *) &rts, sizeof(txh->rts_frame)); + printk(KERN_DEBUG "RTS Frame: %s", hexbuf); + printk(KERN_DEBUG "\n"); +} +#endif /* defined(BCMDBG) */ + +#if defined(BCMDBG) +int +brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf, + int len) +{ + int i; + char *p = buf; + char hexstr[16]; + int slen = 0, nlen = 0; + u32 bit; + const char *name; + + if (len < 2 || !buf) + return 0; + + buf[0] = '\0'; + + for (i = 0; flags != 0; i++) { + bit = bd[i].bit; + name = bd[i].name; + if (bit == 0 && flags != 0) { + /* print any unnamed bits */ + snprintf(hexstr, 16, "0x%X", flags); + name = hexstr; + flags = 0; /* exit loop */ + } else if ((flags & bit) == 0) + continue; + flags &= ~bit; + nlen = strlen(name); + slen += nlen; + /* count btwn flag space */ + if (flags != 0) + slen += 1; + /* need NULL char as well */ + if (len <= slen) + break; + /* copy NULL char but don't count it */ + strncpy(p, name, nlen + 1); + p += nlen; + /* copy btwn flag space and NULL char */ + if (flags != 0) + p += snprintf(p, 2, " "); + len -= slen; + } + + /* indicate the str was too short */ + if (flags != 0) { + if (len < 2) + p -= 2 - len; /* overwrite last char */ + p += snprintf(p, 2, ">"); + } + + return (int)(p - buf); +} +#endif /* defined(BCMDBG) */ + +#if defined(BCMDBG) +void brcms_c_print_rxh(struct d11rxhdr *rxh) +{ + u16 len = rxh->RxFrameSize; + u16 phystatus_0 = rxh->PhyRxStatus_0; + u16 phystatus_1 = rxh->PhyRxStatus_1; + u16 phystatus_2 = rxh->PhyRxStatus_2; + u16 phystatus_3 = rxh->PhyRxStatus_3; + u16 macstatus1 = rxh->RxStatus1; + u16 macstatus2 = rxh->RxStatus2; + char flagstr[64]; + char lenbuf[20]; + static const struct brcms_c_bit_desc macstat_flags[] = { + {RXS_FCSERR, "FCSErr"}, + {RXS_RESPFRAMETX, "Reply"}, + {RXS_PBPRES, "PADDING"}, + {RXS_DECATMPT, "DeCr"}, + {RXS_DECERR, "DeCrErr"}, + {RXS_BCNSENT, "Bcn"}, + {0, NULL} + }; + + printk(KERN_DEBUG "Raw RxDesc:\n"); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, rxh, + sizeof(struct d11rxhdr)); + + brcms_c_format_flags(macstat_flags, macstatus1, flagstr, 64); + + snprintf(lenbuf, sizeof(lenbuf), "0x%x", len); + + printk(KERN_DEBUG "RxFrameSize: %6s (%d)%s\n", lenbuf, len, + (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : ""); + printk(KERN_DEBUG "RxPHYStatus: %04x %04x %04x %04x\n", + phystatus_0, phystatus_1, phystatus_2, phystatus_3); + printk(KERN_DEBUG "RxMACStatus: %x %s\n", macstatus1, flagstr); + printk(KERN_DEBUG "RXMACaggtype: %x\n", + (macstatus2 & RXS_AGGTYPE_MASK)); + printk(KERN_DEBUG "RxTSFTime: %04x\n", rxh->RxTSFTime); +} +#endif /* defined(BCMDBG) */ + +u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate) +{ + u16 table_ptr; + u8 phy_rate, index; + + /* get the phy specific rate encoding for the PLCP SIGNAL field */ + if (is_ofdm_rate(rate)) + table_ptr = M_RT_DIRMAP_A; + else + table_ptr = M_RT_DIRMAP_B; + + /* for a given rate, the LS-nibble of the PLCP SIGNAL field is + * the index into the rate table. + */ + phy_rate = rate_info[rate] & BRCMS_RATE_MASK; + index = phy_rate & 0xf; + + /* Find the SHM pointer to the rate table entry by looking in the + * Direct-map Table + */ + return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2)); +} + +static bool +brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q, + struct sk_buff *pkt, int prec, bool head) +{ + struct sk_buff *p; + int eprec = -1; /* precedence to evict from */ + + /* Determine precedence from which to evict packet, if any */ + if (pktq_pfull(q, prec)) + eprec = prec; + else if (pktq_full(q)) { + p = brcmu_pktq_peek_tail(q, &eprec); + if (eprec > prec) { + wiphy_err(wlc->wiphy, "%s: Failing: eprec %d > prec %d" + "\n", __func__, eprec, prec); + return false; + } + } + + /* Evict if needed */ + if (eprec >= 0) { + bool discard_oldest; + + discard_oldest = ac_bitmap_tst(0, eprec); + + /* Refuse newer packet unless configured to discard oldest */ + if (eprec == prec && !discard_oldest) { + wiphy_err(wlc->wiphy, "%s: No where to go, prec == %d" + "\n", __func__, prec); + return false; + } + + /* Evict packet according to discard policy */ + p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) : + brcmu_pktq_pdeq_tail(q, eprec); + brcmu_pkt_buf_free_skb(p); + } + + /* Enqueue */ + if (head) + p = brcmu_pktq_penq_head(q, prec, pkt); + else + p = brcmu_pktq_penq(q, prec, pkt); + + return true; +} + +/* + * Attempts to queue a packet onto a multiple-precedence queue, + * if necessary evicting a lower precedence packet from the queue. + * + * 'prec' is the precedence number that has already been mapped + * from the packet priority. + * + * Returns true if packet consumed (queued), false if not. + */ +static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q, + struct sk_buff *pkt, int prec) +{ + return brcms_c_prec_enq_head(wlc, q, pkt, prec, false); +} + +void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb, + struct sk_buff *sdu, uint prec) +{ + struct brcms_txq_info *qi = wlc->pkt_queue; /* Check me */ + struct pktq *q = &qi->q; + int prio; + + prio = sdu->priority; + + if (!brcms_c_prec_enq(wlc, q, sdu, prec)) { + /* + * we might hit this condtion in case + * packet flooding from mac80211 stack + */ + brcmu_pkt_buf_free_skb(sdu); + } +} + +/* + * bcmc_fid_generate: + * Generate frame ID for a BCMC packet. The frag field is not used + * for MC frames so is used as part of the sequence number. + */ +static inline u16 +bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg, + struct d11txh *txh) +{ + u16 frameid; + + frameid = le16_to_cpu(txh->TxFrameID) & ~(TXFID_SEQ_MASK | + TXFID_QUEUE_MASK); + frameid |= + (((wlc-> + mc_fid_counter++) << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) | + TX_BCMC_FIFO; + + return frameid; +} + +static uint +brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec, + u8 preamble_type) +{ + uint dur = 0; + + BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n", + wlc->pub->unit, rspec, preamble_type); + /* + * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that + * is less than or equal to the rate of the immediately previous + * frame in the FES + */ + rspec = brcms_basic_rate(wlc, rspec); + /* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */ + dur = + brcms_c_calc_frame_time(wlc, rspec, preamble_type, + (DOT11_ACK_LEN + FCS_LEN)); + return dur; +} + +static uint +brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec, + u8 preamble_type) +{ + BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n", + wlc->pub->unit, rspec, preamble_type); + return brcms_c_calc_ack_time(wlc, rspec, preamble_type); +} + +static uint +brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec, + u8 preamble_type) +{ + BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, " + "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type); + /* + * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that + * is less than or equal to the rate of the immediately previous + * frame in the FES + */ + rspec = brcms_basic_rate(wlc, rspec); + /* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */ + return brcms_c_calc_frame_time(wlc, rspec, preamble_type, + (DOT11_BA_LEN + DOT11_BA_BITMAP_LEN + + FCS_LEN)); +} + +/* brcms_c_compute_frame_dur() + * + * Calculate the 802.11 MAC header DUR field for MPDU + * DUR for a single frame = 1 SIFS + 1 ACK + * DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time + * + * rate MPDU rate in unit of 500kbps + * next_frag_len next MPDU length in bytes + * preamble_type use short/GF or long/MM PLCP header + */ +static u16 +brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate, + u8 preamble_type, uint next_frag_len) +{ + u16 dur, sifs; + + sifs = get_sifs(wlc->band); + + dur = sifs; + dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type); + + if (next_frag_len) { + /* Double the current DUR to get 2 SIFS + 2 ACKs */ + dur *= 2; + /* add another SIFS and the frag time */ + dur += sifs; + dur += + (u16) brcms_c_calc_frame_time(wlc, rate, preamble_type, + next_frag_len); + } + return dur; +} + +/* The opposite of brcms_c_calc_frame_time */ +static uint +brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec, + u8 preamble_type, uint dur) +{ + uint nsyms, mac_len, Ndps, kNdps; + uint rate = rspec2rate(ratespec); + + BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n", + wlc->pub->unit, ratespec, preamble_type, dur); + + if (is_mcs_rate(ratespec)) { + uint mcs = ratespec & RSPEC_RATE_MASK; + int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec); + dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT); + /* payload calculation matches that of regular ofdm */ + if (wlc->band->bandtype == BRCM_BAND_2G) + dur -= DOT11_OFDM_SIGNAL_EXTENSION; + /* kNdbps = kbps * 4 */ + kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec), + rspec_issgi(ratespec)) * 4; + nsyms = dur / APHY_SYMBOL_TIME; + mac_len = + ((nsyms * kNdps) - + ((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000; + } else if (is_ofdm_rate(ratespec)) { + dur -= APHY_PREAMBLE_TIME; + dur -= APHY_SIGNAL_TIME; + /* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */ + Ndps = rate * 2; + nsyms = dur / APHY_SYMBOL_TIME; + mac_len = + ((nsyms * Ndps) - + (APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8; + } else { + if (preamble_type & BRCMS_SHORT_PREAMBLE) + dur -= BPHY_PLCP_SHORT_TIME; + else + dur -= BPHY_PLCP_TIME; + mac_len = dur * rate; + /* divide out factor of 2 in rate (1/2 mbps) */ + mac_len = mac_len / 8 / 2; + } + return mac_len; +} + +/* + * Return true if the specified rate is supported by the specified band. + * BRCM_BAND_AUTO indicates the current band. + */ +static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band, + bool verbose) +{ + struct brcms_c_rateset *hw_rateset; + uint i; + + if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype)) + hw_rateset = &wlc->band->hw_rateset; + else if (wlc->pub->_nbands > 1) + hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset; + else + /* other band specified and we are a single band device */ + return false; + + /* check if this is a mimo rate */ + if (is_mcs_rate(rspec)) { + if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE) + goto error; + + return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK)); + } + + for (i = 0; i < hw_rateset->count; i++) + if (hw_rateset->rates[i] == rspec2rate(rspec)) + return true; + error: + if (verbose) + wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x " + "not in hw_rateset\n", wlc->pub->unit, rspec); + + return false; +} + +static u32 +mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band, + u32 int_val) +{ + u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT; + u8 rate = int_val & NRATE_RATE_MASK; + u32 rspec; + bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE); + bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT); + bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY) + == NRATE_OVERRIDE_MCS_ONLY); + int bcmerror = 0; + + if (!ismcs) + return (u32) rate; + + /* validate the combination of rate/mcs/stf is allowed */ + if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) { + /* mcs only allowed when nmode */ + if (stf > PHY_TXC1_MODE_SDM) { + wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n", + wlc->pub->unit, __func__); + bcmerror = -EINVAL; + goto done; + } + + /* mcs 32 is a special case, DUP mode 40 only */ + if (rate == 32) { + if (!CHSPEC_IS40(wlc->home_chanspec) || + ((stf != PHY_TXC1_MODE_SISO) + && (stf != PHY_TXC1_MODE_CDD))) { + wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs " + "32\n", wlc->pub->unit, __func__); + bcmerror = -EINVAL; + goto done; + } + /* mcs > 7 must use stf SDM */ + } else if (rate > HIGHEST_SINGLE_STREAM_MCS) { + /* mcs > 7 must use stf SDM */ + if (stf != PHY_TXC1_MODE_SDM) { + BCMMSG(wlc->wiphy, "wl%d: enabling " + "SDM mode for mcs %d\n", + wlc->pub->unit, rate); + stf = PHY_TXC1_MODE_SDM; + } + } else { + /* + * MCS 0-7 may use SISO, CDD, and for + * phy_rev >= 3 STBC + */ + if ((stf > PHY_TXC1_MODE_STBC) || + (!BRCMS_STBC_CAP_PHY(wlc) + && (stf == PHY_TXC1_MODE_STBC))) { + wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC" + "\n", wlc->pub->unit, __func__); + bcmerror = -EINVAL; + goto done; + } + } + } else if (is_ofdm_rate(rate)) { + if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) { + wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n", + wlc->pub->unit, __func__); + bcmerror = -EINVAL; + goto done; + } + } else if (is_cck_rate(rate)) { + if ((cur_band->bandtype != BRCM_BAND_2G) + || (stf != PHY_TXC1_MODE_SISO)) { + wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n", + wlc->pub->unit, __func__); + bcmerror = -EINVAL; + goto done; + } + } else { + wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n", + wlc->pub->unit, __func__); + bcmerror = -EINVAL; + goto done; + } + /* make sure multiple antennae are available for non-siso rates */ + if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) { + wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO " + "request\n", wlc->pub->unit, __func__); + bcmerror = -EINVAL; + goto done; + } + + rspec = rate; + if (ismcs) { + rspec |= RSPEC_MIMORATE; + /* For STBC populate the STC field of the ratespec */ + if (stf == PHY_TXC1_MODE_STBC) { + u8 stc; + stc = 1; /* Nss for single stream is always 1 */ + rspec |= (stc << RSPEC_STC_SHIFT); + } + } + + rspec |= (stf << RSPEC_STF_SHIFT); + + if (override_mcs_only) + rspec |= RSPEC_OVERRIDE_MCS_ONLY; + + if (issgi) + rspec |= RSPEC_SHORT_GI; + + if ((rate != 0) + && !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true)) + return rate; + + return rspec; +done: + return rate; +} + +/* + * Compute PLCP, but only requires actual rate and length of pkt. + * Rate is given in the driver standard multiple of 500 kbps. + * le is set for 11 Mbps rate if necessary. + * Broken out for PRQ. + */ + +static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500, + uint length, u8 *plcp) +{ + u16 usec = 0; + u8 le = 0; + + switch (rate_500) { + case BRCM_RATE_1M: + usec = length << 3; + break; + case BRCM_RATE_2M: + usec = length << 2; + break; + case BRCM_RATE_5M5: + usec = (length << 4) / 11; + if ((length << 4) - (usec * 11) > 0) + usec++; + break; + case BRCM_RATE_11M: + usec = (length << 3) / 11; + if ((length << 3) - (usec * 11) > 0) { + usec++; + if ((usec * 11) - (length << 3) >= 8) + le = D11B_PLCP_SIGNAL_LE; + } + break; + + default: + wiphy_err(wlc->wiphy, + "brcms_c_cck_plcp_set: unsupported rate %d\n", + rate_500); + rate_500 = BRCM_RATE_1M; + usec = length << 3; + break; + } + /* PLCP signal byte */ + plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */ + /* PLCP service byte */ + plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED); + /* PLCP length u16, little endian */ + plcp[2] = usec & 0xff; + plcp[3] = (usec >> 8) & 0xff; + /* PLCP CRC16 */ + plcp[4] = 0; + plcp[5] = 0; +} + +/* Rate: 802.11 rate code, length: PSDU length in octets */ +static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp) +{ + u8 mcs = (u8) (rspec & RSPEC_RATE_MASK); + plcp[0] = mcs; + if (rspec_is40mhz(rspec) || (mcs == 32)) + plcp[0] |= MIMO_PLCP_40MHZ; + BRCMS_SET_MIMO_PLCP_LEN(plcp, length); + plcp[3] = rspec_mimoplcp3(rspec); /* rspec already holds this byte */ + plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */ + plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */ + plcp[5] = 0; +} + +/* Rate: 802.11 rate code, length: PSDU length in octets */ +static void +brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp) +{ + u8 rate_signal; + u32 tmp = 0; + int rate = rspec2rate(rspec); + + /* + * encode rate per 802.11a-1999 sec 17.3.4.1, with lsb + * transmitted first + */ + rate_signal = rate_info[rate] & BRCMS_RATE_MASK; + memset(plcp, 0, D11_PHY_HDR_LEN); + D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal); + + tmp = (length & 0xfff) << 5; + plcp[2] |= (tmp >> 16) & 0xff; + plcp[1] |= (tmp >> 8) & 0xff; + plcp[0] |= tmp & 0xff; +} + +/* Rate: 802.11 rate code, length: PSDU length in octets */ +static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec, + uint length, u8 *plcp) +{ + int rate = rspec2rate(rspec); + + brcms_c_cck_plcp_set(wlc, rate, length, plcp); +} + +static void +brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec, + uint length, u8 *plcp) +{ + if (is_mcs_rate(rspec)) + brcms_c_compute_mimo_plcp(rspec, length, plcp); + else if (is_ofdm_rate(rspec)) + brcms_c_compute_ofdm_plcp(rspec, length, plcp); + else + brcms_c_compute_cck_plcp(wlc, rspec, length, plcp); +} + +/* brcms_c_compute_rtscts_dur() + * + * Calculate the 802.11 MAC header DUR field for an RTS or CTS frame + * DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK + * DUR for CTS-TO-SELF w/ frame = 2 SIFS + next frame time + 1 ACK + * + * cts cts-to-self or rts/cts + * rts_rate rts or cts rate in unit of 500kbps + * rate next MPDU rate in unit of 500kbps + * frame_len next MPDU frame length in bytes + */ +u16 +brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only, + u32 rts_rate, + u32 frame_rate, u8 rts_preamble_type, + u8 frame_preamble_type, uint frame_len, bool ba) +{ + u16 dur, sifs; + + sifs = get_sifs(wlc->band); + + if (!cts_only) { + /* RTS/CTS */ + dur = 3 * sifs; + dur += + (u16) brcms_c_calc_cts_time(wlc, rts_rate, + rts_preamble_type); + } else { + /* CTS-TO-SELF */ + dur = 2 * sifs; + } + + dur += + (u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type, + frame_len); + if (ba) + dur += + (u16) brcms_c_calc_ba_time(wlc, frame_rate, + BRCMS_SHORT_PREAMBLE); + else + dur += + (u16) brcms_c_calc_ack_time(wlc, frame_rate, + frame_preamble_type); + return dur; +} + +static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec) +{ + u16 phyctl1 = 0; + u16 bw; + + if (BRCMS_ISLCNPHY(wlc->band)) { + bw = PHY_TXC1_BW_20MHZ; + } else { + bw = rspec_get_bw(rspec); + /* 10Mhz is not supported yet */ + if (bw < PHY_TXC1_BW_20MHZ) { + wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is " + "not supported yet, set to 20L\n", bw); + bw = PHY_TXC1_BW_20MHZ; + } + } + + if (is_mcs_rate(rspec)) { + uint mcs = rspec & RSPEC_RATE_MASK; + + /* bw, stf, coding-type is part of rspec_phytxbyte2 returns */ + phyctl1 = rspec_phytxbyte2(rspec); + /* set the upper byte of phyctl1 */ + phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8); + } else if (is_cck_rate(rspec) && !BRCMS_ISLCNPHY(wlc->band) + && !BRCMS_ISSSLPNPHY(wlc->band)) { + /* + * In CCK mode LPPHY overloads OFDM Modulation bits with CCK + * Data Rate. Eventually MIMOPHY would also be converted to + * this format + */ + /* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */ + phyctl1 = (bw | (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT)); + } else { /* legacy OFDM/CCK */ + s16 phycfg; + /* get the phyctl byte from rate phycfg table */ + phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec)); + if (phycfg == -1) { + wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong " + "legacy OFDM/CCK rate\n"); + phycfg = 0; + } + /* set the upper byte of phyctl1 */ + phyctl1 = + (bw | (phycfg << 8) | + (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT)); + } + return phyctl1; +} + +/* + * Add struct d11txh, struct cck_phy_hdr. + * + * 'p' data must start with 802.11 MAC header + * 'p' must allow enough bytes of local headers to be "pushed" onto the packet + * + * headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes) + * + */ +static u16 +brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw, + struct sk_buff *p, struct scb *scb, uint frag, + uint nfrags, uint queue, uint next_frag_len) +{ + struct ieee80211_hdr *h; + struct d11txh *txh; + u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN]; + int len, phylen, rts_phylen; + u16 mch, phyctl, xfts, mainrates; + u16 seq = 0, mcl = 0, status = 0, frameid = 0; + u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M }; + u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M }; + bool use_rts = false; + bool use_cts = false; + bool use_rifs = false; + bool short_preamble[2] = { false, false }; + u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE }; + u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE }; + u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN]; + struct ieee80211_rts *rts = NULL; + bool qos; + uint ac; + bool hwtkmic = false; + u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ; +#define ANTCFG_NONE 0xFF + u8 antcfg = ANTCFG_NONE; + u8 fbantcfg = ANTCFG_NONE; + uint phyctl1_stf = 0; + u16 durid = 0; + struct ieee80211_tx_rate *txrate[2]; + int k; + struct ieee80211_tx_info *tx_info; + bool is_mcs; + u16 mimo_txbw; + u8 mimo_preamble_type; + + /* locate 802.11 MAC header */ + h = (struct ieee80211_hdr *)(p->data); + qos = ieee80211_is_data_qos(h->frame_control); + + /* compute length of frame in bytes for use in PLCP computations */ + len = brcmu_pkttotlen(p); + phylen = len + FCS_LEN; + + /* Get tx_info */ + tx_info = IEEE80211_SKB_CB(p); + + /* add PLCP */ + plcp = skb_push(p, D11_PHY_HDR_LEN); + + /* add Broadcom tx descriptor header */ + txh = (struct d11txh *) skb_push(p, D11_TXH_LEN); + memset(txh, 0, D11_TXH_LEN); + + /* setup frameid */ + if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { + /* non-AP STA should never use BCMC queue */ + if (queue == TX_BCMC_FIFO) { + wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == " + "TX_BCMC!\n", wlc->pub->unit, __func__); + frameid = bcmc_fid_generate(wlc, NULL, txh); + } else { + /* Increment the counter for first fragment */ + if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + scb->seqnum[p->priority]++; + + /* extract fragment number from frame first */ + seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK; + seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT); + h->seq_ctrl = cpu_to_le16(seq); + + frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) | + (queue & TXFID_QUEUE_MASK); + } + } + frameid |= queue & TXFID_QUEUE_MASK; + + /* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */ + if (ieee80211_is_beacon(h->frame_control)) + mcl |= TXC_IGNOREPMQ; + + txrate[0] = tx_info->control.rates; + txrate[1] = txrate[0] + 1; + + /* + * if rate control algorithm didn't give us a fallback + * rate, use the primary rate + */ + if (txrate[1]->idx < 0) + txrate[1] = txrate[0]; + + for (k = 0; k < hw->max_rates; k++) { + is_mcs = txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false; + if (!is_mcs) { + if ((txrate[k]->idx >= 0) + && (txrate[k]->idx < + hw->wiphy->bands[tx_info->band]->n_bitrates)) { + rspec[k] = + hw->wiphy->bands[tx_info->band]-> + bitrates[txrate[k]->idx].hw_value; + short_preamble[k] = + txrate[k]-> + flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE ? + true : false; + } else { + rspec[k] = BRCM_RATE_1M; + } + } else { + rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band, + NRATE_MCS_INUSE | txrate[k]->idx); + } + + /* + * Currently only support same setting for primay and + * fallback rates. Unify flags for each rate into a + * single value for the frame + */ + use_rts |= + txrate[k]-> + flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false; + use_cts |= + txrate[k]-> + flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false; + + + /* + * (1) RATE: + * determine and validate primary rate + * and fallback rates + */ + if (!rspec_active(rspec[k])) { + rspec[k] = BRCM_RATE_1M; + } else { + if (!is_multicast_ether_addr(h->addr1)) { + /* set tx antenna config */ + brcms_c_antsel_antcfg_get(wlc->asi, false, + false, 0, 0, &antcfg, &fbantcfg); + } + } + } + + phyctl1_stf = wlc->stf->ss_opmode; + + if (wlc->pub->_n_enab & SUPPORT_11N) { + for (k = 0; k < hw->max_rates; k++) { + /* + * apply siso/cdd to single stream mcs's or ofdm + * if rspec is auto selected + */ + if (((is_mcs_rate(rspec[k]) && + is_single_stream(rspec[k] & RSPEC_RATE_MASK)) || + is_ofdm_rate(rspec[k])) + && ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY) + || !(rspec[k] & RSPEC_OVERRIDE))) { + rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK); + + /* For SISO MCS use STBC if possible */ + if (is_mcs_rate(rspec[k]) + && BRCMS_STF_SS_STBC_TX(wlc, scb)) { + u8 stc; + + /* Nss for single stream is always 1 */ + stc = 1; + rspec[k] |= (PHY_TXC1_MODE_STBC << + RSPEC_STF_SHIFT) | + (stc << RSPEC_STC_SHIFT); + } else + rspec[k] |= + (phyctl1_stf << RSPEC_STF_SHIFT); + } + + /* + * Is the phy configured to use 40MHZ frames? If + * so then pick the desired txbw + */ + if (brcms_chspec_bw(wlc->chanspec) == BRCMS_40_MHZ) { + /* default txbw is 20in40 SB */ + mimo_ctlchbw = mimo_txbw = + CHSPEC_SB_UPPER(wlc_phy_chanspec_get( + wlc->band->pi)) + ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ; + + if (is_mcs_rate(rspec[k])) { + /* mcs 32 must be 40b/w DUP */ + if ((rspec[k] & RSPEC_RATE_MASK) + == 32) { + mimo_txbw = + PHY_TXC1_BW_40MHZ_DUP; + /* use override */ + } else if (wlc->mimo_40txbw != AUTO) + mimo_txbw = wlc->mimo_40txbw; + /* else check if dst is using 40 Mhz */ + else if (scb->flags & SCB_IS40) + mimo_txbw = PHY_TXC1_BW_40MHZ; + } else if (is_ofdm_rate(rspec[k])) { + if (wlc->ofdm_40txbw != AUTO) + mimo_txbw = wlc->ofdm_40txbw; + } else if (wlc->cck_40txbw != AUTO) { + mimo_txbw = wlc->cck_40txbw; + } + } else { + /* + * mcs32 is 40 b/w only. + * This is possible for probe packets on + * a STA during SCAN + */ + if ((rspec[k] & RSPEC_RATE_MASK) == 32) + /* mcs 0 */ + rspec[k] = RSPEC_MIMORATE; + + mimo_txbw = PHY_TXC1_BW_20MHZ; + } + + /* Set channel width */ + rspec[k] &= ~RSPEC_BW_MASK; + if ((k == 0) || ((k > 0) && is_mcs_rate(rspec[k]))) + rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT); + else + rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT); + + /* Disable short GI, not supported yet */ + rspec[k] &= ~RSPEC_SHORT_GI; + + mimo_preamble_type = BRCMS_MM_PREAMBLE; + if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD) + mimo_preamble_type = BRCMS_GF_PREAMBLE; + + if ((txrate[k]->flags & IEEE80211_TX_RC_MCS) + && (!is_mcs_rate(rspec[k]))) { + wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_" + "RC_MCS != is_mcs_rate(rspec)\n", + wlc->pub->unit, __func__); + } + + if (is_mcs_rate(rspec[k])) { + preamble_type[k] = mimo_preamble_type; + + /* + * if SGI is selected, then forced mm + * for single stream + */ + if ((rspec[k] & RSPEC_SHORT_GI) + && is_single_stream(rspec[k] & + RSPEC_RATE_MASK)) + preamble_type[k] = BRCMS_MM_PREAMBLE; + } + + /* should be better conditionalized */ + if (!is_mcs_rate(rspec[0]) + && (tx_info->control.rates[0]. + flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)) + preamble_type[k] = BRCMS_SHORT_PREAMBLE; + } + } else { + for (k = 0; k < hw->max_rates; k++) { + /* Set ctrlchbw as 20Mhz */ + rspec[k] &= ~RSPEC_BW_MASK; + rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT); + + /* for nphy, stf of ofdm frames must follow policies */ + if (BRCMS_ISNPHY(wlc->band) && is_ofdm_rate(rspec[k])) { + rspec[k] &= ~RSPEC_STF_MASK; + rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT; + } + } + } + + /* Reset these for use with AMPDU's */ + txrate[0]->count = 0; + txrate[1]->count = 0; + + /* (2) PROTECTION, may change rspec */ + if ((ieee80211_is_data(h->frame_control) || + ieee80211_is_mgmt(h->frame_control)) && + (phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1)) + use_rts = true; + + /* (3) PLCP: determine PLCP header and MAC duration, + * fill struct d11txh */ + brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp); + brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback); + memcpy(&txh->FragPLCPFallback, + plcp_fallback, sizeof(txh->FragPLCPFallback)); + + /* Length field now put in CCK FBR CRC field */ + if (is_cck_rate(rspec[1])) { + txh->FragPLCPFallback[4] = phylen & 0xff; + txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8; + } + + /* MIMO-RATE: need validation ?? */ + mainrates = is_ofdm_rate(rspec[0]) ? + D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) : + plcp[0]; + + /* DUR field for main rate */ + if (!ieee80211_is_pspoll(h->frame_control) && + !is_multicast_ether_addr(h->addr1) && !use_rifs) { + durid = + brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0], + next_frag_len); + h->duration_id = cpu_to_le16(durid); + } else if (use_rifs) { + /* NAV protect to end of next max packet size */ + durid = + (u16) brcms_c_calc_frame_time(wlc, rspec[0], + preamble_type[0], + DOT11_MAX_FRAG_LEN); + durid += RIFS_11N_TIME; + h->duration_id = cpu_to_le16(durid); + } + + /* DUR field for fallback rate */ + if (ieee80211_is_pspoll(h->frame_control)) + txh->FragDurFallback = h->duration_id; + else if (is_multicast_ether_addr(h->addr1) || use_rifs) + txh->FragDurFallback = 0; + else { + durid = brcms_c_compute_frame_dur(wlc, rspec[1], + preamble_type[1], next_frag_len); + txh->FragDurFallback = cpu_to_le16(durid); + } + + /* (4) MAC-HDR: MacTxControlLow */ + if (frag == 0) + mcl |= TXC_STARTMSDU; + + if (!is_multicast_ether_addr(h->addr1)) + mcl |= TXC_IMMEDACK; + + if (wlc->band->bandtype == BRCM_BAND_5G) + mcl |= TXC_FREQBAND_5G; + + if (CHSPEC_IS40(wlc_phy_chanspec_get(wlc->band->pi))) + mcl |= TXC_BW_40; + + /* set AMIC bit if using hardware TKIP MIC */ + if (hwtkmic) + mcl |= TXC_AMIC; + + txh->MacTxControlLow = cpu_to_le16(mcl); + + /* MacTxControlHigh */ + mch = 0; + + /* Set fallback rate preamble type */ + if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) || + (preamble_type[1] == BRCMS_GF_PREAMBLE)) { + if (rspec2rate(rspec[1]) != BRCM_RATE_1M) + mch |= TXC_PREAMBLE_DATA_FB_SHORT; + } + + /* MacFrameControl */ + memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16)); + txh->TxFesTimeNormal = cpu_to_le16(0); + + txh->TxFesTimeFallback = cpu_to_le16(0); + + /* TxFrameRA */ + memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN); + + /* TxFrameID */ + txh->TxFrameID = cpu_to_le16(frameid); + + /* + * TxStatus, Note the case of recreating the first frag of a suppressed + * frame then we may need to reset the retry cnt's via the status reg + */ + txh->TxStatus = cpu_to_le16(status); + + /* + * extra fields for ucode AMPDU aggregation, the new fields are added to + * the END of previous structure so that it's compatible in driver. + */ + txh->MaxNMpdus = cpu_to_le16(0); + txh->MaxABytes_MRT = cpu_to_le16(0); + txh->MaxABytes_FBR = cpu_to_le16(0); + txh->MinMBytes = cpu_to_le16(0); + + /* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration, + * furnish struct d11txh */ + /* RTS PLCP header and RTS frame */ + if (use_rts || use_cts) { + if (use_rts && use_cts) + use_cts = false; + + for (k = 0; k < 2; k++) { + rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k], + false, + mimo_ctlchbw); + } + + if (!is_ofdm_rate(rts_rspec[0]) && + !((rspec2rate(rts_rspec[0]) == BRCM_RATE_1M) || + (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) { + rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE; + mch |= TXC_PREAMBLE_RTS_MAIN_SHORT; + } + + if (!is_ofdm_rate(rts_rspec[1]) && + !((rspec2rate(rts_rspec[1]) == BRCM_RATE_1M) || + (wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) { + rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE; + mch |= TXC_PREAMBLE_RTS_FB_SHORT; + } + + /* RTS/CTS additions to MacTxControlLow */ + if (use_cts) { + txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS); + } else { + txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS); + txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME); + } + + /* RTS PLCP header */ + rts_plcp = txh->RTSPhyHeader; + if (use_cts) + rts_phylen = DOT11_CTS_LEN + FCS_LEN; + else + rts_phylen = DOT11_RTS_LEN + FCS_LEN; + + brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp); + + /* fallback rate version of RTS PLCP header */ + brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen, + rts_plcp_fallback); + memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback, + sizeof(txh->RTSPLCPFallback)); + + /* RTS frame fields... */ + rts = (struct ieee80211_rts *)&txh->rts_frame; + + durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0], + rspec[0], rts_preamble_type[0], + preamble_type[0], phylen, false); + rts->duration = cpu_to_le16(durid); + /* fallback rate version of RTS DUR field */ + durid = brcms_c_compute_rtscts_dur(wlc, use_cts, + rts_rspec[1], rspec[1], + rts_preamble_type[1], + preamble_type[1], phylen, false); + txh->RTSDurFallback = cpu_to_le16(durid); + + if (use_cts) { + rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | + IEEE80211_STYPE_CTS); + + memcpy(&rts->ra, &h->addr2, ETH_ALEN); + } else { + rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | + IEEE80211_STYPE_RTS); + + memcpy(&rts->ra, &h->addr1, 2 * ETH_ALEN); + } + + /* mainrate + * low 8 bits: main frag rate/mcs, + * high 8 bits: rts/cts rate/mcs + */ + mainrates |= (is_ofdm_rate(rts_rspec[0]) ? + D11A_PHY_HDR_GRATE( + (struct ofdm_phy_hdr *) rts_plcp) : + rts_plcp[0]) << 8; + } else { + memset((char *)txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN); + memset((char *)&txh->rts_frame, 0, + sizeof(struct ieee80211_rts)); + memset((char *)txh->RTSPLCPFallback, 0, + sizeof(txh->RTSPLCPFallback)); + txh->RTSDurFallback = 0; + } + +#ifdef SUPPORT_40MHZ + /* add null delimiter count */ + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && is_mcs_rate(rspec)) + txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = + brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen); + +#endif + + /* + * Now that RTS/RTS FB preamble types are updated, write + * the final value + */ + txh->MacTxControlHigh = cpu_to_le16(mch); + + /* + * MainRates (both the rts and frag plcp rates have + * been calculated now) + */ + txh->MainRates = cpu_to_le16(mainrates); + + /* XtraFrameTypes */ + xfts = frametype(rspec[1], wlc->mimoft); + xfts |= (frametype(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT); + xfts |= (frametype(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT); + xfts |= CHSPEC_CHANNEL(wlc_phy_chanspec_get(wlc->band->pi)) << + XFTS_CHANNEL_SHIFT; + txh->XtraFrameTypes = cpu_to_le16(xfts); + + /* PhyTxControlWord */ + phyctl = frametype(rspec[0], wlc->mimoft); + if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) || + (preamble_type[0] == BRCMS_GF_PREAMBLE)) { + if (rspec2rate(rspec[0]) != BRCM_RATE_1M) + phyctl |= PHY_TXC_SHORT_HDR; + } + + /* phytxant is properly bit shifted */ + phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]); + txh->PhyTxControlWord = cpu_to_le16(phyctl); + + /* PhyTxControlWord_1 */ + if (BRCMS_PHY_11N_CAP(wlc->band)) { + u16 phyctl1 = 0; + + phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]); + txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1); + phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]); + txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1); + + if (use_rts || use_cts) { + phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]); + txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1); + phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]); + txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1); + } + + /* + * For mcs frames, if mixedmode(overloaded with long preamble) + * is going to be set, fill in non-zero MModeLen and/or + * MModeFbrLen it will be unnecessary if they are separated + */ + if (is_mcs_rate(rspec[0]) && + (preamble_type[0] == BRCMS_MM_PREAMBLE)) { + u16 mmodelen = + brcms_c_calc_lsig_len(wlc, rspec[0], phylen); + txh->MModeLen = cpu_to_le16(mmodelen); + } + + if (is_mcs_rate(rspec[1]) && + (preamble_type[1] == BRCMS_MM_PREAMBLE)) { + u16 mmodefbrlen = + brcms_c_calc_lsig_len(wlc, rspec[1], phylen); + txh->MModeFbrLen = cpu_to_le16(mmodefbrlen); + } + } + + ac = skb_get_queue_mapping(p); + if ((scb->flags & SCB_WMECAP) && qos && wlc->edcf_txop[ac]) { + uint frag_dur, dur, dur_fallback; + + /* WME: Update TXOP threshold */ + if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) { + frag_dur = + brcms_c_calc_frame_time(wlc, rspec[0], + preamble_type[0], phylen); + + if (rts) { + /* 1 RTS or CTS-to-self frame */ + dur = + brcms_c_calc_cts_time(wlc, rts_rspec[0], + rts_preamble_type[0]); + dur_fallback = + brcms_c_calc_cts_time(wlc, rts_rspec[1], + rts_preamble_type[1]); + /* (SIFS + CTS) + SIFS + frame + SIFS + ACK */ + dur += le16_to_cpu(rts->duration); + dur_fallback += + le16_to_cpu(txh->RTSDurFallback); + } else if (use_rifs) { + dur = frag_dur; + dur_fallback = 0; + } else { + /* frame + SIFS + ACK */ + dur = frag_dur; + dur += + brcms_c_compute_frame_dur(wlc, rspec[0], + preamble_type[0], 0); + + dur_fallback = + brcms_c_calc_frame_time(wlc, rspec[1], + preamble_type[1], + phylen); + dur_fallback += + brcms_c_compute_frame_dur(wlc, rspec[1], + preamble_type[1], 0); + } + /* NEED to set TxFesTimeNormal (hard) */ + txh->TxFesTimeNormal = cpu_to_le16((u16) dur); + /* + * NEED to set fallback rate version of + * TxFesTimeNormal (hard) + */ + txh->TxFesTimeFallback = + cpu_to_le16((u16) dur_fallback); + + /* + * update txop byte threshold (txop minus intraframe + * overhead) + */ + if (wlc->edcf_txop[ac] >= (dur - frag_dur)) { + uint newfragthresh; + + newfragthresh = + brcms_c_calc_frame_len(wlc, + rspec[0], preamble_type[0], + (wlc->edcf_txop[ac] - + (dur - frag_dur))); + /* range bound the fragthreshold */ + if (newfragthresh < DOT11_MIN_FRAG_LEN) + newfragthresh = + DOT11_MIN_FRAG_LEN; + else if (newfragthresh > + wlc->usr_fragthresh) + newfragthresh = + wlc->usr_fragthresh; + /* update the fragthresh and do txc update */ + if (wlc->fragthresh[queue] != + (u16) newfragthresh) + wlc->fragthresh[queue] = + (u16) newfragthresh; + } else { + wiphy_err(wlc->wiphy, "wl%d: %s txop invalid " + "for rate %d\n", + wlc->pub->unit, fifo_names[queue], + rspec2rate(rspec[0])); + } + + if (dur > wlc->edcf_txop[ac]) + wiphy_err(wlc->wiphy, "wl%d: %s: %s txop " + "exceeded phylen %d/%d dur %d/%d\n", + wlc->pub->unit, __func__, + fifo_names[queue], + phylen, wlc->fragthresh[queue], + dur, wlc->edcf_txop[ac]); + } + } + + return 0; +} + +void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu, + struct ieee80211_hw *hw) +{ + u8 prio; + uint fifo; + struct scb *scb = &wlc->pri_scb; + struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data); + + /* + * 802.11 standard requires management traffic + * to go at highest priority + */ + prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority : + MAXPRIO; + fifo = prio2fifo[prio]; + if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0)) + return; + brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio)); + brcms_c_send_q(wlc); +} + +void brcms_c_send_q(struct brcms_c_info *wlc) +{ + struct sk_buff *pkt[DOT11_MAXNUMFRAGS]; + int prec; + u16 prec_map; + int err = 0, i, count; + uint fifo; + struct brcms_txq_info *qi = wlc->pkt_queue; + struct pktq *q = &qi->q; + struct ieee80211_tx_info *tx_info; + + prec_map = wlc->tx_prec_map; + + /* Send all the enq'd pkts that we can. + * Dequeue packets with precedence with empty HW fifo only + */ + while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) { + tx_info = IEEE80211_SKB_CB(pkt[0]); + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { + err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec); + } else { + count = 1; + err = brcms_c_prep_pdu(wlc, pkt[0], &fifo); + if (!err) { + for (i = 0; i < count; i++) + brcms_c_txfifo(wlc, fifo, pkt[i], true, + 1); + } + } + + if (err == -EBUSY) { + brcmu_pktq_penq_head(q, prec, pkt[0]); + /* + * If send failed due to any other reason than a + * change in HW FIFO condition, quit. Otherwise, + * read the new prec_map! + */ + if (prec_map == wlc->tx_prec_map) + break; + prec_map = wlc->tx_prec_map; + } + } +} + +void +brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p, + bool commit, s8 txpktpend) +{ + u16 frameid = INVALIDFID; + struct d11txh *txh; + + txh = (struct d11txh *) (p->data); + + /* When a BC/MC frame is being committed to the BCMC fifo + * via DMA (NOT PIO), update ucode or BSS info as appropriate. + */ + if (fifo == TX_BCMC_FIFO) + frameid = le16_to_cpu(txh->TxFrameID); + + /* + * Bump up pending count for if not using rpc. If rpc is + * used, this will be handled in brcms_b_txfifo() + */ + if (commit) { + wlc->core->txpktpend[fifo] += txpktpend; + BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n", + txpktpend, wlc->core->txpktpend[fifo]); + } + + /* Commit BCMC sequence number in the SHM frame ID location */ + if (frameid != INVALIDFID) { + /* + * To inform the ucode of the last mcast frame posted + * so that it can clear moredata bit + */ + brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid); + } + + if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0) + wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n"); +} + +u32 +brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec, + bool use_rspec, u16 mimo_ctlchbw) +{ + u32 rts_rspec = 0; + + if (use_rspec) + /* use frame rate as rts rate */ + rts_rspec = rspec; + else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(rspec)) + /* Use 11Mbps as the g protection RTS target rate and fallback. + * Use the brcms_basic_rate() lookup to find the best basic rate + * under the target in case 11 Mbps is not Basic. + * 6 and 9 Mbps are not usually selected by rate selection, but + * even if the OFDM rate we are protecting is 6 or 9 Mbps, 11 + * is more robust. + */ + rts_rspec = brcms_basic_rate(wlc, BRCM_RATE_11M); + else + /* calculate RTS rate and fallback rate based on the frame rate + * RTS must be sent at a basic rate since it is a + * control frame, sec 9.6 of 802.11 spec + */ + rts_rspec = brcms_basic_rate(wlc, rspec); + + if (BRCMS_PHY_11N_CAP(wlc->band)) { + /* set rts txbw to correct side band */ + rts_rspec &= ~RSPEC_BW_MASK; + + /* + * if rspec/rspec_fallback is 40MHz, then send RTS on both + * 20MHz channel (DUP), otherwise send RTS on control channel + */ + if (rspec_is40mhz(rspec) && !is_cck_rate(rts_rspec)) + rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT); + else + rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT); + + /* pick siso/cdd as default for ofdm */ + if (is_ofdm_rate(rts_rspec)) { + rts_rspec &= ~RSPEC_STF_MASK; + rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT); + } + } + return rts_rspec; +} + +void +brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend) +{ + wlc->core->txpktpend[fifo] -= txpktpend; + BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend, + wlc->core->txpktpend[fifo]); + + /* There is more room; mark precedences related to this FIFO sendable */ + wlc->tx_prec_map |= wlc->fifo2prec_map[fifo]; + + /* figure out which bsscfg is being worked on... */ +} + +/* Update beacon listen interval in shared memory */ +static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc) +{ + /* wake up every DTIM is the default */ + if (wlc->bcn_li_dtim == 1) + brcms_b_write_shm(wlc->hw, M_BCN_LI, 0); + else + brcms_b_write_shm(wlc->hw, M_BCN_LI, + (wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn); +} + +static void +brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr, + u32 *tsf_h_ptr) +{ + struct d11regs __iomem *regs = wlc_hw->regs; + + /* read the tsf timer low, then high to get an atomic read */ + *tsf_l_ptr = R_REG(®s->tsf_timerlow); + *tsf_h_ptr = R_REG(®s->tsf_timerhigh); +} + +/* + * recover 64bit TSF value from the 16bit TSF value in the rx header + * given the assumption that the TSF passed in header is within 65ms + * of the current tsf. + * + * 6 5 4 4 3 2 1 + * 3.......6.......8.......0.......2.......4.......6.......8......0 + * |<---------- tsf_h ----------->||<--- tsf_l -->||<-RxTSFTime ->| + * + * The RxTSFTime are the lowest 16 bits and provided by the ucode. The + * tsf_l is filled in by brcms_b_recv, which is done earlier in the + * receive call sequence after rx interrupt. Only the higher 16 bits + * are used. Finally, the tsf_h is read from the tsf register. + */ +static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc, + struct d11rxhdr *rxh) +{ + u32 tsf_h, tsf_l; + u16 rx_tsf_0_15, rx_tsf_16_31; + + brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h); + + rx_tsf_16_31 = (u16)(tsf_l >> 16); + rx_tsf_0_15 = rxh->RxTSFTime; + + /* + * a greater tsf time indicates the low 16 bits of + * tsf_l wrapped, so decrement the high 16 bits. + */ + if ((u16)tsf_l < rx_tsf_0_15) { + rx_tsf_16_31 -= 1; + if (rx_tsf_16_31 == 0xffff) + tsf_h -= 1; + } + + return ((u64)tsf_h << 32) | (((u32)rx_tsf_16_31 << 16) + rx_tsf_0_15); +} + +static void +prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh, + struct sk_buff *p, + struct ieee80211_rx_status *rx_status) +{ + int preamble; + int channel; + u32 rspec; + unsigned char *plcp; + + /* fill in TSF and flag its presence */ + rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh); + rx_status->flag |= RX_FLAG_MACTIME_MPDU; + + channel = BRCMS_CHAN_CHANNEL(rxh->RxChan); + + if (channel > 14) { + rx_status->band = IEEE80211_BAND_5GHZ; + rx_status->freq = ieee80211_ofdm_chan_to_freq( + WF_CHAN_FACTOR_5_G/2, channel); + + } else { + rx_status->band = IEEE80211_BAND_2GHZ; + rx_status->freq = ieee80211_dsss_chan_to_freq(channel); + } + + rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh); + + /* noise */ + /* qual */ + rx_status->antenna = + (rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0; + + plcp = p->data; + + rspec = brcms_c_compute_rspec(rxh, plcp); + if (is_mcs_rate(rspec)) { + rx_status->rate_idx = rspec & RSPEC_RATE_MASK; + rx_status->flag |= RX_FLAG_HT; + if (rspec_is40mhz(rspec)) + rx_status->flag |= RX_FLAG_40MHZ; + } else { + switch (rspec2rate(rspec)) { + case BRCM_RATE_1M: + rx_status->rate_idx = 0; + break; + case BRCM_RATE_2M: + rx_status->rate_idx = 1; + break; + case BRCM_RATE_5M5: + rx_status->rate_idx = 2; + break; + case BRCM_RATE_11M: + rx_status->rate_idx = 3; + break; + case BRCM_RATE_6M: + rx_status->rate_idx = 4; + break; + case BRCM_RATE_9M: + rx_status->rate_idx = 5; + break; + case BRCM_RATE_12M: + rx_status->rate_idx = 6; + break; + case BRCM_RATE_18M: + rx_status->rate_idx = 7; + break; + case BRCM_RATE_24M: + rx_status->rate_idx = 8; + break; + case BRCM_RATE_36M: + rx_status->rate_idx = 9; + break; + case BRCM_RATE_48M: + rx_status->rate_idx = 10; + break; + case BRCM_RATE_54M: + rx_status->rate_idx = 11; + break; + default: + wiphy_err(wlc->wiphy, "%s: Unknown rate\n", __func__); + } + + /* + * For 5GHz, we should decrease the index as it is + * a subset of the 2.4G rates. See bitrates field + * of brcms_band_5GHz_nphy (in mac80211_if.c). + */ + if (rx_status->band == IEEE80211_BAND_5GHZ) + rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET; + + /* Determine short preamble and rate_idx */ + preamble = 0; + if (is_cck_rate(rspec)) { + if (rxh->PhyRxStatus_0 & PRXS0_SHORTH) + rx_status->flag |= RX_FLAG_SHORTPRE; + } else if (is_ofdm_rate(rspec)) { + rx_status->flag |= RX_FLAG_SHORTPRE; + } else { + wiphy_err(wlc->wiphy, "%s: Unknown modulation\n", + __func__); + } + } + + if (plcp3_issgi(plcp[3])) + rx_status->flag |= RX_FLAG_SHORT_GI; + + if (rxh->RxStatus1 & RXS_DECERR) { + rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; + wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_PLCP_CRC\n", + __func__); + } + if (rxh->RxStatus1 & RXS_FCSERR) { + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + wiphy_err(wlc->wiphy, "%s: RX_FLAG_FAILED_FCS_CRC\n", + __func__); + } +} + +static void +brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh, + struct sk_buff *p) +{ + int len_mpdu; + struct ieee80211_rx_status rx_status; + + memset(&rx_status, 0, sizeof(rx_status)); + prep_mac80211_status(wlc, rxh, p, &rx_status); + + /* mac header+body length, exclude CRC and plcp header */ + len_mpdu = p->len - D11_PHY_HDR_LEN - FCS_LEN; + skb_pull(p, D11_PHY_HDR_LEN); + __skb_trim(p, len_mpdu); + + memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status)); + ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p); +} + +/* calculate frame duration for Mixed-mode L-SIG spoofing, return + * number of bytes goes in the length field + * + * Formula given by HT PHY Spec v 1.13 + * len = 3(nsyms + nstream + 3) - 3 + */ +u16 +brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, + uint mac_len) +{ + uint nsyms, len = 0, kNdps; + + BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n", + wlc->pub->unit, rspec2rate(ratespec), mac_len); + + if (is_mcs_rate(ratespec)) { + uint mcs = ratespec & RSPEC_RATE_MASK; + int tot_streams = (mcs_2_txstreams(mcs) + 1) + + rspec_stc(ratespec); + + /* + * the payload duration calculation matches that + * of regular ofdm + */ + /* 1000Ndbps = kbps * 4 */ + kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec), + rspec_issgi(ratespec)) * 4; + + if (rspec_stc(ratespec) == 0) + nsyms = + CEIL((APHY_SERVICE_NBITS + 8 * mac_len + + APHY_TAIL_NBITS) * 1000, kNdps); + else + /* STBC needs to have even number of symbols */ + nsyms = + 2 * + CEIL((APHY_SERVICE_NBITS + 8 * mac_len + + APHY_TAIL_NBITS) * 1000, 2 * kNdps); + + /* (+3) account for HT-SIG(2) and HT-STF(1) */ + nsyms += (tot_streams + 3); + /* + * 3 bytes/symbol @ legacy 6Mbps rate + * (-3) excluding service bits and tail bits + */ + len = (3 * nsyms) - 3; + } + + return (u16) len; +} + +static void +brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len) +{ + const struct brcms_c_rateset *rs_dflt; + struct brcms_c_rateset rs; + u8 rate; + u16 entry_ptr; + u8 plcp[D11_PHY_HDR_LEN]; + u16 dur, sifs; + uint i; + + sifs = get_sifs(wlc->band); + + rs_dflt = brcms_c_rateset_get_hwrs(wlc); + + brcms_c_rateset_copy(rs_dflt, &rs); + brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams); + + /* + * walk the phy rate table and update MAC core SHM + * basic rate table entries + */ + for (i = 0; i < rs.count; i++) { + rate = rs.rates[i] & BRCMS_RATE_MASK; + + entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate); + + /* Calculate the Probe Response PLCP for the given rate */ + brcms_c_compute_plcp(wlc, rate, frame_len, plcp); + + /* + * Calculate the duration of the Probe Response + * frame plus SIFS for the MAC + */ + dur = (u16) brcms_c_calc_frame_time(wlc, rate, + BRCMS_LONG_PREAMBLE, frame_len); + dur += sifs; + + /* Update the SHM Rate Table entry Probe Response values */ + brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS, + (u16) (plcp[0] + (plcp[1] << 8))); + brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2, + (u16) (plcp[2] + (plcp[3] << 8))); + brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur); + } +} + +/* Max buffering needed for beacon template/prb resp template is 142 bytes. + * + * PLCP header is 6 bytes. + * 802.11 A3 header is 24 bytes. + * Max beacon frame body template length is 112 bytes. + * Max probe resp frame body template length is 110 bytes. + * + * *len on input contains the max length of the packet available. + * + * The *len value is set to the number of bytes in buf used, and starts + * with the PLCP and included up to, but not including, the 4 byte FCS. + */ +static void +brcms_c_bcn_prb_template(struct brcms_c_info *wlc, u16 type, + u32 bcn_rspec, + struct brcms_bss_cfg *cfg, u16 *buf, int *len) +{ + static const u8 ether_bcast[ETH_ALEN] = {255, 255, 255, 255, 255, 255}; + struct cck_phy_hdr *plcp; + struct ieee80211_mgmt *h; + int hdr_len, body_len; + + hdr_len = D11_PHY_HDR_LEN + DOT11_MAC_HDR_LEN; + + /* calc buffer size provided for frame body */ + body_len = *len - hdr_len; + /* return actual size */ + *len = hdr_len + body_len; + + /* format PHY and MAC headers */ + memset((char *)buf, 0, hdr_len); + + plcp = (struct cck_phy_hdr *) buf; + + /* + * PLCP for Probe Response frames are filled in from + * core's rate table + */ + if (type == IEEE80211_STYPE_BEACON) + /* fill in PLCP */ + brcms_c_compute_plcp(wlc, bcn_rspec, + (DOT11_MAC_HDR_LEN + body_len + FCS_LEN), + (u8 *) plcp); + + /* "Regular" and 16 MBSS but not for 4 MBSS */ + /* Update the phytxctl for the beacon based on the rspec */ + brcms_c_beacon_phytxctl_txant_upd(wlc, bcn_rspec); + + h = (struct ieee80211_mgmt *)&plcp[1]; + + /* fill in 802.11 header */ + h->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | type); + + /* DUR is 0 for multicast bcn, or filled in by MAC for prb resp */ + /* A1 filled in by MAC for prb resp, broadcast for bcn */ + if (type == IEEE80211_STYPE_BEACON) + memcpy(&h->da, ðer_bcast, ETH_ALEN); + memcpy(&h->sa, &cfg->cur_etheraddr, ETH_ALEN); + memcpy(&h->bssid, &cfg->BSSID, ETH_ALEN); + + /* SEQ filled in by MAC */ +} + +int brcms_c_get_header_len(void) +{ + return TXOFF; +} + +/* + * Update all beacons for the system. + */ +void brcms_c_update_beacon(struct brcms_c_info *wlc) +{ + struct brcms_bss_cfg *bsscfg = wlc->bsscfg; + + if (bsscfg->up && !bsscfg->BSS) + /* Clear the soft intmask */ + wlc->defmacintmask &= ~MI_BCNTPL; +} + +/* Write ssid into shared memory */ +static void +brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg) +{ + u8 *ssidptr = cfg->SSID; + u16 base = M_SSID; + u8 ssidbuf[IEEE80211_MAX_SSID_LEN]; + + /* padding the ssid with zero and copy it into shm */ + memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN); + memcpy(ssidbuf, ssidptr, cfg->SSID_len); + + brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN); + brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len); +} + +static void +brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc, + struct brcms_bss_cfg *cfg, + bool suspend) +{ + u16 prb_resp[BCN_TMPL_LEN / 2]; + int len = BCN_TMPL_LEN; + + /* + * write the probe response to hardware, or save in + * the config structure + */ + + /* create the probe response template */ + brcms_c_bcn_prb_template(wlc, IEEE80211_STYPE_PROBE_RESP, 0, + cfg, prb_resp, &len); + + if (suspend) + brcms_c_suspend_mac_and_wait(wlc); + + /* write the probe response into the template region */ + brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE, + (len + 3) & ~3, prb_resp); + + /* write the length of the probe response frame (+PLCP/-FCS) */ + brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len); + + /* write the SSID and SSID length */ + brcms_c_shm_ssid_upd(wlc, cfg); + + /* + * Write PLCP headers and durations for probe response frames + * at all rates. Use the actual frame length covered by the + * PLCP header for the call to brcms_c_mod_prb_rsp_rate_table() + * by subtracting the PLCP len and adding the FCS. + */ + len += (-D11_PHY_HDR_LEN + FCS_LEN); + brcms_c_mod_prb_rsp_rate_table(wlc, (u16) len); + + if (suspend) + brcms_c_enable_mac(wlc); +} + +void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend) +{ + struct brcms_bss_cfg *bsscfg = wlc->bsscfg; + + /* update AP or IBSS probe responses */ + if (bsscfg->up && !bsscfg->BSS) + brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend); +} + +/* prepares pdu for transmission. returns BCM error codes */ +int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop) +{ + uint fifo; + struct d11txh *txh; + struct ieee80211_hdr *h; + struct scb *scb; + + txh = (struct d11txh *) (pdu->data); + h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); + + /* get the pkt queue info. This was put at brcms_c_sendctl or + * brcms_c_send for PDU */ + fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK; + + scb = NULL; + + *fifop = fifo; + + /* return if insufficient dma resources */ + if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) { + /* Mark precedences related to this FIFO, unsendable */ + /* A fifo is full. Clear precedences related to that FIFO */ + wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]); + return -EBUSY; + } + return 0; +} + +int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, + uint *blocks) +{ + if (fifo >= NFIFO) + return -EINVAL; + + *blocks = wlc_hw->xmtfifo_sz[fifo]; + + return 0; +} + +void +brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset, + const u8 *addr) +{ + brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr); + if (match_reg_offset == RCM_BSSID_OFFSET) + memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN); +} + +/* + * Flag 'scan in progress' to withhold dynamic phy calibration + */ +void brcms_c_scan_start(struct brcms_c_info *wlc) +{ + wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true); +} + +void brcms_c_scan_stop(struct brcms_c_info *wlc) +{ + wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false); +} + +void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state) +{ + wlc->pub->associated = state; + wlc->bsscfg->associated = state; +} + +/* + * When a remote STA/AP is removed by Mac80211, or when it can no longer accept + * AMPDU traffic, packets pending in hardware have to be invalidated so that + * when later on hardware releases them, they can be handled appropriately. + */ +void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, + struct ieee80211_sta *sta, + void (*dma_callback_fn)) +{ + struct dma_pub *dmah; + int i; + for (i = 0; i < NFIFO; i++) { + dmah = hw->di[i]; + if (dmah != NULL) + dma_walk_packets(dmah, dma_callback_fn, sta); + } +} + +int brcms_c_get_curband(struct brcms_c_info *wlc) +{ + return wlc->band->bandunit; +} + +void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop) +{ + /* flush packet queue when requested */ + if (drop) + brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL); + + /* wait for queue and DMA fifos to run dry */ + while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0) + brcms_msleep(wlc->wl, 1); +} + +void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval) +{ + wlc->bcn_li_bcn = interval; + if (wlc->pub->up) + brcms_c_bcn_li_upd(wlc); +} + +int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr) +{ + uint qdbm; + + /* Remove override bit and clip to max qdbm value */ + qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff); + return wlc_phy_txpower_set(wlc->band->pi, qdbm, false); +} + +int brcms_c_get_tx_power(struct brcms_c_info *wlc) +{ + uint qdbm; + bool override; + + wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override); + + /* Return qdbm units */ + return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR); +} + +void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc) +{ + wlc->mpc = mpc; + brcms_c_radio_mpc_upd(wlc); +} + +/* Process received frames */ +/* + * Return true if more frames need to be processed. false otherwise. + * Param 'bound' indicates max. # frames to process before break out. + */ +static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p) +{ + struct d11rxhdr *rxh; + struct ieee80211_hdr *h; + uint len; + bool is_amsdu; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + + /* frame starts with rxhdr */ + rxh = (struct d11rxhdr *) (p->data); + + /* strip off rxhdr */ + skb_pull(p, BRCMS_HWRXOFF); + + /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */ + if (rxh->RxStatus1 & RXS_PBPRES) { + if (p->len < 2) { + wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of " + "len %d\n", wlc->pub->unit, p->len); + goto toss; + } + skb_pull(p, 2); + } + + h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN); + len = p->len; + + if (rxh->RxStatus1 & RXS_FCSERR) { + if (wlc->pub->mac80211_state & MAC80211_PROMISC_BCNS) { + wiphy_err(wlc->wiphy, "FCSERR while scanning******* -" + " tossing\n"); + goto toss; + } else { + wiphy_err(wlc->wiphy, "RCSERR!!!\n"); + goto toss; + } + } + + /* check received pkt has at least frame control field */ + if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control)) + goto toss; + + /* not supporting A-MSDU */ + is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK; + if (is_amsdu) + goto toss; + + brcms_c_recvctl(wlc, rxh, p); + return; + + toss: + brcmu_pkt_buf_free_skb(p); +} + +/* Process received frames */ +/* + * Return true if more frames need to be processed. false otherwise. + * Param 'bound' indicates max. # frames to process before break out. + */ +static bool +brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) +{ + struct sk_buff *p; + struct sk_buff *head = NULL; + struct sk_buff *tail = NULL; + uint n = 0; + uint bound_limit = bound ? RXBND : -1; + + BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); + /* gather received frames */ + while ((p = dma_rx(wlc_hw->di[fifo]))) { + + if (!tail) + head = tail = p; + else { + tail->prev = p; + tail = p; + } + + /* !give others some time to run! */ + if (++n >= bound_limit) + break; + } + + /* post more rbufs */ + dma_rxfill(wlc_hw->di[fifo]); + + /* process each frame */ + while ((p = head) != NULL) { + struct d11rxhdr_le *rxh_le; + struct d11rxhdr *rxh; + head = head->prev; + p->prev = NULL; + + rxh_le = (struct d11rxhdr_le *)p->data; + rxh = (struct d11rxhdr *)p->data; + + /* fixup rx header endianness */ + rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize); + rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0); + rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1); + rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2); + rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3); + rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4); + rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5); + rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1); + rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2); + rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime); + rxh->RxChan = le16_to_cpu(rxh_le->RxChan); + + brcms_c_recv(wlc_hw->wlc, p); + } + + return n >= bound_limit; +} + +/* second-level interrupt processing + * Return true if another dpc needs to be re-scheduled. false otherwise. + * Param 'bounded' indicates if applicable loops should be bounded. + */ +bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) +{ + u32 macintstatus; + struct brcms_hardware *wlc_hw = wlc->hw; + struct d11regs __iomem *regs = wlc_hw->regs; + struct wiphy *wiphy = wlc->wiphy; + + if (brcms_deviceremoved(wlc)) { + wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit, + __func__); + brcms_down(wlc->wl); + return false; + } + + /* grab and clear the saved software intstatus bits */ + macintstatus = wlc->macintstatus; + wlc->macintstatus = 0; + + BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n", + wlc_hw->unit, macintstatus); + + WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */ + + /* tx status */ + if (macintstatus & MI_TFS) { + bool fatal; + if (brcms_b_txstatus(wlc->hw, bounded, &fatal)) + wlc->macintstatus |= MI_TFS; + if (fatal) { + wiphy_err(wiphy, "MI_TFS: fatal\n"); + goto fatal; + } + } + + if (macintstatus & (MI_TBTT | MI_DTIM_TBTT)) + brcms_c_tbtt(wlc); + + /* ATIM window end */ + if (macintstatus & MI_ATIMWINEND) { + BCMMSG(wlc->wiphy, "end of ATIM window\n"); + OR_REG(®s->maccommand, wlc->qvalid); + wlc->qvalid = 0; + } + + /* + * received data or control frame, MI_DMAINT is + * indication of RX_FIFO interrupt + */ + if (macintstatus & MI_DMAINT) + if (brcms_b_recv(wlc_hw, RX_FIFO, bounded)) + wlc->macintstatus |= MI_DMAINT; + + /* noise sample collected */ + if (macintstatus & MI_BG_NOISE) + wlc_phy_noise_sample_intr(wlc_hw->band->pi); + + if (macintstatus & MI_GP0) { + wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d " + "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now); + + printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n", + __func__, wlc_hw->sih->chip, + wlc_hw->sih->chiprev); + /* big hammer */ + brcms_init(wlc->wl); + } + + /* gptimer timeout */ + if (macintstatus & MI_TO) + W_REG(®s->gptimer, 0); + + if (macintstatus & MI_RFDISABLE) { + BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the" + " RF Disable Input\n", wlc_hw->unit); + brcms_rfkill_set_hw_state(wlc->wl); + } + + /* send any enq'd tx packets. Just makes sure to jump start tx */ + if (!pktq_empty(&wlc->pkt_queue->q)) + brcms_c_send_q(wlc); + + /* it isn't done and needs to be resched if macintstatus is non-zero */ + return wlc->macintstatus != 0; + + fatal: + brcms_init(wlc->wl); + return wlc->macintstatus != 0; +} + +void brcms_c_init(struct brcms_c_info *wlc) +{ + struct d11regs __iomem *regs; + u16 chanspec; + bool mute = false; + + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); + + regs = wlc->regs; + + /* + * This will happen if a big-hammer was executed. In + * that case, we want to go back to the channel that + * we were on and not new channel + */ + if (wlc->pub->associated) + chanspec = wlc->home_chanspec; + else + chanspec = brcms_c_init_chanspec(wlc); + + brcms_b_init(wlc->hw, chanspec, mute); + + /* update beacon listen interval */ + brcms_c_bcn_li_upd(wlc); + + /* write ethernet address to core */ + brcms_c_set_mac(wlc->bsscfg); + brcms_c_set_bssid(wlc->bsscfg); + + /* Update tsf_cfprep if associated and up */ + if (wlc->pub->associated && wlc->bsscfg->up) { + u32 bi; + + /* get beacon period and convert to uS */ + bi = wlc->bsscfg->current_bss->beacon_period << 10; + /* + * update since init path would reset + * to default value + */ + W_REG(®s->tsf_cfprep, + (bi << CFPREP_CBI_SHIFT)); + + /* Update maccontrol PM related bits */ + brcms_c_set_ps_ctrl(wlc); + } + + brcms_c_bandinit_ordered(wlc, chanspec); + + /* init probe response timeout */ + brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout); + + /* init max burst txop (framebursting) */ + brcms_b_write_shm(wlc->hw, M_MBURST_TXOP, + (wlc-> + _rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP)); + + /* initialize maximum allowed duty cycle */ + brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true); + brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true); + + /* + * Update some shared memory locations related to + * max AMPDU size allowed to received + */ + brcms_c_ampdu_shm_upd(wlc->ampdu); + + /* band-specific inits */ + brcms_c_bsinit(wlc); + + /* Enable EDCF mode (while the MAC is suspended) */ + OR_REG(®s->ifs_ctl, IFS_USEEDCF); + brcms_c_edcf_setparams(wlc, false); + + /* Init precedence maps for empty FIFOs */ + brcms_c_tx_prec_map_init(wlc); + + /* read the ucode version if we have not yet done so */ + if (wlc->ucode_rev == 0) { + wlc->ucode_rev = + brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR) << NBITS(u16); + wlc->ucode_rev |= brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR); + } + + /* ..now really unleash hell (allow the MAC out of suspend) */ + brcms_c_enable_mac(wlc); + + /* clear tx flow control */ + brcms_c_txflowcontrol_reset(wlc); + + /* enable the RF Disable Delay timer */ + W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT); + + /* initialize mpc delay */ + wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; + + /* + * Initialize WME parameters; if they haven't been set by some other + * mechanism (IOVar, etc) then read them from the hardware. + */ + if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) { + /* Uninitialized; read from HW */ + int ac; + + for (ac = 0; ac < AC_COUNT; ac++) + wlc->wme_retries[ac] = + brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac)); + } +} + +/* + * The common driver entry routine. Error codes should be unique + */ +struct brcms_c_info * +brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, + bool piomode, void __iomem *regsva, struct pci_dev *btparam, + uint *perr) +{ + struct brcms_c_info *wlc; + uint err = 0; + uint i, j; + struct brcms_pub *pub; + + /* allocate struct brcms_c_info state and its substructures */ + wlc = (struct brcms_c_info *) brcms_c_attach_malloc(unit, &err, device); + if (wlc == NULL) + goto fail; + wlc->wiphy = wl->wiphy; + pub = wlc->pub; + +#if defined(BCMDBG) + wlc_info_dbg = wlc; +#endif + + wlc->band = wlc->bandstate[0]; + wlc->core = wlc->corestate; + wlc->wl = wl; + pub->unit = unit; + pub->_piomode = piomode; + wlc->bandinit_pending = false; + + /* populate struct brcms_c_info with default values */ + brcms_c_info_init(wlc, unit); + + /* update sta/ap related parameters */ + brcms_c_ap_upd(wlc); + + /* + * low level attach steps(all hw accesses go + * inside, no more in rest of the attach) + */ + err = brcms_b_attach(wlc, vendor, device, unit, piomode, regsva, + btparam); + if (err) + goto fail; + + brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF); + + pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band); + + /* disable allowed duty cycle */ + wlc->tx_duty_cycle_ofdm = 0; + wlc->tx_duty_cycle_cck = 0; + + brcms_c_stf_phy_chain_calc(wlc); + + /* txchain 1: txant 0, txchain 2: txant 1 */ + if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1)) + wlc->stf->txant = wlc->stf->hw_txchain - 1; + + /* push to BMAC driver */ + wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain, + wlc->stf->hw_rxchain); + + /* pull up some info resulting from the low attach */ + for (i = 0; i < NFIFO; i++) + wlc->core->txavail[i] = wlc->hw->txavail[i]; + + memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN); + memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN); + + for (j = 0; j < wlc->pub->_nbands; j++) { + wlc->band = wlc->bandstate[j]; + + if (!brcms_c_attach_stf_ant_init(wlc)) { + err = 24; + goto fail; + } + + /* default contention windows size limits */ + wlc->band->CWmin = APHY_CWMIN; + wlc->band->CWmax = PHY_CWMAX; + + /* init gmode value */ + if (wlc->band->bandtype == BRCM_BAND_2G) { + wlc->band->gmode = GMODE_AUTO; + brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, + wlc->band->gmode); + } + + /* init _n_enab supported mode */ + if (BRCMS_PHY_11N_CAP(wlc->band)) { + pub->_n_enab = SUPPORT_11N; + brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER, + ((pub->_n_enab == + SUPPORT_11N) ? WL_11N_2x2 : + WL_11N_3x3)); + } + + /* init per-band default rateset, depend on band->gmode */ + brcms_default_rateset(wlc, &wlc->band->defrateset); + + /* fill in hw_rateset */ + brcms_c_rateset_filter(&wlc->band->defrateset, + &wlc->band->hw_rateset, false, + BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK, + (bool) (wlc->pub->_n_enab & SUPPORT_11N)); + } + + /* + * update antenna config due to + * wlc->stf->txant/txchain/ant_rx_ovr change + */ + brcms_c_stf_phy_txant_upd(wlc); + + /* attach each modules */ + err = brcms_c_attach_module(wlc); + if (err != 0) + goto fail; + + if (!brcms_c_timers_init(wlc, unit)) { + wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit, + __func__); + err = 32; + goto fail; + } + + /* depend on rateset, gmode */ + wlc->cmi = brcms_c_channel_mgr_attach(wlc); + if (!wlc->cmi) { + wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed" + "\n", unit, __func__); + err = 33; + goto fail; + } + + /* init default when all parameters are ready, i.e. ->rateset */ + brcms_c_bss_default_init(wlc); + + /* + * Complete the wlc default state initializations.. + */ + + /* allocate our initial queue */ + wlc->pkt_queue = brcms_c_txq_alloc(wlc); + if (wlc->pkt_queue == NULL) { + wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n", + unit, __func__); + err = 100; + goto fail; + } + + wlc->bsscfg->wlc = wlc; + + wlc->mimoft = FT_HT; + wlc->mimo_40txbw = AUTO; + wlc->ofdm_40txbw = AUTO; + wlc->cck_40txbw = AUTO; + brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G); + + /* Set default values of SGI */ + if (BRCMS_SGI_CAP_PHY(wlc)) { + brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 | + BRCMS_N_SGI_40)); + } else if (BRCMS_ISSSLPNPHY(wlc->band)) { + brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 | + BRCMS_N_SGI_40)); + } else { + brcms_c_ht_update_sgi_rx(wlc, 0); + } + + /* initialize radio_mpc_disable according to wlc->mpc */ + brcms_c_radio_mpc_upd(wlc); + brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail); + + if (perr) + *perr = 0; + + return wlc; + + fail: + wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n", + unit, __func__, err); + if (wlc) + brcms_c_detach(wlc); + + if (perr) + *perr = err; + return NULL; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h new file mode 100644 index 000000000000..c0e0fcfdfaf8 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h @@ -0,0 +1,735 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_MAIN_H_ +#define _BRCM_MAIN_H_ + +#include <linux/etherdevice.h> + +#include <brcmu_utils.h> +#include "types.h" +#include "d11.h" +#include "scb.h" + +#define INVCHANNEL 255 /* invalid channel */ + +/* max # brcms_c_module_register() calls */ +#define BRCMS_MAXMODULES 22 + +#define SEQNUM_SHIFT 4 +#define SEQNUM_MAX 0x1000 + +#define NTXRATE 64 /* # tx MPDUs rate is reported for */ + +/* Maximum wait time for a MAC suspend */ +/* uS: 83mS is max packet time (64KB ampdu @ 6Mbps) */ +#define BRCMS_MAX_MAC_SUSPEND 83000 + +/* responses for probe requests older that this are tossed, zero to disable */ +#define BRCMS_PRB_RESP_TIMEOUT 0 /* Disable probe response timeout */ + +/* transmit buffer max headroom for protocol headers */ +#define TXOFF (D11_TXH_LEN + D11_PHY_HDR_LEN) + +#define AC_COUNT 4 + +/* Macros for doing definition and get/set of bitfields + * Usage example, e.g. a three-bit field (bits 4-6): + * #define <NAME>_M BITFIELD_MASK(3) + * #define <NAME>_S 4 + * ... + * regval = R_REG(osh, ®s->regfoo); + * field = GFIELD(regval, <NAME>); + * regval = SFIELD(regval, <NAME>, 1); + * W_REG(osh, ®s->regfoo, regval); + */ +#define BITFIELD_MASK(width) \ + (((unsigned)1 << (width)) - 1) +#define GFIELD(val, field) \ + (((val) >> field ## _S) & field ## _M) +#define SFIELD(val, field, bits) \ + (((val) & (~(field ## _M << field ## _S))) | \ + ((unsigned)(bits) << field ## _S)) + +#define SW_TIMER_MAC_STAT_UPD 30 /* periodic MAC stats update */ + +/* max # supported core revisions (0 .. MAXCOREREV - 1) */ +#define MAXCOREREV 28 + +/* Double check that unsupported cores are not enabled */ +#if CONF_MSK(D11CONF, 0x4f) || CONF_GE(D11CONF, MAXCOREREV) +#error "Configuration for D11CONF includes unsupported versions." +#endif /* Bad versions */ + +/* values for shortslot_override */ +#define BRCMS_SHORTSLOT_AUTO -1 /* Driver will manage Shortslot setting */ +#define BRCMS_SHORTSLOT_OFF 0 /* Turn off short slot */ +#define BRCMS_SHORTSLOT_ON 1 /* Turn on short slot */ + +/* value for short/long and mixmode/greenfield preamble */ +#define BRCMS_LONG_PREAMBLE (0) +#define BRCMS_SHORT_PREAMBLE (1 << 0) +#define BRCMS_GF_PREAMBLE (1 << 1) +#define BRCMS_MM_PREAMBLE (1 << 2) +#define BRCMS_IS_MIMO_PREAMBLE(_pre) (((_pre) == BRCMS_GF_PREAMBLE) || \ + ((_pre) == BRCMS_MM_PREAMBLE)) + +/* TxFrameID */ +/* seq and frag bits: SEQNUM_SHIFT, FRAGNUM_MASK (802.11.h) */ +/* rate epoch bits: TXFID_RATE_SHIFT, TXFID_RATE_MASK ((wlc_rate.c) */ +#define TXFID_QUEUE_MASK 0x0007 /* Bits 0-2 */ +#define TXFID_SEQ_MASK 0x7FE0 /* Bits 5-15 */ +#define TXFID_SEQ_SHIFT 5 /* Number of bit shifts */ +#define TXFID_RATE_PROBE_MASK 0x8000 /* Bit 15 for rate probe */ +#define TXFID_RATE_MASK 0x0018 /* Mask for bits 3 and 4 */ +#define TXFID_RATE_SHIFT 3 /* Shift 3 bits for rate mask */ + +/* promote boardrev */ +#define BOARDREV_PROMOTABLE 0xFF /* from */ +#define BOARDREV_PROMOTED 1 /* to */ + +#define DATA_BLOCK_TX_SUPR (1 << 4) + +/* 802.1D Priority to TX FIFO number for wme */ +extern const u8 prio2fifo[]; + +/* Ucode MCTL_WAKE override bits */ +#define BRCMS_WAKE_OVERRIDE_CLKCTL 0x01 +#define BRCMS_WAKE_OVERRIDE_PHYREG 0x02 +#define BRCMS_WAKE_OVERRIDE_MACSUSPEND 0x04 +#define BRCMS_WAKE_OVERRIDE_TXFIFO 0x08 +#define BRCMS_WAKE_OVERRIDE_FORCEFAST 0x10 + +/* stuff pulled in from wlc.c */ + +/* Interrupt bit error summary. Don't include I_RU: we refill DMA at other + * times; and if we run out, constant I_RU interrupts may cause lockup. We + * will still get error counts from rx0ovfl. + */ +#define I_ERRORS (I_PC | I_PD | I_DE | I_RO | I_XU) +/* default software intmasks */ +#define DEF_RXINTMASK (I_RI) /* enable rx int on rxfifo only */ +#define DEF_MACINTMASK (MI_TXSTOP | MI_TBTT | MI_ATIMWINEND | MI_PMQ | \ + MI_PHYTXERR | MI_DMAINT | MI_TFS | MI_BG_NOISE | \ + MI_CCA | MI_TO | MI_GP0 | MI_RFDISABLE | MI_PWRUP) + +#define MAXTXPKTS 6 /* max # pkts pending */ + +/* frameburst */ +#define MAXTXFRAMEBURST 8 /* vanilla xpress mode: max frames/burst */ +#define MAXFRAMEBURST_TXOP 10000 /* Frameburst TXOP in usec */ + +#define NFIFO 6 /* # tx/rx fifopairs */ + +/* PLL requests */ + +/* pll is shared on old chips */ +#define BRCMS_PLLREQ_SHARED 0x1 +/* hold pll for radio monitor register checking */ +#define BRCMS_PLLREQ_RADIO_MON 0x2 +/* hold/release pll for some short operation */ +#define BRCMS_PLLREQ_FLIP 0x4 + +#define CHANNEL_BANDUNIT(wlc, ch) \ + (((ch) <= CH_MAX_2G_CHANNEL) ? BAND_2G_INDEX : BAND_5G_INDEX) + +#define OTHERBANDUNIT(wlc) \ + ((uint)((wlc)->band->bandunit ? BAND_2G_INDEX : BAND_5G_INDEX)) + +/* + * 802.11 protection information + * + * _g: use g spec protection, driver internal. + * g_override: override for use of g spec protection. + * gmode_user: user config gmode, operating band->gmode is different. + * overlap: Overlap BSS/IBSS protection for both 11g and 11n. + * nmode_user: user config nmode, operating pub->nmode is different. + * n_cfg: use OFDM protection on MIMO frames. + * n_cfg_override: override for use of N protection. + * nongf: non-GF present protection. + * nongf_override: override for use of GF protection. + * n_pam_override: override for preamble: MM or GF. + * n_obss: indicated OBSS Non-HT STA present. +*/ +struct brcms_protection { + bool _g; + s8 g_override; + u8 gmode_user; + s8 overlap; + s8 nmode_user; + s8 n_cfg; + s8 n_cfg_override; + bool nongf; + s8 nongf_override; + s8 n_pam_override; + bool n_obss; +}; + +/* + * anything affecting the single/dual streams/antenna operation + * + * hw_txchain: HW txchain bitmap cfg. + * txchain: txchain bitmap being used. + * txstreams: number of txchains being used. + * hw_rxchain: HW rxchain bitmap cfg. + * rxchain: rxchain bitmap being used. + * rxstreams: number of rxchains being used. + * ant_rx_ovr: rx antenna override. + * txant: userTx antenna setting. + * phytxant: phyTx antenna setting in txheader. + * ss_opmode: singlestream Operational mode, 0:siso; 1:cdd. + * ss_algosel_auto: if true, use wlc->stf->ss_algo_channel; + * else use wlc->band->stf->ss_mode_band. + * ss_algo_channel: ss based on per-channel algo: 0: SISO, 1: CDD 2: STBC. + * rxchain_restore_delay: delay time to restore default rxchain. + * ldpc: AUTO/ON/OFF ldpc cap supported. + * txcore[MAX_STREAMS_SUPPORTED + 1]: bitmap of selected core for each Nsts. + * spatial_policy: + */ +struct brcms_stf { + u8 hw_txchain; + u8 txchain; + u8 txstreams; + u8 hw_rxchain; + u8 rxchain; + u8 rxstreams; + u8 ant_rx_ovr; + s8 txant; + u16 phytxant; + u8 ss_opmode; + bool ss_algosel_auto; + u16 ss_algo_channel; + u8 rxchain_restore_delay; + s8 ldpc; + u8 txcore[MAX_STREAMS_SUPPORTED + 1]; + s8 spatial_policy; +}; + +#define BRCMS_STF_SS_STBC_TX(wlc, scb) \ + (((wlc)->stf->txstreams > 1) && (((wlc)->band->band_stf_stbc_tx == ON) \ + || (((scb)->flags & SCB_STBCCAP) && \ + (wlc)->band->band_stf_stbc_tx == AUTO && \ + isset(&((wlc)->stf->ss_algo_channel), PHY_TXC1_MODE_STBC)))) + +#define BRCMS_STBC_CAP_PHY(wlc) (BRCMS_ISNPHY(wlc->band) && \ + NREV_GE(wlc->band->phyrev, 3)) + +#define BRCMS_SGI_CAP_PHY(wlc) ((BRCMS_ISNPHY(wlc->band) && \ + NREV_GE(wlc->band->phyrev, 3)) || \ + BRCMS_ISLCNPHY(wlc->band)) + +#define BRCMS_CHAN_PHYTYPE(x) (((x) & RXS_CHAN_PHYTYPE_MASK) \ + >> RXS_CHAN_PHYTYPE_SHIFT) +#define BRCMS_CHAN_CHANNEL(x) (((x) & RXS_CHAN_ID_MASK) \ + >> RXS_CHAN_ID_SHIFT) + +/* + * core state (mac) + */ +struct brcms_core { + uint coreidx; /* # sb enumerated core */ + + /* fifo */ + uint *txavail[NFIFO]; /* # tx descriptors available */ + s16 txpktpend[NFIFO]; /* tx admission control */ + + struct macstat *macstat_snapshot; /* mac hw prev read values */ +}; + +/* + * band state (phy+ana+radio) + */ +struct brcms_band { + int bandtype; /* BRCM_BAND_2G, BRCM_BAND_5G */ + uint bandunit; /* bandstate[] index */ + + u16 phytype; /* phytype */ + u16 phyrev; + u16 radioid; + u16 radiorev; + struct brcms_phy_pub *pi; /* pointer to phy specific information */ + bool abgphy_encore; + + u8 gmode; /* currently active gmode */ + + struct scb *hwrs_scb; /* permanent scb for hw rateset */ + + /* band-specific copy of default_bss.rateset */ + struct brcms_c_rateset defrateset; + + u8 band_stf_ss_mode; /* Configured STF type, 0:siso; 1:cdd */ + s8 band_stf_stbc_tx; /* STBC TX 0:off; 1:force on; -1:auto */ + /* rates supported by chip (phy-specific) */ + struct brcms_c_rateset hw_rateset; + u8 basic_rate[BRCM_MAXRATE + 1]; /* basic rates indexed by rate */ + bool mimo_cap_40; /* 40 MHz cap enabled on this band */ + s8 antgain; /* antenna gain from srom */ + + u16 CWmin; /* minimum size of contention window, in unit of aSlotTime */ + u16 CWmax; /* maximum size of contention window, in unit of aSlotTime */ + struct ieee80211_supported_band band; +}; + +/* module control blocks */ +struct modulecb { + /* module name : NULL indicates empty array member */ + char name[32]; + /* handle passed when handler 'doiovar' is called */ + struct brcms_info *hdl; + + int (*down_fn)(void *handle); /* down handler. Note: the int returned + * by the down function is a count of the + * number of timers that could not be + * freed. + */ + +}; + +struct brcms_hw_band { + int bandtype; /* BRCM_BAND_2G, BRCM_BAND_5G */ + uint bandunit; /* bandstate[] index */ + u16 mhfs[MHFMAX]; /* MHF array shadow */ + u8 bandhw_stf_ss_mode; /* HW configured STF type, 0:siso; 1:cdd */ + u16 CWmin; + u16 CWmax; + u32 core_flags; + + u16 phytype; /* phytype */ + u16 phyrev; + u16 radioid; + u16 radiorev; + struct brcms_phy_pub *pi; /* pointer to phy specific information */ + bool abgphy_encore; +}; + +struct brcms_hardware { + bool _piomode; /* true if pio mode */ + struct brcms_c_info *wlc; + + /* fifo */ + struct dma_pub *di[NFIFO]; /* dma handles, per fifo */ + + uint unit; /* device instance number */ + + /* version info */ + u16 vendorid; /* PCI vendor id */ + u16 deviceid; /* PCI device id */ + uint corerev; /* core revision */ + u8 sromrev; /* version # of the srom */ + u16 boardrev; /* version # of particular board */ + u32 boardflags; /* Board specific flags from srom */ + u32 boardflags2; /* More board flags if sromrev >= 4 */ + u32 machwcap; /* MAC capabilities */ + u32 machwcap_backup; /* backup of machwcap */ + + struct si_pub *sih; /* SI handle (cookie for siutils calls) */ + struct d11regs __iomem *regs; /* pointer to device registers */ + struct phy_shim_info *physhim; /* phy shim layer handler */ + struct shared_phy *phy_sh; /* pointer to shared phy state */ + struct brcms_hw_band *band;/* pointer to active per-band state */ + /* band state per phy/radio */ + struct brcms_hw_band *bandstate[MAXBANDS]; + u16 bmac_phytxant; /* cache of high phytxant state */ + bool shortslot; /* currently using 11g ShortSlot timing */ + u16 SRL; /* 802.11 dot11ShortRetryLimit */ + u16 LRL; /* 802.11 dot11LongRetryLimit */ + u16 SFBL; /* Short Frame Rate Fallback Limit */ + u16 LFBL; /* Long Frame Rate Fallback Limit */ + + bool up; /* d11 hardware up and running */ + uint now; /* # elapsed seconds */ + uint _nbands; /* # bands supported */ + u16 chanspec; /* bmac chanspec shadow */ + + uint *txavail[NFIFO]; /* # tx descriptors available */ + const u16 *xmtfifo_sz; /* fifo size in 256B for each xmt fifo */ + + u32 pllreq; /* pll requests to keep PLL on */ + + u8 suspended_fifos; /* Which TX fifo to remain awake for */ + u32 maccontrol; /* Cached value of maccontrol */ + uint mac_suspend_depth; /* current depth of mac_suspend levels */ + u32 wake_override; /* bit flags to force MAC to WAKE mode */ + u32 mute_override; /* Prevent ucode from sending beacons */ + u8 etheraddr[ETH_ALEN]; /* currently configured ethernet address */ + bool noreset; /* true= do not reset hw, used by WLC_OUT */ + bool forcefastclk; /* true if h/w is forcing to use fast clk */ + bool clk; /* core is out of reset and has clock */ + bool sbclk; /* sb has clock */ + bool phyclk; /* phy is out of reset and has clock */ + + bool ucode_loaded; /* true after ucode downloaded */ + + + u8 hw_stf_ss_opmode; /* STF single stream operation mode */ + u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic + * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board + */ + u32 antsel_avail; /* + * put struct antsel_info here if more info is + * needed + */ +}; + +/* TX Queue information + * + * Each flow of traffic out of the device has a TX Queue with independent + * flow control. Several interfaces may be associated with a single TX Queue + * if they belong to the same flow of traffic from the device. For multi-channel + * operation there are independent TX Queues for each channel. + */ +struct brcms_txq_info { + struct brcms_txq_info *next; + struct pktq q; + uint stopped; /* tx flow control bits */ +}; + +/* + * Principal common driver data structure. + * + * pub: pointer to driver public state. + * wl: pointer to specific private state. + * regs: pointer to device registers. + * hw: HW related state. + * clkreq_override: setting for clkreq for PCIE : Auto, 0, 1. + * fastpwrup_dly: time in us needed to bring up d11 fast clock. + * macintstatus: bit channel between isr and dpc. + * macintmask: sw runtime master macintmask value. + * defmacintmask: default "on" macintmask value. + * clk: core is out of reset and has clock. + * core: pointer to active io core. + * band: pointer to active per-band state. + * corestate: per-core state (one per hw core). + * bandstate: per-band state (one per phy/radio). + * qvalid: DirFrmQValid and BcMcFrmQValid. + * ampdu: ampdu module handler. + * asi: antsel module handler. + * cmi: channel manager module handler. + * vendorid: PCI vendor id. + * deviceid: PCI device id. + * ucode_rev: microcode revision. + * machwcap: MAC capabilities, BMAC shadow. + * perm_etheraddr: original sprom local ethernet address. + * bandlocked: disable auto multi-band switching. + * bandinit_pending: track band init in auto band. + * radio_monitor: radio timer is running. + * going_down: down path intermediate variable. + * mpc: enable minimum power consumption. + * mpc_dlycnt: # of watchdog cnt before turn disable radio. + * mpc_offcnt: # of watchdog cnt that radio is disabled. + * mpc_delay_off: delay radio disable by # of watchdog cnt. + * prev_non_delay_mpc: prev state brcms_c_is_non_delay_mpc. + * wdtimer: timer for watchdog routine. + * radio_timer: timer for hw radio button monitor routine. + * monitor: monitor (MPDU sniffing) mode. + * bcnmisc_monitor: bcns promisc mode override for monitor. + * _rifs: enable per-packet rifs. + * bcn_li_bcn: beacon listen interval in # beacons. + * bcn_li_dtim: beacon listen interval in # dtims. + * WDarmed: watchdog timer is armed. + * WDlast: last time wlc_watchdog() was called. + * edcf_txop[AC_COUNT]: current txop for each ac. + * wme_retries: per-AC retry limits. + * tx_prec_map: Precedence map based on HW FIFO space. + * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME. + * bsscfg: set of BSS configurations, idx 0 is default and always valid. + * cfg: the primary bsscfg (can be AP or STA). + * tx_queues: common TX Queue list. + * modulecb: + * mimoft: SIGN or 11N. + * cck_40txbw: 11N, cck tx b/w override when in 40MHZ mode. + * ofdm_40txbw: 11N, ofdm tx b/w override when in 40MHZ mode. + * mimo_40txbw: 11N, mimo tx b/w override when in 40MHZ mode. + * default_bss: configured BSS parameters. + * mc_fid_counter: BC/MC FIFO frame ID counter. + * country_default: saved country for leaving 802.11d auto-country mode. + * autocountry_default: initial country for 802.11d auto-country mode. + * prb_resp_timeout: do not send prb resp if request older + * than this, 0 = disable. + * home_chanspec: shared home chanspec. + * chanspec: target operational channel. + * usr_fragthresh: user configured fragmentation threshold. + * fragthresh[NFIFO]: per-fifo fragmentation thresholds. + * RTSThresh: 802.11 dot11RTSThreshold. + * SRL: 802.11 dot11ShortRetryLimit. + * LRL: 802.11 dot11LongRetryLimit. + * SFBL: Short Frame Rate Fallback Limit. + * LFBL: Long Frame Rate Fallback Limit. + * shortslot: currently using 11g ShortSlot timing. + * shortslot_override: 11g ShortSlot override. + * include_legacy_erp: include Legacy ERP info elt ID 47 as well as g ID 42. + * PLCPHdr_override: 802.11b Preamble Type override. + * stf: + * bcn_rspec: save bcn ratespec purpose. + * tempsense_lasttime; + * tx_duty_cycle_ofdm: maximum allowed duty cycle for OFDM. + * tx_duty_cycle_cck: maximum allowed duty cycle for CCK. + * pkt_queue: txq for transmit packets. + * wiphy: + * pri_scb: primary Station Control Block + */ +struct brcms_c_info { + struct brcms_pub *pub; + struct brcms_info *wl; + struct d11regs __iomem *regs; + struct brcms_hardware *hw; + + /* clock */ + u16 fastpwrup_dly; + + /* interrupt */ + u32 macintstatus; + u32 macintmask; + u32 defmacintmask; + + bool clk; + + /* multiband */ + struct brcms_core *core; + struct brcms_band *band; + struct brcms_core *corestate; + struct brcms_band *bandstate[MAXBANDS]; + + /* packet queue */ + uint qvalid; + + struct ampdu_info *ampdu; + struct antsel_info *asi; + struct brcms_cm_info *cmi; + + u16 vendorid; + u16 deviceid; + uint ucode_rev; + + u8 perm_etheraddr[ETH_ALEN]; + + bool bandlocked; + bool bandinit_pending; + + bool radio_monitor; + bool going_down; + + bool mpc; + u8 mpc_dlycnt; + u8 mpc_offcnt; + u8 mpc_delay_off; + u8 prev_non_delay_mpc; + + struct brcms_timer *wdtimer; + struct brcms_timer *radio_timer; + + /* promiscuous */ + bool monitor; + bool bcnmisc_monitor; + + /* driver feature */ + bool _rifs; + + /* AP-STA synchronization, power save */ + u8 bcn_li_bcn; + u8 bcn_li_dtim; + + bool WDarmed; + u32 WDlast; + + /* WME */ + u16 edcf_txop[AC_COUNT]; + + u16 wme_retries[AC_COUNT]; + u16 tx_prec_map; + u16 fifo2prec_map[NFIFO]; + + struct brcms_bss_cfg *bsscfg; + + /* tx queue */ + struct brcms_txq_info *tx_queues; + + struct modulecb *modulecb; + + u8 mimoft; + s8 cck_40txbw; + s8 ofdm_40txbw; + s8 mimo_40txbw; + + struct brcms_bss_info *default_bss; + + u16 mc_fid_counter; + + char country_default[BRCM_CNTRY_BUF_SZ]; + char autocountry_default[BRCM_CNTRY_BUF_SZ]; + u16 prb_resp_timeout; + + u16 home_chanspec; + + /* PHY parameters */ + u16 chanspec; + u16 usr_fragthresh; + u16 fragthresh[NFIFO]; + u16 RTSThresh; + u16 SRL; + u16 LRL; + u16 SFBL; + u16 LFBL; + + /* network config */ + bool shortslot; + s8 shortslot_override; + bool include_legacy_erp; + + struct brcms_protection *protection; + s8 PLCPHdr_override; + + struct brcms_stf *stf; + + u32 bcn_rspec; + + uint tempsense_lasttime; + + u16 tx_duty_cycle_ofdm; + u16 tx_duty_cycle_cck; + + struct brcms_txq_info *pkt_queue; + struct wiphy *wiphy; + struct scb pri_scb; +}; + +/* antsel module specific state */ +struct antsel_info { + struct brcms_c_info *wlc; /* pointer to main wlc structure */ + struct brcms_pub *pub; /* pointer to public fn */ + u8 antsel_type; /* Type of boardlevel mimo antenna switch-logic + * 0 = N/A, 1 = 2x4 board, 2 = 2x3 CB2 board + */ + u8 antsel_antswitch; /* board level antenna switch type */ + bool antsel_avail; /* Ant selection availability (SROM based) */ + struct brcms_antselcfg antcfg_11n; /* antenna configuration */ + struct brcms_antselcfg antcfg_cur; /* current antenna config (auto) */ +}; + +/* + * BSS configuration state + * + * wlc: wlc to which this bsscfg belongs to. + * up: is this configuration up operational + * enable: is this configuration enabled + * associated: is BSS in ASSOCIATED state + * BSS: infraustructure or adhoc + * SSID_len: the length of SSID + * SSID: SSID string + * + * + * BSSID: BSSID (associated) + * cur_etheraddr: h/w address + * flags: BSSCFG flags; see below + * + * current_bss: BSS parms in ASSOCIATED state + * + * + * ID: 'unique' ID of this bsscfg, assigned at bsscfg allocation + */ +struct brcms_bss_cfg { + struct brcms_c_info *wlc; + bool up; + bool enable; + bool associated; + bool BSS; + u8 SSID_len; + u8 SSID[IEEE80211_MAX_SSID_LEN]; + u8 BSSID[ETH_ALEN]; + u8 cur_etheraddr[ETH_ALEN]; + struct brcms_bss_info *current_bss; +}; + +extern void brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, + struct sk_buff *p, + bool commit, s8 txpktpend); +extern void brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, + s8 txpktpend); +extern void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb, + struct sk_buff *sdu, uint prec); +extern void brcms_c_print_txstatus(struct tx_status *txs); +extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo, + uint *blocks); + +#if defined(BCMDBG) +extern void brcms_c_print_txdesc(struct d11txh *txh); +#else +#define brcms_c_print_txdesc(a) +#endif + +extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config); +extern void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, + bool promisc); +extern void brcms_c_send_q(struct brcms_c_info *wlc); +extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, + uint *fifo); +extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec, + uint mac_len); +extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, + u32 rspec, + bool use_rspec, u16 mimo_ctlchbw); +extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only, + u32 rts_rate, + u32 frame_rate, + u8 rts_preamble_type, + u8 frame_preamble_type, uint frame_len, + bool ba); +extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, + struct ieee80211_sta *sta, + void (*dma_callback_fn)); +extern void brcms_c_update_beacon(struct brcms_c_info *wlc); +extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend); +extern int brcms_c_set_nmode(struct brcms_c_info *wlc); +extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, + u32 bcn_rate); +extern void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, + u8 antsel_type); +extern void brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, + u16 chanspec, + bool mute, struct txpwr_limits *txpwr); +extern void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, + u16 v); +extern u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset); +extern void brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, + u16 val, int bands); +extern void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags); +extern void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val); +extern void brcms_b_phy_reset(struct brcms_hardware *wlc_hw); +extern void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw); +extern void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw); +extern void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw, + u32 override_bit); +extern void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw, + u32 override_bit); +extern void brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, + int offset, int len, void *buf); +extern u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate); +extern void brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, + uint offset, const void *buf, int len, + u32 sel); +extern void brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, + void *buf, int len, u32 sel); +extern void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode); +extern u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw); +extern void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk); +extern void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk); +extern void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on); +extern void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant); +extern void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, + u8 stf_mode); +extern void brcms_c_init_scb(struct scb *scb); + +#endif /* _BRCM_MAIN_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c new file mode 100644 index 000000000000..0bcb26792046 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c @@ -0,0 +1,835 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/delay.h> +#include <linux/pci.h> + +#include <defs.h> +#include <soc.h> +#include <chipcommon.h> +#include "aiutils.h" +#include "pub.h" +#include "nicpci.h" + +/* SPROM offsets */ +#define SRSH_ASPM_OFFSET 4 /* word 4 */ +#define SRSH_ASPM_ENB 0x18 /* bit 3, 4 */ +#define SRSH_ASPM_L1_ENB 0x10 /* bit 4 */ +#define SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */ + +#define SRSH_PCIE_MISC_CONFIG 5 /* word 5 */ +#define SRSH_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */ +#define SRSH_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */ +#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */ +#define SRSH_BD_OFFSET 6 /* word 6 */ + +/* chipcontrol */ +#define CHIPCTRL_4321_PLL_DOWN 0x800000/* serdes PLL down override */ + +/* MDIO control */ +#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */ +#define MDIOCTL_DIVISOR_VAL 0x2 +#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */ +#define MDIOCTL_ACCESS_DONE 0x100 /* Transaction complete */ + +/* MDIO Data */ +#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */ +#define MDIODATA_TA 0x00020000 /* Turnaround */ + +#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */ +#define MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */ +#define MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */ +#define MDIODATA_DEVADDR_MASK 0x0f800000 + /* Physmedia devaddr Mask */ + +/* MDIO Data for older revisions < 10 */ +#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift */ +#define MDIODATA_REGADDR_MASK_OLD 0x003c0000 + /* Regaddr Mask */ +#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift */ +#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000 + /* Physmedia devaddr Mask */ + +/* Transactions flags */ +#define MDIODATA_WRITE 0x10000000 +#define MDIODATA_READ 0x20000000 +#define MDIODATA_START 0x40000000 + +#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */ +#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */ + +/* serdes regs (rev < 10) */ +#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */ +#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */ +#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */ + +/* SERDES RX registers */ +#define SERDES_RX_CTRL 1 /* Rx cntrl */ +#define SERDES_RX_TIMER1 2 /* Rx Timer1 */ +#define SERDES_RX_CDR 6 /* CDR */ +#define SERDES_RX_CDRBW 7 /* CDR BW */ +/* SERDES RX control register */ +#define SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */ +#define SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */ + +/* SERDES PLL registers */ +#define SERDES_PLL_CTRL 1 /* PLL control reg */ +#define PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */ + +/* Linkcontrol reg offset in PCIE Cap */ +#define PCIE_CAP_LINKCTRL_OFFSET 16 /* offset in pcie cap */ +#define PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */ +#define PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */ +#define PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */ + +#define PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */ +#define PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */ +#define PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */ +#define PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */ + +/* Power management threshold */ +#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */ +#define PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */ +#define PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */ +#define PCIE_ASPMTIMER_EXTEND 0x01000000 + /* > rev7: + * enable extend ASPM timer + */ + +/* different register spaces to access thru pcie indirect access */ +#define PCIE_CONFIGREGS 1 /* Access to config space */ +#define PCIE_PCIEREGS 2 /* Access to pcie registers */ + +/* PCIE protocol PHY diagnostic registers */ +#define PCIE_PLP_STATUSREG 0x204 /* Status */ + +/* Status reg PCIE_PLP_STATUSREG */ +#define PCIE_PLP_POLARITYINV_STAT 0x10 + +/* PCIE protocol DLLP diagnostic registers */ +#define PCIE_DLLP_LCREG 0x100 /* Link Control */ +#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ + +/* PCIE protocol TLP diagnostic registers */ +#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */ + +/* Sonics to PCI translation types */ +#define SBTOPCI_PREF 0x4 /* prefetch enable */ +#define SBTOPCI_BURST 0x8 /* burst enable */ +#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */ + +#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */ + +/* PCI core index in SROM shadow area */ +#define SRSH_PI_OFFSET 0 /* first word */ +#define SRSH_PI_MASK 0xf000 /* bit 15:12 */ +#define SRSH_PI_SHIFT 12 /* bit 15:12 */ + +/* Sonics side: PCI core and host control registers */ +struct sbpciregs { + u32 control; /* PCI control */ + u32 PAD[3]; + u32 arbcontrol; /* PCI arbiter control */ + u32 clkrun; /* Clkrun Control (>=rev11) */ + u32 PAD[2]; + u32 intstatus; /* Interrupt status */ + u32 intmask; /* Interrupt mask */ + u32 sbtopcimailbox; /* Sonics to PCI mailbox */ + u32 PAD[9]; + u32 bcastaddr; /* Sonics broadcast address */ + u32 bcastdata; /* Sonics broadcast data */ + u32 PAD[2]; + u32 gpioin; /* ro: gpio input (>=rev2) */ + u32 gpioout; /* rw: gpio output (>=rev2) */ + u32 gpioouten; /* rw: gpio output enable (>= rev2) */ + u32 gpiocontrol; /* rw: gpio control (>= rev2) */ + u32 PAD[36]; + u32 sbtopci0; /* Sonics to PCI translation 0 */ + u32 sbtopci1; /* Sonics to PCI translation 1 */ + u32 sbtopci2; /* Sonics to PCI translation 2 */ + u32 PAD[189]; + u32 pcicfg[4][64]; /* 0x400 - 0x7FF, PCI Cfg Space (>=rev8) */ + u16 sprom[36]; /* SPROM shadow Area */ + u32 PAD[46]; +}; + +/* SB side: PCIE core and host control registers */ +struct sbpcieregs { + u32 control; /* host mode only */ + u32 PAD[2]; + u32 biststatus; /* bist Status: 0x00C */ + u32 gpiosel; /* PCIE gpio sel: 0x010 */ + u32 gpioouten; /* PCIE gpio outen: 0x14 */ + u32 PAD[2]; + u32 intstatus; /* Interrupt status: 0x20 */ + u32 intmask; /* Interrupt mask: 0x24 */ + u32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */ + u32 PAD[53]; + u32 sbtopcie0; /* sb to pcie translation 0: 0x100 */ + u32 sbtopcie1; /* sb to pcie translation 1: 0x104 */ + u32 sbtopcie2; /* sb to pcie translation 2: 0x108 */ + u32 PAD[5]; + + /* pcie core supports in direct access to config space */ + u32 configaddr; /* pcie config space access: Address field: 0x120 */ + u32 configdata; /* pcie config space access: Data field: 0x124 */ + + /* mdio access to serdes */ + u32 mdiocontrol; /* controls the mdio access: 0x128 */ + u32 mdiodata; /* Data to the mdio access: 0x12c */ + + /* pcie protocol phy/dllp/tlp register indirect access mechanism */ + u32 pcieindaddr; /* indirect access to + * the internal register: 0x130 + */ + u32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */ + + u32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */ + u32 PAD[177]; + u32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */ + u16 sprom[64]; /* SPROM shadow Area */ +}; + +struct pcicore_info { + union { + struct sbpcieregs __iomem *pcieregs; + struct sbpciregs __iomem *pciregs; + } regs; /* Memory mapped register to the core */ + + struct si_pub *sih; /* System interconnect handle */ + struct pci_dev *dev; + u8 pciecap_lcreg_offset;/* PCIE capability LCreg offset + * in the config space + */ + bool pcie_pr42767; + u8 pcie_polarity; + u8 pcie_war_aspm_ovr; /* Override ASPM/Clkreq settings */ + + u8 pmecap_offset; /* PM Capability offset in the config space */ + bool pmecap; /* Capable of generating PME */ +}; + +#define PCIE_ASPM(sih) \ + (((sih)->buscoretype == PCIE_CORE_ID) && \ + (((sih)->buscorerev >= 3) && \ + ((sih)->buscorerev <= 5))) + + +/* delay needed between the mdio control/ mdiodata register data access */ +static void pr28829_delay(void) +{ + udelay(10); +} + +/* Initialize the PCI core. + * It's caller's responsibility to make sure that this is done only once + */ +struct pcicore_info *pcicore_init(struct si_pub *sih, struct pci_dev *pdev, + void __iomem *regs) +{ + struct pcicore_info *pi; + + /* alloc struct pcicore_info */ + pi = kzalloc(sizeof(struct pcicore_info), GFP_ATOMIC); + if (pi == NULL) + return NULL; + + pi->sih = sih; + pi->dev = pdev; + + if (sih->buscoretype == PCIE_CORE_ID) { + u8 cap_ptr; + pi->regs.pcieregs = regs; + cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP, + NULL, NULL); + pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET; + } else + pi->regs.pciregs = regs; + + return pi; +} + +void pcicore_deinit(struct pcicore_info *pch) +{ + kfree(pch); +} + +/* return cap_offset if requested capability exists in the PCI config space */ +/* Note that it's caller's responsibility to make sure it's a pci bus */ +u8 +pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id, + unsigned char *buf, u32 *buflen) +{ + u8 cap_id; + u8 cap_ptr = 0; + u32 bufsize; + u8 byte_val; + + /* check for Header type 0 */ + pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte_val); + if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL) + goto end; + + /* check if the capability pointer field exists */ + pci_read_config_byte(dev, PCI_STATUS, &byte_val); + if (!(byte_val & PCI_STATUS_CAP_LIST)) + goto end; + + pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); + /* check if the capability pointer is 0x00 */ + if (cap_ptr == 0x00) + goto end; + + /* loop thru the capability list + * and see if the pcie capability exists + */ + + pci_read_config_byte(dev, cap_ptr, &cap_id); + + while (cap_id != req_cap_id) { + pci_read_config_byte(dev, cap_ptr + 1, &cap_ptr); + if (cap_ptr == 0x00) + break; + pci_read_config_byte(dev, cap_ptr, &cap_id); + } + if (cap_id != req_cap_id) + goto end; + + /* found the caller requested capability */ + if (buf != NULL && buflen != NULL) { + u8 cap_data; + + bufsize = *buflen; + if (!bufsize) + goto end; + *buflen = 0; + /* copy the capability data excluding cap ID and next ptr */ + cap_data = cap_ptr + 2; + if ((bufsize + cap_data) > PCI_SZPCR) + bufsize = PCI_SZPCR - cap_data; + *buflen = bufsize; + while (bufsize--) { + pci_read_config_byte(dev, cap_data, buf); + cap_data++; + buf++; + } + } +end: + return cap_ptr; +} + +/* ***** Register Access API */ +static uint +pcie_readreg(struct sbpcieregs __iomem *pcieregs, uint addrtype, uint offset) +{ + uint retval = 0xFFFFFFFF; + + switch (addrtype) { + case PCIE_CONFIGREGS: + W_REG(&pcieregs->configaddr, offset); + (void)R_REG((&pcieregs->configaddr)); + retval = R_REG(&pcieregs->configdata); + break; + case PCIE_PCIEREGS: + W_REG(&pcieregs->pcieindaddr, offset); + (void)R_REG(&pcieregs->pcieindaddr); + retval = R_REG(&pcieregs->pcieinddata); + break; + } + + return retval; +} + +static uint pcie_writereg(struct sbpcieregs __iomem *pcieregs, uint addrtype, + uint offset, uint val) +{ + switch (addrtype) { + case PCIE_CONFIGREGS: + W_REG((&pcieregs->configaddr), offset); + W_REG((&pcieregs->configdata), val); + break; + case PCIE_PCIEREGS: + W_REG((&pcieregs->pcieindaddr), offset); + W_REG((&pcieregs->pcieinddata), val); + break; + default: + break; + } + return 0; +} + +static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk) +{ + struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; + uint mdiodata, i = 0; + uint pcie_serdes_spinwait = 200; + + mdiodata = (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | + (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | + (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | + (blk << 4)); + W_REG(&pcieregs->mdiodata, mdiodata); + + pr28829_delay(); + /* retry till the transaction is complete */ + while (i < pcie_serdes_spinwait) { + if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE) + break; + + udelay(1000); + i++; + } + + if (i >= pcie_serdes_spinwait) + return false; + + return true; +} + +static int +pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write, + uint *val) +{ + struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; + uint mdiodata; + uint i = 0; + uint pcie_serdes_spinwait = 10; + + /* enable mdio access to SERDES */ + W_REG(&pcieregs->mdiocontrol, MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); + + if (pi->sih->buscorerev >= 10) { + /* new serdes is slower in rw, + * using two layers of reg address mapping + */ + if (!pcie_mdiosetblock(pi, physmedia)) + return 1; + mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | + (regaddr << MDIODATA_REGADDR_SHF)); + pcie_serdes_spinwait *= 20; + } else { + mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) | + (regaddr << MDIODATA_REGADDR_SHF_OLD)); + } + + if (!write) + mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA); + else + mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | + *val); + + W_REG(&pcieregs->mdiodata, mdiodata); + + pr28829_delay(); + + /* retry till the transaction is complete */ + while (i < pcie_serdes_spinwait) { + if (R_REG(&pcieregs->mdiocontrol) & MDIOCTL_ACCESS_DONE) { + if (!write) { + pr28829_delay(); + *val = (R_REG(&pcieregs->mdiodata) & + MDIODATA_MASK); + } + /* Disable mdio access to SERDES */ + W_REG(&pcieregs->mdiocontrol, 0); + return 0; + } + udelay(1000); + i++; + } + + /* Timed out. Disable mdio access to SERDES. */ + W_REG(&pcieregs->mdiocontrol, 0); + return 1; +} + +/* use the mdio interface to read from mdio slaves */ +static int +pcie_mdioread(struct pcicore_info *pi, uint physmedia, uint regaddr, + uint *regval) +{ + return pcie_mdioop(pi, physmedia, regaddr, false, regval); +} + +/* use the mdio interface to write to mdio slaves */ +static int +pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint regaddr, uint val) +{ + return pcie_mdioop(pi, physmedia, regaddr, true, &val); +} + +/* ***** Support functions ***** */ +static u8 pcie_clkreq(struct pcicore_info *pi, u32 mask, u32 val) +{ + u32 reg_val; + u8 offset; + + offset = pi->pciecap_lcreg_offset; + if (!offset) + return 0; + + pci_read_config_dword(pi->dev, offset, ®_val); + /* set operation */ + if (mask) { + if (val) + reg_val |= PCIE_CLKREQ_ENAB; + else + reg_val &= ~PCIE_CLKREQ_ENAB; + pci_write_config_dword(pi->dev, offset, reg_val); + pci_read_config_dword(pi->dev, offset, ®_val); + } + if (reg_val & PCIE_CLKREQ_ENAB) + return 1; + else + return 0; +} + +static void pcie_extendL1timer(struct pcicore_info *pi, bool extend) +{ + u32 w; + struct si_pub *sih = pi->sih; + struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; + + if (sih->buscoretype != PCIE_CORE_ID || sih->buscorerev < 7) + return; + + w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); + if (extend) + w |= PCIE_ASPMTIMER_EXTEND; + else + w &= ~PCIE_ASPMTIMER_EXTEND; + pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w); + w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); +} + +/* centralized clkreq control policy */ +static void pcie_clkreq_upd(struct pcicore_info *pi, uint state) +{ + struct si_pub *sih = pi->sih; + + switch (state) { + case SI_DOATTACH: + if (PCIE_ASPM(sih)) + pcie_clkreq(pi, 1, 0); + break; + case SI_PCIDOWN: + if (sih->buscorerev == 6) { /* turn on serdes PLL down */ + ai_corereg(sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_addr), + ~0, 0); + ai_corereg(sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_data), + ~0x40, 0); + } else if (pi->pcie_pr42767) { + pcie_clkreq(pi, 1, 1); + } + break; + case SI_PCIUP: + if (sih->buscorerev == 6) { /* turn off serdes PLL down */ + ai_corereg(sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_addr), + ~0, 0); + ai_corereg(sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_data), + ~0x40, 0x40); + } else if (PCIE_ASPM(sih)) { /* disable clkreq */ + pcie_clkreq(pi, 1, 0); + } + break; + } +} + +/* ***** PCI core WARs ***** */ +/* Done only once at attach time */ +static void pcie_war_polarity(struct pcicore_info *pi) +{ + u32 w; + + if (pi->pcie_polarity != 0) + return; + + w = pcie_readreg(pi->regs.pcieregs, PCIE_PCIEREGS, PCIE_PLP_STATUSREG); + + /* Detect the current polarity at attach and force that polarity and + * disable changing the polarity + */ + if ((w & PCIE_PLP_POLARITYINV_STAT) == 0) + pi->pcie_polarity = SERDES_RX_CTRL_FORCE; + else + pi->pcie_polarity = (SERDES_RX_CTRL_FORCE | + SERDES_RX_CTRL_POLARITY); +} + +/* enable ASPM and CLKREQ if srom doesn't have it */ +/* Needs to happen when update to shadow SROM is needed + * : Coming out of 'standby'/'hibernate' + * : If pcie_war_aspm_ovr state changed + */ +static void pcie_war_aspm_clkreq(struct pcicore_info *pi) +{ + struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; + struct si_pub *sih = pi->sih; + u16 val16; + u16 __iomem *reg16; + u32 w; + + if (!PCIE_ASPM(sih)) + return; + + /* bypass this on QT or VSIM */ + reg16 = &pcieregs->sprom[SRSH_ASPM_OFFSET]; + val16 = R_REG(reg16); + + val16 &= ~SRSH_ASPM_ENB; + if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB) + val16 |= SRSH_ASPM_ENB; + else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB) + val16 |= SRSH_ASPM_L1_ENB; + else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB) + val16 |= SRSH_ASPM_L0s_ENB; + + W_REG(reg16, val16); + + pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w); + w &= ~PCIE_ASPM_ENAB; + w |= pi->pcie_war_aspm_ovr; + pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w); + + reg16 = &pcieregs->sprom[SRSH_CLKREQ_OFFSET_REV5]; + val16 = R_REG(reg16); + + if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) { + val16 |= SRSH_CLKREQ_ENB; + pi->pcie_pr42767 = true; + } else + val16 &= ~SRSH_CLKREQ_ENB; + + W_REG(reg16, val16); +} + +/* Apply the polarity determined at the start */ +/* Needs to happen when coming out of 'standby'/'hibernate' */ +static void pcie_war_serdes(struct pcicore_info *pi) +{ + u32 w = 0; + + if (pi->pcie_polarity != 0) + pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL, + pi->pcie_polarity); + + pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w); + if (w & PLL_CTRL_FREQDET_EN) { + w &= ~PLL_CTRL_FREQDET_EN; + pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w); + } +} + +/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */ +/* Needs to happen when coming out of 'standby'/'hibernate' */ +static void pcie_misc_config_fixup(struct pcicore_info *pi) +{ + struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; + u16 val16; + u16 __iomem *reg16; + + reg16 = &pcieregs->sprom[SRSH_PCIE_MISC_CONFIG]; + val16 = R_REG(reg16); + + if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) { + val16 |= SRSH_L23READY_EXIT_NOPERST; + W_REG(reg16, val16); + } +} + +/* quick hack for testing */ +/* Needs to happen when coming out of 'standby'/'hibernate' */ +static void pcie_war_noplldown(struct pcicore_info *pi) +{ + struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; + u16 __iomem *reg16; + + /* turn off serdes PLL down */ + ai_corereg(pi->sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol), + CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN); + + /* clear srom shadow backdoor */ + reg16 = &pcieregs->sprom[SRSH_BD_OFFSET]; + W_REG(reg16, 0); +} + +/* Needs to happen when coming out of 'standby'/'hibernate' */ +static void pcie_war_pci_setup(struct pcicore_info *pi) +{ + struct si_pub *sih = pi->sih; + struct sbpcieregs __iomem *pcieregs = pi->regs.pcieregs; + u32 w; + + if (sih->buscorerev == 0 || sih->buscorerev == 1) { + w = pcie_readreg(pcieregs, PCIE_PCIEREGS, + PCIE_TLP_WORKAROUNDSREG); + w |= 0x8; + pcie_writereg(pcieregs, PCIE_PCIEREGS, + PCIE_TLP_WORKAROUNDSREG, w); + } + + if (sih->buscorerev == 1) { + w = pcie_readreg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG); + w |= 0x40; + pcie_writereg(pcieregs, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w); + } + + if (sih->buscorerev == 0) { + pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128); + pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100); + pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466); + } else if (PCIE_ASPM(sih)) { + /* Change the L1 threshold for better performance */ + w = pcie_readreg(pcieregs, PCIE_PCIEREGS, + PCIE_DLLP_PMTHRESHREG); + w &= ~PCIE_L1THRESHOLDTIME_MASK; + w |= PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT; + pcie_writereg(pcieregs, PCIE_PCIEREGS, + PCIE_DLLP_PMTHRESHREG, w); + + pcie_war_serdes(pi); + + pcie_war_aspm_clkreq(pi); + } else if (pi->sih->buscorerev == 7) + pcie_war_noplldown(pi); + + /* Note that the fix is actually in the SROM, + * that's why this is open-ended + */ + if (pi->sih->buscorerev >= 6) + pcie_misc_config_fixup(pi); +} + +/* ***** Functions called during driver state changes ***** */ +void pcicore_attach(struct pcicore_info *pi, int state) +{ + struct si_pub *sih = pi->sih; + u32 bfl2 = (u32)getintvar(sih, BRCMS_SROM_BOARDFLAGS2); + + /* Determine if this board needs override */ + if (PCIE_ASPM(sih)) { + if (bfl2 & BFL2_PCIEWAR_OVR) + pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB; + else + pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB; + } + + /* These need to happen in this order only */ + pcie_war_polarity(pi); + + pcie_war_serdes(pi); + + pcie_war_aspm_clkreq(pi); + + pcie_clkreq_upd(pi, state); + +} + +void pcicore_hwup(struct pcicore_info *pi) +{ + if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) + return; + + pcie_war_pci_setup(pi); +} + +void pcicore_up(struct pcicore_info *pi, int state) +{ + if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) + return; + + /* Restore L1 timer for better performance */ + pcie_extendL1timer(pi, true); + + pcie_clkreq_upd(pi, state); +} + +/* When the device is going to enter D3 state + * (or the system is going to enter S3/S4 states) + */ +void pcicore_sleep(struct pcicore_info *pi) +{ + u32 w; + + if (!pi || !PCIE_ASPM(pi->sih)) + return; + + pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w); + w &= ~PCIE_CAP_LCREG_ASPML1; + pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w); + + pi->pcie_pr42767 = false; +} + +void pcicore_down(struct pcicore_info *pi, int state) +{ + if (!pi || pi->sih->buscoretype != PCIE_CORE_ID) + return; + + pcie_clkreq_upd(pi, state); + + /* Reduce L1 timer for better power savings */ + pcie_extendL1timer(pi, false); +} + +/* precondition: current core is sii->buscoretype */ +static void pcicore_fixcfg(struct pcicore_info *pi, u16 __iomem *reg16) +{ + struct si_info *sii = (struct si_info *)(pi->sih); + u16 val16; + uint pciidx; + + pciidx = ai_coreidx(&sii->pub); + val16 = R_REG(reg16); + if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != (u16)pciidx) { + val16 = (u16)(pciidx << SRSH_PI_SHIFT) | + (val16 & ~SRSH_PI_MASK); + W_REG(reg16, val16); + } +} + +void +pcicore_fixcfg_pci(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs) +{ + pcicore_fixcfg(pi, &pciregs->sprom[SRSH_PI_OFFSET]); +} + +void pcicore_fixcfg_pcie(struct pcicore_info *pi, + struct sbpcieregs __iomem *pcieregs) +{ + pcicore_fixcfg(pi, &pcieregs->sprom[SRSH_PI_OFFSET]); +} + +/* precondition: current core is pci core */ +void +pcicore_pci_setup(struct pcicore_info *pi, struct sbpciregs __iomem *pciregs) +{ + u32 w; + + OR_REG(&pciregs->sbtopci2, SBTOPCI_PREF | SBTOPCI_BURST); + + if (((struct si_info *)(pi->sih))->pub.buscorerev >= 11) { + OR_REG(&pciregs->sbtopci2, SBTOPCI_RC_READMULTI); + w = R_REG(&pciregs->clkrun); + W_REG(&pciregs->clkrun, w | PCI_CLKRUN_DSBL); + w = R_REG(&pciregs->clkrun); + } +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h new file mode 100644 index 000000000000..58aa80dc3329 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_NICPCI_H_ +#define _BRCM_NICPCI_H_ + +#include "types.h" + +/* PCI configuration address space size */ +#define PCI_SZPCR 256 + +/* Brcm PCI configuration registers */ +/* backplane address space accessed by BAR0 */ +#define PCI_BAR0_WIN 0x80 +/* sprom property control */ +#define PCI_SPROM_CONTROL 0x88 +/* mask of PCI and other cores interrupts */ +#define PCI_INT_MASK 0x94 +/* backplane core interrupt mask bits offset */ +#define PCI_SBIM_SHIFT 8 +/* backplane address space accessed by second 4KB of BAR0 */ +#define PCI_BAR0_WIN2 0xac +/* pci config space gpio input (>=rev3) */ +#define PCI_GPIO_IN 0xb0 +/* pci config space gpio output (>=rev3) */ +#define PCI_GPIO_OUT 0xb4 +/* pci config space gpio output enable (>=rev3) */ +#define PCI_GPIO_OUTEN 0xb8 + +/* bar0 + 4K accesses external sprom */ +#define PCI_BAR0_SPROM_OFFSET (4 * 1024) +/* bar0 + 6K accesses pci core registers */ +#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) +/* + * pci core SB registers are at the end of the + * 8KB window, so their address is the "regular" + * address plus 4K + */ +#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) +/* bar0 window size Match with corerev 13 */ +#define PCI_BAR0_WINSZ (16 * 1024) +/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ +/* bar0 + 8K accesses pci/pcie core registers */ +#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) +/* bar0 + 12K accesses chipc core registers */ +#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) + +struct sbpciregs; +struct sbpcieregs; + +extern struct pcicore_info *pcicore_init(struct si_pub *sih, + struct pci_dev *pdev, + void __iomem *regs); +extern void pcicore_deinit(struct pcicore_info *pch); +extern void pcicore_attach(struct pcicore_info *pch, int state); +extern void pcicore_hwup(struct pcicore_info *pch); +extern void pcicore_up(struct pcicore_info *pch, int state); +extern void pcicore_sleep(struct pcicore_info *pch); +extern void pcicore_down(struct pcicore_info *pch, int state); +extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id, + unsigned char *buf, u32 *buflen); +extern void pcicore_fixcfg_pci(struct pcicore_info *pch, + struct sbpciregs __iomem *pciregs); +extern void pcicore_fixcfg_pcie(struct pcicore_info *pch, + struct sbpcieregs __iomem *pciregs); +extern void pcicore_pci_setup(struct pcicore_info *pch, + struct sbpciregs __iomem *pciregs); + +#endif /* _BRCM_NICPCI_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.c b/drivers/net/wireless/brcm80211/brcmsmac/otp.c new file mode 100644 index 000000000000..edf551561fd8 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/otp.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/io.h> +#include <linux/errno.h> +#include <linux/string.h> + +#include <brcm_hw_ids.h> +#include <chipcommon.h> +#include "aiutils.h" +#include "otp.h" + +#define OTPS_GUP_MASK 0x00000f00 +#define OTPS_GUP_SHIFT 8 +/* h/w subregion is programmed */ +#define OTPS_GUP_HW 0x00000100 +/* s/w subregion is programmed */ +#define OTPS_GUP_SW 0x00000200 +/* chipid/pkgopt subregion is programmed */ +#define OTPS_GUP_CI 0x00000400 +/* fuse subregion is programmed */ +#define OTPS_GUP_FUSE 0x00000800 + +/* Fields in otpprog in rev >= 21 */ +#define OTPP_COL_MASK 0x000000ff +#define OTPP_COL_SHIFT 0 +#define OTPP_ROW_MASK 0x0000ff00 +#define OTPP_ROW_SHIFT 8 +#define OTPP_OC_MASK 0x0f000000 +#define OTPP_OC_SHIFT 24 +#define OTPP_READERR 0x10000000 +#define OTPP_VALUE_MASK 0x20000000 +#define OTPP_VALUE_SHIFT 29 +#define OTPP_START_BUSY 0x80000000 +#define OTPP_READ 0x40000000 + +/* Opcodes for OTPP_OC field */ +#define OTPPOC_READ 0 +#define OTPPOC_BIT_PROG 1 +#define OTPPOC_VERIFY 3 +#define OTPPOC_INIT 4 +#define OTPPOC_SET 5 +#define OTPPOC_RESET 6 +#define OTPPOC_OCST 7 +#define OTPPOC_ROW_LOCK 8 +#define OTPPOC_PRESCN_TEST 9 + +#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23) + +#define OTPP_TRIES 10000000 /* # of tries for OTPP */ + +#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */ + +/* Fixed size subregions sizes in words */ +#define OTPGU_CI_SZ 2 + +struct otpinfo; + +/* OTP function struct */ +struct otp_fn_s { + int (*init)(struct si_pub *sih, struct otpinfo *oi); + int (*read_region)(struct otpinfo *oi, int region, u16 *data, + uint *wlen); +}; + +struct otpinfo { + uint ccrev; /* chipc revision */ + const struct otp_fn_s *fn; /* OTP functions */ + struct si_pub *sih; /* Saved sb handle */ + + /* IPX OTP section */ + u16 wsize; /* Size of otp in words */ + u16 rows; /* Geometry */ + u16 cols; /* Geometry */ + u32 status; /* Flag bits (lock/prog/rv). + * (Reflected only when OTP is power cycled) + */ + u16 hwbase; /* hardware subregion offset */ + u16 hwlim; /* hardware subregion boundary */ + u16 swbase; /* software subregion offset */ + u16 swlim; /* software subregion boundary */ + u16 fbase; /* fuse subregion offset */ + u16 flim; /* fuse subregion boundary */ + int otpgu_base; /* offset to General Use Region */ +}; + +/* OTP layout */ +/* CC revs 21, 24 and 27 OTP General Use Region word offset */ +#define REVA4_OTPGU_BASE 12 + +/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */ +#define REVB8_OTPGU_BASE 20 + +/* CC rev 36 OTP General Use Region word offset */ +#define REV36_OTPGU_BASE 12 + +/* Subregion word offsets in General Use region */ +#define OTPGU_HSB_OFF 0 +#define OTPGU_SFB_OFF 1 +#define OTPGU_CI_OFF 2 +#define OTPGU_P_OFF 3 +#define OTPGU_SROM_OFF 4 + +/* Flag bit offsets in General Use region */ +#define OTPGU_HWP_OFF 60 +#define OTPGU_SWP_OFF 61 +#define OTPGU_CIP_OFF 62 +#define OTPGU_FUSEP_OFF 63 +#define OTPGU_CIP_MSK 0x4000 +#define OTPGU_P_MSK 0xf000 +#define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16) + +/* OTP Size */ +#define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */ +#define OTP_SZ_FU_288 (288/8) /* 288 bits */ +#define OTP_SZ_FU_216 (216/8) /* 216 bits */ +#define OTP_SZ_FU_72 (72/8) /* 72 bits */ +#define OTP_SZ_CHECKSUM (16/8) /* 16 bits */ +#define OTP4315_SWREG_SZ 178 /* 178 bytes */ +#define OTP_SZ_FU_144 (144/8) /* 144 bits */ + +static u16 +ipxotp_otpr(struct otpinfo *oi, struct chipcregs __iomem *cc, uint wn) +{ + return R_REG(&cc->sromotp[wn]); +} + +/* + * Calculate max HW/SW region byte size by subtracting fuse region + * and checksum size, osizew is oi->wsize (OTP size - GU size) in words + */ +static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew) +{ + int ret = 0; + + switch (sih->chip) { + case BCM43224_CHIP_ID: + case BCM43225_CHIP_ID: + ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; + break; + case BCM4313_CHIP_ID: + ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; + break; + default: + break; /* Don't know about this chip */ + } + + return ret; +} + +static void _ipxotp_init(struct otpinfo *oi, struct chipcregs __iomem *cc) +{ + uint k; + u32 otpp, st; + + /* + * record word offset of General Use Region + * for various chipcommon revs + */ + if (oi->sih->ccrev == 21 || oi->sih->ccrev == 24 + || oi->sih->ccrev == 27) { + oi->otpgu_base = REVA4_OTPGU_BASE; + } else if (oi->sih->ccrev == 36) { + /* + * OTP size greater than equal to 2KB (128 words), + * otpgu_base is similar to rev23 + */ + if (oi->wsize >= 128) + oi->otpgu_base = REVB8_OTPGU_BASE; + else + oi->otpgu_base = REV36_OTPGU_BASE; + } else if (oi->sih->ccrev == 23 || oi->sih->ccrev >= 25) { + oi->otpgu_base = REVB8_OTPGU_BASE; + } + + /* First issue an init command so the status is up to date */ + otpp = + OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK); + + W_REG(&cc->otpprog, otpp); + for (k = 0; + ((st = R_REG(&cc->otpprog)) & OTPP_START_BUSY) + && (k < OTPP_TRIES); k++) + ; + if (k >= OTPP_TRIES) + return; + + /* Read OTP lock bits and subregion programmed indication bits */ + oi->status = R_REG(&cc->otpstatus); + + if ((oi->sih->chip == BCM43224_CHIP_ID) + || (oi->sih->chip == BCM43225_CHIP_ID)) { + u32 p_bits; + p_bits = + (ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_P_OFF) & + OTPGU_P_MSK) + >> OTPGU_P_SHIFT; + oi->status |= (p_bits << OTPS_GUP_SHIFT); + } + + /* + * h/w region base and fuse region limit are fixed to + * the top and the bottom of the general use region. + * Everything else can be flexible. + */ + oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF; + oi->hwlim = oi->wsize; + if (oi->status & OTPS_GUP_HW) { + oi->hwlim = + ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_HSB_OFF) / 16; + oi->swbase = oi->hwlim; + } else + oi->swbase = oi->hwbase; + + /* subtract fuse and checksum from beginning */ + oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2; + + if (oi->status & OTPS_GUP_SW) { + oi->swlim = + ipxotp_otpr(oi, cc, oi->otpgu_base + OTPGU_SFB_OFF) / 16; + oi->fbase = oi->swlim; + } else + oi->fbase = oi->swbase; + + oi->flim = oi->wsize; +} + +static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi) +{ + uint idx; + struct chipcregs __iomem *cc; + + /* Make sure we're running IPX OTP */ + if (!OTPTYPE_IPX(sih->ccrev)) + return -EBADE; + + /* Make sure OTP is not disabled */ + if (ai_is_otp_disabled(sih)) + return -EBADE; + + /* Check for otp size */ + switch ((sih->cccaps & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) { + case 0: + /* Nothing there */ + return -EBADE; + case 1: /* 32x64 */ + oi->rows = 32; + oi->cols = 64; + oi->wsize = 128; + break; + case 2: /* 64x64 */ + oi->rows = 64; + oi->cols = 64; + oi->wsize = 256; + break; + case 5: /* 96x64 */ + oi->rows = 96; + oi->cols = 64; + oi->wsize = 384; + break; + case 7: /* 16x64 *//* 1024 bits */ + oi->rows = 16; + oi->cols = 64; + oi->wsize = 64; + break; + default: + /* Don't know the geometry */ + return -EBADE; + } + + /* Retrieve OTP region info */ + idx = ai_coreidx(sih); + cc = ai_setcoreidx(sih, SI_CC_IDX); + + _ipxotp_init(oi, cc); + + ai_setcoreidx(sih, idx); + + return 0; +} + +static int +ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen) +{ + uint idx; + struct chipcregs __iomem *cc; + uint base, i, sz; + + /* Validate region selection */ + switch (region) { + case OTP_HW_RGN: + sz = (uint) oi->hwlim - oi->hwbase; + if (!(oi->status & OTPS_GUP_HW)) { + *wlen = sz; + return -ENODATA; + } + if (*wlen < sz) { + *wlen = sz; + return -EOVERFLOW; + } + base = oi->hwbase; + break; + case OTP_SW_RGN: + sz = ((uint) oi->swlim - oi->swbase); + if (!(oi->status & OTPS_GUP_SW)) { + *wlen = sz; + return -ENODATA; + } + if (*wlen < sz) { + *wlen = sz; + return -EOVERFLOW; + } + base = oi->swbase; + break; + case OTP_CI_RGN: + sz = OTPGU_CI_SZ; + if (!(oi->status & OTPS_GUP_CI)) { + *wlen = sz; + return -ENODATA; + } + if (*wlen < sz) { + *wlen = sz; + return -EOVERFLOW; + } + base = oi->otpgu_base + OTPGU_CI_OFF; + break; + case OTP_FUSE_RGN: + sz = (uint) oi->flim - oi->fbase; + if (!(oi->status & OTPS_GUP_FUSE)) { + *wlen = sz; + return -ENODATA; + } + if (*wlen < sz) { + *wlen = sz; + return -EOVERFLOW; + } + base = oi->fbase; + break; + case OTP_ALL_RGN: + sz = ((uint) oi->flim - oi->hwbase); + if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) { + *wlen = sz; + return -ENODATA; + } + if (*wlen < sz) { + *wlen = sz; + return -EOVERFLOW; + } + base = oi->hwbase; + break; + default: + return -EINVAL; + } + + idx = ai_coreidx(oi->sih); + cc = ai_setcoreidx(oi->sih, SI_CC_IDX); + + /* Read the data */ + for (i = 0; i < sz; i++) + data[i] = ipxotp_otpr(oi, cc, base + i); + + ai_setcoreidx(oi->sih, idx); + *wlen = sz; + return 0; +} + +static const struct otp_fn_s ipxotp_fn = { + (int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init, + (int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region, +}; + +static int otp_init(struct si_pub *sih, struct otpinfo *oi) +{ + + int ret; + + memset(oi, 0, sizeof(struct otpinfo)); + + oi->ccrev = sih->ccrev; + + if (OTPTYPE_IPX(oi->ccrev)) + oi->fn = &ipxotp_fn; + + if (oi->fn == NULL) + return -EBADE; + + oi->sih = sih; + + ret = (oi->fn->init) (sih, oi); + + return ret; +} + +int +otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) { + struct otpinfo otpinfo; + struct otpinfo *oi = &otpinfo; + int err = 0; + + if (ai_is_otp_disabled(sih)) { + err = -EPERM; + goto out; + } + + err = otp_init(sih, oi); + if (err) + goto out; + + err = ((oi)->fn->read_region)(oi, region, data, wlen); + + out: + return err; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.h b/drivers/net/wireless/brcm80211/brcmsmac/otp.h new file mode 100644 index 000000000000..6b6d31cf9569 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/otp.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_OTP_H_ +#define _BRCM_OTP_H_ + +#include "types.h" + +/* OTP regions */ +#define OTP_HW_RGN 1 +#define OTP_SW_RGN 2 +#define OTP_CI_RGN 4 +#define OTP_FUSE_RGN 8 +/* From h/w region to end of OTP including checksum */ +#define OTP_ALL_RGN 0xf + +/* OTP Size */ +#define OTP_SZ_MAX (6144/8) /* maximum bytes in one CIS */ + +extern int otp_read_region(struct si_pub *sih, int region, u16 *data, + uint *wlen); + +#endif /* _BRCM_OTP_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c new file mode 100644 index 000000000000..a3149254cbcd --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c @@ -0,0 +1,2988 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/kernel.h> +#include <linux/delay.h> +#include <linux/bitops.h> + +#include <brcm_hw_ids.h> +#include <chipcommon.h> +#include <aiutils.h> +#include <d11.h> +#include <phy_shim.h> +#include "phy_hal.h" +#include "phy_int.h" +#include "phy_radio.h" +#include "phy_lcn.h" +#include "phyreg_n.h" + +#define VALID_N_RADIO(radioid) ((radioid == BCM2055_ID) || \ + (radioid == BCM2056_ID) || \ + (radioid == BCM2057_ID)) + +#define VALID_LCN_RADIO(radioid) (radioid == BCM2064_ID) + +#define VALID_RADIO(pi, radioid) ( \ + (ISNPHY(pi) ? VALID_N_RADIO(radioid) : false) || \ + (ISLCNPHY(pi) ? VALID_LCN_RADIO(radioid) : false)) + +/* basic mux operation - can be optimized on several architectures */ +#define MUX(pred, true, false) ((pred) ? (true) : (false)) + +/* modulo inc/dec - assumes x E [0, bound - 1] */ +#define MODINC(x, bound) MUX((x) == (bound) - 1, 0, (x) + 1) + +/* modulo inc/dec, bound = 2^k */ +#define MODDEC_POW2(x, bound) (((x) - 1) & ((bound) - 1)) +#define MODINC_POW2(x, bound) (((x) + 1) & ((bound) - 1)) + +struct chan_info_basic { + u16 chan; + u16 freq; +}; + +static const struct chan_info_basic chan_info_all[] = { + {1, 2412}, + {2, 2417}, + {3, 2422}, + {4, 2427}, + {5, 2432}, + {6, 2437}, + {7, 2442}, + {8, 2447}, + {9, 2452}, + {10, 2457}, + {11, 2462}, + {12, 2467}, + {13, 2472}, + {14, 2484}, + + {34, 5170}, + {38, 5190}, + {42, 5210}, + {46, 5230}, + + {36, 5180}, + {40, 5200}, + {44, 5220}, + {48, 5240}, + {52, 5260}, + {56, 5280}, + {60, 5300}, + {64, 5320}, + + {100, 5500}, + {104, 5520}, + {108, 5540}, + {112, 5560}, + {116, 5580}, + {120, 5600}, + {124, 5620}, + {128, 5640}, + {132, 5660}, + {136, 5680}, + {140, 5700}, + + {149, 5745}, + {153, 5765}, + {157, 5785}, + {161, 5805}, + {165, 5825}, + + {184, 4920}, + {188, 4940}, + {192, 4960}, + {196, 4980}, + {200, 5000}, + {204, 5020}, + {208, 5040}, + {212, 5060}, + {216, 50800} +}; + +const u8 ofdm_rate_lookup[] = { + + BRCM_RATE_48M, + BRCM_RATE_24M, + BRCM_RATE_12M, + BRCM_RATE_6M, + BRCM_RATE_54M, + BRCM_RATE_36M, + BRCM_RATE_18M, + BRCM_RATE_9M +}; + +#define PHY_WREG_LIMIT 24 + +void wlc_phyreg_enter(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + wlapi_bmac_ucode_wake_override_phyreg_set(pi->sh->physhim); +} + +void wlc_phyreg_exit(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim); +} + +void wlc_radioreg_enter(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO); + + udelay(10); +} + +void wlc_radioreg_exit(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + u16 dummy; + + dummy = R_REG(&pi->regs->phyversion); + pi->phy_wreg = 0; + wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0); +} + +u16 read_radio_reg(struct brcms_phy *pi, u16 addr) +{ + u16 data; + + if ((addr == RADIO_IDCODE)) + return 0xffff; + + switch (pi->pubpi.phy_type) { + case PHY_TYPE_N: + if (!CONF_HAS(PHYTYPE, PHY_TYPE_N)) + break; + if (NREV_GE(pi->pubpi.phy_rev, 7)) + addr |= RADIO_2057_READ_OFF; + else + addr |= RADIO_2055_READ_OFF; + break; + + case PHY_TYPE_LCN: + if (!CONF_HAS(PHYTYPE, PHY_TYPE_LCN)) + break; + addr |= RADIO_2064_READ_OFF; + break; + + default: + break; + } + + if ((D11REV_GE(pi->sh->corerev, 24)) || + (D11REV_IS(pi->sh->corerev, 22) + && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { + W_REG_FLUSH(&pi->regs->radioregaddr, addr); + data = R_REG(&pi->regs->radioregdata); + } else { + W_REG_FLUSH(&pi->regs->phy4waddr, addr); + +#ifdef __ARM_ARCH_4T__ + __asm__(" .align 4 "); + __asm__(" nop "); + data = R_REG(&pi->regs->phy4wdatalo); +#else + data = R_REG(&pi->regs->phy4wdatalo); +#endif + + } + pi->phy_wreg = 0; + + return data; +} + +void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) +{ + if ((D11REV_GE(pi->sh->corerev, 24)) || + (D11REV_IS(pi->sh->corerev, 22) + && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { + + W_REG_FLUSH(&pi->regs->radioregaddr, addr); + W_REG(&pi->regs->radioregdata, val); + } else { + W_REG_FLUSH(&pi->regs->phy4waddr, addr); + W_REG(&pi->regs->phy4wdatalo, val); + } + + if (++pi->phy_wreg >= pi->phy_wreg_limit) { + (void)R_REG(&pi->regs->maccontrol); + pi->phy_wreg = 0; + } +} + +static u32 read_radio_id(struct brcms_phy *pi) +{ + u32 id; + + if (D11REV_GE(pi->sh->corerev, 24)) { + u32 b0, b1, b2; + + W_REG_FLUSH(&pi->regs->radioregaddr, 0); + b0 = (u32) R_REG(&pi->regs->radioregdata); + W_REG_FLUSH(&pi->regs->radioregaddr, 1); + b1 = (u32) R_REG(&pi->regs->radioregdata); + W_REG_FLUSH(&pi->regs->radioregaddr, 2); + b2 = (u32) R_REG(&pi->regs->radioregdata); + + id = ((b0 & 0xf) << 28) | (((b2 << 8) | b1) << 12) | ((b0 >> 4) + & 0xf); + } else { + W_REG_FLUSH(&pi->regs->phy4waddr, RADIO_IDCODE); + id = (u32) R_REG(&pi->regs->phy4wdatalo); + id |= (u32) R_REG(&pi->regs->phy4wdatahi) << 16; + } + pi->phy_wreg = 0; + return id; +} + +void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) +{ + u16 rval; + + rval = read_radio_reg(pi, addr); + write_radio_reg(pi, addr, (rval & val)); +} + +void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) +{ + u16 rval; + + rval = read_radio_reg(pi, addr); + write_radio_reg(pi, addr, (rval | val)); +} + +void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask) +{ + u16 rval; + + rval = read_radio_reg(pi, addr); + write_radio_reg(pi, addr, (rval ^ mask)); +} + +void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) +{ + u16 rval; + + rval = read_radio_reg(pi, addr); + write_radio_reg(pi, addr, (rval & ~mask) | (val & mask)); +} + +void write_phy_channel_reg(struct brcms_phy *pi, uint val) +{ + W_REG(&pi->regs->phychannel, val); +} + +u16 read_phy_reg(struct brcms_phy *pi, u16 addr) +{ + struct d11regs __iomem *regs; + + regs = pi->regs; + + W_REG_FLUSH(®s->phyregaddr, addr); + + pi->phy_wreg = 0; + return R_REG(®s->phyregdata); +} + +void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) +{ + struct d11regs __iomem *regs; + + regs = pi->regs; + +#ifdef CONFIG_BCM47XX + W_REG_FLUSH(®s->phyregaddr, addr); + W_REG(®s->phyregdata, val); + if (addr == 0x72) + (void)R_REG(®s->phyregdata); +#else + W_REG((u32 __iomem *)(®s->phyregaddr), addr | (val << 16)); + if (++pi->phy_wreg >= pi->phy_wreg_limit) { + pi->phy_wreg = 0; + (void)R_REG(®s->phyversion); + } +#endif +} + +void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) +{ + struct d11regs __iomem *regs; + + regs = pi->regs; + + W_REG_FLUSH(®s->phyregaddr, addr); + + W_REG(®s->phyregdata, (R_REG(®s->phyregdata) & val)); + pi->phy_wreg = 0; +} + +void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) +{ + struct d11regs __iomem *regs; + + regs = pi->regs; + + W_REG_FLUSH(®s->phyregaddr, addr); + + W_REG(®s->phyregdata, (R_REG(®s->phyregdata) | val)); + pi->phy_wreg = 0; +} + +void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) +{ + struct d11regs __iomem *regs; + + regs = pi->regs; + + W_REG_FLUSH(®s->phyregaddr, addr); + + W_REG(®s->phyregdata, + ((R_REG(®s->phyregdata) & ~mask) | (val & mask))); + pi->phy_wreg = 0; +} + +static void wlc_set_phy_uninitted(struct brcms_phy *pi) +{ + int i, j; + + pi->initialized = false; + + pi->tx_vos = 0xffff; + pi->nrssi_table_delta = 0x7fffffff; + pi->rc_cal = 0xffff; + pi->mintxbias = 0xffff; + pi->txpwridx = -1; + if (ISNPHY(pi)) { + pi->phy_spuravoid = SPURAVOID_DISABLE; + + if (NREV_GE(pi->pubpi.phy_rev, 3) + && NREV_LT(pi->pubpi.phy_rev, 7)) + pi->phy_spuravoid = SPURAVOID_AUTO; + + pi->nphy_papd_skip = 0; + pi->nphy_papd_epsilon_offset[0] = 0xf588; + pi->nphy_papd_epsilon_offset[1] = 0xf588; + pi->nphy_txpwr_idx[0] = 128; + pi->nphy_txpwr_idx[1] = 128; + pi->nphy_txpwrindex[0].index_internal = 40; + pi->nphy_txpwrindex[1].index_internal = 40; + pi->phy_pabias = 0; + } else { + pi->phy_spuravoid = SPURAVOID_AUTO; + } + pi->radiopwr = 0xffff; + for (i = 0; i < STATIC_NUM_RF; i++) { + for (j = 0; j < STATIC_NUM_BB; j++) + pi->stats_11b_txpower[i][j] = -1; + } +} + +struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp) +{ + struct shared_phy *sh; + + sh = kzalloc(sizeof(struct shared_phy), GFP_ATOMIC); + if (sh == NULL) + return NULL; + + sh->sih = shp->sih; + sh->physhim = shp->physhim; + sh->unit = shp->unit; + sh->corerev = shp->corerev; + + sh->vid = shp->vid; + sh->did = shp->did; + sh->chip = shp->chip; + sh->chiprev = shp->chiprev; + sh->chippkg = shp->chippkg; + sh->sromrev = shp->sromrev; + sh->boardtype = shp->boardtype; + sh->boardrev = shp->boardrev; + sh->boardvendor = shp->boardvendor; + sh->boardflags = shp->boardflags; + sh->boardflags2 = shp->boardflags2; + sh->buscorerev = shp->buscorerev; + + sh->fast_timer = PHY_SW_TIMER_FAST; + sh->slow_timer = PHY_SW_TIMER_SLOW; + sh->glacial_timer = PHY_SW_TIMER_GLACIAL; + + sh->rssi_mode = RSSI_ANT_MERGE_MAX; + + return sh; +} + +static void wlc_phy_timercb_phycal(struct brcms_phy *pi) +{ + uint delay = 5; + + if (PHY_PERICAL_MPHASE_PENDING(pi)) { + if (!pi->sh->up) { + wlc_phy_cal_perical_mphase_reset(pi); + return; + } + + if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi)) { + + delay = 1000; + wlc_phy_cal_perical_mphase_restart(pi); + } else + wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_AUTO); + wlapi_add_timer(pi->phycal_timer, delay, 0); + return; + } + +} + +static u32 wlc_phy_get_radio_ver(struct brcms_phy *pi) +{ + u32 ver; + + ver = read_radio_id(pi); + + return ver; +} + +struct brcms_phy_pub * +wlc_phy_attach(struct shared_phy *sh, struct d11regs __iomem *regs, + int bandtype, struct wiphy *wiphy) +{ + struct brcms_phy *pi; + u32 sflags = 0; + uint phyversion; + u32 idcode; + int i; + + if (D11REV_IS(sh->corerev, 4)) + sflags = SISF_2G_PHY | SISF_5G_PHY; + else + sflags = ai_core_sflags(sh->sih, 0, 0); + + if (bandtype == BRCM_BAND_5G) { + if ((sflags & (SISF_5G_PHY | SISF_DB_PHY)) == 0) + return NULL; + } + + pi = sh->phy_head; + if ((sflags & SISF_DB_PHY) && pi) { + wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags); + pi->refcnt++; + return &pi->pubpi_ro; + } + + pi = kzalloc(sizeof(struct brcms_phy), GFP_ATOMIC); + if (pi == NULL) + return NULL; + pi->wiphy = wiphy; + pi->regs = regs; + pi->sh = sh; + pi->phy_init_por = true; + pi->phy_wreg_limit = PHY_WREG_LIMIT; + + pi->txpwr_percent = 100; + + pi->do_initcal = true; + + pi->phycal_tempdelta = 0; + + if (bandtype == BRCM_BAND_2G && (sflags & SISF_2G_PHY)) + pi->pubpi.coreflags = SICF_GMODE; + + wlapi_bmac_corereset(pi->sh->physhim, pi->pubpi.coreflags); + phyversion = R_REG(&pi->regs->phyversion); + + pi->pubpi.phy_type = PHY_TYPE(phyversion); + pi->pubpi.phy_rev = phyversion & PV_PV_MASK; + + if (pi->pubpi.phy_type == PHY_TYPE_LCNXN) { + pi->pubpi.phy_type = PHY_TYPE_N; + pi->pubpi.phy_rev += LCNXN_BASEREV; + } + pi->pubpi.phy_corenum = PHY_CORE_NUM_2; + pi->pubpi.ana_rev = (phyversion & PV_AV_MASK) >> PV_AV_SHIFT; + + if (!pi->pubpi.phy_type == PHY_TYPE_N && + !pi->pubpi.phy_type == PHY_TYPE_LCN) + goto err; + + if (bandtype == BRCM_BAND_5G) { + if (!ISNPHY(pi)) + goto err; + } else if (!ISNPHY(pi) && !ISLCNPHY(pi)) { + goto err; + } + + wlc_phy_anacore((struct brcms_phy_pub *) pi, ON); + + idcode = wlc_phy_get_radio_ver(pi); + pi->pubpi.radioid = + (idcode & IDCODE_ID_MASK) >> IDCODE_ID_SHIFT; + pi->pubpi.radiorev = + (idcode & IDCODE_REV_MASK) >> IDCODE_REV_SHIFT; + pi->pubpi.radiover = + (idcode & IDCODE_VER_MASK) >> IDCODE_VER_SHIFT; + if (!VALID_RADIO(pi, pi->pubpi.radioid)) + goto err; + + wlc_phy_switch_radio((struct brcms_phy_pub *) pi, OFF); + + wlc_set_phy_uninitted(pi); + + pi->bw = WL_CHANSPEC_BW_20; + pi->radio_chanspec = (bandtype == BRCM_BAND_2G) ? + ch20mhz_chspec(1) : ch20mhz_chspec(36); + + pi->rxiq_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY; + pi->rxiq_antsel = ANT_RX_DIV_DEF; + + pi->watchdog_override = true; + + pi->cal_type_override = PHY_PERICAL_AUTO; + + pi->nphy_saved_noisevars.bufcount = 0; + + if (ISNPHY(pi)) + pi->min_txpower = PHY_TXPWR_MIN_NPHY; + else + pi->min_txpower = PHY_TXPWR_MIN; + + pi->sh->phyrxchain = 0x3; + + pi->rx2tx_biasentry = -1; + + pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP; + pi->phy_txcore_enable_temp = + PHY_CHAIN_TX_DISABLE_TEMP - PHY_HYSTERESIS_DELTATEMP; + pi->phy_tempsense_offset = 0; + pi->phy_txcore_heatedup = false; + + pi->nphy_lastcal_temp = -50; + + pi->phynoise_polling = true; + if (ISNPHY(pi) || ISLCNPHY(pi)) + pi->phynoise_polling = false; + + for (i = 0; i < TXP_NUM_RATES; i++) { + pi->txpwr_limit[i] = BRCMS_TXPWR_MAX; + pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX; + pi->tx_user_target[i] = BRCMS_TXPWR_MAX; + } + + pi->radiopwr_override = RADIOPWR_OVERRIDE_DEF; + + pi->user_txpwr_at_rfport = false; + + if (ISNPHY(pi)) { + + pi->phycal_timer = wlapi_init_timer(pi->sh->physhim, + wlc_phy_timercb_phycal, + pi, "phycal"); + if (!pi->phycal_timer) + goto err; + + if (!wlc_phy_attach_nphy(pi)) + goto err; + + } else if (ISLCNPHY(pi)) { + if (!wlc_phy_attach_lcnphy(pi)) + goto err; + + } + + pi->refcnt++; + pi->next = pi->sh->phy_head; + sh->phy_head = pi; + + memcpy(&pi->pubpi_ro, &pi->pubpi, sizeof(struct brcms_phy_pub)); + + return &pi->pubpi_ro; + +err: + kfree(pi); + return NULL; +} + +void wlc_phy_detach(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (pih) { + if (--pi->refcnt) + return; + + if (pi->phycal_timer) { + wlapi_free_timer(pi->phycal_timer); + pi->phycal_timer = NULL; + } + + if (pi->sh->phy_head == pi) + pi->sh->phy_head = pi->next; + else if (pi->sh->phy_head->next == pi) + pi->sh->phy_head->next = NULL; + + if (pi->pi_fptr.detach) + (pi->pi_fptr.detach)(pi); + + kfree(pi); + } +} + +bool +wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, u16 *phyrev, + u16 *radioid, u16 *radiover) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + *phytype = (u16) pi->pubpi.phy_type; + *phyrev = (u16) pi->pubpi.phy_rev; + *radioid = pi->pubpi.radioid; + *radiover = pi->pubpi.radiorev; + + return true; +} + +bool wlc_phy_get_encore(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + return pi->pubpi.abgphy_encore; +} + +u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + return pi->pubpi.coreflags; +} + +void wlc_phy_anacore(struct brcms_phy_pub *pih, bool on) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (ISNPHY(pi)) { + if (on) { + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + write_phy_reg(pi, 0xa6, 0x0d); + write_phy_reg(pi, 0x8f, 0x0); + write_phy_reg(pi, 0xa7, 0x0d); + write_phy_reg(pi, 0xa5, 0x0); + } else { + write_phy_reg(pi, 0xa5, 0x0); + } + } else { + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + write_phy_reg(pi, 0x8f, 0x07ff); + write_phy_reg(pi, 0xa6, 0x0fd); + write_phy_reg(pi, 0xa5, 0x07ff); + write_phy_reg(pi, 0xa7, 0x0fd); + } else { + write_phy_reg(pi, 0xa5, 0x7fff); + } + } + } else if (ISLCNPHY(pi)) { + if (on) { + and_phy_reg(pi, 0x43b, + ~((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); + } else { + or_phy_reg(pi, 0x43c, + (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); + or_phy_reg(pi, 0x43b, + (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); + } + } +} + +u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + u32 phy_bw_clkbits = 0; + + if (pi && (ISNPHY(pi) || ISLCNPHY(pi))) { + switch (pi->bw) { + case WL_CHANSPEC_BW_10: + phy_bw_clkbits = SICF_BW10; + break; + case WL_CHANSPEC_BW_20: + phy_bw_clkbits = SICF_BW20; + break; + case WL_CHANSPEC_BW_40: + phy_bw_clkbits = SICF_BW40; + break; + default: + break; + } + } + + return phy_bw_clkbits; +} + +void wlc_phy_por_inform(struct brcms_phy_pub *ppi) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + pi->phy_init_por = true; +} + +void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + pi->edcrs_threshold_lock = lock; + + write_phy_reg(pi, 0x22c, 0x46b); + write_phy_reg(pi, 0x22d, 0x46b); + write_phy_reg(pi, 0x22e, 0x3c0); + write_phy_reg(pi, 0x22f, 0x3c0); +} + +void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + pi->do_initcal = initcal; +} + +void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *pih, bool newstate) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (!pi || !pi->sh) + return; + + pi->sh->clk = newstate; +} + +void wlc_phy_hw_state_upd(struct brcms_phy_pub *pih, bool newstate) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (!pi || !pi->sh) + return; + + pi->sh->up = newstate; +} + +void wlc_phy_init(struct brcms_phy_pub *pih, u16 chanspec) +{ + u32 mc; + void (*phy_init)(struct brcms_phy *) = NULL; + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (pi->init_in_progress) + return; + + pi->init_in_progress = true; + + pi->radio_chanspec = chanspec; + + mc = R_REG(&pi->regs->maccontrol); + if (WARN(mc & MCTL_EN_MAC, "HW error MAC running on init")) + return; + + if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) + pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; + + if (WARN(!(ai_core_sflags(pi->sh->sih, 0, 0) & SISF_FCLKA), + "HW error SISF_FCLKA\n")) + return; + + phy_init = pi->pi_fptr.init; + + if (phy_init == NULL) + return; + + wlc_phy_anacore(pih, ON); + + if (CHSPEC_BW(pi->radio_chanspec) != pi->bw) + wlapi_bmac_bw_set(pi->sh->physhim, + CHSPEC_BW(pi->radio_chanspec)); + + pi->nphy_gain_boost = true; + + wlc_phy_switch_radio((struct brcms_phy_pub *) pi, ON); + + (*phy_init)(pi); + + pi->phy_init_por = false; + + if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) + wlc_phy_do_dummy_tx(pi, true, OFF); + + if (!(ISNPHY(pi))) + wlc_phy_txpower_update_shm(pi); + + wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, pi->sh->rx_antdiv); + + pi->init_in_progress = false; +} + +void wlc_phy_cal_init(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + void (*cal_init)(struct brcms_phy *) = NULL; + + if (WARN((R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) != 0, + "HW error: MAC enabled during phy cal\n")) + return; + + if (!pi->initialized) { + cal_init = pi->pi_fptr.calinit; + if (cal_init) + (*cal_init)(pi); + + pi->initialized = true; + } +} + +int wlc_phy_down(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + int callbacks = 0; + + if (pi->phycal_timer + && !wlapi_del_timer(pi->phycal_timer)) + callbacks++; + + pi->nphy_iqcal_chanspec_2G = 0; + pi->nphy_iqcal_chanspec_5G = 0; + + return callbacks; +} + +void +wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, + u16 tblAddr, u16 tblDataHi, u16 tblDataLo) +{ + write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); + + pi->tbl_data_hi = tblDataHi; + pi->tbl_data_lo = tblDataLo; + + if (pi->sh->chip == BCM43224_CHIP_ID && + pi->sh->chiprev == 1) { + pi->tbl_addr = tblAddr; + pi->tbl_save_id = tbl_id; + pi->tbl_save_offset = tbl_offset; + } +} + +void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val) +{ + if ((pi->sh->chip == BCM43224_CHIP_ID) && + (pi->sh->chiprev == 1) && + (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { + read_phy_reg(pi, pi->tbl_data_lo); + + write_phy_reg(pi, pi->tbl_addr, + (pi->tbl_save_id << 10) | pi->tbl_save_offset); + pi->tbl_save_offset++; + } + + if (width == 32) { + write_phy_reg(pi, pi->tbl_data_hi, (u16) (val >> 16)); + write_phy_reg(pi, pi->tbl_data_lo, (u16) val); + } else { + write_phy_reg(pi, pi->tbl_data_lo, (u16) val); + } +} + +void +wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, + u16 tblAddr, u16 tblDataHi, u16 tblDataLo) +{ + uint idx; + uint tbl_id = ptbl_info->tbl_id; + uint tbl_offset = ptbl_info->tbl_offset; + uint tbl_width = ptbl_info->tbl_width; + const u8 *ptbl_8b = (const u8 *)ptbl_info->tbl_ptr; + const u16 *ptbl_16b = (const u16 *)ptbl_info->tbl_ptr; + const u32 *ptbl_32b = (const u32 *)ptbl_info->tbl_ptr; + + write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); + + for (idx = 0; idx < ptbl_info->tbl_len; idx++) { + + if ((pi->sh->chip == BCM43224_CHIP_ID) && + (pi->sh->chiprev == 1) && + (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { + read_phy_reg(pi, tblDataLo); + + write_phy_reg(pi, tblAddr, + (tbl_id << 10) | (tbl_offset + idx)); + } + + if (tbl_width == 32) { + write_phy_reg(pi, tblDataHi, + (u16) (ptbl_32b[idx] >> 16)); + write_phy_reg(pi, tblDataLo, (u16) ptbl_32b[idx]); + } else if (tbl_width == 16) { + write_phy_reg(pi, tblDataLo, ptbl_16b[idx]); + } else { + write_phy_reg(pi, tblDataLo, ptbl_8b[idx]); + } + } +} + +void +wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, + u16 tblAddr, u16 tblDataHi, u16 tblDataLo) +{ + uint idx; + uint tbl_id = ptbl_info->tbl_id; + uint tbl_offset = ptbl_info->tbl_offset; + uint tbl_width = ptbl_info->tbl_width; + u8 *ptbl_8b = (u8 *)ptbl_info->tbl_ptr; + u16 *ptbl_16b = (u16 *)ptbl_info->tbl_ptr; + u32 *ptbl_32b = (u32 *)ptbl_info->tbl_ptr; + + write_phy_reg(pi, tblAddr, (tbl_id << 10) | tbl_offset); + + for (idx = 0; idx < ptbl_info->tbl_len; idx++) { + + if ((pi->sh->chip == BCM43224_CHIP_ID) && + (pi->sh->chiprev == 1)) { + (void)read_phy_reg(pi, tblDataLo); + + write_phy_reg(pi, tblAddr, + (tbl_id << 10) | (tbl_offset + idx)); + } + + if (tbl_width == 32) { + ptbl_32b[idx] = read_phy_reg(pi, tblDataLo); + ptbl_32b[idx] |= (read_phy_reg(pi, tblDataHi) << 16); + } else if (tbl_width == 16) { + ptbl_16b[idx] = read_phy_reg(pi, tblDataLo); + } else { + ptbl_8b[idx] = (u8) read_phy_reg(pi, tblDataLo); + } + } +} + +uint +wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi, + struct radio_20xx_regs *radioregs) +{ + uint i = 0; + + do { + if (radioregs[i].do_init) + write_radio_reg(pi, radioregs[i].address, + (u16) radioregs[i].init); + + i++; + } while (radioregs[i].address != 0xffff); + + return i; +} + +uint +wlc_phy_init_radio_regs(struct brcms_phy *pi, + const struct radio_regs *radioregs, + u16 core_offset) +{ + uint i = 0; + uint count = 0; + + do { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (radioregs[i].do_init_a) { + write_radio_reg(pi, + radioregs[i]. + address | core_offset, + (u16) radioregs[i].init_a); + if (ISNPHY(pi) && (++count % 4 == 0)) + BRCMS_PHY_WAR_PR51571(pi); + } + } else { + if (radioregs[i].do_init_g) { + write_radio_reg(pi, + radioregs[i]. + address | core_offset, + (u16) radioregs[i].init_g); + if (ISNPHY(pi) && (++count % 4 == 0)) + BRCMS_PHY_WAR_PR51571(pi); + } + } + + i++; + } while (radioregs[i].address != 0xffff); + + return i; +} + +void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on) +{ +#define DUMMY_PKT_LEN 20 + struct d11regs __iomem *regs = pi->regs; + int i, count; + u8 ofdmpkt[DUMMY_PKT_LEN] = { + 0xcc, 0x01, 0x02, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 + }; + u8 cckpkt[DUMMY_PKT_LEN] = { + 0x6e, 0x84, 0x0b, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 + }; + u32 *dummypkt; + + dummypkt = (u32 *) (ofdm ? ofdmpkt : cckpkt); + wlapi_bmac_write_template_ram(pi->sh->physhim, 0, DUMMY_PKT_LEN, + dummypkt); + + W_REG(®s->xmtsel, 0); + + if (D11REV_GE(pi->sh->corerev, 11)) + W_REG(®s->wepctl, 0x100); + else + W_REG(®s->wepctl, 0); + + W_REG(®s->txe_phyctl, (ofdm ? 1 : 0) | PHY_TXC_ANT_0); + if (ISNPHY(pi) || ISLCNPHY(pi)) + W_REG(®s->txe_phyctl1, 0x1A02); + + W_REG(®s->txe_wm_0, 0); + W_REG(®s->txe_wm_1, 0); + + W_REG(®s->xmttplatetxptr, 0); + W_REG(®s->xmttxcnt, DUMMY_PKT_LEN); + + W_REG(®s->xmtsel, ((8 << 8) | (1 << 5) | (1 << 2) | 2)); + + W_REG(®s->txe_ctl, 0); + + if (!pa_on) { + if (ISNPHY(pi)) + wlc_phy_pa_override_nphy(pi, OFF); + } + + if (ISNPHY(pi) || ISLCNPHY(pi)) + W_REG(®s->txe_aux, 0xD0); + else + W_REG(®s->txe_aux, ((1 << 5) | (1 << 4))); + + (void)R_REG(®s->txe_aux); + + i = 0; + count = ofdm ? 30 : 250; + while ((i++ < count) + && (R_REG(®s->txe_status) & (1 << 7))) + udelay(10); + + i = 0; + + while ((i++ < 10) + && ((R_REG(®s->txe_status) & (1 << 10)) == 0)) + udelay(10); + + i = 0; + + while ((i++ < 10) && ((R_REG(®s->ifsstat) & (1 << 8)))) + udelay(10); + + if (!pa_on) { + if (ISNPHY(pi)) + wlc_phy_pa_override_nphy(pi, ON); + } +} + +void wlc_phy_hold_upd(struct brcms_phy_pub *pih, u32 id, bool set) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (set) + mboolset(pi->measure_hold, id); + else + mboolclr(pi->measure_hold, id); + + return; +} + +void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (mute) + mboolset(pi->measure_hold, PHY_HOLD_FOR_MUTE); + else + mboolclr(pi->measure_hold, PHY_HOLD_FOR_MUTE); + + if (!mute && (flags & PHY_MUTE_FOR_PREISM)) + pi->nphy_perical_last = pi->sh->now - pi->sh->glacial_timer; + return; +} + +void wlc_phy_clear_tssi(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (ISNPHY(pi)) { + return; + } else { + wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W); + wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W); + wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W); + wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W); + } +} + +static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi) +{ + return false; +} + +void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + (void)R_REG(&pi->regs->maccontrol); + + if (ISNPHY(pi)) { + wlc_phy_switch_radio_nphy(pi, on); + } else if (ISLCNPHY(pi)) { + if (on) { + and_phy_reg(pi, 0x44c, + ~((0x1 << 8) | + (0x1 << 9) | + (0x1 << 10) | (0x1 << 11) | (0x1 << 12))); + and_phy_reg(pi, 0x4b0, ~((0x1 << 3) | (0x1 << 11))); + and_phy_reg(pi, 0x4f9, ~(0x1 << 3)); + } else { + and_phy_reg(pi, 0x44d, + ~((0x1 << 10) | + (0x1 << 11) | + (0x1 << 12) | (0x1 << 13) | (0x1 << 14))); + or_phy_reg(pi, 0x44c, + (0x1 << 8) | + (0x1 << 9) | + (0x1 << 10) | (0x1 << 11) | (0x1 << 12)); + + and_phy_reg(pi, 0x4b7, ~((0x7f << 8))); + and_phy_reg(pi, 0x4b1, ~((0x1 << 13))); + or_phy_reg(pi, 0x4b0, (0x1 << 3) | (0x1 << 11)); + and_phy_reg(pi, 0x4fa, ~((0x1 << 3))); + or_phy_reg(pi, 0x4f9, (0x1 << 3)); + } + } +} + +u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + return pi->bw; +} + +void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + pi->bw = bw; +} + +void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + pi->radio_chanspec = newch; + +} + +u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + return pi->radio_chanspec; +} + +void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + u16 m_cur_channel; + void (*chanspec_set)(struct brcms_phy *, u16) = NULL; + m_cur_channel = CHSPEC_CHANNEL(chanspec); + if (CHSPEC_IS5G(chanspec)) + m_cur_channel |= D11_CURCHANNEL_5G; + if (CHSPEC_IS40(chanspec)) + m_cur_channel |= D11_CURCHANNEL_40; + wlapi_bmac_write_shm(pi->sh->physhim, M_CURCHANNEL, m_cur_channel); + + chanspec_set = pi->pi_fptr.chanset; + if (chanspec_set) + (*chanspec_set)(pi, chanspec); + +} + +int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq) +{ + int range = -1; + + if (freq < 2500) + range = WL_CHAN_FREQ_RANGE_2G; + else if (freq <= 5320) + range = WL_CHAN_FREQ_RANGE_5GL; + else if (freq <= 5700) + range = WL_CHAN_FREQ_RANGE_5GM; + else + range = WL_CHAN_FREQ_RANGE_5GH; + + return range; +} + +int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec) +{ + int range = -1; + uint channel = CHSPEC_CHANNEL(chanspec); + uint freq = wlc_phy_channel2freq(channel); + + if (ISNPHY(pi)) + range = wlc_phy_get_chan_freq_range_nphy(pi, channel); + else if (ISLCNPHY(pi)) + range = wlc_phy_chanspec_freq2bandrange_lpssn(freq); + + return range; +} + +void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, + bool wide_filter) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + pi->channel_14_wide_filter = wide_filter; + +} + +int wlc_phy_channel2freq(uint channel) +{ + uint i; + + for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) + if (chan_info_all[i].chan == channel) + return chan_info_all[i].freq; + return 0; +} + +void +wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, + struct brcms_chanvec *channels) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + uint i; + uint channel; + + memset(channels, 0, sizeof(struct brcms_chanvec)); + + for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { + channel = chan_info_all[i].chan; + + if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM) + && (channel <= LAST_REF5_CHANNUM)) + continue; + + if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) || + (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL)) + setbit(channels->vec, channel); + } +} + +u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + uint i; + uint channel; + u16 chspec; + + for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { + channel = chan_info_all[i].chan; + + if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) { + uint j; + + for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) { + if (chan_info_all[j].chan == + channel + CH_10MHZ_APART) + break; + } + + if (j == ARRAY_SIZE(chan_info_all)) + continue; + + channel = upper_20_sb(channel); + chspec = channel | WL_CHANSPEC_BW_40 | + WL_CHANSPEC_CTL_SB_LOWER; + if (band == BRCM_BAND_2G) + chspec |= WL_CHANSPEC_BAND_2G; + else + chspec |= WL_CHANSPEC_BAND_5G; + } else + chspec = ch20mhz_chspec(channel); + + if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM) + && (channel <= LAST_REF5_CHANNUM)) + continue; + + if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) || + (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL)) + return chspec; + } + + return (u16) INVCHANSPEC; +} + +int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + *qdbm = pi->tx_user_target[0]; + if (override != NULL) + *override = pi->txpwroverride; + return 0; +} + +void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, + struct txpwr_limits *txpwr) +{ + bool mac_enabled = false; + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + memcpy(&pi->tx_user_target[TXP_FIRST_CCK], + &txpwr->cck[0], BRCMS_NUM_RATES_CCK); + + memcpy(&pi->tx_user_target[TXP_FIRST_OFDM], + &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM); + memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD], + &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM); + + memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], + &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM); + memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], + &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM); + + memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO], + &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); + memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD], + &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); + memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC], + &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); + memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM], + &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); + + memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO], + &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); + memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD], + &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); + memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC], + &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); + memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM], + &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); + + if (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) + mac_enabled = true; + + if (mac_enabled) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + wlc_phy_txpower_recalc_target(pi); + wlc_phy_cal_txpower_recalc_sw(pi); + + if (mac_enabled) + wlapi_enable_mac(pi->sh->physhim); +} + +int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + int i; + + if (qdbm > 127) + return -EINVAL; + + for (i = 0; i < TXP_NUM_RATES; i++) + pi->tx_user_target[i] = (u8) qdbm; + + pi->txpwroverride = false; + + if (pi->sh->up) { + if (!SCAN_INPROG_PHY(pi)) { + bool suspend; + + suspend = (0 == (R_REG(&pi->regs->maccontrol) & + MCTL_EN_MAC)); + + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + wlc_phy_txpower_recalc_target(pi); + wlc_phy_cal_txpower_recalc_sw(pi); + + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); + } + } + return 0; +} + +void +wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr, + u8 *max_pwr, int txp_rate_idx) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + uint i; + + *min_pwr = pi->min_txpower * BRCMS_TXPWR_DB_FACTOR; + + if (ISNPHY(pi)) { + if (txp_rate_idx < 0) + txp_rate_idx = TXP_FIRST_CCK; + wlc_phy_txpower_sromlimit_get_nphy(pi, channel, max_pwr, + (u8) txp_rate_idx); + + } else if ((channel <= CH_MAX_2G_CHANNEL)) { + if (txp_rate_idx < 0) + txp_rate_idx = TXP_FIRST_CCK; + *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx]; + } else { + + *max_pwr = BRCMS_TXPWR_MAX; + + if (txp_rate_idx < 0) + txp_rate_idx = TXP_FIRST_OFDM; + + for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { + if (channel == chan_info_all[i].chan) + break; + } + + if (pi->hwtxpwr) { + *max_pwr = pi->hwtxpwr[i]; + } else { + + if ((i >= FIRST_MID_5G_CHAN) && (i <= LAST_MID_5G_CHAN)) + *max_pwr = + pi->tx_srom_max_rate_5g_mid[txp_rate_idx]; + if ((i >= FIRST_HIGH_5G_CHAN) + && (i <= LAST_HIGH_5G_CHAN)) + *max_pwr = + pi->tx_srom_max_rate_5g_hi[txp_rate_idx]; + if ((i >= FIRST_LOW_5G_CHAN) && (i <= LAST_LOW_5G_CHAN)) + *max_pwr = + pi->tx_srom_max_rate_5g_low[txp_rate_idx]; + } + } +} + +void +wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, + u8 *max_txpwr, u8 *min_txpwr) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + u8 tx_pwr_max = 0; + u8 tx_pwr_min = 255; + u8 max_num_rate; + u8 maxtxpwr, mintxpwr, rate, pactrl; + + pactrl = 0; + + max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES : + ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + + 1) : (TXP_LAST_OFDM + 1); + + for (rate = 0; rate < max_num_rate; rate++) { + + wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr, + rate); + + maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0; + + maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0; + + tx_pwr_max = max(tx_pwr_max, maxtxpwr); + tx_pwr_min = min(tx_pwr_min, maxtxpwr); + } + *max_txpwr = tx_pwr_max; + *min_txpwr = tx_pwr_min; +} + +void +wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit, + s32 *max_pwr, s32 *min_pwr, u32 *step_pwr) +{ + return; +} + +u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + return pi->tx_power_min; +} + +u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + return pi->tx_power_max; +} + +static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi) +{ + if (ISLCNPHY(pi)) + return wlc_lcnphy_vbatsense(pi, 0); + else + return 0; +} + +static s8 wlc_phy_env_measure_temperature(struct brcms_phy *pi) +{ + if (ISLCNPHY(pi)) + return wlc_lcnphy_tempsense_degree(pi, 0); + else + return 0; +} + +static void wlc_phy_upd_env_txpwr_rate_limits(struct brcms_phy *pi, u32 band) +{ + u8 i; + s8 temp, vbat; + + for (i = 0; i < TXP_NUM_RATES; i++) + pi->txpwr_env_limit[i] = BRCMS_TXPWR_MAX; + + vbat = wlc_phy_env_measure_vbat(pi); + temp = wlc_phy_env_measure_temperature(pi); + +} + +static s8 +wlc_user_txpwr_antport_to_rfport(struct brcms_phy *pi, uint chan, u32 band, + u8 rate) +{ + s8 offset = 0; + + if (!pi->user_txpwr_at_rfport) + return offset; + return offset; +} + +void wlc_phy_txpower_recalc_target(struct brcms_phy *pi) +{ + u8 maxtxpwr, mintxpwr, rate, pactrl; + uint target_chan; + u8 tx_pwr_target[TXP_NUM_RATES]; + u8 tx_pwr_max = 0; + u8 tx_pwr_min = 255; + u8 tx_pwr_max_rate_ind = 0; + u8 max_num_rate; + u8 start_rate = 0; + u16 chspec; + u32 band = CHSPEC2BAND(pi->radio_chanspec); + void (*txpwr_recalc_fn)(struct brcms_phy *) = NULL; + + chspec = pi->radio_chanspec; + if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_NONE) + target_chan = CHSPEC_CHANNEL(chspec); + else if (CHSPEC_CTL_SB(chspec) == WL_CHANSPEC_CTL_SB_UPPER) + target_chan = upper_20_sb(CHSPEC_CHANNEL(chspec)); + else + target_chan = lower_20_sb(CHSPEC_CHANNEL(chspec)); + + pactrl = 0; + if (ISLCNPHY(pi)) { + u32 offset_mcs, i; + + if (CHSPEC_IS40(pi->radio_chanspec)) { + offset_mcs = pi->mcs40_po; + for (i = TXP_FIRST_SISO_MCS_20; + i <= TXP_LAST_SISO_MCS_20; i++) { + pi->tx_srom_max_rate_2g[i - 8] = + pi->tx_srom_max_2g - + ((offset_mcs & 0xf) * 2); + offset_mcs >>= 4; + } + } else { + offset_mcs = pi->mcs20_po; + for (i = TXP_FIRST_SISO_MCS_20; + i <= TXP_LAST_SISO_MCS_20; i++) { + pi->tx_srom_max_rate_2g[i - 8] = + pi->tx_srom_max_2g - + ((offset_mcs & 0xf) * 2); + offset_mcs >>= 4; + } + } + } + + max_num_rate = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : + ((ISLCNPHY(pi)) ? + (TXP_LAST_SISO_MCS_20 + 1) : (TXP_LAST_OFDM + 1))); + + wlc_phy_upd_env_txpwr_rate_limits(pi, band); + + for (rate = start_rate; rate < max_num_rate; rate++) { + + tx_pwr_target[rate] = pi->tx_user_target[rate]; + + if (pi->user_txpwr_at_rfport) + tx_pwr_target[rate] += + wlc_user_txpwr_antport_to_rfport(pi, + target_chan, + band, + rate); + + wlc_phy_txpower_sromlimit((struct brcms_phy_pub *) pi, + target_chan, + &mintxpwr, &maxtxpwr, rate); + + maxtxpwr = min(maxtxpwr, pi->txpwr_limit[rate]); + + maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0; + + maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0; + + maxtxpwr = min(maxtxpwr, tx_pwr_target[rate]); + + if (pi->txpwr_percent <= 100) + maxtxpwr = (maxtxpwr * pi->txpwr_percent) / 100; + + tx_pwr_target[rate] = max(maxtxpwr, mintxpwr); + + tx_pwr_target[rate] = + min(tx_pwr_target[rate], pi->txpwr_env_limit[rate]); + + if (tx_pwr_target[rate] > tx_pwr_max) + tx_pwr_max_rate_ind = rate; + + tx_pwr_max = max(tx_pwr_max, tx_pwr_target[rate]); + tx_pwr_min = min(tx_pwr_min, tx_pwr_target[rate]); + } + + memset(pi->tx_power_offset, 0, sizeof(pi->tx_power_offset)); + pi->tx_power_max = tx_pwr_max; + pi->tx_power_min = tx_pwr_min; + pi->tx_power_max_rate_ind = tx_pwr_max_rate_ind; + for (rate = 0; rate < max_num_rate; rate++) { + + pi->tx_power_target[rate] = tx_pwr_target[rate]; + + if (!pi->hwpwrctrl || ISNPHY(pi)) + pi->tx_power_offset[rate] = + pi->tx_power_max - pi->tx_power_target[rate]; + else + pi->tx_power_offset[rate] = + pi->tx_power_target[rate] - pi->tx_power_min; + } + + txpwr_recalc_fn = pi->pi_fptr.txpwrrecalc; + if (txpwr_recalc_fn) + (*txpwr_recalc_fn)(pi); +} + +static void +wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr, + u16 chanspec) +{ + u8 tmp_txpwr_limit[2 * BRCMS_NUM_RATES_OFDM]; + u8 *txpwr_ptr1 = NULL, *txpwr_ptr2 = NULL; + int rate_start_index = 0, rate1, rate2, k; + + for (rate1 = WL_TX_POWER_CCK_FIRST, rate2 = 0; + rate2 < WL_TX_POWER_CCK_NUM; rate1++, rate2++) + pi->txpwr_limit[rate1] = txpwr->cck[rate2]; + + for (rate1 = WL_TX_POWER_OFDM_FIRST, rate2 = 0; + rate2 < WL_TX_POWER_OFDM_NUM; rate1++, rate2++) + pi->txpwr_limit[rate1] = txpwr->ofdm[rate2]; + + if (ISNPHY(pi)) { + + for (k = 0; k < 4; k++) { + switch (k) { + case 0: + + txpwr_ptr1 = txpwr->mcs_20_siso; + txpwr_ptr2 = txpwr->ofdm; + rate_start_index = WL_TX_POWER_OFDM_FIRST; + break; + case 1: + + txpwr_ptr1 = txpwr->mcs_20_cdd; + txpwr_ptr2 = txpwr->ofdm_cdd; + rate_start_index = WL_TX_POWER_OFDM20_CDD_FIRST; + break; + case 2: + + txpwr_ptr1 = txpwr->mcs_40_siso; + txpwr_ptr2 = txpwr->ofdm_40_siso; + rate_start_index = + WL_TX_POWER_OFDM40_SISO_FIRST; + break; + case 3: + + txpwr_ptr1 = txpwr->mcs_40_cdd; + txpwr_ptr2 = txpwr->ofdm_40_cdd; + rate_start_index = WL_TX_POWER_OFDM40_CDD_FIRST; + break; + } + + for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM; + rate2++) { + tmp_txpwr_limit[rate2] = 0; + tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] = + txpwr_ptr1[rate2]; + } + wlc_phy_mcs_to_ofdm_powers_nphy( + tmp_txpwr_limit, 0, + BRCMS_NUM_RATES_OFDM - + 1, BRCMS_NUM_RATES_OFDM); + for (rate1 = rate_start_index, rate2 = 0; + rate2 < BRCMS_NUM_RATES_OFDM; rate1++, rate2++) + pi->txpwr_limit[rate1] = + min(txpwr_ptr2[rate2], + tmp_txpwr_limit[rate2]); + } + + for (k = 0; k < 4; k++) { + switch (k) { + case 0: + + txpwr_ptr1 = txpwr->ofdm; + txpwr_ptr2 = txpwr->mcs_20_siso; + rate_start_index = WL_TX_POWER_MCS20_SISO_FIRST; + break; + case 1: + + txpwr_ptr1 = txpwr->ofdm_cdd; + txpwr_ptr2 = txpwr->mcs_20_cdd; + rate_start_index = WL_TX_POWER_MCS20_CDD_FIRST; + break; + case 2: + + txpwr_ptr1 = txpwr->ofdm_40_siso; + txpwr_ptr2 = txpwr->mcs_40_siso; + rate_start_index = WL_TX_POWER_MCS40_SISO_FIRST; + break; + case 3: + + txpwr_ptr1 = txpwr->ofdm_40_cdd; + txpwr_ptr2 = txpwr->mcs_40_cdd; + rate_start_index = WL_TX_POWER_MCS40_CDD_FIRST; + break; + } + for (rate2 = 0; rate2 < BRCMS_NUM_RATES_OFDM; + rate2++) { + tmp_txpwr_limit[rate2] = 0; + tmp_txpwr_limit[BRCMS_NUM_RATES_OFDM + rate2] = + txpwr_ptr1[rate2]; + } + wlc_phy_ofdm_to_mcs_powers_nphy( + tmp_txpwr_limit, 0, + BRCMS_NUM_RATES_OFDM - + 1, BRCMS_NUM_RATES_OFDM); + for (rate1 = rate_start_index, rate2 = 0; + rate2 < BRCMS_NUM_RATES_MCS_1_STREAM; + rate1++, rate2++) + pi->txpwr_limit[rate1] = + min(txpwr_ptr2[rate2], + tmp_txpwr_limit[rate2]); + } + + for (k = 0; k < 2; k++) { + switch (k) { + case 0: + + rate_start_index = WL_TX_POWER_MCS20_STBC_FIRST; + txpwr_ptr1 = txpwr->mcs_20_stbc; + break; + case 1: + + rate_start_index = WL_TX_POWER_MCS40_STBC_FIRST; + txpwr_ptr1 = txpwr->mcs_40_stbc; + break; + } + for (rate1 = rate_start_index, rate2 = 0; + rate2 < BRCMS_NUM_RATES_MCS_1_STREAM; + rate1++, rate2++) + pi->txpwr_limit[rate1] = txpwr_ptr1[rate2]; + } + + for (k = 0; k < 2; k++) { + switch (k) { + case 0: + + rate_start_index = WL_TX_POWER_MCS20_SDM_FIRST; + txpwr_ptr1 = txpwr->mcs_20_mimo; + break; + case 1: + + rate_start_index = WL_TX_POWER_MCS40_SDM_FIRST; + txpwr_ptr1 = txpwr->mcs_40_mimo; + break; + } + for (rate1 = rate_start_index, rate2 = 0; + rate2 < BRCMS_NUM_RATES_MCS_2_STREAM; + rate1++, rate2++) + pi->txpwr_limit[rate1] = txpwr_ptr1[rate2]; + } + + pi->txpwr_limit[WL_TX_POWER_MCS_32] = txpwr->mcs32; + + pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST] = + min(pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST], + pi->txpwr_limit[WL_TX_POWER_MCS_32]); + pi->txpwr_limit[WL_TX_POWER_MCS_32] = + pi->txpwr_limit[WL_TX_POWER_MCS40_CDD_FIRST]; + } +} + +void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + pi->txpwr_percent = txpwr_percent; +} + +void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + pi->sh->machwcap = machwcap; +} + +void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + u16 rxc; + rxc = 0; + + if (start_end == ON) { + if (!ISNPHY(pi)) + return; + + if (NREV_IS(pi->pubpi.phy_rev, 3) + || NREV_IS(pi->pubpi.phy_rev, 4)) { + W_REG(&pi->regs->phyregaddr, 0xa0); + (void)R_REG(&pi->regs->phyregaddr); + rxc = R_REG(&pi->regs->phyregdata); + W_REG(&pi->regs->phyregdata, + (0x1 << 15) | rxc); + } + } else { + if (NREV_IS(pi->pubpi.phy_rev, 3) + || NREV_IS(pi->pubpi.phy_rev, 4)) { + W_REG(&pi->regs->phyregaddr, 0xa0); + (void)R_REG(&pi->regs->phyregaddr); + W_REG(&pi->regs->phyregdata, rxc); + } + + wlc_phy_por_inform(ppi); + } +} + +void +wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, + u16 chanspec) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + wlc_phy_txpower_reg_limit_calc(pi, txpwr, chanspec); + + if (ISLCNPHY(pi)) { + int i, j; + for (i = TXP_FIRST_OFDM_20_CDD, j = 0; + j < BRCMS_NUM_RATES_MCS_1_STREAM; i++, j++) { + if (txpwr->mcs_20_siso[j]) + pi->txpwr_limit[i] = txpwr->mcs_20_siso[j]; + else + pi->txpwr_limit[i] = txpwr->ofdm[j]; + } + } + + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + wlc_phy_txpower_recalc_target(pi); + wlc_phy_cal_txpower_recalc_sw(pi); + wlapi_enable_mac(pi->sh->physhim); +} + +void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + pi->ofdm_rateset_war = war; +} + +void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + pi->bf_preempt_4306 = bf_preempt; +} + +void wlc_phy_txpower_update_shm(struct brcms_phy *pi) +{ + int j; + if (ISNPHY(pi)) + return; + + if (!pi->sh->clk) + return; + + if (pi->hwpwrctrl) { + u16 offset; + + wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_MAX, 63); + wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_N, + 1 << NUM_TSSI_FRAMES); + + wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_TARGET, + pi->tx_power_min << NUM_TSSI_FRAMES); + + wlapi_bmac_write_shm(pi->sh->physhim, M_TXPWR_CUR, + pi->hwpwr_txcur); + + for (j = TXP_FIRST_OFDM; j <= TXP_LAST_OFDM; j++) { + const u8 ucode_ofdm_rates[] = { + 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c + }; + offset = wlapi_bmac_rate_shm_offset( + pi->sh->physhim, + ucode_ofdm_rates[j - TXP_FIRST_OFDM]); + wlapi_bmac_write_shm(pi->sh->physhim, offset + 6, + pi->tx_power_offset[j]); + wlapi_bmac_write_shm(pi->sh->physhim, offset + 14, + -(pi->tx_power_offset[j] / 2)); + } + + wlapi_bmac_mhf(pi->sh->physhim, MHF2, MHF2_HWPWRCTL, + MHF2_HWPWRCTL, BRCM_BAND_ALL); + } else { + int i; + + for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) + pi->tx_power_offset[i] = + (u8) roundup(pi->tx_power_offset[i], 8); + wlapi_bmac_write_shm(pi->sh->physhim, M_OFDM_OFFSET, + (u16) + ((pi->tx_power_offset[TXP_FIRST_OFDM] + + 7) >> 3)); + } +} + +bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + if (ISNPHY(pi)) + return pi->nphy_txpwrctrl; + else + return pi->hwpwrctrl; +} + +void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + bool suspend; + + if (!pi->hwpwrctrl_capable) + return; + + pi->hwpwrctrl = hwpwrctrl; + pi->nphy_txpwrctrl = hwpwrctrl; + pi->txpwrctrl = hwpwrctrl; + + if (ISNPHY(pi)) { + suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl); + if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) + wlc_phy_txpwr_fixpower_nphy(pi); + else + mod_phy_reg(pi, 0x1e7, (0x7f << 0), + pi->saved_txpwr_idx); + + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); + } +} + +void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi) +{ + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + pi->ipa2g_on = (pi->srom_fem2g.extpagain == 2); + pi->ipa5g_on = (pi->srom_fem5g.extpagain == 2); + } else { + pi->ipa2g_on = false; + pi->ipa5g_on = false; + } +} + +static u32 wlc_phy_txpower_est_power_nphy(struct brcms_phy *pi) +{ + s16 tx0_status, tx1_status; + u16 estPower1, estPower2; + u8 pwr0, pwr1, adj_pwr0, adj_pwr1; + u32 est_pwr; + + estPower1 = read_phy_reg(pi, 0x118); + estPower2 = read_phy_reg(pi, 0x119); + + if ((estPower1 & (0x1 << 8)) == (0x1 << 8)) + pwr0 = (u8) (estPower1 & (0xff << 0)) >> 0; + else + pwr0 = 0x80; + + if ((estPower2 & (0x1 << 8)) == (0x1 << 8)) + pwr1 = (u8) (estPower2 & (0xff << 0)) >> 0; + else + pwr1 = 0x80; + + tx0_status = read_phy_reg(pi, 0x1ed); + tx1_status = read_phy_reg(pi, 0x1ee); + + if ((tx0_status & (0x1 << 15)) == (0x1 << 15)) + adj_pwr0 = (u8) (tx0_status & (0xff << 0)) >> 0; + else + adj_pwr0 = 0x80; + if ((tx1_status & (0x1 << 15)) == (0x1 << 15)) + adj_pwr1 = (u8) (tx1_status & (0xff << 0)) >> 0; + else + adj_pwr1 = 0x80; + + est_pwr = (u32) ((pwr0 << 24) | (pwr1 << 16) | (adj_pwr0 << 8) | + adj_pwr1); + + return est_pwr; +} + +void +wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, + uint channel) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + uint rate, num_rates; + u8 min_pwr, max_pwr; + +#if WL_TX_POWER_RATES != TXP_NUM_RATES +#error "struct tx_power out of sync with this fn" +#endif + + if (ISNPHY(pi)) { + power->rf_cores = 2; + power->flags |= (WL_TX_POWER_F_MIMO); + if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON) + power->flags |= + (WL_TX_POWER_F_ENABLED | WL_TX_POWER_F_HW); + } else if (ISLCNPHY(pi)) { + power->rf_cores = 1; + power->flags |= (WL_TX_POWER_F_SISO); + if (pi->radiopwr_override == RADIOPWR_OVERRIDE_DEF) + power->flags |= WL_TX_POWER_F_ENABLED; + if (pi->hwpwrctrl) + power->flags |= WL_TX_POWER_F_HW; + } + + num_rates = ((ISNPHY(pi)) ? (TXP_NUM_RATES) : + ((ISLCNPHY(pi)) ? + (TXP_LAST_OFDM_20_CDD + 1) : (TXP_LAST_OFDM + 1))); + + for (rate = 0; rate < num_rates; rate++) { + power->user_limit[rate] = pi->tx_user_target[rate]; + wlc_phy_txpower_sromlimit(ppi, channel, &min_pwr, &max_pwr, + rate); + power->board_limit[rate] = (u8) max_pwr; + power->target[rate] = pi->tx_power_target[rate]; + } + + if (ISNPHY(pi)) { + u32 est_pout; + + wlapi_suspend_mac_and_wait(pi->sh->physhim); + wlc_phyreg_enter((struct brcms_phy_pub *) pi); + est_pout = wlc_phy_txpower_est_power_nphy(pi); + wlc_phyreg_exit((struct brcms_phy_pub *) pi); + wlapi_enable_mac(pi->sh->physhim); + + power->est_Pout[0] = (est_pout >> 8) & 0xff; + power->est_Pout[1] = est_pout & 0xff; + + power->est_Pout_act[0] = est_pout >> 24; + power->est_Pout_act[1] = (est_pout >> 16) & 0xff; + + if (power->est_Pout[0] == 0x80) + power->est_Pout[0] = 0; + if (power->est_Pout[1] == 0x80) + power->est_Pout[1] = 0; + + if (power->est_Pout_act[0] == 0x80) + power->est_Pout_act[0] = 0; + if (power->est_Pout_act[1] == 0x80) + power->est_Pout_act[1] = 0; + + power->est_Pout_cck = 0; + + power->tx_power_max[0] = pi->tx_power_max; + power->tx_power_max[1] = pi->tx_power_max; + + power->tx_power_max_rate_ind[0] = pi->tx_power_max_rate_ind; + power->tx_power_max_rate_ind[1] = pi->tx_power_max_rate_ind; + } else if (pi->hwpwrctrl && pi->sh->up) { + + wlc_phyreg_enter(ppi); + if (ISLCNPHY(pi)) { + + power->tx_power_max[0] = pi->tx_power_max; + power->tx_power_max[1] = pi->tx_power_max; + + power->tx_power_max_rate_ind[0] = + pi->tx_power_max_rate_ind; + power->tx_power_max_rate_ind[1] = + pi->tx_power_max_rate_ind; + + if (wlc_phy_tpc_isenabled_lcnphy(pi)) + power->flags |= + (WL_TX_POWER_F_HW | + WL_TX_POWER_F_ENABLED); + else + power->flags &= + ~(WL_TX_POWER_F_HW | + WL_TX_POWER_F_ENABLED); + + wlc_lcnphy_get_tssi(pi, (s8 *) &power->est_Pout[0], + (s8 *) &power->est_Pout_cck); + } + wlc_phyreg_exit(ppi); + } +} + +void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + pi->antsel_type = antsel_type; +} + +bool wlc_phy_test_ison(struct brcms_phy_pub *ppi) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + return pi->phytest_on; +} + +void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + bool suspend; + + pi->sh->rx_antdiv = val; + + if (!(ISNPHY(pi) && D11REV_IS(pi->sh->corerev, 16))) { + if (val > ANT_RX_DIV_FORCE_1) + wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, + MHF1_ANTDIV, BRCM_BAND_ALL); + else + wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_ANTDIV, 0, + BRCM_BAND_ALL); + } + + if (ISNPHY(pi)) + return; + + if (!pi->sh->clk) + return; + + suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + if (ISLCNPHY(pi)) { + if (val > ANT_RX_DIV_FORCE_1) { + mod_phy_reg(pi, 0x410, (0x1 << 1), 0x01 << 1); + mod_phy_reg(pi, 0x410, + (0x1 << 0), + ((ANT_RX_DIV_START_1 == val) ? 1 : 0) << 0); + } else { + mod_phy_reg(pi, 0x410, (0x1 << 1), 0x00 << 1); + mod_phy_reg(pi, 0x410, (0x1 << 0), (u16) val << 0); + } + } + + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); + + return; +} + +static bool +wlc_phy_noise_calc_phy(struct brcms_phy *pi, u32 *cmplx_pwr, s8 *pwr_ant) +{ + s8 cmplx_pwr_dbm[PHY_CORE_MAX]; + u8 i; + + memset((u8 *) cmplx_pwr_dbm, 0, sizeof(cmplx_pwr_dbm)); + wlc_phy_compute_dB(cmplx_pwr, cmplx_pwr_dbm, pi->pubpi.phy_corenum); + + for (i = 0; i < pi->pubpi.phy_corenum; i++) { + if (NREV_GE(pi->pubpi.phy_rev, 3)) + cmplx_pwr_dbm[i] += (s8) PHY_NOISE_OFFSETFACT_4322; + else + + cmplx_pwr_dbm[i] += (s8) (16 - (15) * 3 - 70); + } + + for (i = 0; i < pi->pubpi.phy_corenum; i++) { + pi->nphy_noise_win[i][pi->nphy_noise_index] = cmplx_pwr_dbm[i]; + pwr_ant[i] = cmplx_pwr_dbm[i]; + } + pi->nphy_noise_index = + MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ); + return true; +} + +static void wlc_phy_noise_cb(struct brcms_phy *pi, u8 channel, s8 noise_dbm) +{ + if (!pi->phynoise_state) + return; + + if (pi->phynoise_state & PHY_NOISE_STATE_MON) { + if (pi->phynoise_chan_watchdog == channel) { + pi->sh->phy_noise_window[pi->sh->phy_noise_index] = + noise_dbm; + pi->sh->phy_noise_index = + MODINC(pi->sh->phy_noise_index, MA_WINDOW_SZ); + } + pi->phynoise_state &= ~PHY_NOISE_STATE_MON; + } + + if (pi->phynoise_state & PHY_NOISE_STATE_EXTERNAL) + pi->phynoise_state &= ~PHY_NOISE_STATE_EXTERNAL; + +} + +static s8 wlc_phy_noise_read_shmem(struct brcms_phy *pi) +{ + u32 cmplx_pwr[PHY_CORE_MAX]; + s8 noise_dbm_ant[PHY_CORE_MAX]; + u16 lo, hi; + u32 cmplx_pwr_tot = 0; + s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; + u8 idx, core; + + memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr)); + memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant)); + + for (idx = 0, core = 0; core < pi->pubpi.phy_corenum; idx += 2, + core++) { + lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP(idx)); + hi = wlapi_bmac_read_shm(pi->sh->physhim, + M_PWRIND_MAP(idx + 1)); + cmplx_pwr[core] = (hi << 16) + lo; + cmplx_pwr_tot += cmplx_pwr[core]; + if (cmplx_pwr[core] == 0) + noise_dbm_ant[core] = PHY_NOISE_FIXED_VAL_NPHY; + else + cmplx_pwr[core] >>= PHY_NOISE_SAMPLE_LOG_NUM_UCODE; + } + + if (cmplx_pwr_tot != 0) + wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant); + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + pi->nphy_noise_win[core][pi->nphy_noise_index] = + noise_dbm_ant[core]; + + if (noise_dbm_ant[core] > noise_dbm) + noise_dbm = noise_dbm_ant[core]; + } + pi->nphy_noise_index = + MODINC_POW2(pi->nphy_noise_index, PHY_NOISE_WINDOW_SZ); + + return noise_dbm; + +} + +void wlc_phy_noise_sample_intr(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + u16 jssi_aux; + u8 channel = 0; + s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; + + if (ISLCNPHY(pi)) { + u32 cmplx_pwr, cmplx_pwr0, cmplx_pwr1; + u16 lo, hi; + s32 pwr_offset_dB, gain_dB; + u16 status_0, status_1; + + jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX); + channel = jssi_aux & D11_CURCHANNEL_MAX; + + lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP0); + hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP1); + cmplx_pwr0 = (hi << 16) + lo; + + lo = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP2); + hi = wlapi_bmac_read_shm(pi->sh->physhim, M_PWRIND_MAP3); + cmplx_pwr1 = (hi << 16) + lo; + cmplx_pwr = (cmplx_pwr0 + cmplx_pwr1) >> 6; + + status_0 = 0x44; + status_1 = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_0); + if ((cmplx_pwr > 0 && cmplx_pwr < 500) + && ((status_1 & 0xc000) == 0x4000)) { + + wlc_phy_compute_dB(&cmplx_pwr, &noise_dbm, + pi->pubpi.phy_corenum); + pwr_offset_dB = (read_phy_reg(pi, 0x434) & 0xFF); + if (pwr_offset_dB > 127) + pwr_offset_dB -= 256; + + noise_dbm += (s8) (pwr_offset_dB - 30); + + gain_dB = (status_0 & 0x1ff); + noise_dbm -= (s8) (gain_dB); + } else { + noise_dbm = PHY_NOISE_FIXED_VAL_LCNPHY; + } + } else if (ISNPHY(pi)) { + + jssi_aux = wlapi_bmac_read_shm(pi->sh->physhim, M_JSSI_AUX); + channel = jssi_aux & D11_CURCHANNEL_MAX; + + noise_dbm = wlc_phy_noise_read_shmem(pi); + } + + wlc_phy_noise_cb(pi, channel, noise_dbm); + +} + +static void +wlc_phy_noise_sample_request(struct brcms_phy_pub *pih, u8 reason, u8 ch) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + s8 noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; + bool sampling_in_progress = (pi->phynoise_state != 0); + bool wait_for_intr = true; + + switch (reason) { + case PHY_NOISE_SAMPLE_MON: + pi->phynoise_chan_watchdog = ch; + pi->phynoise_state |= PHY_NOISE_STATE_MON; + break; + + case PHY_NOISE_SAMPLE_EXTERNAL: + pi->phynoise_state |= PHY_NOISE_STATE_EXTERNAL; + break; + + default: + break; + } + + if (sampling_in_progress) + return; + + pi->phynoise_now = pi->sh->now; + + if (pi->phy_fixed_noise) { + if (ISNPHY(pi)) { + pi->nphy_noise_win[WL_ANT_IDX_1][pi->nphy_noise_index] = + PHY_NOISE_FIXED_VAL_NPHY; + pi->nphy_noise_win[WL_ANT_IDX_2][pi->nphy_noise_index] = + PHY_NOISE_FIXED_VAL_NPHY; + pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index, + PHY_NOISE_WINDOW_SZ); + noise_dbm = PHY_NOISE_FIXED_VAL_NPHY; + } else { + noise_dbm = PHY_NOISE_FIXED_VAL; + } + + wait_for_intr = false; + goto done; + } + + if (ISLCNPHY(pi)) { + if (!pi->phynoise_polling + || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) { + wlapi_bmac_write_shm(pi->sh->physhim, M_JSSI_0, 0); + wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0); + wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0); + wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0); + wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0); + + OR_REG(&pi->regs->maccommand, + MCMD_BG_NOISE); + } else { + wlapi_suspend_mac_and_wait(pi->sh->physhim); + wlc_lcnphy_deaf_mode(pi, (bool) 0); + noise_dbm = (s8) wlc_lcnphy_rx_signal_power(pi, 20); + wlc_lcnphy_deaf_mode(pi, (bool) 1); + wlapi_enable_mac(pi->sh->physhim); + wait_for_intr = false; + } + } else if (ISNPHY(pi)) { + if (!pi->phynoise_polling + || (reason == PHY_NOISE_SAMPLE_EXTERNAL)) { + + wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP0, 0); + wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP1, 0); + wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP2, 0); + wlapi_bmac_write_shm(pi->sh->physhim, M_PWRIND_MAP3, 0); + + OR_REG(&pi->regs->maccommand, + MCMD_BG_NOISE); + } else { + struct phy_iq_est est[PHY_CORE_MAX]; + u32 cmplx_pwr[PHY_CORE_MAX]; + s8 noise_dbm_ant[PHY_CORE_MAX]; + u16 log_num_samps, num_samps, classif_state = 0; + u8 wait_time = 32; + u8 wait_crs = 0; + u8 i; + + memset((u8 *) est, 0, sizeof(est)); + memset((u8 *) cmplx_pwr, 0, sizeof(cmplx_pwr)); + memset((u8 *) noise_dbm_ant, 0, sizeof(noise_dbm_ant)); + + log_num_samps = PHY_NOISE_SAMPLE_LOG_NUM_NPHY; + num_samps = 1 << log_num_samps; + + wlapi_suspend_mac_and_wait(pi->sh->physhim); + classif_state = wlc_phy_classifier_nphy(pi, 0, 0); + wlc_phy_classifier_nphy(pi, 3, 0); + wlc_phy_rx_iq_est_nphy(pi, est, num_samps, wait_time, + wait_crs); + wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state); + wlapi_enable_mac(pi->sh->physhim); + + for (i = 0; i < pi->pubpi.phy_corenum; i++) + cmplx_pwr[i] = (est[i].i_pwr + est[i].q_pwr) >> + log_num_samps; + + wlc_phy_noise_calc_phy(pi, cmplx_pwr, noise_dbm_ant); + + for (i = 0; i < pi->pubpi.phy_corenum; i++) { + pi->nphy_noise_win[i][pi->nphy_noise_index] = + noise_dbm_ant[i]; + + if (noise_dbm_ant[i] > noise_dbm) + noise_dbm = noise_dbm_ant[i]; + } + pi->nphy_noise_index = MODINC_POW2(pi->nphy_noise_index, + PHY_NOISE_WINDOW_SZ); + + wait_for_intr = false; + } + } + +done: + + if (!wait_for_intr) + wlc_phy_noise_cb(pi, ch, noise_dbm); + +} + +void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih) +{ + u8 channel; + + channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih)); + + wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel); +} + +static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = { + 8, + 8, + 8, + 8, + 8, + 8, + 8, + 9, + 10, + 8, + 8, + 7, + 7, + 1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 1, + 1, + 0, + 0, + 0, + 0 +}; + +void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_cmplx_pwr_dB, u8 core) +{ + u8 msb, secondmsb, i; + u32 tmp; + + for (i = 0; i < core; i++) { + secondmsb = 0; + tmp = cmplx_pwr[i]; + msb = fls(tmp); + if (msb) + secondmsb = (u8) ((tmp >> (--msb - 1)) & 1); + p_cmplx_pwr_dB[i] = (s8) (3 * msb + 2 * secondmsb); + } +} + +int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, + struct d11rxhdr *rxh) +{ + int rssi = rxh->PhyRxStatus_1 & PRXS1_JSSI_MASK; + uint radioid = pih->radioid; + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if ((pi->sh->corerev >= 11) + && !(rxh->RxStatus2 & RXS_PHYRXST_VALID)) { + rssi = BRCMS_RSSI_INVALID; + goto end; + } + + if (ISLCNPHY(pi)) { + u8 gidx = (rxh->PhyRxStatus_2 & 0xFC00) >> 10; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + if (rssi > 127) + rssi -= 256; + + rssi = rssi + lcnphy_gain_index_offset_for_pkt_rssi[gidx]; + if ((rssi > -46) && (gidx > 18)) + rssi = rssi + 7; + + rssi = rssi + pi_lcn->lcnphy_pkteng_rssi_slope; + + rssi = rssi + 2; + + } + + if (ISLCNPHY(pi)) { + if (rssi > 127) + rssi -= 256; + } else if (radioid == BCM2055_ID || radioid == BCM2056_ID + || radioid == BCM2057_ID) { + rssi = wlc_phy_rssi_compute_nphy(pi, rxh); + } + +end: + return rssi; +} + +void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih) +{ + return; +} + +void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih) +{ + return; +} + +void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag) +{ + struct brcms_phy *pi; + pi = (struct brcms_phy *) ppi; + + if (ISLCNPHY(pi)) + wlc_lcnphy_deaf_mode(pi, true); + else if (ISNPHY(pi)) + wlc_nphy_deaf_mode(pi, true); +} + +void wlc_phy_watchdog(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + bool delay_phy_cal = false; + pi->sh->now++; + + if (!pi->watchdog_override) + return; + + if (!(SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi))) + wlc_phy_noise_sample_request((struct brcms_phy_pub *) pi, + PHY_NOISE_SAMPLE_MON, + CHSPEC_CHANNEL(pi-> + radio_chanspec)); + + if (pi->phynoise_state && (pi->sh->now - pi->phynoise_now) > 5) + pi->phynoise_state = 0; + + if ((!pi->phycal_txpower) || + ((pi->sh->now - pi->phycal_txpower) >= pi->sh->fast_timer)) { + + if (!SCAN_INPROG_PHY(pi) && wlc_phy_cal_txpower_recalc_sw(pi)) + pi->phycal_txpower = pi->sh->now; + } + + if ((SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) + || ASSOC_INPROG_PHY(pi))) + return; + + if (ISNPHY(pi) && !pi->disable_percal && !delay_phy_cal) { + + if ((pi->nphy_perical != PHY_PERICAL_DISABLE) && + (pi->nphy_perical != PHY_PERICAL_MANUAL) && + ((pi->sh->now - pi->nphy_perical_last) >= + pi->sh->glacial_timer)) + wlc_phy_cal_perical((struct brcms_phy_pub *) pi, + PHY_PERICAL_WATCHDOG); + + wlc_phy_txpwr_papd_cal_nphy(pi); + } + + if (ISLCNPHY(pi)) { + if (pi->phy_forcecal || + ((pi->sh->now - pi->phy_lastcal) >= + pi->sh->glacial_timer)) { + if (!(SCAN_RM_IN_PROGRESS(pi) || ASSOC_INPROG_PHY(pi))) + wlc_lcnphy_calib_modes( + pi, + LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL); + if (! + (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) + || ASSOC_INPROG_PHY(pi) + || pi->carrier_suppr_disable + || pi->disable_percal)) + wlc_lcnphy_calib_modes(pi, + PHY_PERICAL_WATCHDOG); + } + } +} + +void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + uint i; + uint k; + + for (i = 0; i < MA_WINDOW_SZ; i++) + pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff); + if (ISLCNPHY(pi)) { + for (i = 0; i < MA_WINDOW_SZ; i++) + pi->sh->phy_noise_window[i] = + PHY_NOISE_FIXED_VAL_LCNPHY; + } + pi->sh->phy_noise_index = 0; + + for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) { + for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++) + pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY; + } + pi->nphy_noise_index = 0; +} + +void +wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag) +{ + *eps_imag = (epsilon >> 13); + if (*eps_imag > 0xfff) + *eps_imag -= 0x2000; + + *eps_real = (epsilon & 0x1fff); + if (*eps_real > 0xfff) + *eps_real -= 0x2000; +} + +void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi) +{ + wlapi_del_timer(pi->phycal_timer); + + pi->cal_type_override = PHY_PERICAL_AUTO; + pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE; + pi->mphase_txcal_cmdidx = 0; +} + +static void +wlc_phy_cal_perical_mphase_schedule(struct brcms_phy *pi, uint delay) +{ + + if ((pi->nphy_perical != PHY_PERICAL_MPHASE) && + (pi->nphy_perical != PHY_PERICAL_MANUAL)) + return; + + wlapi_del_timer(pi->phycal_timer); + + pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT; + wlapi_add_timer(pi->phycal_timer, delay, 0); +} + +void wlc_phy_cal_perical(struct brcms_phy_pub *pih, u8 reason) +{ + s16 nphy_currtemp = 0; + s16 delta_temp = 0; + bool do_periodic_cal = true; + struct brcms_phy *pi = (struct brcms_phy *) pih; + + if (!ISNPHY(pi)) + return; + + if ((pi->nphy_perical == PHY_PERICAL_DISABLE) || + (pi->nphy_perical == PHY_PERICAL_MANUAL)) + return; + + switch (reason) { + case PHY_PERICAL_DRIVERUP: + break; + + case PHY_PERICAL_PHYINIT: + if (pi->nphy_perical == PHY_PERICAL_MPHASE) { + if (PHY_PERICAL_MPHASE_PENDING(pi)) + wlc_phy_cal_perical_mphase_reset(pi); + + wlc_phy_cal_perical_mphase_schedule( + pi, + PHY_PERICAL_INIT_DELAY); + } + break; + + case PHY_PERICAL_JOIN_BSS: + case PHY_PERICAL_START_IBSS: + case PHY_PERICAL_UP_BSS: + if ((pi->nphy_perical == PHY_PERICAL_MPHASE) && + PHY_PERICAL_MPHASE_PENDING(pi)) + wlc_phy_cal_perical_mphase_reset(pi); + + pi->first_cal_after_assoc = true; + + pi->cal_type_override = PHY_PERICAL_FULL; + + if (pi->phycal_tempdelta) + pi->nphy_lastcal_temp = wlc_phy_tempsense_nphy(pi); + + wlc_phy_cal_perical_nphy_run(pi, PHY_PERICAL_FULL); + break; + + case PHY_PERICAL_WATCHDOG: + if (pi->phycal_tempdelta) { + nphy_currtemp = wlc_phy_tempsense_nphy(pi); + delta_temp = + (nphy_currtemp > pi->nphy_lastcal_temp) ? + nphy_currtemp - pi->nphy_lastcal_temp : + pi->nphy_lastcal_temp - nphy_currtemp; + + if ((delta_temp < (s16) pi->phycal_tempdelta) && + (pi->nphy_txiqlocal_chanspec == + pi->radio_chanspec)) + do_periodic_cal = false; + else + pi->nphy_lastcal_temp = nphy_currtemp; + } + + if (do_periodic_cal) { + if (pi->nphy_perical == PHY_PERICAL_MPHASE) { + if (!PHY_PERICAL_MPHASE_PENDING(pi)) + wlc_phy_cal_perical_mphase_schedule( + pi, + PHY_PERICAL_WDOG_DELAY); + } else if (pi->nphy_perical == PHY_PERICAL_SPHASE) + wlc_phy_cal_perical_nphy_run(pi, + PHY_PERICAL_AUTO); + } + break; + default: + break; + } +} + +void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi) +{ + pi->mphase_cal_phase_id = MPHASE_CAL_STATE_INIT; + pi->mphase_txcal_cmdidx = 0; +} + +u8 wlc_phy_nbits(s32 value) +{ + s32 abs_val; + u8 nbits = 0; + + abs_val = abs(value); + while ((abs_val >> nbits) > 0) + nbits++; + + return nbits; +} + +void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + pi->sh->hw_phytxchain = txchain; + pi->sh->hw_phyrxchain = rxchain; + pi->sh->phytxchain = txchain; + pi->sh->phyrxchain = rxchain; + pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain); +} + +void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + pi->sh->phytxchain = txchain; + + if (ISNPHY(pi)) + wlc_phy_rxcore_setstate_nphy(pih, rxchain); + + pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain); +} + +void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + + *txchain = pi->sh->phytxchain; + *rxchain = pi->sh->phyrxchain; +} + +u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) +{ + s16 nphy_currtemp; + u8 active_bitmap; + struct brcms_phy *pi = (struct brcms_phy *) pih; + + active_bitmap = (pi->phy_txcore_heatedup) ? 0x31 : 0x33; + + if (!pi->watchdog_override) + return active_bitmap; + + if (NREV_GE(pi->pubpi.phy_rev, 6)) { + wlapi_suspend_mac_and_wait(pi->sh->physhim); + nphy_currtemp = wlc_phy_tempsense_nphy(pi); + wlapi_enable_mac(pi->sh->physhim); + + if (!pi->phy_txcore_heatedup) { + if (nphy_currtemp >= pi->phy_txcore_disable_temp) { + active_bitmap &= 0xFD; + pi->phy_txcore_heatedup = true; + } + } else { + if (nphy_currtemp <= pi->phy_txcore_enable_temp) { + active_bitmap |= 0x2; + pi->phy_txcore_heatedup = false; + } + } + } + + return active_bitmap; +} + +s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + u8 siso_mcs_id, cdd_mcs_id; + + siso_mcs_id = + (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO : + TXP_FIRST_MCS_20_SISO; + cdd_mcs_id = + (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD : + TXP_FIRST_MCS_20_CDD; + + if (pi->tx_power_target[siso_mcs_id] > + (pi->tx_power_target[cdd_mcs_id] + 12)) + return PHY_TXC1_MODE_SISO; + else + return PHY_TXC1_MODE_CDD; +} + +const u8 *wlc_phy_get_ofdm_rate_lookup(void) +{ + return ofdm_rate_lookup; +} + +void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) +{ + if ((pi->sh->chip == BCM4313_CHIP_ID) && + (pi->sh->boardflags & BFL_FEM)) { + if (mode) { + u16 txant = 0; + txant = wlapi_bmac_get_txant(pi->sh->physhim); + if (txant == 1) { + mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2); + + mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2); + + } + ai_corereg(pi->sh->sih, SI_CC_IDX, + offsetof(struct chipcregs, gpiocontrol), + ~0x0, 0x0); + ai_corereg(pi->sh->sih, SI_CC_IDX, + offsetof(struct chipcregs, gpioout), 0x40, + 0x40); + ai_corereg(pi->sh->sih, SI_CC_IDX, + offsetof(struct chipcregs, gpioouten), 0x40, + 0x40); + } else { + mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2); + + mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2); + + ai_corereg(pi->sh->sih, SI_CC_IDX, + offsetof(struct chipcregs, gpioout), 0x40, + 0x00); + ai_corereg(pi->sh->sih, SI_CC_IDX, + offsetof(struct chipcregs, gpioouten), 0x40, + 0x0); + ai_corereg(pi->sh->sih, SI_CC_IDX, + offsetof(struct chipcregs, gpiocontrol), + ~0x0, 0x40); + } + } +} + +void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc) +{ + return; +} + +void +wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset) +{ + *cckoffset = 0; + *ofdmoffset = 0; +} + +s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec) +{ + + return rssi; +} + +bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + if (ISNPHY(pi)) + return wlc_phy_n_txpower_ipa_ison(pi); + else + return 0; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h new file mode 100644 index 000000000000..96e15163222b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_hal.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +/* + * phy_hal.h: functionality exported from the phy to higher layers + */ + +#ifndef _BRCM_PHY_HAL_H_ +#define _BRCM_PHY_HAL_H_ + +#include <brcmu_utils.h> +#include <brcmu_wifi.h> +#include <phy_shim.h> + +#define IDCODE_VER_MASK 0x0000000f +#define IDCODE_VER_SHIFT 0 +#define IDCODE_MFG_MASK 0x00000fff +#define IDCODE_MFG_SHIFT 0 +#define IDCODE_ID_MASK 0x0ffff000 +#define IDCODE_ID_SHIFT 12 +#define IDCODE_REV_MASK 0xf0000000 +#define IDCODE_REV_SHIFT 28 + +#define NORADIO_ID 0xe4f5 +#define NORADIO_IDCODE 0x4e4f5246 + +#define BCM2055_ID 0x2055 +#define BCM2055_IDCODE 0x02055000 +#define BCM2055A0_IDCODE 0x1205517f + +#define BCM2056_ID 0x2056 +#define BCM2056_IDCODE 0x02056000 +#define BCM2056A0_IDCODE 0x1205617f + +#define BCM2057_ID 0x2057 +#define BCM2057_IDCODE 0x02057000 +#define BCM2057A0_IDCODE 0x1205717f + +#define BCM2064_ID 0x2064 +#define BCM2064_IDCODE 0x02064000 +#define BCM2064A0_IDCODE 0x0206417f + +#define PHY_TPC_HW_OFF false +#define PHY_TPC_HW_ON true + +#define PHY_PERICAL_DRIVERUP 1 +#define PHY_PERICAL_WATCHDOG 2 +#define PHY_PERICAL_PHYINIT 3 +#define PHY_PERICAL_JOIN_BSS 4 +#define PHY_PERICAL_START_IBSS 5 +#define PHY_PERICAL_UP_BSS 6 +#define PHY_PERICAL_CHAN 7 +#define PHY_FULLCAL 8 + +#define PHY_PERICAL_DISABLE 0 +#define PHY_PERICAL_SPHASE 1 +#define PHY_PERICAL_MPHASE 2 +#define PHY_PERICAL_MANUAL 3 + +#define PHY_HOLD_FOR_ASSOC 1 +#define PHY_HOLD_FOR_SCAN 2 +#define PHY_HOLD_FOR_RM 4 +#define PHY_HOLD_FOR_PLT 8 +#define PHY_HOLD_FOR_MUTE 16 +#define PHY_HOLD_FOR_NOT_ASSOC 0x20 + +#define PHY_MUTE_FOR_PREISM 1 +#define PHY_MUTE_ALL 0xffffffff + +#define PHY_NOISE_FIXED_VAL (-95) +#define PHY_NOISE_FIXED_VAL_NPHY (-92) +#define PHY_NOISE_FIXED_VAL_LCNPHY (-92) + +#define PHY_MODE_CAL 0x0002 +#define PHY_MODE_NOISEM 0x0004 + +#define BRCMS_TXPWR_DB_FACTOR 4 + +/* a large TX Power as an init value to factor out of min() calculations, + * keep low enough to fit in an s8, units are .25 dBm + */ +#define BRCMS_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ + +#define BRCMS_NUM_RATES_CCK 4 +#define BRCMS_NUM_RATES_OFDM 8 +#define BRCMS_NUM_RATES_MCS_1_STREAM 8 +#define BRCMS_NUM_RATES_MCS_2_STREAM 8 +#define BRCMS_NUM_RATES_MCS_3_STREAM 8 +#define BRCMS_NUM_RATES_MCS_4_STREAM 8 + +#define BRCMS_RSSI_INVALID 0 /* invalid RSSI value */ + +struct d11regs; +struct phy_shim_info; + +struct txpwr_limits { + u8 cck[BRCMS_NUM_RATES_CCK]; + u8 ofdm[BRCMS_NUM_RATES_OFDM]; + + u8 ofdm_cdd[BRCMS_NUM_RATES_OFDM]; + + u8 ofdm_40_siso[BRCMS_NUM_RATES_OFDM]; + u8 ofdm_40_cdd[BRCMS_NUM_RATES_OFDM]; + + u8 mcs_20_siso[BRCMS_NUM_RATES_MCS_1_STREAM]; + u8 mcs_20_cdd[BRCMS_NUM_RATES_MCS_1_STREAM]; + u8 mcs_20_stbc[BRCMS_NUM_RATES_MCS_1_STREAM]; + u8 mcs_20_mimo[BRCMS_NUM_RATES_MCS_2_STREAM]; + + u8 mcs_40_siso[BRCMS_NUM_RATES_MCS_1_STREAM]; + u8 mcs_40_cdd[BRCMS_NUM_RATES_MCS_1_STREAM]; + u8 mcs_40_stbc[BRCMS_NUM_RATES_MCS_1_STREAM]; + u8 mcs_40_mimo[BRCMS_NUM_RATES_MCS_2_STREAM]; + u8 mcs32; +}; + +struct tx_power { + u32 flags; + u16 chanspec; /* txpwr report for this channel */ + u16 local_chanspec; /* channel on which we are associated */ + u8 local_max; /* local max according to the AP */ + u8 local_constraint; /* local constraint according to the AP */ + s8 antgain[2]; /* Ant gain for each band - from SROM */ + u8 rf_cores; /* count of RF Cores being reported */ + u8 est_Pout[4]; /* Latest tx power out estimate per RF chain */ + u8 est_Pout_act[4]; /* Latest tx power out estimate per RF chain + * without adjustment */ + u8 est_Pout_cck; /* Latest CCK tx power out estimate */ + u8 tx_power_max[4]; /* Maximum target power among all rates */ + /* Index of the rate with the max target power */ + u8 tx_power_max_rate_ind[4]; + /* User limit */ + u8 user_limit[WL_TX_POWER_RATES]; + /* Regulatory power limit */ + u8 reg_limit[WL_TX_POWER_RATES]; + /* Max power board can support (SROM) */ + u8 board_limit[WL_TX_POWER_RATES]; + /* Latest target power */ + u8 target[WL_TX_POWER_RATES]; +}; + +struct tx_inst_power { + u8 txpwr_est_Pout[2]; /* Latest estimate for 2.4 and 5 Ghz */ + u8 txpwr_est_Pout_gofdm; /* Pwr estimate for 2.4 OFDM */ +}; + +struct brcms_chanvec { + u8 vec[MAXCHANNEL / NBBY]; +}; + +struct shared_phy_params { + struct si_pub *sih; + struct phy_shim_info *physhim; + uint unit; + uint corerev; + uint buscorerev; + u16 vid; + u16 did; + uint chip; + uint chiprev; + uint chippkg; + uint sromrev; + uint boardtype; + uint boardrev; + uint boardvendor; + u32 boardflags; + u32 boardflags2; +}; + + +extern struct shared_phy *wlc_phy_shared_attach(struct shared_phy_params *shp); +extern struct brcms_phy_pub *wlc_phy_attach(struct shared_phy *sh, + struct d11regs __iomem *regs, + int bandtype, struct wiphy *wiphy); +extern void wlc_phy_detach(struct brcms_phy_pub *ppi); + +extern bool wlc_phy_get_phyversion(struct brcms_phy_pub *pih, u16 *phytype, + u16 *phyrev, u16 *radioid, + u16 *radiover); +extern bool wlc_phy_get_encore(struct brcms_phy_pub *pih); +extern u32 wlc_phy_get_coreflags(struct brcms_phy_pub *pih); + +extern void wlc_phy_hw_clk_state_upd(struct brcms_phy_pub *ppi, bool newstate); +extern void wlc_phy_hw_state_upd(struct brcms_phy_pub *ppi, bool newstate); +extern void wlc_phy_init(struct brcms_phy_pub *ppi, u16 chanspec); +extern void wlc_phy_watchdog(struct brcms_phy_pub *ppi); +extern int wlc_phy_down(struct brcms_phy_pub *ppi); +extern u32 wlc_phy_clk_bwbits(struct brcms_phy_pub *pih); +extern void wlc_phy_cal_init(struct brcms_phy_pub *ppi); +extern void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init); + +extern void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, + u16 chanspec); +extern u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi); +extern void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, + u16 newch); +extern u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi); +extern void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw); + +extern int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, + struct d11rxhdr *rxh); +extern void wlc_phy_por_inform(struct brcms_phy_pub *ppi); +extern void wlc_phy_noise_sample_intr(struct brcms_phy_pub *ppi); +extern bool wlc_phy_bist_check_phy(struct brcms_phy_pub *ppi); + +extern void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag); + +extern void wlc_phy_switch_radio(struct brcms_phy_pub *ppi, bool on); +extern void wlc_phy_anacore(struct brcms_phy_pub *ppi, bool on); + + +extern void wlc_phy_BSSinit(struct brcms_phy_pub *ppi, bool bonlyap, int rssi); + +extern void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, + bool wide_filter); +extern void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, + struct brcms_chanvec *channels); +extern u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, + uint band); + +extern void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan, + u8 *_min_, u8 *_max_, int rate); +extern void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, + uint chan, u8 *_max_, u8 *_min_); +extern void wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, + uint band, s32 *, s32 *, u32 *); +extern void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, + struct txpwr_limits *, + u16 chanspec); +extern int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, + bool *override); +extern int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, + bool override); +extern void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, + struct txpwr_limits *); +extern bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi); +extern void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, + bool hwpwrctrl); +extern u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi); +extern u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi); +extern bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *pih); + +extern void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, + u8 rxchain); +extern void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, + u8 rxchain); +extern void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, + u8 *rxchain); +extern u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih); +extern s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, + u16 chanspec); +extern void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val); + +extern void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason); +extern void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *ppi); +extern void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock); +extern void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi); + +extern void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val); +extern void wlc_phy_clear_tssi(struct brcms_phy_pub *ppi); +extern void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, u32 id, bool val); +extern void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, u32 flags); + +extern void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type); + +extern void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, + struct tx_power *power, uint channel); + +extern void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal); +extern bool wlc_phy_test_ison(struct brcms_phy_pub *ppi); +extern void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, + u8 txpwr_percent); +extern void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war); +extern void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, + bool bf_preempt); +extern void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap); + +extern void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end); + +extern void wlc_phy_freqtrack_start(struct brcms_phy_pub *ppi); +extern void wlc_phy_freqtrack_end(struct brcms_phy_pub *ppi); + +extern const u8 *wlc_phy_get_ofdm_rate_lookup(void); + +extern s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi, + u8 mcs_offset); +extern s8 wlc_phy_get_tx_power_offset(struct brcms_phy_pub *ppi, u8 tbl_offset); +#endif /* _BRCM_PHY_HAL_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h new file mode 100644 index 000000000000..bea85241a244 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h @@ -0,0 +1,1169 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_PHY_INT_H_ +#define _BRCM_PHY_INT_H_ + +#include <types.h> +#include <brcmu_utils.h> +#include <brcmu_wifi.h> + +#define PHY_VERSION { 1, 82, 8, 0 } + +#define LCNXN_BASEREV 16 + +struct phy_shim_info; + +struct brcms_phy_srom_fem { + /* TSSI positive slope, 1: positive, 0: negative */ + u8 tssipos; + /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ + u8 extpagain; + /* support 32 combinations of different Pdet dynamic ranges */ + u8 pdetrange; + /* TR switch isolation */ + u8 triso; + /* antswctrl lookup table configuration: 32 possible choices */ + u8 antswctrllut; +}; + +#define ISNPHY(pi) PHYTYPE_IS((pi)->pubpi.phy_type, PHY_TYPE_N) +#define ISLCNPHY(pi) PHYTYPE_IS((pi)->pubpi.phy_type, PHY_TYPE_LCN) + +#define PHY_GET_RFATTN(rfgain) ((rfgain) & 0x0f) +#define PHY_GET_PADMIX(rfgain) (((rfgain) & 0x10) >> 4) +#define PHY_GET_RFGAINID(rfattn, padmix, width) ((rfattn) + ((padmix)*(width))) +#define PHY_SAT(x, n) ((x) > ((1<<((n)-1))-1) ? ((1<<((n)-1))-1) : \ + ((x) < -(1<<((n)-1)) ? -(1<<((n)-1)) : (x))) +#define PHY_SHIFT_ROUND(x, n) ((x) >= 0 ? ((x)+(1<<((n)-1)))>>(n) : (x)>>(n)) +#define PHY_HW_ROUND(x, s) ((x >> s) + ((x >> (s-1)) & (s != 0))) + +#define CH_5G_GROUP 3 +#define A_LOW_CHANS 0 +#define A_MID_CHANS 1 +#define A_HIGH_CHANS 2 +#define CH_2G_GROUP 1 +#define G_ALL_CHANS 0 + +#define FIRST_REF5_CHANNUM 149 +#define LAST_REF5_CHANNUM 165 +#define FIRST_5G_CHAN 14 +#define LAST_5G_CHAN 50 +#define FIRST_MID_5G_CHAN 14 +#define LAST_MID_5G_CHAN 35 +#define FIRST_HIGH_5G_CHAN 36 +#define LAST_HIGH_5G_CHAN 41 +#define FIRST_LOW_5G_CHAN 42 +#define LAST_LOW_5G_CHAN 50 + +#define BASE_LOW_5G_CHAN 4900 +#define BASE_MID_5G_CHAN 5100 +#define BASE_HIGH_5G_CHAN 5500 + +#define CHAN5G_FREQ(chan) (5000 + chan*5) +#define CHAN2G_FREQ(chan) (2407 + chan*5) + +#define TXP_FIRST_CCK 0 +#define TXP_LAST_CCK 3 +#define TXP_FIRST_OFDM 4 +#define TXP_LAST_OFDM 11 +#define TXP_FIRST_OFDM_20_CDD 12 +#define TXP_LAST_OFDM_20_CDD 19 +#define TXP_FIRST_MCS_20_SISO 20 +#define TXP_LAST_MCS_20_SISO 27 +#define TXP_FIRST_MCS_20_CDD 28 +#define TXP_LAST_MCS_20_CDD 35 +#define TXP_FIRST_MCS_20_STBC 36 +#define TXP_LAST_MCS_20_STBC 43 +#define TXP_FIRST_MCS_20_SDM 44 +#define TXP_LAST_MCS_20_SDM 51 +#define TXP_FIRST_OFDM_40_SISO 52 +#define TXP_LAST_OFDM_40_SISO 59 +#define TXP_FIRST_OFDM_40_CDD 60 +#define TXP_LAST_OFDM_40_CDD 67 +#define TXP_FIRST_MCS_40_SISO 68 +#define TXP_LAST_MCS_40_SISO 75 +#define TXP_FIRST_MCS_40_CDD 76 +#define TXP_LAST_MCS_40_CDD 83 +#define TXP_FIRST_MCS_40_STBC 84 +#define TXP_LAST_MCS_40_STBC 91 +#define TXP_FIRST_MCS_40_SDM 92 +#define TXP_LAST_MCS_40_SDM 99 +#define TXP_MCS_32 100 +#define TXP_NUM_RATES 101 +#define ADJ_PWR_TBL_LEN 84 + +#define TXP_FIRST_SISO_MCS_20 20 +#define TXP_LAST_SISO_MCS_20 27 + +#define PHY_CORE_NUM_1 1 +#define PHY_CORE_NUM_2 2 +#define PHY_CORE_NUM_3 3 +#define PHY_CORE_NUM_4 4 +#define PHY_CORE_MAX PHY_CORE_NUM_4 +#define PHY_CORE_0 0 +#define PHY_CORE_1 1 +#define PHY_CORE_2 2 +#define PHY_CORE_3 3 + +#define MA_WINDOW_SZ 8 + +#define PHY_NOISE_SAMPLE_MON 1 +#define PHY_NOISE_SAMPLE_EXTERNAL 2 +#define PHY_NOISE_WINDOW_SZ 16 +#define PHY_NOISE_GLITCH_INIT_MA 10 +#define PHY_NOISE_GLITCH_INIT_MA_BADPlCP 10 +#define PHY_NOISE_STATE_MON 0x1 +#define PHY_NOISE_STATE_EXTERNAL 0x2 +#define PHY_NOISE_SAMPLE_LOG_NUM_NPHY 10 +#define PHY_NOISE_SAMPLE_LOG_NUM_UCODE 9 + +#define PHY_NOISE_OFFSETFACT_4322 (-103) +#define PHY_NOISE_MA_WINDOW_SZ 2 + +#define PHY_RSSI_TABLE_SIZE 64 +#define RSSI_ANT_MERGE_MAX 0 +#define RSSI_ANT_MERGE_MIN 1 +#define RSSI_ANT_MERGE_AVG 2 + +#define PHY_TSSI_TABLE_SIZE 64 +#define APHY_TSSI_TABLE_SIZE 256 +#define TX_GAIN_TABLE_LENGTH 64 +#define DEFAULT_11A_TXP_IDX 24 +#define NUM_TSSI_FRAMES 4 +#define NULL_TSSI 0x7f +#define NULL_TSSI_W 0x7f7f + +#define PHY_PAPD_EPS_TBL_SIZE_LCNPHY 64 + +#define LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL 9 + +#define PHY_TXPWR_MIN 10 +#define PHY_TXPWR_MIN_NPHY 8 +#define RADIOPWR_OVERRIDE_DEF (-1) + +#define PWRTBL_NUM_COEFF 3 + +#define SPURAVOID_DISABLE 0 +#define SPURAVOID_AUTO 1 +#define SPURAVOID_FORCEON 2 +#define SPURAVOID_FORCEON2 3 + +#define PHY_SW_TIMER_FAST 15 +#define PHY_SW_TIMER_SLOW 60 +#define PHY_SW_TIMER_GLACIAL 120 + +#define PHY_PERICAL_AUTO 0 +#define PHY_PERICAL_FULL 1 +#define PHY_PERICAL_PARTIAL 2 + +#define PHY_PERICAL_NODELAY 0 +#define PHY_PERICAL_INIT_DELAY 5 +#define PHY_PERICAL_ASSOC_DELAY 5 +#define PHY_PERICAL_WDOG_DELAY 5 + +#define MPHASE_TXCAL_NUMCMDS 2 + +#define PHY_PERICAL_MPHASE_PENDING(pi) \ + (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_IDLE) + +enum { + MPHASE_CAL_STATE_IDLE = 0, + MPHASE_CAL_STATE_INIT = 1, + MPHASE_CAL_STATE_TXPHASE0, + MPHASE_CAL_STATE_TXPHASE1, + MPHASE_CAL_STATE_TXPHASE2, + MPHASE_CAL_STATE_TXPHASE3, + MPHASE_CAL_STATE_TXPHASE4, + MPHASE_CAL_STATE_TXPHASE5, + MPHASE_CAL_STATE_PAPDCAL, + MPHASE_CAL_STATE_RXCAL, + MPHASE_CAL_STATE_RSSICAL, + MPHASE_CAL_STATE_IDLETSSI +}; + +enum phy_cal_mode { + CAL_FULL, + CAL_RECAL, + CAL_CURRECAL, + CAL_DIGCAL, + CAL_GCTRL, + CAL_SOFT, + CAL_DIGLO +}; + +#define RDR_NTIERS 1 +#define RDR_TIER_SIZE 64 +#define RDR_LIST_SIZE (512/3) +#define RDR_EPOCH_SIZE 40 +#define RDR_NANTENNAS 2 +#define RDR_NTIER_SIZE RDR_LIST_SIZE +#define RDR_LP_BUFFER_SIZE 64 +#define LP_LEN_HIS_SIZE 10 + +#define STATIC_NUM_RF 32 +#define STATIC_NUM_BB 9 + +#define BB_MULT_MASK 0x0000ffff +#define BB_MULT_VALID_MASK 0x80000000 + +#define CORDIC_AG 39797 +#define CORDIC_NI 18 +#define FIXED(X) ((s32)((X) << 16)) + +#define FLOAT(X) \ + (((X) >= 0) ? ((((X) >> 15) + 1) >> 1) : -((((-(X)) >> 15) + 1) >> 1)) + +#define PHY_CHAIN_TX_DISABLE_TEMP 115 +#define PHY_HYSTERESIS_DELTATEMP 5 + +#define SCAN_INPROG_PHY(pi) \ + (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN)) + +#define PLT_INPROG_PHY(pi) (mboolisset(pi->measure_hold, PHY_HOLD_FOR_PLT)) + +#define ASSOC_INPROG_PHY(pi) \ + (mboolisset(pi->measure_hold, PHY_HOLD_FOR_ASSOC)) + +#define SCAN_RM_IN_PROGRESS(pi) \ + (mboolisset(pi->measure_hold, PHY_HOLD_FOR_SCAN | PHY_HOLD_FOR_RM)) + +#define PHY_MUTED(pi) \ + (mboolisset(pi->measure_hold, PHY_HOLD_FOR_MUTE)) + +#define PUB_NOT_ASSOC(pi) \ + (mboolisset(pi->measure_hold, PHY_HOLD_FOR_NOT_ASSOC)) + +struct phy_table_info { + uint table; + int q; + uint max; +}; + +struct phytbl_info { + const void *tbl_ptr; + u32 tbl_len; + u32 tbl_id; + u32 tbl_offset; + u32 tbl_width; +}; + +struct interference_info { + u8 curr_home_channel; + u16 crsminpwrthld_40_stored; + u16 crsminpwrthld_20L_stored; + u16 crsminpwrthld_20U_stored; + u16 init_gain_code_core1_stored; + u16 init_gain_code_core2_stored; + u16 init_gain_codeb_core1_stored; + u16 init_gain_codeb_core2_stored; + u16 init_gain_table_stored[4]; + + u16 clip1_hi_gain_code_core1_stored; + u16 clip1_hi_gain_code_core2_stored; + u16 clip1_hi_gain_codeb_core1_stored; + u16 clip1_hi_gain_codeb_core2_stored; + u16 nb_clip_thresh_core1_stored; + u16 nb_clip_thresh_core2_stored; + u16 init_ofdmlna2gainchange_stored[4]; + u16 init_ccklna2gainchange_stored[4]; + u16 clip1_lo_gain_code_core1_stored; + u16 clip1_lo_gain_code_core2_stored; + u16 clip1_lo_gain_codeb_core1_stored; + u16 clip1_lo_gain_codeb_core2_stored; + u16 w1_clip_thresh_core1_stored; + u16 w1_clip_thresh_core2_stored; + u16 radio_2056_core1_rssi_gain_stored; + u16 radio_2056_core2_rssi_gain_stored; + u16 energy_drop_timeout_len_stored; + + u16 ed_crs40_assertthld0_stored; + u16 ed_crs40_assertthld1_stored; + u16 ed_crs40_deassertthld0_stored; + u16 ed_crs40_deassertthld1_stored; + u16 ed_crs20L_assertthld0_stored; + u16 ed_crs20L_assertthld1_stored; + u16 ed_crs20L_deassertthld0_stored; + u16 ed_crs20L_deassertthld1_stored; + u16 ed_crs20U_assertthld0_stored; + u16 ed_crs20U_assertthld1_stored; + u16 ed_crs20U_deassertthld0_stored; + u16 ed_crs20U_deassertthld1_stored; + + u16 badplcp_ma; + u16 badplcp_ma_previous; + u16 badplcp_ma_total; + u16 badplcp_ma_list[MA_WINDOW_SZ]; + int badplcp_ma_index; + s16 pre_badplcp_cnt; + s16 bphy_pre_badplcp_cnt; + + u16 init_gain_core1; + u16 init_gain_core2; + u16 init_gainb_core1; + u16 init_gainb_core2; + u16 init_gain_rfseq[4]; + + u16 crsminpwr0; + u16 crsminpwrl0; + u16 crsminpwru0; + + s16 crsminpwr_index; + + u16 radio_2057_core1_rssi_wb1a_gc_stored; + u16 radio_2057_core2_rssi_wb1a_gc_stored; + u16 radio_2057_core1_rssi_wb1g_gc_stored; + u16 radio_2057_core2_rssi_wb1g_gc_stored; + u16 radio_2057_core1_rssi_wb2_gc_stored; + u16 radio_2057_core2_rssi_wb2_gc_stored; + u16 radio_2057_core1_rssi_nb_gc_stored; + u16 radio_2057_core2_rssi_nb_gc_stored; +}; + +struct aci_save_gphy { + u16 rc_cal_ovr; + u16 phycrsth1; + u16 phycrsth2; + u16 init_n1p1_gain; + u16 p1_p2_gain; + u16 n1_n2_gain; + u16 n1_p1_gain; + u16 div_search_gain; + u16 div_p1_p2_gain; + u16 div_search_gn_change; + u16 table_7_2; + u16 table_7_3; + u16 cckshbits_gnref; + u16 clip_thresh; + u16 clip2_thresh; + u16 clip3_thresh; + u16 clip_p2_thresh; + u16 clip_pwdn_thresh; + u16 clip_n1p1_thresh; + u16 clip_n1_pwdn_thresh; + u16 bbconfig; + u16 cthr_sthr_shdin; + u16 energy; + u16 clip_p1_p2_thresh; + u16 threshold; + u16 reg15; + u16 reg16; + u16 reg17; + u16 div_srch_idx; + u16 div_srch_p1_p2; + u16 div_srch_gn_back; + u16 ant_dwell; + u16 ant_wr_settle; +}; + +struct lo_complex_abgphy_info { + s8 i; + s8 q; +}; + +struct nphy_iq_comp { + s16 a0; + s16 b0; + s16 a1; + s16 b1; +}; + +struct nphy_txpwrindex { + s8 index; + s8 index_internal; + s8 index_internal_save; + u16 AfectrlOverride; + u16 AfeCtrlDacGain; + u16 rad_gain; + u8 bbmult; + u16 iqcomp_a; + u16 iqcomp_b; + u16 locomp; +}; + +struct txiqcal_cache { + + u16 txcal_coeffs_2G[8]; + u16 txcal_radio_regs_2G[8]; + struct nphy_iq_comp rxcal_coeffs_2G; + + u16 txcal_coeffs_5G[8]; + u16 txcal_radio_regs_5G[8]; + struct nphy_iq_comp rxcal_coeffs_5G; +}; + +struct nphy_pwrctrl { + s8 max_pwr_2g; + s8 idle_targ_2g; + s16 pwrdet_2g_a1; + s16 pwrdet_2g_b0; + s16 pwrdet_2g_b1; + s8 max_pwr_5gm; + s8 idle_targ_5gm; + s8 max_pwr_5gh; + s8 max_pwr_5gl; + s16 pwrdet_5gm_a1; + s16 pwrdet_5gm_b0; + s16 pwrdet_5gm_b1; + s16 pwrdet_5gl_a1; + s16 pwrdet_5gl_b0; + s16 pwrdet_5gl_b1; + s16 pwrdet_5gh_a1; + s16 pwrdet_5gh_b0; + s16 pwrdet_5gh_b1; + s8 idle_targ_5gl; + s8 idle_targ_5gh; + s8 idle_tssi_2g; + s8 idle_tssi_5g; + s8 idle_tssi; + s16 a1; + s16 b0; + s16 b1; +}; + +struct nphy_txgains { + u16 txlpf[2]; + u16 txgm[2]; + u16 pga[2]; + u16 pad[2]; + u16 ipa[2]; +}; + +#define PHY_NOISEVAR_BUFSIZE 10 + +struct nphy_noisevar_buf { + int bufcount; + int tone_id[PHY_NOISEVAR_BUFSIZE]; + u32 noise_vars[PHY_NOISEVAR_BUFSIZE]; + u32 min_noise_vars[PHY_NOISEVAR_BUFSIZE]; +}; + +struct rssical_cache { + u16 rssical_radio_regs_2G[2]; + u16 rssical_phyregs_2G[12]; + + u16 rssical_radio_regs_5G[2]; + u16 rssical_phyregs_5G[12]; +}; + +struct lcnphy_cal_results { + + u16 txiqlocal_a; + u16 txiqlocal_b; + u16 txiqlocal_didq; + u8 txiqlocal_ei0; + u8 txiqlocal_eq0; + u8 txiqlocal_fi0; + u8 txiqlocal_fq0; + + u16 txiqlocal_bestcoeffs[11]; + u16 txiqlocal_bestcoeffs_valid; + + u32 papd_eps_tbl[PHY_PAPD_EPS_TBL_SIZE_LCNPHY]; + u16 analog_gain_ref; + u16 lut_begin; + u16 lut_end; + u16 lut_step; + u16 rxcompdbm; + u16 papdctrl; + u16 sslpnCalibClkEnCtrl; + + u16 rxiqcal_coeff_a0; + u16 rxiqcal_coeff_b0; +}; + +struct shared_phy { + struct brcms_phy *phy_head; + uint unit; + struct si_pub *sih; + struct phy_shim_info *physhim; + uint corerev; + u32 machwcap; + bool up; + bool clk; + uint now; + u16 vid; + u16 did; + uint chip; + uint chiprev; + uint chippkg; + uint sromrev; + uint boardtype; + uint boardrev; + uint boardvendor; + u32 boardflags; + u32 boardflags2; + uint buscorerev; + uint fast_timer; + uint slow_timer; + uint glacial_timer; + u8 rx_antdiv; + s8 phy_noise_window[MA_WINDOW_SZ]; + uint phy_noise_index; + u8 hw_phytxchain; + u8 hw_phyrxchain; + u8 phytxchain; + u8 phyrxchain; + u8 rssi_mode; + bool _rifs_phy; +}; + +struct brcms_phy_pub { + uint phy_type; + uint phy_rev; + u8 phy_corenum; + u16 radioid; + u8 radiorev; + u8 radiover; + + uint coreflags; + uint ana_rev; + bool abgphy_encore; +}; + +struct phy_func_ptr { + void (*init)(struct brcms_phy *); + void (*calinit)(struct brcms_phy *); + void (*chanset)(struct brcms_phy *, u16 chanspec); + void (*txpwrrecalc)(struct brcms_phy *); + int (*longtrn)(struct brcms_phy *, int); + void (*txiqccget)(struct brcms_phy *, u16 *, u16 *); + void (*txiqccset)(struct brcms_phy *, u16, u16); + u16 (*txloccget)(struct brcms_phy *); + void (*radioloftget)(struct brcms_phy *, u8 *, u8 *, u8 *, u8 *); + void (*carrsuppr)(struct brcms_phy *); + s32 (*rxsigpwr)(struct brcms_phy *, s32); + void (*detach)(struct brcms_phy *); +}; + +struct brcms_phy { + struct brcms_phy_pub pubpi_ro; + struct shared_phy *sh; + struct phy_func_ptr pi_fptr; + + union { + struct brcms_phy_lcnphy *pi_lcnphy; + } u; + bool user_txpwr_at_rfport; + + struct d11regs __iomem *regs; + struct brcms_phy *next; + struct brcms_phy_pub pubpi; + + bool do_initcal; + bool phytest_on; + bool ofdm_rateset_war; + bool bf_preempt_4306; + u16 radio_chanspec; + u8 antsel_type; + u16 bw; + u8 txpwr_percent; + bool phy_init_por; + + bool init_in_progress; + bool initialized; + bool sbtml_gm; + uint refcnt; + bool watchdog_override; + u8 phynoise_state; + uint phynoise_now; + int phynoise_chan_watchdog; + bool phynoise_polling; + bool disable_percal; + u32 measure_hold; + + s16 txpa_2g[PWRTBL_NUM_COEFF]; + s16 txpa_2g_low_temp[PWRTBL_NUM_COEFF]; + s16 txpa_2g_high_temp[PWRTBL_NUM_COEFF]; + s16 txpa_5g_low[PWRTBL_NUM_COEFF]; + s16 txpa_5g_mid[PWRTBL_NUM_COEFF]; + s16 txpa_5g_hi[PWRTBL_NUM_COEFF]; + + u8 tx_srom_max_2g; + u8 tx_srom_max_5g_low; + u8 tx_srom_max_5g_mid; + u8 tx_srom_max_5g_hi; + u8 tx_srom_max_rate_2g[TXP_NUM_RATES]; + u8 tx_srom_max_rate_5g_low[TXP_NUM_RATES]; + u8 tx_srom_max_rate_5g_mid[TXP_NUM_RATES]; + u8 tx_srom_max_rate_5g_hi[TXP_NUM_RATES]; + u8 tx_user_target[TXP_NUM_RATES]; + s8 tx_power_offset[TXP_NUM_RATES]; + u8 tx_power_target[TXP_NUM_RATES]; + + struct brcms_phy_srom_fem srom_fem2g; + struct brcms_phy_srom_fem srom_fem5g; + + u8 tx_power_max; + u8 tx_power_max_rate_ind; + bool hwpwrctrl; + u8 nphy_txpwrctrl; + s8 nphy_txrx_chain; + bool phy_5g_pwrgain; + + u16 phy_wreg; + u16 phy_wreg_limit; + + s8 n_preamble_override; + u8 antswitch; + u8 aa2g, aa5g; + + s8 idle_tssi[CH_5G_GROUP]; + s8 target_idle_tssi; + s8 txpwr_est_Pout; + u8 tx_power_min; + u8 txpwr_limit[TXP_NUM_RATES]; + u8 txpwr_env_limit[TXP_NUM_RATES]; + u8 adj_pwr_tbl_nphy[ADJ_PWR_TBL_LEN]; + + bool channel_14_wide_filter; + + bool txpwroverride; + bool txpwridx_override_aphy; + s16 radiopwr_override; + u16 hwpwr_txcur; + u8 saved_txpwr_idx; + + bool edcrs_threshold_lock; + + u32 tr_R_gain_val; + u32 tr_T_gain_val; + + s16 ofdm_analog_filt_bw_override; + s16 cck_analog_filt_bw_override; + s16 ofdm_rccal_override; + s16 cck_rccal_override; + u16 extlna_type; + + uint interference_mode_crs_time; + u16 crsglitch_prev; + bool interference_mode_crs; + + u32 phy_tx_tone_freq; + uint phy_lastcal; + bool phy_forcecal; + bool phy_fixed_noise; + u32 xtalfreq; + u8 pdiv; + s8 carrier_suppr_disable; + + bool phy_bphy_evm; + bool phy_bphy_rfcs; + s8 phy_scraminit; + u8 phy_gpiosel; + + s16 phy_txcore_disable_temp; + s16 phy_txcore_enable_temp; + s8 phy_tempsense_offset; + bool phy_txcore_heatedup; + + u16 radiopwr; + u16 bb_atten; + u16 txctl1; + + u16 mintxbias; + u16 mintxmag; + struct lo_complex_abgphy_info gphy_locomp_iq + [STATIC_NUM_RF][STATIC_NUM_BB]; + s8 stats_11b_txpower[STATIC_NUM_RF][STATIC_NUM_BB]; + u16 gain_table[TX_GAIN_TABLE_LENGTH]; + bool loopback_gain; + s16 max_lpback_gain_hdB; + s16 trsw_rx_gain_hdB; + u8 power_vec[8]; + + u16 rc_cal; + int nrssi_table_delta; + int nrssi_slope_scale; + int nrssi_slope_offset; + int min_rssi; + int max_rssi; + + s8 txpwridx; + u8 min_txpower; + + u8 a_band_high_disable; + + u16 tx_vos; + u16 global_tx_bb_dc_bias_loft; + + int rf_max; + int bb_max; + int rf_list_size; + int bb_list_size; + u16 *rf_attn_list; + u16 *bb_attn_list; + u16 padmix_mask; + u16 padmix_reg; + u16 *txmag_list; + uint txmag_len; + bool txmag_enable; + + s8 *a_tssi_to_dbm; + s8 *m_tssi_to_dbm; + s8 *l_tssi_to_dbm; + s8 *h_tssi_to_dbm; + u8 *hwtxpwr; + + u16 freqtrack_saved_regs[2]; + int cur_interference_mode; + bool hwpwrctrl_capable; + bool temppwrctrl_capable; + + uint phycal_nslope; + uint phycal_noffset; + uint phycal_mlo; + uint phycal_txpower; + + u8 phy_aa2g; + + bool nphy_tableloaded; + s8 nphy_rssisel; + u32 nphy_bb_mult_save; + u16 nphy_txiqlocal_bestc[11]; + bool nphy_txiqlocal_coeffsvalid; + struct nphy_txpwrindex nphy_txpwrindex[PHY_CORE_NUM_2]; + struct nphy_pwrctrl nphy_pwrctrl_info[PHY_CORE_NUM_2]; + u16 cck2gpo; + u32 ofdm2gpo; + u32 ofdm5gpo; + u32 ofdm5glpo; + u32 ofdm5ghpo; + u8 bw402gpo; + u8 bw405gpo; + u8 bw405glpo; + u8 bw405ghpo; + u8 cdd2gpo; + u8 cdd5gpo; + u8 cdd5glpo; + u8 cdd5ghpo; + u8 stbc2gpo; + u8 stbc5gpo; + u8 stbc5glpo; + u8 stbc5ghpo; + u8 bwdup2gpo; + u8 bwdup5gpo; + u8 bwdup5glpo; + u8 bwdup5ghpo; + u16 mcs2gpo[8]; + u16 mcs5gpo[8]; + u16 mcs5glpo[8]; + u16 mcs5ghpo[8]; + u32 nphy_rxcalparams; + + u8 phy_spuravoid; + bool phy_isspuravoid; + + u8 phy_pabias; + u8 nphy_papd_skip; + u8 nphy_tssi_slope; + + s16 nphy_noise_win[PHY_CORE_MAX][PHY_NOISE_WINDOW_SZ]; + u8 nphy_noise_index; + + u8 nphy_txpid2g[PHY_CORE_NUM_2]; + u8 nphy_txpid5g[PHY_CORE_NUM_2]; + u8 nphy_txpid5gl[PHY_CORE_NUM_2]; + u8 nphy_txpid5gh[PHY_CORE_NUM_2]; + + bool nphy_gain_boost; + bool nphy_elna_gain_config; + u16 old_bphy_test; + u16 old_bphy_testcontrol; + + bool phyhang_avoid; + + bool rssical_nphy; + u8 nphy_perical; + uint nphy_perical_last; + u8 cal_type_override; + u8 mphase_cal_phase_id; + u8 mphase_txcal_cmdidx; + u8 mphase_txcal_numcmds; + u16 mphase_txcal_bestcoeffs[11]; + u16 nphy_txiqlocal_chanspec; + u16 nphy_iqcal_chanspec_2G; + u16 nphy_iqcal_chanspec_5G; + u16 nphy_rssical_chanspec_2G; + u16 nphy_rssical_chanspec_5G; + struct wlapi_timer *phycal_timer; + bool use_int_tx_iqlo_cal_nphy; + bool internal_tx_iqlo_cal_tapoff_intpa_nphy; + s16 nphy_lastcal_temp; + + struct txiqcal_cache calibration_cache; + struct rssical_cache rssical_cache; + + u8 nphy_txpwr_idx[2]; + u8 nphy_papd_cal_type; + uint nphy_papd_last_cal; + u16 nphy_papd_tx_gain_at_last_cal[2]; + u8 nphy_papd_cal_gain_index[2]; + s16 nphy_papd_epsilon_offset[2]; + bool nphy_papd_recal_enable; + u32 nphy_papd_recal_counter; + bool nphy_force_papd_cal; + bool nphy_papdcomp; + bool ipa2g_on; + bool ipa5g_on; + + u16 classifier_state; + u16 clip_state[2]; + uint nphy_deaf_count; + u8 rxiq_samps; + u8 rxiq_antsel; + + u16 rfctrlIntc1_save; + u16 rfctrlIntc2_save; + bool first_cal_after_assoc; + u16 tx_rx_cal_radio_saveregs[22]; + u16 tx_rx_cal_phy_saveregs[15]; + + u8 nphy_cal_orig_pwr_idx[2]; + u8 nphy_txcal_pwr_idx[2]; + u8 nphy_rxcal_pwr_idx[2]; + u16 nphy_cal_orig_tx_gain[2]; + struct nphy_txgains nphy_cal_target_gain; + u16 nphy_txcal_bbmult; + u16 nphy_gmval; + + u16 nphy_saved_bbconf; + + bool nphy_gband_spurwar_en; + bool nphy_gband_spurwar2_en; + bool nphy_aband_spurwar_en; + u16 nphy_rccal_value; + u16 nphy_crsminpwr[3]; + struct nphy_noisevar_buf nphy_saved_noisevars; + bool nphy_anarxlpf_adjusted; + bool nphy_crsminpwr_adjusted; + bool nphy_noisevars_adjusted; + + bool nphy_rxcal_active; + u16 radar_percal_mask; + bool dfs_lp_buffer_nphy; + + u16 nphy_fineclockgatecontrol; + + s8 rx2tx_biasentry; + + u16 crsminpwr0; + u16 crsminpwrl0; + u16 crsminpwru0; + s16 noise_crsminpwr_index; + u16 init_gain_core1; + u16 init_gain_core2; + u16 init_gainb_core1; + u16 init_gainb_core2; + u8 aci_noise_curr_channel; + u16 init_gain_rfseq[4]; + + bool radio_is_on; + + bool nphy_sample_play_lpf_bw_ctl_ovr; + + u16 tbl_data_hi; + u16 tbl_data_lo; + u16 tbl_addr; + + uint tbl_save_id; + uint tbl_save_offset; + + u8 txpwrctrl; + s8 txpwrindex[PHY_CORE_MAX]; + + u8 phycal_tempdelta; + u32 mcs20_po; + u32 mcs40_po; + struct wiphy *wiphy; +}; + +struct cs32 { + s32 q; + s32 i; +}; + +struct radio_regs { + u16 address; + u32 init_a; + u32 init_g; + u8 do_init_a; + u8 do_init_g; +}; + +struct radio_20xx_regs { + u16 address; + u8 init; + u8 do_init; +}; + +struct lcnphy_radio_regs { + u16 address; + u8 init_a; + u8 init_g; + u8 do_init_a; + u8 do_init_g; +}; + +extern u16 read_phy_reg(struct brcms_phy *pi, u16 addr); +extern void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); +extern void and_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); +extern void or_phy_reg(struct brcms_phy *pi, u16 addr, u16 val); +extern void mod_phy_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val); + +extern u16 read_radio_reg(struct brcms_phy *pi, u16 addr); +extern void or_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); +extern void and_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); +extern void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, + u16 val); +extern void xor_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask); + +extern void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); + +extern void wlc_phyreg_enter(struct brcms_phy_pub *pih); +extern void wlc_phyreg_exit(struct brcms_phy_pub *pih); +extern void wlc_radioreg_enter(struct brcms_phy_pub *pih); +extern void wlc_radioreg_exit(struct brcms_phy_pub *pih); + +extern void wlc_phy_read_table(struct brcms_phy *pi, + const struct phytbl_info *ptbl_info, + u16 tblAddr, u16 tblDataHi, + u16 tblDatalo); +extern void wlc_phy_write_table(struct brcms_phy *pi, + const struct phytbl_info *ptbl_info, + u16 tblAddr, u16 tblDataHi, u16 tblDatalo); +extern void wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, + uint tbl_offset, u16 tblAddr, u16 tblDataHi, + u16 tblDataLo); +extern void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val); + +extern void write_phy_channel_reg(struct brcms_phy *pi, uint val); +extern void wlc_phy_txpower_update_shm(struct brcms_phy *pi); + +extern u8 wlc_phy_nbits(s32 value); +extern void wlc_phy_compute_dB(u32 *cmplx_pwr, s8 *p_dB, u8 core); + +extern uint wlc_phy_init_radio_regs_allbands(struct brcms_phy *pi, + struct radio_20xx_regs *radioregs); +extern uint wlc_phy_init_radio_regs(struct brcms_phy *pi, + const struct radio_regs *radioregs, + u16 core_offset); + +extern void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi); + +extern void wlc_phy_do_dummy_tx(struct brcms_phy *pi, bool ofdm, bool pa_on); +extern void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, + s32 *eps_imag); + +extern void wlc_phy_cal_perical_mphase_reset(struct brcms_phy *pi); +extern void wlc_phy_cal_perical_mphase_restart(struct brcms_phy *pi); + +extern bool wlc_phy_attach_nphy(struct brcms_phy *pi); +extern bool wlc_phy_attach_lcnphy(struct brcms_phy *pi); + +extern void wlc_phy_detach_lcnphy(struct brcms_phy *pi); + +extern void wlc_phy_init_nphy(struct brcms_phy *pi); +extern void wlc_phy_init_lcnphy(struct brcms_phy *pi); + +extern void wlc_phy_cal_init_nphy(struct brcms_phy *pi); +extern void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi); + +extern void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, + u16 chanspec); +extern void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, + u16 chanspec); +extern void wlc_phy_chanspec_set_fixup_lcnphy(struct brcms_phy *pi, + u16 chanspec); +extern int wlc_phy_channel2freq(uint channel); +extern int wlc_phy_chanspec_freq2bandrange_lpssn(uint); +extern int wlc_phy_chanspec_bandrange_get(struct brcms_phy *, u16 chanspec); + +extern void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode); +extern s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi); + +extern void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi); +extern void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi); +extern void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi); + +extern void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index); +extern void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable); +extern void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi); +extern void wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, + u16 max_val, bool iqcalmode); + +extern void wlc_phy_txpower_sromlimit_get_nphy(struct brcms_phy *pi, uint chan, + u8 *max_pwr, u8 rate_id); +extern void wlc_phy_ofdm_to_mcs_powers_nphy(u8 *power, u8 rate_mcs_start, + u8 rate_mcs_end, + u8 rate_ofdm_start); +extern void wlc_phy_mcs_to_ofdm_powers_nphy(u8 *power, + u8 rate_ofdm_start, + u8 rate_ofdm_end, + u8 rate_mcs_start); + +extern u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode); +extern s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode); +extern s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode); +extern s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode); +extern void wlc_phy_carrier_suppress_lcnphy(struct brcms_phy *pi); +extern void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel); +extern void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode); +extern void wlc_2064_vco_cal(struct brcms_phy *pi); + +extern void wlc_phy_txpower_recalc_target(struct brcms_phy *pi); + +#define LCNPHY_TBL_ID_PAPDCOMPDELTATBL 0x18 +#define LCNPHY_TX_POWER_TABLE_SIZE 128 +#define LCNPHY_MAX_TX_POWER_INDEX (LCNPHY_TX_POWER_TABLE_SIZE - 1) +#define LCNPHY_TBL_ID_TXPWRCTL 0x07 +#define LCNPHY_TX_PWR_CTRL_OFF 0 +#define LCNPHY_TX_PWR_CTRL_SW (0x1 << 15) +#define LCNPHY_TX_PWR_CTRL_HW ((0x1 << 15) | \ + (0x1 << 14) | \ + (0x1 << 13)) + +#define LCNPHY_TX_PWR_CTRL_TEMPBASED 0xE001 + +extern void wlc_lcnphy_write_table(struct brcms_phy *pi, + const struct phytbl_info *pti); +extern void wlc_lcnphy_read_table(struct brcms_phy *pi, + struct phytbl_info *pti); +extern void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b); +extern void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq); +extern void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b); +extern u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi); +extern void wlc_lcnphy_get_radio_loft(struct brcms_phy *pi, u8 *ei0, + u8 *eq0, u8 *fi0, u8 *fq0); +extern void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode); +extern void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode); +extern bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi); +extern void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi); +extern s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1); +extern void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, + s8 *cck_pwr); +extern void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi); + +extern s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index); + +#define NPHY_MAX_HPVGA1_INDEX 10 +#define NPHY_DEF_HPVGA1_INDEXLIMIT 7 + +struct phy_iq_est { + s32 iq_prod; + u32 i_pwr; + u32 q_pwr; +}; + +extern void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, + bool enable); +extern void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode); + +#define wlc_phy_write_table_nphy(pi, pti) \ + wlc_phy_write_table(pi, pti, 0x72, 0x74, 0x73) + +#define wlc_phy_read_table_nphy(pi, pti) \ + wlc_phy_read_table(pi, pti, 0x72, 0x74, 0x73) + +#define wlc_nphy_table_addr(pi, id, off) \ + wlc_phy_table_addr((pi), (id), (off), 0x72, 0x74, 0x73) + +#define wlc_nphy_table_data_write(pi, w, v) \ + wlc_phy_table_data_write((pi), (w), (v)) + +extern void wlc_phy_table_read_nphy(struct brcms_phy *pi, u32, u32 l, u32 o, + u32 w, void *d); +extern void wlc_phy_table_write_nphy(struct brcms_phy *pi, u32, u32, u32, + u32, const void *); + +#define PHY_IPA(pi) \ + ((pi->ipa2g_on && CHSPEC_IS2G(pi->radio_chanspec)) || \ + (pi->ipa5g_on && CHSPEC_IS5G(pi->radio_chanspec))) + +#define BRCMS_PHY_WAR_PR51571(pi) \ + if (NREV_LT((pi)->pubpi.phy_rev, 3)) \ + (void)R_REG(&(pi)->regs->maccontrol) + +extern void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype); +extern void wlc_phy_aci_reset_nphy(struct brcms_phy *pi); +extern void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en); + +extern u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint chan); +extern void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on); + +extern void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi); + +extern void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd); +extern s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi); + +extern u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val); + +extern void wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est, + u16 num_samps, u8 wait_time, + u8 wait_for_crs); + +extern void wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write, + struct nphy_iq_comp *comp); +extern void wlc_phy_aci_and_noise_reduction_nphy(struct brcms_phy *pi); + +extern void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, + u8 rxcore_bitmask); +extern u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih); + +extern void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type); +extern void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi); +extern void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi); +extern void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi); +extern u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi); + +extern struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi); +extern int wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, + struct nphy_txgains target_gain, + bool full, bool m); +extern int wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi, + struct nphy_txgains target_gain, + u8 type, bool d); +extern void wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, + s8 txpwrindex, bool res); +extern void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core, u8 rssi_type); +extern int wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, + s32 *rssi_buf, u8 nsamps); +extern void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi); +extern int wlc_phy_aci_scan_nphy(struct brcms_phy *pi); +extern void wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, + s32 dBm_targetpower, bool debug); +extern int wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, + u8 mode, u8, bool); +extern void wlc_phy_stopplayback_nphy(struct brcms_phy *pi); +extern void wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, + u8 num_samps); +extern void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi); + +extern int wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, + struct d11rxhdr *rxh); + +#define NPHY_TESTPATTERN_BPHY_EVM 0 +#define NPHY_TESTPATTERN_BPHY_RFCS 1 + +extern void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs); + +void wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, + s8 *ofdmoffset); +extern s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, + u16 chanspec); + +extern bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pih); +#endif /* _BRCM_PHY_INT_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c new file mode 100644 index 000000000000..a63aa99d9810 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -0,0 +1,5154 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/kernel.h> +#include <linux/delay.h> +#include <linux/cordic.h> + +#include <pmu.h> +#include <d11.h> +#include <phy_shim.h> +#include "phy_qmath.h" +#include "phy_hal.h" +#include "phy_radio.h" +#include "phytbl_lcn.h" +#include "phy_lcn.h" + +#define PLL_2064_NDIV 90 +#define PLL_2064_LOW_END_VCO 3000 +#define PLL_2064_LOW_END_KVCO 27 +#define PLL_2064_HIGH_END_VCO 4200 +#define PLL_2064_HIGH_END_KVCO 68 +#define PLL_2064_LOOP_BW_DOUBLER 200 +#define PLL_2064_D30_DOUBLER 10500 +#define PLL_2064_LOOP_BW 260 +#define PLL_2064_D30 8000 +#define PLL_2064_CAL_REF_TO 8 +#define PLL_2064_MHZ 1000000 +#define PLL_2064_OPEN_LOOP_DELAY 5 + +#define TEMPSENSE 1 +#define VBATSENSE 2 + +#define NOISE_IF_UPD_CHK_INTERVAL 1 +#define NOISE_IF_UPD_RST_INTERVAL 60 +#define NOISE_IF_UPD_THRESHOLD_CNT 1 +#define NOISE_IF_UPD_TRHRESHOLD 50 +#define NOISE_IF_UPD_TIMEOUT 1000 +#define NOISE_IF_OFF 0 +#define NOISE_IF_CHK 1 +#define NOISE_IF_ON 2 + +#define PAPD_BLANKING_PROFILE 3 +#define PAPD2LUT 0 +#define PAPD_CORR_NORM 0 +#define PAPD_BLANKING_THRESHOLD 0 +#define PAPD_STOP_AFTER_LAST_UPDATE 0 + +#define LCN_TARGET_PWR 60 + +#define LCN_VBAT_OFFSET_433X 34649679 +#define LCN_VBAT_SLOPE_433X 8258032 + +#define LCN_VBAT_SCALE_NOM 53 +#define LCN_VBAT_SCALE_DEN 432 + +#define LCN_TEMPSENSE_OFFSET 80812 +#define LCN_TEMPSENSE_DEN 2647 + +#define LCN_BW_LMT 200 +#define LCN_CUR_LMT 1250 +#define LCN_MULT 1 +#define LCN_VCO_DIV 30 +#define LCN_OFFSET 680 +#define LCN_FACT 490 +#define LCN_CUR_DIV 2640 + +#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT \ + (0 + 8) +#define LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK \ + (0x7f << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT) + +#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT \ + (0 + 8) +#define LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK \ + (0x7f << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT) + +#define wlc_lcnphy_enable_tx_gain_override(pi) \ + wlc_lcnphy_set_tx_gain_override(pi, true) +#define wlc_lcnphy_disable_tx_gain_override(pi) \ + wlc_lcnphy_set_tx_gain_override(pi, false) + +#define wlc_lcnphy_iqcal_active(pi) \ + (read_phy_reg((pi), 0x451) & \ + ((0x1 << 15) | (0x1 << 14))) + +#define txpwrctrl_off(pi) (0x7 != ((read_phy_reg(pi, 0x4a4) & 0xE000) >> 13)) +#define wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) \ + (pi->temppwrctrl_capable) +#define wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) \ + (pi->hwpwrctrl_capable) + +#define SWCTRL_BT_TX 0x18 +#define SWCTRL_OVR_DISABLE 0x40 + +#define AFE_CLK_INIT_MODE_TXRX2X 1 +#define AFE_CLK_INIT_MODE_PAPD 0 + +#define LCNPHY_TBL_ID_IQLOCAL 0x00 + +#define LCNPHY_TBL_ID_RFSEQ 0x08 +#define LCNPHY_TBL_ID_GAIN_IDX 0x0d +#define LCNPHY_TBL_ID_SW_CTRL 0x0f +#define LCNPHY_TBL_ID_GAIN_TBL 0x12 +#define LCNPHY_TBL_ID_SPUR 0x14 +#define LCNPHY_TBL_ID_SAMPLEPLAY 0x15 +#define LCNPHY_TBL_ID_SAMPLEPLAY1 0x16 + +#define LCNPHY_TX_PWR_CTRL_RATE_OFFSET 832 +#define LCNPHY_TX_PWR_CTRL_MAC_OFFSET 128 +#define LCNPHY_TX_PWR_CTRL_GAIN_OFFSET 192 +#define LCNPHY_TX_PWR_CTRL_IQ_OFFSET 320 +#define LCNPHY_TX_PWR_CTRL_LO_OFFSET 448 +#define LCNPHY_TX_PWR_CTRL_PWR_OFFSET 576 + +#define LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313 140 + +#define LCNPHY_TX_PWR_CTRL_START_NPT 1 +#define LCNPHY_TX_PWR_CTRL_MAX_NPT 7 + +#define LCNPHY_NOISE_SAMPLES_DEFAULT 5000 + +#define LCNPHY_ACI_DETECT_START 1 +#define LCNPHY_ACI_DETECT_PROGRESS 2 +#define LCNPHY_ACI_DETECT_STOP 3 + +#define LCNPHY_ACI_CRSHIFRMLO_TRSH 100 +#define LCNPHY_ACI_GLITCH_TRSH 2000 +#define LCNPHY_ACI_TMOUT 250 +#define LCNPHY_ACI_DETECT_TIMEOUT 2 +#define LCNPHY_ACI_START_DELAY 0 + +#define wlc_lcnphy_tx_gain_override_enabled(pi) \ + (0 != (read_phy_reg((pi), 0x43b) & (0x1 << 6))) + +#define wlc_lcnphy_total_tx_frames(pi) \ + wlapi_bmac_read_shm((pi)->sh->physhim, M_UCODE_MACSTAT + \ + offsetof(struct macstat, txallfrm)) + +struct lcnphy_txgains { + u16 gm_gain; + u16 pga_gain; + u16 pad_gain; + u16 dac_gain; +}; + +enum lcnphy_cal_mode { + LCNPHY_CAL_FULL, + LCNPHY_CAL_RECAL, + LCNPHY_CAL_CURRECAL, + LCNPHY_CAL_DIGCAL, + LCNPHY_CAL_GCTRL +}; + +struct lcnphy_rx_iqcomp { + u8 chan; + s16 a; + s16 b; +}; + +struct lcnphy_spb_tone { + s16 re; + s16 im; +}; + +struct lcnphy_unsign16_struct { + u16 re; + u16 im; +}; + +struct lcnphy_iq_est { + u32 iq_prod; + u32 i_pwr; + u32 q_pwr; +}; + +struct lcnphy_sfo_cfg { + u16 ptcentreTs20; + u16 ptcentreFactor; +}; + +enum lcnphy_papd_cal_type { + LCNPHY_PAPD_CAL_CW, + LCNPHY_PAPD_CAL_OFDM +}; + +typedef u16 iqcal_gain_params_lcnphy[9]; + +static const iqcal_gain_params_lcnphy tbl_iqcal_gainparams_lcnphy_2G[] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +static const iqcal_gain_params_lcnphy *tbl_iqcal_gainparams_lcnphy[1] = { + tbl_iqcal_gainparams_lcnphy_2G, +}; + +static const u16 iqcal_gainparams_numgains_lcnphy[1] = { + sizeof(tbl_iqcal_gainparams_lcnphy_2G) / + sizeof(*tbl_iqcal_gainparams_lcnphy_2G), +}; + +static const struct lcnphy_sfo_cfg lcnphy_sfo_cfg[] = { + {965, 1087}, + {967, 1085}, + {969, 1082}, + {971, 1080}, + {973, 1078}, + {975, 1076}, + {977, 1073}, + {979, 1071}, + {981, 1069}, + {983, 1067}, + {985, 1065}, + {987, 1063}, + {989, 1060}, + {994, 1055} +}; + +static const +u16 lcnphy_iqcal_loft_gainladder[] = { + ((2 << 8) | 0), + ((3 << 8) | 0), + ((4 << 8) | 0), + ((6 << 8) | 0), + ((8 << 8) | 0), + ((11 << 8) | 0), + ((16 << 8) | 0), + ((16 << 8) | 1), + ((16 << 8) | 2), + ((16 << 8) | 3), + ((16 << 8) | 4), + ((16 << 8) | 5), + ((16 << 8) | 6), + ((16 << 8) | 7), + ((23 << 8) | 7), + ((32 << 8) | 7), + ((45 << 8) | 7), + ((64 << 8) | 7), + ((91 << 8) | 7), + ((128 << 8) | 7) +}; + +static const +u16 lcnphy_iqcal_ir_gainladder[] = { + ((1 << 8) | 0), + ((2 << 8) | 0), + ((4 << 8) | 0), + ((6 << 8) | 0), + ((8 << 8) | 0), + ((11 << 8) | 0), + ((16 << 8) | 0), + ((23 << 8) | 0), + ((32 << 8) | 0), + ((45 << 8) | 0), + ((64 << 8) | 0), + ((64 << 8) | 1), + ((64 << 8) | 2), + ((64 << 8) | 3), + ((64 << 8) | 4), + ((64 << 8) | 5), + ((64 << 8) | 6), + ((64 << 8) | 7), + ((91 << 8) | 7), + ((128 << 8) | 7) +}; + +static const +struct lcnphy_spb_tone lcnphy_spb_tone_3750[] = { + {88, 0}, + {73, 49}, + {34, 81}, + {-17, 86}, + {-62, 62}, + {-86, 17}, + {-81, -34}, + {-49, -73}, + {0, -88}, + {49, -73}, + {81, -34}, + {86, 17}, + {62, 62}, + {17, 86}, + {-34, 81}, + {-73, 49}, + {-88, 0}, + {-73, -49}, + {-34, -81}, + {17, -86}, + {62, -62}, + {86, -17}, + {81, 34}, + {49, 73}, + {0, 88}, + {-49, 73}, + {-81, 34}, + {-86, -17}, + {-62, -62}, + {-17, -86}, + {34, -81}, + {73, -49}, +}; + +static const +u16 iqlo_loopback_rf_regs[20] = { + RADIO_2064_REG036, + RADIO_2064_REG11A, + RADIO_2064_REG03A, + RADIO_2064_REG025, + RADIO_2064_REG028, + RADIO_2064_REG005, + RADIO_2064_REG112, + RADIO_2064_REG0FF, + RADIO_2064_REG11F, + RADIO_2064_REG00B, + RADIO_2064_REG113, + RADIO_2064_REG007, + RADIO_2064_REG0FC, + RADIO_2064_REG0FD, + RADIO_2064_REG012, + RADIO_2064_REG057, + RADIO_2064_REG059, + RADIO_2064_REG05C, + RADIO_2064_REG078, + RADIO_2064_REG092, +}; + +static const +u16 tempsense_phy_regs[14] = { + 0x503, + 0x4a4, + 0x4d0, + 0x4d9, + 0x4da, + 0x4a6, + 0x938, + 0x939, + 0x4d8, + 0x4d0, + 0x4d7, + 0x4a5, + 0x40d, + 0x4a2, +}; + +static const +u16 rxiq_cal_rf_reg[11] = { + RADIO_2064_REG098, + RADIO_2064_REG116, + RADIO_2064_REG12C, + RADIO_2064_REG06A, + RADIO_2064_REG00B, + RADIO_2064_REG01B, + RADIO_2064_REG113, + RADIO_2064_REG01D, + RADIO_2064_REG114, + RADIO_2064_REG02E, + RADIO_2064_REG12A, +}; + +static const +struct lcnphy_rx_iqcomp lcnphy_rx_iqcomp_table_rev0[] = { + {1, 0, 0}, + {2, 0, 0}, + {3, 0, 0}, + {4, 0, 0}, + {5, 0, 0}, + {6, 0, 0}, + {7, 0, 0}, + {8, 0, 0}, + {9, 0, 0}, + {10, 0, 0}, + {11, 0, 0}, + {12, 0, 0}, + {13, 0, 0}, + {14, 0, 0}, + {34, 0, 0}, + {38, 0, 0}, + {42, 0, 0}, + {46, 0, 0}, + {36, 0, 0}, + {40, 0, 0}, + {44, 0, 0}, + {48, 0, 0}, + {52, 0, 0}, + {56, 0, 0}, + {60, 0, 0}, + {64, 0, 0}, + {100, 0, 0}, + {104, 0, 0}, + {108, 0, 0}, + {112, 0, 0}, + {116, 0, 0}, + {120, 0, 0}, + {124, 0, 0}, + {128, 0, 0}, + {132, 0, 0}, + {136, 0, 0}, + {140, 0, 0}, + {149, 0, 0}, + {153, 0, 0}, + {157, 0, 0}, + {161, 0, 0}, + {165, 0, 0}, + {184, 0, 0}, + {188, 0, 0}, + {192, 0, 0}, + {196, 0, 0}, + {200, 0, 0}, + {204, 0, 0}, + {208, 0, 0}, + {212, 0, 0}, + {216, 0, 0}, +}; + +static const u32 lcnphy_23bitgaincode_table[] = { + 0x200100, + 0x200200, + 0x200004, + 0x200014, + 0x200024, + 0x200034, + 0x200134, + 0x200234, + 0x200334, + 0x200434, + 0x200037, + 0x200137, + 0x200237, + 0x200337, + 0x200437, + 0x000035, + 0x000135, + 0x000235, + 0x000037, + 0x000137, + 0x000237, + 0x000337, + 0x00013f, + 0x00023f, + 0x00033f, + 0x00034f, + 0x00044f, + 0x00144f, + 0x00244f, + 0x00254f, + 0x00354f, + 0x00454f, + 0x00464f, + 0x01464f, + 0x02464f, + 0x03464f, + 0x04464f, +}; + +static const s8 lcnphy_gain_table[] = { + -16, + -13, + 10, + 7, + 4, + 0, + 3, + 6, + 9, + 12, + 15, + 18, + 21, + 24, + 27, + 30, + 33, + 36, + 39, + 42, + 45, + 48, + 50, + 53, + 56, + 59, + 62, + 65, + 68, + 71, + 74, + 77, + 80, + 83, + 86, + 89, + 92, +}; + +static const s8 lcnphy_gain_index_offset_for_rssi[] = { + 7, + 7, + 7, + 7, + 7, + 7, + 7, + 8, + 7, + 7, + 6, + 7, + 7, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -2, + -2, + -2 +}; + +struct chan_info_2064_lcnphy { + uint chan; + uint freq; + u8 logen_buftune; + u8 logen_rccr_tx; + u8 txrf_mix_tune_ctrl; + u8 pa_input_tune_g; + u8 logen_rccr_rx; + u8 pa_rxrf_lna1_freq_tune; + u8 pa_rxrf_lna2_freq_tune; + u8 rxrf_rxrf_spare1; +}; + +static const struct chan_info_2064_lcnphy chan_info_2064_lcnphy[] = { + {1, 2412, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {2, 2417, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {3, 2422, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {4, 2427, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {5, 2432, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {6, 2437, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {7, 2442, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {8, 2447, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {9, 2452, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {10, 2457, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {11, 2462, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {12, 2467, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {13, 2472, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, + {14, 2484, 0x0B, 0x0A, 0x00, 0x07, 0x0A, 0x88, 0x88, 0x80}, +}; + +static const struct lcnphy_radio_regs lcnphy_radio_regs_2064[] = { + {0x00, 0, 0, 0, 0}, + {0x01, 0x64, 0x64, 0, 0}, + {0x02, 0x20, 0x20, 0, 0}, + {0x03, 0x66, 0x66, 0, 0}, + {0x04, 0xf8, 0xf8, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0x10, 0x10, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0x37, 0x37, 0, 0}, + {0x0B, 0x6, 0x6, 0, 0}, + {0x0C, 0x55, 0x55, 0, 0}, + {0x0D, 0x8b, 0x8b, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0x5, 0x5, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0xe, 0xe, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0xb, 0xb, 0, 0}, + {0x14, 0x2, 0x2, 0, 0}, + {0x15, 0x12, 0x12, 0, 0}, + {0x16, 0x12, 0x12, 0, 0}, + {0x17, 0xc, 0xc, 0, 0}, + {0x18, 0xc, 0xc, 0, 0}, + {0x19, 0xc, 0xc, 0, 0}, + {0x1A, 0x8, 0x8, 0, 0}, + {0x1B, 0x2, 0x2, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0x1, 0x1, 0, 0}, + {0x1E, 0x12, 0x12, 0, 0}, + {0x1F, 0x6e, 0x6e, 0, 0}, + {0x20, 0x2, 0x2, 0, 0}, + {0x21, 0x23, 0x23, 0, 0}, + {0x22, 0x8, 0x8, 0, 0}, + {0x23, 0, 0, 0, 0}, + {0x24, 0, 0, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0x33, 0x33, 0, 0}, + {0x27, 0x55, 0x55, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x30, 0x30, 0, 0}, + {0x2A, 0xb, 0xb, 0, 0}, + {0x2B, 0x1b, 0x1b, 0, 0}, + {0x2C, 0x3, 0x3, 0, 0}, + {0x2D, 0x1b, 0x1b, 0, 0}, + {0x2E, 0, 0, 0, 0}, + {0x2F, 0x20, 0x20, 0, 0}, + {0x30, 0xa, 0xa, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0x62, 0x62, 0, 0}, + {0x33, 0x19, 0x19, 0, 0}, + {0x34, 0x33, 0x33, 0, 0}, + {0x35, 0x77, 0x77, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x70, 0x70, 0, 0}, + {0x38, 0x3, 0x3, 0, 0}, + {0x39, 0xf, 0xf, 0, 0}, + {0x3A, 0x6, 0x6, 0, 0}, + {0x3B, 0xcf, 0xcf, 0, 0}, + {0x3C, 0x1a, 0x1a, 0, 0}, + {0x3D, 0x6, 0x6, 0, 0}, + {0x3E, 0x42, 0x42, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0xfb, 0xfb, 0, 0}, + {0x41, 0x9a, 0x9a, 0, 0}, + {0x42, 0x7a, 0x7a, 0, 0}, + {0x43, 0x29, 0x29, 0, 0}, + {0x44, 0, 0, 0, 0}, + {0x45, 0x8, 0x8, 0, 0}, + {0x46, 0xce, 0xce, 0, 0}, + {0x47, 0x27, 0x27, 0, 0}, + {0x48, 0x62, 0x62, 0, 0}, + {0x49, 0x6, 0x6, 0, 0}, + {0x4A, 0x58, 0x58, 0, 0}, + {0x4B, 0xf7, 0xf7, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0xb3, 0xb3, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0, 0, 0, 0}, + {0x51, 0x9, 0x9, 0, 0}, + {0x52, 0x5, 0x5, 0, 0}, + {0x53, 0x17, 0x17, 0, 0}, + {0x54, 0x38, 0x38, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0xb, 0xb, 0, 0}, + {0x58, 0, 0, 0, 0}, + {0x59, 0, 0, 0, 0}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0, 0, 0, 0}, + {0x5C, 0, 0, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x88, 0x88, 0, 0}, + {0x5F, 0xcc, 0xcc, 0, 0}, + {0x60, 0x74, 0x74, 0, 0}, + {0x61, 0x74, 0x74, 0, 0}, + {0x62, 0x74, 0x74, 0, 0}, + {0x63, 0x44, 0x44, 0, 0}, + {0x64, 0x77, 0x77, 0, 0}, + {0x65, 0x44, 0x44, 0, 0}, + {0x66, 0x77, 0x77, 0, 0}, + {0x67, 0x55, 0x55, 0, 0}, + {0x68, 0x77, 0x77, 0, 0}, + {0x69, 0x77, 0x77, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0x7f, 0x7f, 0, 0}, + {0x6C, 0x8, 0x8, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0x88, 0x88, 0, 0}, + {0x6F, 0x66, 0x66, 0, 0}, + {0x70, 0x66, 0x66, 0, 0}, + {0x71, 0x28, 0x28, 0, 0}, + {0x72, 0x55, 0x55, 0, 0}, + {0x73, 0x4, 0x4, 0, 0}, + {0x74, 0, 0, 0, 0}, + {0x75, 0, 0, 0, 0}, + {0x76, 0, 0, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0xd6, 0xd6, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0xb4, 0xb4, 0, 0}, + {0x84, 0x1, 0x1, 0, 0}, + {0x85, 0x20, 0x20, 0, 0}, + {0x86, 0x5, 0x5, 0, 0}, + {0x87, 0xff, 0xff, 0, 0}, + {0x88, 0x7, 0x7, 0, 0}, + {0x89, 0x77, 0x77, 0, 0}, + {0x8A, 0x77, 0x77, 0, 0}, + {0x8B, 0x77, 0x77, 0, 0}, + {0x8C, 0x77, 0x77, 0, 0}, + {0x8D, 0x8, 0x8, 0, 0}, + {0x8E, 0xa, 0xa, 0, 0}, + {0x8F, 0x8, 0x8, 0, 0}, + {0x90, 0x18, 0x18, 0, 0}, + {0x91, 0x5, 0x5, 0, 0}, + {0x92, 0x1f, 0x1f, 0, 0}, + {0x93, 0x10, 0x10, 0, 0}, + {0x94, 0x3, 0x3, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0xaa, 0xaa, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0x23, 0x23, 0, 0}, + {0x9A, 0x7, 0x7, 0, 0}, + {0x9B, 0xf, 0xf, 0, 0}, + {0x9C, 0x10, 0x10, 0, 0}, + {0x9D, 0x3, 0x3, 0, 0}, + {0x9E, 0x4, 0x4, 0, 0}, + {0x9F, 0x20, 0x20, 0, 0}, + {0xA0, 0, 0, 0, 0}, + {0xA1, 0, 0, 0, 0}, + {0xA2, 0, 0, 0, 0}, + {0xA3, 0, 0, 0, 0}, + {0xA4, 0x1, 0x1, 0, 0}, + {0xA5, 0x77, 0x77, 0, 0}, + {0xA6, 0x77, 0x77, 0, 0}, + {0xA7, 0x77, 0x77, 0, 0}, + {0xA8, 0x77, 0x77, 0, 0}, + {0xA9, 0x8c, 0x8c, 0, 0}, + {0xAA, 0x88, 0x88, 0, 0}, + {0xAB, 0x78, 0x78, 0, 0}, + {0xAC, 0x57, 0x57, 0, 0}, + {0xAD, 0x88, 0x88, 0, 0}, + {0xAE, 0, 0, 0, 0}, + {0xAF, 0x8, 0x8, 0, 0}, + {0xB0, 0x88, 0x88, 0, 0}, + {0xB1, 0, 0, 0, 0}, + {0xB2, 0x1b, 0x1b, 0, 0}, + {0xB3, 0x3, 0x3, 0, 0}, + {0xB4, 0x24, 0x24, 0, 0}, + {0xB5, 0x3, 0x3, 0, 0}, + {0xB6, 0x1b, 0x1b, 0, 0}, + {0xB7, 0x24, 0x24, 0, 0}, + {0xB8, 0x3, 0x3, 0, 0}, + {0xB9, 0, 0, 0, 0}, + {0xBA, 0xaa, 0xaa, 0, 0}, + {0xBB, 0, 0, 0, 0}, + {0xBC, 0x4, 0x4, 0, 0}, + {0xBD, 0, 0, 0, 0}, + {0xBE, 0x8, 0x8, 0, 0}, + {0xBF, 0x11, 0x11, 0, 0}, + {0xC0, 0, 0, 0, 0}, + {0xC1, 0, 0, 0, 0}, + {0xC2, 0x62, 0x62, 0, 0}, + {0xC3, 0x1e, 0x1e, 0, 0}, + {0xC4, 0x33, 0x33, 0, 0}, + {0xC5, 0x37, 0x37, 0, 0}, + {0xC6, 0, 0, 0, 0}, + {0xC7, 0x70, 0x70, 0, 0}, + {0xC8, 0x1e, 0x1e, 0, 0}, + {0xC9, 0x6, 0x6, 0, 0}, + {0xCA, 0x4, 0x4, 0, 0}, + {0xCB, 0x2f, 0x2f, 0, 0}, + {0xCC, 0xf, 0xf, 0, 0}, + {0xCD, 0, 0, 0, 0}, + {0xCE, 0xff, 0xff, 0, 0}, + {0xCF, 0x8, 0x8, 0, 0}, + {0xD0, 0x3f, 0x3f, 0, 0}, + {0xD1, 0x3f, 0x3f, 0, 0}, + {0xD2, 0x3f, 0x3f, 0, 0}, + {0xD3, 0, 0, 0, 0}, + {0xD4, 0, 0, 0, 0}, + {0xD5, 0, 0, 0, 0}, + {0xD6, 0xcc, 0xcc, 0, 0}, + {0xD7, 0, 0, 0, 0}, + {0xD8, 0x8, 0x8, 0, 0}, + {0xD9, 0x8, 0x8, 0, 0}, + {0xDA, 0x8, 0x8, 0, 0}, + {0xDB, 0x11, 0x11, 0, 0}, + {0xDC, 0, 0, 0, 0}, + {0xDD, 0x87, 0x87, 0, 0}, + {0xDE, 0x88, 0x88, 0, 0}, + {0xDF, 0x8, 0x8, 0, 0}, + {0xE0, 0x8, 0x8, 0, 0}, + {0xE1, 0x8, 0x8, 0, 0}, + {0xE2, 0, 0, 0, 0}, + {0xE3, 0, 0, 0, 0}, + {0xE4, 0, 0, 0, 0}, + {0xE5, 0xf5, 0xf5, 0, 0}, + {0xE6, 0x30, 0x30, 0, 0}, + {0xE7, 0x1, 0x1, 0, 0}, + {0xE8, 0, 0, 0, 0}, + {0xE9, 0xff, 0xff, 0, 0}, + {0xEA, 0, 0, 0, 0}, + {0xEB, 0, 0, 0, 0}, + {0xEC, 0x22, 0x22, 0, 0}, + {0xED, 0, 0, 0, 0}, + {0xEE, 0, 0, 0, 0}, + {0xEF, 0, 0, 0, 0}, + {0xF0, 0x3, 0x3, 0, 0}, + {0xF1, 0x1, 0x1, 0, 0}, + {0xF2, 0, 0, 0, 0}, + {0xF3, 0, 0, 0, 0}, + {0xF4, 0, 0, 0, 0}, + {0xF5, 0, 0, 0, 0}, + {0xF6, 0, 0, 0, 0}, + {0xF7, 0x6, 0x6, 0, 0}, + {0xF8, 0, 0, 0, 0}, + {0xF9, 0, 0, 0, 0}, + {0xFA, 0x40, 0x40, 0, 0}, + {0xFB, 0, 0, 0, 0}, + {0xFC, 0x1, 0x1, 0, 0}, + {0xFD, 0x80, 0x80, 0, 0}, + {0xFE, 0x2, 0x2, 0, 0}, + {0xFF, 0x10, 0x10, 0, 0}, + {0x100, 0x2, 0x2, 0, 0}, + {0x101, 0x1e, 0x1e, 0, 0}, + {0x102, 0x1e, 0x1e, 0, 0}, + {0x103, 0, 0, 0, 0}, + {0x104, 0x1f, 0x1f, 0, 0}, + {0x105, 0, 0x8, 0, 1}, + {0x106, 0x2a, 0x2a, 0, 0}, + {0x107, 0xf, 0xf, 0, 0}, + {0x108, 0, 0, 0, 0}, + {0x109, 0, 0, 0, 0}, + {0x10A, 0, 0, 0, 0}, + {0x10B, 0, 0, 0, 0}, + {0x10C, 0, 0, 0, 0}, + {0x10D, 0, 0, 0, 0}, + {0x10E, 0, 0, 0, 0}, + {0x10F, 0, 0, 0, 0}, + {0x110, 0, 0, 0, 0}, + {0x111, 0, 0, 0, 0}, + {0x112, 0, 0, 0, 0}, + {0x113, 0, 0, 0, 0}, + {0x114, 0, 0, 0, 0}, + {0x115, 0, 0, 0, 0}, + {0x116, 0, 0, 0, 0}, + {0x117, 0, 0, 0, 0}, + {0x118, 0, 0, 0, 0}, + {0x119, 0, 0, 0, 0}, + {0x11A, 0, 0, 0, 0}, + {0x11B, 0, 0, 0, 0}, + {0x11C, 0x1, 0x1, 0, 0}, + {0x11D, 0, 0, 0, 0}, + {0x11E, 0, 0, 0, 0}, + {0x11F, 0, 0, 0, 0}, + {0x120, 0, 0, 0, 0}, + {0x121, 0, 0, 0, 0}, + {0x122, 0x80, 0x80, 0, 0}, + {0x123, 0, 0, 0, 0}, + {0x124, 0xf8, 0xf8, 0, 0}, + {0x125, 0, 0, 0, 0}, + {0x126, 0, 0, 0, 0}, + {0x127, 0, 0, 0, 0}, + {0x128, 0, 0, 0, 0}, + {0x129, 0, 0, 0, 0}, + {0x12A, 0, 0, 0, 0}, + {0x12B, 0, 0, 0, 0}, + {0x12C, 0, 0, 0, 0}, + {0x12D, 0, 0, 0, 0}, + {0x12E, 0, 0, 0, 0}, + {0x12F, 0, 0, 0, 0}, + {0x130, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +#define LCNPHY_NUM_DIG_FILT_COEFFS 16 +#define LCNPHY_NUM_TX_DIG_FILTERS_CCK 13 + +static const u16 LCNPHY_txdigfiltcoeffs_cck[LCNPHY_NUM_TX_DIG_FILTERS_CCK] + [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = { + {0, 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778, 1582, 64, + 128, 64,}, + {1, 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608, 1863, 93, + 167, 93,}, + {2, 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192, 778, 1582, 64, + 128, 64,}, + {3, 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205, 754, 1760, + 170, 340, 170,}, + {20, 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205, 767, 1760, + 256, 185, 256,}, + {21, 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205, 767, 1760, + 256, 273, 256,}, + {22, 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205, 767, 1760, + 256, 352, 256,}, + {23, 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205, 767, 1760, + 128, 233, 128,}, + {24, 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766, 1760, 256, + 1881, 256,}, + {25, 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765, 1760, 256, + 1881, 256,}, + {26, 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614, 1864, 128, + 384, 288,}, + {27, 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576, 613, 1864, + 128, 384, 288,}, + {30, 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205, 754, 1760, + 170, 340, 170,}, +}; + +#define LCNPHY_NUM_TX_DIG_FILTERS_OFDM 3 +static const u16 LCNPHY_txdigfiltcoeffs_ofdm[LCNPHY_NUM_TX_DIG_FILTERS_OFDM] + [LCNPHY_NUM_DIG_FILT_COEFFS + 1] = { + {0, 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0, + 0x278, 0xfea0, 0x80, 0x100, 0x80,}, + {1, 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, + 750, 0xFE2B, 212, 0xFFCE, 212,}, + {2, 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748, + 0xFEF2, 128, 0xFFE2, 128} +}; + +#define wlc_lcnphy_set_start_tx_pwr_idx(pi, idx) \ + mod_phy_reg(pi, 0x4a4, \ + (0x1ff << 0), \ + (u16)(idx) << 0) + +#define wlc_lcnphy_set_tx_pwr_npt(pi, npt) \ + mod_phy_reg(pi, 0x4a5, \ + (0x7 << 8), \ + (u16)(npt) << 8) + +#define wlc_lcnphy_get_tx_pwr_ctrl(pi) \ + (read_phy_reg((pi), 0x4a4) & \ + ((0x1 << 15) | \ + (0x1 << 14) | \ + (0x1 << 13))) + +#define wlc_lcnphy_get_tx_pwr_npt(pi) \ + ((read_phy_reg(pi, 0x4a5) & \ + (0x7 << 8)) >> \ + 8) + +#define wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on(pi) \ + (read_phy_reg(pi, 0x473) & 0x1ff) + +#define wlc_lcnphy_get_target_tx_pwr(pi) \ + ((read_phy_reg(pi, 0x4a7) & \ + (0xff << 0)) >> \ + 0) + +#define wlc_lcnphy_set_target_tx_pwr(pi, target) \ + mod_phy_reg(pi, 0x4a7, \ + (0xff << 0), \ + (u16)(target) << 0) + +#define wlc_radio_2064_rcal_done(pi) \ + (0 != (read_radio_reg(pi, RADIO_2064_REG05C) & 0x20)) + +#define tempsense_done(pi) \ + (0x8000 == (read_phy_reg(pi, 0x476) & 0x8000)) + +#define LCNPHY_IQLOCC_READ(val) \ + ((u8)(-(s8)(((val) & 0xf0) >> 4) + (s8)((val) & 0x0f))) + +#define FIXED_TXPWR 78 +#define LCNPHY_TEMPSENSE(val) ((s16)((val > 255) ? (val - 512) : val)) + +void wlc_lcnphy_write_table(struct brcms_phy *pi, const struct phytbl_info *pti) +{ + wlc_phy_write_table(pi, pti, 0x455, 0x457, 0x456); +} + +void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti) +{ + wlc_phy_read_table(pi, pti, 0x455, 0x457, 0x456); +} + +static void +wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id, + const u16 *tbl_ptr, u32 tbl_len, + u32 tbl_width, u32 tbl_offset) +{ + struct phytbl_info tab; + tab.tbl_id = tbl_id; + tab.tbl_ptr = tbl_ptr; + tab.tbl_len = tbl_len; + tab.tbl_width = tbl_width; + tab.tbl_offset = tbl_offset; + wlc_lcnphy_read_table(pi, &tab); +} + +static void +wlc_lcnphy_common_write_table(struct brcms_phy *pi, u32 tbl_id, + const u16 *tbl_ptr, u32 tbl_len, + u32 tbl_width, u32 tbl_offset) +{ + + struct phytbl_info tab; + tab.tbl_id = tbl_id; + tab.tbl_ptr = tbl_ptr; + tab.tbl_len = tbl_len; + tab.tbl_width = tbl_width; + tab.tbl_offset = tbl_offset; + wlc_lcnphy_write_table(pi, &tab); +} + +static u32 +wlc_lcnphy_qdiv_roundup(u32 dividend, u32 divisor, u8 precision) +{ + u32 quotient, remainder, roundup, rbit; + + quotient = dividend / divisor; + remainder = dividend % divisor; + rbit = divisor & 1; + roundup = (divisor >> 1) + rbit; + + while (precision--) { + quotient <<= 1; + if (remainder >= roundup) { + quotient++; + remainder = ((remainder - roundup) << 1) + rbit; + } else { + remainder <<= 1; + } + } + + if (remainder >= roundup) + quotient++; + + return quotient; +} + +static int wlc_lcnphy_calc_floor(s16 coeff_x, int type) +{ + int k; + k = 0; + if (type == 0) { + if (coeff_x < 0) + k = (coeff_x - 1) / 2; + else + k = coeff_x / 2; + } + + if (type == 1) { + if ((coeff_x + 1) < 0) + k = (coeff_x) / 2; + else + k = (coeff_x + 1) / 2; + } + return k; +} + +static void +wlc_lcnphy_get_tx_gain(struct brcms_phy *pi, struct lcnphy_txgains *gains) +{ + u16 dac_gain, rfgain0, rfgain1; + + dac_gain = read_phy_reg(pi, 0x439) >> 0; + gains->dac_gain = (dac_gain & 0x380) >> 7; + + rfgain0 = (read_phy_reg(pi, 0x4b5) & (0xffff << 0)) >> 0; + rfgain1 = (read_phy_reg(pi, 0x4fb) & (0x7fff << 0)) >> 0; + + gains->gm_gain = rfgain0 & 0xff; + gains->pga_gain = (rfgain0 >> 8) & 0xff; + gains->pad_gain = rfgain1 & 0xff; +} + + +static void wlc_lcnphy_set_dac_gain(struct brcms_phy *pi, u16 dac_gain) +{ + u16 dac_ctrl; + + dac_ctrl = (read_phy_reg(pi, 0x439) >> 0); + dac_ctrl = dac_ctrl & 0xc7f; + dac_ctrl = dac_ctrl | (dac_gain << 7); + mod_phy_reg(pi, 0x439, (0xfff << 0), (dac_ctrl) << 0); + +} + +static void wlc_lcnphy_set_tx_gain_override(struct brcms_phy *pi, bool bEnable) +{ + u16 bit = bEnable ? 1 : 0; + + mod_phy_reg(pi, 0x4b0, (0x1 << 7), bit << 7); + + mod_phy_reg(pi, 0x4b0, (0x1 << 14), bit << 14); + + mod_phy_reg(pi, 0x43b, (0x1 << 6), bit << 6); +} + +static void +wlc_lcnphy_rx_gain_override_enable(struct brcms_phy *pi, bool enable) +{ + u16 ebit = enable ? 1 : 0; + + mod_phy_reg(pi, 0x4b0, (0x1 << 8), ebit << 8); + + mod_phy_reg(pi, 0x44c, (0x1 << 0), ebit << 0); + + if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { + mod_phy_reg(pi, 0x44c, (0x1 << 4), ebit << 4); + mod_phy_reg(pi, 0x44c, (0x1 << 6), ebit << 6); + mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5); + mod_phy_reg(pi, 0x4b0, (0x1 << 6), ebit << 6); + } else { + mod_phy_reg(pi, 0x4b0, (0x1 << 12), ebit << 12); + mod_phy_reg(pi, 0x4b0, (0x1 << 13), ebit << 13); + mod_phy_reg(pi, 0x4b0, (0x1 << 5), ebit << 5); + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + mod_phy_reg(pi, 0x4b0, (0x1 << 10), ebit << 10); + mod_phy_reg(pi, 0x4e5, (0x1 << 3), ebit << 3); + } +} + +static void +wlc_lcnphy_set_rx_gain_by_distribution(struct brcms_phy *pi, + u16 trsw, + u16 ext_lna, + u16 biq2, + u16 biq1, + u16 tia, u16 lna2, u16 lna1) +{ + u16 gain0_15, gain16_19; + + gain16_19 = biq2 & 0xf; + gain0_15 = ((biq1 & 0xf) << 12) | + ((tia & 0xf) << 8) | + ((lna2 & 0x3) << 6) | + ((lna2 & + 0x3) << 4) | ((lna1 & 0x3) << 2) | ((lna1 & 0x3) << 0); + + mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); + mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); + mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); + + if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { + mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); + mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10); + } else { + mod_phy_reg(pi, 0x4b1, (0x1 << 10), 0 << 10); + + mod_phy_reg(pi, 0x4b1, (0x1 << 15), 0 << 15); + + mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); + } + + mod_phy_reg(pi, 0x44d, (0x1 << 0), (!trsw) << 0); + +} + +static void wlc_lcnphy_set_trsw_override(struct brcms_phy *pi, bool tx, bool rx) +{ + + mod_phy_reg(pi, 0x44d, + (0x1 << 1) | + (0x1 << 0), (tx ? (0x1 << 1) : 0) | (rx ? (0x1 << 0) : 0)); + + or_phy_reg(pi, 0x44c, (0x1 << 1) | (0x1 << 0)); +} + +static void wlc_lcnphy_clear_trsw_override(struct brcms_phy *pi) +{ + + and_phy_reg(pi, 0x44c, (u16) ~((0x1 << 1) | (0x1 << 0))); +} + +static void wlc_lcnphy_set_rx_iq_comp(struct brcms_phy *pi, u16 a, u16 b) +{ + mod_phy_reg(pi, 0x645, (0x3ff << 0), (a) << 0); + + mod_phy_reg(pi, 0x646, (0x3ff << 0), (b) << 0); + + mod_phy_reg(pi, 0x647, (0x3ff << 0), (a) << 0); + + mod_phy_reg(pi, 0x648, (0x3ff << 0), (b) << 0); + + mod_phy_reg(pi, 0x649, (0x3ff << 0), (a) << 0); + + mod_phy_reg(pi, 0x64a, (0x3ff << 0), (b) << 0); + +} + +static bool +wlc_lcnphy_rx_iq_est(struct brcms_phy *pi, + u16 num_samps, + u8 wait_time, struct lcnphy_iq_est *iq_est) +{ + int wait_count = 0; + bool result = true; + u8 phybw40; + phybw40 = CHSPEC_IS40(pi->radio_chanspec); + + mod_phy_reg(pi, 0x6da, (0x1 << 5), (1) << 5); + + mod_phy_reg(pi, 0x410, (0x1 << 3), (0) << 3); + + mod_phy_reg(pi, 0x482, (0xffff << 0), (num_samps) << 0); + + mod_phy_reg(pi, 0x481, (0xff << 0), ((u16) wait_time) << 0); + + mod_phy_reg(pi, 0x481, (0x1 << 8), (0) << 8); + + mod_phy_reg(pi, 0x481, (0x1 << 9), (1) << 9); + + while (read_phy_reg(pi, 0x481) & (0x1 << 9)) { + + if (wait_count > (10 * 500)) { + result = false; + goto cleanup; + } + udelay(100); + wait_count++; + } + + iq_est->iq_prod = ((u32) read_phy_reg(pi, 0x483) << 16) | + (u32) read_phy_reg(pi, 0x484); + iq_est->i_pwr = ((u32) read_phy_reg(pi, 0x485) << 16) | + (u32) read_phy_reg(pi, 0x486); + iq_est->q_pwr = ((u32) read_phy_reg(pi, 0x487) << 16) | + (u32) read_phy_reg(pi, 0x488); + +cleanup: + mod_phy_reg(pi, 0x410, (0x1 << 3), (1) << 3); + + mod_phy_reg(pi, 0x6da, (0x1 << 5), (0) << 5); + + return result; +} + +static bool wlc_lcnphy_calc_rx_iq_comp(struct brcms_phy *pi, u16 num_samps) +{ +#define LCNPHY_MIN_RXIQ_PWR 2 + bool result; + u16 a0_new, b0_new; + struct lcnphy_iq_est iq_est = { 0, 0, 0 }; + s32 a, b, temp; + s16 iq_nbits, qq_nbits, arsh, brsh; + s32 iq; + u32 ii, qq; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + a0_new = ((read_phy_reg(pi, 0x645) & (0x3ff << 0)) >> 0); + b0_new = ((read_phy_reg(pi, 0x646) & (0x3ff << 0)) >> 0); + mod_phy_reg(pi, 0x6d1, (0x1 << 2), (0) << 2); + + mod_phy_reg(pi, 0x64b, (0x1 << 6), (1) << 6); + + wlc_lcnphy_set_rx_iq_comp(pi, 0, 0); + + result = wlc_lcnphy_rx_iq_est(pi, num_samps, 32, &iq_est); + if (!result) + goto cleanup; + + iq = (s32) iq_est.iq_prod; + ii = iq_est.i_pwr; + qq = iq_est.q_pwr; + + if ((ii + qq) < LCNPHY_MIN_RXIQ_PWR) { + result = false; + goto cleanup; + } + + iq_nbits = wlc_phy_nbits(iq); + qq_nbits = wlc_phy_nbits(qq); + + arsh = 10 - (30 - iq_nbits); + if (arsh >= 0) { + a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh))); + temp = (s32) (ii >> arsh); + if (temp == 0) + return false; + } else { + a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh))); + temp = (s32) (ii << -arsh); + if (temp == 0) + return false; + } + a /= temp; + brsh = qq_nbits - 31 + 20; + if (brsh >= 0) { + b = (qq << (31 - qq_nbits)); + temp = (s32) (ii >> brsh); + if (temp == 0) + return false; + } else { + b = (qq << (31 - qq_nbits)); + temp = (s32) (ii << -brsh); + if (temp == 0) + return false; + } + b /= temp; + b -= a * a; + b = (s32) int_sqrt((unsigned long) b); + b -= (1 << 10); + a0_new = (u16) (a & 0x3ff); + b0_new = (u16) (b & 0x3ff); +cleanup: + + wlc_lcnphy_set_rx_iq_comp(pi, a0_new, b0_new); + + mod_phy_reg(pi, 0x64b, (0x1 << 0), (1) << 0); + + mod_phy_reg(pi, 0x64b, (0x1 << 3), (1) << 3); + + pi_lcn->lcnphy_cal_results.rxiqcal_coeff_a0 = a0_new; + pi_lcn->lcnphy_cal_results.rxiqcal_coeff_b0 = b0_new; + + return result; +} + +static u32 wlc_lcnphy_measure_digital_power(struct brcms_phy *pi, u16 nsamples) +{ + struct lcnphy_iq_est iq_est = { 0, 0, 0 }; + + if (!wlc_lcnphy_rx_iq_est(pi, nsamples, 32, &iq_est)) + return 0; + return (iq_est.i_pwr + iq_est.q_pwr) / nsamples; +} + +static bool +wlc_lcnphy_rx_iq_cal(struct brcms_phy *pi, + const struct lcnphy_rx_iqcomp *iqcomp, + int iqcomp_sz, bool tx_switch, bool rx_switch, int module, + int tx_gain_idx) +{ + struct lcnphy_txgains old_gains; + u16 tx_pwr_ctrl; + u8 tx_gain_index_old = 0; + bool result = false, tx_gain_override_old = false; + u16 i, Core1TxControl_old, RFOverride0_old, + RFOverrideVal0_old, rfoverride2_old, rfoverride2val_old, + rfoverride3_old, rfoverride3val_old, rfoverride4_old, + rfoverride4val_old, afectrlovr_old, afectrlovrval_old; + int tia_gain; + u32 received_power, rx_pwr_threshold; + u16 old_sslpnCalibClkEnCtrl, old_sslpnRxFeClkEnCtrl; + u16 values_to_save[11]; + s16 *ptr; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC); + if (NULL == ptr) + return false; + if (module == 2) { + while (iqcomp_sz--) { + if (iqcomp[iqcomp_sz].chan == + CHSPEC_CHANNEL(pi->radio_chanspec)) { + wlc_lcnphy_set_rx_iq_comp(pi, + (u16) + iqcomp[iqcomp_sz].a, + (u16) + iqcomp[iqcomp_sz].b); + result = true; + break; + } + } + goto cal_done; + } + + if (module == 1) { + + tx_pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + + for (i = 0; i < 11; i++) + values_to_save[i] = + read_radio_reg(pi, rxiq_cal_rf_reg[i]); + Core1TxControl_old = read_phy_reg(pi, 0x631); + + or_phy_reg(pi, 0x631, 0x0015); + + RFOverride0_old = read_phy_reg(pi, 0x44c); + RFOverrideVal0_old = read_phy_reg(pi, 0x44d); + rfoverride2_old = read_phy_reg(pi, 0x4b0); + rfoverride2val_old = read_phy_reg(pi, 0x4b1); + rfoverride3_old = read_phy_reg(pi, 0x4f9); + rfoverride3val_old = read_phy_reg(pi, 0x4fa); + rfoverride4_old = read_phy_reg(pi, 0x938); + rfoverride4val_old = read_phy_reg(pi, 0x939); + afectrlovr_old = read_phy_reg(pi, 0x43b); + afectrlovrval_old = read_phy_reg(pi, 0x43c); + old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); + old_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); + + tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); + if (tx_gain_override_old) { + wlc_lcnphy_get_tx_gain(pi, &old_gains); + tx_gain_index_old = pi_lcn->lcnphy_current_index; + } + + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_idx); + + mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); + + mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); + + write_radio_reg(pi, RADIO_2064_REG116, 0x06); + write_radio_reg(pi, RADIO_2064_REG12C, 0x07); + write_radio_reg(pi, RADIO_2064_REG06A, 0xd3); + write_radio_reg(pi, RADIO_2064_REG098, 0x03); + write_radio_reg(pi, RADIO_2064_REG00B, 0x7); + mod_radio_reg(pi, RADIO_2064_REG113, 1 << 4, 1 << 4); + write_radio_reg(pi, RADIO_2064_REG01D, 0x01); + write_radio_reg(pi, RADIO_2064_REG114, 0x01); + write_radio_reg(pi, RADIO_2064_REG02E, 0x10); + write_radio_reg(pi, RADIO_2064_REG12A, 0x08); + + mod_phy_reg(pi, 0x938, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x939, (0x1 << 0), 0 << 0); + mod_phy_reg(pi, 0x938, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x939, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x938, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x939, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x938, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x939, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x938, (0x1 << 5), 1 << 5); + mod_phy_reg(pi, 0x939, (0x1 << 5), 0 << 5); + + mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); + + wlc_lcnphy_start_tx_tone(pi, 2000, 120, 0); + write_phy_reg(pi, 0x6da, 0xffff); + or_phy_reg(pi, 0x6db, 0x3); + wlc_lcnphy_set_trsw_override(pi, tx_switch, rx_switch); + wlc_lcnphy_rx_gain_override_enable(pi, true); + + tia_gain = 8; + rx_pwr_threshold = 950; + while (tia_gain > 0) { + tia_gain -= 1; + wlc_lcnphy_set_rx_gain_by_distribution(pi, + 0, 0, 2, 2, + (u16) + tia_gain, 1, 0); + udelay(500); + + received_power = + wlc_lcnphy_measure_digital_power(pi, 2000); + if (received_power < rx_pwr_threshold) + break; + } + result = wlc_lcnphy_calc_rx_iq_comp(pi, 0xffff); + + wlc_lcnphy_stop_tx_tone(pi); + + write_phy_reg(pi, 0x631, Core1TxControl_old); + + write_phy_reg(pi, 0x44c, RFOverrideVal0_old); + write_phy_reg(pi, 0x44d, RFOverrideVal0_old); + write_phy_reg(pi, 0x4b0, rfoverride2_old); + write_phy_reg(pi, 0x4b1, rfoverride2val_old); + write_phy_reg(pi, 0x4f9, rfoverride3_old); + write_phy_reg(pi, 0x4fa, rfoverride3val_old); + write_phy_reg(pi, 0x938, rfoverride4_old); + write_phy_reg(pi, 0x939, rfoverride4val_old); + write_phy_reg(pi, 0x43b, afectrlovr_old); + write_phy_reg(pi, 0x43c, afectrlovrval_old); + write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); + write_phy_reg(pi, 0x6db, old_sslpnRxFeClkEnCtrl); + + wlc_lcnphy_clear_trsw_override(pi); + + mod_phy_reg(pi, 0x44c, (0x1 << 2), 0 << 2); + + for (i = 0; i < 11; i++) + write_radio_reg(pi, rxiq_cal_rf_reg[i], + values_to_save[i]); + + if (tx_gain_override_old) + wlc_lcnphy_set_tx_pwr_by_index(pi, tx_gain_index_old); + else + wlc_lcnphy_disable_tx_gain_override(pi); + + wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl); + wlc_lcnphy_rx_gain_override_enable(pi, false); + } + +cal_done: + kfree(ptr); + return result; +} + +s8 wlc_lcnphy_get_current_tx_pwr_idx(struct brcms_phy *pi) +{ + s8 index; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + if (txpwrctrl_off(pi)) + index = pi_lcn->lcnphy_current_index; + else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) + index = (s8) (wlc_lcnphy_get_current_tx_pwr_idx_if_pwrctrl_on( + pi) / 2); + else + index = pi_lcn->lcnphy_current_index; + return index; +} + +void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel) +{ + u16 afectrlovr, afectrlovrval; + afectrlovr = read_phy_reg(pi, 0x43b); + afectrlovrval = read_phy_reg(pi, 0x43c); + if (channel != 0) { + mod_phy_reg(pi, 0x43b, (0x1 << 1), (1) << 1); + + mod_phy_reg(pi, 0x43c, (0x1 << 1), (0) << 1); + + mod_phy_reg(pi, 0x43b, (0x1 << 4), (1) << 4); + + mod_phy_reg(pi, 0x43c, (0x1 << 6), (0) << 6); + + write_phy_reg(pi, 0x44b, 0xffff); + wlc_lcnphy_tx_pu(pi, 1); + + mod_phy_reg(pi, 0x634, (0xff << 8), (0) << 8); + + or_phy_reg(pi, 0x6da, 0x0080); + + or_phy_reg(pi, 0x00a, 0x228); + } else { + and_phy_reg(pi, 0x00a, ~(0x228)); + + and_phy_reg(pi, 0x6da, 0xFF7F); + write_phy_reg(pi, 0x43b, afectrlovr); + write_phy_reg(pi, 0x43c, afectrlovrval); + } +} + +static void wlc_lcnphy_toggle_afe_pwdn(struct brcms_phy *pi) +{ + u16 save_AfeCtrlOvrVal, save_AfeCtrlOvr; + + save_AfeCtrlOvrVal = read_phy_reg(pi, 0x43c); + save_AfeCtrlOvr = read_phy_reg(pi, 0x43b); + + write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal | 0x1); + write_phy_reg(pi, 0x43b, save_AfeCtrlOvr | 0x1); + + write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal & 0xfffe); + write_phy_reg(pi, 0x43b, save_AfeCtrlOvr & 0xfffe); + + write_phy_reg(pi, 0x43c, save_AfeCtrlOvrVal); + write_phy_reg(pi, 0x43b, save_AfeCtrlOvr); +} + +static void +wlc_lcnphy_txrx_spur_avoidance_mode(struct brcms_phy *pi, bool enable) +{ + if (enable) { + write_phy_reg(pi, 0x942, 0x7); + write_phy_reg(pi, 0x93b, ((1 << 13) + 23)); + write_phy_reg(pi, 0x93c, ((1 << 13) + 1989)); + + write_phy_reg(pi, 0x44a, 0x084); + write_phy_reg(pi, 0x44a, 0x080); + write_phy_reg(pi, 0x6d3, 0x2222); + write_phy_reg(pi, 0x6d3, 0x2220); + } else { + write_phy_reg(pi, 0x942, 0x0); + write_phy_reg(pi, 0x93b, ((0 << 13) + 23)); + write_phy_reg(pi, 0x93c, ((0 << 13) + 1989)); + } + wlapi_switch_macfreq(pi->sh->physhim, enable); +} + +static void +wlc_lcnphy_set_chanspec_tweaks(struct brcms_phy *pi, u16 chanspec) +{ + u8 channel = CHSPEC_CHANNEL(chanspec); + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + if (channel == 14) + mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); + else + mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); + + pi_lcn->lcnphy_bandedge_corr = 2; + if (channel == 1) + pi_lcn->lcnphy_bandedge_corr = 4; + + if (channel == 1 || channel == 2 || channel == 3 || + channel == 4 || channel == 9 || + channel == 10 || channel == 11 || channel == 12) { + si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03000c04); + si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x0); + si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x200005c0); + + si_pmu_pllupd(pi->sh->sih); + write_phy_reg(pi, 0x942, 0); + wlc_lcnphy_txrx_spur_avoidance_mode(pi, false); + pi_lcn->lcnphy_spurmod = 0; + mod_phy_reg(pi, 0x424, (0xff << 8), (0x1b) << 8); + + write_phy_reg(pi, 0x425, 0x5907); + } else { + si_pmu_pllcontrol(pi->sh->sih, 0x2, 0xffffffff, 0x03140c04); + si_pmu_pllcontrol(pi->sh->sih, 0x3, 0xffffff, 0x333333); + si_pmu_pllcontrol(pi->sh->sih, 0x4, 0xffffffff, 0x202c2820); + + si_pmu_pllupd(pi->sh->sih); + write_phy_reg(pi, 0x942, 0); + wlc_lcnphy_txrx_spur_avoidance_mode(pi, true); + + pi_lcn->lcnphy_spurmod = 0; + mod_phy_reg(pi, 0x424, (0xff << 8), (0x1f) << 8); + + write_phy_reg(pi, 0x425, 0x590a); + } + + or_phy_reg(pi, 0x44a, 0x44); + write_phy_reg(pi, 0x44a, 0x80); +} + +static void +wlc_lcnphy_radio_2064_channel_tune_4313(struct brcms_phy *pi, u8 channel) +{ + uint i; + const struct chan_info_2064_lcnphy *ci; + u8 rfpll_doubler = 0; + u8 pll_pwrup, pll_pwrup_ovr; + s32 qFxtal, qFref, qFvco, qFcal; + u8 d15, d16, f16, e44, e45; + u32 div_int, div_frac, fvco3, fpfd, fref3, fcal_div; + u16 loop_bw, d30, setCount; + + u8 h29, h28_ten, e30, h30_ten, cp_current; + u16 g30, d28; + + ci = &chan_info_2064_lcnphy[0]; + rfpll_doubler = 1; + + mod_radio_reg(pi, RADIO_2064_REG09D, 0x4, 0x1 << 2); + + write_radio_reg(pi, RADIO_2064_REG09E, 0xf); + if (!rfpll_doubler) { + loop_bw = PLL_2064_LOOP_BW; + d30 = PLL_2064_D30; + } else { + loop_bw = PLL_2064_LOOP_BW_DOUBLER; + d30 = PLL_2064_D30_DOUBLER; + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + for (i = 0; i < ARRAY_SIZE(chan_info_2064_lcnphy); i++) + if (chan_info_2064_lcnphy[i].chan == channel) + break; + + if (i >= ARRAY_SIZE(chan_info_2064_lcnphy)) + return; + + ci = &chan_info_2064_lcnphy[i]; + } + + write_radio_reg(pi, RADIO_2064_REG02A, ci->logen_buftune); + + mod_radio_reg(pi, RADIO_2064_REG030, 0x3, ci->logen_rccr_tx); + + mod_radio_reg(pi, RADIO_2064_REG091, 0x3, ci->txrf_mix_tune_ctrl); + + mod_radio_reg(pi, RADIO_2064_REG038, 0xf, ci->pa_input_tune_g); + + mod_radio_reg(pi, RADIO_2064_REG030, 0x3 << 2, + (ci->logen_rccr_rx) << 2); + + mod_radio_reg(pi, RADIO_2064_REG05E, 0xf, ci->pa_rxrf_lna1_freq_tune); + + mod_radio_reg(pi, RADIO_2064_REG05E, (0xf) << 4, + (ci->pa_rxrf_lna2_freq_tune) << 4); + + write_radio_reg(pi, RADIO_2064_REG06C, ci->rxrf_rxrf_spare1); + + pll_pwrup = (u8) read_radio_reg(pi, RADIO_2064_REG044); + pll_pwrup_ovr = (u8) read_radio_reg(pi, RADIO_2064_REG12B); + + or_radio_reg(pi, RADIO_2064_REG044, 0x07); + + or_radio_reg(pi, RADIO_2064_REG12B, (0x07) << 1); + e44 = 0; + e45 = 0; + + fpfd = rfpll_doubler ? (pi->xtalfreq << 1) : (pi->xtalfreq); + if (pi->xtalfreq > 26000000) + e44 = 1; + if (pi->xtalfreq > 52000000) + e45 = 1; + if (e44 == 0) + fcal_div = 1; + else if (e45 == 0) + fcal_div = 2; + else + fcal_div = 4; + fvco3 = (ci->freq * 3); + fref3 = 2 * fpfd; + + qFxtal = wlc_lcnphy_qdiv_roundup(pi->xtalfreq, PLL_2064_MHZ, 16); + qFref = wlc_lcnphy_qdiv_roundup(fpfd, PLL_2064_MHZ, 16); + qFcal = pi->xtalfreq * fcal_div / PLL_2064_MHZ; + qFvco = wlc_lcnphy_qdiv_roundup(fvco3, 2, 16); + + write_radio_reg(pi, RADIO_2064_REG04F, 0x02); + + d15 = (pi->xtalfreq * fcal_div * 4 / 5) / PLL_2064_MHZ - 1; + write_radio_reg(pi, RADIO_2064_REG052, (0x07 & (d15 >> 2))); + write_radio_reg(pi, RADIO_2064_REG053, (d15 & 0x3) << 5); + + d16 = (qFcal * 8 / (d15 + 1)) - 1; + write_radio_reg(pi, RADIO_2064_REG051, d16); + + f16 = ((d16 + 1) * (d15 + 1)) / qFcal; + setCount = f16 * 3 * (ci->freq) / 32 - 1; + mod_radio_reg(pi, RADIO_2064_REG053, (0x0f << 0), + (u8) (setCount >> 8)); + + or_radio_reg(pi, RADIO_2064_REG053, 0x10); + write_radio_reg(pi, RADIO_2064_REG054, (u8) (setCount & 0xff)); + + div_int = ((fvco3 * (PLL_2064_MHZ >> 4)) / fref3) << 4; + + div_frac = ((fvco3 * (PLL_2064_MHZ >> 4)) % fref3) << 4; + while (div_frac >= fref3) { + div_int++; + div_frac -= fref3; + } + div_frac = wlc_lcnphy_qdiv_roundup(div_frac, fref3, 20); + + mod_radio_reg(pi, RADIO_2064_REG045, (0x1f << 0), + (u8) (div_int >> 4)); + mod_radio_reg(pi, RADIO_2064_REG046, (0x1f << 4), + (u8) (div_int << 4)); + mod_radio_reg(pi, RADIO_2064_REG046, (0x0f << 0), + (u8) (div_frac >> 16)); + write_radio_reg(pi, RADIO_2064_REG047, (u8) (div_frac >> 8) & 0xff); + write_radio_reg(pi, RADIO_2064_REG048, (u8) div_frac & 0xff); + + write_radio_reg(pi, RADIO_2064_REG040, 0xfb); + + write_radio_reg(pi, RADIO_2064_REG041, 0x9A); + write_radio_reg(pi, RADIO_2064_REG042, 0xA3); + write_radio_reg(pi, RADIO_2064_REG043, 0x0C); + + h29 = LCN_BW_LMT / loop_bw; + d28 = (((PLL_2064_HIGH_END_KVCO - PLL_2064_LOW_END_KVCO) * + (fvco3 / 2 - PLL_2064_LOW_END_VCO)) / + (PLL_2064_HIGH_END_VCO - PLL_2064_LOW_END_VCO)) + + PLL_2064_LOW_END_KVCO; + h28_ten = (d28 * 10) / LCN_VCO_DIV; + e30 = (d30 - LCN_OFFSET) / LCN_FACT; + g30 = LCN_OFFSET + (e30 * LCN_FACT); + h30_ten = (g30 * 10) / LCN_CUR_DIV; + cp_current = ((LCN_CUR_LMT * h29 * LCN_MULT * 100) / h28_ten) / h30_ten; + mod_radio_reg(pi, RADIO_2064_REG03C, 0x3f, cp_current); + + if (channel >= 1 && channel <= 5) + write_radio_reg(pi, RADIO_2064_REG03C, 0x8); + else + write_radio_reg(pi, RADIO_2064_REG03C, 0x7); + write_radio_reg(pi, RADIO_2064_REG03D, 0x3); + + mod_radio_reg(pi, RADIO_2064_REG044, 0x0c, 0x0c); + udelay(1); + + wlc_2064_vco_cal(pi); + + write_radio_reg(pi, RADIO_2064_REG044, pll_pwrup); + write_radio_reg(pi, RADIO_2064_REG12B, pll_pwrup_ovr); + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { + write_radio_reg(pi, RADIO_2064_REG038, 3); + write_radio_reg(pi, RADIO_2064_REG091, 7); + } +} + +static int +wlc_lcnphy_load_tx_iir_filter(struct brcms_phy *pi, bool is_ofdm, s16 filt_type) +{ + s16 filt_index = -1; + int j; + + u16 addr[] = { + 0x910, + 0x91e, + 0x91f, + 0x924, + 0x925, + 0x926, + 0x920, + 0x921, + 0x927, + 0x928, + 0x929, + 0x922, + 0x923, + 0x930, + 0x931, + 0x932 + }; + + u16 addr_ofdm[] = { + 0x90f, + 0x900, + 0x901, + 0x906, + 0x907, + 0x908, + 0x902, + 0x903, + 0x909, + 0x90a, + 0x90b, + 0x904, + 0x905, + 0x90c, + 0x90d, + 0x90e + }; + + if (!is_ofdm) { + for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_CCK; j++) { + if (filt_type == LCNPHY_txdigfiltcoeffs_cck[j][0]) { + filt_index = (s16) j; + break; + } + } + + if (filt_index != -1) { + for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, addr[j], + LCNPHY_txdigfiltcoeffs_cck + [filt_index][j + 1]); + } + } else { + for (j = 0; j < LCNPHY_NUM_TX_DIG_FILTERS_OFDM; j++) { + if (filt_type == LCNPHY_txdigfiltcoeffs_ofdm[j][0]) { + filt_index = (s16) j; + break; + } + } + + if (filt_index != -1) { + for (j = 0; j < LCNPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, addr_ofdm[j], + LCNPHY_txdigfiltcoeffs_ofdm + [filt_index][j + 1]); + } + } + + return (filt_index != -1) ? 0 : -1; +} + +void wlc_phy_chanspec_set_lcnphy(struct brcms_phy *pi, u16 chanspec) +{ + u8 channel = CHSPEC_CHANNEL(chanspec); + + wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec); + + wlc_lcnphy_set_chanspec_tweaks(pi, pi->radio_chanspec); + + or_phy_reg(pi, 0x44a, 0x44); + write_phy_reg(pi, 0x44a, 0x80); + + wlc_lcnphy_radio_2064_channel_tune_4313(pi, channel); + udelay(1000); + + wlc_lcnphy_toggle_afe_pwdn(pi); + + write_phy_reg(pi, 0x657, lcnphy_sfo_cfg[channel - 1].ptcentreTs20); + write_phy_reg(pi, 0x658, lcnphy_sfo_cfg[channel - 1].ptcentreFactor); + + if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { + mod_phy_reg(pi, 0x448, (0x3 << 8), (2) << 8); + + wlc_lcnphy_load_tx_iir_filter(pi, false, 3); + } else { + mod_phy_reg(pi, 0x448, (0x3 << 8), (1) << 8); + + wlc_lcnphy_load_tx_iir_filter(pi, false, 2); + } + + wlc_lcnphy_load_tx_iir_filter(pi, true, 0); + + mod_phy_reg(pi, 0x4eb, (0x7 << 3), (1) << 3); + +} + +static u16 wlc_lcnphy_get_pa_gain(struct brcms_phy *pi) +{ + u16 pa_gain; + + pa_gain = (read_phy_reg(pi, 0x4fb) & + LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK) >> + LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT; + + return pa_gain; +} + +static void wlc_lcnphy_set_tx_gain(struct brcms_phy *pi, + struct lcnphy_txgains *target_gains) +{ + u16 pa_gain = wlc_lcnphy_get_pa_gain(pi); + + mod_phy_reg( + pi, 0x4b5, + (0xffff << 0), + ((target_gains->gm_gain) | + (target_gains->pga_gain << 8)) << + 0); + mod_phy_reg(pi, 0x4fb, + (0x7fff << 0), + ((target_gains->pad_gain) | (pa_gain << 8)) << 0); + + mod_phy_reg( + pi, 0x4fc, + (0xffff << 0), + ((target_gains->gm_gain) | + (target_gains->pga_gain << 8)) << + 0); + mod_phy_reg(pi, 0x4fd, + (0x7fff << 0), + ((target_gains->pad_gain) | (pa_gain << 8)) << 0); + + wlc_lcnphy_set_dac_gain(pi, target_gains->dac_gain); + + wlc_lcnphy_enable_tx_gain_override(pi); +} + +static void wlc_lcnphy_set_bbmult(struct brcms_phy *pi, u8 m0) +{ + u16 m0m1 = (u16) m0 << 8; + struct phytbl_info tab; + + tab.tbl_ptr = &m0m1; + tab.tbl_len = 1; + tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; + tab.tbl_offset = 87; + tab.tbl_width = 16; + wlc_lcnphy_write_table(pi, &tab); +} + +static void wlc_lcnphy_clear_tx_power_offsets(struct brcms_phy *pi) +{ + u32 data_buf[64]; + struct phytbl_info tab; + + memset(data_buf, 0, sizeof(data_buf)); + + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_ptr = data_buf; + + if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { + + tab.tbl_len = 30; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; + wlc_lcnphy_write_table(pi, &tab); + } + + tab.tbl_len = 64; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_MAC_OFFSET; + wlc_lcnphy_write_table(pi, &tab); +} + +enum lcnphy_tssi_mode { + LCNPHY_TSSI_PRE_PA, + LCNPHY_TSSI_POST_PA, + LCNPHY_TSSI_EXT +}; + +static void +wlc_lcnphy_set_tssi_mux(struct brcms_phy *pi, enum lcnphy_tssi_mode pos) +{ + mod_phy_reg(pi, 0x4d7, (0x1 << 0), (0x1) << 0); + + mod_phy_reg(pi, 0x4d7, (0x1 << 6), (1) << 6); + + if (LCNPHY_TSSI_POST_PA == pos) { + mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0) << 2); + + mod_phy_reg(pi, 0x4d9, (0x1 << 3), (1) << 3); + + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { + mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); + } else { + mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0x1); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); + } + } else { + mod_phy_reg(pi, 0x4d9, (0x1 << 2), (0x1) << 2); + + mod_phy_reg(pi, 0x4d9, (0x1 << 3), (0) << 3); + + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { + mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); + } else { + mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 0x8); + } + } + mod_phy_reg(pi, 0x637, (0x3 << 14), (0) << 14); + + if (LCNPHY_TSSI_EXT == pos) { + write_radio_reg(pi, RADIO_2064_REG07F, 1); + mod_radio_reg(pi, RADIO_2064_REG005, 0x7, 0x2); + mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 0x1 << 7); + mod_radio_reg(pi, RADIO_2064_REG028, 0x1f, 0x3); + } +} + +static u16 wlc_lcnphy_rfseq_tbl_adc_pwrup(struct brcms_phy *pi) +{ + u16 N1, N2, N3, N4, N5, N6, N; + N1 = ((read_phy_reg(pi, 0x4a5) & (0xff << 0)) + >> 0); + N2 = 1 << ((read_phy_reg(pi, 0x4a5) & (0x7 << 12)) + >> 12); + N3 = ((read_phy_reg(pi, 0x40d) & (0xff << 0)) + >> 0); + N4 = 1 << ((read_phy_reg(pi, 0x40d) & (0x7 << 8)) + >> 8); + N5 = ((read_phy_reg(pi, 0x4a2) & (0xff << 0)) + >> 0); + N6 = 1 << ((read_phy_reg(pi, 0x4a2) & (0x7 << 8)) + >> 8); + N = 2 * (N1 + N2 + N3 + N4 + 2 * (N5 + N6)) + 80; + if (N < 1600) + N = 1600; + return N; +} + +static void wlc_lcnphy_pwrctrl_rssiparams(struct brcms_phy *pi) +{ + u16 auxpga_vmid, auxpga_vmid_temp, auxpga_gain_temp; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + auxpga_vmid = (2 << 8) | + (pi_lcn->lcnphy_rssi_vc << 4) | pi_lcn->lcnphy_rssi_vf; + auxpga_vmid_temp = (2 << 8) | (8 << 4) | 4; + auxpga_gain_temp = 2; + + mod_phy_reg(pi, 0x4d8, (0x1 << 0), (0) << 0); + + mod_phy_reg(pi, 0x4d8, (0x1 << 1), (0) << 1); + + mod_phy_reg(pi, 0x4d7, (0x1 << 3), (0) << 3); + + mod_phy_reg(pi, 0x4db, + (0x3ff << 0) | + (0x7 << 12), + (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); + + mod_phy_reg(pi, 0x4dc, + (0x3ff << 0) | + (0x7 << 12), + (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); + + mod_phy_reg(pi, 0x40a, + (0x3ff << 0) | + (0x7 << 12), + (auxpga_vmid << 0) | (pi_lcn->lcnphy_rssi_gs << 12)); + + mod_phy_reg(pi, 0x40b, + (0x3ff << 0) | + (0x7 << 12), + (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); + + mod_phy_reg(pi, 0x40c, + (0x3ff << 0) | + (0x7 << 12), + (auxpga_vmid_temp << 0) | (auxpga_gain_temp << 12)); + + mod_radio_reg(pi, RADIO_2064_REG082, (1 << 5), (1 << 5)); +} + +static void wlc_lcnphy_tssi_setup(struct brcms_phy *pi) +{ + struct phytbl_info tab; + u32 rfseq, ind; + + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_ptr = &ind; + tab.tbl_len = 1; + tab.tbl_offset = 0; + for (ind = 0; ind < 128; ind++) { + wlc_lcnphy_write_table(pi, &tab); + tab.tbl_offset++; + } + tab.tbl_offset = 704; + for (ind = 0; ind < 128; ind++) { + wlc_lcnphy_write_table(pi, &tab); + tab.tbl_offset++; + } + mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0); + + mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2); + + mod_phy_reg(pi, 0x503, (0x1 << 4), (1) << 4); + + wlc_lcnphy_set_tssi_mux(pi, LCNPHY_TSSI_EXT); + mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); + + mod_phy_reg(pi, 0x4a4, (0x1 << 15), (1) << 15); + + mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5); + + mod_phy_reg(pi, 0x4a4, (0x1ff << 0), (0) << 0); + + mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0); + + mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12); + + mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8); + + mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0); + + mod_phy_reg(pi, 0x40d, (0x7 << 8), (4) << 8); + + mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0); + + mod_phy_reg(pi, 0x4a2, (0x7 << 8), (4) << 8); + + mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (0) << 6); + + mod_phy_reg(pi, 0x4a8, (0xff << 0), (0x1) << 0); + + wlc_lcnphy_clear_tx_power_offsets(pi); + + mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15); + + mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (0xff) << 0); + + mod_phy_reg(pi, 0x49a, (0x1ff << 0), (0xff) << 0); + + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { + mod_radio_reg(pi, RADIO_2064_REG028, 0xf, 0xe); + mod_radio_reg(pi, RADIO_2064_REG086, 0x4, 0x4); + } else { + mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); + mod_radio_reg(pi, RADIO_2064_REG11A, 0x8, 1 << 3); + } + + write_radio_reg(pi, RADIO_2064_REG025, 0xc); + + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { + mod_radio_reg(pi, RADIO_2064_REG03A, 0x1, 1); + } else { + if (CHSPEC_IS2G(pi->radio_chanspec)) + mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1); + else + mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 0 << 1); + } + + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) + mod_radio_reg(pi, RADIO_2064_REG03A, 0x2, 1 << 1); + else + mod_radio_reg(pi, RADIO_2064_REG03A, 0x4, 1 << 2); + + mod_radio_reg(pi, RADIO_2064_REG11A, 0x1, 1 << 0); + + mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 1 << 3); + + if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) + mod_phy_reg(pi, 0x4d7, + (0x1 << 3) | (0x7 << 12), 0 << 3 | 2 << 12); + + rfseq = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi); + tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; + tab.tbl_width = 16; + tab.tbl_ptr = &rfseq; + tab.tbl_len = 1; + tab.tbl_offset = 6; + wlc_lcnphy_write_table(pi, &tab); + + mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2); + + mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2); + + mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); + + mod_phy_reg(pi, 0x4d7, (0x1 << 2), (1) << 2); + + mod_phy_reg(pi, 0x4d7, (0xf << 8), (0) << 8); + + wlc_lcnphy_pwrctrl_rssiparams(pi); +} + +void wlc_lcnphy_tx_pwr_update_npt(struct brcms_phy *pi) +{ + u16 tx_cnt, tx_total, npt; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + tx_total = wlc_lcnphy_total_tx_frames(pi); + tx_cnt = tx_total - pi_lcn->lcnphy_tssi_tx_cnt; + npt = wlc_lcnphy_get_tx_pwr_npt(pi); + + if (tx_cnt > (1 << npt)) { + + pi_lcn->lcnphy_tssi_tx_cnt = tx_total; + + pi_lcn->lcnphy_tssi_idx = wlc_lcnphy_get_current_tx_pwr_idx(pi); + pi_lcn->lcnphy_tssi_npt = npt; + + } +} + +s32 wlc_lcnphy_tssi2dbm(s32 tssi, s32 a1, s32 b0, s32 b1) +{ + s32 a, b, p; + + a = 32768 + (a1 * tssi); + b = (1024 * b0) + (64 * b1 * tssi); + p = ((2 * b) + a) / (2 * a); + + return p; +} + +static void wlc_lcnphy_txpower_reset_npt(struct brcms_phy *pi) +{ + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) + return; + + pi_lcn->lcnphy_tssi_idx = LCNPHY_TX_PWR_CTRL_START_INDEX_2G_4313; + pi_lcn->lcnphy_tssi_npt = LCNPHY_TX_PWR_CTRL_START_NPT; +} + +void wlc_lcnphy_txpower_recalc_target(struct brcms_phy *pi) +{ + struct phytbl_info tab; + u32 rate_table[BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM + + BRCMS_NUM_RATES_MCS_1_STREAM]; + uint i, j; + if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) + return; + + for (i = 0, j = 0; i < ARRAY_SIZE(rate_table); i++, j++) { + + if (i == BRCMS_NUM_RATES_CCK + BRCMS_NUM_RATES_OFDM) + j = TXP_FIRST_MCS_20_SISO; + + rate_table[i] = (u32) ((s32) (-pi->tx_power_offset[j])); + } + + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_len = ARRAY_SIZE(rate_table); + tab.tbl_ptr = rate_table; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; + wlc_lcnphy_write_table(pi, &tab); + + if (wlc_lcnphy_get_target_tx_pwr(pi) != pi->tx_power_min) { + wlc_lcnphy_set_target_tx_pwr(pi, pi->tx_power_min); + + wlc_lcnphy_txpower_reset_npt(pi); + } +} + +static void wlc_lcnphy_set_tx_pwr_soft_ctrl(struct brcms_phy *pi, s8 index) +{ + u32 cck_offset[4] = { 22, 22, 22, 22 }; + u32 ofdm_offset, reg_offset_cck; + int i; + u16 index2; + struct phytbl_info tab; + + if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) + return; + + mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14); + + mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x0) << 14); + + or_phy_reg(pi, 0x6da, 0x0040); + + reg_offset_cck = 0; + for (i = 0; i < 4; i++) + cck_offset[i] -= reg_offset_cck; + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_len = 4; + tab.tbl_ptr = cck_offset; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; + wlc_lcnphy_write_table(pi, &tab); + ofdm_offset = 0; + tab.tbl_len = 1; + tab.tbl_ptr = &ofdm_offset; + for (i = 836; i < 862; i++) { + tab.tbl_offset = i; + wlc_lcnphy_write_table(pi, &tab); + } + + mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0x1) << 15); + + mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0x1) << 14); + + mod_phy_reg(pi, 0x4a4, (0x1 << 13), (0x1) << 13); + + mod_phy_reg(pi, 0x4b0, (0x1 << 7), (0) << 7); + + mod_phy_reg(pi, 0x43b, (0x1 << 6), (0) << 6); + + mod_phy_reg(pi, 0x4a9, (0x1 << 15), (1) << 15); + + index2 = (u16) (index * 2); + mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0); + + mod_phy_reg(pi, 0x6a3, (0x1 << 4), (0) << 4); + +} + +static s8 wlc_lcnphy_tempcompensated_txpwrctrl(struct brcms_phy *pi) +{ + s8 index, delta_brd, delta_temp, new_index, tempcorrx; + s16 manp, meas_temp, temp_diff; + bool neg = 0; + u16 temp; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) + return pi_lcn->lcnphy_current_index; + + index = FIXED_TXPWR; + + if (pi_lcn->lcnphy_tempsense_slope == 0) + return index; + + temp = (u16) wlc_lcnphy_tempsense(pi, 0); + meas_temp = LCNPHY_TEMPSENSE(temp); + + if (pi->tx_power_min != 0) + delta_brd = (pi_lcn->lcnphy_measPower - pi->tx_power_min); + else + delta_brd = 0; + + manp = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_rawtempsense); + temp_diff = manp - meas_temp; + if (temp_diff < 0) { + neg = 1; + temp_diff = -temp_diff; + } + + delta_temp = (s8) wlc_lcnphy_qdiv_roundup((u32) (temp_diff * 192), + (u32) (pi_lcn-> + lcnphy_tempsense_slope + * 10), 0); + if (neg) + delta_temp = -delta_temp; + + if (pi_lcn->lcnphy_tempsense_option == 3 + && LCNREV_IS(pi->pubpi.phy_rev, 0)) + delta_temp = 0; + if (pi_lcn->lcnphy_tempcorrx > 31) + tempcorrx = (s8) (pi_lcn->lcnphy_tempcorrx - 64); + else + tempcorrx = (s8) pi_lcn->lcnphy_tempcorrx; + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) + tempcorrx = 4; + new_index = + index + delta_brd + delta_temp - pi_lcn->lcnphy_bandedge_corr; + new_index += tempcorrx; + + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) + index = 127; + + if (new_index < 0 || new_index > 126) + return index; + + return new_index; +} + +static u16 wlc_lcnphy_set_tx_pwr_ctrl_mode(struct brcms_phy *pi, u16 mode) +{ + + u16 current_mode = mode; + if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && + mode == LCNPHY_TX_PWR_CTRL_HW) + current_mode = LCNPHY_TX_PWR_CTRL_TEMPBASED; + if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) && + mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) + current_mode = LCNPHY_TX_PWR_CTRL_HW; + return current_mode; +} + +void wlc_lcnphy_set_tx_pwr_ctrl(struct brcms_phy *pi, u16 mode) +{ + u16 old_mode = wlc_lcnphy_get_tx_pwr_ctrl(pi); + s8 index; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, mode); + old_mode = wlc_lcnphy_set_tx_pwr_ctrl_mode(pi, old_mode); + + mod_phy_reg(pi, 0x6da, (0x1 << 6), + ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 1 : 0) << 6); + + mod_phy_reg(pi, 0x6a3, (0x1 << 4), + ((LCNPHY_TX_PWR_CTRL_HW == mode) ? 0 : 1) << 4); + + if (old_mode != mode) { + if (LCNPHY_TX_PWR_CTRL_HW == old_mode) { + + wlc_lcnphy_tx_pwr_update_npt(pi); + + wlc_lcnphy_clear_tx_power_offsets(pi); + } + if (LCNPHY_TX_PWR_CTRL_HW == mode) { + + wlc_lcnphy_txpower_recalc_target(pi); + + wlc_lcnphy_set_start_tx_pwr_idx(pi, + pi_lcn-> + lcnphy_tssi_idx); + wlc_lcnphy_set_tx_pwr_npt(pi, pi_lcn->lcnphy_tssi_npt); + mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0); + + pi_lcn->lcnphy_tssi_tx_cnt = + wlc_lcnphy_total_tx_frames(pi); + + wlc_lcnphy_disable_tx_gain_override(pi); + pi_lcn->lcnphy_tx_power_idx_override = -1; + } else + wlc_lcnphy_enable_tx_gain_override(pi); + + mod_phy_reg(pi, 0x4a4, + ((0x1 << 15) | (0x1 << 14) | (0x1 << 13)), mode); + if (mode == LCNPHY_TX_PWR_CTRL_TEMPBASED) { + index = wlc_lcnphy_tempcompensated_txpwrctrl(pi); + wlc_lcnphy_set_tx_pwr_soft_ctrl(pi, index); + pi_lcn->lcnphy_current_index = (s8) + ((read_phy_reg(pi, + 0x4a9) & + 0xFF) / 2); + } + } +} + +static void +wlc_lcnphy_tx_iqlo_loopback(struct brcms_phy *pi, u16 *values_to_save) +{ + u16 vmid; + int i; + for (i = 0; i < 20; i++) + values_to_save[i] = + read_radio_reg(pi, iqlo_loopback_rf_regs[i]); + + mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12); + mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14); + + mod_phy_reg(pi, 0x44c, (0x1 << 11), 1 << 11); + mod_phy_reg(pi, 0x44d, (0x1 << 13), 0 << 13); + + mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); + + mod_phy_reg(pi, 0x43b, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x43c, (0x1 << 0), 0 << 0); + + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) + and_radio_reg(pi, RADIO_2064_REG03A, 0xFD); + else + and_radio_reg(pi, RADIO_2064_REG03A, 0xF9); + or_radio_reg(pi, RADIO_2064_REG11A, 0x1); + + or_radio_reg(pi, RADIO_2064_REG036, 0x01); + or_radio_reg(pi, RADIO_2064_REG11A, 0x18); + udelay(20); + + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { + if (CHSPEC_IS5G(pi->radio_chanspec)) + mod_radio_reg(pi, RADIO_2064_REG03A, 1, 0); + else + or_radio_reg(pi, RADIO_2064_REG03A, 1); + } else { + if (CHSPEC_IS5G(pi->radio_chanspec)) + mod_radio_reg(pi, RADIO_2064_REG03A, 3, 1); + else + or_radio_reg(pi, RADIO_2064_REG03A, 0x3); + } + + udelay(20); + + write_radio_reg(pi, RADIO_2064_REG025, 0xF); + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { + if (CHSPEC_IS5G(pi->radio_chanspec)) + mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x4); + else + mod_radio_reg(pi, RADIO_2064_REG028, 0xF, 0x6); + } else { + if (CHSPEC_IS5G(pi->radio_chanspec)) + mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x4 << 1); + else + mod_radio_reg(pi, RADIO_2064_REG028, 0x1e, 0x6 << 1); + } + + udelay(20); + + write_radio_reg(pi, RADIO_2064_REG005, 0x8); + or_radio_reg(pi, RADIO_2064_REG112, 0x80); + udelay(20); + + or_radio_reg(pi, RADIO_2064_REG0FF, 0x10); + or_radio_reg(pi, RADIO_2064_REG11F, 0x44); + udelay(20); + + or_radio_reg(pi, RADIO_2064_REG00B, 0x7); + or_radio_reg(pi, RADIO_2064_REG113, 0x10); + udelay(20); + + write_radio_reg(pi, RADIO_2064_REG007, 0x1); + udelay(20); + + vmid = 0x2A6; + mod_radio_reg(pi, RADIO_2064_REG0FC, 0x3 << 0, (vmid >> 8) & 0x3); + write_radio_reg(pi, RADIO_2064_REG0FD, (vmid & 0xff)); + or_radio_reg(pi, RADIO_2064_REG11F, 0x44); + udelay(20); + + or_radio_reg(pi, RADIO_2064_REG0FF, 0x10); + udelay(20); + write_radio_reg(pi, RADIO_2064_REG012, 0x02); + or_radio_reg(pi, RADIO_2064_REG112, 0x06); + write_radio_reg(pi, RADIO_2064_REG036, 0x11); + write_radio_reg(pi, RADIO_2064_REG059, 0xcc); + write_radio_reg(pi, RADIO_2064_REG05C, 0x2e); + write_radio_reg(pi, RADIO_2064_REG078, 0xd7); + write_radio_reg(pi, RADIO_2064_REG092, 0x15); +} + +static bool wlc_lcnphy_iqcal_wait(struct brcms_phy *pi) +{ + uint delay_count = 0; + + while (wlc_lcnphy_iqcal_active(pi)) { + udelay(100); + delay_count++; + + if (delay_count > (10 * 500)) + break; + } + + return (0 == wlc_lcnphy_iqcal_active(pi)); +} + +static void +wlc_lcnphy_tx_iqlo_loopback_cleanup(struct brcms_phy *pi, u16 *values_to_save) +{ + int i; + + and_phy_reg(pi, 0x44c, 0x0 >> 11); + + and_phy_reg(pi, 0x43b, 0xC); + + for (i = 0; i < 20; i++) + write_radio_reg(pi, iqlo_loopback_rf_regs[i], + values_to_save[i]); +} + +static void +wlc_lcnphy_tx_iqlo_cal(struct brcms_phy *pi, + struct lcnphy_txgains *target_gains, + enum lcnphy_cal_mode cal_mode, bool keep_tone) +{ + + struct lcnphy_txgains cal_gains, temp_gains; + u16 hash; + u8 band_idx; + int j; + u16 ncorr_override[5]; + u16 syst_coeffs[] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; + + u16 commands_fullcal[] = { + 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 + }; + + u16 commands_recal[] = { + 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234 + }; + + u16 command_nums_fullcal[] = { + 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 + }; + + u16 command_nums_recal[] = { + 0x7a97, 0x7a97, 0x7a97, 0x7a87, 0x7a87, 0x7b97 + }; + u16 *command_nums = command_nums_fullcal; + + u16 *start_coeffs = NULL, *cal_cmds = NULL, cal_type, diq_start; + u16 tx_pwr_ctrl_old, save_txpwrctrlrfctrl2; + u16 save_sslpnCalibClkEnCtrl, save_sslpnRxFeClkEnCtrl; + bool tx_gain_override_old; + struct lcnphy_txgains old_gains; + uint i, n_cal_cmds = 0, n_cal_start = 0; + u16 *values_to_save; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + values_to_save = kmalloc(sizeof(u16) * 20, GFP_ATOMIC); + if (NULL == values_to_save) + return; + + save_sslpnRxFeClkEnCtrl = read_phy_reg(pi, 0x6db); + save_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); + + or_phy_reg(pi, 0x6da, 0x40); + or_phy_reg(pi, 0x6db, 0x3); + + switch (cal_mode) { + case LCNPHY_CAL_FULL: + start_coeffs = syst_coeffs; + cal_cmds = commands_fullcal; + n_cal_cmds = ARRAY_SIZE(commands_fullcal); + break; + + case LCNPHY_CAL_RECAL: + start_coeffs = syst_coeffs; + cal_cmds = commands_recal; + n_cal_cmds = ARRAY_SIZE(commands_recal); + command_nums = command_nums_recal; + break; + + default: + break; + } + + wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, + start_coeffs, 11, 16, 64); + + write_phy_reg(pi, 0x6da, 0xffff); + mod_phy_reg(pi, 0x503, (0x1 << 3), (1) << 3); + + tx_pwr_ctrl_old = wlc_lcnphy_get_tx_pwr_ctrl(pi); + + mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); + + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + + save_txpwrctrlrfctrl2 = read_phy_reg(pi, 0x4db); + + mod_phy_reg(pi, 0x4db, (0x3ff << 0), (0x2a6) << 0); + + mod_phy_reg(pi, 0x4db, (0x7 << 12), (2) << 12); + + wlc_lcnphy_tx_iqlo_loopback(pi, values_to_save); + + tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); + if (tx_gain_override_old) + wlc_lcnphy_get_tx_gain(pi, &old_gains); + + if (!target_gains) { + if (!tx_gain_override_old) + wlc_lcnphy_set_tx_pwr_by_index(pi, + pi_lcn->lcnphy_tssi_idx); + wlc_lcnphy_get_tx_gain(pi, &temp_gains); + target_gains = &temp_gains; + } + + hash = (target_gains->gm_gain << 8) | + (target_gains->pga_gain << 4) | (target_gains->pad_gain); + + band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0); + + cal_gains = *target_gains; + memset(ncorr_override, 0, sizeof(ncorr_override)); + for (j = 0; j < iqcal_gainparams_numgains_lcnphy[band_idx]; j++) { + if (hash == tbl_iqcal_gainparams_lcnphy[band_idx][j][0]) { + cal_gains.gm_gain = + tbl_iqcal_gainparams_lcnphy[band_idx][j][1]; + cal_gains.pga_gain = + tbl_iqcal_gainparams_lcnphy[band_idx][j][2]; + cal_gains.pad_gain = + tbl_iqcal_gainparams_lcnphy[band_idx][j][3]; + memcpy(ncorr_override, + &tbl_iqcal_gainparams_lcnphy[band_idx][j][3], + sizeof(ncorr_override)); + break; + } + } + + wlc_lcnphy_set_tx_gain(pi, &cal_gains); + + write_phy_reg(pi, 0x453, 0xaa9); + write_phy_reg(pi, 0x93d, 0xc0); + + wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, + lcnphy_iqcal_loft_gainladder, + ARRAY_SIZE(lcnphy_iqcal_loft_gainladder), + 16, 0); + + wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, + lcnphy_iqcal_ir_gainladder, + ARRAY_SIZE( + lcnphy_iqcal_ir_gainladder), 16, + 32); + + if (pi->phy_tx_tone_freq) { + + wlc_lcnphy_stop_tx_tone(pi); + udelay(5); + wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1); + } else { + wlc_lcnphy_start_tx_tone(pi, 3750, 88, 1); + } + + write_phy_reg(pi, 0x6da, 0xffff); + + for (i = n_cal_start; i < n_cal_cmds; i++) { + u16 zero_diq = 0; + u16 best_coeffs[11]; + u16 command_num; + + cal_type = (cal_cmds[i] & 0x0f00) >> 8; + + command_num = command_nums[i]; + if (ncorr_override[cal_type]) + command_num = + ncorr_override[cal_type] << 8 | (command_num & + 0xff); + + write_phy_reg(pi, 0x452, command_num); + + if ((cal_type == 3) || (cal_type == 4)) { + wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, + &diq_start, 1, 16, 69); + + wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, + &zero_diq, 1, 16, 69); + } + + write_phy_reg(pi, 0x451, cal_cmds[i]); + + if (!wlc_lcnphy_iqcal_wait(pi)) + goto cleanup; + + wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, + best_coeffs, + ARRAY_SIZE(best_coeffs), 16, 96); + wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, + best_coeffs, + ARRAY_SIZE(best_coeffs), 16, 64); + + if ((cal_type == 3) || (cal_type == 4)) + wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, + &diq_start, 1, 16, 69); + wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, + pi_lcn->lcnphy_cal_results. + txiqlocal_bestcoeffs, + ARRAY_SIZE(pi_lcn-> + lcnphy_cal_results. + txiqlocal_bestcoeffs), + 16, 96); + } + + wlc_lcnphy_common_read_table(pi, LCNPHY_TBL_ID_IQLOCAL, + pi_lcn->lcnphy_cal_results. + txiqlocal_bestcoeffs, + ARRAY_SIZE(pi_lcn->lcnphy_cal_results. + txiqlocal_bestcoeffs), 16, 96); + pi_lcn->lcnphy_cal_results.txiqlocal_bestcoeffs_valid = true; + + wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, + &pi_lcn->lcnphy_cal_results. + txiqlocal_bestcoeffs[0], 4, 16, 80); + + wlc_lcnphy_common_write_table(pi, LCNPHY_TBL_ID_IQLOCAL, + &pi_lcn->lcnphy_cal_results. + txiqlocal_bestcoeffs[5], 2, 16, 85); + +cleanup: + wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, values_to_save); + kfree(values_to_save); + + if (!keep_tone) + wlc_lcnphy_stop_tx_tone(pi); + + write_phy_reg(pi, 0x4db, save_txpwrctrlrfctrl2); + + write_phy_reg(pi, 0x453, 0); + + if (tx_gain_override_old) + wlc_lcnphy_set_tx_gain(pi, &old_gains); + wlc_lcnphy_set_tx_pwr_ctrl(pi, tx_pwr_ctrl_old); + + write_phy_reg(pi, 0x6da, save_sslpnCalibClkEnCtrl); + write_phy_reg(pi, 0x6db, save_sslpnRxFeClkEnCtrl); + +} + +static void wlc_lcnphy_idle_tssi_est(struct brcms_phy_pub *ppi) +{ + bool suspend, tx_gain_override_old; + struct lcnphy_txgains old_gains; + struct brcms_phy *pi = (struct brcms_phy *) ppi; + u16 idleTssi, idleTssi0_2C, idleTssi0_OB, idleTssi0_regvalue_OB, + idleTssi0_regvalue_2C; + u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + u16 SAVE_lpfgain = read_radio_reg(pi, RADIO_2064_REG112); + u16 SAVE_jtag_bb_afe_switch = + read_radio_reg(pi, RADIO_2064_REG007) & 1; + u16 SAVE_jtag_auxpga = read_radio_reg(pi, RADIO_2064_REG0FF) & 0x10; + u16 SAVE_iqadc_aux_en = read_radio_reg(pi, RADIO_2064_REG11F) & 4; + idleTssi = read_phy_reg(pi, 0x4ab); + suspend = + (0 == + (R_REG(&((struct brcms_phy *) pi)->regs->maccontrol) & + MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + + tx_gain_override_old = wlc_lcnphy_tx_gain_override_enabled(pi); + wlc_lcnphy_get_tx_gain(pi, &old_gains); + + wlc_lcnphy_enable_tx_gain_override(pi); + wlc_lcnphy_set_tx_pwr_by_index(pi, 127); + write_radio_reg(pi, RADIO_2064_REG112, 0x6); + mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 1); + mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 1 << 4); + mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 1 << 2); + wlc_lcnphy_tssi_setup(pi); + wlc_phy_do_dummy_tx(pi, true, OFF); + idleTssi = ((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) + >> 0); + + idleTssi0_2C = ((read_phy_reg(pi, 0x63e) & (0x1ff << 0)) + >> 0); + + if (idleTssi0_2C >= 256) + idleTssi0_OB = idleTssi0_2C - 256; + else + idleTssi0_OB = idleTssi0_2C + 256; + + idleTssi0_regvalue_OB = idleTssi0_OB; + if (idleTssi0_regvalue_OB >= 256) + idleTssi0_regvalue_2C = idleTssi0_regvalue_OB - 256; + else + idleTssi0_regvalue_2C = idleTssi0_regvalue_OB + 256; + mod_phy_reg(pi, 0x4a6, (0x1ff << 0), (idleTssi0_regvalue_2C) << 0); + + mod_phy_reg(pi, 0x44c, (0x1 << 12), (0) << 12); + + wlc_lcnphy_set_tx_gain_override(pi, tx_gain_override_old); + wlc_lcnphy_set_tx_gain(pi, &old_gains); + wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); + + write_radio_reg(pi, RADIO_2064_REG112, SAVE_lpfgain); + mod_radio_reg(pi, RADIO_2064_REG007, 0x1, SAVE_jtag_bb_afe_switch); + mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, SAVE_jtag_auxpga); + mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, SAVE_iqadc_aux_en); + mod_radio_reg(pi, RADIO_2064_REG112, 0x80, 1 << 7); + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); +} + +static void wlc_lcnphy_vbat_temp_sense_setup(struct brcms_phy *pi, u8 mode) +{ + bool suspend; + u16 save_txpwrCtrlEn; + u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain; + u16 auxpga_vmid; + struct phytbl_info tab; + u32 val; + u8 save_reg007, save_reg0FF, save_reg11F, save_reg005, save_reg025, + save_reg112; + u16 values_to_save[14]; + s8 index; + int i; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + udelay(999); + + save_reg007 = (u8) read_radio_reg(pi, RADIO_2064_REG007); + save_reg0FF = (u8) read_radio_reg(pi, RADIO_2064_REG0FF); + save_reg11F = (u8) read_radio_reg(pi, RADIO_2064_REG11F); + save_reg005 = (u8) read_radio_reg(pi, RADIO_2064_REG005); + save_reg025 = (u8) read_radio_reg(pi, RADIO_2064_REG025); + save_reg112 = (u8) read_radio_reg(pi, RADIO_2064_REG112); + + for (i = 0; i < 14; i++) + values_to_save[i] = read_phy_reg(pi, tempsense_phy_regs[i]); + suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + save_txpwrCtrlEn = read_radio_reg(pi, 0x4a4); + + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + index = pi_lcn->lcnphy_current_index; + wlc_lcnphy_set_tx_pwr_by_index(pi, 127); + mod_radio_reg(pi, RADIO_2064_REG007, 0x1, 0x1); + mod_radio_reg(pi, RADIO_2064_REG0FF, 0x10, 0x1 << 4); + mod_radio_reg(pi, RADIO_2064_REG11F, 0x4, 0x1 << 2); + mod_phy_reg(pi, 0x503, (0x1 << 0), (0) << 0); + + mod_phy_reg(pi, 0x503, (0x1 << 2), (0) << 2); + + mod_phy_reg(pi, 0x4a4, (0x1 << 14), (0) << 14); + + mod_phy_reg(pi, 0x4a4, (0x1 << 15), (0) << 15); + + mod_phy_reg(pi, 0x4d0, (0x1 << 5), (0) << 5); + + mod_phy_reg(pi, 0x4a5, (0xff << 0), (255) << 0); + + mod_phy_reg(pi, 0x4a5, (0x7 << 12), (5) << 12); + + mod_phy_reg(pi, 0x4a5, (0x7 << 8), (0) << 8); + + mod_phy_reg(pi, 0x40d, (0xff << 0), (64) << 0); + + mod_phy_reg(pi, 0x40d, (0x7 << 8), (6) << 8); + + mod_phy_reg(pi, 0x4a2, (0xff << 0), (64) << 0); + + mod_phy_reg(pi, 0x4a2, (0x7 << 8), (6) << 8); + + mod_phy_reg(pi, 0x4d9, (0x7 << 4), (2) << 4); + + mod_phy_reg(pi, 0x4d9, (0x7 << 8), (3) << 8); + + mod_phy_reg(pi, 0x4d9, (0x7 << 12), (1) << 12); + + mod_phy_reg(pi, 0x4da, (0x1 << 12), (0) << 12); + + mod_phy_reg(pi, 0x4da, (0x1 << 13), (1) << 13); + + mod_phy_reg(pi, 0x4a6, (0x1 << 15), (1) << 15); + + write_radio_reg(pi, RADIO_2064_REG025, 0xC); + + mod_radio_reg(pi, RADIO_2064_REG005, 0x8, 0x1 << 3); + + mod_phy_reg(pi, 0x938, (0x1 << 2), (1) << 2); + + mod_phy_reg(pi, 0x939, (0x1 << 2), (1) << 2); + + mod_phy_reg(pi, 0x4a4, (0x1 << 12), (1) << 12); + + val = wlc_lcnphy_rfseq_tbl_adc_pwrup(pi); + tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; + tab.tbl_width = 16; + tab.tbl_len = 1; + tab.tbl_ptr = &val; + tab.tbl_offset = 6; + wlc_lcnphy_write_table(pi, &tab); + if (mode == TEMPSENSE) { + mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3); + + mod_phy_reg(pi, 0x4d7, (0x7 << 12), (1) << 12); + + auxpga_vmidcourse = 8; + auxpga_vmidfine = 0x4; + auxpga_gain = 2; + mod_radio_reg(pi, RADIO_2064_REG082, 0x20, 1 << 5); + } else { + mod_phy_reg(pi, 0x4d7, (0x1 << 3), (1) << 3); + + mod_phy_reg(pi, 0x4d7, (0x7 << 12), (3) << 12); + + auxpga_vmidcourse = 7; + auxpga_vmidfine = 0xa; + auxpga_gain = 2; + } + auxpga_vmid = + (u16) ((2 << 8) | (auxpga_vmidcourse << 4) | auxpga_vmidfine); + mod_phy_reg(pi, 0x4d8, (0x1 << 0), (1) << 0); + + mod_phy_reg(pi, 0x4d8, (0x3ff << 2), (auxpga_vmid) << 2); + + mod_phy_reg(pi, 0x4d8, (0x1 << 1), (1) << 1); + + mod_phy_reg(pi, 0x4d8, (0x7 << 12), (auxpga_gain) << 12); + + mod_phy_reg(pi, 0x4d0, (0x1 << 5), (1) << 5); + + write_radio_reg(pi, RADIO_2064_REG112, 0x6); + + wlc_phy_do_dummy_tx(pi, true, OFF); + if (!tempsense_done(pi)) + udelay(10); + + write_radio_reg(pi, RADIO_2064_REG007, (u16) save_reg007); + write_radio_reg(pi, RADIO_2064_REG0FF, (u16) save_reg0FF); + write_radio_reg(pi, RADIO_2064_REG11F, (u16) save_reg11F); + write_radio_reg(pi, RADIO_2064_REG005, (u16) save_reg005); + write_radio_reg(pi, RADIO_2064_REG025, (u16) save_reg025); + write_radio_reg(pi, RADIO_2064_REG112, (u16) save_reg112); + for (i = 0; i < 14; i++) + write_phy_reg(pi, tempsense_phy_regs[i], values_to_save[i]); + wlc_lcnphy_set_tx_pwr_by_index(pi, (int)index); + + write_radio_reg(pi, 0x4a4, save_txpwrCtrlEn); + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); + udelay(999); +} + +static void wlc_lcnphy_tx_pwr_ctrl_init(struct brcms_phy_pub *ppi) +{ + struct lcnphy_txgains tx_gains; + u8 bbmult; + struct phytbl_info tab; + s32 a1, b0, b1; + s32 tssi, pwr, maxtargetpwr, mintargetpwr; + bool suspend; + struct brcms_phy *pi = (struct brcms_phy *) ppi; + + suspend = + (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + if (!pi->hwpwrctrl_capable) { + if (CHSPEC_IS2G(pi->radio_chanspec)) { + tx_gains.gm_gain = 4; + tx_gains.pga_gain = 12; + tx_gains.pad_gain = 12; + tx_gains.dac_gain = 0; + + bbmult = 150; + } else { + tx_gains.gm_gain = 7; + tx_gains.pga_gain = 15; + tx_gains.pad_gain = 14; + tx_gains.dac_gain = 0; + + bbmult = 150; + } + wlc_lcnphy_set_tx_gain(pi, &tx_gains); + wlc_lcnphy_set_bbmult(pi, bbmult); + wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); + } else { + + wlc_lcnphy_idle_tssi_est(ppi); + + wlc_lcnphy_clear_tx_power_offsets(pi); + + b0 = pi->txpa_2g[0]; + b1 = pi->txpa_2g[1]; + a1 = pi->txpa_2g[2]; + maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1); + mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1); + + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_ptr = &pwr; + tab.tbl_len = 1; + tab.tbl_offset = 0; + for (tssi = 0; tssi < 128; tssi++) { + pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1); + + pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr; + wlc_lcnphy_write_table(pi, &tab); + tab.tbl_offset++; + } + + mod_phy_reg(pi, 0x410, (0x1 << 7), (0) << 7); + + write_phy_reg(pi, 0x4a8, 10); + + wlc_lcnphy_set_target_tx_pwr(pi, LCN_TARGET_PWR); + + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW); + } + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); +} + +static u8 wlc_lcnphy_get_bbmult(struct brcms_phy *pi) +{ + u16 m0m1; + struct phytbl_info tab; + + tab.tbl_ptr = &m0m1; + tab.tbl_len = 1; + tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; + tab.tbl_offset = 87; + tab.tbl_width = 16; + wlc_lcnphy_read_table(pi, &tab); + + return (u8) ((m0m1 & 0xff00) >> 8); +} + +static void wlc_lcnphy_set_pa_gain(struct brcms_phy *pi, u16 gain) +{ + mod_phy_reg(pi, 0x4fb, + LCNPHY_txgainctrlovrval1_pagain_ovr_val1_MASK, + gain << LCNPHY_txgainctrlovrval1_pagain_ovr_val1_SHIFT); + mod_phy_reg(pi, 0x4fd, + LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_MASK, + gain << LCNPHY_stxtxgainctrlovrval1_pagain_ovr_val1_SHIFT); +} + +void +wlc_lcnphy_get_radio_loft(struct brcms_phy *pi, + u8 *ei0, u8 *eq0, u8 *fi0, u8 *fq0) +{ + *ei0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG089)); + *eq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08A)); + *fi0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08B)); + *fq0 = LCNPHY_IQLOCC_READ(read_radio_reg(pi, RADIO_2064_REG08C)); +} + +void wlc_lcnphy_set_tx_iqcc(struct brcms_phy *pi, u16 a, u16 b) +{ + struct phytbl_info tab; + u16 iqcc[2]; + + iqcc[0] = a; + iqcc[1] = b; + + tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; + tab.tbl_width = 16; + tab.tbl_ptr = iqcc; + tab.tbl_len = 2; + tab.tbl_offset = 80; + wlc_lcnphy_write_table(pi, &tab); +} + +void wlc_lcnphy_set_tx_locc(struct brcms_phy *pi, u16 didq) +{ + struct phytbl_info tab; + + tab.tbl_id = LCNPHY_TBL_ID_IQLOCAL; + tab.tbl_width = 16; + tab.tbl_ptr = &didq; + tab.tbl_len = 1; + tab.tbl_offset = 85; + wlc_lcnphy_write_table(pi, &tab); +} + +void wlc_lcnphy_set_tx_pwr_by_index(struct brcms_phy *pi, int index) +{ + struct phytbl_info tab; + u16 a, b; + u8 bb_mult; + u32 bbmultiqcomp, txgain, locoeffs, rfpower; + struct lcnphy_txgains gains; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + pi_lcn->lcnphy_tx_power_idx_override = (s8) index; + pi_lcn->lcnphy_current_index = (u8) index; + + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_len = 1; + + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index; + tab.tbl_ptr = &bbmultiqcomp; + wlc_lcnphy_read_table(pi, &tab); + + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index; + tab.tbl_width = 32; + tab.tbl_ptr = &txgain; + wlc_lcnphy_read_table(pi, &tab); + + gains.gm_gain = (u16) (txgain & 0xff); + gains.pga_gain = (u16) (txgain >> 8) & 0xff; + gains.pad_gain = (u16) (txgain >> 16) & 0xff; + gains.dac_gain = (u16) (bbmultiqcomp >> 28) & 0x07; + wlc_lcnphy_set_tx_gain(pi, &gains); + wlc_lcnphy_set_pa_gain(pi, (u16) (txgain >> 24) & 0x7f); + + bb_mult = (u8) ((bbmultiqcomp >> 20) & 0xff); + wlc_lcnphy_set_bbmult(pi, bb_mult); + + wlc_lcnphy_enable_tx_gain_override(pi); + + if (!wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { + + a = (u16) ((bbmultiqcomp >> 10) & 0x3ff); + b = (u16) (bbmultiqcomp & 0x3ff); + wlc_lcnphy_set_tx_iqcc(pi, a, b); + + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + index; + tab.tbl_ptr = &locoeffs; + wlc_lcnphy_read_table(pi, &tab); + + wlc_lcnphy_set_tx_locc(pi, (u16) locoeffs); + + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index; + tab.tbl_ptr = &rfpower; + wlc_lcnphy_read_table(pi, &tab); + mod_phy_reg(pi, 0x6a6, (0x1fff << 0), (rfpower * 8) << 0); + + } +} + +static void wlc_lcnphy_clear_papd_comptable(struct brcms_phy *pi) +{ + u32 j; + struct phytbl_info tab; + u32 temp_offset[128]; + tab.tbl_ptr = temp_offset; + tab.tbl_len = 128; + tab.tbl_id = LCNPHY_TBL_ID_PAPDCOMPDELTATBL; + tab.tbl_width = 32; + tab.tbl_offset = 0; + + memset(temp_offset, 0, sizeof(temp_offset)); + for (j = 1; j < 128; j += 2) + temp_offset[j] = 0x80000; + + wlc_lcnphy_write_table(pi, &tab); + return; +} + +void wlc_lcnphy_tx_pu(struct brcms_phy *pi, bool bEnable) +{ + if (!bEnable) { + + and_phy_reg(pi, 0x43b, ~(u16) ((0x1 << 1) | (0x1 << 4))); + + mod_phy_reg(pi, 0x43c, (0x1 << 1), 1 << 1); + + and_phy_reg(pi, 0x44c, + ~(u16) ((0x1 << 3) | + (0x1 << 5) | + (0x1 << 12) | + (0x1 << 0) | (0x1 << 1) | (0x1 << 2))); + + and_phy_reg(pi, 0x44d, + ~(u16) ((0x1 << 3) | (0x1 << 5) | (0x1 << 14))); + mod_phy_reg(pi, 0x44d, (0x1 << 2), 1 << 2); + + mod_phy_reg(pi, 0x44d, (0x1 << 1) | (0x1 << 0), (0x1 << 0)); + + and_phy_reg(pi, 0x4f9, + ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); + + and_phy_reg(pi, 0x4fa, + ~(u16) ((0x1 << 0) | (0x1 << 1) | (0x1 << 2))); + } else { + + mod_phy_reg(pi, 0x43b, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x43c, (0x1 << 1), 0 << 1); + + mod_phy_reg(pi, 0x43b, (0x1 << 4), 1 << 4); + mod_phy_reg(pi, 0x43c, (0x1 << 6), 0 << 6); + + mod_phy_reg(pi, 0x44c, (0x1 << 12), 1 << 12); + mod_phy_reg(pi, 0x44d, (0x1 << 14), 1 << 14); + + wlc_lcnphy_set_trsw_override(pi, true, false); + + mod_phy_reg(pi, 0x44d, (0x1 << 2), 0 << 2); + mod_phy_reg(pi, 0x44c, (0x1 << 2), 1 << 2); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + + mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x44d, (0x1 << 3), 1 << 3); + + mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5); + mod_phy_reg(pi, 0x44d, (0x1 << 5), 0 << 5); + + mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x4fa, (0x1 << 1), 1 << 1); + + mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x4fa, (0x1 << 2), 1 << 2); + + mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x4fa, (0x1 << 0), 1 << 0); + } else { + + mod_phy_reg(pi, 0x44c, (0x1 << 3), 1 << 3); + mod_phy_reg(pi, 0x44d, (0x1 << 3), 0 << 3); + + mod_phy_reg(pi, 0x44c, (0x1 << 5), 1 << 5); + mod_phy_reg(pi, 0x44d, (0x1 << 5), 1 << 5); + + mod_phy_reg(pi, 0x4f9, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0x4fa, (0x1 << 1), 0 << 1); + + mod_phy_reg(pi, 0x4f9, (0x1 << 2), 1 << 2); + mod_phy_reg(pi, 0x4fa, (0x1 << 2), 0 << 2); + + mod_phy_reg(pi, 0x4f9, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x4fa, (0x1 << 0), 0 << 0); + } + } +} + +static void +wlc_lcnphy_run_samples(struct brcms_phy *pi, + u16 num_samps, + u16 num_loops, u16 wait, bool iqcalmode) +{ + + or_phy_reg(pi, 0x6da, 0x8080); + + mod_phy_reg(pi, 0x642, (0x7f << 0), (num_samps - 1) << 0); + if (num_loops != 0xffff) + num_loops--; + mod_phy_reg(pi, 0x640, (0xffff << 0), num_loops << 0); + + mod_phy_reg(pi, 0x641, (0xffff << 0), wait << 0); + + if (iqcalmode) { + + and_phy_reg(pi, 0x453, (u16) ~(0x1 << 15)); + or_phy_reg(pi, 0x453, (0x1 << 15)); + } else { + write_phy_reg(pi, 0x63f, 1); + wlc_lcnphy_tx_pu(pi, 1); + } + + or_radio_reg(pi, RADIO_2064_REG112, 0x6); +} + +void wlc_lcnphy_deaf_mode(struct brcms_phy *pi, bool mode) +{ + + u8 phybw40; + phybw40 = CHSPEC_IS40(pi->radio_chanspec); + + if (LCNREV_LT(pi->pubpi.phy_rev, 2)) { + mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5); + mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9); + } else { + mod_phy_reg(pi, 0x4b0, (0x1 << 5), (mode) << 5); + mod_phy_reg(pi, 0x4b1, (0x1 << 9), 0 << 9); + } + + if (phybw40 == 0) { + mod_phy_reg((pi), 0x410, + (0x1 << 6) | + (0x1 << 5), + ((CHSPEC_IS2G( + pi->radio_chanspec)) ? (!mode) : 0) << + 6 | (!mode) << 5); + mod_phy_reg(pi, 0x410, (0x1 << 7), (mode) << 7); + } +} + +void +wlc_lcnphy_start_tx_tone(struct brcms_phy *pi, s32 f_kHz, u16 max_val, + bool iqcalmode) +{ + u8 phy_bw; + u16 num_samps, t, k; + u32 bw; + s32 theta = 0, rot = 0; + struct cordic_iq tone_samp; + u32 data_buf[64]; + u16 i_samp, q_samp; + struct phytbl_info tab; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + pi->phy_tx_tone_freq = f_kHz; + + wlc_lcnphy_deaf_mode(pi, true); + + phy_bw = 40; + if (pi_lcn->lcnphy_spurmod) { + write_phy_reg(pi, 0x942, 0x2); + write_phy_reg(pi, 0x93b, 0x0); + write_phy_reg(pi, 0x93c, 0x0); + wlc_lcnphy_txrx_spur_avoidance_mode(pi, false); + } + + if (f_kHz) { + k = 1; + do { + bw = phy_bw * 1000 * k; + num_samps = bw / abs(f_kHz); + k++; + } while ((num_samps * (u32) (abs(f_kHz))) != bw); + } else + num_samps = 2; + + rot = ((f_kHz * 36) / phy_bw) / 100; + theta = 0; + + for (t = 0; t < num_samps; t++) { + + tone_samp = cordic_calc_iq(theta); + + theta += rot; + + i_samp = (u16) (FLOAT(tone_samp.i * max_val) & 0x3ff); + q_samp = (u16) (FLOAT(tone_samp.q * max_val) & 0x3ff); + data_buf[t] = (i_samp << 10) | q_samp; + } + + mod_phy_reg(pi, 0x6d6, (0x3 << 0), 0 << 0); + + mod_phy_reg(pi, 0x6da, (0x1 << 3), 1 << 3); + + tab.tbl_ptr = data_buf; + tab.tbl_len = num_samps; + tab.tbl_id = LCNPHY_TBL_ID_SAMPLEPLAY; + tab.tbl_offset = 0; + tab.tbl_width = 32; + wlc_lcnphy_write_table(pi, &tab); + + wlc_lcnphy_run_samples(pi, num_samps, 0xffff, 0, iqcalmode); +} + +void wlc_lcnphy_stop_tx_tone(struct brcms_phy *pi) +{ + s16 playback_status; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + pi->phy_tx_tone_freq = 0; + if (pi_lcn->lcnphy_spurmod) { + write_phy_reg(pi, 0x942, 0x7); + write_phy_reg(pi, 0x93b, 0x2017); + write_phy_reg(pi, 0x93c, 0x27c5); + wlc_lcnphy_txrx_spur_avoidance_mode(pi, true); + } + + playback_status = read_phy_reg(pi, 0x644); + if (playback_status & (0x1 << 0)) { + wlc_lcnphy_tx_pu(pi, 0); + mod_phy_reg(pi, 0x63f, (0x1 << 1), 1 << 1); + } else if (playback_status & (0x1 << 1)) + mod_phy_reg(pi, 0x453, (0x1 << 15), 0 << 15); + + mod_phy_reg(pi, 0x6d6, (0x3 << 0), 1 << 0); + + mod_phy_reg(pi, 0x6da, (0x1 << 3), 0 << 3); + + mod_phy_reg(pi, 0x6da, (0x1 << 7), 0 << 7); + + and_radio_reg(pi, RADIO_2064_REG112, 0xFFF9); + + wlc_lcnphy_deaf_mode(pi, false); +} + +static void +wlc_lcnphy_set_cc(struct brcms_phy *pi, int cal_type, s16 coeff_x, s16 coeff_y) +{ + u16 di0dq0; + u16 x, y, data_rf; + int k; + switch (cal_type) { + case 0: + wlc_lcnphy_set_tx_iqcc(pi, coeff_x, coeff_y); + break; + case 2: + di0dq0 = (coeff_x & 0xff) << 8 | (coeff_y & 0xff); + wlc_lcnphy_set_tx_locc(pi, di0dq0); + break; + case 3: + k = wlc_lcnphy_calc_floor(coeff_x, 0); + y = 8 + k; + k = wlc_lcnphy_calc_floor(coeff_x, 1); + x = 8 - k; + data_rf = (x * 16 + y); + write_radio_reg(pi, RADIO_2064_REG089, data_rf); + k = wlc_lcnphy_calc_floor(coeff_y, 0); + y = 8 + k; + k = wlc_lcnphy_calc_floor(coeff_y, 1); + x = 8 - k; + data_rf = (x * 16 + y); + write_radio_reg(pi, RADIO_2064_REG08A, data_rf); + break; + case 4: + k = wlc_lcnphy_calc_floor(coeff_x, 0); + y = 8 + k; + k = wlc_lcnphy_calc_floor(coeff_x, 1); + x = 8 - k; + data_rf = (x * 16 + y); + write_radio_reg(pi, RADIO_2064_REG08B, data_rf); + k = wlc_lcnphy_calc_floor(coeff_y, 0); + y = 8 + k; + k = wlc_lcnphy_calc_floor(coeff_y, 1); + x = 8 - k; + data_rf = (x * 16 + y); + write_radio_reg(pi, RADIO_2064_REG08C, data_rf); + break; + } +} + +static struct lcnphy_unsign16_struct +wlc_lcnphy_get_cc(struct brcms_phy *pi, int cal_type) +{ + u16 a, b, didq; + u8 di0, dq0, ei, eq, fi, fq; + struct lcnphy_unsign16_struct cc; + cc.re = 0; + cc.im = 0; + switch (cal_type) { + case 0: + wlc_lcnphy_get_tx_iqcc(pi, &a, &b); + cc.re = a; + cc.im = b; + break; + case 2: + didq = wlc_lcnphy_get_tx_locc(pi); + di0 = (((didq & 0xff00) << 16) >> 24); + dq0 = (((didq & 0x00ff) << 24) >> 24); + cc.re = (u16) di0; + cc.im = (u16) dq0; + break; + case 3: + wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq); + cc.re = (u16) ei; + cc.im = (u16) eq; + break; + case 4: + wlc_lcnphy_get_radio_loft(pi, &ei, &eq, &fi, &fq); + cc.re = (u16) fi; + cc.im = (u16) fq; + break; + } + return cc; +} + +static void +wlc_lcnphy_samp_cap(struct brcms_phy *pi, int clip_detect_algo, u16 thresh, + s16 *ptr, int mode) +{ + u32 curval1, curval2, stpptr, curptr, strptr, val; + u16 sslpnCalibClkEnCtrl, timer; + u16 old_sslpnCalibClkEnCtrl; + s16 imag, real; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + timer = 0; + old_sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); + + curval1 = R_REG(&pi->regs->psm_corectlsts); + ptr[130] = 0; + W_REG(&pi->regs->psm_corectlsts, ((1 << 6) | curval1)); + + W_REG(&pi->regs->smpl_clct_strptr, 0x7E00); + W_REG(&pi->regs->smpl_clct_stpptr, 0x8000); + udelay(20); + curval2 = R_REG(&pi->regs->psm_phy_hdr_param); + W_REG(&pi->regs->psm_phy_hdr_param, curval2 | 0x30); + + write_phy_reg(pi, 0x555, 0x0); + write_phy_reg(pi, 0x5a6, 0x5); + + write_phy_reg(pi, 0x5a2, (u16) (mode | mode << 6)); + write_phy_reg(pi, 0x5cf, 3); + write_phy_reg(pi, 0x5a5, 0x3); + write_phy_reg(pi, 0x583, 0x0); + write_phy_reg(pi, 0x584, 0x0); + write_phy_reg(pi, 0x585, 0x0fff); + write_phy_reg(pi, 0x586, 0x0000); + + write_phy_reg(pi, 0x580, 0x4501); + + sslpnCalibClkEnCtrl = read_phy_reg(pi, 0x6da); + write_phy_reg(pi, 0x6da, (u32) (sslpnCalibClkEnCtrl | 0x2008)); + stpptr = R_REG(&pi->regs->smpl_clct_stpptr); + curptr = R_REG(&pi->regs->smpl_clct_curptr); + do { + udelay(10); + curptr = R_REG(&pi->regs->smpl_clct_curptr); + timer++; + } while ((curptr != stpptr) && (timer < 500)); + + W_REG(&pi->regs->psm_phy_hdr_param, 0x2); + strptr = 0x7E00; + W_REG(&pi->regs->tplatewrptr, strptr); + while (strptr < 0x8000) { + val = R_REG(&pi->regs->tplatewrdata); + imag = ((val >> 16) & 0x3ff); + real = ((val) & 0x3ff); + if (imag > 511) + imag -= 1024; + + if (real > 511) + real -= 1024; + + if (pi_lcn->lcnphy_iqcal_swp_dis) + ptr[(strptr - 0x7E00) / 4] = real; + else + ptr[(strptr - 0x7E00) / 4] = imag; + + if (clip_detect_algo) { + if (imag > thresh || imag < -thresh) { + strptr = 0x8000; + ptr[130] = 1; + } + } + + strptr += 4; + } + + write_phy_reg(pi, 0x6da, old_sslpnCalibClkEnCtrl); + W_REG(&pi->regs->psm_phy_hdr_param, curval2); + W_REG(&pi->regs->psm_corectlsts, curval1); +} + +static void +wlc_lcnphy_a1(struct brcms_phy *pi, int cal_type, int num_levels, + int step_size_lg2) +{ + const struct lcnphy_spb_tone *phy_c1; + struct lcnphy_spb_tone phy_c2; + struct lcnphy_unsign16_struct phy_c3; + int phy_c4, phy_c5, k, l, j, phy_c6; + u16 phy_c7, phy_c8, phy_c9; + s16 phy_c10, phy_c11, phy_c12, phy_c13, phy_c14, phy_c15, phy_c16; + s16 *ptr, phy_c17; + s32 phy_c18, phy_c19; + u32 phy_c20, phy_c21; + bool phy_c22, phy_c23, phy_c24, phy_c25; + u16 phy_c26, phy_c27; + u16 phy_c28, phy_c29, phy_c30; + u16 phy_c31; + u16 *phy_c32; + phy_c21 = 0; + phy_c10 = phy_c13 = phy_c14 = phy_c8 = 0; + ptr = kmalloc(sizeof(s16) * 131, GFP_ATOMIC); + if (NULL == ptr) + return; + + phy_c32 = kmalloc(sizeof(u16) * 20, GFP_ATOMIC); + if (NULL == phy_c32) { + kfree(ptr); + return; + } + phy_c26 = read_phy_reg(pi, 0x6da); + phy_c27 = read_phy_reg(pi, 0x6db); + phy_c31 = read_radio_reg(pi, RADIO_2064_REG026); + write_phy_reg(pi, 0x93d, 0xC0); + + wlc_lcnphy_start_tx_tone(pi, 3750, 88, 0); + write_phy_reg(pi, 0x6da, 0xffff); + or_phy_reg(pi, 0x6db, 0x3); + + wlc_lcnphy_tx_iqlo_loopback(pi, phy_c32); + udelay(500); + phy_c28 = read_phy_reg(pi, 0x938); + phy_c29 = read_phy_reg(pi, 0x4d7); + phy_c30 = read_phy_reg(pi, 0x4d8); + or_phy_reg(pi, 0x938, 0x1 << 2); + or_phy_reg(pi, 0x4d7, 0x1 << 2); + or_phy_reg(pi, 0x4d7, 0x1 << 3); + mod_phy_reg(pi, 0x4d7, (0x7 << 12), 0x2 << 12); + or_phy_reg(pi, 0x4d8, 1 << 0); + or_phy_reg(pi, 0x4d8, 1 << 1); + mod_phy_reg(pi, 0x4d8, (0x3ff << 2), 0x23A << 2); + mod_phy_reg(pi, 0x4d8, (0x7 << 12), 0x7 << 12); + phy_c1 = &lcnphy_spb_tone_3750[0]; + phy_c4 = 32; + + if (num_levels == 0) { + if (cal_type != 0) + num_levels = 4; + else + num_levels = 9; + } + if (step_size_lg2 == 0) { + if (cal_type != 0) + step_size_lg2 = 3; + else + step_size_lg2 = 8; + } + + phy_c7 = (1 << step_size_lg2); + phy_c3 = wlc_lcnphy_get_cc(pi, cal_type); + phy_c15 = (s16) phy_c3.re; + phy_c16 = (s16) phy_c3.im; + if (cal_type == 2) { + if (phy_c3.re > 127) + phy_c15 = phy_c3.re - 256; + if (phy_c3.im > 127) + phy_c16 = phy_c3.im - 256; + } + wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16); + udelay(20); + for (phy_c8 = 0; phy_c7 != 0 && phy_c8 < num_levels; phy_c8++) { + phy_c23 = 1; + phy_c22 = 0; + switch (cal_type) { + case 0: + phy_c10 = 511; + break; + case 2: + phy_c10 = 127; + break; + case 3: + phy_c10 = 15; + break; + case 4: + phy_c10 = 15; + break; + } + + phy_c9 = read_phy_reg(pi, 0x93d); + phy_c9 = 2 * phy_c9; + phy_c24 = 0; + phy_c5 = 7; + phy_c25 = 1; + while (1) { + write_radio_reg(pi, RADIO_2064_REG026, + (phy_c5 & 0x7) | ((phy_c5 & 0x7) << 4)); + udelay(50); + phy_c22 = 0; + ptr[130] = 0; + wlc_lcnphy_samp_cap(pi, 1, phy_c9, &ptr[0], 2); + if (ptr[130] == 1) + phy_c22 = 1; + if (phy_c22) + phy_c5 -= 1; + if ((phy_c22 != phy_c24) && (!phy_c25)) + break; + if (!phy_c22) + phy_c5 += 1; + if (phy_c5 <= 0 || phy_c5 >= 7) + break; + phy_c24 = phy_c22; + phy_c25 = 0; + } + + if (phy_c5 < 0) + phy_c5 = 0; + else if (phy_c5 > 7) + phy_c5 = 7; + + for (k = -phy_c7; k <= phy_c7; k += phy_c7) { + for (l = -phy_c7; l <= phy_c7; l += phy_c7) { + phy_c11 = phy_c15 + k; + phy_c12 = phy_c16 + l; + + if (phy_c11 < -phy_c10) + phy_c11 = -phy_c10; + else if (phy_c11 > phy_c10) + phy_c11 = phy_c10; + if (phy_c12 < -phy_c10) + phy_c12 = -phy_c10; + else if (phy_c12 > phy_c10) + phy_c12 = phy_c10; + wlc_lcnphy_set_cc(pi, cal_type, phy_c11, + phy_c12); + udelay(20); + wlc_lcnphy_samp_cap(pi, 0, 0, ptr, 2); + + phy_c18 = 0; + phy_c19 = 0; + for (j = 0; j < 128; j++) { + if (cal_type != 0) + phy_c6 = j % phy_c4; + else + phy_c6 = (2 * j) % phy_c4; + + phy_c2.re = phy_c1[phy_c6].re; + phy_c2.im = phy_c1[phy_c6].im; + phy_c17 = ptr[j]; + phy_c18 = phy_c18 + phy_c17 * phy_c2.re; + phy_c19 = phy_c19 + phy_c17 * phy_c2.im; + } + + phy_c18 = phy_c18 >> 10; + phy_c19 = phy_c19 >> 10; + phy_c20 = ((phy_c18 * phy_c18) + + (phy_c19 * phy_c19)); + + if (phy_c23 || phy_c20 < phy_c21) { + phy_c21 = phy_c20; + phy_c13 = phy_c11; + phy_c14 = phy_c12; + } + phy_c23 = 0; + } + } + phy_c23 = 1; + phy_c15 = phy_c13; + phy_c16 = phy_c14; + phy_c7 = phy_c7 >> 1; + wlc_lcnphy_set_cc(pi, cal_type, phy_c15, phy_c16); + udelay(20); + } + goto cleanup; +cleanup: + wlc_lcnphy_tx_iqlo_loopback_cleanup(pi, phy_c32); + wlc_lcnphy_stop_tx_tone(pi); + write_phy_reg(pi, 0x6da, phy_c26); + write_phy_reg(pi, 0x6db, phy_c27); + write_phy_reg(pi, 0x938, phy_c28); + write_phy_reg(pi, 0x4d7, phy_c29); + write_phy_reg(pi, 0x4d8, phy_c30); + write_radio_reg(pi, RADIO_2064_REG026, phy_c31); + + kfree(phy_c32); + kfree(ptr); +} + +void wlc_lcnphy_get_tx_iqcc(struct brcms_phy *pi, u16 *a, u16 *b) +{ + u16 iqcc[2]; + struct phytbl_info tab; + + tab.tbl_ptr = iqcc; + tab.tbl_len = 2; + tab.tbl_id = 0; + tab.tbl_offset = 80; + tab.tbl_width = 16; + wlc_lcnphy_read_table(pi, &tab); + + *a = iqcc[0]; + *b = iqcc[1]; +} + +static void wlc_lcnphy_tx_iqlo_soft_cal_full(struct brcms_phy *pi) +{ + struct lcnphy_unsign16_struct iqcc0, locc2, locc3, locc4; + + wlc_lcnphy_set_cc(pi, 0, 0, 0); + wlc_lcnphy_set_cc(pi, 2, 0, 0); + wlc_lcnphy_set_cc(pi, 3, 0, 0); + wlc_lcnphy_set_cc(pi, 4, 0, 0); + + wlc_lcnphy_a1(pi, 4, 0, 0); + wlc_lcnphy_a1(pi, 3, 0, 0); + wlc_lcnphy_a1(pi, 2, 3, 2); + wlc_lcnphy_a1(pi, 0, 5, 8); + wlc_lcnphy_a1(pi, 2, 2, 1); + wlc_lcnphy_a1(pi, 0, 4, 3); + + iqcc0 = wlc_lcnphy_get_cc(pi, 0); + locc2 = wlc_lcnphy_get_cc(pi, 2); + locc3 = wlc_lcnphy_get_cc(pi, 3); + locc4 = wlc_lcnphy_get_cc(pi, 4); +} + +u16 wlc_lcnphy_get_tx_locc(struct brcms_phy *pi) +{ + struct phytbl_info tab; + u16 didq; + + tab.tbl_id = 0; + tab.tbl_width = 16; + tab.tbl_ptr = &didq; + tab.tbl_len = 1; + tab.tbl_offset = 85; + wlc_lcnphy_read_table(pi, &tab); + + return didq; +} + +static void wlc_lcnphy_txpwrtbl_iqlo_cal(struct brcms_phy *pi) +{ + + struct lcnphy_txgains target_gains, old_gains; + u8 save_bb_mult; + u16 a, b, didq, save_pa_gain = 0; + uint idx, SAVE_txpwrindex = 0xFF; + u32 val; + u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + struct phytbl_info tab; + u8 ei0, eq0, fi0, fq0; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + wlc_lcnphy_get_tx_gain(pi, &old_gains); + save_pa_gain = wlc_lcnphy_get_pa_gain(pi); + + save_bb_mult = wlc_lcnphy_get_bbmult(pi); + + if (SAVE_txpwrctrl == LCNPHY_TX_PWR_CTRL_OFF) + SAVE_txpwrindex = wlc_lcnphy_get_current_tx_pwr_idx(pi); + + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + + target_gains.gm_gain = 7; + target_gains.pga_gain = 0; + target_gains.pad_gain = 21; + target_gains.dac_gain = 0; + wlc_lcnphy_set_tx_gain(pi, &target_gains); + wlc_lcnphy_set_tx_pwr_by_index(pi, 16); + + if (LCNREV_IS(pi->pubpi.phy_rev, 1) || pi_lcn->lcnphy_hw_iqcal_en) { + + wlc_lcnphy_set_tx_pwr_by_index(pi, 30); + + wlc_lcnphy_tx_iqlo_cal(pi, &target_gains, + (pi_lcn-> + lcnphy_recal ? LCNPHY_CAL_RECAL : + LCNPHY_CAL_FULL), false); + } else { + wlc_lcnphy_tx_iqlo_soft_cal_full(pi); + } + + wlc_lcnphy_get_radio_loft(pi, &ei0, &eq0, &fi0, &fq0); + if ((abs((s8) fi0) == 15) && (abs((s8) fq0) == 15)) { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + target_gains.gm_gain = 255; + target_gains.pga_gain = 255; + target_gains.pad_gain = 0xf0; + target_gains.dac_gain = 0; + } else { + target_gains.gm_gain = 7; + target_gains.pga_gain = 45; + target_gains.pad_gain = 186; + target_gains.dac_gain = 0; + } + + if (LCNREV_IS(pi->pubpi.phy_rev, 1) + || pi_lcn->lcnphy_hw_iqcal_en) { + + target_gains.pga_gain = 0; + target_gains.pad_gain = 30; + wlc_lcnphy_set_tx_pwr_by_index(pi, 16); + wlc_lcnphy_tx_iqlo_cal(pi, &target_gains, + LCNPHY_CAL_FULL, false); + } else { + wlc_lcnphy_tx_iqlo_soft_cal_full(pi); + } + } + + wlc_lcnphy_get_tx_iqcc(pi, &a, &b); + + didq = wlc_lcnphy_get_tx_locc(pi); + + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_ptr = &val; + + tab.tbl_len = 1; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_RATE_OFFSET; + + for (idx = 0; idx < 128; idx++) { + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + idx; + + wlc_lcnphy_read_table(pi, &tab); + val = (val & 0xfff00000) | + ((u32) (a & 0x3FF) << 10) | (b & 0x3ff); + wlc_lcnphy_write_table(pi, &tab); + + val = didq; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_LO_OFFSET + idx; + wlc_lcnphy_write_table(pi, &tab); + } + + pi_lcn->lcnphy_cal_results.txiqlocal_a = a; + pi_lcn->lcnphy_cal_results.txiqlocal_b = b; + pi_lcn->lcnphy_cal_results.txiqlocal_didq = didq; + pi_lcn->lcnphy_cal_results.txiqlocal_ei0 = ei0; + pi_lcn->lcnphy_cal_results.txiqlocal_eq0 = eq0; + pi_lcn->lcnphy_cal_results.txiqlocal_fi0 = fi0; + pi_lcn->lcnphy_cal_results.txiqlocal_fq0 = fq0; + + wlc_lcnphy_set_bbmult(pi, save_bb_mult); + wlc_lcnphy_set_pa_gain(pi, save_pa_gain); + wlc_lcnphy_set_tx_gain(pi, &old_gains); + + if (SAVE_txpwrctrl != LCNPHY_TX_PWR_CTRL_OFF) + wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); + else + wlc_lcnphy_set_tx_pwr_by_index(pi, SAVE_txpwrindex); +} + +s16 wlc_lcnphy_tempsense_new(struct brcms_phy *pi, bool mode) +{ + u16 tempsenseval1, tempsenseval2; + s16 avg = 0; + bool suspend = 0; + + if (mode == 1) { + suspend = + (0 == + (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); + } + tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF; + tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF; + + if (tempsenseval1 > 255) + avg = (s16) (tempsenseval1 - 512); + else + avg = (s16) tempsenseval1; + + if (tempsenseval2 > 255) + avg += (s16) (tempsenseval2 - 512); + else + avg += (s16) tempsenseval2; + + avg /= 2; + + if (mode == 1) { + + mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); + + udelay(100); + mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); + + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); + } + return avg; +} + +u16 wlc_lcnphy_tempsense(struct brcms_phy *pi, bool mode) +{ + u16 tempsenseval1, tempsenseval2; + s32 avg = 0; + bool suspend = 0; + u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + if (mode == 1) { + suspend = + (0 == + (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + wlc_lcnphy_vbat_temp_sense_setup(pi, TEMPSENSE); + } + tempsenseval1 = read_phy_reg(pi, 0x476) & 0x1FF; + tempsenseval2 = read_phy_reg(pi, 0x477) & 0x1FF; + + if (tempsenseval1 > 255) + avg = (int)(tempsenseval1 - 512); + else + avg = (int)tempsenseval1; + + if (pi_lcn->lcnphy_tempsense_option == 1 || pi->hwpwrctrl_capable) { + if (tempsenseval2 > 255) + avg = (int)(avg - tempsenseval2 + 512); + else + avg = (int)(avg - tempsenseval2); + } else { + if (tempsenseval2 > 255) + avg = (int)(avg + tempsenseval2 - 512); + else + avg = (int)(avg + tempsenseval2); + avg = avg / 2; + } + if (avg < 0) + avg = avg + 512; + + if (pi_lcn->lcnphy_tempsense_option == 2) + avg = tempsenseval1; + + if (mode) + wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_txpwrctrl); + + if (mode == 1) { + + mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); + + udelay(100); + mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); + + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); + } + return (u16) avg; +} + +s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode) +{ + s32 degree = wlc_lcnphy_tempsense_new(pi, mode); + degree = + ((degree << + 10) + LCN_TEMPSENSE_OFFSET + (LCN_TEMPSENSE_DEN >> 1)) + / LCN_TEMPSENSE_DEN; + return (s8) degree; +} + +s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode) +{ + u16 vbatsenseval; + s32 avg = 0; + bool suspend = 0; + + if (mode == 1) { + suspend = + (0 == + (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + wlc_lcnphy_vbat_temp_sense_setup(pi, VBATSENSE); + } + + vbatsenseval = read_phy_reg(pi, 0x475) & 0x1FF; + + if (vbatsenseval > 255) + avg = (s32) (vbatsenseval - 512); + else + avg = (s32) vbatsenseval; + + avg = (avg * LCN_VBAT_SCALE_NOM + + (LCN_VBAT_SCALE_DEN >> 1)) / LCN_VBAT_SCALE_DEN; + + if (mode == 1) { + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); + } + return (s8) avg; +} + +static void wlc_lcnphy_afe_clk_init(struct brcms_phy *pi, u8 mode) +{ + u8 phybw40; + phybw40 = CHSPEC_IS40(pi->radio_chanspec); + + mod_phy_reg(pi, 0x6d1, (0x1 << 7), (1) << 7); + + if (((mode == AFE_CLK_INIT_MODE_PAPD) && (phybw40 == 0)) || + (mode == AFE_CLK_INIT_MODE_TXRX2X)) + write_phy_reg(pi, 0x6d0, 0x7); + + wlc_lcnphy_toggle_afe_pwdn(pi); +} + +static void wlc_lcnphy_temp_adj(struct brcms_phy *pi) +{ +} + +static void wlc_lcnphy_glacial_timer_based_cal(struct brcms_phy *pi) +{ + bool suspend; + s8 index; + u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + suspend = + (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + wlc_lcnphy_deaf_mode(pi, true); + pi->phy_lastcal = pi->sh->now; + pi->phy_forcecal = false; + index = pi_lcn->lcnphy_current_index; + + wlc_lcnphy_txpwrtbl_iqlo_cal(pi); + + wlc_lcnphy_set_tx_pwr_by_index(pi, index); + wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl); + wlc_lcnphy_deaf_mode(pi, false); + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); + +} + +static void wlc_lcnphy_periodic_cal(struct brcms_phy *pi) +{ + bool suspend, full_cal; + const struct lcnphy_rx_iqcomp *rx_iqcomp; + int rx_iqcomp_sz; + u16 SAVE_pwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + s8 index; + struct phytbl_info tab; + s32 a1, b0, b1; + s32 tssi, pwr, maxtargetpwr, mintargetpwr; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + pi->phy_lastcal = pi->sh->now; + pi->phy_forcecal = false; + full_cal = + (pi_lcn->lcnphy_full_cal_channel != + CHSPEC_CHANNEL(pi->radio_chanspec)); + pi_lcn->lcnphy_full_cal_channel = CHSPEC_CHANNEL(pi->radio_chanspec); + index = pi_lcn->lcnphy_current_index; + + suspend = + (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) { + wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000); + wlapi_suspend_mac_and_wait(pi->sh->physhim); + } + + wlc_lcnphy_deaf_mode(pi, true); + + wlc_lcnphy_txpwrtbl_iqlo_cal(pi); + + rx_iqcomp = lcnphy_rx_iqcomp_table_rev0; + rx_iqcomp_sz = ARRAY_SIZE(lcnphy_rx_iqcomp_table_rev0); + + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) + wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 40); + else + wlc_lcnphy_rx_iq_cal(pi, NULL, 0, true, false, 1, 127); + + if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) { + + wlc_lcnphy_idle_tssi_est((struct brcms_phy_pub *) pi); + + b0 = pi->txpa_2g[0]; + b1 = pi->txpa_2g[1]; + a1 = pi->txpa_2g[2]; + maxtargetpwr = wlc_lcnphy_tssi2dbm(10, a1, b0, b1); + mintargetpwr = wlc_lcnphy_tssi2dbm(125, a1, b0, b1); + + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_ptr = &pwr; + tab.tbl_len = 1; + tab.tbl_offset = 0; + for (tssi = 0; tssi < 128; tssi++) { + pwr = wlc_lcnphy_tssi2dbm(tssi, a1, b0, b1); + pwr = (pwr < mintargetpwr) ? mintargetpwr : pwr; + wlc_lcnphy_write_table(pi, &tab); + tab.tbl_offset++; + } + } + + wlc_lcnphy_set_tx_pwr_by_index(pi, index); + wlc_lcnphy_set_tx_pwr_ctrl(pi, SAVE_pwrctrl); + wlc_lcnphy_deaf_mode(pi, false); + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); +} + +void wlc_lcnphy_calib_modes(struct brcms_phy *pi, uint mode) +{ + u16 temp_new; + int temp1, temp2, temp_diff; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + switch (mode) { + case PHY_PERICAL_CHAN: + break; + case PHY_FULLCAL: + wlc_lcnphy_periodic_cal(pi); + break; + case PHY_PERICAL_PHYINIT: + wlc_lcnphy_periodic_cal(pi); + break; + case PHY_PERICAL_WATCHDOG: + if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { + temp_new = wlc_lcnphy_tempsense(pi, 0); + temp1 = LCNPHY_TEMPSENSE(temp_new); + temp2 = LCNPHY_TEMPSENSE(pi_lcn->lcnphy_cal_temper); + temp_diff = temp1 - temp2; + if ((pi_lcn->lcnphy_cal_counter > 90) || + (temp_diff > 60) || (temp_diff < -60)) { + wlc_lcnphy_glacial_timer_based_cal(pi); + wlc_2064_vco_cal(pi); + pi_lcn->lcnphy_cal_temper = temp_new; + pi_lcn->lcnphy_cal_counter = 0; + } else + pi_lcn->lcnphy_cal_counter++; + } + break; + case LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL: + if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) + wlc_lcnphy_tx_power_adjustment( + (struct brcms_phy_pub *) pi); + break; + } +} + +void wlc_lcnphy_get_tssi(struct brcms_phy *pi, s8 *ofdm_pwr, s8 *cck_pwr) +{ + s8 cck_offset; + u16 status; + status = (read_phy_reg(pi, 0x4ab)); + if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi) && + (status & (0x1 << 15))) { + *ofdm_pwr = (s8) (((read_phy_reg(pi, 0x4ab) & (0x1ff << 0)) + >> 0) >> 1); + + if (wlc_phy_tpc_isenabled_lcnphy(pi)) + cck_offset = pi->tx_power_offset[TXP_FIRST_CCK]; + else + cck_offset = 0; + + *cck_pwr = *ofdm_pwr + cck_offset; + } else { + *cck_pwr = 0; + *ofdm_pwr = 0; + } +} + +void wlc_phy_cal_init_lcnphy(struct brcms_phy *pi) +{ + return; + +} + +void wlc_lcnphy_tx_power_adjustment(struct brcms_phy_pub *ppi) +{ + s8 index; + u16 index2; + struct brcms_phy *pi = (struct brcms_phy *) ppi; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + u16 SAVE_txpwrctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi) && + SAVE_txpwrctrl) { + index = wlc_lcnphy_tempcompensated_txpwrctrl(pi); + index2 = (u16) (index * 2); + mod_phy_reg(pi, 0x4a9, (0x1ff << 0), (index2) << 0); + + pi_lcn->lcnphy_current_index = + (s8)((read_phy_reg(pi, 0x4a9) & 0xFF) / 2); + } +} + +static void +wlc_lcnphy_load_tx_gain_table(struct brcms_phy *pi, + const struct lcnphy_tx_gain_tbl_entry *gain_table) +{ + u32 j; + struct phytbl_info tab; + u32 val; + u16 pa_gain; + u16 gm_gain; + + if (CHSPEC_IS5G(pi->radio_chanspec)) + pa_gain = 0x70; + else + pa_gain = 0x70; + + if (pi->sh->boardflags & BFL_FEM) + pa_gain = 0x10; + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_len = 1; + tab.tbl_ptr = &val; + + for (j = 0; j < 128; j++) { + gm_gain = gain_table[j].gm; + val = (((u32) pa_gain << 24) | + (gain_table[j].pad << 16) | + (gain_table[j].pga << 8) | gm_gain); + + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + j; + wlc_lcnphy_write_table(pi, &tab); + + val = (gain_table[j].dac << 28) | (gain_table[j].bb_mult << 20); + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + j; + wlc_lcnphy_write_table(pi, &tab); + } +} + +static void wlc_lcnphy_load_rfpower(struct brcms_phy *pi) +{ + struct phytbl_info tab; + u32 val, bbmult, rfgain; + u8 index; + u8 scale_factor = 1; + s16 temp, temp1, temp2, qQ, qQ1, qQ2, shift; + + tab.tbl_id = LCNPHY_TBL_ID_TXPWRCTL; + tab.tbl_width = 32; + tab.tbl_len = 1; + + for (index = 0; index < 128; index++) { + tab.tbl_ptr = &bbmult; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_IQ_OFFSET + index; + wlc_lcnphy_read_table(pi, &tab); + bbmult = bbmult >> 20; + + tab.tbl_ptr = &rfgain; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_GAIN_OFFSET + index; + wlc_lcnphy_read_table(pi, &tab); + + qm_log10((s32) (bbmult), 0, &temp1, &qQ1); + qm_log10((s32) (1 << 6), 0, &temp2, &qQ2); + + if (qQ1 < qQ2) { + temp2 = qm_shr16(temp2, qQ2 - qQ1); + qQ = qQ1; + } else { + temp1 = qm_shr16(temp1, qQ1 - qQ2); + qQ = qQ2; + } + temp = qm_sub16(temp1, temp2); + + if (qQ >= 4) + shift = qQ - 4; + else + shift = 4 - qQ; + + val = (((index << shift) + (5 * temp) + + (1 << (scale_factor + shift - 3))) >> (scale_factor + + shift - 2)); + + tab.tbl_ptr = &val; + tab.tbl_offset = LCNPHY_TX_PWR_CTRL_PWR_OFFSET + index; + wlc_lcnphy_write_table(pi, &tab); + } +} + +static void wlc_lcnphy_bu_tweaks(struct brcms_phy *pi) +{ + or_phy_reg(pi, 0x805, 0x1); + + mod_phy_reg(pi, 0x42f, (0x7 << 0), (0x3) << 0); + + mod_phy_reg(pi, 0x030, (0x7 << 0), (0x3) << 0); + + write_phy_reg(pi, 0x414, 0x1e10); + write_phy_reg(pi, 0x415, 0x0640); + + mod_phy_reg(pi, 0x4df, (0xff << 8), -9 << 8); + + or_phy_reg(pi, 0x44a, 0x44); + write_phy_reg(pi, 0x44a, 0x80); + mod_phy_reg(pi, 0x434, (0xff << 0), (0xFD) << 0); + + mod_phy_reg(pi, 0x420, (0xff << 0), (16) << 0); + + if (!(pi->sh->boardrev < 0x1204)) + mod_radio_reg(pi, RADIO_2064_REG09B, 0xF0, 0xF0); + + write_phy_reg(pi, 0x7d6, 0x0902); + mod_phy_reg(pi, 0x429, (0xf << 0), (0x9) << 0); + + mod_phy_reg(pi, 0x429, (0x3f << 4), (0xe) << 4); + + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { + mod_phy_reg(pi, 0x423, (0xff << 0), (0x46) << 0); + + mod_phy_reg(pi, 0x411, (0xff << 0), (1) << 0); + + mod_phy_reg(pi, 0x434, (0xff << 0), (0xFF) << 0); + + mod_phy_reg(pi, 0x656, (0xf << 0), (2) << 0); + + mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2); + + mod_radio_reg(pi, RADIO_2064_REG0F7, 0x4, 0x4); + mod_radio_reg(pi, RADIO_2064_REG0F1, 0x3, 0); + mod_radio_reg(pi, RADIO_2064_REG0F2, 0xF8, 0x90); + mod_radio_reg(pi, RADIO_2064_REG0F3, 0x3, 0x2); + mod_radio_reg(pi, RADIO_2064_REG0F3, 0xf0, 0xa0); + + mod_radio_reg(pi, RADIO_2064_REG11F, 0x2, 0x2); + + wlc_lcnphy_clear_tx_power_offsets(pi); + mod_phy_reg(pi, 0x4d0, (0x1ff << 6), (10) << 6); + + } +} + +static void wlc_lcnphy_rcal(struct brcms_phy *pi) +{ + u8 rcal_value; + + and_radio_reg(pi, RADIO_2064_REG05B, 0xfD); + + or_radio_reg(pi, RADIO_2064_REG004, 0x40); + or_radio_reg(pi, RADIO_2064_REG120, 0x10); + + or_radio_reg(pi, RADIO_2064_REG078, 0x80); + or_radio_reg(pi, RADIO_2064_REG129, 0x02); + + or_radio_reg(pi, RADIO_2064_REG057, 0x01); + + or_radio_reg(pi, RADIO_2064_REG05B, 0x02); + mdelay(5); + SPINWAIT(!wlc_radio_2064_rcal_done(pi), 10 * 1000 * 1000); + + if (wlc_radio_2064_rcal_done(pi)) { + rcal_value = (u8) read_radio_reg(pi, RADIO_2064_REG05C); + rcal_value = rcal_value & 0x1f; + } + + and_radio_reg(pi, RADIO_2064_REG05B, 0xfD); + + and_radio_reg(pi, RADIO_2064_REG057, 0xFE); +} + +static void wlc_lcnphy_rc_cal(struct brcms_phy *pi) +{ + u8 dflt_rc_cal_val; + u16 flt_val; + + dflt_rc_cal_val = 7; + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) + dflt_rc_cal_val = 11; + flt_val = + (dflt_rc_cal_val << 10) | (dflt_rc_cal_val << 5) | + (dflt_rc_cal_val); + write_phy_reg(pi, 0x933, flt_val); + write_phy_reg(pi, 0x934, flt_val); + write_phy_reg(pi, 0x935, flt_val); + write_phy_reg(pi, 0x936, flt_val); + write_phy_reg(pi, 0x937, (flt_val & 0x1FF)); + + return; +} + +static void wlc_radio_2064_init(struct brcms_phy *pi) +{ + u32 i; + const struct lcnphy_radio_regs *lcnphyregs = NULL; + + lcnphyregs = lcnphy_radio_regs_2064; + + for (i = 0; lcnphyregs[i].address != 0xffff; i++) + if (CHSPEC_IS5G(pi->radio_chanspec) && lcnphyregs[i].do_init_a) + write_radio_reg(pi, + ((lcnphyregs[i].address & 0x3fff) | + RADIO_DEFAULT_CORE), + (u16) lcnphyregs[i].init_a); + else if (lcnphyregs[i].do_init_g) + write_radio_reg(pi, + ((lcnphyregs[i].address & 0x3fff) | + RADIO_DEFAULT_CORE), + (u16) lcnphyregs[i].init_g); + + write_radio_reg(pi, RADIO_2064_REG032, 0x62); + write_radio_reg(pi, RADIO_2064_REG033, 0x19); + + write_radio_reg(pi, RADIO_2064_REG090, 0x10); + + write_radio_reg(pi, RADIO_2064_REG010, 0x00); + + if (LCNREV_IS(pi->pubpi.phy_rev, 1)) { + + write_radio_reg(pi, RADIO_2064_REG060, 0x7f); + write_radio_reg(pi, RADIO_2064_REG061, 0x72); + write_radio_reg(pi, RADIO_2064_REG062, 0x7f); + } + + write_radio_reg(pi, RADIO_2064_REG01D, 0x02); + write_radio_reg(pi, RADIO_2064_REG01E, 0x06); + + mod_phy_reg(pi, 0x4ea, (0x7 << 0), 0 << 0); + + mod_phy_reg(pi, 0x4ea, (0x7 << 3), 1 << 3); + + mod_phy_reg(pi, 0x4ea, (0x7 << 6), 2 << 6); + + mod_phy_reg(pi, 0x4ea, (0x7 << 9), 3 << 9); + + mod_phy_reg(pi, 0x4ea, (0x7 << 12), 4 << 12); + + write_phy_reg(pi, 0x4ea, 0x4688); + + mod_phy_reg(pi, 0x4eb, (0x7 << 0), 2 << 0); + + mod_phy_reg(pi, 0x4eb, (0x7 << 6), 0 << 6); + + mod_phy_reg(pi, 0x46a, (0xffff << 0), 25 << 0); + + wlc_lcnphy_set_tx_locc(pi, 0); + + wlc_lcnphy_rcal(pi); + + wlc_lcnphy_rc_cal(pi); +} + +static void wlc_lcnphy_radio_init(struct brcms_phy *pi) +{ + wlc_radio_2064_init(pi); +} + +static void wlc_lcnphy_tbl_init(struct brcms_phy *pi) +{ + uint idx; + u8 phybw40; + struct phytbl_info tab; + u32 val; + + phybw40 = CHSPEC_IS40(pi->radio_chanspec); + + for (idx = 0; idx < dot11lcnphytbl_info_sz_rev0; idx++) + wlc_lcnphy_write_table(pi, &dot11lcnphytbl_info_rev0[idx]); + + if (pi->sh->boardflags & BFL_FEM_BT) { + tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; + tab.tbl_width = 16; + tab.tbl_ptr = &val; + tab.tbl_len = 1; + val = 100; + tab.tbl_offset = 4; + wlc_lcnphy_write_table(pi, &tab); + } + + tab.tbl_id = LCNPHY_TBL_ID_RFSEQ; + tab.tbl_width = 16; + tab.tbl_ptr = &val; + tab.tbl_len = 1; + + val = 114; + tab.tbl_offset = 0; + wlc_lcnphy_write_table(pi, &tab); + + val = 130; + tab.tbl_offset = 1; + wlc_lcnphy_write_table(pi, &tab); + + val = 6; + tab.tbl_offset = 8; + wlc_lcnphy_write_table(pi, &tab); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (pi->sh->boardflags & BFL_FEM) + wlc_lcnphy_load_tx_gain_table( + pi, + dot11lcnphy_2GHz_extPA_gaintable_rev0); + else + wlc_lcnphy_load_tx_gain_table( + pi, + dot11lcnphy_2GHz_gaintable_rev0); + } + + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) { + const struct phytbl_info *tb; + int l; + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + l = dot11lcnphytbl_rx_gain_info_2G_rev2_sz; + if (pi->sh->boardflags & BFL_EXTLNA) + tb = dot11lcnphytbl_rx_gain_info_extlna_2G_rev2; + else + tb = dot11lcnphytbl_rx_gain_info_2G_rev2; + } else { + l = dot11lcnphytbl_rx_gain_info_5G_rev2_sz; + if (pi->sh->boardflags & BFL_EXTLNA_5GHz) + tb = dot11lcnphytbl_rx_gain_info_extlna_5G_rev2; + else + tb = dot11lcnphytbl_rx_gain_info_5G_rev2; + } + + for (idx = 0; idx < l; idx++) + wlc_lcnphy_write_table(pi, &tb[idx]); + } + + if ((pi->sh->boardflags & BFL_FEM) + && !(pi->sh->boardflags & BFL_FEM_BT)) + wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313_epa); + else if (pi->sh->boardflags & BFL_FEM_BT) { + if (pi->sh->boardrev < 0x1250) + wlc_lcnphy_write_table( + pi, + &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa); + else + wlc_lcnphy_write_table( + pi, + &dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250); + } else + wlc_lcnphy_write_table(pi, &dot11lcn_sw_ctrl_tbl_info_4313); + + wlc_lcnphy_load_rfpower(pi); + + wlc_lcnphy_clear_papd_comptable(pi); +} + +static void wlc_lcnphy_rev0_baseband_init(struct brcms_phy *pi) +{ + u16 afectrl1; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + write_radio_reg(pi, RADIO_2064_REG11C, 0x0); + + write_phy_reg(pi, 0x43b, 0x0); + write_phy_reg(pi, 0x43c, 0x0); + write_phy_reg(pi, 0x44c, 0x0); + write_phy_reg(pi, 0x4e6, 0x0); + write_phy_reg(pi, 0x4f9, 0x0); + write_phy_reg(pi, 0x4b0, 0x0); + write_phy_reg(pi, 0x938, 0x0); + write_phy_reg(pi, 0x4b0, 0x0); + write_phy_reg(pi, 0x44e, 0); + + or_phy_reg(pi, 0x567, 0x03); + + or_phy_reg(pi, 0x44a, 0x44); + write_phy_reg(pi, 0x44a, 0x80); + + if (!(pi->sh->boardflags & BFL_FEM)) + wlc_lcnphy_set_tx_pwr_by_index(pi, 52); + + if (0) { + afectrl1 = 0; + afectrl1 = (u16) ((pi_lcn->lcnphy_rssi_vf) | + (pi_lcn->lcnphy_rssi_vc << 4) | + (pi_lcn->lcnphy_rssi_gs << 10)); + write_phy_reg(pi, 0x43e, afectrl1); + } + + mod_phy_reg(pi, 0x634, (0xff << 0), 0xC << 0); + if (pi->sh->boardflags & BFL_FEM) { + mod_phy_reg(pi, 0x634, (0xff << 0), 0xA << 0); + + write_phy_reg(pi, 0x910, 0x1); + } + + mod_phy_reg(pi, 0x448, (0x3 << 8), 1 << 8); + mod_phy_reg(pi, 0x608, (0xff << 0), 0x17 << 0); + mod_phy_reg(pi, 0x604, (0x7ff << 0), 0x3EA << 0); + +} + +static void wlc_lcnphy_rev2_baseband_init(struct brcms_phy *pi) +{ + if (CHSPEC_IS5G(pi->radio_chanspec)) { + mod_phy_reg(pi, 0x416, (0xff << 0), 80 << 0); + mod_phy_reg(pi, 0x416, (0xff << 8), 80 << 8); + } +} + +static void wlc_lcnphy_agc_temp_init(struct brcms_phy *pi) +{ + s16 temp; + struct phytbl_info tab; + u32 tableBuffer[2]; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + temp = (s16) read_phy_reg(pi, 0x4df); + pi_lcn->lcnphy_ofdmgainidxtableoffset = (temp & (0xff << 0)) >> 0; + + if (pi_lcn->lcnphy_ofdmgainidxtableoffset > 127) + pi_lcn->lcnphy_ofdmgainidxtableoffset -= 256; + + pi_lcn->lcnphy_dsssgainidxtableoffset = (temp & (0xff << 8)) >> 8; + + if (pi_lcn->lcnphy_dsssgainidxtableoffset > 127) + pi_lcn->lcnphy_dsssgainidxtableoffset -= 256; + + tab.tbl_ptr = tableBuffer; + tab.tbl_len = 2; + tab.tbl_id = 17; + tab.tbl_offset = 59; + tab.tbl_width = 32; + wlc_lcnphy_read_table(pi, &tab); + + if (tableBuffer[0] > 63) + tableBuffer[0] -= 128; + pi_lcn->lcnphy_tr_R_gain_val = tableBuffer[0]; + + if (tableBuffer[1] > 63) + tableBuffer[1] -= 128; + pi_lcn->lcnphy_tr_T_gain_val = tableBuffer[1]; + + temp = (s16) (read_phy_reg(pi, 0x434) & (0xff << 0)); + if (temp > 127) + temp -= 256; + pi_lcn->lcnphy_input_pwr_offset_db = (s8) temp; + + pi_lcn->lcnphy_Med_Low_Gain_db = + (read_phy_reg(pi, 0x424) & (0xff << 8)) >> 8; + pi_lcn->lcnphy_Very_Low_Gain_db = + (read_phy_reg(pi, 0x425) & (0xff << 0)) >> 0; + + tab.tbl_ptr = tableBuffer; + tab.tbl_len = 2; + tab.tbl_id = LCNPHY_TBL_ID_GAIN_IDX; + tab.tbl_offset = 28; + tab.tbl_width = 32; + wlc_lcnphy_read_table(pi, &tab); + + pi_lcn->lcnphy_gain_idx_14_lowword = tableBuffer[0]; + pi_lcn->lcnphy_gain_idx_14_hiword = tableBuffer[1]; + +} + +static void wlc_lcnphy_baseband_init(struct brcms_phy *pi) +{ + + wlc_lcnphy_tbl_init(pi); + wlc_lcnphy_rev0_baseband_init(pi); + if (LCNREV_IS(pi->pubpi.phy_rev, 2)) + wlc_lcnphy_rev2_baseband_init(pi); + wlc_lcnphy_bu_tweaks(pi); +} + +void wlc_phy_init_lcnphy(struct brcms_phy *pi) +{ + u8 phybw40; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + phybw40 = CHSPEC_IS40(pi->radio_chanspec); + + pi_lcn->lcnphy_cal_counter = 0; + pi_lcn->lcnphy_cal_temper = pi_lcn->lcnphy_rawtempsense; + + or_phy_reg(pi, 0x44a, 0x80); + and_phy_reg(pi, 0x44a, 0x7f); + + wlc_lcnphy_afe_clk_init(pi, AFE_CLK_INIT_MODE_TXRX2X); + + write_phy_reg(pi, 0x60a, 160); + + write_phy_reg(pi, 0x46a, 25); + + wlc_lcnphy_baseband_init(pi); + + wlc_lcnphy_radio_init(pi); + + if (CHSPEC_IS2G(pi->radio_chanspec)) + wlc_lcnphy_tx_pwr_ctrl_init((struct brcms_phy_pub *) pi); + + wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec); + + si_pmu_regcontrol(pi->sh->sih, 0, 0xf, 0x9); + + si_pmu_chipcontrol(pi->sh->sih, 0, 0xffffffff, 0x03CDDDDD); + + if ((pi->sh->boardflags & BFL_FEM) + && wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) + wlc_lcnphy_set_tx_pwr_by_index(pi, FIXED_TXPWR); + + wlc_lcnphy_agc_temp_init(pi); + + wlc_lcnphy_temp_adj(pi); + + mod_phy_reg(pi, 0x448, (0x1 << 14), (1) << 14); + + udelay(100); + mod_phy_reg(pi, 0x448, (0x1 << 14), (0) << 14); + + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_HW); + pi_lcn->lcnphy_noise_samples = LCNPHY_NOISE_SAMPLES_DEFAULT; + wlc_lcnphy_calib_modes(pi, PHY_PERICAL_PHYINIT); +} + +static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) +{ + s8 txpwr = 0; + int i; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + struct phy_shim_info *shim = pi->sh->physhim; + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + u16 cckpo = 0; + u32 offset_ofdm, offset_mcs; + + pi_lcn->lcnphy_tr_isolation_mid = + (u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G); + + pi_lcn->lcnphy_rx_power_offset = + (u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G); + + pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0); + pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1); + pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2); + + pi_lcn->lcnphy_rssi_vf = + (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G); + pi_lcn->lcnphy_rssi_vc = + (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G); + pi_lcn->lcnphy_rssi_gs = + (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G); + + pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf; + pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc; + pi_lcn->lcnphy_rssi_gs_lowtemp = pi_lcn->lcnphy_rssi_gs; + + pi_lcn->lcnphy_rssi_vf_hightemp = pi_lcn->lcnphy_rssi_vf; + pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc; + pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs; + + txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0); + pi->tx_srom_max_2g = txpwr; + + for (i = 0; i < PWRTBL_NUM_COEFF; i++) { + pi->txpa_2g_low_temp[i] = pi->txpa_2g[i]; + pi->txpa_2g_high_temp[i] = pi->txpa_2g[i]; + } + + cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO); + offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO); + if (cckpo) { + uint max_pwr_chan = txpwr; + + for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) { + pi->tx_srom_max_rate_2g[i] = + max_pwr_chan - ((cckpo & 0xf) * 2); + cckpo >>= 4; + } + + for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) { + pi->tx_srom_max_rate_2g[i] = + max_pwr_chan - + ((offset_ofdm & 0xf) * 2); + offset_ofdm >>= 4; + } + } else { + u8 opo = 0; + + opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO); + + for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) + pi->tx_srom_max_rate_2g[i] = txpwr; + + for (i = TXP_FIRST_OFDM; i <= TXP_LAST_OFDM; i++) { + pi->tx_srom_max_rate_2g[i] = txpwr - + ((offset_ofdm & 0xf) * 2); + offset_ofdm >>= 4; + } + offset_mcs = + wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO1) << 16; + offset_mcs |= + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO0); + pi_lcn->lcnphy_mcs20_po = offset_mcs; + for (i = TXP_FIRST_SISO_MCS_20; + i <= TXP_LAST_SISO_MCS_20; i++) { + pi->tx_srom_max_rate_2g[i] = + txpwr - ((offset_mcs & 0xf) * 2); + offset_mcs >>= 4; + } + } + + pi_lcn->lcnphy_rawtempsense = + (u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE); + pi_lcn->lcnphy_measPower = + (u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER); + pi_lcn->lcnphy_tempsense_slope = + (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE); + pi_lcn->lcnphy_hw_iqcal_en = + (bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN); + pi_lcn->lcnphy_iqcal_swp_dis = + (bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS); + pi_lcn->lcnphy_tempcorrx = + (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX); + pi_lcn->lcnphy_tempsense_option = + (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION); + pi_lcn->lcnphy_freqoffset_corr = + (u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR); + if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1) + wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, + (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G)); + } + pi_lcn->lcnphy_cck_dig_filt_type = -1; + + return true; +} + +void wlc_2064_vco_cal(struct brcms_phy *pi) +{ + u8 calnrst; + + mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 1 << 3); + calnrst = (u8) read_radio_reg(pi, RADIO_2064_REG056) & 0xf8; + write_radio_reg(pi, RADIO_2064_REG056, calnrst); + udelay(1); + write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x03); + udelay(1); + write_radio_reg(pi, RADIO_2064_REG056, calnrst | 0x07); + udelay(300); + mod_radio_reg(pi, RADIO_2064_REG057, 1 << 3, 0); +} + +bool wlc_phy_tpc_isenabled_lcnphy(struct brcms_phy *pi) +{ + if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) + return 0; + else + return (LCNPHY_TX_PWR_CTRL_HW == + wlc_lcnphy_get_tx_pwr_ctrl((pi))); +} + +void wlc_phy_txpower_recalc_target_lcnphy(struct brcms_phy *pi) +{ + u16 pwr_ctrl; + if (wlc_lcnphy_tempsense_based_pwr_ctrl_enabled(pi)) { + wlc_lcnphy_calib_modes(pi, LCNPHY_PERICAL_TEMPBASED_TXPWRCTRL); + } else if (wlc_lcnphy_tssi_based_pwr_ctrl_enabled(pi)) { + pwr_ctrl = wlc_lcnphy_get_tx_pwr_ctrl(pi); + wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); + wlc_lcnphy_txpower_recalc_target(pi); + wlc_lcnphy_set_tx_pwr_ctrl(pi, pwr_ctrl); + } +} + +void wlc_phy_detach_lcnphy(struct brcms_phy *pi) +{ + kfree(pi->u.pi_lcnphy); +} + +bool wlc_phy_attach_lcnphy(struct brcms_phy *pi) +{ + struct brcms_phy_lcnphy *pi_lcn; + + pi->u.pi_lcnphy = kzalloc(sizeof(struct brcms_phy_lcnphy), GFP_ATOMIC); + if (pi->u.pi_lcnphy == NULL) + return false; + + pi_lcn = pi->u.pi_lcnphy; + + if (0 == (pi->sh->boardflags & BFL_NOPA)) { + pi->hwpwrctrl = true; + pi->hwpwrctrl_capable = true; + } + + pi->xtalfreq = si_pmu_alp_clock(pi->sh->sih); + pi_lcn->lcnphy_papd_rxGnCtrl_init = 0; + + pi->pi_fptr.init = wlc_phy_init_lcnphy; + pi->pi_fptr.calinit = wlc_phy_cal_init_lcnphy; + pi->pi_fptr.chanset = wlc_phy_chanspec_set_lcnphy; + pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_lcnphy; + pi->pi_fptr.txiqccget = wlc_lcnphy_get_tx_iqcc; + pi->pi_fptr.txiqccset = wlc_lcnphy_set_tx_iqcc; + pi->pi_fptr.txloccget = wlc_lcnphy_get_tx_locc; + pi->pi_fptr.radioloftget = wlc_lcnphy_get_radio_loft; + pi->pi_fptr.detach = wlc_phy_detach_lcnphy; + + if (!wlc_phy_txpwr_srom_read_lcnphy(pi)) + return false; + + if ((pi->sh->boardflags & BFL_FEM) && + (LCNREV_IS(pi->pubpi.phy_rev, 1))) { + if (pi_lcn->lcnphy_tempsense_option == 3) { + pi->hwpwrctrl = true; + pi->hwpwrctrl_capable = true; + pi->temppwrctrl_capable = false; + } else { + pi->hwpwrctrl = false; + pi->hwpwrctrl_capable = false; + pi->temppwrctrl_capable = true; + } + } + + return true; +} + +static void wlc_lcnphy_set_rx_gain(struct brcms_phy *pi, u32 gain) +{ + u16 trsw, ext_lna, lna1, lna2, tia, biq0, biq1, gain0_15, gain16_19; + + trsw = (gain & ((u32) 1 << 28)) ? 0 : 1; + ext_lna = (u16) (gain >> 29) & 0x01; + lna1 = (u16) (gain >> 0) & 0x0f; + lna2 = (u16) (gain >> 4) & 0x0f; + tia = (u16) (gain >> 8) & 0xf; + biq0 = (u16) (gain >> 12) & 0xf; + biq1 = (u16) (gain >> 16) & 0xf; + + gain0_15 = (u16) ((lna1 & 0x3) | ((lna1 & 0x3) << 2) | + ((lna2 & 0x3) << 4) | ((lna2 & 0x3) << 6) | + ((tia & 0xf) << 8) | ((biq0 & 0xf) << 12)); + gain16_19 = biq1; + + mod_phy_reg(pi, 0x44d, (0x1 << 0), trsw << 0); + mod_phy_reg(pi, 0x4b1, (0x1 << 9), ext_lna << 9); + mod_phy_reg(pi, 0x4b1, (0x1 << 10), ext_lna << 10); + mod_phy_reg(pi, 0x4b6, (0xffff << 0), gain0_15 << 0); + mod_phy_reg(pi, 0x4b7, (0xf << 0), gain16_19 << 0); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + mod_phy_reg(pi, 0x4b1, (0x3 << 11), lna1 << 11); + mod_phy_reg(pi, 0x4e6, (0x3 << 3), lna1 << 3); + } + wlc_lcnphy_rx_gain_override_enable(pi, true); +} + +static u32 wlc_lcnphy_get_receive_power(struct brcms_phy *pi, s32 *gain_index) +{ + u32 received_power = 0; + s32 max_index = 0; + u32 gain_code = 0; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + max_index = 36; + if (*gain_index >= 0) + gain_code = lcnphy_23bitgaincode_table[*gain_index]; + + if (-1 == *gain_index) { + *gain_index = 0; + while ((*gain_index <= (s32) max_index) + && (received_power < 700)) { + wlc_lcnphy_set_rx_gain(pi, + lcnphy_23bitgaincode_table + [*gain_index]); + received_power = + wlc_lcnphy_measure_digital_power( + pi, + pi_lcn-> + lcnphy_noise_samples); + (*gain_index)++; + } + (*gain_index)--; + } else { + wlc_lcnphy_set_rx_gain(pi, gain_code); + received_power = + wlc_lcnphy_measure_digital_power(pi, + pi_lcn-> + lcnphy_noise_samples); + } + + return received_power; +} + +s32 wlc_lcnphy_rx_signal_power(struct brcms_phy *pi, s32 gain_index) +{ + s32 gain = 0; + s32 nominal_power_db; + s32 log_val, gain_mismatch, desired_gain, input_power_offset_db, + input_power_db; + s32 received_power, temperature; + u32 power; + u32 msb1, msb2, val1, val2, diff1, diff2; + uint freq; + struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; + + received_power = wlc_lcnphy_get_receive_power(pi, &gain_index); + + gain = lcnphy_gain_table[gain_index]; + + nominal_power_db = read_phy_reg(pi, 0x425) >> 8; + + power = (received_power * 16); + msb1 = ffs(power) - 1; + msb2 = msb1 + 1; + val1 = 1 << msb1; + val2 = 1 << msb2; + diff1 = (power - val1); + diff2 = (val2 - power); + if (diff1 < diff2) + log_val = msb1; + else + log_val = msb2; + + log_val = log_val * 3; + + gain_mismatch = (nominal_power_db / 2) - (log_val); + + desired_gain = gain + gain_mismatch; + + input_power_offset_db = read_phy_reg(pi, 0x434) & 0xFF; + + if (input_power_offset_db > 127) + input_power_offset_db -= 256; + + input_power_db = input_power_offset_db - desired_gain; + + input_power_db = + input_power_db + lcnphy_gain_index_offset_for_rssi[gain_index]; + + freq = wlc_phy_channel2freq(CHSPEC_CHANNEL(pi->radio_chanspec)); + if ((freq > 2427) && (freq <= 2467)) + input_power_db = input_power_db - 1; + + temperature = pi_lcn->lcnphy_lastsensed_temperature; + + if ((temperature - 15) < -30) + input_power_db = + input_power_db + + (((temperature - 10 - 25) * 286) >> 12) - + 7; + else if ((temperature - 15) < 4) + input_power_db = + input_power_db + + (((temperature - 10 - 25) * 286) >> 12) - + 3; + else + input_power_db = input_power_db + + (((temperature - 10 - 25) * 286) >> 12); + + wlc_lcnphy_rx_gain_override_enable(pi, 0); + + return input_power_db; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h new file mode 100644 index 000000000000..f4a8ab09da43 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_PHY_LCN_H_ +#define _BRCM_PHY_LCN_H_ + +#include <types.h> + +struct brcms_phy_lcnphy { + int lcnphy_txrf_sp_9_override; + u8 lcnphy_full_cal_channel; + u8 lcnphy_cal_counter; + u16 lcnphy_cal_temper; + bool lcnphy_recal; + + u8 lcnphy_rc_cap; + u32 lcnphy_mcs20_po; + + u8 lcnphy_tr_isolation_mid; + u8 lcnphy_tr_isolation_low; + u8 lcnphy_tr_isolation_hi; + + u8 lcnphy_bx_arch; + u8 lcnphy_rx_power_offset; + u8 lcnphy_rssi_vf; + u8 lcnphy_rssi_vc; + u8 lcnphy_rssi_gs; + u8 lcnphy_tssi_val; + u8 lcnphy_rssi_vf_lowtemp; + u8 lcnphy_rssi_vc_lowtemp; + u8 lcnphy_rssi_gs_lowtemp; + + u8 lcnphy_rssi_vf_hightemp; + u8 lcnphy_rssi_vc_hightemp; + u8 lcnphy_rssi_gs_hightemp; + + s16 lcnphy_pa0b0; + s16 lcnphy_pa0b1; + s16 lcnphy_pa0b2; + + u16 lcnphy_rawtempsense; + u8 lcnphy_measPower; + u8 lcnphy_tempsense_slope; + u8 lcnphy_freqoffset_corr; + u8 lcnphy_tempsense_option; + u8 lcnphy_tempcorrx; + bool lcnphy_iqcal_swp_dis; + bool lcnphy_hw_iqcal_en; + uint lcnphy_bandedge_corr; + bool lcnphy_spurmod; + u16 lcnphy_tssi_tx_cnt; + u16 lcnphy_tssi_idx; + u16 lcnphy_tssi_npt; + + u16 lcnphy_target_tx_freq; + s8 lcnphy_tx_power_idx_override; + u16 lcnphy_noise_samples; + + u32 lcnphy_papdRxGnIdx; + u32 lcnphy_papd_rxGnCtrl_init; + + u32 lcnphy_gain_idx_14_lowword; + u32 lcnphy_gain_idx_14_hiword; + u32 lcnphy_gain_idx_27_lowword; + u32 lcnphy_gain_idx_27_hiword; + s16 lcnphy_ofdmgainidxtableoffset; + s16 lcnphy_dsssgainidxtableoffset; + u32 lcnphy_tr_R_gain_val; + u32 lcnphy_tr_T_gain_val; + s8 lcnphy_input_pwr_offset_db; + u16 lcnphy_Med_Low_Gain_db; + u16 lcnphy_Very_Low_Gain_db; + s8 lcnphy_lastsensed_temperature; + s8 lcnphy_pkteng_rssi_slope; + u8 lcnphy_saved_tx_user_target[TXP_NUM_RATES]; + u8 lcnphy_volt_winner; + u8 lcnphy_volt_low; + u8 lcnphy_54_48_36_24mbps_backoff; + u8 lcnphy_11n_backoff; + u8 lcnphy_lowerofdm; + u8 lcnphy_cck; + u8 lcnphy_psat_2pt3_detected; + s32 lcnphy_lowest_Re_div_Im; + s8 lcnphy_final_papd_cal_idx; + u16 lcnphy_extstxctrl4; + u16 lcnphy_extstxctrl0; + u16 lcnphy_extstxctrl1; + s16 lcnphy_cck_dig_filt_type; + s16 lcnphy_ofdm_dig_filt_type; + struct lcnphy_cal_results lcnphy_cal_results; + + u8 lcnphy_psat_pwr; + u8 lcnphy_psat_indx; + s32 lcnphy_min_phase; + u8 lcnphy_final_idx; + u8 lcnphy_start_idx; + u8 lcnphy_current_index; + u16 lcnphy_logen_buf_1; + u16 lcnphy_local_ovr_2; + u16 lcnphy_local_oval_6; + u16 lcnphy_local_oval_5; + u16 lcnphy_logen_mixer_1; + + u8 lcnphy_aci_stat; + uint lcnphy_aci_start_time; + s8 lcnphy_tx_power_offset[TXP_NUM_RATES]; +}; +#endif /* _BRCM_PHY_LCN_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c new file mode 100644 index 000000000000..cd19c2f7a347 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -0,0 +1,28876 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/kernel.h> +#include <linux/delay.h> +#include <linux/cordic.h> + +#include <brcm_hw_ids.h> +#include <aiutils.h> +#include <chipcommon.h> +#include <pmu.h> +#include <d11.h> +#include <phy_shim.h> +#include "phy_int.h" +#include "phy_hal.h" +#include "phy_radio.h" +#include "phyreg_n.h" +#include "phytbl_n.h" + +#define READ_RADIO_REG2(pi, radio_type, jspace, core, reg_name) \ + read_radio_reg(pi, radio_type##_##jspace##_##reg_name | \ + ((core == PHY_CORE_0) ? \ + radio_type##_##jspace##0 : \ + radio_type##_##jspace##1)) + +#define WRITE_RADIO_REG2(pi, radio_type, jspace, core, reg_name, value) \ + write_radio_reg(pi, radio_type##_##jspace##_##reg_name | \ + ((core == PHY_CORE_0) ? \ + radio_type##_##jspace##0 : \ + radio_type##_##jspace##1), value) + +#define WRITE_RADIO_SYN(pi, radio_type, reg_name, value) \ + write_radio_reg(pi, radio_type##_##SYN##_##reg_name, value) + +#define READ_RADIO_REG3(pi, radio_type, jspace, core, reg_name) \ + read_radio_reg(pi, ((core == PHY_CORE_0) ? \ + radio_type##_##jspace##0##_##reg_name : \ + radio_type##_##jspace##1##_##reg_name)) + +#define WRITE_RADIO_REG3(pi, radio_type, jspace, core, reg_name, value) \ + write_radio_reg(pi, ((core == PHY_CORE_0) ? \ + radio_type##_##jspace##0##_##reg_name : \ + radio_type##_##jspace##1##_##reg_name), \ + value) + +#define READ_RADIO_REG4(pi, radio_type, jspace, core, reg_name) \ + read_radio_reg(pi, ((core == PHY_CORE_0) ? \ + radio_type##_##reg_name##_##jspace##0 : \ + radio_type##_##reg_name##_##jspace##1)) + +#define WRITE_RADIO_REG4(pi, radio_type, jspace, core, reg_name, value) \ + write_radio_reg(pi, ((core == PHY_CORE_0) ? \ + radio_type##_##reg_name##_##jspace##0 : \ + radio_type##_##reg_name##_##jspace##1), \ + value) + +#define NPHY_ACI_MAX_UNDETECT_WINDOW_SZ 40 +#define NPHY_ACI_CHANNEL_DELTA 5 +#define NPHY_ACI_CHANNEL_SKIP 4 +#define NPHY_ACI_40MHZ_CHANNEL_DELTA 6 +#define NPHY_ACI_40MHZ_CHANNEL_SKIP 5 +#define NPHY_ACI_40MHZ_CHANNEL_DELTA_GE_REV3 6 +#define NPHY_ACI_40MHZ_CHANNEL_SKIP_GE_REV3 5 +#define NPHY_ACI_CHANNEL_DELTA_GE_REV3 4 +#define NPHY_ACI_CHANNEL_SKIP_GE_REV3 3 + +#define NPHY_NOISE_NOASSOC_GLITCH_TH_UP 2 + +#define NPHY_NOISE_NOASSOC_GLITCH_TH_DN 8 + +#define NPHY_NOISE_ASSOC_GLITCH_TH_UP 2 + +#define NPHY_NOISE_ASSOC_GLITCH_TH_DN 8 + +#define NPHY_NOISE_ASSOC_ACI_GLITCH_TH_UP 2 + +#define NPHY_NOISE_ASSOC_ACI_GLITCH_TH_DN 8 + +#define NPHY_NOISE_NOASSOC_ENTER_TH 400 + +#define NPHY_NOISE_ASSOC_ENTER_TH 400 + +#define NPHY_NOISE_ASSOC_RX_GLITCH_BADPLCP_ENTER_TH 400 + +#define NPHY_NOISE_CRSMINPWR_ARRAY_MAX_INDEX 44 +#define NPHY_NOISE_CRSMINPWR_ARRAY_MAX_INDEX_REV_7 56 + +#define NPHY_NOISE_NOASSOC_CRSIDX_INCR 16 + +#define NPHY_NOISE_ASSOC_CRSIDX_INCR 8 + +#define NPHY_IS_SROM_REINTERPRET NREV_GE(pi->pubpi.phy_rev, 5) + +#define NPHY_RSSICAL_MAXREAD 31 + +#define NPHY_RSSICAL_NPOLL 8 +#define NPHY_RSSICAL_MAXD (1<<20) +#define NPHY_MIN_RXIQ_PWR 2 + +#define NPHY_RSSICAL_W1_TARGET 25 +#define NPHY_RSSICAL_W2_TARGET NPHY_RSSICAL_W1_TARGET +#define NPHY_RSSICAL_NB_TARGET 0 + +#define NPHY_RSSICAL_W1_TARGET_REV3 29 +#define NPHY_RSSICAL_W2_TARGET_REV3 NPHY_RSSICAL_W1_TARGET_REV3 + +#define NPHY_CALSANITY_RSSI_NB_MAX_POS 9 +#define NPHY_CALSANITY_RSSI_NB_MAX_NEG -9 +#define NPHY_CALSANITY_RSSI_W1_MAX_POS 12 +#define NPHY_CALSANITY_RSSI_W1_MAX_NEG (NPHY_RSSICAL_W1_TARGET - \ + NPHY_RSSICAL_MAXREAD) +#define NPHY_CALSANITY_RSSI_W2_MAX_POS NPHY_CALSANITY_RSSI_W1_MAX_POS +#define NPHY_CALSANITY_RSSI_W2_MAX_NEG (NPHY_RSSICAL_W2_TARGET - \ + NPHY_RSSICAL_MAXREAD) +#define NPHY_RSSI_SXT(x) ((s8) (-((x) & 0x20) + ((x) & 0x1f))) +#define NPHY_RSSI_NB_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_NB_MAX_POS) || \ + ((x) < NPHY_CALSANITY_RSSI_NB_MAX_NEG)) +#define NPHY_RSSI_W1_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_W1_MAX_POS) || \ + ((x) < NPHY_CALSANITY_RSSI_W1_MAX_NEG)) +#define NPHY_RSSI_W2_VIOL(x) (((x) > NPHY_CALSANITY_RSSI_W2_MAX_POS) || \ + ((x) < NPHY_CALSANITY_RSSI_W2_MAX_NEG)) + +#define NPHY_IQCAL_NUMGAINS 9 +#define NPHY_N_GCTL 0x66 + +#define NPHY_PAPD_EPS_TBL_SIZE 64 +#define NPHY_PAPD_SCL_TBL_SIZE 64 +#define NPHY_NUM_DIG_FILT_COEFFS 15 + +#define NPHY_PAPD_COMP_OFF 0 +#define NPHY_PAPD_COMP_ON 1 + +#define NPHY_SROM_TEMPSHIFT 32 +#define NPHY_SROM_MAXTEMPOFFSET 16 +#define NPHY_SROM_MINTEMPOFFSET -16 + +#define NPHY_CAL_MAXTEMPDELTA 64 + +#define NPHY_NOISEVAR_TBLLEN40 256 +#define NPHY_NOISEVAR_TBLLEN20 128 + +#define NPHY_ANARXLPFBW_REDUCTIONFACT 7 + +#define NPHY_ADJUSTED_MINCRSPOWER 0x1e + +/* 5357 Chip specific ChipControl register bits */ +#define CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */ +#define CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */ + +#define NPHY_CAL_TSSISAMPS 64 +#define NPHY_TEST_TONE_FREQ_40MHz 4000 +#define NPHY_TEST_TONE_FREQ_20MHz 2500 + +#define MAX_205x_RCAL_WAITLOOPS 10000 + +#define NPHY_RXCAL_TONEAMP 181 +#define NPHY_RXCAL_TONEFREQ_40MHz 4000 +#define NPHY_RXCAL_TONEFREQ_20MHz 2000 + +#define TXFILT_SHAPING_OFDM20 0 +#define TXFILT_SHAPING_OFDM40 1 +#define TXFILT_SHAPING_CCK 2 +#define TXFILT_DEFAULT_OFDM20 3 +#define TXFILT_DEFAULT_OFDM40 4 + +struct nphy_iqcal_params { + u16 txlpf; + u16 txgm; + u16 pga; + u16 pad; + u16 ipa; + u16 cal_gain; + u16 ncorr[5]; +}; + +struct nphy_txiqcal_ladder { + u8 percent; + u8 g_env; +}; + +struct nphy_ipa_txcalgains { + struct nphy_txgains gains; + bool useindex; + u8 index; +}; + +struct nphy_papd_restore_state { + u16 fbmix[2]; + u16 vga_master[2]; + u16 intpa_master[2]; + u16 afectrl[2]; + u16 afeoverride[2]; + u16 pwrup[2]; + u16 atten[2]; + u16 mm; +}; + +struct nphy_ipa_txrxgain { + u16 hpvga; + u16 lpf_biq1; + u16 lpf_biq0; + u16 lna2; + u16 lna1; + s8 txpwrindex; +}; + +#define NPHY_IPA_RXCAL_MAXGAININDEX (6 - 1) + +static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz[] = { + {0, 0, 0, 0, 0, 100}, + {0, 0, 0, 0, 0, 50}, + {0, 0, 0, 0, 0, -1}, + {0, 0, 0, 3, 0, -1}, + {0, 0, 3, 3, 0, -1}, + {0, 2, 3, 3, 0, -1} +}; + +static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz[] = { + {0, 0, 0, 0, 0, 128}, + {0, 0, 0, 0, 0, 70}, + {0, 0, 0, 0, 0, 20}, + {0, 0, 0, 3, 0, 20}, + {0, 0, 3, 3, 0, 20}, + {0, 2, 3, 3, 0, 20} +}; + +static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_5GHz_rev7[] = { + {0, 0, 0, 0, 0, 100}, + {0, 0, 0, 0, 0, 50}, + {0, 0, 0, 0, 0, -1}, + {0, 0, 0, 3, 0, -1}, + {0, 0, 3, 3, 0, -1}, + {0, 0, 5, 3, 0, -1} +}; + +static const struct nphy_ipa_txrxgain nphy_ipa_rxcal_gaintbl_2GHz_rev7[] = { + {0, 0, 0, 0, 0, 10}, + {0, 0, 0, 1, 0, 10}, + {0, 0, 1, 2, 0, 10}, + {0, 0, 1, 3, 0, 10}, + {0, 0, 4, 3, 0, 10}, + {0, 0, 6, 3, 0, 10} +}; + +enum { + NPHY_RXCAL_GAIN_INIT = 0, + NPHY_RXCAL_GAIN_UP, + NPHY_RXCAL_GAIN_DOWN +}; + +#define wlc_phy_get_papd_nphy(pi) \ + (read_phy_reg((pi), 0x1e7) & \ + ((0x1 << 15) | \ + (0x1 << 14) | \ + (0x1 << 13))) + +static const u16 NPHY_IPA_REV4_txdigi_filtcoeffs[][NPHY_NUM_DIG_FILT_COEFFS] = { + {-377, 137, -407, 208, -1527, 956, 93, 186, 93, + 230, -44, 230, 201, -191, 201}, + {-77, 20, -98, 49, -93, 60, 56, 111, 56, 26, -5, + 26, 34, -32, 34}, + {-360, 164, -376, 164, -1533, 576, 308, -314, 308, + 121, -73, 121, 91, 124, 91}, + {-295, 200, -363, 142, -1391, 826, 151, 301, 151, + 151, 301, 151, 602, -752, 602}, + {-92, 58, -96, 49, -104, 44, 17, 35, 17, + 12, 25, 12, 13, 27, 13}, + {-375, 136, -399, 209, -1479, 949, 130, 260, 130, + 230, -44, 230, 201, -191, 201}, + {0xed9, 0xc8, 0xe95, 0x8e, 0xa91, 0x33a, 0x97, 0x12d, 0x97, + 0x97, 0x12d, 0x97, 0x25a, 0xd10, 0x25a} +}; + +struct chan_info_nphy_2055 { + u16 chan; + u16 freq; + uint unknown; + u8 RF_pll_ref; + u8 RF_rf_pll_mod1; + u8 RF_rf_pll_mod0; + u8 RF_vco_cap_tail; + u8 RF_vco_cal1; + u8 RF_vco_cal2; + u8 RF_pll_lf_c1; + u8 RF_pll_lf_r1; + u8 RF_pll_lf_c2; + u8 RF_lgbuf_cen_buf; + u8 RF_lgen_tune1; + u8 RF_lgen_tune2; + u8 RF_core1_lgbuf_a_tune; + u8 RF_core1_lgbuf_g_tune; + u8 RF_core1_rxrf_reg1; + u8 RF_core1_tx_pga_pad_tn; + u8 RF_core1_tx_mx_bgtrim; + u8 RF_core2_lgbuf_a_tune; + u8 RF_core2_lgbuf_g_tune; + u8 RF_core2_rxrf_reg1; + u8 RF_core2_tx_pga_pad_tn; + u8 RF_core2_tx_mx_bgtrim; + u16 PHY_BW1a; + u16 PHY_BW2; + u16 PHY_BW3; + u16 PHY_BW4; + u16 PHY_BW5; + u16 PHY_BW6; +}; + +struct chan_info_nphy_radio205x { + u16 chan; + u16 freq; + u8 RF_SYN_pll_vcocal1; + u8 RF_SYN_pll_vcocal2; + u8 RF_SYN_pll_refdiv; + u8 RF_SYN_pll_mmd2; + u8 RF_SYN_pll_mmd1; + u8 RF_SYN_pll_loopfilter1; + u8 RF_SYN_pll_loopfilter2; + u8 RF_SYN_pll_loopfilter3; + u8 RF_SYN_pll_loopfilter4; + u8 RF_SYN_pll_loopfilter5; + u8 RF_SYN_reserved_addr27; + u8 RF_SYN_reserved_addr28; + u8 RF_SYN_reserved_addr29; + u8 RF_SYN_logen_VCOBUF1; + u8 RF_SYN_logen_MIXER2; + u8 RF_SYN_logen_BUF3; + u8 RF_SYN_logen_BUF4; + u8 RF_RX0_lnaa_tune; + u8 RF_RX0_lnag_tune; + u8 RF_TX0_intpaa_boost_tune; + u8 RF_TX0_intpag_boost_tune; + u8 RF_TX0_pada_boost_tune; + u8 RF_TX0_padg_boost_tune; + u8 RF_TX0_pgaa_boost_tune; + u8 RF_TX0_pgag_boost_tune; + u8 RF_TX0_mixa_boost_tune; + u8 RF_TX0_mixg_boost_tune; + u8 RF_RX1_lnaa_tune; + u8 RF_RX1_lnag_tune; + u8 RF_TX1_intpaa_boost_tune; + u8 RF_TX1_intpag_boost_tune; + u8 RF_TX1_pada_boost_tune; + u8 RF_TX1_padg_boost_tune; + u8 RF_TX1_pgaa_boost_tune; + u8 RF_TX1_pgag_boost_tune; + u8 RF_TX1_mixa_boost_tune; + u8 RF_TX1_mixg_boost_tune; + u16 PHY_BW1a; + u16 PHY_BW2; + u16 PHY_BW3; + u16 PHY_BW4; + u16 PHY_BW5; + u16 PHY_BW6; +}; + +struct chan_info_nphy_radio2057 { + u16 chan; + u16 freq; + u8 RF_vcocal_countval0; + u8 RF_vcocal_countval1; + u8 RF_rfpll_refmaster_sparextalsize; + u8 RF_rfpll_loopfilter_r1; + u8 RF_rfpll_loopfilter_c2; + u8 RF_rfpll_loopfilter_c1; + u8 RF_cp_kpd_idac; + u8 RF_rfpll_mmd0; + u8 RF_rfpll_mmd1; + u8 RF_vcobuf_tune; + u8 RF_logen_mx2g_tune; + u8 RF_logen_mx5g_tune; + u8 RF_logen_indbuf2g_tune; + u8 RF_logen_indbuf5g_tune; + u8 RF_txmix2g_tune_boost_pu_core0; + u8 RF_pad2g_tune_pus_core0; + u8 RF_pga_boost_tune_core0; + u8 RF_txmix5g_boost_tune_core0; + u8 RF_pad5g_tune_misc_pus_core0; + u8 RF_lna2g_tune_core0; + u8 RF_lna5g_tune_core0; + u8 RF_txmix2g_tune_boost_pu_core1; + u8 RF_pad2g_tune_pus_core1; + u8 RF_pga_boost_tune_core1; + u8 RF_txmix5g_boost_tune_core1; + u8 RF_pad5g_tune_misc_pus_core1; + u8 RF_lna2g_tune_core1; + u8 RF_lna5g_tune_core1; + u16 PHY_BW1a; + u16 PHY_BW2; + u16 PHY_BW3; + u16 PHY_BW4; + u16 PHY_BW5; + u16 PHY_BW6; +}; + +struct chan_info_nphy_radio2057_rev5 { + u16 chan; + u16 freq; + u8 RF_vcocal_countval0; + u8 RF_vcocal_countval1; + u8 RF_rfpll_refmaster_sparextalsize; + u8 RF_rfpll_loopfilter_r1; + u8 RF_rfpll_loopfilter_c2; + u8 RF_rfpll_loopfilter_c1; + u8 RF_cp_kpd_idac; + u8 RF_rfpll_mmd0; + u8 RF_rfpll_mmd1; + u8 RF_vcobuf_tune; + u8 RF_logen_mx2g_tune; + u8 RF_logen_indbuf2g_tune; + u8 RF_txmix2g_tune_boost_pu_core0; + u8 RF_pad2g_tune_pus_core0; + u8 RF_lna2g_tune_core0; + u8 RF_txmix2g_tune_boost_pu_core1; + u8 RF_pad2g_tune_pus_core1; + u8 RF_lna2g_tune_core1; + u16 PHY_BW1a; + u16 PHY_BW2; + u16 PHY_BW3; + u16 PHY_BW4; + u16 PHY_BW5; + u16 PHY_BW6; +}; + +struct nphy_sfo_cfg { + u16 PHY_BW1a; + u16 PHY_BW2; + u16 PHY_BW3; + u16 PHY_BW4; + u16 PHY_BW5; + u16 PHY_BW6; +}; + +static const struct chan_info_nphy_2055 chan_info_nphy_2055[] = { + { + 184, 4920, 3280, 0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7B4, 0x7B0, 0x7AC, 0x214, 0x215, 0x216}, + { + 186, 4930, 3287, 0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7B8, 0x7B4, 0x7B0, 0x213, 0x214, 0x215}, + { + 188, 4940, 3293, 0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7BC, 0x7B8, 0x7B4, 0x212, 0x213, 0x214}, + { + 190, 4950, 3300, 0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7C0, 0x7BC, 0x7B8, 0x211, 0x212, 0x213}, + { + 192, 4960, 3307, 0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7C4, 0x7C0, 0x7BC, 0x20F, 0x211, 0x212}, + { + 194, 4970, 3313, 0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7C8, 0x7C4, 0x7C0, 0x20E, 0x20F, 0x211}, + { + 196, 4980, 3320, 0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7CC, 0x7C8, 0x7C4, 0x20D, 0x20E, 0x20F}, + { + 198, 4990, 3327, 0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7D0, 0x7CC, 0x7C8, 0x20C, 0x20D, 0x20E}, + { + 200, 5000, 3333, 0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7D4, 0x7D0, 0x7CC, 0x20B, 0x20C, 0x20D}, + { + 202, 5010, 3340, 0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7D8, 0x7D4, 0x7D0, 0x20A, 0x20B, 0x20C}, + { + 204, 5020, 3347, 0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7DC, 0x7D8, 0x7D4, 0x209, 0x20A, 0x20B}, + { + 206, 5030, 3353, 0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7E0, 0x7DC, 0x7D8, 0x208, 0x209, 0x20A}, + { + 208, 5040, 3360, 0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7E4, 0x7E0, 0x7DC, 0x207, 0x208, 0x209}, + { + 210, 5050, 3367, 0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F, 0x8F, 0xFF, 0x00, 0x0F, + 0x0F, 0x8F, 0x7E8, 0x7E4, 0x7E0, 0x206, 0x207, 0x208}, + { + 212, 5060, 3373, 0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, 0x8E, 0xFF, 0x00, 0x0E, + 0x0F, 0x8E, 0x7EC, 0x7E8, 0x7E4, 0x205, 0x206, 0x207}, + { + 214, 5070, 3380, 0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A, + 0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F, 0x8E, 0xFF, 0x00, 0x0E, + 0x0F, 0x8E, 0x7F0, 0x7EC, 0x7E8, 0x204, 0x205, 0x206}, + { + 216, 5080, 3387, 0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, 0x8D, 0xEE, 0x00, 0x0E, + 0x0F, 0x8D, 0x7F4, 0x7F0, 0x7EC, 0x203, 0x204, 0x205}, + { + 218, 5090, 3393, 0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F, 0x8D, 0xEE, 0x00, 0x0E, + 0x0F, 0x8D, 0x7F8, 0x7F4, 0x7F0, 0x202, 0x203, 0x204}, + { + 220, 5100, 3400, 0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, 0x8D, 0xEE, 0x00, 0x0D, + 0x0F, 0x8D, 0x7FC, 0x7F8, 0x7F4, 0x201, 0x202, 0x203}, + { + 222, 5110, 3407, 0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A, + 0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F, 0x8D, 0xEE, 0x00, 0x0D, + 0x0F, 0x8D, 0x800, 0x7FC, 0x7F8, 0x200, 0x201, 0x202}, + { + 224, 5120, 3413, 0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, 0x8C, 0xDD, 0x00, 0x0D, + 0x0F, 0x8C, 0x804, 0x800, 0x7FC, 0x1FF, 0x200, 0x201}, + { + 226, 5130, 3420, 0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F, 0x8C, 0xDD, 0x00, 0x0D, + 0x0F, 0x8C, 0x808, 0x804, 0x800, 0x1FE, 0x1FF, 0x200}, + { + 228, 5140, 3427, 0x71, 0x02, 0x02, 0x0C, 0xC6, 0x01, 0x04, 0x0A, + 0x00, 0x8D, 0x99, 0x99, 0xDD, 0x00, 0x0C, 0x0E, 0x8B, 0xDD, 0x00, 0x0C, + 0x0E, 0x8B, 0x80C, 0x808, 0x804, 0x1FD, 0x1FE, 0x1FF}, + { + 32, 5160, 3440, 0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, 0x8A, 0xCC, 0x00, 0x0B, + 0x0D, 0x8A, 0x814, 0x810, 0x80C, 0x1FB, 0x1FC, 0x1FD}, + { + 34, 5170, 3447, 0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D, 0x8A, 0xCC, 0x00, 0x0B, + 0x0D, 0x8A, 0x818, 0x814, 0x810, 0x1FA, 0x1FB, 0x1FC}, + { + 36, 5180, 3453, 0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, 0x89, 0xCC, 0x00, 0x0B, + 0x0C, 0x89, 0x81C, 0x818, 0x814, 0x1F9, 0x1FA, 0x1FB}, + { + 38, 5190, 3460, 0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A, + 0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C, 0x89, 0xCC, 0x00, 0x0B, + 0x0C, 0x89, 0x820, 0x81C, 0x818, 0x1F8, 0x1F9, 0x1FA}, + { + 40, 5200, 3467, 0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, 0x89, 0xBB, 0x00, 0x0A, + 0x0B, 0x89, 0x824, 0x820, 0x81C, 0x1F7, 0x1F8, 0x1F9}, + { + 42, 5210, 3473, 0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B, 0x89, 0xBB, 0x00, 0x0A, + 0x0B, 0x89, 0x828, 0x824, 0x820, 0x1F6, 0x1F7, 0x1F8}, + { + 44, 5220, 3480, 0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, 0x88, 0xBB, 0x00, 0x09, + 0x0A, 0x88, 0x82C, 0x828, 0x824, 0x1F5, 0x1F6, 0x1F7}, + { + 46, 5230, 3487, 0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A, + 0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A, 0x88, 0xBB, 0x00, 0x09, + 0x0A, 0x88, 0x830, 0x82C, 0x828, 0x1F4, 0x1F5, 0x1F6}, + { + 48, 5240, 3493, 0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, 0x87, 0xAA, 0x00, 0x09, + 0x0A, 0x87, 0x834, 0x830, 0x82C, 0x1F3, 0x1F4, 0x1F5}, + { + 50, 5250, 3500, 0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A, 0x87, 0xAA, 0x00, 0x09, + 0x0A, 0x87, 0x838, 0x834, 0x830, 0x1F2, 0x1F3, 0x1F4}, + { + 52, 5260, 3507, 0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, 0x87, 0xAA, 0x00, 0x08, + 0x09, 0x87, 0x83C, 0x838, 0x834, 0x1F1, 0x1F2, 0x1F3}, + { + 54, 5270, 3513, 0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A, + 0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09, 0x87, 0xAA, 0x00, 0x08, + 0x09, 0x87, 0x840, 0x83C, 0x838, 0x1F0, 0x1F1, 0x1F2}, + { + 56, 5280, 3520, 0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, 0x86, 0x99, 0x00, 0x08, + 0x08, 0x86, 0x844, 0x840, 0x83C, 0x1F0, 0x1F0, 0x1F1}, + { + 58, 5290, 3527, 0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08, 0x86, 0x99, 0x00, 0x08, + 0x08, 0x86, 0x848, 0x844, 0x840, 0x1EF, 0x1F0, 0x1F0}, + { + 60, 5300, 3533, 0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, 0x85, 0x99, 0x00, 0x08, + 0x07, 0x85, 0x84C, 0x848, 0x844, 0x1EE, 0x1EF, 0x1F0}, + { + 62, 5310, 3540, 0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A, + 0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07, 0x85, 0x99, 0x00, 0x08, + 0x07, 0x85, 0x850, 0x84C, 0x848, 0x1ED, 0x1EE, 0x1EF}, + { + 64, 5320, 3547, 0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, 0x84, 0x88, 0x00, 0x07, + 0x07, 0x84, 0x854, 0x850, 0x84C, 0x1EC, 0x1ED, 0x1EE}, + { + 66, 5330, 3553, 0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07, 0x84, 0x88, 0x00, 0x07, + 0x07, 0x84, 0x858, 0x854, 0x850, 0x1EB, 0x1EC, 0x1ED}, + { + 68, 5340, 3560, 0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, 0x84, 0x88, 0x00, 0x07, + 0x06, 0x84, 0x85C, 0x858, 0x854, 0x1EA, 0x1EB, 0x1EC}, + { + 70, 5350, 3567, 0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A, + 0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06, 0x84, 0x88, 0x00, 0x07, + 0x06, 0x84, 0x860, 0x85C, 0x858, 0x1E9, 0x1EA, 0x1EB}, + { + 72, 5360, 3573, 0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, 0x83, 0x77, 0x00, 0x06, + 0x05, 0x83, 0x864, 0x860, 0x85C, 0x1E8, 0x1E9, 0x1EA}, + { + 74, 5370, 3580, 0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05, 0x83, 0x77, 0x00, 0x06, + 0x05, 0x83, 0x868, 0x864, 0x860, 0x1E7, 0x1E8, 0x1E9}, + { + 76, 5380, 3587, 0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, 0x82, 0x77, 0x00, 0x06, + 0x04, 0x82, 0x86C, 0x868, 0x864, 0x1E6, 0x1E7, 0x1E8}, + { + 78, 5390, 3593, 0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A, + 0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04, 0x82, 0x77, 0x00, 0x06, + 0x04, 0x82, 0x870, 0x86C, 0x868, 0x1E5, 0x1E6, 0x1E7}, + { + 80, 5400, 3600, 0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, 0x81, 0x66, 0x00, 0x05, + 0x04, 0x81, 0x874, 0x870, 0x86C, 0x1E5, 0x1E5, 0x1E6}, + { + 82, 5410, 3607, 0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04, 0x81, 0x66, 0x00, 0x05, + 0x04, 0x81, 0x878, 0x874, 0x870, 0x1E4, 0x1E5, 0x1E5}, + { + 84, 5420, 3613, 0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, 0x80, 0x66, 0x00, 0x05, + 0x03, 0x80, 0x87C, 0x878, 0x874, 0x1E3, 0x1E4, 0x1E5}, + { + 86, 5430, 3620, 0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A, + 0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03, 0x80, 0x66, 0x00, 0x05, + 0x03, 0x80, 0x880, 0x87C, 0x878, 0x1E2, 0x1E3, 0x1E4}, + { + 88, 5440, 3627, 0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, 0x80, 0x55, 0x00, 0x04, + 0x02, 0x80, 0x884, 0x880, 0x87C, 0x1E1, 0x1E2, 0x1E3}, + { + 90, 5450, 3633, 0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02, 0x80, 0x55, 0x00, 0x04, + 0x02, 0x80, 0x888, 0x884, 0x880, 0x1E0, 0x1E1, 0x1E2}, + { + 92, 5460, 3640, 0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, 0x80, 0x55, 0x00, 0x04, + 0x01, 0x80, 0x88C, 0x888, 0x884, 0x1DF, 0x1E0, 0x1E1}, + { + 94, 5470, 3647, 0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A, + 0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01, 0x80, 0x55, 0x00, 0x04, + 0x01, 0x80, 0x890, 0x88C, 0x888, 0x1DE, 0x1DF, 0x1E0}, + { + 96, 5480, 3653, 0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03, + 0x00, 0x80, 0x894, 0x890, 0x88C, 0x1DD, 0x1DE, 0x1DF}, + { + 98, 5490, 3660, 0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03, + 0x00, 0x80, 0x898, 0x894, 0x890, 0x1DD, 0x1DD, 0x1DE}, + { + 100, 5500, 3667, 0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03, + 0x00, 0x80, 0x89C, 0x898, 0x894, 0x1DC, 0x1DD, 0x1DD}, + { + 102, 5510, 3673, 0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00, 0x80, 0x44, 0x00, 0x03, + 0x00, 0x80, 0x8A0, 0x89C, 0x898, 0x1DB, 0x1DC, 0x1DD}, + { + 104, 5520, 3680, 0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02, + 0x00, 0x80, 0x8A4, 0x8A0, 0x89C, 0x1DA, 0x1DB, 0x1DC}, + { + 106, 5530, 3687, 0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02, + 0x00, 0x80, 0x8A8, 0x8A4, 0x8A0, 0x1D9, 0x1DA, 0x1DB}, + { + 108, 5540, 3693, 0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02, + 0x00, 0x80, 0x8AC, 0x8A8, 0x8A4, 0x1D8, 0x1D9, 0x1DA}, + { + 110, 5550, 3700, 0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A, + 0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, 0x80, 0x33, 0x00, 0x02, + 0x00, 0x80, 0x8B0, 0x8AC, 0x8A8, 0x1D7, 0x1D8, 0x1D9}, + { + 112, 5560, 3707, 0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01, + 0x00, 0x80, 0x8B4, 0x8B0, 0x8AC, 0x1D7, 0x1D7, 0x1D8}, + { + 114, 5570, 3713, 0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01, + 0x00, 0x80, 0x8B8, 0x8B4, 0x8B0, 0x1D6, 0x1D7, 0x1D7}, + { + 116, 5580, 3720, 0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01, + 0x00, 0x80, 0x8BC, 0x8B8, 0x8B4, 0x1D5, 0x1D6, 0x1D7}, + { + 118, 5590, 3727, 0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A, + 0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00, 0x80, 0x22, 0x00, 0x01, + 0x00, 0x80, 0x8C0, 0x8BC, 0x8B8, 0x1D4, 0x1D5, 0x1D6}, + { + 120, 5600, 3733, 0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x80, 0x11, 0x00, 0x01, + 0x00, 0x80, 0x8C4, 0x8C0, 0x8BC, 0x1D3, 0x1D4, 0x1D5}, + { + 122, 5610, 3740, 0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, 0x80, 0x11, 0x00, 0x01, + 0x00, 0x80, 0x8C8, 0x8C4, 0x8C0, 0x1D2, 0x1D3, 0x1D4}, + { + 124, 5620, 3747, 0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, + 0x00, 0x80, 0x8CC, 0x8C8, 0x8C4, 0x1D2, 0x1D2, 0x1D3}, + { + 126, 5630, 3753, 0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A, + 0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, + 0x00, 0x80, 0x8D0, 0x8CC, 0x8C8, 0x1D1, 0x1D2, 0x1D2}, + { + 128, 5640, 3760, 0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8D4, 0x8D0, 0x8CC, 0x1D0, 0x1D1, 0x1D2}, + { + 130, 5650, 3767, 0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8D8, 0x8D4, 0x8D0, 0x1CF, 0x1D0, 0x1D1}, + { + 132, 5660, 3773, 0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8DC, 0x8D8, 0x8D4, 0x1CE, 0x1CF, 0x1D0}, + { + 134, 5670, 3780, 0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8E0, 0x8DC, 0x8D8, 0x1CE, 0x1CE, 0x1CF}, + { + 136, 5680, 3787, 0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8E4, 0x8E0, 0x8DC, 0x1CD, 0x1CE, 0x1CE}, + { + 138, 5690, 3793, 0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8E8, 0x8E4, 0x8E0, 0x1CC, 0x1CD, 0x1CE}, + { + 140, 5700, 3800, 0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8EC, 0x8E8, 0x8E4, 0x1CB, 0x1CC, 0x1CD}, + { + 142, 5710, 3807, 0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8F0, 0x8EC, 0x8E8, 0x1CA, 0x1CB, 0x1CC}, + { + 144, 5720, 3813, 0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8F4, 0x8F0, 0x8EC, 0x1C9, 0x1CA, 0x1CB}, + { + 145, 5725, 3817, 0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8F6, 0x8F2, 0x8EE, 0x1C9, 0x1CA, 0x1CB}, + { + 146, 5730, 3820, 0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8F8, 0x8F4, 0x8F0, 0x1C9, 0x1C9, 0x1CA}, + { + 147, 5735, 3823, 0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8FA, 0x8F6, 0x8F2, 0x1C8, 0x1C9, 0x1CA}, + { + 148, 5740, 3827, 0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8FC, 0x8F8, 0x8F4, 0x1C8, 0x1C9, 0x1C9}, + { + 149, 5745, 3830, 0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x8FE, 0x8FA, 0x8F6, 0x1C8, 0x1C8, 0x1C9}, + { + 150, 5750, 3833, 0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x900, 0x8FC, 0x8F8, 0x1C7, 0x1C8, 0x1C9}, + { + 151, 5755, 3837, 0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x902, 0x8FE, 0x8FA, 0x1C7, 0x1C8, 0x1C8}, + { + 152, 5760, 3840, 0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x904, 0x900, 0x8FC, 0x1C6, 0x1C7, 0x1C8}, + { + 153, 5765, 3843, 0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x906, 0x902, 0x8FE, 0x1C6, 0x1C7, 0x1C8}, + { + 154, 5770, 3847, 0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x908, 0x904, 0x900, 0x1C6, 0x1C6, 0x1C7}, + { + 155, 5775, 3850, 0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x90A, 0x906, 0x902, 0x1C5, 0x1C6, 0x1C7}, + { + 156, 5780, 3853, 0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x90C, 0x908, 0x904, 0x1C5, 0x1C6, 0x1C6}, + { + 157, 5785, 3857, 0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x90E, 0x90A, 0x906, 0x1C4, 0x1C5, 0x1C6}, + { + 158, 5790, 3860, 0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x910, 0x90C, 0x908, 0x1C4, 0x1C5, 0x1C6}, + { + 159, 5795, 3863, 0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x912, 0x90E, 0x90A, 0x1C4, 0x1C4, 0x1C5}, + { + 160, 5800, 3867, 0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x914, 0x910, 0x90C, 0x1C3, 0x1C4, 0x1C5}, + { + 161, 5805, 3870, 0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x916, 0x912, 0x90E, 0x1C3, 0x1C4, 0x1C4}, + { + 162, 5810, 3873, 0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x918, 0x914, 0x910, 0x1C2, 0x1C3, 0x1C4}, + { + 163, 5815, 3877, 0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x91A, 0x916, 0x912, 0x1C2, 0x1C3, 0x1C4}, + { + 164, 5820, 3880, 0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x91C, 0x918, 0x914, 0x1C2, 0x1C2, 0x1C3}, + { + 165, 5825, 3883, 0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x91E, 0x91A, 0x916, 0x1C1, 0x1C2, 0x1C3}, + { + 166, 5830, 3887, 0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x920, 0x91C, 0x918, 0x1C1, 0x1C2, 0x1C2}, + { + 168, 5840, 3893, 0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x924, 0x920, 0x91C, 0x1C0, 0x1C1, 0x1C2}, + { + 170, 5850, 3900, 0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x928, 0x924, 0x920, 0x1BF, 0x1C0, 0x1C1}, + { + 172, 5860, 3907, 0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x92C, 0x928, 0x924, 0x1BF, 0x1BF, 0x1C0}, + { + 174, 5870, 3913, 0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x930, 0x92C, 0x928, 0x1BE, 0x1BF, 0x1BF}, + { + 176, 5880, 3920, 0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x934, 0x930, 0x92C, 0x1BD, 0x1BE, 0x1BF}, + { + 178, 5890, 3927, 0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x938, 0x934, 0x930, 0x1BC, 0x1BD, 0x1BE}, + { + 180, 5900, 3933, 0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x93C, 0x938, 0x934, 0x1BC, 0x1BC, 0x1BD}, + { + 182, 5910, 3940, 0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x940, 0x93C, 0x938, 0x1BB, 0x1BC, 0x1BC}, + { + 1, 2412, 3216, 0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C, 0x80, 0xFF, 0x88, 0x0D, + 0x0C, 0x80, 0x3C9, 0x3C5, 0x3C1, 0x43A, 0x43F, 0x443}, + { + 2, 2417, 3223, 0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B, 0x80, 0xFF, 0x88, 0x0C, + 0x0B, 0x80, 0x3CB, 0x3C7, 0x3C3, 0x438, 0x43D, 0x441}, + { + 3, 2422, 3229, 0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, 0x80, 0xFF, 0x88, 0x0C, + 0x0A, 0x80, 0x3CD, 0x3C9, 0x3C5, 0x436, 0x43A, 0x43F}, + { + 4, 2427, 3236, 0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A, 0x80, 0xFF, 0x88, 0x0C, + 0x0A, 0x80, 0x3CF, 0x3CB, 0x3C7, 0x434, 0x438, 0x43D}, + { + 5, 2432, 3243, 0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09, 0x80, 0xFF, 0x88, 0x0C, + 0x09, 0x80, 0x3D1, 0x3CD, 0x3C9, 0x431, 0x436, 0x43A}, + { + 6, 2437, 3249, 0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08, 0x80, 0xFF, 0x88, 0x0B, + 0x08, 0x80, 0x3D3, 0x3CF, 0x3CB, 0x42F, 0x434, 0x438}, + { + 7, 2442, 3256, 0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07, 0x80, 0xFF, 0x88, 0x0A, + 0x07, 0x80, 0x3D5, 0x3D1, 0x3CD, 0x42D, 0x431, 0x436}, + { + 8, 2447, 3263, 0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06, 0x80, 0xFF, 0x88, 0x0A, + 0x06, 0x80, 0x3D7, 0x3D3, 0x3CF, 0x42B, 0x42F, 0x434}, + { + 9, 2452, 3269, 0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06, 0x80, 0xFF, 0x88, 0x09, + 0x06, 0x80, 0x3D9, 0x3D5, 0x3D1, 0x429, 0x42D, 0x431}, + { + 10, 2457, 3276, 0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05, 0x80, 0xFF, 0x88, 0x08, + 0x05, 0x80, 0x3DB, 0x3D7, 0x3D3, 0x427, 0x42B, 0x42F}, + { + 11, 2462, 3283, 0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04, 0x80, 0xFF, 0x88, 0x08, + 0x04, 0x80, 0x3DD, 0x3D9, 0x3D5, 0x424, 0x429, 0x42D}, + { + 12, 2467, 3289, 0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03, 0x80, 0xFF, 0x88, 0x08, + 0x03, 0x80, 0x3DF, 0x3DB, 0x3D7, 0x422, 0x427, 0x42B}, + { + 13, 2472, 3296, 0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03, 0x80, 0xFF, 0x88, 0x07, + 0x03, 0x80, 0x3E1, 0x3DD, 0x3D9, 0x420, 0x424, 0x429}, + { + 14, 2484, 3312, 0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15, + 0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01, 0x80, 0xFF, 0x88, 0x07, + 0x01, 0x80, 0x3E6, 0x3E2, 0x3DE, 0x41B, 0x41F, 0x424} +}; + +static const struct chan_info_nphy_radio205x chan_info_nphyrev3_2056[] = { + { + 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, + { + 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, + { + 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, + { + 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, + { + 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, + { + 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, + { + 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, + { + 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, + { + 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, + { + 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, + { + 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, + { + 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, + { + 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, + { + 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, + { + 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, + { + 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, + { + 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, + { + 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, + { + 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xff, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xff, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, + { + 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, + { + 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, + { + 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, + { + 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, + { + 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, + { + 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xff, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, + { + 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, + { + 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xfc, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, + { + 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, + { + 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, + { + 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, + { + 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, + { + 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, + { + 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, + { + 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, + { + 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, + { + 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, + { + 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xfc, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, + { + 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfc, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, + { + 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, + { + 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, + { + 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, + { + 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, + { + 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, + { + 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, + { + 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, + { + 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, + { + 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x8f, 0x00, 0x05, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xfa, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, + { + 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, + { + 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, + { + 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, + { + 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00, 0x8e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, + { + 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7e, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00, 0x7e, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, + { + 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7d, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xfa, 0x00, 0x7d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xfa, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, + { + 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xf8, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, + { + 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xf8, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, + { + 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5d, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xf8, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, + { + 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5c, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x08, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x08, + 0x00, 0xf8, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, + { + 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x5c, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, + { + 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, + { + 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x4c, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, + { + 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, + { + 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, + { + 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x3b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, + { + 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2b, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x2b, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, + { + 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2a, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x2a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, + { + 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, + { + 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, + { + 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x1a, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x1a, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, + { + 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, + { + 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x19, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, + { + 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, + { + 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x09, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, + { + 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf8, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf8, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, + { + 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf6, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, + { + 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf6, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, + { + 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf6, 0x00, 0x08, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf6, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, + { + 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x07, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf6, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf6, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, + { + 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf6, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf6, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, + { + 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, + { + 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, + { + 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, + { + 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, + { + 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, + { + 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, + { + 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, + { + 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x06, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, + { + 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, + { + 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, + { + 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, + { + 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, + { + 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, + { + 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, + { + 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, + { + 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, + { + 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, + { + 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, + { + 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, + { + 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, + { + 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, + { + 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, + { + 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, + { + 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, + { + 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, + { + 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf4, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf4, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, + { + 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf2, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf2, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, + { + 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf2, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, + { + 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf2, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, + { + 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x06, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x06, + 0x00, 0xf2, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, + { + 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x05, 0x00, 0xf2, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05, + 0x00, 0xf2, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, + { + 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x05, 0x00, 0xf2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x05, + 0x00, 0xf2, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, + { + 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xff, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfd, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfb, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf7, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0xf6, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0f, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf5, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf4, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf3, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x05, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0d, 0x00, 0xf0, 0x00, 0x05, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0d, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio205x chan_info_nphyrev4_2056_A1[] = { + { + 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, + { + 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, + { + 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, + { + 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, + { + 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, + { + 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, + { + 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, + { + 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0e, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0e, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, + { + 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, + { + 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, + { + 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, + { + 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, + { + 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, + { + 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, + { + 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, + { + 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, + { + 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, + { + 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0d, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xff, 0x00, 0x0d, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xff, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, + { + 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, + { + 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, + { + 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, + { + 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, + { + 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, + { + 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, + { + 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xff, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, + { + 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, + { + 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0c, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfe, 0x00, 0xef, 0x00, 0x0c, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfe, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, + { + 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xef, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xef, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, + { + 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, + { + 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, + { + 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xdf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xdf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, + { + 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, + { + 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, + { + 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, + { + 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xcf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xcf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, + { + 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, + { + 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xbf, 0x00, 0x0a, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfc, 0x00, 0xbf, 0x00, 0x0a, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfc, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, + { + 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, + { + 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, + { + 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xbf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xbf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, + { + 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, + { + 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xaf, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0xaf, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, + { + 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, + { + 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, + { + 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, + { + 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x9f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x9f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, + { + 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x8f, 0x00, 0x08, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xfa, 0x00, 0x8f, 0x00, 0x08, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xfa, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, + { + 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, + { + 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8f, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8f, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, + { + 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, + { + 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x8e, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x8e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, + { + 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7e, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x7e, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, + { + 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x7d, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x7d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, + { + 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, + { + 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x6d, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x6d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, + { + 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5d, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x5d, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, + { + 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x5c, 0x00, 0x07, 0x00, 0x7f, + 0x00, 0x0f, 0x00, 0xf8, 0x00, 0x5c, 0x00, 0x07, 0x00, 0x7f, 0x00, 0x0f, + 0x00, 0xf8, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, + { + 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x5c, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x5c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, + { + 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, + { + 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x4c, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x4c, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, + { + 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, + { + 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, + { + 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x3b, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x3b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, + { + 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2b, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x2b, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, + { + 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x2a, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x2a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, + { + 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, + { + 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x1a, 0x00, 0x06, 0x00, 0x7f, + 0x00, 0x0d, 0x00, 0xf6, 0x00, 0x1a, 0x00, 0x06, 0x00, 0x7f, 0x00, 0x0d, + 0x00, 0xf6, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, + { + 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x1a, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, + { + 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, + { + 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x19, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x19, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, + { + 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, + { + 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x09, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x09, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, + { + 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, + { + 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, + { + 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, + { + 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x08, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x08, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, + { + 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x07, 0x00, 0x04, 0x00, 0x7f, + 0x00, 0x0b, 0x00, 0xf4, 0x00, 0x07, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x0b, + 0x00, 0xf4, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, + { + 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, + { + 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, + { + 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x07, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x07, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, + { + 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, + { + 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, + { + 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, + { + 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, + { + 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, + { + 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x06, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x06, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, + { + 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, + { + 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, + { + 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, + { + 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, + { + 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, + { + 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x05, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, + { + 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, + { + 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, + { + 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x04, 0x00, 0x03, 0x00, 0x7f, + 0x00, 0x0a, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x0a, + 0x00, 0xf2, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, + { + 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, + { + 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, + { + 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, + { + 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x04, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, + { + 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, + { + 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, + { + 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, + { + 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, + { + 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, + { + 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x03, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x03, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, + { + 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, + { + 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, + { + 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x02, 0x00, 0x02, 0x00, 0x7f, + 0x00, 0x09, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x09, + 0x00, 0xf0, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, + { + 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf0, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, + { + 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x07, 0x00, 0xf0, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x07, + 0x00, 0xf0, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, + { + 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xff, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xff, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfd, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfb, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf8, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf7, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf5, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf4, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf3, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf2, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x04, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0xf0, 0x00, 0x04, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0e, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio205x chan_info_nphyrev5_2056v5[] = { + { + 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0f, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, + { + 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, + { + 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, + { + 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, + { + 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, + { + 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, + { + 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, + { + 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, + { + 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, + { + 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, + { + 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, + { + 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, + { + 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, + { + 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, + { + 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, + { + 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, + { + 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, + { + 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, + { + 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, + { + 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, + { + 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, + { + 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, + { + 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, + 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, + { + 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, + { + 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, + { + 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, + { + 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, + { + 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, + { + 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, + { + 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, + { + 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xea, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x6e, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, + { + 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x6d, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, + { + 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xe9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x6d, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, + { + 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xd9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x6d, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, + { + 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xd8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, + { + 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, + { + 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0f, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, + { + 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, + { + 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, + { + 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, + { + 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb7, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6b, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, + { + 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xb7, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6b, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, + { + 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa7, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x6b, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, + { + 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x6b, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, + { + 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0xa6, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x5b, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, + { + 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x96, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x5a, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, + { + 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8f, 0x0e, 0x00, 0xff, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x5a, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, + { + 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x5a, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, + { + 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x5a, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, + { + 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x5a, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, + { + 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xc8, 0x85, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x59, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, + { + 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x59, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, + { + 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x59, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, + { + 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, + { + 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x74, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, + { + 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, + { + 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0d, 0x00, 0xc8, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, + { + 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x78, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, + { + 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x78, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, + { + 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x78, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, + { + 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x63, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x78, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, + { + 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x77, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, + { + 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x77, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, + { + 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x77, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, + { + 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x52, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x76, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, + { + 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x52, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x76, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, + { + 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8d, 0x0b, 0x00, 0x84, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x76, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, + { + 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x76, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, + { + 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x76, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, + { + 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x76, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, + { + 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x76, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, + { + 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x75, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, + { + 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x75, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, + { + 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x75, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, + { + 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x74, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, + { + 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x74, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, + { + 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8b, 0x09, 0x00, 0x70, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x74, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, + { + 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x74, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, + { + 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x74, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, + { + 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x74, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, + { + 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x74, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, + { + 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x84, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, + { + 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, + { + 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, + { + 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, + { + 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, + { + 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, + { + 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, + { + 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, + { + 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, + { + 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, + { + 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, + { + 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, + { + 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, + { + 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x8a, 0x06, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, + { + 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, + { + 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, + { + 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, + { + 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, + { + 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, + { + 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x82, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, + { + 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x72, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, + { + 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x72, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, + { + 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x72, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, + { + 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x72, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, + { + 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x71, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, + { + 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x71, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, + { + 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x88, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x71, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, + { + 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x71, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, + { + 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x87, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x71, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, + { + 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0b, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x1f, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x09, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x08, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x07, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x06, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x05, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v6[] = { + { + 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, + { + 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, + { + 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, + { + 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, + { + 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, + { + 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, + { + 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, + { + 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, + { + 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, + { + 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, + { + 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, + { + 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, + { + 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, + { + 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, + { + 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, + { + 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, + { + 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, + { + 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, + { + 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, + { + 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, + { + 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, + { + 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, + { + 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, + { + 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, + { + 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, + { + 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, + { + 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, + { + 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, + { + 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, + { + 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, + { + 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, + { + 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, + { + 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, + { + 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, + { + 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, + { + 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, + { + 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, + { + 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, + { + 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, + { + 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, + { + 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, + { + 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, + { + 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, + { + 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, + { + 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, + { + 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, + { + 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, + { + 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, + { + 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, + { + 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, + { + 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, + { + 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, + { + 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, + { + 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, + { + 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, + { + 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, + { + 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, + { + 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, + { + 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, + { + 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, + { + 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, + { + 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, + { + 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, + { + 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, + { + 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, + { + 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, + { + 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, + { + 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, + { + 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, + { + 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, + { + 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, + { + 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, + { + 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, + { + 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, + { + 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, + { + 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, + { + 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, + { + 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, + { + 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, + { + 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, + { + 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, + { + 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, + { + 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, + { + 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, + { + 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, + { + 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, + { + 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, + { + 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, + { + 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, + { + 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, + { + 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, + { + 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, + { + 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, + { + 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, + { + 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, + { + 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, + { + 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, + { + 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, + { + 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, + { + 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, + { + 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, + { + 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, + { + 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, + { + 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, + { + 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, + { + 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, + { + 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, + { + 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, + { + 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, + { + 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, + { + 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x67, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x57, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x56, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x46, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x23, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x12, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x02, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x01, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio205x chan_info_nphyrev5n6_2056v7[] = { + { + 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0f, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, + { + 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, + { + 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, + { + 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0b, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0b, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, + { + 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0e, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, + { + 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, + { + 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, + { + 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, + { + 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, + { + 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x0a, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x0a, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, + { + 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0d, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, + { + 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xff, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xff, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, + { + 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, + { + 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, + { + 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x70, + 0x00, 0x0c, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x70, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, + { + 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, + { + 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, + { + 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, + { + 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, + { + 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, + { + 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0b, 0x00, 0x9f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, + { + 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x70, + 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x70, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, + { + 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, + 0x00, 0x0a, 0x00, 0x9f, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, + { + 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x07, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x07, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, + { + 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfb, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, + { + 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, + { + 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, + { + 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, + { + 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, + { + 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xfa, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x09, 0x00, 0x9e, 0x00, 0xfa, 0x00, 0x06, 0x00, 0x70, 0x00, 0x09, + 0x00, 0x6e, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, + { + 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xea, 0x00, 0x06, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x9e, 0x00, 0xea, 0x00, 0x06, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x6e, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, + { + 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xe9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x6d, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, + { + 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xe9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x9d, 0x00, 0xe9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x6d, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, + { + 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xd9, 0x00, 0x05, 0x00, 0x70, + 0x00, 0x08, 0x00, 0x9d, 0x00, 0xd9, 0x00, 0x05, 0x00, 0x70, 0x00, 0x08, + 0x00, 0x6d, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, + { + 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xd8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xd8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, + { + 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, + { + 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, + { + 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, + { + 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xc8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xc8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, + { + 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb8, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9c, 0x00, 0xb8, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6c, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, + { + 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xb7, 0x00, 0x04, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x04, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6b, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, + { + 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xb7, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x07, 0x00, 0x9b, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x07, + 0x00, 0x6b, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, + { + 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa7, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa7, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x6b, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, + { + 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x6b, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, + { + 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0xa6, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9b, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x7b, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, + { + 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x96, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9a, 0x00, 0x96, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x7a, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, + { + 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x7a, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, + { + 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x06, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x06, + 0x00, 0x7a, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, + { + 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x7a, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, + { + 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x95, 0x00, 0x03, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x9a, 0x00, 0x95, 0x00, 0x03, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x7a, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, + { + 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x85, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x99, 0x00, 0x85, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x79, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, + { + 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x79, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, + { + 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x05, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x05, + 0x00, 0x79, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, + { + 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x02, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x99, 0x00, 0x84, 0x00, 0x02, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x79, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, + { + 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x74, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x99, 0x00, 0x74, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x79, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, + { + 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x78, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, + { + 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x78, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, + { + 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x78, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, + { + 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x78, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, + { + 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x04, 0x00, 0x98, 0x00, 0x73, 0x00, 0x01, 0x00, 0x70, 0x00, 0x04, + 0x00, 0x78, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, + { + 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x63, 0x00, 0x01, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x98, 0x00, 0x63, 0x00, 0x01, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x78, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, + { + 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x77, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, + { + 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x77, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, + { + 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x03, 0x00, 0x97, 0x00, 0x62, 0x00, 0x00, 0x00, 0x70, 0x00, 0x03, + 0x00, 0x77, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, + { + 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x52, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x76, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, + { + 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x52, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x52, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x86, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, + { + 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x86, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, + { + 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x86, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, + { + 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x86, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, + { + 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x86, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, + { + 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x96, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x86, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, + { + 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x51, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x02, 0x00, 0x95, 0x00, 0x51, 0x00, 0x00, 0x00, 0x70, 0x00, 0x02, + 0x00, 0x85, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, + { + 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x85, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, + { + 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x95, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x85, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, + { + 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x84, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, + { + 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x84, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, + { + 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, + { + 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, + { + 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, + { + 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, + { + 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x40, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x40, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, + { + 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x01, 0x00, 0x94, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x01, + 0x00, 0x94, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, + { + 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, + { + 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, + { + 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, + { + 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, + { + 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x30, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x30, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, + { + 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x93, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x93, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, + { + 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, + { + 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, + { + 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, + { + 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, + { + 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, + { + 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, + { + 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, + { + 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, + { + 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, + { + 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, + { + 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, + { + 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, + { + 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, + { + 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, + { + 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x10, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, + { + 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, + { + 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, + { + 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, + { + 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, + { + 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, + { + 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, + { + 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x91, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, + { + 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0b, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x89, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0f, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0f, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x76, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x66, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x55, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0e, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0e, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x22, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0d, 0x00, 0x08, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v8[] = { + { + 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, + { + 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, + { + 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, + { + 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, + { + 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, + { + 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, + { + 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, + { + 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, + { + 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, + { + 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, + { + 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, + { + 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, + { + 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, + { + 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, + { + 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, + { + 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, + { + 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, + { + 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, + { + 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, + { + 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, + { + 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, + { + 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, + { + 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, + { + 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, + { + 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, + { + 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, + { + 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, + { + 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, + { + 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, + { + 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, + { + 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, + { + 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, + { + 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, + { + 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, + { + 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, + { + 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, + { + 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, + { + 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, + { + 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, + { + 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, + { + 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, + { + 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, + { + 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, + { + 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, + { + 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, + { + 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, + { + 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, + { + 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, + { + 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, + { + 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, + { + 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, + { + 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, + { + 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, + { + 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, + { + 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, + { + 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, + { + 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, + { + 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, + { + 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, + { + 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, + { + 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, + { + 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, + { + 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, + { + 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, + { + 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, + { + 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, + { + 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, + { + 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, + { + 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, + { + 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, + { + 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, + { + 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, + { + 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, + { + 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, + { + 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, + { + 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, + { + 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, + { + 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, + { + 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, + { + 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, + { + 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, + { + 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, + { + 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, + { + 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, + { + 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, + { + 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, + { + 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, + { + 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, + { + 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, + { + 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, + { + 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, + { + 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, + { + 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, + { + 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, + { + 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, + { + 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, + { + 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, + { + 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, + { + 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, + { + 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, + { + 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x07, 0x07, 0x04, 0x10, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, + { + 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, + { + 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, + { + 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, + { + 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, + { + 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, + { + 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, + { + 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, + { + 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, + { + 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x04, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, + { + 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x08, 0x08, 0x04, 0x16, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio205x chan_info_nphyrev6_2056v11[] = { + { + 184, 4920, 0xff, 0x01, 0x01, 0x01, 0xec, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07b4, 0x07b0, 0x07ac, 0x0214, 0x0215, 0x0216}, + { + 186, 4930, 0xff, 0x01, 0x01, 0x01, 0xed, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07b8, 0x07b4, 0x07b0, 0x0213, 0x0214, 0x0215}, + { + 188, 4940, 0xff, 0x01, 0x01, 0x01, 0xee, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07bc, 0x07b8, 0x07b4, 0x0212, 0x0213, 0x0214}, + { + 190, 4950, 0xff, 0x01, 0x01, 0x01, 0xef, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c0, 0x07bc, 0x07b8, 0x0211, 0x0212, 0x0213}, + { + 192, 4960, 0xff, 0x01, 0x01, 0x01, 0xf0, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c4, 0x07c0, 0x07bc, 0x020f, 0x0211, 0x0212}, + { + 194, 4970, 0xff, 0x01, 0x01, 0x01, 0xf1, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07c8, 0x07c4, 0x07c0, 0x020e, 0x020f, 0x0211}, + { + 196, 4980, 0xff, 0x01, 0x01, 0x01, 0xf2, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07cc, 0x07c8, 0x07c4, 0x020d, 0x020e, 0x020f}, + { + 198, 4990, 0xff, 0x01, 0x01, 0x01, 0xf3, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d0, 0x07cc, 0x07c8, 0x020c, 0x020d, 0x020e}, + { + 200, 5000, 0xff, 0x01, 0x01, 0x01, 0xf4, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d4, 0x07d0, 0x07cc, 0x020b, 0x020c, 0x020d}, + { + 202, 5010, 0xff, 0x01, 0x01, 0x01, 0xf5, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07d8, 0x07d4, 0x07d0, 0x020a, 0x020b, 0x020c}, + { + 204, 5020, 0xf7, 0x01, 0x01, 0x01, 0xf6, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07dc, 0x07d8, 0x07d4, 0x0209, 0x020a, 0x020b}, + { + 206, 5030, 0xf7, 0x01, 0x01, 0x01, 0xf7, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e0, 0x07dc, 0x07d8, 0x0208, 0x0209, 0x020a}, + { + 208, 5040, 0xef, 0x01, 0x01, 0x01, 0xf8, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e4, 0x07e0, 0x07dc, 0x0207, 0x0208, 0x0209}, + { + 210, 5050, 0xef, 0x01, 0x01, 0x01, 0xf9, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07e8, 0x07e4, 0x07e0, 0x0206, 0x0207, 0x0208}, + { + 212, 5060, 0xe6, 0x01, 0x01, 0x01, 0xfa, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfe, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfe, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07ec, 0x07e8, 0x07e4, 0x0205, 0x0206, 0x0207}, + { + 214, 5070, 0xe6, 0x01, 0x01, 0x01, 0xfb, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f0, 0x07ec, 0x07e8, 0x0204, 0x0205, 0x0206}, + { + 216, 5080, 0xde, 0x01, 0x01, 0x01, 0xfc, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f4, 0x07f0, 0x07ec, 0x0203, 0x0204, 0x0205}, + { + 218, 5090, 0xde, 0x01, 0x01, 0x01, 0xfd, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x01, 0x01, 0x01, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x09, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x09, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07f8, 0x07f4, 0x07f0, 0x0202, 0x0203, 0x0204}, + { + 220, 5100, 0xd6, 0x01, 0x01, 0x01, 0xfe, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfd, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfd, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x07fc, 0x07f8, 0x07f4, 0x0201, 0x0202, 0x0203}, + { + 222, 5110, 0xd6, 0x01, 0x01, 0x01, 0xff, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0800, 0x07fc, 0x07f8, 0x0200, 0x0201, 0x0202}, + { + 224, 5120, 0xce, 0x01, 0x01, 0x02, 0x00, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0804, 0x0800, 0x07fc, 0x01ff, 0x0200, 0x0201}, + { + 226, 5130, 0xce, 0x01, 0x01, 0x02, 0x01, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfc, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfc, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x0808, 0x0804, 0x0800, 0x01fe, 0x01ff, 0x0200}, + { + 228, 5140, 0xc6, 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfb, 0x00, 0x08, 0x00, 0x77, + 0x00, 0x0f, 0x00, 0x6f, 0x00, 0xfb, 0x00, 0x08, 0x00, 0x77, 0x00, 0x0f, + 0x00, 0x6f, 0x00, 0x080c, 0x0808, 0x0804, 0x01fd, 0x01fe, 0x01ff}, + { + 32, 5160, 0xbe, 0x01, 0x01, 0x02, 0x04, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x0814, 0x0810, 0x080c, 0x01fb, 0x01fc, 0x01fd}, + { + 34, 5170, 0xbe, 0x01, 0x01, 0x02, 0x05, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xfa, 0x00, 0x07, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xfa, 0x00, 0x07, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x0818, 0x0814, 0x0810, 0x01fa, 0x01fb, 0x01fc}, + { + 36, 5180, 0xb6, 0x01, 0x01, 0x02, 0x06, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0e, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0e, + 0x00, 0x6f, 0x00, 0x081c, 0x0818, 0x0814, 0x01f9, 0x01fa, 0x01fb}, + { + 38, 5190, 0xb6, 0x01, 0x01, 0x02, 0x07, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x06, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x06, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0820, 0x081c, 0x0818, 0x01f8, 0x01f9, 0x01fa}, + { + 40, 5200, 0xaf, 0x01, 0x01, 0x02, 0x08, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0824, 0x0820, 0x081c, 0x01f7, 0x01f8, 0x01f9}, + { + 42, 5210, 0xaf, 0x01, 0x01, 0x02, 0x09, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8f, 0x0f, 0x00, 0xff, 0xf9, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xf9, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0828, 0x0824, 0x0820, 0x01f6, 0x01f7, 0x01f8}, + { + 44, 5220, 0xa7, 0x01, 0x01, 0x02, 0x0a, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xfe, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x082c, 0x0828, 0x0824, 0x01f5, 0x01f6, 0x01f7}, + { + 46, 5230, 0xa7, 0x01, 0x01, 0x02, 0x0b, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xd8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xd8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0830, 0x082c, 0x0828, 0x01f4, 0x01f5, 0x01f6}, + { + 48, 5240, 0xa0, 0x01, 0x01, 0x02, 0x0c, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xee, 0xc8, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc8, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0834, 0x0830, 0x082c, 0x01f3, 0x01f4, 0x01f5}, + { + 50, 5250, 0xa0, 0x01, 0x01, 0x02, 0x0d, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0f, 0x00, 0xed, 0xc7, 0x00, 0x05, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x0838, 0x0834, 0x0830, 0x01f2, 0x01f3, 0x01f4}, + { + 52, 5260, 0x98, 0x01, 0x01, 0x02, 0x0e, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x02, 0x02, 0x02, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0d, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0d, + 0x00, 0x6f, 0x00, 0x083c, 0x0838, 0x0834, 0x01f1, 0x01f2, 0x01f3}, + { + 54, 5270, 0x98, 0x01, 0x01, 0x02, 0x0f, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8e, 0x0e, 0x00, 0xed, 0xc7, 0x00, 0x04, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xc7, 0x00, 0x04, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0840, 0x083c, 0x0838, 0x01f0, 0x01f1, 0x01f2}, + { + 56, 5280, 0x91, 0x01, 0x01, 0x02, 0x10, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0844, 0x0840, 0x083c, 0x01f0, 0x01f0, 0x01f1}, + { + 58, 5290, 0x91, 0x01, 0x01, 0x02, 0x11, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0848, 0x0844, 0x0840, 0x01ef, 0x01f0, 0x01f0}, + { + 60, 5300, 0x8a, 0x01, 0x01, 0x02, 0x12, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x084c, 0x0848, 0x0844, 0x01ee, 0x01ef, 0x01f0}, + { + 62, 5310, 0x8a, 0x01, 0x01, 0x02, 0x13, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdc, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0850, 0x084c, 0x0848, 0x01ed, 0x01ee, 0x01ef}, + { + 64, 5320, 0x83, 0x01, 0x01, 0x02, 0x14, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0e, 0x00, 0xdb, 0xb7, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0c, 0x00, 0x6f, 0x00, 0xb7, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0c, + 0x00, 0x6f, 0x00, 0x0854, 0x0850, 0x084c, 0x01ec, 0x01ed, 0x01ee}, + { + 66, 5330, 0x83, 0x01, 0x01, 0x02, 0x15, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xcb, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0858, 0x0854, 0x0850, 0x01eb, 0x01ec, 0x01ed}, + { + 68, 5340, 0x7c, 0x01, 0x01, 0x02, 0x16, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8d, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x085c, 0x0858, 0x0854, 0x01ea, 0x01eb, 0x01ec}, + { + 70, 5350, 0x7c, 0x01, 0x01, 0x02, 0x17, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xca, 0xa6, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0b, 0x00, 0x6f, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0b, + 0x00, 0x6f, 0x00, 0x0860, 0x085c, 0x0858, 0x01e9, 0x01ea, 0x01eb}, + { + 72, 5360, 0x75, 0x01, 0x01, 0x02, 0x18, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0864, 0x0860, 0x085c, 0x01e8, 0x01e9, 0x01ea}, + { + 74, 5370, 0x75, 0x01, 0x01, 0x02, 0x19, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0d, 0x00, 0xc9, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0868, 0x0864, 0x0860, 0x01e7, 0x01e8, 0x01e9}, + { + 76, 5380, 0x6e, 0x01, 0x01, 0x02, 0x1a, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x95, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x95, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x086c, 0x0868, 0x0864, 0x01e6, 0x01e7, 0x01e8}, + { + 78, 5390, 0x6e, 0x01, 0x01, 0x02, 0x1b, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0870, 0x086c, 0x0868, 0x01e5, 0x01e6, 0x01e7}, + { + 80, 5400, 0x67, 0x01, 0x01, 0x02, 0x1c, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb8, 0x84, 0x00, 0x03, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x03, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0874, 0x0870, 0x086c, 0x01e5, 0x01e5, 0x01e6}, + { + 82, 5410, 0x67, 0x01, 0x01, 0x02, 0x1d, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xb7, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0878, 0x0874, 0x0870, 0x01e4, 0x01e5, 0x01e5}, + { + 84, 5420, 0x61, 0x01, 0x01, 0x02, 0x1e, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0c, 0x00, 0xa7, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x087c, 0x0878, 0x0874, 0x01e3, 0x01e4, 0x01e5}, + { + 86, 5430, 0x61, 0x01, 0x01, 0x02, 0x1f, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x03, 0x03, 0x03, 0x8c, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x0a, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x0a, + 0x00, 0x6f, 0x00, 0x0880, 0x087c, 0x0878, 0x01e2, 0x01e3, 0x01e4}, + { + 88, 5440, 0x5a, 0x01, 0x01, 0x02, 0x20, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0xa6, 0x84, 0x00, 0x02, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x02, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0884, 0x0880, 0x087c, 0x01e1, 0x01e2, 0x01e3}, + { + 90, 5450, 0x5a, 0x01, 0x01, 0x02, 0x21, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0888, 0x0884, 0x0880, 0x01e0, 0x01e1, 0x01e2}, + { + 92, 5460, 0x53, 0x01, 0x01, 0x02, 0x22, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x95, 0x84, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x84, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x088c, 0x0888, 0x0884, 0x01df, 0x01e0, 0x01e1}, + { + 94, 5470, 0x53, 0x01, 0x01, 0x02, 0x23, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8b, 0x0b, 0x00, 0x94, 0x73, 0x00, 0x01, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x01, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0890, 0x088c, 0x0888, 0x01de, 0x01df, 0x01e0}, + { + 96, 5480, 0x4d, 0x01, 0x01, 0x02, 0x24, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x84, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0894, 0x0890, 0x088c, 0x01dd, 0x01de, 0x01df}, + { + 98, 5490, 0x4d, 0x01, 0x01, 0x02, 0x25, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x83, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x0898, 0x0894, 0x0890, 0x01dd, 0x01dd, 0x01de}, + { + 100, 5500, 0x47, 0x01, 0x01, 0x02, 0x26, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x089c, 0x0898, 0x0894, 0x01dc, 0x01dd, 0x01dd}, + { + 102, 5510, 0x47, 0x01, 0x01, 0x02, 0x27, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x82, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a0, 0x089c, 0x0898, 0x01db, 0x01dc, 0x01dd}, + { + 104, 5520, 0x40, 0x01, 0x01, 0x02, 0x28, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x0a, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a4, 0x08a0, 0x089c, 0x01da, 0x01db, 0x01dc}, + { + 106, 5530, 0x40, 0x01, 0x01, 0x02, 0x29, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x72, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08a8, 0x08a4, 0x08a0, 0x01d9, 0x01da, 0x01db}, + { + 108, 5540, 0x3a, 0x01, 0x01, 0x02, 0x2a, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x8a, 0x09, 0x00, 0x71, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08ac, 0x08a8, 0x08a4, 0x01d8, 0x01d9, 0x01da}, + { + 110, 5550, 0x3a, 0x01, 0x01, 0x02, 0x2b, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b0, 0x08ac, 0x08a8, 0x01d7, 0x01d8, 0x01d9}, + { + 112, 5560, 0x34, 0x01, 0x01, 0x02, 0x2c, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x73, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b4, 0x08b0, 0x08ac, 0x01d7, 0x01d7, 0x01d8}, + { + 114, 5570, 0x34, 0x01, 0x01, 0x02, 0x2d, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x09, 0x00, 0x61, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x09, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x09, + 0x00, 0x6f, 0x00, 0x08b8, 0x08b4, 0x08b0, 0x01d6, 0x01d7, 0x01d7}, + { + 116, 5580, 0x2e, 0x01, 0x01, 0x02, 0x2e, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x60, 0x62, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08bc, 0x08b8, 0x08b4, 0x01d5, 0x01d6, 0x01d7}, + { + 118, 5590, 0x2e, 0x01, 0x01, 0x02, 0x2f, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x04, 0x04, 0x04, 0x89, 0x08, 0x00, 0x50, 0x61, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x61, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c0, 0x08bc, 0x08b8, 0x01d4, 0x01d5, 0x01d6}, + { + 120, 5600, 0x28, 0x01, 0x01, 0x02, 0x30, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c4, 0x08c0, 0x08bc, 0x01d3, 0x01d4, 0x01d5}, + { + 122, 5610, 0x28, 0x01, 0x01, 0x02, 0x31, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x51, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x08, 0x00, 0x6f, 0x00, 0x51, 0x00, 0x00, 0x00, 0x77, 0x00, 0x08, + 0x00, 0x6f, 0x00, 0x08c8, 0x08c4, 0x08c0, 0x01d2, 0x01d3, 0x01d4}, + { + 124, 5620, 0x21, 0x01, 0x01, 0x02, 0x32, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x89, 0x08, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08cc, 0x08c8, 0x08c4, 0x01d2, 0x01d2, 0x01d3}, + { + 126, 5630, 0x21, 0x01, 0x01, 0x02, 0x33, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x50, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d0, 0x08cc, 0x08c8, 0x01d1, 0x01d2, 0x01d2}, + { + 128, 5640, 0x1c, 0x01, 0x01, 0x02, 0x34, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x50, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x50, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d4, 0x08d0, 0x08cc, 0x01d0, 0x01d1, 0x01d2}, + { + 130, 5650, 0x1c, 0x01, 0x01, 0x02, 0x35, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x07, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x07, + 0x00, 0x6f, 0x00, 0x08d8, 0x08d4, 0x08d0, 0x01cf, 0x01d0, 0x01d1}, + { + 132, 5660, 0x16, 0x01, 0x01, 0x02, 0x36, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08dc, 0x08d8, 0x08d4, 0x01ce, 0x01cf, 0x01d0}, + { + 134, 5670, 0x16, 0x01, 0x01, 0x02, 0x37, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x88, 0x07, 0x00, 0x40, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, 0x01ce, 0x01cf}, + { + 136, 5680, 0x10, 0x01, 0x01, 0x02, 0x38, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, 0x01ce, 0x01ce}, + { + 138, 5690, 0x10, 0x01, 0x01, 0x02, 0x39, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6f, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6f, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, 0x01cd, 0x01ce}, + { + 140, 5700, 0x0a, 0x01, 0x01, 0x02, 0x3a, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, 0x01cc, 0x01cd}, + { + 142, 5710, 0x0a, 0x01, 0x01, 0x02, 0x3b, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, 0x01cb, 0x01cc}, + { + 144, 5720, 0x0a, 0x01, 0x01, 0x02, 0x3c, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, 0x01ca, 0x01cb}, + { + 145, 5725, 0x03, 0x01, 0x02, 0x04, 0x79, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x06, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, 0x01ca, 0x01cb}, + { + 146, 5730, 0x0a, 0x01, 0x01, 0x02, 0x3d, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6e, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6e, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, 0x01c9, 0x01ca}, + { + 147, 5735, 0x03, 0x01, 0x02, 0x04, 0x7b, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, 0x01c9, 0x01ca}, + { + 148, 5740, 0x0a, 0x01, 0x01, 0x02, 0x3e, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, 0x01c9, 0x01c9}, + { + 149, 5745, 0xfe, 0x00, 0x02, 0x04, 0x7d, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x06, 0x00, 0x6d, 0x00, 0x30, 0x00, 0x00, 0x00, 0x77, 0x00, 0x06, + 0x00, 0x6d, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, 0x01c8, 0x01c9}, + { + 150, 5750, 0x0a, 0x01, 0x01, 0x02, 0x3f, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6d, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6d, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, 0x01c8, 0x01c9}, + { + 151, 5755, 0xfe, 0x00, 0x02, 0x04, 0x7f, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x05, 0x05, 0x05, 0x87, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, 0x01c8, 0x01c8}, + { + 152, 5760, 0x0a, 0x01, 0x01, 0x02, 0x40, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x20, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, 0x01c7, 0x01c8}, + { + 153, 5765, 0xf8, 0x00, 0x02, 0x04, 0x81, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x05, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6c, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, 0x01c7, 0x01c8}, + { + 154, 5770, 0x0a, 0x01, 0x01, 0x02, 0x41, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, 0x01c6, 0x01c7}, + { + 155, 5775, 0xf8, 0x00, 0x02, 0x04, 0x83, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, 0x01c6, 0x01c7}, + { + 156, 5780, 0x0a, 0x01, 0x01, 0x02, 0x42, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x05, 0x05, 0x05, 0x86, 0x04, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, 0x01c6, 0x01c6}, + { + 157, 5785, 0xf2, 0x00, 0x02, 0x04, 0x85, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, 0x01c5, 0x01c6}, + { + 158, 5790, 0x0a, 0x01, 0x01, 0x02, 0x43, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x10, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, 0x01c5, 0x01c6}, + { + 159, 5795, 0xf2, 0x00, 0x02, 0x04, 0x87, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, 0x01c4, 0x01c5}, + { + 160, 5800, 0x0a, 0x01, 0x01, 0x02, 0x44, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6b, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, 0x01c4, 0x01c5}, + { + 161, 5805, 0xed, 0x00, 0x02, 0x04, 0x89, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, 0x01c4, 0x01c4}, + { + 162, 5810, 0x0a, 0x01, 0x01, 0x02, 0x45, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, 0x01c3, 0x01c4}, + { + 163, 5815, 0xed, 0x00, 0x02, 0x04, 0x8b, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, 0x01c3, 0x01c4}, + { + 164, 5820, 0x0a, 0x01, 0x01, 0x02, 0x46, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x6a, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, 0x01c2, 0x01c3}, + { + 165, 5825, 0xed, 0x00, 0x02, 0x04, 0x8d, 0x05, 0x05, 0x02, 0x15, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, 0x01c2, 0x01c3}, + { + 166, 5830, 0x0a, 0x01, 0x01, 0x02, 0x47, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x05, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x05, + 0x00, 0x69, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, 0x01c2, 0x01c2}, + { + 168, 5840, 0x0a, 0x01, 0x01, 0x02, 0x48, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x86, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, 0x01c1, 0x01c2}, + { + 170, 5850, 0xe0, 0x00, 0x01, 0x02, 0x49, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, 0x01c0, 0x01c1}, + { + 172, 5860, 0xde, 0x00, 0x01, 0x02, 0x4a, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x69, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, 0x01bf, 0x01c0}, + { + 174, 5870, 0xdb, 0x00, 0x01, 0x02, 0x4b, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, 0x01bf, 0x01bf}, + { + 176, 5880, 0xd8, 0x00, 0x01, 0x02, 0x4c, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, 0x01be, 0x01bf}, + { + 178, 5890, 0xd6, 0x00, 0x01, 0x02, 0x4d, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, 0x01bd, 0x01be}, + { + 180, 5900, 0xd3, 0x00, 0x01, 0x02, 0x4e, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, 0x01bc, 0x01bd}, + { + 182, 5910, 0xd6, 0x00, 0x01, 0x02, 0x4f, 0x05, 0x05, 0x02, 0x0c, 0x01, + 0x06, 0x06, 0x06, 0x85, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x04, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x04, + 0x00, 0x68, 0x00, 0x0940, 0x093c, 0x0938, 0x01bb, 0x01bc, 0x01bc}, + { + 1, 2412, 0x00, 0x01, 0x03, 0x09, 0x6c, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x04, 0x04, 0x04, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03c9, 0x03c5, 0x03c1, 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x00, 0x01, 0x03, 0x09, 0x71, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x78, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03cb, 0x03c7, 0x03c3, 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x00, 0x01, 0x03, 0x09, 0x76, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x67, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0b, 0x00, 0x0a, 0x00, 0x89, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0b, 0x00, 0x0a, 0x03cd, 0x03c9, 0x03c5, 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x00, 0x01, 0x03, 0x09, 0x7b, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x78, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03cf, 0x03cb, 0x03c7, 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x00, 0x01, 0x03, 0x09, 0x80, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x56, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x77, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d1, 0x03cd, 0x03c9, 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x00, 0x01, 0x03, 0x09, 0x85, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x76, 0x00, 0x03, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d3, 0x03cf, 0x03cb, 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x00, 0x01, 0x03, 0x09, 0x8a, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x05, 0x05, 0x05, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x45, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x0a, 0x03d5, 0x03d1, 0x03cd, 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x00, 0x01, 0x03, 0x09, 0x8f, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x55, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03d7, 0x03d3, 0x03cf, 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x00, 0x01, 0x03, 0x09, 0x94, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x23, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x45, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03d9, 0x03d5, 0x03d1, 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x00, 0x01, 0x03, 0x09, 0x99, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x12, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x0a, 0x00, 0x09, 0x00, 0x34, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x0a, 0x00, 0x09, 0x03db, 0x03d7, 0x03d3, 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x00, 0x01, 0x03, 0x09, 0x9e, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x33, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03dd, 0x03d9, 0x03d5, 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x00, 0x01, 0x03, 0x09, 0xa3, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x06, 0x06, 0x06, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x22, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03df, 0x03db, 0x03d7, 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x00, 0x01, 0x03, 0x09, 0xa8, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x11, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03e1, 0x03dd, 0x03d9, 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0xff, 0x01, 0x03, 0x09, 0xb4, 0x06, 0x06, 0x04, 0x2b, 0x01, + 0x07, 0x07, 0x07, 0x8f, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x70, 0x00, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x70, 0x00, + 0x09, 0x00, 0x09, 0x03e6, 0x03e2, 0x03de, 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio2057 chan_info_nphyrev7_2057_rev4[] = { + { + 184, 4920, 0x68, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xec, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07b4, 0x07b0, 0x07ac, 0x0214, + 0x0215, + 0x0216, + }, + { + 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07b8, 0x07b4, 0x07b0, 0x0213, + 0x0214, + 0x0215, + }, + { + 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07bc, 0x07b8, 0x07b4, 0x0212, + 0x0213, + 0x0214, + }, + { + 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c0, 0x07bc, 0x07b8, 0x0211, + 0x0212, + 0x0213, + }, + { + 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c4, 0x07c0, 0x07bc, 0x020f, + 0x0211, + 0x0212, + }, + { + 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07c8, 0x07c4, 0x07c0, 0x020e, + 0x020f, + 0x0211, + }, + { + 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07cc, 0x07c8, 0x07c4, 0x020d, + 0x020e, + 0x020f, + }, + { + 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d0, 0x07cc, 0x07c8, 0x020c, + 0x020d, + 0x020e, + }, + { + 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d4, 0x07d0, 0x07cc, 0x020b, + 0x020c, + 0x020d, + }, + { + 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07d8, 0x07d4, 0x07d0, 0x020a, + 0x020b, + 0x020c, + }, + { + 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07dc, 0x07d8, 0x07d4, 0x0209, + 0x020a, + 0x020b, + }, + { + 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e0, 0x07dc, 0x07d8, 0x0208, + 0x0209, + 0x020a, + }, + { + 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e4, 0x07e0, 0x07dc, 0x0207, + 0x0208, + 0x0209, + }, + { + 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xf3, 0x00, 0xef, 0x07e8, 0x07e4, 0x07e0, 0x0206, + 0x0207, + 0x0208, + }, + { + 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xe3, 0x00, 0xef, 0x00, + 0x00, 0x0f, 0x0f, 0xe3, 0x00, 0xef, 0x07ec, 0x07e8, 0x07e4, 0x0205, + 0x0206, + 0x0207, + }, + { + 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x00, + 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x07f0, 0x07ec, 0x07e8, 0x0204, + 0x0205, + 0x0206, + }, + { + 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x00, + 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xef, 0x07f4, 0x07f0, 0x07ec, 0x0203, + 0x0204, + 0x0205, + }, + { + 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, + 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x07f8, 0x07f4, 0x07f0, 0x0202, + 0x0203, + 0x0204, + }, + { + 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, + 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x07fc, 0x07f8, 0x07f4, 0x0201, + 0x0202, + 0x0203, + }, + { + 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, + 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0800, 0x07fc, 0x07f8, 0x0200, + 0x0201, + 0x0202, + }, + { + 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, + 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0804, 0x0800, 0x07fc, 0x01ff, + 0x0200, + 0x0201, + }, + { + 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x00, + 0x00, 0x0e, 0x0f, 0xe3, 0x00, 0xd6, 0x0808, 0x0804, 0x0800, 0x01fe, + 0x01ff, + 0x0200, + }, + { + 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0e, 0x0e, 0xe3, 0x00, 0xd6, 0x00, + 0x00, 0x0e, 0x0e, 0xe3, 0x00, 0xd6, 0x080c, 0x0808, 0x0804, 0x01fd, + 0x01fe, + 0x01ff, + }, + { + 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x00, + 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x0814, 0x0810, 0x080c, 0x01fb, + 0x01fc, + 0x01fd, + }, + { + 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x00, + 0x00, 0x0d, 0x0e, 0xe3, 0x00, 0xd6, 0x0818, 0x0814, 0x0810, 0x01fa, + 0x01fb, + 0x01fc, + }, + { + 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x081c, 0x0818, 0x0814, 0x01f9, + 0x01fa, + 0x01fb, + }, + { + 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0820, 0x081c, 0x0818, 0x01f8, + 0x01f9, + 0x01fa, + }, + { + 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0824, 0x0820, 0x081c, 0x01f7, + 0x01f8, + 0x01f9, + }, + { + 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0d, 0x0e, 0xd3, 0x00, 0xd6, 0x0828, 0x0824, 0x0820, 0x01f6, + 0x01f7, + 0x01f8, + }, + { + 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x082c, 0x0828, 0x0824, 0x01f5, + 0x01f6, + 0x01f7, + }, + { + 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0830, 0x082c, 0x0828, 0x01f4, + 0x01f5, + 0x01f6, + }, + { + 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0834, 0x0830, 0x082c, 0x01f3, + 0x01f4, + 0x01f5, + }, + { + 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0c, 0x0e, 0xd3, 0x00, 0xd6, 0x0838, 0x0834, 0x0830, 0x01f2, + 0x01f3, + 0x01f4, + }, + { + 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x083c, 0x0838, 0x0834, 0x01f1, + 0x01f2, + 0x01f3, + }, + { + 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x00, + 0x00, 0x0c, 0x0d, 0xd3, 0x00, 0xd6, 0x0840, 0x083c, 0x0838, 0x01f0, + 0x01f1, + 0x01f2, + }, + { + 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00, + 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x0844, 0x0840, 0x083c, 0x01f0, + 0x01f0, + 0x01f1, + }, + { + 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00, + 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x0848, 0x0844, 0x0840, 0x01ef, + 0x01f0, + 0x01f0, + }, + { + 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x00, + 0x00, 0x0c, 0x0c, 0xc3, 0x00, 0xd4, 0x084c, 0x0848, 0x0844, 0x01ee, + 0x01ef, + 0x01f0, + }, + { + 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00, + 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0850, 0x084c, 0x0848, 0x01ed, + 0x01ee, + 0x01ef, + }, + { + 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00, + 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0854, 0x0850, 0x084c, 0x01ec, + 0x01ed, + 0x01ee, + }, + { + 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x00, + 0x00, 0x0b, 0x0c, 0xc3, 0x00, 0xd4, 0x0858, 0x0854, 0x0850, 0x01eb, + 0x01ec, + 0x01ed, + }, + { + 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0c, 0xc3, 0x00, 0xa1, 0x00, + 0x00, 0x0a, 0x0c, 0xc3, 0x00, 0xa1, 0x085c, 0x0858, 0x0854, 0x01ea, + 0x01eb, + 0x01ec, + }, + { + 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00, + 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0860, 0x085c, 0x0858, 0x01e9, + 0x01ea, + 0x01eb, + }, + { + 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00, + 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0864, 0x0860, 0x085c, 0x01e8, + 0x01e9, + 0x01ea, + }, + { + 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00, + 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x0868, 0x0864, 0x0860, 0x01e7, + 0x01e8, + 0x01e9, + }, + { + 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x00, + 0x00, 0x0a, 0x0b, 0xb3, 0x00, 0xa1, 0x086c, 0x0868, 0x0864, 0x01e6, + 0x01e7, + 0x01e8, + }, + { + 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0a, 0x0a, 0xa3, 0x00, 0xa1, 0x00, + 0x00, 0x0a, 0x0a, 0xa3, 0x00, 0xa1, 0x0870, 0x086c, 0x0868, 0x01e5, + 0x01e6, + 0x01e7, + }, + { + 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x00, + 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x0874, 0x0870, 0x086c, 0x01e5, + 0x01e5, + 0x01e6, + }, + { + 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x00, + 0x00, 0x09, 0x0a, 0xa3, 0x00, 0x90, 0x0878, 0x0874, 0x0870, 0x01e4, + 0x01e5, + 0x01e5, + }, + { + 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0xa3, 0x00, 0x90, 0x00, + 0x00, 0x09, 0x09, 0xa3, 0x00, 0x90, 0x087c, 0x0878, 0x0874, 0x01e3, + 0x01e4, + 0x01e5, + }, + { + 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00, + 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0880, 0x087c, 0x0878, 0x01e2, + 0x01e3, + 0x01e4, + }, + { + 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00, + 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0884, 0x0880, 0x087c, 0x01e1, + 0x01e2, + 0x01e3, + }, + { + 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x00, + 0x00, 0x09, 0x09, 0x93, 0x00, 0x90, 0x0888, 0x0884, 0x0880, 0x01e0, + 0x01e1, + 0x01e2, + }, + { + 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x08, 0x93, 0x00, 0x90, 0x00, + 0x00, 0x08, 0x08, 0x93, 0x00, 0x90, 0x088c, 0x0888, 0x0884, 0x01df, + 0x01e0, + 0x01e1, + }, + { + 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x08, 0x93, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x08, 0x93, 0x00, 0x60, 0x0890, 0x088c, 0x0888, 0x01de, + 0x01df, + 0x01e0, + }, + { + 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x0894, 0x0890, 0x088c, 0x01dd, + 0x01de, + 0x01df, + }, + { + 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x0898, 0x0894, 0x0890, 0x01dd, + 0x01dd, + 0x01de, + }, + { + 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x089c, 0x0898, 0x0894, 0x01dc, + 0x01dd, + 0x01dd, + }, + { + 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x07, 0x93, 0x00, 0x60, 0x08a0, 0x089c, 0x0898, 0x01db, + 0x01dc, + 0x01dd, + }, + { + 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08a4, 0x08a0, 0x089c, 0x01da, + 0x01db, + 0x01dc, + }, + { + 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08a8, 0x08a4, 0x08a0, 0x01d9, + 0x01da, + 0x01db, + }, + { + 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x06, 0x93, 0x00, 0x60, 0x08ac, 0x08a8, 0x08a4, 0x01d8, + 0x01d9, + 0x01da, + }, + { + 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b0, 0x08ac, 0x08a8, 0x01d7, + 0x01d8, + 0x01d9, + }, + { + 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b4, 0x08b0, 0x08ac, 0x01d7, + 0x01d7, + 0x01d8, + }, + { + 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x00, + 0x00, 0x08, 0x05, 0x83, 0x00, 0x60, 0x08b8, 0x08b4, 0x08b0, 0x01d6, + 0x01d7, + 0x01d7, + }, + { + 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x05, 0x83, 0x00, 0x60, 0x00, + 0x00, 0x07, 0x05, 0x83, 0x00, 0x60, 0x08bc, 0x08b8, 0x08b4, 0x01d5, + 0x01d6, + 0x01d7, + }, + { + 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x04, 0x83, 0x00, 0x60, 0x00, + 0x00, 0x07, 0x04, 0x83, 0x00, 0x60, 0x08c0, 0x08bc, 0x08b8, 0x01d4, + 0x01d5, + 0x01d6, + }, + { + 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x07, 0x04, 0x73, 0x00, 0x30, 0x00, + 0x00, 0x07, 0x04, 0x73, 0x00, 0x30, 0x08c4, 0x08c0, 0x08bc, 0x01d3, + 0x01d4, + 0x01d5, + }, + { + 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08c8, 0x08c4, 0x08c0, 0x01d2, + 0x01d3, + 0x01d4, + }, + { + 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08cc, 0x08c8, 0x08c4, 0x01d2, + 0x01d2, + 0x01d3, + }, + { + 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08d0, 0x08cc, 0x08c8, 0x01d1, + 0x01d2, + 0x01d2, + }, + { + 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x04, 0x73, 0x00, 0x30, 0x08d4, 0x08d0, 0x08cc, 0x01d0, + 0x01d1, + 0x01d2, + }, + { + 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x08d8, 0x08d4, 0x08d0, 0x01cf, + 0x01d0, + 0x01d1, + }, + { + 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x00, + 0x00, 0x06, 0x03, 0x63, 0x00, 0x30, 0x08dc, 0x08d8, 0x08d4, 0x01ce, + 0x01cf, + 0x01d0, + }, + { + 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x03, 0x63, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x03, 0x63, 0x00, 0x00, 0x08e0, 0x08dc, 0x08d8, 0x01ce, + 0x01ce, + 0x01cf, + }, + { + 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08e4, 0x08e0, 0x08dc, 0x01cd, + 0x01ce, + 0x01ce, + }, + { + 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08e8, 0x08e4, 0x08e0, 0x01cc, + 0x01cd, + 0x01ce, + }, + { + 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08ec, 0x08e8, 0x08e4, 0x01cb, + 0x01cc, + 0x01cd, + }, + { + 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08f0, 0x08ec, 0x08e8, 0x01ca, + 0x01cb, + 0x01cc, + }, + { + 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x02, 0x53, 0x00, 0x00, 0x08f4, 0x08f0, 0x08ec, 0x01c9, + 0x01ca, + 0x01cb, + }, + { + 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x05, 0x01, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x01, 0x53, 0x00, 0x00, 0x08f6, 0x08f2, 0x08ee, 0x01c9, + 0x01ca, + 0x01cb, + }, + { + 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08f8, 0x08f4, 0x08f0, 0x01c9, + 0x01c9, + 0x01ca, + }, + { + 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fa, 0x08f6, 0x08f2, 0x01c8, + 0x01c9, + 0x01ca, + }, + { + 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fc, 0x08f8, 0x08f4, 0x01c8, + 0x01c9, + 0x01c9, + }, + { + 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x08fe, 0x08fa, 0x08f6, 0x01c8, + 0x01c8, + 0x01c9, + }, + { + 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, + 0x01c8, + 0x01c9, + }, + { + 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x53, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, + 0x01c8, + 0x01c8, + }, + { + 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, + 0x01c7, + 0x01c8, + }, + { + 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, + 0x01c7, + 0x01c8, + }, + { + 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, + 0x01c6, + 0x01c7, + }, + { + 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x43, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, + 0x01c6, + 0x01c7, + }, + { + 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x03, 0x01, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x01, 0x43, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, + 0x01c6, + 0x01c6, + }, + { + 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, + 0x01c5, + 0x01c6, + }, + { + 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, + 0x01c5, + 0x01c6, + }, + { + 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, + 0x01c4, + 0x01c5, + }, + { + 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, + 0x01c4, + 0x01c5, + }, + { + 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, + 0x01c4, + 0x01c4, + }, + { + 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, + 0x01c3, + 0x01c4, + }, + { + 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, + 0x01c3, + 0x01c4, + }, + { + 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, + 0x01c2, + 0x01c3, + }, + { + 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, + 0x01c2, + 0x01c3, + }, + { + 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, + 0x01c2, + 0x01c2, + }, + { + 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, + 0x01c1, + 0x01c2, + }, + { + 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, + 0x01c0, + 0x01c1, + }, + { + 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, + 0x01bf, + 0x01c0, + }, + { + 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, + 0x01bf, + 0x01bf, + }, + { + 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, + 0x01be, + 0x01bf, + }, + { + 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, + 0x01bd, + 0x01be, + }, + { + 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x43, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, + 0x01bc, + 0x01bd, + }, + { + 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f, + 0x0a, 0x00, 0x0a, 0x00, 0x71, 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71, + 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a, + 0x043f, + 0x0443, + }, + { + 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f, + 0x0a, 0x00, 0x0a, 0x00, 0x71, 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71, + 0xa3, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438, + 0x043d, + 0x0441, + }, + { + 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f, + 0x09, 0x00, 0x09, 0x00, 0x71, 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71, + 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436, + 0x043a, + 0x043f, + }, + { + 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f, + 0x09, 0x00, 0x09, 0x00, 0x71, 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x71, + 0x93, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434, + 0x0438, + 0x043d, + }, + { + 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f, + 0x08, 0x00, 0x08, 0x00, 0x51, 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51, + 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431, + 0x0436, + 0x043a, + }, + { + 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f, + 0x08, 0x00, 0x08, 0x00, 0x51, 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51, + 0x83, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f, + 0x0434, + 0x0438, + }, + { + 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x51, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x51, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d, + 0x0431, + 0x0436, + }, + { + 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x31, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b, + 0x042f, + 0x0434, + }, + { + 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x31, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429, + 0x042d, + 0x0431, + }, + { + 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f, + 0x06, 0x00, 0x06, 0x00, 0x31, 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31, + 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427, + 0x042b, + 0x042f, + }, + { + 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f, + 0x06, 0x00, 0x06, 0x00, 0x31, 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x31, + 0x63, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424, + 0x0429, + 0x042d, + }, + { + 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f, + 0x05, 0x00, 0x05, 0x00, 0x11, 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x11, + 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422, + 0x0427, + 0x042b, + }, + { + 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f, + 0x05, 0x00, 0x05, 0x00, 0x11, 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x11, + 0x53, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420, + 0x0424, + 0x0429, + }, + { + 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f, + 0x04, 0x00, 0x04, 0x00, 0x11, 0x43, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x11, + 0x43, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b, + 0x041f, + 0x0424} +}; + +static const struct chan_info_nphy_radio2057_rev5 +chan_info_nphyrev8_2057_rev5[] = { + { + 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0d, + 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03c9, 0x03c5, 0x03c1, + 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0d, + 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03cb, 0x03c7, 0x03c3, + 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0d, + 0x08, 0x0e, 0x61, 0x03, 0xef, 0x61, 0x03, 0xef, 0x03cd, 0x03c9, 0x03c5, + 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0c, + 0x08, 0x0e, 0x61, 0x03, 0xdf, 0x61, 0x03, 0xdf, 0x03cf, 0x03cb, 0x03c7, + 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0c, + 0x07, 0x0d, 0x61, 0x03, 0xcf, 0x61, 0x03, 0xcf, 0x03d1, 0x03cd, 0x03c9, + 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0c, + 0x07, 0x0d, 0x61, 0x03, 0xbf, 0x61, 0x03, 0xbf, 0x03d3, 0x03cf, 0x03cb, + 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0b, + 0x07, 0x0d, 0x61, 0x03, 0xaf, 0x61, 0x03, 0xaf, 0x03d5, 0x03d1, 0x03cd, + 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0b, + 0x07, 0x0d, 0x61, 0x03, 0x9f, 0x61, 0x03, 0x9f, 0x03d7, 0x03d3, 0x03cf, + 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0b, + 0x07, 0x0d, 0x61, 0x03, 0x8f, 0x61, 0x03, 0x8f, 0x03d9, 0x03d5, 0x03d1, + 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0b, + 0x07, 0x0c, 0x61, 0x03, 0x7f, 0x61, 0x03, 0x7f, 0x03db, 0x03d7, 0x03d3, + 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0b, + 0x07, 0x0c, 0x61, 0x03, 0x6f, 0x61, 0x03, 0x6f, 0x03dd, 0x03d9, 0x03d5, + 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0b, + 0x06, 0x0c, 0x61, 0x03, 0x5f, 0x61, 0x03, 0x5f, 0x03df, 0x03db, 0x03d7, + 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0a, + 0x06, 0x0b, 0x61, 0x03, 0x4f, 0x61, 0x03, 0x4f, 0x03e1, 0x03dd, 0x03d9, + 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0a, + 0x06, 0x0b, 0x61, 0x03, 0x3f, 0x61, 0x03, 0x3f, 0x03e6, 0x03e2, 0x03de, + 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio2057_rev5 +chan_info_nphyrev9_2057_rev5v1[] = { + { + 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0d, + 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03c9, 0x03c5, 0x03c1, + 0x043a, 0x043f, 0x0443}, + { + 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0d, + 0x08, 0x0e, 0x61, 0x03, 0xff, 0x61, 0x03, 0xff, 0x03cb, 0x03c7, 0x03c3, + 0x0438, 0x043d, 0x0441}, + { + 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0d, + 0x08, 0x0e, 0x61, 0x03, 0xef, 0x61, 0x03, 0xef, 0x03cd, 0x03c9, 0x03c5, + 0x0436, 0x043a, 0x043f}, + { + 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0c, + 0x08, 0x0e, 0x61, 0x03, 0xdf, 0x61, 0x03, 0xdf, 0x03cf, 0x03cb, 0x03c7, + 0x0434, 0x0438, 0x043d}, + { + 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0c, + 0x07, 0x0d, 0x61, 0x03, 0xcf, 0x61, 0x03, 0xcf, 0x03d1, 0x03cd, 0x03c9, + 0x0431, 0x0436, 0x043a}, + { + 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0c, + 0x07, 0x0d, 0x61, 0x03, 0xbf, 0x61, 0x03, 0xbf, 0x03d3, 0x03cf, 0x03cb, + 0x042f, 0x0434, 0x0438}, + { + 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0b, + 0x07, 0x0d, 0x61, 0x03, 0xaf, 0x61, 0x03, 0xaf, 0x03d5, 0x03d1, 0x03cd, + 0x042d, 0x0431, 0x0436}, + { + 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0b, + 0x07, 0x0d, 0x61, 0x03, 0x9f, 0x61, 0x03, 0x9f, 0x03d7, 0x03d3, 0x03cf, + 0x042b, 0x042f, 0x0434}, + { + 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0b, + 0x07, 0x0d, 0x61, 0x03, 0x8f, 0x61, 0x03, 0x8f, 0x03d9, 0x03d5, 0x03d1, + 0x0429, 0x042d, 0x0431}, + { + 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0b, + 0x07, 0x0c, 0x61, 0x03, 0x7f, 0x61, 0x03, 0x7f, 0x03db, 0x03d7, 0x03d3, + 0x0427, 0x042b, 0x042f}, + { + 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0b, + 0x07, 0x0c, 0x61, 0x03, 0x6f, 0x61, 0x03, 0x6f, 0x03dd, 0x03d9, 0x03d5, + 0x0424, 0x0429, 0x042d}, + { + 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0b, + 0x06, 0x0c, 0x61, 0x03, 0x5f, 0x61, 0x03, 0x5f, 0x03df, 0x03db, 0x03d7, + 0x0422, 0x0427, 0x042b}, + { + 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0a, + 0x06, 0x0b, 0x61, 0x03, 0x4f, 0x61, 0x03, 0x4f, 0x03e1, 0x03dd, 0x03d9, + 0x0420, 0x0424, 0x0429}, + { + 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0a, + 0x06, 0x0b, 0x61, 0x03, 0x3f, 0x61, 0x03, 0x3f, 0x03e6, 0x03e2, 0x03de, + 0x041b, 0x041f, 0x0424} +}; + +static const struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev7[] = { + { + 184, 4920, 0x68, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xec, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b4, 0x07b0, 0x07ac, 0x0214, + 0x0215, + 0x0216}, + { + 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b8, 0x07b4, 0x07b0, 0x0213, + 0x0214, + 0x0215}, + { + 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07bc, 0x07b8, 0x07b4, 0x0212, + 0x0213, + 0x0214}, + { + 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c0, 0x07bc, 0x07b8, 0x0211, + 0x0212, + 0x0213}, + { + 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c4, 0x07c0, 0x07bc, 0x020f, + 0x0211, + 0x0212}, + { + 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c8, 0x07c4, 0x07c0, 0x020e, + 0x020f, + 0x0211}, + { + 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07cc, 0x07c8, 0x07c4, 0x020d, + 0x020e, + 0x020f}, + { + 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07d0, 0x07cc, 0x07c8, 0x020c, + 0x020d, + 0x020e}, + { + 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d4, 0x07d0, 0x07cc, 0x020b, + 0x020c, + 0x020d}, + { + 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d8, 0x07d4, 0x07d0, 0x020a, + 0x020b, + 0x020c}, + { + 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07dc, 0x07d8, 0x07d4, 0x0209, + 0x020a, + 0x020b}, + { + 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e0, 0x07dc, 0x07d8, 0x0208, + 0x0209, + 0x020a}, + { + 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e4, 0x07e0, 0x07dc, 0x0207, + 0x0208, + 0x0209}, + { + 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e8, 0x07e4, 0x07e0, 0x0206, + 0x0207, + 0x0208}, + { + 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07ec, 0x07e8, 0x07e4, 0x0205, + 0x0206, + 0x0207}, + { + 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f0, 0x07ec, 0x07e8, 0x0204, + 0x0205, + 0x0206}, + { + 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f4, 0x07f0, 0x07ec, 0x0203, + 0x0204, + 0x0205}, + { + 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f8, 0x07f4, 0x07f0, 0x0202, + 0x0203, + 0x0204}, + { + 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x07fc, 0x07f8, 0x07f4, 0x0201, + 0x0202, + 0x0203}, + { + 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0800, 0x07fc, 0x07f8, 0x0200, + 0x0201, + 0x0202}, + { + 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0804, 0x0800, 0x07fc, 0x01ff, + 0x0200, + 0x0201}, + { + 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0808, 0x0804, 0x0800, 0x01fe, + 0x01ff, + 0x0200}, + { + 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x080c, 0x0808, 0x0804, 0x01fd, + 0x01fe, + 0x01ff}, + { + 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0814, 0x0810, 0x080c, 0x01fb, + 0x01fc, + 0x01fd}, + { + 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0818, 0x0814, 0x0810, 0x01fa, + 0x01fb, + 0x01fc}, + { + 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x081c, 0x0818, 0x0814, 0x01f9, + 0x01fa, + 0x01fb}, + { + 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0820, 0x081c, 0x0818, 0x01f8, + 0x01f9, + 0x01fa}, + { + 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0824, 0x0820, 0x081c, 0x01f7, + 0x01f8, + 0x01f9}, + { + 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0828, 0x0824, 0x0820, 0x01f6, + 0x01f7, + 0x01f8}, + { + 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x082c, 0x0828, 0x0824, 0x01f5, + 0x01f6, + 0x01f7}, + { + 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0830, 0x082c, 0x0828, 0x01f4, + 0x01f5, + 0x01f6}, + { + 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0834, 0x0830, 0x082c, 0x01f3, + 0x01f4, + 0x01f5}, + { + 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0838, 0x0834, 0x0830, 0x01f2, + 0x01f3, + 0x01f4}, + { + 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x083c, 0x0838, 0x0834, 0x01f1, + 0x01f2, + 0x01f3}, + { + 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0840, 0x083c, 0x0838, 0x01f0, + 0x01f1, + 0x01f2}, + { + 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0844, 0x0840, 0x083c, 0x01f0, + 0x01f0, + 0x01f1}, + { + 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0848, 0x0844, 0x0840, 0x01ef, + 0x01f0, + 0x01f0}, + { + 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x084c, 0x0848, 0x0844, 0x01ee, + 0x01ef, + 0x01f0}, + { + 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0850, 0x084c, 0x0848, 0x01ed, + 0x01ee, + 0x01ef}, + { + 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0854, 0x0850, 0x084c, 0x01ec, + 0x01ed, + 0x01ee}, + { + 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0858, 0x0854, 0x0850, 0x01eb, + 0x01ec, + 0x01ed}, + { + 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x085c, 0x0858, 0x0854, 0x01ea, + 0x01eb, + 0x01ec}, + { + 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0860, 0x085c, 0x0858, 0x01e9, + 0x01ea, + 0x01eb}, + { + 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0864, 0x0860, 0x085c, 0x01e8, + 0x01e9, + 0x01ea}, + { + 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0868, 0x0864, 0x0860, 0x01e7, + 0x01e8, + 0x01e9}, + { + 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x086c, 0x0868, 0x0864, 0x01e6, + 0x01e7, + 0x01e8}, + { + 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0870, 0x086c, 0x0868, 0x01e5, + 0x01e6, + 0x01e7}, + { + 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0874, 0x0870, 0x086c, 0x01e5, + 0x01e5, + 0x01e6}, + { + 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0878, 0x0874, 0x0870, 0x01e4, + 0x01e5, + 0x01e5}, + { + 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x087c, 0x0878, 0x0874, 0x01e3, + 0x01e4, + 0x01e5}, + { + 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0880, 0x087c, 0x0878, 0x01e2, + 0x01e3, + 0x01e4}, + { + 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0884, 0x0880, 0x087c, 0x01e1, + 0x01e2, + 0x01e3}, + { + 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0888, 0x0884, 0x0880, 0x01e0, + 0x01e1, + 0x01e2}, + { + 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x088c, 0x0888, 0x0884, 0x01df, + 0x01e0, + 0x01e1}, + { + 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0890, 0x088c, 0x0888, 0x01de, + 0x01df, + 0x01e0}, + { + 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0894, 0x0890, 0x088c, 0x01dd, + 0x01de, + 0x01df}, + { + 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0898, 0x0894, 0x0890, 0x01dd, + 0x01dd, + 0x01de}, + { + 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x089c, 0x0898, 0x0894, 0x01dc, + 0x01dd, + 0x01dd}, + { + 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a0, 0x089c, 0x0898, 0x01db, + 0x01dc, + 0x01dd}, + { + 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a4, 0x08a0, 0x089c, 0x01da, + 0x01db, + 0x01dc}, + { + 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a8, 0x08a4, 0x08a0, 0x01d9, + 0x01da, + 0x01db}, + { + 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08ac, 0x08a8, 0x08a4, 0x01d8, + 0x01d9, + 0x01da}, + { + 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b0, 0x08ac, 0x08a8, 0x01d7, + 0x01d8, + 0x01d9}, + { + 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b4, 0x08b0, 0x08ac, 0x01d7, + 0x01d7, + 0x01d8}, + { + 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b8, 0x08b4, 0x08b0, 0x01d6, + 0x01d7, + 0x01d7}, + { + 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08bc, 0x08b8, 0x08b4, 0x01d5, + 0x01d6, + 0x01d7}, + { + 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08c0, 0x08bc, 0x08b8, 0x01d4, + 0x01d5, + 0x01d6}, + { + 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c4, 0x08c0, 0x08bc, 0x01d3, + 0x01d4, + 0x01d5}, + { + 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c8, 0x08c4, 0x08c0, 0x01d2, + 0x01d3, + 0x01d4}, + { + 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08cc, 0x08c8, 0x08c4, 0x01d2, + 0x01d2, + 0x01d3}, + { + 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d0, 0x08cc, 0x08c8, 0x01d1, + 0x01d2, + 0x01d2}, + { + 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d4, 0x08d0, 0x08cc, 0x01d0, + 0x01d1, + 0x01d2}, + { + 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08d8, 0x08d4, 0x08d0, 0x01cf, + 0x01d0, + 0x01d1}, + { + 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08dc, 0x08d8, 0x08d4, 0x01ce, + 0x01cf, + 0x01d0}, + { + 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08e0, 0x08dc, 0x08d8, 0x01ce, + 0x01ce, + 0x01cf}, + { + 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e4, 0x08e0, 0x08dc, 0x01cd, + 0x01ce, + 0x01ce}, + { + 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e8, 0x08e4, 0x08e0, 0x01cc, + 0x01cd, + 0x01ce}, + { + 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08ec, 0x08e8, 0x08e4, 0x01cb, + 0x01cc, + 0x01cd}, + { + 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f0, 0x08ec, 0x08e8, 0x01ca, + 0x01cb, + 0x01cc}, + { + 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f4, 0x08f0, 0x08ec, 0x01c9, + 0x01ca, + 0x01cb}, + { + 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f6, 0x08f2, 0x08ee, 0x01c9, + 0x01ca, + 0x01cb}, + { + 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f8, 0x08f4, 0x08f0, 0x01c9, + 0x01c9, + 0x01ca}, + { + 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fa, 0x08f6, 0x08f2, 0x01c8, + 0x01c9, + 0x01ca}, + { + 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fc, 0x08f8, 0x08f4, 0x01c8, + 0x01c9, + 0x01c9}, + { + 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fe, 0x08fa, 0x08f6, 0x01c8, + 0x01c8, + 0x01c9}, + { + 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, + 0x01c8, + 0x01c9}, + { + 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, + 0x01c8, + 0x01c8}, + { + 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, + 0x01c7, + 0x01c8}, + { + 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, + 0x01c7, + 0x01c8}, + { + 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, + 0x01c6, + 0x01c7}, + { + 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, + 0x01c6, + 0x01c7}, + { + 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, + 0x01c6, + 0x01c6}, + { + 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, + 0x01c5, + 0x01c6}, + { + 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, + 0x01c5, + 0x01c6}, + { + 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, + 0x01c4, + 0x01c5}, + { + 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, + 0x01c4, + 0x01c5}, + { + 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, + 0x01c4, + 0x01c4}, + { + 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, + 0x01c3, + 0x01c4}, + { + 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, + 0x01c3, + 0x01c4}, + { + 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, + 0x01c2, + 0x01c3}, + { + 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, + 0x01c2, + 0x01c3}, + { + 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, + 0x01c2, + 0x01c2}, + { + 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, + 0x01c1, + 0x01c2}, + { + 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, + 0x01c0, + 0x01c1}, + { + 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, + 0x01bf, + 0x01c0}, + { + 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, + 0x01bf, + 0x01bf}, + { + 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, + 0x01be, + 0x01bf}, + { + 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, + 0x01bd, + 0x01be}, + { + 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, + 0x01bc, + 0x01bd}, + { + 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f, + 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a, + 0x043f, + 0x0443}, + { + 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f, + 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438, + 0x043d, + 0x0441}, + { + 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f, + 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436, + 0x043a, + 0x043f}, + { + 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f, + 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434, + 0x0438, + 0x043d}, + { + 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f, + 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431, + 0x0436, + 0x043a}, + { + 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f, + 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f, + 0x0434, + 0x0438}, + { + 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d, + 0x0431, + 0x0436}, + { + 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b, + 0x042f, + 0x0434}, + { + 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429, + 0x042d, + 0x0431}, + { + 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f, + 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427, + 0x042b, + 0x042f}, + { + 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f, + 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424, + 0x0429, + 0x042d}, + { + 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f, + 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422, + 0x0427, + 0x042b}, + { + 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f, + 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420, + 0x0424, + 0x0429}, + { + 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f, + 0x04, 0x00, 0x04, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b, + 0x041f, + 0x0424} +}; + +static const struct chan_info_nphy_radio2057 chan_info_nphyrev8_2057_rev8[] = { + { + 186, 4930, 0x6b, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xed, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07b8, 0x07b4, 0x07b0, 0x0213, + 0x0214, + 0x0215}, + { + 188, 4940, 0x6e, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xee, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0xd3, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07bc, 0x07b8, 0x07b4, 0x0212, + 0x0213, + 0x0214}, + { + 190, 4950, 0x72, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xef, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c0, 0x07bc, 0x07b8, 0x0211, + 0x0212, + 0x0213}, + { + 192, 4960, 0x75, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf0, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c4, 0x07c0, 0x07bc, 0x020f, + 0x0211, + 0x0212}, + { + 194, 4970, 0x78, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf1, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07c8, 0x07c4, 0x07c0, 0x020e, + 0x020f, + 0x0211}, + { + 196, 4980, 0x7c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf2, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07cc, 0x07c8, 0x07c4, 0x020d, + 0x020e, + 0x020f}, + { + 198, 4990, 0x7f, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf3, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xd3, 0x00, 0xff, 0x07d0, 0x07cc, 0x07c8, 0x020c, + 0x020d, + 0x020e}, + { + 200, 5000, 0x82, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf4, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d4, 0x07d0, 0x07cc, 0x020b, + 0x020c, + 0x020d}, + { + 202, 5010, 0x86, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf5, 0x01, 0x0f, + 0x00, 0x0f, 0x00, 0xff, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07d8, 0x07d4, 0x07d0, 0x020a, + 0x020b, + 0x020c}, + { + 204, 5020, 0x89, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf6, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07dc, 0x07d8, 0x07d4, 0x0209, + 0x020a, + 0x020b}, + { + 206, 5030, 0x8c, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf7, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e0, 0x07dc, 0x07d8, 0x0208, + 0x0209, + 0x020a}, + { + 208, 5040, 0x90, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf8, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e4, 0x07e0, 0x07dc, 0x0207, + 0x0208, + 0x0209}, + { + 210, 5050, 0x93, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xf9, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07e8, 0x07e4, 0x07e0, 0x0206, + 0x0207, + 0x0208}, + { + 212, 5060, 0x96, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfa, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07ec, 0x07e8, 0x07e4, 0x0205, + 0x0206, + 0x0207}, + { + 214, 5070, 0x9a, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfb, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f0, 0x07ec, 0x07e8, 0x0204, + 0x0205, + 0x0206}, + { + 216, 5080, 0x9d, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfc, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f4, 0x07f0, 0x07ec, 0x0203, + 0x0204, + 0x0205}, + { + 218, 5090, 0xa0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfd, 0x01, 0x0e, + 0x00, 0x0e, 0x00, 0xee, 0x00, 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x00, + 0x00, 0x0f, 0x0f, 0xb3, 0x00, 0xff, 0x07f8, 0x07f4, 0x07f0, 0x0202, + 0x0203, + 0x0204}, + { + 220, 5100, 0xa4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xfe, 0x01, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x07fc, 0x07f8, 0x07f4, 0x0201, + 0x0202, + 0x0203}, + { + 222, 5110, 0xa7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0xff, 0x01, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0800, 0x07fc, 0x07f8, 0x0200, + 0x0201, + 0x0202}, + { + 224, 5120, 0xaa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x00, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0804, 0x0800, 0x07fc, 0x01ff, + 0x0200, + 0x0201}, + { + 226, 5130, 0xae, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x01, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0808, 0x0804, 0x0800, 0x01fe, + 0x01ff, + 0x0200}, + { + 228, 5140, 0xb1, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x02, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x080c, 0x0808, 0x0804, 0x01fd, + 0x01fe, + 0x01ff}, + { + 32, 5160, 0xb8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x04, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0814, 0x0810, 0x080c, 0x01fb, + 0x01fc, + 0x01fd}, + { + 34, 5170, 0xbb, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x05, 0x02, 0x0d, + 0x00, 0x0d, 0x00, 0xdd, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0818, 0x0814, 0x0810, 0x01fa, + 0x01fb, + 0x01fc}, + { + 36, 5180, 0xbe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x06, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x081c, 0x0818, 0x0814, 0x01f9, + 0x01fa, + 0x01fb}, + { + 38, 5190, 0xc2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x07, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x00, + 0x00, 0x0f, 0x0f, 0xa3, 0x00, 0xfc, 0x0820, 0x081c, 0x0818, 0x01f8, + 0x01f9, + 0x01fa}, + { + 40, 5200, 0xc5, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x08, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0824, 0x0820, 0x081c, 0x01f7, + 0x01f8, + 0x01f9}, + { + 42, 5210, 0xc8, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x09, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0828, 0x0824, 0x0820, 0x01f6, + 0x01f7, + 0x01f8}, + { + 44, 5220, 0xcc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0a, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x082c, 0x0828, 0x0824, 0x01f5, + 0x01f6, + 0x01f7}, + { + 46, 5230, 0xcf, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0b, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0830, 0x082c, 0x0828, 0x01f4, + 0x01f5, + 0x01f6}, + { + 48, 5240, 0xd2, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0c, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0834, 0x0830, 0x082c, 0x01f3, + 0x01f4, + 0x01f5}, + { + 50, 5250, 0xd6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0d, 0x02, 0x0c, + 0x00, 0x0c, 0x00, 0xcc, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0838, 0x0834, 0x0830, 0x01f2, + 0x01f3, + 0x01f4}, + { + 52, 5260, 0xd9, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0e, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x083c, 0x0838, 0x0834, 0x01f1, + 0x01f2, + 0x01f3}, + { + 54, 5270, 0xdc, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x0f, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0840, 0x083c, 0x0838, 0x01f0, + 0x01f1, + 0x01f2}, + { + 56, 5280, 0xe0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x10, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0844, 0x0840, 0x083c, 0x01f0, + 0x01f0, + 0x01f1}, + { + 58, 5290, 0xe3, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x11, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x00, + 0x00, 0x0f, 0x0f, 0x93, 0x00, 0xf8, 0x0848, 0x0844, 0x0840, 0x01ef, + 0x01f0, + 0x01f0}, + { + 60, 5300, 0xe6, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x12, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x084c, 0x0848, 0x0844, 0x01ee, + 0x01ef, + 0x01f0}, + { + 62, 5310, 0xea, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x13, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0850, 0x084c, 0x0848, 0x01ed, + 0x01ee, + 0x01ef}, + { + 64, 5320, 0xed, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x14, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0854, 0x0850, 0x084c, 0x01ec, + 0x01ed, + 0x01ee}, + { + 66, 5330, 0xf0, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x15, 0x02, 0x0b, + 0x00, 0x0b, 0x00, 0xbb, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0858, 0x0854, 0x0850, 0x01eb, + 0x01ec, + 0x01ed}, + { + 68, 5340, 0xf4, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x16, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x085c, 0x0858, 0x0854, 0x01ea, + 0x01eb, + 0x01ec}, + { + 70, 5350, 0xf7, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x17, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0860, 0x085c, 0x0858, 0x01e9, + 0x01ea, + 0x01eb}, + { + 72, 5360, 0xfa, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x18, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0864, 0x0860, 0x085c, 0x01e8, + 0x01e9, + 0x01ea}, + { + 74, 5370, 0xfe, 0x16, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x19, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0868, 0x0864, 0x0860, 0x01e7, + 0x01e8, + 0x01e9}, + { + 76, 5380, 0x01, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1a, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x086c, 0x0868, 0x0864, 0x01e6, + 0x01e7, + 0x01e8}, + { + 78, 5390, 0x04, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1b, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x00, + 0x00, 0x0f, 0x0c, 0x83, 0x00, 0xf5, 0x0870, 0x086c, 0x0868, 0x01e5, + 0x01e6, + 0x01e7}, + { + 80, 5400, 0x08, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1c, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0874, 0x0870, 0x086c, 0x01e5, + 0x01e5, + 0x01e6}, + { + 82, 5410, 0x0b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1d, 0x02, 0x0a, + 0x00, 0x0a, 0x00, 0xaa, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0878, 0x0874, 0x0870, 0x01e4, + 0x01e5, + 0x01e5}, + { + 84, 5420, 0x0e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1e, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x087c, 0x0878, 0x0874, 0x01e3, + 0x01e4, + 0x01e5}, + { + 86, 5430, 0x12, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x1f, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0880, 0x087c, 0x0878, 0x01e2, + 0x01e3, + 0x01e4}, + { + 88, 5440, 0x15, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x20, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0884, 0x0880, 0x087c, 0x01e1, + 0x01e2, + 0x01e3}, + { + 90, 5450, 0x18, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x21, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0888, 0x0884, 0x0880, 0x01e0, + 0x01e1, + 0x01e2}, + { + 92, 5460, 0x1c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x22, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x088c, 0x0888, 0x0884, 0x01df, + 0x01e0, + 0x01e1}, + { + 94, 5470, 0x1f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x23, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0890, 0x088c, 0x0888, 0x01de, + 0x01df, + 0x01e0}, + { + 96, 5480, 0x22, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x24, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0894, 0x0890, 0x088c, 0x01dd, + 0x01de, + 0x01df}, + { + 98, 5490, 0x26, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x25, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x00, + 0x00, 0x0d, 0x09, 0x53, 0x00, 0xb1, 0x0898, 0x0894, 0x0890, 0x01dd, + 0x01dd, + 0x01de}, + { + 100, 5500, 0x29, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x26, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x089c, 0x0898, 0x0894, 0x01dc, + 0x01dd, + 0x01dd}, + { + 102, 5510, 0x2c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x27, 0x02, 0x09, + 0x00, 0x09, 0x00, 0x99, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a0, 0x089c, 0x0898, 0x01db, + 0x01dc, + 0x01dd}, + { + 104, 5520, 0x30, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x28, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a4, 0x08a0, 0x089c, 0x01da, + 0x01db, + 0x01dc}, + { + 106, 5530, 0x33, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x29, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08a8, 0x08a4, 0x08a0, 0x01d9, + 0x01da, + 0x01db}, + { + 108, 5540, 0x36, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2a, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08ac, 0x08a8, 0x08a4, 0x01d8, + 0x01d9, + 0x01da}, + { + 110, 5550, 0x3a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2b, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b0, 0x08ac, 0x08a8, 0x01d7, + 0x01d8, + 0x01d9}, + { + 112, 5560, 0x3d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2c, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b4, 0x08b0, 0x08ac, 0x01d7, + 0x01d7, + 0x01d8}, + { + 114, 5570, 0x40, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2d, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08b8, 0x08b4, 0x08b0, 0x01d6, + 0x01d7, + 0x01d7}, + { + 116, 5580, 0x44, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2e, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08bc, 0x08b8, 0x08b4, 0x01d5, + 0x01d6, + 0x01d7}, + { + 118, 5590, 0x47, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x2f, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x00, + 0x00, 0x0a, 0x06, 0x43, 0x00, 0x80, 0x08c0, 0x08bc, 0x08b8, 0x01d4, + 0x01d5, + 0x01d6}, + { + 120, 5600, 0x4a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x30, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c4, 0x08c0, 0x08bc, 0x01d3, + 0x01d4, + 0x01d5}, + { + 122, 5610, 0x4e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x31, 0x02, 0x08, + 0x00, 0x08, 0x00, 0x88, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08c8, 0x08c4, 0x08c0, 0x01d2, + 0x01d3, + 0x01d4}, + { + 124, 5620, 0x51, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x32, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08cc, 0x08c8, 0x08c4, 0x01d2, + 0x01d2, + 0x01d3}, + { + 126, 5630, 0x54, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x33, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d0, 0x08cc, 0x08c8, 0x01d1, + 0x01d2, + 0x01d2}, + { + 128, 5640, 0x58, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x34, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x04, 0x23, 0x00, 0x60, 0x08d4, 0x08d0, 0x08cc, 0x01d0, + 0x01d1, + 0x01d2}, + { + 130, 5650, 0x5b, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x35, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08d8, 0x08d4, 0x08d0, 0x01cf, + 0x01d0, + 0x01d1}, + { + 132, 5660, 0x5e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x36, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08dc, 0x08d8, 0x08d4, 0x01ce, + 0x01cf, + 0x01d0}, + { + 134, 5670, 0x62, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x37, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x03, 0x23, 0x00, 0x60, 0x08e0, 0x08dc, 0x08d8, 0x01ce, + 0x01ce, + 0x01cf}, + { + 136, 5680, 0x65, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x38, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e4, 0x08e0, 0x08dc, 0x01cd, + 0x01ce, + 0x01ce}, + { + 138, 5690, 0x68, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x39, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x00, + 0x00, 0x09, 0x02, 0x23, 0x00, 0x60, 0x08e8, 0x08e4, 0x08e0, 0x01cc, + 0x01cd, + 0x01ce}, + { + 140, 5700, 0x6c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3a, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08ec, 0x08e8, 0x08e4, 0x01cb, + 0x01cc, + 0x01cd}, + { + 142, 5710, 0x6f, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3b, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f0, 0x08ec, 0x08e8, 0x01ca, + 0x01cb, + 0x01cc}, + { + 144, 5720, 0x72, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3c, 0x02, 0x07, + 0x00, 0x07, 0x00, 0x77, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f4, 0x08f0, 0x08ec, 0x01c9, + 0x01ca, + 0x01cb}, + { + 145, 5725, 0x74, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x79, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f6, 0x08f2, 0x08ee, 0x01c9, + 0x01ca, + 0x01cb}, + { + 146, 5730, 0x76, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3d, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08f8, 0x08f4, 0x08f0, 0x01c9, + 0x01c9, + 0x01ca}, + { + 147, 5735, 0x77, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7b, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fa, 0x08f6, 0x08f2, 0x01c8, + 0x01c9, + 0x01ca}, + { + 148, 5740, 0x79, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3e, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fc, 0x08f8, 0x08f4, 0x01c8, + 0x01c9, + 0x01c9}, + { + 149, 5745, 0x7b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7d, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x30, 0x08fe, 0x08fa, 0x08f6, 0x01c8, + 0x01c8, + 0x01c9}, + { + 150, 5750, 0x7c, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x3f, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0900, 0x08fc, 0x08f8, 0x01c7, + 0x01c8, + 0x01c9}, + { + 151, 5755, 0x7e, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x7f, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0902, 0x08fe, 0x08fa, 0x01c7, + 0x01c8, + 0x01c8}, + { + 152, 5760, 0x80, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x40, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0904, 0x0900, 0x08fc, 0x01c6, + 0x01c7, + 0x01c8}, + { + 153, 5765, 0x81, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x81, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0906, 0x0902, 0x08fe, 0x01c6, + 0x01c7, + 0x01c8}, + { + 154, 5770, 0x83, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x41, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0908, 0x0904, 0x0900, 0x01c6, + 0x01c6, + 0x01c7}, + { + 155, 5775, 0x85, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x83, 0x04, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090a, 0x0906, 0x0902, 0x01c5, + 0x01c6, + 0x01c7}, + { + 156, 5780, 0x86, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x42, 0x02, 0x06, + 0x00, 0x06, 0x00, 0x66, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090c, 0x0908, 0x0904, 0x01c5, + 0x01c6, + 0x01c6}, + { + 157, 5785, 0x88, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x85, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x090e, 0x090a, 0x0906, 0x01c4, + 0x01c5, + 0x01c6}, + { + 158, 5790, 0x8a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x43, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0910, 0x090c, 0x0908, 0x01c4, + 0x01c5, + 0x01c6}, + { + 159, 5795, 0x8b, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x87, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x02, 0x13, 0x00, 0x00, 0x0912, 0x090e, 0x090a, 0x01c4, + 0x01c4, + 0x01c5}, + { + 160, 5800, 0x8d, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x44, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x01, 0x03, 0x00, 0x00, 0x0914, 0x0910, 0x090c, 0x01c3, + 0x01c4, + 0x01c5}, + { + 161, 5805, 0x8f, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x89, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0916, 0x0912, 0x090e, 0x01c3, + 0x01c4, + 0x01c4}, + { + 162, 5810, 0x90, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x45, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0918, 0x0914, 0x0910, 0x01c2, + 0x01c3, + 0x01c4}, + { + 163, 5815, 0x92, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8b, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091a, 0x0916, 0x0912, 0x01c2, + 0x01c3, + 0x01c4}, + { + 164, 5820, 0x94, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x46, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091c, 0x0918, 0x0914, 0x01c2, + 0x01c2, + 0x01c3}, + { + 165, 5825, 0x95, 0x17, 0x20, 0x14, 0x08, 0x08, 0x30, 0x8d, 0x04, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x091e, 0x091a, 0x0916, 0x01c1, + 0x01c2, + 0x01c3}, + { + 166, 5830, 0x97, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x47, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0920, 0x091c, 0x0918, 0x01c1, + 0x01c2, + 0x01c2}, + { + 168, 5840, 0x9a, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x48, 0x02, 0x05, + 0x00, 0x05, 0x00, 0x55, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0924, 0x0920, 0x091c, 0x01c0, + 0x01c1, + 0x01c2}, + { + 170, 5850, 0x9e, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x49, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0928, 0x0924, 0x0920, 0x01bf, + 0x01c0, + 0x01c1}, + { + 172, 5860, 0xa1, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4a, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x092c, 0x0928, 0x0924, 0x01bf, + 0x01bf, + 0x01c0}, + { + 174, 5870, 0xa4, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4b, 0x02, 0x04, + 0x00, 0x04, 0x00, 0x44, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0930, 0x092c, 0x0928, 0x01be, + 0x01bf, + 0x01bf}, + { + 176, 5880, 0xa8, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4c, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0934, 0x0930, 0x092c, 0x01bd, + 0x01be, + 0x01bf}, + { + 178, 5890, 0xab, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4d, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x0938, 0x0934, 0x0930, 0x01bc, + 0x01bd, + 0x01be}, + { + 180, 5900, 0xae, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x30, 0x4e, 0x02, 0x03, + 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x01, 0x03, 0x00, 0x00, 0x093c, 0x0938, 0x0934, 0x01bc, + 0x01bc, + 0x01bd}, + { + 1, 2412, 0x48, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x6c, 0x09, 0x0f, + 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03c9, 0x03c5, 0x03c1, 0x043a, + 0x043f, + 0x0443}, + { + 2, 2417, 0x4b, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x71, 0x09, 0x0f, + 0x0a, 0x00, 0x0a, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cb, 0x03c7, 0x03c3, 0x0438, + 0x043d, + 0x0441}, + { + 3, 2422, 0x4e, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x76, 0x09, 0x0f, + 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cd, 0x03c9, 0x03c5, 0x0436, + 0x043a, + 0x043f}, + { + 4, 2427, 0x52, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x7b, 0x09, 0x0f, + 0x09, 0x00, 0x09, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03cf, 0x03cb, 0x03c7, 0x0434, + 0x0438, + 0x043d}, + { + 5, 2432, 0x55, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x80, 0x09, 0x0f, + 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d1, 0x03cd, 0x03c9, 0x0431, + 0x0436, + 0x043a}, + { + 6, 2437, 0x58, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x85, 0x09, 0x0f, + 0x08, 0x00, 0x08, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d3, 0x03cf, 0x03cb, 0x042f, + 0x0434, + 0x0438}, + { + 7, 2442, 0x5c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8a, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d5, 0x03d1, 0x03cd, 0x042d, + 0x0431, + 0x0436}, + { + 8, 2447, 0x5f, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x8f, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d7, 0x03d3, 0x03cf, 0x042b, + 0x042f, + 0x0434}, + { + 9, 2452, 0x62, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x94, 0x09, 0x0f, + 0x07, 0x00, 0x07, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03d9, 0x03d5, 0x03d1, 0x0429, + 0x042d, + 0x0431}, + { + 10, 2457, 0x66, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x99, 0x09, 0x0f, + 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03db, 0x03d7, 0x03d3, 0x0427, + 0x042b, + 0x042f}, + { + 11, 2462, 0x69, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0x9e, 0x09, 0x0f, + 0x06, 0x00, 0x06, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03dd, 0x03d9, 0x03d5, 0x0424, + 0x0429, + 0x042d}, + { + 12, 2467, 0x6c, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa3, 0x09, 0x0f, + 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03df, 0x03db, 0x03d7, 0x0422, + 0x0427, + 0x042b}, + { + 13, 2472, 0x70, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xa8, 0x09, 0x0f, + 0x05, 0x00, 0x05, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x03e1, 0x03dd, 0x03d9, 0x0420, + 0x0424, + 0x0429}, + { + 14, 2484, 0x78, 0x16, 0x30, 0x1b, 0x0a, 0x0a, 0x30, 0xb4, 0x09, 0x0f, + 0x04, 0x00, 0x04, 0x00, 0x61, 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x61, + 0x73, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x03e6, 0x03e2, 0x03de, 0x041b, + 0x041f, + 0x0424} +}; + +static struct radio_regs regs_2055[] = { + {0x02, 0x80, 0x80, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0x27, 0x27, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0x27, 0x27, 0, 0}, + {0x07, 0x7f, 0x7f, 1, 1}, + {0x08, 0x7, 0x7, 1, 1}, + {0x09, 0x7f, 0x7f, 1, 1}, + {0x0A, 0x7, 0x7, 1, 1}, + {0x0B, 0x15, 0x15, 0, 0}, + {0x0C, 0x15, 0x15, 0, 0}, + {0x0D, 0x4f, 0x4f, 1, 1}, + {0x0E, 0x5, 0x5, 1, 1}, + {0x0F, 0x4f, 0x4f, 1, 1}, + {0x10, 0x5, 0x5, 1, 1}, + {0x11, 0xd0, 0xd0, 0, 0}, + {0x12, 0x2, 0x2, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0x40, 0x40, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0xc0, 0xc0, 0, 0}, + {0x1E, 0xff, 0xff, 0, 0}, + {0x1F, 0xc0, 0xc0, 0, 0}, + {0x20, 0xff, 0xff, 0, 0}, + {0x21, 0xc0, 0xc0, 0, 0}, + {0x22, 0, 0, 0, 0}, + {0x23, 0x2c, 0x2c, 0, 0}, + {0x24, 0, 0, 0, 0}, + {0x25, 0, 0, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0, 0, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0, 0, 0, 0}, + {0x2A, 0, 0, 0, 0}, + {0x2B, 0, 0, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0xa4, 0xa4, 0, 0}, + {0x2E, 0x38, 0x38, 0, 0}, + {0x2F, 0, 0, 0, 0}, + {0x30, 0x4, 0x4, 1, 1}, + {0x31, 0, 0, 0, 0}, + {0x32, 0xa, 0xa, 0, 0}, + {0x33, 0x87, 0x87, 0, 0}, + {0x34, 0x9, 0x9, 0, 0}, + {0x35, 0x70, 0x70, 0, 0}, + {0x36, 0x11, 0x11, 0, 0}, + {0x37, 0x18, 0x18, 1, 1}, + {0x38, 0x6, 0x6, 0, 0}, + {0x39, 0x4, 0x4, 1, 1}, + {0x3A, 0x6, 0x6, 0, 0}, + {0x3B, 0x9e, 0x9e, 0, 0}, + {0x3C, 0x9, 0x9, 0, 0}, + {0x3D, 0xc8, 0xc8, 1, 1}, + {0x3E, 0x88, 0x88, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0, 0, 0, 0}, + {0x42, 0x1, 0x1, 0, 0}, + {0x43, 0x2, 0x2, 0, 0}, + {0x44, 0x96, 0x96, 0, 0}, + {0x45, 0x3e, 0x3e, 0, 0}, + {0x46, 0x3e, 0x3e, 0, 0}, + {0x47, 0x13, 0x13, 0, 0}, + {0x48, 0x2, 0x2, 0, 0}, + {0x49, 0x15, 0x15, 0, 0}, + {0x4A, 0x7, 0x7, 0, 0}, + {0x4B, 0, 0, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0, 0, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0, 0, 0, 0}, + {0x50, 0x8, 0x8, 0, 0}, + {0x51, 0x8, 0x8, 0, 0}, + {0x52, 0x6, 0x6, 0, 0}, + {0x53, 0x84, 0x84, 1, 1}, + {0x54, 0xc3, 0xc3, 0, 0}, + {0x55, 0x8f, 0x8f, 0, 0}, + {0x56, 0xff, 0xff, 0, 0}, + {0x57, 0xff, 0xff, 0, 0}, + {0x58, 0x88, 0x88, 0, 0}, + {0x59, 0x88, 0x88, 0, 0}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0xcc, 0xcc, 0, 0}, + {0x5C, 0x6, 0x6, 0, 0}, + {0x5D, 0x80, 0x80, 0, 0}, + {0x5E, 0x80, 0x80, 0, 0}, + {0x5F, 0xf8, 0xf8, 0, 0}, + {0x60, 0x88, 0x88, 0, 0}, + {0x61, 0x88, 0x88, 0, 0}, + {0x62, 0x88, 0x8, 1, 1}, + {0x63, 0x88, 0x88, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0x1, 0x1, 1, 1}, + {0x66, 0x8a, 0x8a, 0, 0}, + {0x67, 0x8, 0x8, 0, 0}, + {0x68, 0x83, 0x83, 0, 0}, + {0x69, 0x6, 0x6, 0, 0}, + {0x6A, 0xa0, 0xa0, 0, 0}, + {0x6B, 0xa, 0xa, 0, 0}, + {0x6C, 0x87, 0x87, 1, 1}, + {0x6D, 0x2a, 0x2a, 0, 0}, + {0x6E, 0x2a, 0x2a, 0, 0}, + {0x6F, 0x2a, 0x2a, 0, 0}, + {0x70, 0x2a, 0x2a, 0, 0}, + {0x71, 0x18, 0x18, 0, 0}, + {0x72, 0x6a, 0x6a, 1, 1}, + {0x73, 0xab, 0xab, 1, 1}, + {0x74, 0x13, 0x13, 1, 1}, + {0x75, 0xc1, 0xc1, 1, 1}, + {0x76, 0xaa, 0xaa, 1, 1}, + {0x77, 0x87, 0x87, 1, 1}, + {0x78, 0, 0, 0, 0}, + {0x79, 0x6, 0x6, 0, 0}, + {0x7A, 0x7, 0x7, 0, 0}, + {0x7B, 0x7, 0x7, 0, 0}, + {0x7C, 0x15, 0x15, 0, 0}, + {0x7D, 0x55, 0x55, 0, 0}, + {0x7E, 0x97, 0x97, 1, 1}, + {0x7F, 0x8, 0x8, 0, 0}, + {0x80, 0x14, 0x14, 1, 1}, + {0x81, 0x33, 0x33, 0, 0}, + {0x82, 0x88, 0x88, 0, 0}, + {0x83, 0x6, 0x6, 0, 0}, + {0x84, 0x3, 0x3, 1, 1}, + {0x85, 0xa, 0xa, 0, 0}, + {0x86, 0x3, 0x3, 1, 1}, + {0x87, 0x2a, 0x2a, 0, 0}, + {0x88, 0xa4, 0xa4, 0, 0}, + {0x89, 0x18, 0x18, 0, 0}, + {0x8A, 0x28, 0x28, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0x4a, 0x4a, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0xf8, 0xf8, 0, 0}, + {0x8F, 0x88, 0x88, 0, 0}, + {0x90, 0x88, 0x88, 0, 0}, + {0x91, 0x88, 0x8, 1, 1}, + {0x92, 0x88, 0x88, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0x1, 0x1, 1, 1}, + {0x95, 0x8a, 0x8a, 0, 0}, + {0x96, 0x8, 0x8, 0, 0}, + {0x97, 0x83, 0x83, 0, 0}, + {0x98, 0x6, 0x6, 0, 0}, + {0x99, 0xa0, 0xa0, 0, 0}, + {0x9A, 0xa, 0xa, 0, 0}, + {0x9B, 0x87, 0x87, 1, 1}, + {0x9C, 0x2a, 0x2a, 0, 0}, + {0x9D, 0x2a, 0x2a, 0, 0}, + {0x9E, 0x2a, 0x2a, 0, 0}, + {0x9F, 0x2a, 0x2a, 0, 0}, + {0xA0, 0x18, 0x18, 0, 0}, + {0xA1, 0x6a, 0x6a, 1, 1}, + {0xA2, 0xab, 0xab, 1, 1}, + {0xA3, 0x13, 0x13, 1, 1}, + {0xA4, 0xc1, 0xc1, 1, 1}, + {0xA5, 0xaa, 0xaa, 1, 1}, + {0xA6, 0x87, 0x87, 1, 1}, + {0xA7, 0, 0, 0, 0}, + {0xA8, 0x6, 0x6, 0, 0}, + {0xA9, 0x7, 0x7, 0, 0}, + {0xAA, 0x7, 0x7, 0, 0}, + {0xAB, 0x15, 0x15, 0, 0}, + {0xAC, 0x55, 0x55, 0, 0}, + {0xAD, 0x97, 0x97, 1, 1}, + {0xAE, 0x8, 0x8, 0, 0}, + {0xAF, 0x14, 0x14, 1, 1}, + {0xB0, 0x33, 0x33, 0, 0}, + {0xB1, 0x88, 0x88, 0, 0}, + {0xB2, 0x6, 0x6, 0, 0}, + {0xB3, 0x3, 0x3, 1, 1}, + {0xB4, 0xa, 0xa, 0, 0}, + {0xB5, 0x3, 0x3, 1, 1}, + {0xB6, 0x2a, 0x2a, 0, 0}, + {0xB7, 0xa4, 0xa4, 0, 0}, + {0xB8, 0x18, 0x18, 0, 0}, + {0xB9, 0x28, 0x28, 0, 0}, + {0xBA, 0, 0, 0, 0}, + {0xBB, 0x4a, 0x4a, 0, 0}, + {0xBC, 0, 0, 0, 0}, + {0xBD, 0x71, 0x71, 0, 0}, + {0xBE, 0x72, 0x72, 0, 0}, + {0xBF, 0x73, 0x73, 0, 0}, + {0xC0, 0x74, 0x74, 0, 0}, + {0xC1, 0x75, 0x75, 0, 0}, + {0xC2, 0x76, 0x76, 0, 0}, + {0xC3, 0x77, 0x77, 0, 0}, + {0xC4, 0x78, 0x78, 0, 0}, + {0xC5, 0x79, 0x79, 0, 0}, + {0xC6, 0x7a, 0x7a, 0, 0}, + {0xC7, 0, 0, 0, 0}, + {0xC8, 0, 0, 0, 0}, + {0xC9, 0, 0, 0, 0}, + {0xCA, 0, 0, 0, 0}, + {0xCB, 0, 0, 0, 0}, + {0xCC, 0, 0, 0, 0}, + {0xCD, 0, 0, 0, 0}, + {0xCE, 0x6, 0x6, 0, 0}, + {0xCF, 0, 0, 0, 0}, + {0xD0, 0, 0, 0, 0}, + {0xD1, 0x18, 0x18, 0, 0}, + {0xD2, 0x88, 0x88, 0, 0}, + {0xD3, 0, 0, 0, 0}, + {0xD4, 0, 0, 0, 0}, + {0xD5, 0, 0, 0, 0}, + {0xD6, 0, 0, 0, 0}, + {0xD7, 0, 0, 0, 0}, + {0xD8, 0, 0, 0, 0}, + {0xD9, 0, 0, 0, 0}, + {0xDA, 0x6, 0x6, 0, 0}, + {0xDB, 0, 0, 0, 0}, + {0xDC, 0, 0, 0, 0}, + {0xDD, 0x18, 0x18, 0, 0}, + {0xDE, 0x88, 0x88, 0, 0}, + {0xDF, 0, 0, 0, 0}, + {0xE0, 0, 0, 0, 0}, + {0xE1, 0, 0, 0, 0}, + {0xE2, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static struct radio_regs regs_SYN_2056[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0x1, 0x1, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0x60, 0x60, 0, 0}, + {0x23, 0x6, 0x6, 0, 0}, + {0x24, 0xc, 0xc, 0, 0}, + {0x25, 0, 0, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0, 0, 0, 0}, + {0x28, 0x1, 0x1, 0, 0}, + {0x29, 0, 0, 0, 0}, + {0x2A, 0, 0, 0, 0}, + {0x2B, 0, 0, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0xd, 0xd, 0, 0}, + {0x2F, 0x1f, 0x1f, 0, 0}, + {0x30, 0x15, 0x15, 0, 0}, + {0x31, 0xf, 0xf, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0, 0, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0, 0, 0, 0}, + {0x38, 0, 0, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0, 0, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x13, 0x13, 0, 0}, + {0x3D, 0xf, 0xf, 0, 0}, + {0x3E, 0x18, 0x18, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x20, 0x20, 0, 0}, + {0x42, 0x20, 0x20, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x77, 0x77, 0, 0}, + {0x45, 0x7, 0x7, 0, 0}, + {0x46, 0x1, 0x1, 0, 0}, + {0x47, 0x4, 0x4, 0, 0}, + {0x48, 0xf, 0xf, 0, 0}, + {0x49, 0x30, 0x30, 0, 0}, + {0x4A, 0x32, 0x32, 0, 0}, + {0x4B, 0xd, 0xd, 0, 0}, + {0x4C, 0xd, 0xd, 0, 0}, + {0x4D, 0x4, 0x4, 0, 0}, + {0x4E, 0x6, 0x6, 0, 0}, + {0x4F, 0x1, 0x1, 0, 0}, + {0x50, 0x1c, 0x1c, 0, 0}, + {0x51, 0x2, 0x2, 0, 0}, + {0x52, 0x2, 0x2, 0, 0}, + {0x53, 0xf7, 0xf7, 1, 1}, + {0x54, 0xb4, 0xb4, 0, 0}, + {0x55, 0xd2, 0xd2, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x4, 0x4, 0, 0}, + {0x59, 0x96, 0x96, 0, 0}, + {0x5A, 0x3e, 0x3e, 0, 0}, + {0x5B, 0x3e, 0x3e, 0, 0}, + {0x5C, 0x13, 0x13, 0, 0}, + {0x5D, 0x2, 0x2, 0, 0}, + {0x5E, 0, 0, 0, 0}, + {0x5F, 0x7, 0x7, 0, 0}, + {0x60, 0x7, 0x7, 1, 1}, + {0x61, 0x8, 0x8, 0, 0}, + {0x62, 0x3, 0x3, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0x40, 0x40, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0x1, 0x1, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0x60, 0x60, 0, 0}, + {0x71, 0x66, 0x66, 0, 0}, + {0x72, 0xc, 0xc, 0, 0}, + {0x73, 0x66, 0x66, 0, 0}, + {0x74, 0x8f, 0x8f, 1, 1}, + {0x75, 0, 0, 0, 0}, + {0x76, 0xcc, 0xcc, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0x66, 0x66, 0, 0}, + {0x79, 0x66, 0x66, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0xff, 0xff, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0, 0, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0, 0, 0, 0}, + {0x9A, 0, 0, 0, 0}, + {0x9B, 0, 0, 0, 0}, + {0x9C, 0, 0, 0, 0}, + {0x9D, 0, 0, 0, 0}, + {0x9E, 0, 0, 0, 0}, + {0x9F, 0x6, 0x6, 0, 0}, + {0xA0, 0x66, 0x66, 0, 0}, + {0xA1, 0x66, 0x66, 0, 0}, + {0xA2, 0x66, 0x66, 0, 0}, + {0xA3, 0x66, 0x66, 0, 0}, + {0xA4, 0x66, 0x66, 0, 0}, + {0xA5, 0x66, 0x66, 0, 0}, + {0xA6, 0x66, 0x66, 0, 0}, + {0xA7, 0x66, 0x66, 0, 0}, + {0xA8, 0x66, 0x66, 0, 0}, + {0xA9, 0x66, 0x66, 0, 0}, + {0xAA, 0x66, 0x66, 0, 0}, + {0xAB, 0x66, 0x66, 0, 0}, + {0xAC, 0x66, 0x66, 0, 0}, + {0xAD, 0x66, 0x66, 0, 0}, + {0xAE, 0x66, 0x66, 0, 0}, + {0xAF, 0x66, 0x66, 0, 0}, + {0xB0, 0x66, 0x66, 0, 0}, + {0xB1, 0x66, 0x66, 0, 0}, + {0xB2, 0x66, 0x66, 0, 0}, + {0xB3, 0xa, 0xa, 0, 0}, + {0xB4, 0, 0, 0, 0}, + {0xB5, 0, 0, 0, 0}, + {0xB6, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_TX_2056[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0x88, 0x88, 0, 0}, + {0x22, 0x88, 0x88, 0, 0}, + {0x23, 0x88, 0x88, 0, 0}, + {0x24, 0x88, 0x88, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0x3, 0x3, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x3, 0x3, 0, 0}, + {0x2A, 0x37, 0x37, 0, 0}, + {0x2B, 0x3, 0x3, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0x1, 0x1, 0, 0}, + {0x2F, 0x1, 0x1, 0, 0}, + {0x30, 0, 0, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0x11, 0x11, 0, 0}, + {0x34, 0x11, 0x11, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x3, 0x3, 0, 0}, + {0x38, 0xf, 0xf, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0x2d, 0x2d, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x6e, 0x6e, 0, 0}, + {0x3D, 0xf0, 0xf0, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x3, 0x3, 0, 0}, + {0x42, 0x3, 0x3, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x1e, 0x1e, 0, 0}, + {0x45, 0, 0, 0, 0}, + {0x46, 0x6e, 0x6e, 0, 0}, + {0x47, 0xf0, 0xf0, 1, 1}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x2, 0x2, 0, 0}, + {0x4A, 0xff, 0xff, 1, 1}, + {0x4B, 0xc, 0xc, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0x38, 0x38, 0, 0}, + {0x4E, 0x70, 0x70, 1, 1}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0x88, 0x88, 0, 0}, + {0x51, 0xc, 0xc, 0, 0}, + {0x52, 0, 0, 0, 0}, + {0x53, 0x8, 0x8, 0, 0}, + {0x54, 0x70, 0x70, 1, 1}, + {0x55, 0x2, 0x2, 0, 0}, + {0x56, 0xff, 0xff, 1, 1}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x83, 0x83, 0, 0}, + {0x59, 0x77, 0x77, 1, 1}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x88, 0x88, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x8, 0x8, 0, 0}, + {0x5F, 0x77, 0x77, 1, 1}, + {0x60, 0x1, 0x1, 0, 0}, + {0x61, 0, 0, 0, 0}, + {0x62, 0x7, 0x7, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0x7, 0x7, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0x74, 0x74, 1, 1}, + {0x68, 0, 0, 0, 0}, + {0x69, 0xa, 0xa, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0x2, 0x2, 0, 0}, + {0x72, 0, 0, 0, 0}, + {0x73, 0, 0, 0, 0}, + {0x74, 0xe, 0xe, 0, 0}, + {0x75, 0xe, 0xe, 0, 0}, + {0x76, 0xe, 0xe, 0, 0}, + {0x77, 0x13, 0x13, 0, 0}, + {0x78, 0x13, 0x13, 0, 0}, + {0x79, 0x1b, 0x1b, 0, 0}, + {0x7A, 0x1b, 0x1b, 0, 0}, + {0x7B, 0x55, 0x55, 0, 0}, + {0x7C, 0x5b, 0x5b, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_RX_2056[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0x3, 0x3, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0, 0, 0, 0}, + {0x23, 0x90, 0x90, 0, 0}, + {0x24, 0x55, 0x55, 0, 0}, + {0x25, 0x15, 0x15, 0, 0}, + {0x26, 0x5, 0x5, 0, 0}, + {0x27, 0x15, 0x15, 0, 0}, + {0x28, 0x5, 0x5, 0, 0}, + {0x29, 0x20, 0x20, 0, 0}, + {0x2A, 0x11, 0x11, 0, 0}, + {0x2B, 0x90, 0x90, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0x88, 0x88, 0, 0}, + {0x2E, 0x32, 0x32, 0, 0}, + {0x2F, 0x77, 0x77, 0, 0}, + {0x30, 0x17, 0x17, 1, 1}, + {0x31, 0xff, 0xff, 1, 1}, + {0x32, 0x20, 0x20, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0x88, 0x88, 0, 0}, + {0x35, 0x32, 0x32, 0, 0}, + {0x36, 0x77, 0x77, 0, 0}, + {0x37, 0x17, 0x17, 1, 1}, + {0x38, 0xf0, 0xf0, 1, 1}, + {0x39, 0x20, 0x20, 0, 0}, + {0x3A, 0x8, 0x8, 0, 0}, + {0x3B, 0x99, 0x99, 0, 0}, + {0x3C, 0, 0, 0, 0}, + {0x3D, 0x44, 0x44, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0x44, 0x44, 0, 0}, + {0x40, 0xf, 0xf, 1, 1}, + {0x41, 0x6, 0x6, 0, 0}, + {0x42, 0x4, 0x4, 0, 0}, + {0x43, 0x50, 0x50, 1, 1}, + {0x44, 0x8, 0x8, 0, 0}, + {0x45, 0x99, 0x99, 0, 0}, + {0x46, 0, 0, 0, 0}, + {0x47, 0x11, 0x11, 0, 0}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x44, 0x44, 0, 0}, + {0x4A, 0x7, 0x7, 0, 0}, + {0x4B, 0x6, 0x6, 0, 0}, + {0x4C, 0x4, 0x4, 0, 0}, + {0x4D, 0, 0, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x66, 0x66, 0, 0}, + {0x50, 0x66, 0x66, 0, 0}, + {0x51, 0x57, 0x57, 0, 0}, + {0x52, 0x57, 0x57, 0, 0}, + {0x53, 0x44, 0x44, 0, 0}, + {0x54, 0, 0, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0x8, 0x8, 0, 0}, + {0x57, 0x8, 0x8, 0, 0}, + {0x58, 0x7, 0x7, 0, 0}, + {0x59, 0x22, 0x22, 0, 0}, + {0x5A, 0x22, 0x22, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x23, 0x23, 0, 0}, + {0x5D, 0x7, 0x7, 0, 0}, + {0x5E, 0x55, 0x55, 0, 0}, + {0x5F, 0x23, 0x23, 0, 0}, + {0x60, 0x41, 0x41, 0, 0}, + {0x61, 0x1, 0x1, 0, 0}, + {0x62, 0xa, 0xa, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0, 0, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0xc, 0xc, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0, 0, 0, 0}, + {0x72, 0x22, 0x22, 0, 0}, + {0x73, 0x22, 0x22, 0, 0}, + {0x74, 0x2, 0x2, 0, 0}, + {0x75, 0xa, 0xa, 0, 0}, + {0x76, 0x1, 0x1, 0, 0}, + {0x77, 0x22, 0x22, 0, 0}, + {0x78, 0x30, 0x30, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_SYN_2056_A1[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0x1, 0x1, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0x60, 0x60, 0, 0}, + {0x23, 0x6, 0x6, 0, 0}, + {0x24, 0xc, 0xc, 0, 0}, + {0x25, 0, 0, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0, 0, 0, 0}, + {0x28, 0x1, 0x1, 0, 0}, + {0x29, 0, 0, 0, 0}, + {0x2A, 0, 0, 0, 0}, + {0x2B, 0, 0, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0xd, 0xd, 0, 0}, + {0x2F, 0x1f, 0x1f, 0, 0}, + {0x30, 0x15, 0x15, 0, 0}, + {0x31, 0xf, 0xf, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0, 0, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0, 0, 0, 0}, + {0x38, 0, 0, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0, 0, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x13, 0x13, 0, 0}, + {0x3D, 0xf, 0xf, 0, 0}, + {0x3E, 0x18, 0x18, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x20, 0x20, 0, 0}, + {0x42, 0x20, 0x20, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x77, 0x77, 0, 0}, + {0x45, 0x7, 0x7, 0, 0}, + {0x46, 0x1, 0x1, 0, 0}, + {0x47, 0x4, 0x4, 0, 0}, + {0x48, 0xf, 0xf, 0, 0}, + {0x49, 0x30, 0x30, 0, 0}, + {0x4A, 0x32, 0x32, 0, 0}, + {0x4B, 0xd, 0xd, 0, 0}, + {0x4C, 0xd, 0xd, 0, 0}, + {0x4D, 0x4, 0x4, 0, 0}, + {0x4E, 0x6, 0x6, 0, 0}, + {0x4F, 0x1, 0x1, 0, 0}, + {0x50, 0x1c, 0x1c, 0, 0}, + {0x51, 0x2, 0x2, 0, 0}, + {0x52, 0x2, 0x2, 0, 0}, + {0x53, 0xf7, 0xf7, 1, 1}, + {0x54, 0xb4, 0xb4, 0, 0}, + {0x55, 0xd2, 0xd2, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x4, 0x4, 0, 0}, + {0x59, 0x96, 0x96, 0, 0}, + {0x5A, 0x3e, 0x3e, 0, 0}, + {0x5B, 0x3e, 0x3e, 0, 0}, + {0x5C, 0x13, 0x13, 0, 0}, + {0x5D, 0x2, 0x2, 0, 0}, + {0x5E, 0, 0, 0, 0}, + {0x5F, 0x7, 0x7, 0, 0}, + {0x60, 0x7, 0x7, 1, 1}, + {0x61, 0x8, 0x8, 0, 0}, + {0x62, 0x3, 0x3, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0x40, 0x40, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0x1, 0x1, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0x60, 0x60, 0, 0}, + {0x71, 0x66, 0x66, 0, 0}, + {0x72, 0xc, 0xc, 0, 0}, + {0x73, 0x66, 0x66, 0, 0}, + {0x74, 0x8f, 0x8f, 1, 1}, + {0x75, 0, 0, 0, 0}, + {0x76, 0xcc, 0xcc, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0x66, 0x66, 0, 0}, + {0x79, 0x66, 0x66, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0xff, 0xff, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0, 0, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0, 0, 0, 0}, + {0x9A, 0, 0, 0, 0}, + {0x9B, 0, 0, 0, 0}, + {0x9C, 0, 0, 0, 0}, + {0x9D, 0, 0, 0, 0}, + {0x9E, 0, 0, 0, 0}, + {0x9F, 0x6, 0x6, 0, 0}, + {0xA0, 0x66, 0x66, 0, 0}, + {0xA1, 0x66, 0x66, 0, 0}, + {0xA2, 0x66, 0x66, 0, 0}, + {0xA3, 0x66, 0x66, 0, 0}, + {0xA4, 0x66, 0x66, 0, 0}, + {0xA5, 0x66, 0x66, 0, 0}, + {0xA6, 0x66, 0x66, 0, 0}, + {0xA7, 0x66, 0x66, 0, 0}, + {0xA8, 0x66, 0x66, 0, 0}, + {0xA9, 0x66, 0x66, 0, 0}, + {0xAA, 0x66, 0x66, 0, 0}, + {0xAB, 0x66, 0x66, 0, 0}, + {0xAC, 0x66, 0x66, 0, 0}, + {0xAD, 0x66, 0x66, 0, 0}, + {0xAE, 0x66, 0x66, 0, 0}, + {0xAF, 0x66, 0x66, 0, 0}, + {0xB0, 0x66, 0x66, 0, 0}, + {0xB1, 0x66, 0x66, 0, 0}, + {0xB2, 0x66, 0x66, 0, 0}, + {0xB3, 0xa, 0xa, 0, 0}, + {0xB4, 0, 0, 0, 0}, + {0xB5, 0, 0, 0, 0}, + {0xB6, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_TX_2056_A1[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0x88, 0x88, 0, 0}, + {0x22, 0x88, 0x88, 0, 0}, + {0x23, 0x88, 0x88, 0, 0}, + {0x24, 0x88, 0x88, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0x3, 0x3, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x3, 0x3, 0, 0}, + {0x2A, 0x37, 0x37, 0, 0}, + {0x2B, 0x3, 0x3, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0x1, 0x1, 0, 0}, + {0x2F, 0x1, 0x1, 0, 0}, + {0x30, 0, 0, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0x11, 0x11, 0, 0}, + {0x34, 0x11, 0x11, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x3, 0x3, 0, 0}, + {0x38, 0xf, 0xf, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0x2d, 0x2d, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x6e, 0x6e, 0, 0}, + {0x3D, 0xf0, 0xf0, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x3, 0x3, 0, 0}, + {0x42, 0x3, 0x3, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x1e, 0x1e, 0, 0}, + {0x45, 0, 0, 0, 0}, + {0x46, 0x6e, 0x6e, 0, 0}, + {0x47, 0xf0, 0xf0, 1, 1}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x2, 0x2, 0, 0}, + {0x4A, 0xff, 0xff, 1, 1}, + {0x4B, 0xc, 0xc, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0x38, 0x38, 0, 0}, + {0x4E, 0x70, 0x70, 1, 1}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0x88, 0x88, 0, 0}, + {0x51, 0xc, 0xc, 0, 0}, + {0x52, 0, 0, 0, 0}, + {0x53, 0x8, 0x8, 0, 0}, + {0x54, 0x70, 0x70, 1, 1}, + {0x55, 0x2, 0x2, 0, 0}, + {0x56, 0xff, 0xff, 1, 1}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x83, 0x83, 0, 0}, + {0x59, 0x77, 0x77, 1, 1}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x88, 0x88, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x8, 0x8, 0, 0}, + {0x5F, 0x77, 0x77, 1, 1}, + {0x60, 0x1, 0x1, 0, 0}, + {0x61, 0, 0, 0, 0}, + {0x62, 0x7, 0x7, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0x7, 0x7, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0x72, 0x72, 1, 1}, + {0x68, 0, 0, 0, 0}, + {0x69, 0xa, 0xa, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0x2, 0x2, 0, 0}, + {0x72, 0, 0, 0, 0}, + {0x73, 0, 0, 0, 0}, + {0x74, 0xe, 0xe, 0, 0}, + {0x75, 0xe, 0xe, 0, 0}, + {0x76, 0xe, 0xe, 0, 0}, + {0x77, 0x13, 0x13, 0, 0}, + {0x78, 0x13, 0x13, 0, 0}, + {0x79, 0x1b, 0x1b, 0, 0}, + {0x7A, 0x1b, 0x1b, 0, 0}, + {0x7B, 0x55, 0x55, 0, 0}, + {0x7C, 0x5b, 0x5b, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_RX_2056_A1[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0x3, 0x3, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0, 0, 0, 0}, + {0x23, 0x90, 0x90, 0, 0}, + {0x24, 0x55, 0x55, 0, 0}, + {0x25, 0x15, 0x15, 0, 0}, + {0x26, 0x5, 0x5, 0, 0}, + {0x27, 0x15, 0x15, 0, 0}, + {0x28, 0x5, 0x5, 0, 0}, + {0x29, 0x20, 0x20, 0, 0}, + {0x2A, 0x11, 0x11, 0, 0}, + {0x2B, 0x90, 0x90, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0x88, 0x88, 0, 0}, + {0x2E, 0x32, 0x32, 0, 0}, + {0x2F, 0x77, 0x77, 0, 0}, + {0x30, 0x17, 0x17, 1, 1}, + {0x31, 0xff, 0xff, 1, 1}, + {0x32, 0x20, 0x20, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0x88, 0x88, 0, 0}, + {0x35, 0x32, 0x32, 0, 0}, + {0x36, 0x77, 0x77, 0, 0}, + {0x37, 0x17, 0x17, 1, 1}, + {0x38, 0xf0, 0xf0, 1, 1}, + {0x39, 0x20, 0x20, 0, 0}, + {0x3A, 0x8, 0x8, 0, 0}, + {0x3B, 0x55, 0x55, 1, 1}, + {0x3C, 0, 0, 0, 0}, + {0x3D, 0x44, 0x44, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0x44, 0x44, 0, 0}, + {0x40, 0xf, 0xf, 1, 1}, + {0x41, 0x6, 0x6, 0, 0}, + {0x42, 0x4, 0x4, 0, 0}, + {0x43, 0x50, 0x50, 1, 1}, + {0x44, 0x8, 0x8, 0, 0}, + {0x45, 0x55, 0x55, 1, 1}, + {0x46, 0, 0, 0, 0}, + {0x47, 0x11, 0x11, 0, 0}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x44, 0x44, 0, 0}, + {0x4A, 0x7, 0x7, 0, 0}, + {0x4B, 0x6, 0x6, 0, 0}, + {0x4C, 0x4, 0x4, 0, 0}, + {0x4D, 0, 0, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x26, 0x26, 1, 1}, + {0x50, 0x26, 0x26, 1, 1}, + {0x51, 0xf, 0xf, 1, 1}, + {0x52, 0xf, 0xf, 1, 1}, + {0x53, 0x44, 0x44, 0, 0}, + {0x54, 0, 0, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0x8, 0x8, 0, 0}, + {0x57, 0x8, 0x8, 0, 0}, + {0x58, 0x7, 0x7, 0, 0}, + {0x59, 0x22, 0x22, 0, 0}, + {0x5A, 0x22, 0x22, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x2f, 0x2f, 1, 1}, + {0x5D, 0x7, 0x7, 0, 0}, + {0x5E, 0x55, 0x55, 0, 0}, + {0x5F, 0x23, 0x23, 0, 0}, + {0x60, 0x41, 0x41, 0, 0}, + {0x61, 0x1, 0x1, 0, 0}, + {0x62, 0xa, 0xa, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0, 0, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0xc, 0xc, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0, 0, 0, 0}, + {0x72, 0x22, 0x22, 0, 0}, + {0x73, 0x22, 0x22, 0, 0}, + {0x74, 0, 0, 1, 1}, + {0x75, 0xa, 0xa, 0, 0}, + {0x76, 0x1, 0x1, 0, 0}, + {0x77, 0x22, 0x22, 0, 0}, + {0x78, 0x30, 0x30, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_SYN_2056_rev5[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0x1, 0x1, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0x60, 0x60, 0, 0}, + {0x23, 0x6, 0x6, 0, 0}, + {0x24, 0xc, 0xc, 0, 0}, + {0x25, 0, 0, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0, 0, 0, 0}, + {0x28, 0x1, 0x1, 0, 0}, + {0x29, 0, 0, 0, 0}, + {0x2A, 0, 0, 0, 0}, + {0x2B, 0, 0, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0, 0, 0, 0}, + {0x2F, 0x1f, 0x1f, 0, 0}, + {0x30, 0x15, 0x15, 0, 0}, + {0x31, 0xf, 0xf, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0, 0, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0, 0, 0, 0}, + {0x38, 0, 0, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0, 0, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x13, 0x13, 0, 0}, + {0x3D, 0xf, 0xf, 0, 0}, + {0x3E, 0x18, 0x18, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x20, 0x20, 0, 0}, + {0x42, 0x20, 0x20, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x77, 0x77, 0, 0}, + {0x45, 0x7, 0x7, 0, 0}, + {0x46, 0x1, 0x1, 0, 0}, + {0x47, 0x4, 0x4, 0, 0}, + {0x48, 0xf, 0xf, 0, 0}, + {0x49, 0x30, 0x30, 0, 0}, + {0x4A, 0x32, 0x32, 0, 0}, + {0x4B, 0xd, 0xd, 0, 0}, + {0x4C, 0xd, 0xd, 0, 0}, + {0x4D, 0x4, 0x4, 0, 0}, + {0x4E, 0x6, 0x6, 0, 0}, + {0x4F, 0x1, 0x1, 0, 0}, + {0x50, 0x1c, 0x1c, 0, 0}, + {0x51, 0x2, 0x2, 0, 0}, + {0x52, 0x2, 0x2, 0, 0}, + {0x53, 0xf7, 0xf7, 1, 1}, + {0x54, 0xb4, 0xb4, 0, 0}, + {0x55, 0xd2, 0xd2, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x4, 0x4, 0, 0}, + {0x59, 0x96, 0x96, 0, 0}, + {0x5A, 0x3e, 0x3e, 0, 0}, + {0x5B, 0x3e, 0x3e, 0, 0}, + {0x5C, 0x13, 0x13, 0, 0}, + {0x5D, 0x2, 0x2, 0, 0}, + {0x5E, 0, 0, 0, 0}, + {0x5F, 0x7, 0x7, 0, 0}, + {0x60, 0x7, 0x7, 1, 1}, + {0x61, 0x8, 0x8, 0, 0}, + {0x62, 0x3, 0x3, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0x40, 0x40, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0x1, 0x1, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0x60, 0x60, 0, 0}, + {0x71, 0x66, 0x66, 0, 0}, + {0x72, 0xc, 0xc, 0, 0}, + {0x73, 0x66, 0x66, 0, 0}, + {0x74, 0x8f, 0x8f, 1, 1}, + {0x75, 0, 0, 0, 0}, + {0x76, 0xcc, 0xcc, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0x66, 0x66, 0, 0}, + {0x79, 0x66, 0x66, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0xff, 0xff, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0, 0, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0, 0, 0, 0}, + {0x9A, 0, 0, 0, 0}, + {0x9B, 0, 0, 0, 0}, + {0x9C, 0, 0, 0, 0}, + {0x9D, 0, 0, 0, 0}, + {0x9E, 0, 0, 0, 0}, + {0x9F, 0x6, 0x6, 0, 0}, + {0xA0, 0x66, 0x66, 0, 0}, + {0xA1, 0x66, 0x66, 0, 0}, + {0xA2, 0x66, 0x66, 0, 0}, + {0xA3, 0x66, 0x66, 0, 0}, + {0xA4, 0x66, 0x66, 0, 0}, + {0xA5, 0x66, 0x66, 0, 0}, + {0xA6, 0x66, 0x66, 0, 0}, + {0xA7, 0x66, 0x66, 0, 0}, + {0xA8, 0x66, 0x66, 0, 0}, + {0xA9, 0x66, 0x66, 0, 0}, + {0xAA, 0x66, 0x66, 0, 0}, + {0xAB, 0x66, 0x66, 0, 0}, + {0xAC, 0x66, 0x66, 0, 0}, + {0xAD, 0x66, 0x66, 0, 0}, + {0xAE, 0x66, 0x66, 0, 0}, + {0xAF, 0x66, 0x66, 0, 0}, + {0xB0, 0x66, 0x66, 0, 0}, + {0xB1, 0x66, 0x66, 0, 0}, + {0xB2, 0x66, 0x66, 0, 0}, + {0xB3, 0xa, 0xa, 0, 0}, + {0xB4, 0, 0, 0, 0}, + {0xB5, 0, 0, 0, 0}, + {0xB6, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_TX_2056_rev5[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0x88, 0x88, 0, 0}, + {0x22, 0x88, 0x88, 0, 0}, + {0x23, 0x88, 0x88, 0, 0}, + {0x24, 0x88, 0x88, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0x3, 0x3, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x3, 0x3, 0, 0}, + {0x2A, 0x37, 0x37, 0, 0}, + {0x2B, 0x3, 0x3, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0x1, 0x1, 0, 0}, + {0x2F, 0x1, 0x1, 0, 0}, + {0x30, 0, 0, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0x11, 0x11, 0, 0}, + {0x34, 0x11, 0x11, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x3, 0x3, 0, 0}, + {0x38, 0xf, 0xf, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0x2d, 0x2d, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x6e, 0x6e, 0, 0}, + {0x3D, 0xf0, 0xf0, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x3, 0x3, 0, 0}, + {0x42, 0x3, 0x3, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x1e, 0x1e, 0, 0}, + {0x45, 0, 0, 0, 0}, + {0x46, 0x6e, 0x6e, 0, 0}, + {0x47, 0xf0, 0xf0, 1, 1}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x2, 0x2, 0, 0}, + {0x4A, 0xff, 0xff, 1, 1}, + {0x4B, 0xc, 0xc, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0x38, 0x38, 0, 0}, + {0x4E, 0x70, 0x70, 1, 1}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0x88, 0x88, 0, 0}, + {0x51, 0xc, 0xc, 0, 0}, + {0x52, 0, 0, 0, 0}, + {0x53, 0x8, 0x8, 0, 0}, + {0x54, 0x70, 0x70, 1, 1}, + {0x55, 0x2, 0x2, 0, 0}, + {0x56, 0xff, 0xff, 1, 1}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x83, 0x83, 0, 0}, + {0x59, 0x77, 0x77, 1, 1}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x88, 0x88, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x8, 0x8, 0, 0}, + {0x5F, 0x77, 0x77, 1, 1}, + {0x60, 0x1, 0x1, 0, 0}, + {0x61, 0, 0, 0, 0}, + {0x62, 0x7, 0x7, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0x7, 0x7, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 1, 1}, + {0x68, 0, 0, 0, 0}, + {0x69, 0xa, 0xa, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0x2, 0x2, 0, 0}, + {0x72, 0, 0, 0, 0}, + {0x73, 0, 0, 0, 0}, + {0x74, 0xe, 0xe, 0, 0}, + {0x75, 0xe, 0xe, 0, 0}, + {0x76, 0xe, 0xe, 0, 0}, + {0x77, 0x13, 0x13, 0, 0}, + {0x78, 0x13, 0x13, 0, 0}, + {0x79, 0x1b, 0x1b, 0, 0}, + {0x7A, 0x1b, 0x1b, 0, 0}, + {0x7B, 0x55, 0x55, 0, 0}, + {0x7C, 0x5b, 0x5b, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0x70, 0x70, 0, 0}, + {0x94, 0x70, 0x70, 0, 0}, + {0x95, 0x71, 0x71, 1, 1}, + {0x96, 0x71, 0x71, 1, 1}, + {0x97, 0x72, 0x72, 1, 1}, + {0x98, 0x73, 0x73, 1, 1}, + {0x99, 0x74, 0x74, 1, 1}, + {0x9A, 0x75, 0x75, 1, 1}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_RX_2056_rev5[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0x3, 0x3, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0, 0, 0, 0}, + {0x23, 0x90, 0x90, 0, 0}, + {0x24, 0x55, 0x55, 0, 0}, + {0x25, 0x15, 0x15, 0, 0}, + {0x26, 0x5, 0x5, 0, 0}, + {0x27, 0x15, 0x15, 0, 0}, + {0x28, 0x5, 0x5, 0, 0}, + {0x29, 0x20, 0x20, 0, 0}, + {0x2A, 0x11, 0x11, 0, 0}, + {0x2B, 0x90, 0x90, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0x88, 0x88, 0, 0}, + {0x2E, 0x32, 0x32, 0, 0}, + {0x2F, 0x77, 0x77, 0, 0}, + {0x30, 0x17, 0x17, 1, 1}, + {0x31, 0xff, 0xff, 1, 1}, + {0x32, 0x20, 0x20, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0x88, 0x88, 0, 0}, + {0x35, 0x32, 0x32, 0, 0}, + {0x36, 0x77, 0x77, 0, 0}, + {0x37, 0x17, 0x17, 1, 1}, + {0x38, 0xf0, 0xf0, 1, 1}, + {0x39, 0x20, 0x20, 0, 0}, + {0x3A, 0x8, 0x8, 0, 0}, + {0x3B, 0x55, 0x55, 1, 1}, + {0x3C, 0, 0, 0, 0}, + {0x3D, 0x88, 0x88, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 1, 1}, + {0x40, 0x7, 0x7, 1, 1}, + {0x41, 0x6, 0x6, 0, 0}, + {0x42, 0x4, 0x4, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x8, 0x8, 0, 0}, + {0x45, 0x55, 0x55, 1, 1}, + {0x46, 0, 0, 0, 0}, + {0x47, 0x11, 0x11, 0, 0}, + {0x48, 0, 0, 0, 0}, + {0x49, 0, 0, 1, 1}, + {0x4A, 0x7, 0x7, 0, 0}, + {0x4B, 0x6, 0x6, 0, 0}, + {0x4C, 0x4, 0x4, 0, 0}, + {0x4D, 0, 0, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x26, 0x26, 1, 1}, + {0x50, 0x26, 0x26, 1, 1}, + {0x51, 0xf, 0xf, 1, 1}, + {0x52, 0xf, 0xf, 1, 1}, + {0x53, 0x44, 0x44, 0, 0}, + {0x54, 0, 0, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0x8, 0x8, 0, 0}, + {0x57, 0x8, 0x8, 0, 0}, + {0x58, 0x7, 0x7, 0, 0}, + {0x59, 0x22, 0x22, 0, 0}, + {0x5A, 0x22, 0x22, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x4, 0x4, 1, 1}, + {0x5D, 0x7, 0x7, 0, 0}, + {0x5E, 0x55, 0x55, 0, 0}, + {0x5F, 0x23, 0x23, 0, 0}, + {0x60, 0x41, 0x41, 0, 0}, + {0x61, 0x1, 0x1, 0, 0}, + {0x62, 0xa, 0xa, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0, 0, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0xc, 0xc, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0, 0, 0, 0}, + {0x72, 0x22, 0x22, 0, 0}, + {0x73, 0x22, 0x22, 0, 0}, + {0x74, 0, 0, 1, 1}, + {0x75, 0xa, 0xa, 0, 0}, + {0x76, 0x1, 0x1, 0, 0}, + {0x77, 0x22, 0x22, 0, 0}, + {0x78, 0x30, 0x30, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_SYN_2056_rev6[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0x1, 0x1, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0x60, 0x60, 0, 0}, + {0x23, 0x6, 0x6, 0, 0}, + {0x24, 0xc, 0xc, 0, 0}, + {0x25, 0, 0, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0, 0, 0, 0}, + {0x28, 0x1, 0x1, 0, 0}, + {0x29, 0, 0, 0, 0}, + {0x2A, 0, 0, 0, 0}, + {0x2B, 0, 0, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0, 0, 0, 0}, + {0x2F, 0x1f, 0x1f, 0, 0}, + {0x30, 0x15, 0x15, 0, 0}, + {0x31, 0xf, 0xf, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0, 0, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0, 0, 0, 0}, + {0x38, 0, 0, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0, 0, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x13, 0x13, 0, 0}, + {0x3D, 0xf, 0xf, 0, 0}, + {0x3E, 0x18, 0x18, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x20, 0x20, 0, 0}, + {0x42, 0x20, 0x20, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x77, 0x77, 0, 0}, + {0x45, 0x7, 0x7, 0, 0}, + {0x46, 0x1, 0x1, 0, 0}, + {0x47, 0x4, 0x4, 0, 0}, + {0x48, 0xf, 0xf, 0, 0}, + {0x49, 0x30, 0x30, 0, 0}, + {0x4A, 0x32, 0x32, 0, 0}, + {0x4B, 0xd, 0xd, 0, 0}, + {0x4C, 0xd, 0xd, 0, 0}, + {0x4D, 0x4, 0x4, 0, 0}, + {0x4E, 0x6, 0x6, 0, 0}, + {0x4F, 0x1, 0x1, 0, 0}, + {0x50, 0x1c, 0x1c, 0, 0}, + {0x51, 0x2, 0x2, 0, 0}, + {0x52, 0x2, 0x2, 0, 0}, + {0x53, 0xf7, 0xf7, 1, 1}, + {0x54, 0xb4, 0xb4, 0, 0}, + {0x55, 0xd2, 0xd2, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x4, 0x4, 0, 0}, + {0x59, 0x96, 0x96, 0, 0}, + {0x5A, 0x3e, 0x3e, 0, 0}, + {0x5B, 0x3e, 0x3e, 0, 0}, + {0x5C, 0x13, 0x13, 0, 0}, + {0x5D, 0x2, 0x2, 0, 0}, + {0x5E, 0, 0, 0, 0}, + {0x5F, 0x7, 0x7, 0, 0}, + {0x60, 0x7, 0x7, 1, 1}, + {0x61, 0x8, 0x8, 0, 0}, + {0x62, 0x3, 0x3, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0x40, 0x40, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0x1, 0x1, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0x60, 0x60, 0, 0}, + {0x71, 0x66, 0x66, 0, 0}, + {0x72, 0xc, 0xc, 0, 0}, + {0x73, 0x66, 0x66, 0, 0}, + {0x74, 0x8f, 0x8f, 1, 1}, + {0x75, 0, 0, 0, 0}, + {0x76, 0xcc, 0xcc, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0x66, 0x66, 0, 0}, + {0x79, 0x66, 0x66, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0xff, 0xff, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0, 0, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0, 0, 0, 0}, + {0x9A, 0, 0, 0, 0}, + {0x9B, 0, 0, 0, 0}, + {0x9C, 0, 0, 0, 0}, + {0x9D, 0, 0, 0, 0}, + {0x9E, 0, 0, 0, 0}, + {0x9F, 0x6, 0x6, 0, 0}, + {0xA0, 0x66, 0x66, 0, 0}, + {0xA1, 0x66, 0x66, 0, 0}, + {0xA2, 0x66, 0x66, 0, 0}, + {0xA3, 0x66, 0x66, 0, 0}, + {0xA4, 0x66, 0x66, 0, 0}, + {0xA5, 0x66, 0x66, 0, 0}, + {0xA6, 0x66, 0x66, 0, 0}, + {0xA7, 0x66, 0x66, 0, 0}, + {0xA8, 0x66, 0x66, 0, 0}, + {0xA9, 0x66, 0x66, 0, 0}, + {0xAA, 0x66, 0x66, 0, 0}, + {0xAB, 0x66, 0x66, 0, 0}, + {0xAC, 0x66, 0x66, 0, 0}, + {0xAD, 0x66, 0x66, 0, 0}, + {0xAE, 0x66, 0x66, 0, 0}, + {0xAF, 0x66, 0x66, 0, 0}, + {0xB0, 0x66, 0x66, 0, 0}, + {0xB1, 0x66, 0x66, 0, 0}, + {0xB2, 0x66, 0x66, 0, 0}, + {0xB3, 0xa, 0xa, 0, 0}, + {0xB4, 0, 0, 0, 0}, + {0xB5, 0, 0, 0, 0}, + {0xB6, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_TX_2056_rev6[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0x88, 0x88, 0, 0}, + {0x22, 0x88, 0x88, 0, 0}, + {0x23, 0x88, 0x88, 0, 0}, + {0x24, 0x88, 0x88, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0x3, 0x3, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x3, 0x3, 0, 0}, + {0x2A, 0x37, 0x37, 0, 0}, + {0x2B, 0x3, 0x3, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0x1, 0x1, 0, 0}, + {0x2F, 0x1, 0x1, 0, 0}, + {0x30, 0, 0, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0x11, 0x11, 0, 0}, + {0x34, 0xee, 0xee, 1, 1}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x3, 0x3, 0, 0}, + {0x38, 0x50, 0x50, 1, 1}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0x50, 0x50, 1, 1}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x6e, 0x6e, 0, 0}, + {0x3D, 0xf0, 0xf0, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x3, 0x3, 0, 0}, + {0x42, 0x3, 0x3, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x1e, 0x1e, 0, 0}, + {0x45, 0, 0, 0, 0}, + {0x46, 0x6e, 0x6e, 0, 0}, + {0x47, 0xf0, 0xf0, 1, 1}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x2, 0x2, 0, 0}, + {0x4A, 0xff, 0xff, 1, 1}, + {0x4B, 0xc, 0xc, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0x38, 0x38, 0, 0}, + {0x4E, 0x70, 0x70, 1, 1}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0x88, 0x88, 0, 0}, + {0x51, 0xc, 0xc, 0, 0}, + {0x52, 0, 0, 0, 0}, + {0x53, 0x8, 0x8, 0, 0}, + {0x54, 0x70, 0x70, 1, 1}, + {0x55, 0x2, 0x2, 0, 0}, + {0x56, 0xff, 0xff, 1, 1}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x83, 0x83, 0, 0}, + {0x59, 0x77, 0x77, 1, 1}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x88, 0x88, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x8, 0x8, 0, 0}, + {0x5F, 0x77, 0x77, 1, 1}, + {0x60, 0x1, 0x1, 0, 0}, + {0x61, 0, 0, 0, 0}, + {0x62, 0x7, 0x7, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0x7, 0x7, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 1, 1}, + {0x68, 0, 0, 0, 0}, + {0x69, 0xa, 0xa, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0x2, 0x2, 0, 0}, + {0x72, 0, 0, 0, 0}, + {0x73, 0, 0, 0, 0}, + {0x74, 0xe, 0xe, 0, 0}, + {0x75, 0xe, 0xe, 0, 0}, + {0x76, 0xe, 0xe, 0, 0}, + {0x77, 0x13, 0x13, 0, 0}, + {0x78, 0x13, 0x13, 0, 0}, + {0x79, 0x1b, 0x1b, 0, 0}, + {0x7A, 0x1b, 0x1b, 0, 0}, + {0x7B, 0x55, 0x55, 0, 0}, + {0x7C, 0x5b, 0x5b, 0, 0}, + {0x7D, 0x30, 0x30, 1, 1}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0x70, 0x70, 0, 0}, + {0x94, 0x70, 0x70, 0, 0}, + {0x95, 0x70, 0x70, 0, 0}, + {0x96, 0x70, 0x70, 0, 0}, + {0x97, 0x70, 0x70, 0, 0}, + {0x98, 0x70, 0x70, 0, 0}, + {0x99, 0x70, 0x70, 0, 0}, + {0x9A, 0x70, 0x70, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_RX_2056_rev6[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0x3, 0x3, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0, 0, 0, 0}, + {0x23, 0x90, 0x90, 0, 0}, + {0x24, 0x55, 0x55, 0, 0}, + {0x25, 0x15, 0x15, 0, 0}, + {0x26, 0x5, 0x5, 0, 0}, + {0x27, 0x15, 0x15, 0, 0}, + {0x28, 0x5, 0x5, 0, 0}, + {0x29, 0x20, 0x20, 0, 0}, + {0x2A, 0x11, 0x11, 0, 0}, + {0x2B, 0x90, 0x90, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0x88, 0x88, 0, 0}, + {0x2E, 0x32, 0x32, 0, 0}, + {0x2F, 0x77, 0x77, 0, 0}, + {0x30, 0x17, 0x17, 1, 1}, + {0x31, 0xff, 0xff, 1, 1}, + {0x32, 0x20, 0x20, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0x88, 0x88, 0, 0}, + {0x35, 0x32, 0x32, 0, 0}, + {0x36, 0x77, 0x77, 0, 0}, + {0x37, 0x17, 0x17, 1, 1}, + {0x38, 0xf0, 0xf0, 1, 1}, + {0x39, 0x20, 0x20, 0, 0}, + {0x3A, 0x8, 0x8, 0, 0}, + {0x3B, 0x55, 0x55, 1, 1}, + {0x3C, 0, 0, 0, 0}, + {0x3D, 0x88, 0x88, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0x44, 0x44, 0, 0}, + {0x40, 0x7, 0x7, 1, 1}, + {0x41, 0x6, 0x6, 0, 0}, + {0x42, 0x4, 0x4, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x8, 0x8, 0, 0}, + {0x45, 0x55, 0x55, 1, 1}, + {0x46, 0, 0, 0, 0}, + {0x47, 0x11, 0x11, 0, 0}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x44, 0x44, 0, 0}, + {0x4A, 0x7, 0x7, 0, 0}, + {0x4B, 0x6, 0x6, 0, 0}, + {0x4C, 0x4, 0x4, 0, 0}, + {0x4D, 0, 0, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x26, 0x26, 1, 1}, + {0x50, 0x26, 0x26, 1, 1}, + {0x51, 0xf, 0xf, 1, 1}, + {0x52, 0xf, 0xf, 1, 1}, + {0x53, 0x44, 0x44, 0, 0}, + {0x54, 0, 0, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0x8, 0x8, 0, 0}, + {0x57, 0x8, 0x8, 0, 0}, + {0x58, 0x7, 0x7, 0, 0}, + {0x59, 0x22, 0x22, 0, 0}, + {0x5A, 0x22, 0x22, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x4, 0x4, 1, 1}, + {0x5D, 0x7, 0x7, 0, 0}, + {0x5E, 0x55, 0x55, 0, 0}, + {0x5F, 0x23, 0x23, 0, 0}, + {0x60, 0x41, 0x41, 0, 0}, + {0x61, 0x1, 0x1, 0, 0}, + {0x62, 0xa, 0xa, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0, 0, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0xc, 0xc, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0, 0, 0, 0}, + {0x72, 0x22, 0x22, 0, 0}, + {0x73, 0x22, 0x22, 0, 0}, + {0x74, 0, 0, 1, 1}, + {0x75, 0xa, 0xa, 0, 0}, + {0x76, 0x1, 0x1, 0, 0}, + {0x77, 0x22, 0x22, 0, 0}, + {0x78, 0x30, 0x30, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0x5, 0x5, 1, 1}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0} +}; + +static struct radio_regs regs_SYN_2056_rev7[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0x1, 0x1, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0x60, 0x60, 0, 0}, + {0x23, 0x6, 0x6, 0, 0}, + {0x24, 0xc, 0xc, 0, 0}, + {0x25, 0, 0, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0, 0, 0, 0}, + {0x28, 0x1, 0x1, 0, 0}, + {0x29, 0, 0, 0, 0}, + {0x2A, 0, 0, 0, 0}, + {0x2B, 0, 0, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0, 0, 0, 0}, + {0x2F, 0x1f, 0x1f, 0, 0}, + {0x30, 0x15, 0x15, 0, 0}, + {0x31, 0xf, 0xf, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0, 0, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0, 0, 0, 0}, + {0x38, 0, 0, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0, 0, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x13, 0x13, 0, 0}, + {0x3D, 0xf, 0xf, 0, 0}, + {0x3E, 0x18, 0x18, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x20, 0x20, 0, 0}, + {0x42, 0x20, 0x20, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x77, 0x77, 0, 0}, + {0x45, 0x7, 0x7, 0, 0}, + {0x46, 0x1, 0x1, 0, 0}, + {0x47, 0x4, 0x4, 0, 0}, + {0x48, 0xf, 0xf, 0, 0}, + {0x49, 0x30, 0x30, 0, 0}, + {0x4A, 0x32, 0x32, 0, 0}, + {0x4B, 0xd, 0xd, 0, 0}, + {0x4C, 0xd, 0xd, 0, 0}, + {0x4D, 0x4, 0x4, 0, 0}, + {0x4E, 0x6, 0x6, 0, 0}, + {0x4F, 0x1, 0x1, 0, 0}, + {0x50, 0x1c, 0x1c, 0, 0}, + {0x51, 0x2, 0x2, 0, 0}, + {0x52, 0x2, 0x2, 0, 0}, + {0x53, 0xf7, 0xf7, 1, 1}, + {0x54, 0xb4, 0xb4, 0, 0}, + {0x55, 0xd2, 0xd2, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x4, 0x4, 0, 0}, + {0x59, 0x96, 0x96, 0, 0}, + {0x5A, 0x3e, 0x3e, 0, 0}, + {0x5B, 0x3e, 0x3e, 0, 0}, + {0x5C, 0x13, 0x13, 0, 0}, + {0x5D, 0x2, 0x2, 0, 0}, + {0x5E, 0, 0, 0, 0}, + {0x5F, 0x7, 0x7, 0, 0}, + {0x60, 0x7, 0x7, 1, 1}, + {0x61, 0x8, 0x8, 0, 0}, + {0x62, 0x3, 0x3, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0x40, 0x40, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0x1, 0x1, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0x60, 0x60, 0, 0}, + {0x71, 0x66, 0x66, 0, 0}, + {0x72, 0xc, 0xc, 0, 0}, + {0x73, 0x66, 0x66, 0, 0}, + {0x74, 0x8f, 0x8f, 1, 1}, + {0x75, 0, 0, 0, 0}, + {0x76, 0xcc, 0xcc, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0x66, 0x66, 0, 0}, + {0x79, 0x66, 0x66, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0xff, 0xff, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0, 0, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0, 0, 0, 0}, + {0x9A, 0, 0, 0, 0}, + {0x9B, 0, 0, 0, 0}, + {0x9C, 0, 0, 0, 0}, + {0x9D, 0, 0, 0, 0}, + {0x9E, 0, 0, 0, 0}, + {0x9F, 0x6, 0x6, 0, 0}, + {0xA0, 0x66, 0x66, 0, 0}, + {0xA1, 0x66, 0x66, 0, 0}, + {0xA2, 0x66, 0x66, 0, 0}, + {0xA3, 0x66, 0x66, 0, 0}, + {0xA4, 0x66, 0x66, 0, 0}, + {0xA5, 0x66, 0x66, 0, 0}, + {0xA6, 0x66, 0x66, 0, 0}, + {0xA7, 0x66, 0x66, 0, 0}, + {0xA8, 0x66, 0x66, 0, 0}, + {0xA9, 0x66, 0x66, 0, 0}, + {0xAA, 0x66, 0x66, 0, 0}, + {0xAB, 0x66, 0x66, 0, 0}, + {0xAC, 0x66, 0x66, 0, 0}, + {0xAD, 0x66, 0x66, 0, 0}, + {0xAE, 0x66, 0x66, 0, 0}, + {0xAF, 0x66, 0x66, 0, 0}, + {0xB0, 0x66, 0x66, 0, 0}, + {0xB1, 0x66, 0x66, 0, 0}, + {0xB2, 0x66, 0x66, 0, 0}, + {0xB3, 0xa, 0xa, 0, 0}, + {0xB4, 0, 0, 0, 0}, + {0xB5, 0, 0, 0, 0}, + {0xB6, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static struct radio_regs regs_TX_2056_rev7[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0x88, 0x88, 0, 0}, + {0x22, 0x88, 0x88, 0, 0}, + {0x23, 0x88, 0x88, 0, 0}, + {0x24, 0x88, 0x88, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0x3, 0x3, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x3, 0x3, 0, 0}, + {0x2A, 0x37, 0x37, 0, 0}, + {0x2B, 0x3, 0x3, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0x1, 0x1, 0, 0}, + {0x2F, 0x1, 0x1, 0, 0}, + {0x30, 0, 0, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0x11, 0x11, 0, 0}, + {0x34, 0xee, 0xee, 1, 1}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x3, 0x3, 0, 0}, + {0x38, 0x50, 0x50, 1, 1}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0x50, 0x50, 1, 1}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x6e, 0x6e, 0, 0}, + {0x3D, 0xf0, 0xf0, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x3, 0x3, 0, 0}, + {0x42, 0x3, 0x3, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x1e, 0x1e, 0, 0}, + {0x45, 0, 0, 0, 0}, + {0x46, 0x6e, 0x6e, 0, 0}, + {0x47, 0xf0, 0xf0, 1, 1}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x2, 0x2, 0, 0}, + {0x4A, 0xff, 0xff, 1, 1}, + {0x4B, 0xc, 0xc, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0x38, 0x38, 0, 0}, + {0x4E, 0x70, 0x70, 1, 1}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0x88, 0x88, 0, 0}, + {0x51, 0xc, 0xc, 0, 0}, + {0x52, 0, 0, 0, 0}, + {0x53, 0x8, 0x8, 0, 0}, + {0x54, 0x70, 0x70, 1, 1}, + {0x55, 0x2, 0x2, 0, 0}, + {0x56, 0xff, 0xff, 1, 1}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x83, 0x83, 0, 0}, + {0x59, 0x77, 0x77, 1, 1}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x88, 0x88, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x8, 0x8, 0, 0}, + {0x5F, 0x77, 0x77, 1, 1}, + {0x60, 0x1, 0x1, 0, 0}, + {0x61, 0, 0, 0, 0}, + {0x62, 0x7, 0x7, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0x7, 0x7, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 1, 1}, + {0x68, 0, 0, 0, 0}, + {0x69, 0xa, 0xa, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0x2, 0x2, 0, 0}, + {0x72, 0, 0, 0, 0}, + {0x73, 0, 0, 0, 0}, + {0x74, 0xe, 0xe, 0, 0}, + {0x75, 0xe, 0xe, 0, 0}, + {0x76, 0xe, 0xe, 0, 0}, + {0x77, 0x13, 0x13, 0, 0}, + {0x78, 0x13, 0x13, 0, 0}, + {0x79, 0x1b, 0x1b, 0, 0}, + {0x7A, 0x1b, 0x1b, 0, 0}, + {0x7B, 0x55, 0x55, 0, 0}, + {0x7C, 0x5b, 0x5b, 0, 0}, + {0x7D, 0x30, 0x30, 1, 1}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0x70, 0x70, 0, 0}, + {0x94, 0x70, 0x70, 0, 0}, + {0x95, 0x71, 0x71, 1, 1}, + {0x96, 0x71, 0x71, 1, 1}, + {0x97, 0x72, 0x72, 1, 1}, + {0x98, 0x73, 0x73, 1, 1}, + {0x99, 0x74, 0x74, 1, 1}, + {0x9A, 0x75, 0x75, 1, 1}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static struct radio_regs regs_RX_2056_rev7[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0x3, 0x3, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0, 0, 0, 0}, + {0x23, 0x90, 0x90, 0, 0}, + {0x24, 0x55, 0x55, 0, 0}, + {0x25, 0x15, 0x15, 0, 0}, + {0x26, 0x5, 0x5, 0, 0}, + {0x27, 0x15, 0x15, 0, 0}, + {0x28, 0x5, 0x5, 0, 0}, + {0x29, 0x20, 0x20, 0, 0}, + {0x2A, 0x11, 0x11, 0, 0}, + {0x2B, 0x90, 0x90, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0x88, 0x88, 0, 0}, + {0x2E, 0x32, 0x32, 0, 0}, + {0x2F, 0x77, 0x77, 0, 0}, + {0x30, 0x17, 0x17, 1, 1}, + {0x31, 0xff, 0xff, 1, 1}, + {0x32, 0x20, 0x20, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0x88, 0x88, 0, 0}, + {0x35, 0x32, 0x32, 0, 0}, + {0x36, 0x77, 0x77, 0, 0}, + {0x37, 0x17, 0x17, 1, 1}, + {0x38, 0xf0, 0xf0, 1, 1}, + {0x39, 0x20, 0x20, 0, 0}, + {0x3A, 0x8, 0x8, 0, 0}, + {0x3B, 0x55, 0x55, 1, 1}, + {0x3C, 0, 0, 0, 0}, + {0x3D, 0x88, 0x88, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 1, 1}, + {0x40, 0x7, 0x7, 1, 1}, + {0x41, 0x6, 0x6, 0, 0}, + {0x42, 0x4, 0x4, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x8, 0x8, 0, 0}, + {0x45, 0x55, 0x55, 1, 1}, + {0x46, 0, 0, 0, 0}, + {0x47, 0x11, 0x11, 0, 0}, + {0x48, 0, 0, 0, 0}, + {0x49, 0, 0, 1, 1}, + {0x4A, 0x7, 0x7, 0, 0}, + {0x4B, 0x6, 0x6, 0, 0}, + {0x4C, 0x4, 0x4, 0, 0}, + {0x4D, 0, 0, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x26, 0x26, 1, 1}, + {0x50, 0x26, 0x26, 1, 1}, + {0x51, 0xf, 0xf, 1, 1}, + {0x52, 0xf, 0xf, 1, 1}, + {0x53, 0x44, 0x44, 0, 0}, + {0x54, 0, 0, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0x8, 0x8, 0, 0}, + {0x57, 0x8, 0x8, 0, 0}, + {0x58, 0x7, 0x7, 0, 0}, + {0x59, 0x22, 0x22, 0, 0}, + {0x5A, 0x22, 0x22, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x4, 0x4, 1, 1}, + {0x5D, 0x7, 0x7, 0, 0}, + {0x5E, 0x55, 0x55, 0, 0}, + {0x5F, 0x23, 0x23, 0, 0}, + {0x60, 0x41, 0x41, 0, 0}, + {0x61, 0x1, 0x1, 0, 0}, + {0x62, 0xa, 0xa, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0, 0, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0xc, 0xc, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0, 0, 0, 0}, + {0x72, 0x22, 0x22, 0, 0}, + {0x73, 0x22, 0x22, 0, 0}, + {0x74, 0, 0, 1, 1}, + {0x75, 0xa, 0xa, 0, 0}, + {0x76, 0x1, 0x1, 0, 0}, + {0x77, 0x22, 0x22, 0, 0}, + {0x78, 0x30, 0x30, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static struct radio_regs regs_SYN_2056_rev8[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0x1, 0x1, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0x60, 0x60, 0, 0}, + {0x23, 0x6, 0x6, 0, 0}, + {0x24, 0xc, 0xc, 0, 0}, + {0x25, 0, 0, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0, 0, 0, 0}, + {0x28, 0x1, 0x1, 0, 0}, + {0x29, 0, 0, 0, 0}, + {0x2A, 0, 0, 0, 0}, + {0x2B, 0, 0, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0, 0, 0, 0}, + {0x2F, 0x1f, 0x1f, 0, 0}, + {0x30, 0x15, 0x15, 0, 0}, + {0x31, 0xf, 0xf, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0, 0, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0, 0, 0, 0}, + {0x38, 0, 0, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0, 0, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x13, 0x13, 0, 0}, + {0x3D, 0xf, 0xf, 0, 0}, + {0x3E, 0x18, 0x18, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x20, 0x20, 0, 0}, + {0x42, 0x20, 0x20, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x77, 0x77, 0, 0}, + {0x45, 0x7, 0x7, 0, 0}, + {0x46, 0x1, 0x1, 0, 0}, + {0x47, 0x4, 0x4, 0, 0}, + {0x48, 0xf, 0xf, 0, 0}, + {0x49, 0x30, 0x30, 0, 0}, + {0x4A, 0x32, 0x32, 0, 0}, + {0x4B, 0xd, 0xd, 0, 0}, + {0x4C, 0xd, 0xd, 0, 0}, + {0x4D, 0x4, 0x4, 0, 0}, + {0x4E, 0x6, 0x6, 0, 0}, + {0x4F, 0x1, 0x1, 0, 0}, + {0x50, 0x1c, 0x1c, 0, 0}, + {0x51, 0x2, 0x2, 0, 0}, + {0x52, 0x2, 0x2, 0, 0}, + {0x53, 0xf7, 0xf7, 1, 1}, + {0x54, 0xb4, 0xb4, 0, 0}, + {0x55, 0xd2, 0xd2, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x4, 0x4, 0, 0}, + {0x59, 0x96, 0x96, 0, 0}, + {0x5A, 0x3e, 0x3e, 0, 0}, + {0x5B, 0x3e, 0x3e, 0, 0}, + {0x5C, 0x13, 0x13, 0, 0}, + {0x5D, 0x2, 0x2, 0, 0}, + {0x5E, 0, 0, 0, 0}, + {0x5F, 0x7, 0x7, 0, 0}, + {0x60, 0x7, 0x7, 1, 1}, + {0x61, 0x8, 0x8, 0, 0}, + {0x62, 0x3, 0x3, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0x40, 0x40, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0x1, 0x1, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0x60, 0x60, 0, 0}, + {0x71, 0x66, 0x66, 0, 0}, + {0x72, 0xc, 0xc, 0, 0}, + {0x73, 0x66, 0x66, 0, 0}, + {0x74, 0x8f, 0x8f, 1, 1}, + {0x75, 0, 0, 0, 0}, + {0x76, 0xcc, 0xcc, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0x66, 0x66, 0, 0}, + {0x79, 0x66, 0x66, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0xff, 0xff, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0, 0, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0, 0, 0, 0}, + {0x9A, 0, 0, 0, 0}, + {0x9B, 0, 0, 0, 0}, + {0x9C, 0, 0, 0, 0}, + {0x9D, 0, 0, 0, 0}, + {0x9E, 0, 0, 0, 0}, + {0x9F, 0x6, 0x6, 0, 0}, + {0xA0, 0x66, 0x66, 0, 0}, + {0xA1, 0x66, 0x66, 0, 0}, + {0xA2, 0x66, 0x66, 0, 0}, + {0xA3, 0x66, 0x66, 0, 0}, + {0xA4, 0x66, 0x66, 0, 0}, + {0xA5, 0x66, 0x66, 0, 0}, + {0xA6, 0x66, 0x66, 0, 0}, + {0xA7, 0x66, 0x66, 0, 0}, + {0xA8, 0x66, 0x66, 0, 0}, + {0xA9, 0x66, 0x66, 0, 0}, + {0xAA, 0x66, 0x66, 0, 0}, + {0xAB, 0x66, 0x66, 0, 0}, + {0xAC, 0x66, 0x66, 0, 0}, + {0xAD, 0x66, 0x66, 0, 0}, + {0xAE, 0x66, 0x66, 0, 0}, + {0xAF, 0x66, 0x66, 0, 0}, + {0xB0, 0x66, 0x66, 0, 0}, + {0xB1, 0x66, 0x66, 0, 0}, + {0xB2, 0x66, 0x66, 0, 0}, + {0xB3, 0xa, 0xa, 0, 0}, + {0xB4, 0, 0, 0, 0}, + {0xB5, 0, 0, 0, 0}, + {0xB6, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static struct radio_regs regs_TX_2056_rev8[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0x88, 0x88, 0, 0}, + {0x22, 0x88, 0x88, 0, 0}, + {0x23, 0x88, 0x88, 0, 0}, + {0x24, 0x88, 0x88, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0x3, 0x3, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x3, 0x3, 0, 0}, + {0x2A, 0x37, 0x37, 0, 0}, + {0x2B, 0x3, 0x3, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0x1, 0x1, 0, 0}, + {0x2F, 0x1, 0x1, 0, 0}, + {0x30, 0, 0, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0x11, 0x11, 0, 0}, + {0x34, 0xee, 0xee, 1, 1}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x3, 0x3, 0, 0}, + {0x38, 0x50, 0x50, 1, 1}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0x50, 0x50, 1, 1}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x6e, 0x6e, 0, 0}, + {0x3D, 0xf0, 0xf0, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x3, 0x3, 0, 0}, + {0x42, 0x3, 0x3, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x1e, 0x1e, 0, 0}, + {0x45, 0, 0, 0, 0}, + {0x46, 0x6e, 0x6e, 0, 0}, + {0x47, 0xf0, 0xf0, 1, 1}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x2, 0x2, 0, 0}, + {0x4A, 0xff, 0xff, 1, 1}, + {0x4B, 0xc, 0xc, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0x38, 0x38, 0, 0}, + {0x4E, 0x70, 0x70, 1, 1}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0x88, 0x88, 0, 0}, + {0x51, 0xc, 0xc, 0, 0}, + {0x52, 0, 0, 0, 0}, + {0x53, 0x8, 0x8, 0, 0}, + {0x54, 0x70, 0x70, 1, 1}, + {0x55, 0x2, 0x2, 0, 0}, + {0x56, 0xff, 0xff, 1, 1}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x83, 0x83, 0, 0}, + {0x59, 0x77, 0x77, 1, 1}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x88, 0x88, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x8, 0x8, 0, 0}, + {0x5F, 0x77, 0x77, 1, 1}, + {0x60, 0x1, 0x1, 0, 0}, + {0x61, 0, 0, 0, 0}, + {0x62, 0x7, 0x7, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0x7, 0x7, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 1, 1}, + {0x68, 0, 0, 0, 0}, + {0x69, 0xa, 0xa, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0x2, 0x2, 0, 0}, + {0x72, 0, 0, 0, 0}, + {0x73, 0, 0, 0, 0}, + {0x74, 0xe, 0xe, 0, 0}, + {0x75, 0xe, 0xe, 0, 0}, + {0x76, 0xe, 0xe, 0, 0}, + {0x77, 0x13, 0x13, 0, 0}, + {0x78, 0x13, 0x13, 0, 0}, + {0x79, 0x1b, 0x1b, 0, 0}, + {0x7A, 0x1b, 0x1b, 0, 0}, + {0x7B, 0x55, 0x55, 0, 0}, + {0x7C, 0x5b, 0x5b, 0, 0}, + {0x7D, 0x30, 0x30, 1, 1}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0x70, 0x70, 0, 0}, + {0x94, 0x70, 0x70, 0, 0}, + {0x95, 0x70, 0x70, 0, 0}, + {0x96, 0x70, 0x70, 0, 0}, + {0x97, 0x70, 0x70, 0, 0}, + {0x98, 0x70, 0x70, 0, 0}, + {0x99, 0x70, 0x70, 0, 0}, + {0x9A, 0x70, 0x70, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static struct radio_regs regs_RX_2056_rev8[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0x3, 0x3, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0, 0, 0, 0}, + {0x23, 0x90, 0x90, 0, 0}, + {0x24, 0x55, 0x55, 0, 0}, + {0x25, 0x15, 0x15, 0, 0}, + {0x26, 0x5, 0x5, 0, 0}, + {0x27, 0x15, 0x15, 0, 0}, + {0x28, 0x5, 0x5, 0, 0}, + {0x29, 0x20, 0x20, 0, 0}, + {0x2A, 0x11, 0x11, 0, 0}, + {0x2B, 0x90, 0x90, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0x88, 0x88, 0, 0}, + {0x2E, 0x32, 0x32, 0, 0}, + {0x2F, 0x77, 0x77, 0, 0}, + {0x30, 0x17, 0x17, 1, 1}, + {0x31, 0xff, 0xff, 1, 1}, + {0x32, 0x20, 0x20, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0x88, 0x88, 0, 0}, + {0x35, 0x32, 0x32, 0, 0}, + {0x36, 0x77, 0x77, 0, 0}, + {0x37, 0x17, 0x17, 1, 1}, + {0x38, 0xf0, 0xf0, 1, 1}, + {0x39, 0x20, 0x20, 0, 0}, + {0x3A, 0x8, 0x8, 0, 0}, + {0x3B, 0x55, 0x55, 1, 1}, + {0x3C, 0, 0, 0, 0}, + {0x3D, 0x88, 0x88, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0x44, 0x44, 0, 0}, + {0x40, 0x7, 0x7, 1, 1}, + {0x41, 0x6, 0x6, 0, 0}, + {0x42, 0x4, 0x4, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x8, 0x8, 0, 0}, + {0x45, 0x55, 0x55, 1, 1}, + {0x46, 0, 0, 0, 0}, + {0x47, 0x11, 0x11, 0, 0}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x44, 0x44, 0, 0}, + {0x4A, 0x7, 0x7, 0, 0}, + {0x4B, 0x6, 0x6, 0, 0}, + {0x4C, 0x4, 0x4, 0, 0}, + {0x4D, 0, 0, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x26, 0x26, 1, 1}, + {0x50, 0x26, 0x26, 1, 1}, + {0x51, 0xf, 0xf, 1, 1}, + {0x52, 0xf, 0xf, 1, 1}, + {0x53, 0x44, 0x44, 0, 0}, + {0x54, 0, 0, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0x8, 0x8, 0, 0}, + {0x57, 0x8, 0x8, 0, 0}, + {0x58, 0x7, 0x7, 0, 0}, + {0x59, 0x22, 0x22, 0, 0}, + {0x5A, 0x22, 0x22, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x4, 0x4, 1, 1}, + {0x5D, 0x7, 0x7, 0, 0}, + {0x5E, 0x55, 0x55, 0, 0}, + {0x5F, 0x23, 0x23, 0, 0}, + {0x60, 0x41, 0x41, 0, 0}, + {0x61, 0x1, 0x1, 0, 0}, + {0x62, 0xa, 0xa, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0, 0, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0xc, 0xc, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0, 0, 0, 0}, + {0x72, 0x22, 0x22, 0, 0}, + {0x73, 0x22, 0x22, 0, 0}, + {0x74, 0, 0, 1, 1}, + {0x75, 0xa, 0xa, 0, 0}, + {0x76, 0x1, 0x1, 0, 0}, + {0x77, 0x22, 0x22, 0, 0}, + {0x78, 0x30, 0x30, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0x5, 0x5, 1, 1}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static const struct radio_regs regs_SYN_2056_rev11[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0x1, 0x1, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0x60, 0x60, 0, 0}, + {0x23, 0x6, 0x6, 0, 0}, + {0x24, 0xc, 0xc, 0, 0}, + {0x25, 0, 0, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0, 0, 0, 0}, + {0x28, 0x1, 0x1, 0, 0}, + {0x29, 0, 0, 0, 0}, + {0x2A, 0, 0, 0, 0}, + {0x2B, 0, 0, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0, 0, 0, 0}, + {0x2F, 0x1f, 0x1f, 0, 0}, + {0x30, 0x15, 0x15, 0, 0}, + {0x31, 0xf, 0xf, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0, 0, 0, 0}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0, 0, 0, 0}, + {0x38, 0, 0, 0, 0}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0, 0, 0, 0}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x13, 0x13, 0, 0}, + {0x3D, 0xf, 0xf, 0, 0}, + {0x3E, 0x18, 0x18, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x20, 0x20, 0, 0}, + {0x42, 0x20, 0x20, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x77, 0x77, 0, 0}, + {0x45, 0x7, 0x7, 0, 0}, + {0x46, 0x1, 0x1, 0, 0}, + {0x47, 0x6, 0x6, 1, 1}, + {0x48, 0xf, 0xf, 0, 0}, + {0x49, 0x3f, 0x3f, 1, 1}, + {0x4A, 0x32, 0x32, 0, 0}, + {0x4B, 0x6, 0x6, 1, 1}, + {0x4C, 0x6, 0x6, 1, 1}, + {0x4D, 0x4, 0x4, 0, 0}, + {0x4E, 0x2b, 0x2b, 1, 1}, + {0x4F, 0x1, 0x1, 0, 0}, + {0x50, 0x1c, 0x1c, 0, 0}, + {0x51, 0x2, 0x2, 0, 0}, + {0x52, 0x2, 0x2, 0, 0}, + {0x53, 0xf7, 0xf7, 1, 1}, + {0x54, 0xb4, 0xb4, 0, 0}, + {0x55, 0xd2, 0xd2, 0, 0}, + {0x56, 0, 0, 0, 0}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x4, 0x4, 0, 0}, + {0x59, 0x96, 0x96, 0, 0}, + {0x5A, 0x3e, 0x3e, 0, 0}, + {0x5B, 0x3e, 0x3e, 0, 0}, + {0x5C, 0x13, 0x13, 0, 0}, + {0x5D, 0x2, 0x2, 0, 0}, + {0x5E, 0, 0, 0, 0}, + {0x5F, 0x7, 0x7, 0, 0}, + {0x60, 0x7, 0x7, 1, 1}, + {0x61, 0x8, 0x8, 0, 0}, + {0x62, 0x3, 0x3, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0x40, 0x40, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0x1, 0x1, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0x60, 0x60, 0, 0}, + {0x71, 0x66, 0x66, 0, 0}, + {0x72, 0xc, 0xc, 0, 0}, + {0x73, 0x66, 0x66, 0, 0}, + {0x74, 0x8f, 0x8f, 1, 1}, + {0x75, 0, 0, 0, 0}, + {0x76, 0xcc, 0xcc, 0, 0}, + {0x77, 0x1, 0x1, 0, 0}, + {0x78, 0x66, 0x66, 0, 0}, + {0x79, 0x66, 0x66, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0, 0, 0, 0}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0xff, 0xff, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0x95, 0, 0, 0, 0}, + {0x96, 0, 0, 0, 0}, + {0x97, 0, 0, 0, 0}, + {0x98, 0, 0, 0, 0}, + {0x99, 0, 0, 0, 0}, + {0x9A, 0, 0, 0, 0}, + {0x9B, 0, 0, 0, 0}, + {0x9C, 0, 0, 0, 0}, + {0x9D, 0, 0, 0, 0}, + {0x9E, 0, 0, 0, 0}, + {0x9F, 0x6, 0x6, 0, 0}, + {0xA0, 0x66, 0x66, 0, 0}, + {0xA1, 0x66, 0x66, 0, 0}, + {0xA2, 0x66, 0x66, 0, 0}, + {0xA3, 0x66, 0x66, 0, 0}, + {0xA4, 0x66, 0x66, 0, 0}, + {0xA5, 0x66, 0x66, 0, 0}, + {0xA6, 0x66, 0x66, 0, 0}, + {0xA7, 0x66, 0x66, 0, 0}, + {0xA8, 0x66, 0x66, 0, 0}, + {0xA9, 0x66, 0x66, 0, 0}, + {0xAA, 0x66, 0x66, 0, 0}, + {0xAB, 0x66, 0x66, 0, 0}, + {0xAC, 0x66, 0x66, 0, 0}, + {0xAD, 0x66, 0x66, 0, 0}, + {0xAE, 0x66, 0x66, 0, 0}, + {0xAF, 0x66, 0x66, 0, 0}, + {0xB0, 0x66, 0x66, 0, 0}, + {0xB1, 0x66, 0x66, 0, 0}, + {0xB2, 0x66, 0x66, 0, 0}, + {0xB3, 0xa, 0xa, 0, 0}, + {0xB4, 0, 0, 0, 0}, + {0xB5, 0, 0, 0, 0}, + {0xB6, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static const struct radio_regs regs_TX_2056_rev11[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0, 0, 0, 0}, + {0x21, 0x88, 0x88, 0, 0}, + {0x22, 0x88, 0x88, 0, 0}, + {0x23, 0x88, 0x88, 0, 0}, + {0x24, 0x88, 0x88, 0, 0}, + {0x25, 0xc, 0xc, 0, 0}, + {0x26, 0, 0, 0, 0}, + {0x27, 0x3, 0x3, 0, 0}, + {0x28, 0, 0, 0, 0}, + {0x29, 0x3, 0x3, 0, 0}, + {0x2A, 0x37, 0x37, 0, 0}, + {0x2B, 0x3, 0x3, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0, 0, 0, 0}, + {0x2E, 0x1, 0x1, 0, 0}, + {0x2F, 0x1, 0x1, 0, 0}, + {0x30, 0, 0, 0, 0}, + {0x31, 0, 0, 0, 0}, + {0x32, 0, 0, 0, 0}, + {0x33, 0x11, 0x11, 0, 0}, + {0x34, 0xee, 0xee, 1, 1}, + {0x35, 0, 0, 0, 0}, + {0x36, 0, 0, 0, 0}, + {0x37, 0x3, 0x3, 0, 0}, + {0x38, 0x50, 0x50, 1, 1}, + {0x39, 0, 0, 0, 0}, + {0x3A, 0x50, 0x50, 1, 1}, + {0x3B, 0, 0, 0, 0}, + {0x3C, 0x6e, 0x6e, 0, 0}, + {0x3D, 0xf0, 0xf0, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0, 0, 0, 0}, + {0x40, 0, 0, 0, 0}, + {0x41, 0x3, 0x3, 0, 0}, + {0x42, 0x3, 0x3, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x1e, 0x1e, 0, 0}, + {0x45, 0, 0, 0, 0}, + {0x46, 0x6e, 0x6e, 0, 0}, + {0x47, 0xf0, 0xf0, 1, 1}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x2, 0x2, 0, 0}, + {0x4A, 0xff, 0xff, 1, 1}, + {0x4B, 0xc, 0xc, 0, 0}, + {0x4C, 0, 0, 0, 0}, + {0x4D, 0x38, 0x38, 0, 0}, + {0x4E, 0x70, 0x70, 1, 1}, + {0x4F, 0x2, 0x2, 0, 0}, + {0x50, 0x88, 0x88, 0, 0}, + {0x51, 0xc, 0xc, 0, 0}, + {0x52, 0, 0, 0, 0}, + {0x53, 0x8, 0x8, 0, 0}, + {0x54, 0x70, 0x70, 1, 1}, + {0x55, 0x2, 0x2, 0, 0}, + {0x56, 0xff, 0xff, 1, 1}, + {0x57, 0, 0, 0, 0}, + {0x58, 0x83, 0x83, 0, 0}, + {0x59, 0x77, 0x77, 1, 1}, + {0x5A, 0, 0, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x88, 0x88, 0, 0}, + {0x5D, 0, 0, 0, 0}, + {0x5E, 0x8, 0x8, 0, 0}, + {0x5F, 0x77, 0x77, 1, 1}, + {0x60, 0x1, 0x1, 0, 0}, + {0x61, 0, 0, 0, 0}, + {0x62, 0x7, 0x7, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0x7, 0x7, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 1, 1}, + {0x68, 0, 0, 0, 0}, + {0x69, 0xa, 0xa, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0, 0, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0x2, 0x2, 0, 0}, + {0x72, 0, 0, 0, 0}, + {0x73, 0, 0, 0, 0}, + {0x74, 0xe, 0xe, 0, 0}, + {0x75, 0xe, 0xe, 0, 0}, + {0x76, 0xe, 0xe, 0, 0}, + {0x77, 0x13, 0x13, 0, 0}, + {0x78, 0x13, 0x13, 0, 0}, + {0x79, 0x1b, 0x1b, 0, 0}, + {0x7A, 0x1b, 0x1b, 0, 0}, + {0x7B, 0x55, 0x55, 0, 0}, + {0x7C, 0x5b, 0x5b, 0, 0}, + {0x7D, 0x30, 0x30, 1, 1}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0x70, 0x70, 0, 0}, + {0x94, 0x70, 0x70, 0, 0}, + {0x95, 0x70, 0x70, 0, 0}, + {0x96, 0x70, 0x70, 0, 0}, + {0x97, 0x70, 0x70, 0, 0}, + {0x98, 0x70, 0x70, 0, 0}, + {0x99, 0x70, 0x70, 0, 0}, + {0x9A, 0x70, 0x70, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static const struct radio_regs regs_RX_2056_rev11[] = { + {0x02, 0, 0, 0, 0}, + {0x03, 0, 0, 0, 0}, + {0x04, 0, 0, 0, 0}, + {0x05, 0, 0, 0, 0}, + {0x06, 0, 0, 0, 0}, + {0x07, 0, 0, 0, 0}, + {0x08, 0, 0, 0, 0}, + {0x09, 0, 0, 0, 0}, + {0x0A, 0, 0, 0, 0}, + {0x0B, 0, 0, 0, 0}, + {0x0C, 0, 0, 0, 0}, + {0x0D, 0, 0, 0, 0}, + {0x0E, 0, 0, 0, 0}, + {0x0F, 0, 0, 0, 0}, + {0x10, 0, 0, 0, 0}, + {0x11, 0, 0, 0, 0}, + {0x12, 0, 0, 0, 0}, + {0x13, 0, 0, 0, 0}, + {0x14, 0, 0, 0, 0}, + {0x15, 0, 0, 0, 0}, + {0x16, 0, 0, 0, 0}, + {0x17, 0, 0, 0, 0}, + {0x18, 0, 0, 0, 0}, + {0x19, 0, 0, 0, 0}, + {0x1A, 0, 0, 0, 0}, + {0x1B, 0, 0, 0, 0}, + {0x1C, 0, 0, 0, 0}, + {0x1D, 0, 0, 0, 0}, + {0x1E, 0, 0, 0, 0}, + {0x1F, 0, 0, 0, 0}, + {0x20, 0x3, 0x3, 0, 0}, + {0x21, 0, 0, 0, 0}, + {0x22, 0, 0, 0, 0}, + {0x23, 0x90, 0x90, 0, 0}, + {0x24, 0x55, 0x55, 0, 0}, + {0x25, 0x15, 0x15, 0, 0}, + {0x26, 0x5, 0x5, 0, 0}, + {0x27, 0x15, 0x15, 0, 0}, + {0x28, 0x5, 0x5, 0, 0}, + {0x29, 0x20, 0x20, 0, 0}, + {0x2A, 0x11, 0x11, 0, 0}, + {0x2B, 0x90, 0x90, 0, 0}, + {0x2C, 0, 0, 0, 0}, + {0x2D, 0x88, 0x88, 0, 0}, + {0x2E, 0x32, 0x32, 0, 0}, + {0x2F, 0x77, 0x77, 0, 0}, + {0x30, 0x17, 0x17, 1, 1}, + {0x31, 0xff, 0xff, 1, 1}, + {0x32, 0x20, 0x20, 0, 0}, + {0x33, 0, 0, 0, 0}, + {0x34, 0x88, 0x88, 0, 0}, + {0x35, 0x32, 0x32, 0, 0}, + {0x36, 0x77, 0x77, 0, 0}, + {0x37, 0x17, 0x17, 1, 1}, + {0x38, 0xf0, 0xf0, 1, 1}, + {0x39, 0x20, 0x20, 0, 0}, + {0x3A, 0x8, 0x8, 0, 0}, + {0x3B, 0x55, 0x55, 1, 1}, + {0x3C, 0, 0, 0, 0}, + {0x3D, 0x88, 0x88, 1, 1}, + {0x3E, 0, 0, 0, 0}, + {0x3F, 0x44, 0x44, 0, 0}, + {0x40, 0x7, 0x7, 1, 1}, + {0x41, 0x6, 0x6, 0, 0}, + {0x42, 0x4, 0x4, 0, 0}, + {0x43, 0, 0, 0, 0}, + {0x44, 0x8, 0x8, 0, 0}, + {0x45, 0x55, 0x55, 1, 1}, + {0x46, 0, 0, 0, 0}, + {0x47, 0x11, 0x11, 0, 0}, + {0x48, 0, 0, 0, 0}, + {0x49, 0x44, 0x44, 0, 0}, + {0x4A, 0x7, 0x7, 0, 0}, + {0x4B, 0x6, 0x6, 0, 0}, + {0x4C, 0x4, 0x4, 0, 0}, + {0x4D, 0, 0, 0, 0}, + {0x4E, 0, 0, 0, 0}, + {0x4F, 0x26, 0x26, 1, 1}, + {0x50, 0x26, 0x26, 1, 1}, + {0x51, 0xf, 0xf, 1, 1}, + {0x52, 0xf, 0xf, 1, 1}, + {0x53, 0x44, 0x44, 0, 0}, + {0x54, 0, 0, 0, 0}, + {0x55, 0, 0, 0, 0}, + {0x56, 0x8, 0x8, 0, 0}, + {0x57, 0x8, 0x8, 0, 0}, + {0x58, 0x7, 0x7, 0, 0}, + {0x59, 0x22, 0x22, 0, 0}, + {0x5A, 0x22, 0x22, 0, 0}, + {0x5B, 0x2, 0x2, 0, 0}, + {0x5C, 0x4, 0x4, 1, 1}, + {0x5D, 0x7, 0x7, 0, 0}, + {0x5E, 0x55, 0x55, 0, 0}, + {0x5F, 0x23, 0x23, 0, 0}, + {0x60, 0x41, 0x41, 0, 0}, + {0x61, 0x1, 0x1, 0, 0}, + {0x62, 0xa, 0xa, 0, 0}, + {0x63, 0, 0, 0, 0}, + {0x64, 0, 0, 0, 0}, + {0x65, 0, 0, 0, 0}, + {0x66, 0, 0, 0, 0}, + {0x67, 0, 0, 0, 0}, + {0x68, 0, 0, 0, 0}, + {0x69, 0, 0, 0, 0}, + {0x6A, 0, 0, 0, 0}, + {0x6B, 0xc, 0xc, 0, 0}, + {0x6C, 0, 0, 0, 0}, + {0x6D, 0, 0, 0, 0}, + {0x6E, 0, 0, 0, 0}, + {0x6F, 0, 0, 0, 0}, + {0x70, 0, 0, 0, 0}, + {0x71, 0, 0, 0, 0}, + {0x72, 0x22, 0x22, 0, 0}, + {0x73, 0x22, 0x22, 0, 0}, + {0x74, 0, 0, 1, 1}, + {0x75, 0xa, 0xa, 0, 0}, + {0x76, 0x1, 0x1, 0, 0}, + {0x77, 0x22, 0x22, 0, 0}, + {0x78, 0x30, 0x30, 0, 0}, + {0x79, 0, 0, 0, 0}, + {0x7A, 0, 0, 0, 0}, + {0x7B, 0, 0, 0, 0}, + {0x7C, 0, 0, 0, 0}, + {0x7D, 0x5, 0x5, 1, 1}, + {0x7E, 0, 0, 0, 0}, + {0x7F, 0, 0, 0, 0}, + {0x80, 0, 0, 0, 0}, + {0x81, 0, 0, 0, 0}, + {0x82, 0, 0, 0, 0}, + {0x83, 0, 0, 0, 0}, + {0x84, 0, 0, 0, 0}, + {0x85, 0, 0, 0, 0}, + {0x86, 0, 0, 0, 0}, + {0x87, 0, 0, 0, 0}, + {0x88, 0, 0, 0, 0}, + {0x89, 0, 0, 0, 0}, + {0x8A, 0, 0, 0, 0}, + {0x8B, 0, 0, 0, 0}, + {0x8C, 0, 0, 0, 0}, + {0x8D, 0, 0, 0, 0}, + {0x8E, 0, 0, 0, 0}, + {0x8F, 0, 0, 0, 0}, + {0x90, 0, 0, 0, 0}, + {0x91, 0, 0, 0, 0}, + {0x92, 0, 0, 0, 0}, + {0x93, 0, 0, 0, 0}, + {0x94, 0, 0, 0, 0}, + {0xFFFF, 0, 0, 0, 0}, +}; + +static struct radio_20xx_regs regs_2057_rev4[] = { + {0x00, 0x84, 0}, + {0x01, 0, 0}, + {0x02, 0x60, 0}, + {0x03, 0x1f, 0}, + {0x04, 0x4, 0}, + {0x05, 0x2, 0}, + {0x06, 0x1, 0}, + {0x07, 0x1, 0}, + {0x08, 0x1, 0}, + {0x09, 0x69, 0}, + {0x0A, 0x66, 0}, + {0x0B, 0x6, 0}, + {0x0C, 0x18, 0}, + {0x0D, 0x3, 0}, + {0x0E, 0x20, 1}, + {0x0F, 0x20, 0}, + {0x10, 0, 0}, + {0x11, 0x7c, 0}, + {0x12, 0x42, 0}, + {0x13, 0xbd, 0}, + {0x14, 0x7, 0}, + {0x15, 0xf7, 0}, + {0x16, 0x8, 0}, + {0x17, 0x17, 0}, + {0x18, 0x7, 0}, + {0x19, 0, 0}, + {0x1A, 0x2, 0}, + {0x1B, 0x13, 0}, + {0x1C, 0x3e, 0}, + {0x1D, 0x3e, 0}, + {0x1E, 0x96, 0}, + {0x1F, 0x4, 0}, + {0x20, 0, 0}, + {0x21, 0, 0}, + {0x22, 0x17, 0}, + {0x23, 0x4, 0}, + {0x24, 0x1, 0}, + {0x25, 0x6, 0}, + {0x26, 0x4, 0}, + {0x27, 0xd, 0}, + {0x28, 0xd, 0}, + {0x29, 0x30, 0}, + {0x2A, 0x32, 0}, + {0x2B, 0x8, 0}, + {0x2C, 0x1c, 0}, + {0x2D, 0x2, 0}, + {0x2E, 0x4, 0}, + {0x2F, 0x7f, 0}, + {0x30, 0x27, 0}, + {0x31, 0, 1}, + {0x32, 0, 1}, + {0x33, 0, 1}, + {0x34, 0, 0}, + {0x35, 0x26, 1}, + {0x36, 0x18, 0}, + {0x37, 0x7, 0}, + {0x38, 0x66, 0}, + {0x39, 0x66, 0}, + {0x3A, 0x66, 0}, + {0x3B, 0x66, 0}, + {0x3C, 0xff, 1}, + {0x3D, 0xff, 1}, + {0x3E, 0xff, 1}, + {0x3F, 0xff, 1}, + {0x40, 0x16, 0}, + {0x41, 0x7, 0}, + {0x42, 0x19, 0}, + {0x43, 0x7, 0}, + {0x44, 0x6, 0}, + {0x45, 0x3, 0}, + {0x46, 0x1, 0}, + {0x47, 0x7, 0}, + {0x48, 0x33, 0}, + {0x49, 0x5, 0}, + {0x4A, 0x77, 0}, + {0x4B, 0x66, 0}, + {0x4C, 0x66, 0}, + {0x4D, 0, 0}, + {0x4E, 0x4, 0}, + {0x4F, 0xc, 0}, + {0x50, 0, 0}, + {0x51, 0x75, 0}, + {0x56, 0x7, 0}, + {0x57, 0, 0}, + {0x58, 0, 0}, + {0x59, 0xa8, 0}, + {0x5A, 0, 0}, + {0x5B, 0x1f, 0}, + {0x5C, 0x30, 0}, + {0x5D, 0x1, 0}, + {0x5E, 0x30, 0}, + {0x5F, 0x70, 0}, + {0x60, 0, 0}, + {0x61, 0, 0}, + {0x62, 0x33, 1}, + {0x63, 0x19, 0}, + {0x64, 0x62, 0}, + {0x65, 0, 0}, + {0x66, 0x11, 0}, + {0x69, 0, 0}, + {0x6A, 0x7e, 0}, + {0x6B, 0x3f, 0}, + {0x6C, 0x7f, 0}, + {0x6D, 0x78, 0}, + {0x6E, 0xc8, 0}, + {0x6F, 0x88, 0}, + {0x70, 0x8, 0}, + {0x71, 0xf, 0}, + {0x72, 0xbc, 0}, + {0x73, 0x8, 0}, + {0x74, 0x60, 0}, + {0x75, 0x1e, 0}, + {0x76, 0x70, 0}, + {0x77, 0, 0}, + {0x78, 0, 0}, + {0x79, 0, 0}, + {0x7A, 0x33, 0}, + {0x7B, 0x1e, 0}, + {0x7C, 0x62, 0}, + {0x7D, 0x11, 0}, + {0x80, 0x3c, 0}, + {0x81, 0x9c, 0}, + {0x82, 0xa, 0}, + {0x83, 0x9d, 0}, + {0x84, 0xa, 0}, + {0x85, 0, 0}, + {0x86, 0x40, 0}, + {0x87, 0x40, 0}, + {0x88, 0x88, 0}, + {0x89, 0x10, 0}, + {0x8A, 0xf0, 1}, + {0x8B, 0x10, 1}, + {0x8C, 0xf0, 1}, + {0x8D, 0, 0}, + {0x8E, 0, 0}, + {0x8F, 0x10, 0}, + {0x90, 0x55, 0}, + {0x91, 0x3f, 1}, + {0x92, 0x36, 1}, + {0x93, 0, 0}, + {0x94, 0, 0}, + {0x95, 0, 0}, + {0x96, 0x87, 0}, + {0x97, 0x11, 0}, + {0x98, 0, 0}, + {0x99, 0x33, 0}, + {0x9A, 0x88, 0}, + {0x9B, 0, 0}, + {0x9C, 0x87, 0}, + {0x9D, 0x11, 0}, + {0x9E, 0, 0}, + {0x9F, 0x33, 0}, + {0xA0, 0x88, 0}, + {0xA1, 0xe1, 0}, + {0xA2, 0x3f, 0}, + {0xA3, 0x44, 0}, + {0xA4, 0x8c, 1}, + {0xA5, 0x6d, 0}, + {0xA6, 0x22, 0}, + {0xA7, 0xbe, 0}, + {0xA8, 0x55, 1}, + {0xA9, 0xc, 0}, + {0xAA, 0xc, 0}, + {0xAB, 0xaa, 0}, + {0xAC, 0x2, 0}, + {0xAD, 0, 0}, + {0xAE, 0x10, 0}, + {0xAF, 0x1, 1}, + {0xB0, 0, 0}, + {0xB1, 0, 0}, + {0xB2, 0x80, 0}, + {0xB3, 0x60, 0}, + {0xB4, 0x44, 0}, + {0xB5, 0x55, 0}, + {0xB6, 0x1, 0}, + {0xB7, 0x55, 0}, + {0xB8, 0x1, 0}, + {0xB9, 0x5, 0}, + {0xBA, 0x55, 0}, + {0xBB, 0x55, 0}, + {0xC1, 0, 0}, + {0xC2, 0, 0}, + {0xC3, 0, 0}, + {0xC4, 0, 0}, + {0xC5, 0, 0}, + {0xC6, 0, 0}, + {0xC7, 0, 0}, + {0xC8, 0, 0}, + {0xC9, 0, 0}, + {0xCA, 0, 0}, + {0xCB, 0, 0}, + {0xCC, 0, 0}, + {0xCD, 0, 0}, + {0xCE, 0x5e, 0}, + {0xCF, 0xc, 0}, + {0xD0, 0xc, 0}, + {0xD1, 0xc, 0}, + {0xD2, 0, 0}, + {0xD3, 0x2b, 0}, + {0xD4, 0xc, 0}, + {0xD5, 0, 0}, + {0xD6, 0x75, 0}, + {0xDB, 0x7, 0}, + {0xDC, 0, 0}, + {0xDD, 0, 0}, + {0xDE, 0xa8, 0}, + {0xDF, 0, 0}, + {0xE0, 0x1f, 0}, + {0xE1, 0x30, 0}, + {0xE2, 0x1, 0}, + {0xE3, 0x30, 0}, + {0xE4, 0x70, 0}, + {0xE5, 0, 0}, + {0xE6, 0, 0}, + {0xE7, 0x33, 0}, + {0xE8, 0x19, 0}, + {0xE9, 0x62, 0}, + {0xEA, 0, 0}, + {0xEB, 0x11, 0}, + {0xEE, 0, 0}, + {0xEF, 0x7e, 0}, + {0xF0, 0x3f, 0}, + {0xF1, 0x7f, 0}, + {0xF2, 0x78, 0}, + {0xF3, 0xc8, 0}, + {0xF4, 0x88, 0}, + {0xF5, 0x8, 0}, + {0xF6, 0xf, 0}, + {0xF7, 0xbc, 0}, + {0xF8, 0x8, 0}, + {0xF9, 0x60, 0}, + {0xFA, 0x1e, 0}, + {0xFB, 0x70, 0}, + {0xFC, 0, 0}, + {0xFD, 0, 0}, + {0xFE, 0, 0}, + {0xFF, 0x33, 0}, + {0x100, 0x1e, 0}, + {0x101, 0x62, 0}, + {0x102, 0x11, 0}, + {0x105, 0x3c, 0}, + {0x106, 0x9c, 0}, + {0x107, 0xa, 0}, + {0x108, 0x9d, 0}, + {0x109, 0xa, 0}, + {0x10A, 0, 0}, + {0x10B, 0x40, 0}, + {0x10C, 0x40, 0}, + {0x10D, 0x88, 0}, + {0x10E, 0x10, 0}, + {0x10F, 0xf0, 1}, + {0x110, 0x10, 1}, + {0x111, 0xf0, 1}, + {0x112, 0, 0}, + {0x113, 0, 0}, + {0x114, 0x10, 0}, + {0x115, 0x55, 0}, + {0x116, 0x3f, 1}, + {0x117, 0x36, 1}, + {0x118, 0, 0}, + {0x119, 0, 0}, + {0x11A, 0, 0}, + {0x11B, 0x87, 0}, + {0x11C, 0x11, 0}, + {0x11D, 0, 0}, + {0x11E, 0x33, 0}, + {0x11F, 0x88, 0}, + {0x120, 0, 0}, + {0x121, 0x87, 0}, + {0x122, 0x11, 0}, + {0x123, 0, 0}, + {0x124, 0x33, 0}, + {0x125, 0x88, 0}, + {0x126, 0xe1, 0}, + {0x127, 0x3f, 0}, + {0x128, 0x44, 0}, + {0x129, 0x8c, 1}, + {0x12A, 0x6d, 0}, + {0x12B, 0x22, 0}, + {0x12C, 0xbe, 0}, + {0x12D, 0x55, 1}, + {0x12E, 0xc, 0}, + {0x12F, 0xc, 0}, + {0x130, 0xaa, 0}, + {0x131, 0x2, 0}, + {0x132, 0, 0}, + {0x133, 0x10, 0}, + {0x134, 0x1, 1}, + {0x135, 0, 0}, + {0x136, 0, 0}, + {0x137, 0x80, 0}, + {0x138, 0x60, 0}, + {0x139, 0x44, 0}, + {0x13A, 0x55, 0}, + {0x13B, 0x1, 0}, + {0x13C, 0x55, 0}, + {0x13D, 0x1, 0}, + {0x13E, 0x5, 0}, + {0x13F, 0x55, 0}, + {0x140, 0x55, 0}, + {0x146, 0, 0}, + {0x147, 0, 0}, + {0x148, 0, 0}, + {0x149, 0, 0}, + {0x14A, 0, 0}, + {0x14B, 0, 0}, + {0x14C, 0, 0}, + {0x14D, 0, 0}, + {0x14E, 0, 0}, + {0x14F, 0, 0}, + {0x150, 0, 0}, + {0x151, 0, 0}, + {0x152, 0, 0}, + {0x153, 0, 0}, + {0x154, 0xc, 0}, + {0x155, 0xc, 0}, + {0x156, 0xc, 0}, + {0x157, 0, 0}, + {0x158, 0x2b, 0}, + {0x159, 0x84, 0}, + {0x15A, 0x15, 0}, + {0x15B, 0xf, 0}, + {0x15C, 0, 0}, + {0x15D, 0, 0}, + {0x15E, 0, 1}, + {0x15F, 0, 1}, + {0x160, 0, 1}, + {0x161, 0, 1}, + {0x162, 0, 1}, + {0x163, 0, 1}, + {0x164, 0, 0}, + {0x165, 0, 0}, + {0x166, 0, 0}, + {0x167, 0, 0}, + {0x168, 0, 0}, + {0x169, 0x2, 1}, + {0x16A, 0, 1}, + {0x16B, 0, 1}, + {0x16C, 0, 1}, + {0x16D, 0, 0}, + {0x170, 0, 0}, + {0x171, 0x77, 0}, + {0x172, 0x77, 0}, + {0x173, 0x77, 0}, + {0x174, 0x77, 0}, + {0x175, 0, 0}, + {0x176, 0x3, 0}, + {0x177, 0x37, 0}, + {0x178, 0x3, 0}, + {0x179, 0, 0}, + {0x17A, 0x21, 0}, + {0x17B, 0x21, 0}, + {0x17C, 0, 0}, + {0x17D, 0xaa, 0}, + {0x17E, 0, 0}, + {0x17F, 0xaa, 0}, + {0x180, 0, 0}, + {0x190, 0, 0}, + {0x191, 0x77, 0}, + {0x192, 0x77, 0}, + {0x193, 0x77, 0}, + {0x194, 0x77, 0}, + {0x195, 0, 0}, + {0x196, 0x3, 0}, + {0x197, 0x37, 0}, + {0x198, 0x3, 0}, + {0x199, 0, 0}, + {0x19A, 0x21, 0}, + {0x19B, 0x21, 0}, + {0x19C, 0, 0}, + {0x19D, 0xaa, 0}, + {0x19E, 0, 0}, + {0x19F, 0xaa, 0}, + {0x1A0, 0, 0}, + {0x1A1, 0x2, 0}, + {0x1A2, 0xf, 0}, + {0x1A3, 0xf, 0}, + {0x1A4, 0, 1}, + {0x1A5, 0, 1}, + {0x1A6, 0, 1}, + {0x1A7, 0x2, 0}, + {0x1A8, 0xf, 0}, + {0x1A9, 0xf, 0}, + {0x1AA, 0, 1}, + {0x1AB, 0, 1}, + {0x1AC, 0, 1}, + {0xFFFF, 0, 0}, +}; + +static struct radio_20xx_regs regs_2057_rev5[] = { + {0x00, 0, 1}, + {0x01, 0x57, 1}, + {0x02, 0x20, 1}, + {0x03, 0x1f, 0}, + {0x04, 0x4, 0}, + {0x05, 0x2, 0}, + {0x06, 0x1, 0}, + {0x07, 0x1, 0}, + {0x08, 0x1, 0}, + {0x09, 0x69, 0}, + {0x0A, 0x66, 0}, + {0x0B, 0x6, 0}, + {0x0C, 0x18, 0}, + {0x0D, 0x3, 0}, + {0x0E, 0x20, 0}, + {0x0F, 0x20, 0}, + {0x10, 0, 0}, + {0x11, 0x7c, 0}, + {0x12, 0x42, 0}, + {0x13, 0xbd, 0}, + {0x14, 0x7, 0}, + {0x15, 0x87, 0}, + {0x16, 0x8, 0}, + {0x17, 0x17, 0}, + {0x18, 0x7, 0}, + {0x19, 0, 0}, + {0x1A, 0x2, 0}, + {0x1B, 0x13, 0}, + {0x1C, 0x3e, 0}, + {0x1D, 0x3e, 0}, + {0x1E, 0x96, 0}, + {0x1F, 0x4, 0}, + {0x20, 0, 0}, + {0x21, 0, 0}, + {0x22, 0x17, 0}, + {0x23, 0x6, 1}, + {0x24, 0x1, 0}, + {0x25, 0x6, 0}, + {0x26, 0x4, 0}, + {0x27, 0xd, 0}, + {0x28, 0xd, 0}, + {0x29, 0x30, 0}, + {0x2A, 0x32, 0}, + {0x2B, 0x8, 0}, + {0x2C, 0x1c, 0}, + {0x2D, 0x2, 0}, + {0x2E, 0x4, 0}, + {0x2F, 0x7f, 0}, + {0x30, 0x27, 0}, + {0x31, 0, 1}, + {0x32, 0, 1}, + {0x33, 0, 1}, + {0x34, 0, 0}, + {0x35, 0x20, 0}, + {0x36, 0x18, 0}, + {0x37, 0x7, 0}, + {0x38, 0x66, 0}, + {0x39, 0x66, 0}, + {0x3C, 0xff, 0}, + {0x3D, 0xff, 0}, + {0x40, 0x16, 0}, + {0x41, 0x7, 0}, + {0x45, 0x3, 0}, + {0x46, 0x1, 0}, + {0x47, 0x7, 0}, + {0x4B, 0x66, 0}, + {0x4C, 0x66, 0}, + {0x4D, 0, 0}, + {0x4E, 0x4, 0}, + {0x4F, 0xc, 0}, + {0x50, 0, 0}, + {0x51, 0x70, 1}, + {0x56, 0x7, 0}, + {0x57, 0, 0}, + {0x58, 0, 0}, + {0x59, 0x88, 1}, + {0x5A, 0, 0}, + {0x5B, 0x1f, 0}, + {0x5C, 0x20, 1}, + {0x5D, 0x1, 0}, + {0x5E, 0x30, 0}, + {0x5F, 0x70, 0}, + {0x60, 0, 0}, + {0x61, 0, 0}, + {0x62, 0x33, 1}, + {0x63, 0xf, 1}, + {0x64, 0xf, 1}, + {0x65, 0, 0}, + {0x66, 0x11, 0}, + {0x80, 0x3c, 0}, + {0x81, 0x1, 1}, + {0x82, 0xa, 0}, + {0x85, 0, 0}, + {0x86, 0x40, 0}, + {0x87, 0x40, 0}, + {0x88, 0x88, 0}, + {0x89, 0x10, 0}, + {0x8A, 0xf0, 0}, + {0x8B, 0x10, 0}, + {0x8C, 0xf0, 0}, + {0x8F, 0x10, 0}, + {0x90, 0x55, 0}, + {0x91, 0x3f, 1}, + {0x92, 0x36, 1}, + {0x93, 0, 0}, + {0x94, 0, 0}, + {0x95, 0, 0}, + {0x96, 0x87, 0}, + {0x97, 0x11, 0}, + {0x98, 0, 0}, + {0x99, 0x33, 0}, + {0x9A, 0x88, 0}, + {0xA1, 0x20, 1}, + {0xA2, 0x3f, 0}, + {0xA3, 0x44, 0}, + {0xA4, 0x8c, 0}, + {0xA5, 0x6c, 0}, + {0xA6, 0x22, 0}, + {0xA7, 0xbe, 0}, + {0xA8, 0x55, 0}, + {0xAA, 0xc, 0}, + {0xAB, 0xaa, 0}, + {0xAC, 0x2, 0}, + {0xAD, 0, 0}, + {0xAE, 0x10, 0}, + {0xAF, 0x1, 0}, + {0xB0, 0, 0}, + {0xB1, 0, 0}, + {0xB2, 0x80, 0}, + {0xB3, 0x60, 0}, + {0xB4, 0x44, 0}, + {0xB5, 0x55, 0}, + {0xB6, 0x1, 0}, + {0xB7, 0x55, 0}, + {0xB8, 0x1, 0}, + {0xB9, 0x5, 0}, + {0xBA, 0x55, 0}, + {0xBB, 0x55, 0}, + {0xC3, 0, 0}, + {0xC4, 0, 0}, + {0xC5, 0, 0}, + {0xC6, 0, 0}, + {0xC7, 0, 0}, + {0xC8, 0, 0}, + {0xC9, 0, 0}, + {0xCA, 0, 0}, + {0xCB, 0, 0}, + {0xCD, 0, 0}, + {0xCE, 0x5e, 0}, + {0xCF, 0xc, 0}, + {0xD0, 0xc, 0}, + {0xD1, 0xc, 0}, + {0xD2, 0, 0}, + {0xD3, 0x2b, 0}, + {0xD4, 0xc, 0}, + {0xD5, 0, 0}, + {0xD6, 0x70, 1}, + {0xDB, 0x7, 0}, + {0xDC, 0, 0}, + {0xDD, 0, 0}, + {0xDE, 0x88, 1}, + {0xDF, 0, 0}, + {0xE0, 0x1f, 0}, + {0xE1, 0x20, 1}, + {0xE2, 0x1, 0}, + {0xE3, 0x30, 0}, + {0xE4, 0x70, 0}, + {0xE5, 0, 0}, + {0xE6, 0, 0}, + {0xE7, 0x33, 0}, + {0xE8, 0xf, 1}, + {0xE9, 0xf, 1}, + {0xEA, 0, 0}, + {0xEB, 0x11, 0}, + {0x105, 0x3c, 0}, + {0x106, 0x1, 1}, + {0x107, 0xa, 0}, + {0x10A, 0, 0}, + {0x10B, 0x40, 0}, + {0x10C, 0x40, 0}, + {0x10D, 0x88, 0}, + {0x10E, 0x10, 0}, + {0x10F, 0xf0, 0}, + {0x110, 0x10, 0}, + {0x111, 0xf0, 0}, + {0x114, 0x10, 0}, + {0x115, 0x55, 0}, + {0x116, 0x3f, 1}, + {0x117, 0x36, 1}, + {0x118, 0, 0}, + {0x119, 0, 0}, + {0x11A, 0, 0}, + {0x11B, 0x87, 0}, + {0x11C, 0x11, 0}, + {0x11D, 0, 0}, + {0x11E, 0x33, 0}, + {0x11F, 0x88, 0}, + {0x126, 0x20, 1}, + {0x127, 0x3f, 0}, + {0x128, 0x44, 0}, + {0x129, 0x8c, 0}, + {0x12A, 0x6c, 0}, + {0x12B, 0x22, 0}, + {0x12C, 0xbe, 0}, + {0x12D, 0x55, 0}, + {0x12F, 0xc, 0}, + {0x130, 0xaa, 0}, + {0x131, 0x2, 0}, + {0x132, 0, 0}, + {0x133, 0x10, 0}, + {0x134, 0x1, 0}, + {0x135, 0, 0}, + {0x136, 0, 0}, + {0x137, 0x80, 0}, + {0x138, 0x60, 0}, + {0x139, 0x44, 0}, + {0x13A, 0x55, 0}, + {0x13B, 0x1, 0}, + {0x13C, 0x55, 0}, + {0x13D, 0x1, 0}, + {0x13E, 0x5, 0}, + {0x13F, 0x55, 0}, + {0x140, 0x55, 0}, + {0x148, 0, 0}, + {0x149, 0, 0}, + {0x14A, 0, 0}, + {0x14B, 0, 0}, + {0x14C, 0, 0}, + {0x14D, 0, 0}, + {0x14E, 0, 0}, + {0x14F, 0, 0}, + {0x150, 0, 0}, + {0x154, 0xc, 0}, + {0x155, 0xc, 0}, + {0x156, 0xc, 0}, + {0x157, 0, 0}, + {0x158, 0x2b, 0}, + {0x159, 0x84, 0}, + {0x15A, 0x15, 0}, + {0x15B, 0xf, 0}, + {0x15C, 0, 0}, + {0x15D, 0, 0}, + {0x15E, 0, 1}, + {0x15F, 0, 1}, + {0x160, 0, 1}, + {0x161, 0, 1}, + {0x162, 0, 1}, + {0x163, 0, 1}, + {0x164, 0, 0}, + {0x165, 0, 0}, + {0x166, 0, 0}, + {0x167, 0, 0}, + {0x168, 0, 0}, + {0x169, 0, 0}, + {0x16A, 0, 1}, + {0x16B, 0, 1}, + {0x16C, 0, 1}, + {0x16D, 0, 0}, + {0x170, 0, 0}, + {0x171, 0x77, 0}, + {0x172, 0x77, 0}, + {0x173, 0x77, 0}, + {0x174, 0x77, 0}, + {0x175, 0, 0}, + {0x176, 0x3, 0}, + {0x177, 0x37, 0}, + {0x178, 0x3, 0}, + {0x179, 0, 0}, + {0x17B, 0x21, 0}, + {0x17C, 0, 0}, + {0x17D, 0xaa, 0}, + {0x17E, 0, 0}, + {0x190, 0, 0}, + {0x191, 0x77, 0}, + {0x192, 0x77, 0}, + {0x193, 0x77, 0}, + {0x194, 0x77, 0}, + {0x195, 0, 0}, + {0x196, 0x3, 0}, + {0x197, 0x37, 0}, + {0x198, 0x3, 0}, + {0x199, 0, 0}, + {0x19B, 0x21, 0}, + {0x19C, 0, 0}, + {0x19D, 0xaa, 0}, + {0x19E, 0, 0}, + {0x1A1, 0x2, 0}, + {0x1A2, 0xf, 0}, + {0x1A3, 0xf, 0}, + {0x1A4, 0, 1}, + {0x1A5, 0, 1}, + {0x1A6, 0, 1}, + {0x1A7, 0x2, 0}, + {0x1A8, 0xf, 0}, + {0x1A9, 0xf, 0}, + {0x1AA, 0, 1}, + {0x1AB, 0, 1}, + {0x1AC, 0, 1}, + {0x1AD, 0x84, 0}, + {0x1AE, 0x60, 0}, + {0x1AF, 0x47, 0}, + {0x1B0, 0x47, 0}, + {0x1B1, 0, 0}, + {0x1B2, 0, 0}, + {0x1B3, 0, 0}, + {0x1B4, 0, 0}, + {0x1B5, 0, 0}, + {0x1B6, 0, 0}, + {0x1B7, 0xc, 1}, + {0x1B8, 0, 0}, + {0x1B9, 0, 0}, + {0x1BA, 0, 0}, + {0x1BB, 0, 0}, + {0x1BC, 0, 0}, + {0x1BD, 0, 0}, + {0x1BE, 0, 0}, + {0x1BF, 0, 0}, + {0x1C0, 0, 0}, + {0x1C1, 0x1, 1}, + {0x1C2, 0x80, 1}, + {0x1C3, 0, 0}, + {0x1C4, 0, 0}, + {0x1C5, 0, 0}, + {0x1C6, 0, 0}, + {0x1C7, 0, 0}, + {0x1C8, 0, 0}, + {0x1C9, 0, 0}, + {0x1CA, 0, 0}, + {0xFFFF, 0, 0} +}; + +static struct radio_20xx_regs regs_2057_rev5v1[] = { + {0x00, 0x15, 1}, + {0x01, 0x57, 1}, + {0x02, 0x20, 1}, + {0x03, 0x1f, 0}, + {0x04, 0x4, 0}, + {0x05, 0x2, 0}, + {0x06, 0x1, 0}, + {0x07, 0x1, 0}, + {0x08, 0x1, 0}, + {0x09, 0x69, 0}, + {0x0A, 0x66, 0}, + {0x0B, 0x6, 0}, + {0x0C, 0x18, 0}, + {0x0D, 0x3, 0}, + {0x0E, 0x20, 0}, + {0x0F, 0x20, 0}, + {0x10, 0, 0}, + {0x11, 0x7c, 0}, + {0x12, 0x42, 0}, + {0x13, 0xbd, 0}, + {0x14, 0x7, 0}, + {0x15, 0x87, 0}, + {0x16, 0x8, 0}, + {0x17, 0x17, 0}, + {0x18, 0x7, 0}, + {0x19, 0, 0}, + {0x1A, 0x2, 0}, + {0x1B, 0x13, 0}, + {0x1C, 0x3e, 0}, + {0x1D, 0x3e, 0}, + {0x1E, 0x96, 0}, + {0x1F, 0x4, 0}, + {0x20, 0, 0}, + {0x21, 0, 0}, + {0x22, 0x17, 0}, + {0x23, 0x6, 1}, + {0x24, 0x1, 0}, + {0x25, 0x6, 0}, + {0x26, 0x4, 0}, + {0x27, 0xd, 0}, + {0x28, 0xd, 0}, + {0x29, 0x30, 0}, + {0x2A, 0x32, 0}, + {0x2B, 0x8, 0}, + {0x2C, 0x1c, 0}, + {0x2D, 0x2, 0}, + {0x2E, 0x4, 0}, + {0x2F, 0x7f, 0}, + {0x30, 0x27, 0}, + {0x31, 0, 1}, + {0x32, 0, 1}, + {0x33, 0, 1}, + {0x34, 0, 0}, + {0x35, 0x20, 0}, + {0x36, 0x18, 0}, + {0x37, 0x7, 0}, + {0x38, 0x66, 0}, + {0x39, 0x66, 0}, + {0x3C, 0xff, 0}, + {0x3D, 0xff, 0}, + {0x40, 0x16, 0}, + {0x41, 0x7, 0}, + {0x45, 0x3, 0}, + {0x46, 0x1, 0}, + {0x47, 0x7, 0}, + {0x4B, 0x66, 0}, + {0x4C, 0x66, 0}, + {0x4D, 0, 0}, + {0x4E, 0x4, 0}, + {0x4F, 0xc, 0}, + {0x50, 0, 0}, + {0x51, 0x70, 1}, + {0x56, 0x7, 0}, + {0x57, 0, 0}, + {0x58, 0, 0}, + {0x59, 0x88, 1}, + {0x5A, 0, 0}, + {0x5B, 0x1f, 0}, + {0x5C, 0x20, 1}, + {0x5D, 0x1, 0}, + {0x5E, 0x30, 0}, + {0x5F, 0x70, 0}, + {0x60, 0, 0}, + {0x61, 0, 0}, + {0x62, 0x33, 1}, + {0x63, 0xf, 1}, + {0x64, 0xf, 1}, + {0x65, 0, 0}, + {0x66, 0x11, 0}, + {0x80, 0x3c, 0}, + {0x81, 0x1, 1}, + {0x82, 0xa, 0}, + {0x85, 0, 0}, + {0x86, 0x40, 0}, + {0x87, 0x40, 0}, + {0x88, 0x88, 0}, + {0x89, 0x10, 0}, + {0x8A, 0xf0, 0}, + {0x8B, 0x10, 0}, + {0x8C, 0xf0, 0}, + {0x8F, 0x10, 0}, + {0x90, 0x55, 0}, + {0x91, 0x3f, 1}, + {0x92, 0x36, 1}, + {0x93, 0, 0}, + {0x94, 0, 0}, + {0x95, 0, 0}, + {0x96, 0x87, 0}, + {0x97, 0x11, 0}, + {0x98, 0, 0}, + {0x99, 0x33, 0}, + {0x9A, 0x88, 0}, + {0xA1, 0x20, 1}, + {0xA2, 0x3f, 0}, + {0xA3, 0x44, 0}, + {0xA4, 0x8c, 0}, + {0xA5, 0x6c, 0}, + {0xA6, 0x22, 0}, + {0xA7, 0xbe, 0}, + {0xA8, 0x55, 0}, + {0xAA, 0xc, 0}, + {0xAB, 0xaa, 0}, + {0xAC, 0x2, 0}, + {0xAD, 0, 0}, + {0xAE, 0x10, 0}, + {0xAF, 0x1, 0}, + {0xB0, 0, 0}, + {0xB1, 0, 0}, + {0xB2, 0x80, 0}, + {0xB3, 0x60, 0}, + {0xB4, 0x44, 0}, + {0xB5, 0x55, 0}, + {0xB6, 0x1, 0}, + {0xB7, 0x55, 0}, + {0xB8, 0x1, 0}, + {0xB9, 0x5, 0}, + {0xBA, 0x55, 0}, + {0xBB, 0x55, 0}, + {0xC3, 0, 0}, + {0xC4, 0, 0}, + {0xC5, 0, 0}, + {0xC6, 0, 0}, + {0xC7, 0, 0}, + {0xC8, 0, 0}, + {0xC9, 0x1, 1}, + {0xCA, 0, 0}, + {0xCB, 0, 0}, + {0xCD, 0, 0}, + {0xCE, 0x5e, 0}, + {0xCF, 0xc, 0}, + {0xD0, 0xc, 0}, + {0xD1, 0xc, 0}, + {0xD2, 0, 0}, + {0xD3, 0x2b, 0}, + {0xD4, 0xc, 0}, + {0xD5, 0, 0}, + {0xD6, 0x70, 1}, + {0xDB, 0x7, 0}, + {0xDC, 0, 0}, + {0xDD, 0, 0}, + {0xDE, 0x88, 1}, + {0xDF, 0, 0}, + {0xE0, 0x1f, 0}, + {0xE1, 0x20, 1}, + {0xE2, 0x1, 0}, + {0xE3, 0x30, 0}, + {0xE4, 0x70, 0}, + {0xE5, 0, 0}, + {0xE6, 0, 0}, + {0xE7, 0x33, 0}, + {0xE8, 0xf, 1}, + {0xE9, 0xf, 1}, + {0xEA, 0, 0}, + {0xEB, 0x11, 0}, + {0x105, 0x3c, 0}, + {0x106, 0x1, 1}, + {0x107, 0xa, 0}, + {0x10A, 0, 0}, + {0x10B, 0x40, 0}, + {0x10C, 0x40, 0}, + {0x10D, 0x88, 0}, + {0x10E, 0x10, 0}, + {0x10F, 0xf0, 0}, + {0x110, 0x10, 0}, + {0x111, 0xf0, 0}, + {0x114, 0x10, 0}, + {0x115, 0x55, 0}, + {0x116, 0x3f, 1}, + {0x117, 0x36, 1}, + {0x118, 0, 0}, + {0x119, 0, 0}, + {0x11A, 0, 0}, + {0x11B, 0x87, 0}, + {0x11C, 0x11, 0}, + {0x11D, 0, 0}, + {0x11E, 0x33, 0}, + {0x11F, 0x88, 0}, + {0x126, 0x20, 1}, + {0x127, 0x3f, 0}, + {0x128, 0x44, 0}, + {0x129, 0x8c, 0}, + {0x12A, 0x6c, 0}, + {0x12B, 0x22, 0}, + {0x12C, 0xbe, 0}, + {0x12D, 0x55, 0}, + {0x12F, 0xc, 0}, + {0x130, 0xaa, 0}, + {0x131, 0x2, 0}, + {0x132, 0, 0}, + {0x133, 0x10, 0}, + {0x134, 0x1, 0}, + {0x135, 0, 0}, + {0x136, 0, 0}, + {0x137, 0x80, 0}, + {0x138, 0x60, 0}, + {0x139, 0x44, 0}, + {0x13A, 0x55, 0}, + {0x13B, 0x1, 0}, + {0x13C, 0x55, 0}, + {0x13D, 0x1, 0}, + {0x13E, 0x5, 0}, + {0x13F, 0x55, 0}, + {0x140, 0x55, 0}, + {0x148, 0, 0}, + {0x149, 0, 0}, + {0x14A, 0, 0}, + {0x14B, 0, 0}, + {0x14C, 0, 0}, + {0x14D, 0, 0}, + {0x14E, 0x1, 1}, + {0x14F, 0, 0}, + {0x150, 0, 0}, + {0x154, 0xc, 0}, + {0x155, 0xc, 0}, + {0x156, 0xc, 0}, + {0x157, 0, 0}, + {0x158, 0x2b, 0}, + {0x159, 0x84, 0}, + {0x15A, 0x15, 0}, + {0x15B, 0xf, 0}, + {0x15C, 0, 0}, + {0x15D, 0, 0}, + {0x15E, 0, 1}, + {0x15F, 0, 1}, + {0x160, 0, 1}, + {0x161, 0, 1}, + {0x162, 0, 1}, + {0x163, 0, 1}, + {0x164, 0, 0}, + {0x165, 0, 0}, + {0x166, 0, 0}, + {0x167, 0, 0}, + {0x168, 0, 0}, + {0x169, 0, 0}, + {0x16A, 0, 1}, + {0x16B, 0, 1}, + {0x16C, 0, 1}, + {0x16D, 0, 0}, + {0x170, 0, 0}, + {0x171, 0x77, 0}, + {0x172, 0x77, 0}, + {0x173, 0x77, 0}, + {0x174, 0x77, 0}, + {0x175, 0, 0}, + {0x176, 0x3, 0}, + {0x177, 0x37, 0}, + {0x178, 0x3, 0}, + {0x179, 0, 0}, + {0x17B, 0x21, 0}, + {0x17C, 0, 0}, + {0x17D, 0xaa, 0}, + {0x17E, 0, 0}, + {0x190, 0, 0}, + {0x191, 0x77, 0}, + {0x192, 0x77, 0}, + {0x193, 0x77, 0}, + {0x194, 0x77, 0}, + {0x195, 0, 0}, + {0x196, 0x3, 0}, + {0x197, 0x37, 0}, + {0x198, 0x3, 0}, + {0x199, 0, 0}, + {0x19B, 0x21, 0}, + {0x19C, 0, 0}, + {0x19D, 0xaa, 0}, + {0x19E, 0, 0}, + {0x1A1, 0x2, 0}, + {0x1A2, 0xf, 0}, + {0x1A3, 0xf, 0}, + {0x1A4, 0, 1}, + {0x1A5, 0, 1}, + {0x1A6, 0, 1}, + {0x1A7, 0x2, 0}, + {0x1A8, 0xf, 0}, + {0x1A9, 0xf, 0}, + {0x1AA, 0, 1}, + {0x1AB, 0, 1}, + {0x1AC, 0, 1}, + {0x1AD, 0x84, 0}, + {0x1AE, 0x60, 0}, + {0x1AF, 0x47, 0}, + {0x1B0, 0x47, 0}, + {0x1B1, 0, 0}, + {0x1B2, 0, 0}, + {0x1B3, 0, 0}, + {0x1B4, 0, 0}, + {0x1B5, 0, 0}, + {0x1B6, 0, 0}, + {0x1B7, 0xc, 1}, + {0x1B8, 0, 0}, + {0x1B9, 0, 0}, + {0x1BA, 0, 0}, + {0x1BB, 0, 0}, + {0x1BC, 0, 0}, + {0x1BD, 0, 0}, + {0x1BE, 0, 0}, + {0x1BF, 0, 0}, + {0x1C0, 0, 0}, + {0x1C1, 0x1, 1}, + {0x1C2, 0x80, 1}, + {0x1C3, 0, 0}, + {0x1C4, 0, 0}, + {0x1C5, 0, 0}, + {0x1C6, 0, 0}, + {0x1C7, 0, 0}, + {0x1C8, 0, 0}, + {0x1C9, 0, 0}, + {0x1CA, 0, 0}, + {0xFFFF, 0, 0} +}; + +static struct radio_20xx_regs regs_2057_rev7[] = { + {0x00, 0, 1}, + {0x01, 0x57, 1}, + {0x02, 0x20, 1}, + {0x03, 0x1f, 0}, + {0x04, 0x4, 0}, + {0x05, 0x2, 0}, + {0x06, 0x1, 0}, + {0x07, 0x1, 0}, + {0x08, 0x1, 0}, + {0x09, 0x69, 0}, + {0x0A, 0x66, 0}, + {0x0B, 0x6, 0}, + {0x0C, 0x18, 0}, + {0x0D, 0x3, 0}, + {0x0E, 0x20, 0}, + {0x0F, 0x20, 0}, + {0x10, 0, 0}, + {0x11, 0x7c, 0}, + {0x12, 0x42, 0}, + {0x13, 0xbd, 0}, + {0x14, 0x7, 0}, + {0x15, 0x87, 0}, + {0x16, 0x8, 0}, + {0x17, 0x17, 0}, + {0x18, 0x7, 0}, + {0x19, 0, 0}, + {0x1A, 0x2, 0}, + {0x1B, 0x13, 0}, + {0x1C, 0x3e, 0}, + {0x1D, 0x3e, 0}, + {0x1E, 0x96, 0}, + {0x1F, 0x4, 0}, + {0x20, 0, 0}, + {0x21, 0, 0}, + {0x22, 0x17, 0}, + {0x23, 0x6, 0}, + {0x24, 0x1, 0}, + {0x25, 0x6, 0}, + {0x26, 0x4, 0}, + {0x27, 0xd, 0}, + {0x28, 0xd, 0}, + {0x29, 0x30, 0}, + {0x2A, 0x32, 0}, + {0x2B, 0x8, 0}, + {0x2C, 0x1c, 0}, + {0x2D, 0x2, 0}, + {0x2E, 0x4, 0}, + {0x2F, 0x7f, 0}, + {0x30, 0x27, 0}, + {0x31, 0, 1}, + {0x32, 0, 1}, + {0x33, 0, 1}, + {0x34, 0, 0}, + {0x35, 0x20, 0}, + {0x36, 0x18, 0}, + {0x37, 0x7, 0}, + {0x38, 0x66, 0}, + {0x39, 0x66, 0}, + {0x3A, 0x66, 0}, + {0x3B, 0x66, 0}, + {0x3C, 0xff, 0}, + {0x3D, 0xff, 0}, + {0x3E, 0xff, 0}, + {0x3F, 0xff, 0}, + {0x40, 0x16, 0}, + {0x41, 0x7, 0}, + {0x42, 0x19, 0}, + {0x43, 0x7, 0}, + {0x44, 0x6, 0}, + {0x45, 0x3, 0}, + {0x46, 0x1, 0}, + {0x47, 0x7, 0}, + {0x48, 0x33, 0}, + {0x49, 0x5, 0}, + {0x4A, 0x77, 0}, + {0x4B, 0x66, 0}, + {0x4C, 0x66, 0}, + {0x4D, 0, 0}, + {0x4E, 0x4, 0}, + {0x4F, 0xc, 0}, + {0x50, 0, 0}, + {0x51, 0x70, 1}, + {0x56, 0x7, 0}, + {0x57, 0, 0}, + {0x58, 0, 0}, + {0x59, 0x88, 1}, + {0x5A, 0, 0}, + {0x5B, 0x1f, 0}, + {0x5C, 0x20, 1}, + {0x5D, 0x1, 0}, + {0x5E, 0x30, 0}, + {0x5F, 0x70, 0}, + {0x60, 0, 0}, + {0x61, 0, 0}, + {0x62, 0x33, 1}, + {0x63, 0xf, 1}, + {0x64, 0x13, 1}, + {0x65, 0, 0}, + {0x66, 0xee, 1}, + {0x69, 0, 0}, + {0x6A, 0x7e, 0}, + {0x6B, 0x3f, 0}, + {0x6C, 0x7f, 0}, + {0x6D, 0x78, 0}, + {0x6E, 0x58, 1}, + {0x6F, 0x88, 0}, + {0x70, 0x8, 0}, + {0x71, 0xf, 0}, + {0x72, 0xbc, 0}, + {0x73, 0x8, 0}, + {0x74, 0x60, 0}, + {0x75, 0x13, 1}, + {0x76, 0x70, 0}, + {0x77, 0, 0}, + {0x78, 0, 0}, + {0x79, 0, 0}, + {0x7A, 0x33, 0}, + {0x7B, 0x13, 1}, + {0x7C, 0x14, 1}, + {0x7D, 0xee, 1}, + {0x80, 0x3c, 0}, + {0x81, 0x1, 1}, + {0x82, 0xa, 0}, + {0x83, 0x9d, 0}, + {0x84, 0xa, 0}, + {0x85, 0, 0}, + {0x86, 0x40, 0}, + {0x87, 0x40, 0}, + {0x88, 0x88, 0}, + {0x89, 0x10, 0}, + {0x8A, 0xf0, 0}, + {0x8B, 0x10, 0}, + {0x8C, 0xf0, 0}, + {0x8D, 0, 0}, + {0x8E, 0, 0}, + {0x8F, 0x10, 0}, + {0x90, 0x55, 0}, + {0x91, 0x3f, 1}, + {0x92, 0x36, 1}, + {0x93, 0, 0}, + {0x94, 0, 0}, + {0x95, 0, 0}, + {0x96, 0x87, 0}, + {0x97, 0x11, 0}, + {0x98, 0, 0}, + {0x99, 0x33, 0}, + {0x9A, 0x88, 0}, + {0x9B, 0, 0}, + {0x9C, 0x87, 0}, + {0x9D, 0x11, 0}, + {0x9E, 0, 0}, + {0x9F, 0x33, 0}, + {0xA0, 0x88, 0}, + {0xA1, 0x20, 1}, + {0xA2, 0x3f, 0}, + {0xA3, 0x44, 0}, + {0xA4, 0x8c, 0}, + {0xA5, 0x6c, 0}, + {0xA6, 0x22, 0}, + {0xA7, 0xbe, 0}, + {0xA8, 0x55, 0}, + {0xAA, 0xc, 0}, + {0xAB, 0xaa, 0}, + {0xAC, 0x2, 0}, + {0xAD, 0, 0}, + {0xAE, 0x10, 0}, + {0xAF, 0x1, 0}, + {0xB0, 0, 0}, + {0xB1, 0, 0}, + {0xB2, 0x80, 0}, + {0xB3, 0x60, 0}, + {0xB4, 0x44, 0}, + {0xB5, 0x55, 0}, + {0xB6, 0x1, 0}, + {0xB7, 0x55, 0}, + {0xB8, 0x1, 0}, + {0xB9, 0x5, 0}, + {0xBA, 0x55, 0}, + {0xBB, 0x55, 0}, + {0xC1, 0, 0}, + {0xC2, 0, 0}, + {0xC3, 0, 0}, + {0xC4, 0, 0}, + {0xC5, 0, 0}, + {0xC6, 0, 0}, + {0xC7, 0, 0}, + {0xC8, 0, 0}, + {0xC9, 0, 0}, + {0xCA, 0, 0}, + {0xCB, 0, 0}, + {0xCC, 0, 0}, + {0xCD, 0, 0}, + {0xCE, 0x5e, 0}, + {0xCF, 0xc, 0}, + {0xD0, 0xc, 0}, + {0xD1, 0xc, 0}, + {0xD2, 0, 0}, + {0xD3, 0x2b, 0}, + {0xD4, 0xc, 0}, + {0xD5, 0, 0}, + {0xD6, 0x70, 1}, + {0xDB, 0x7, 0}, + {0xDC, 0, 0}, + {0xDD, 0, 0}, + {0xDE, 0x88, 1}, + {0xDF, 0, 0}, + {0xE0, 0x1f, 0}, + {0xE1, 0x20, 1}, + {0xE2, 0x1, 0}, + {0xE3, 0x30, 0}, + {0xE4, 0x70, 0}, + {0xE5, 0, 0}, + {0xE6, 0, 0}, + {0xE7, 0x33, 0}, + {0xE8, 0xf, 1}, + {0xE9, 0x13, 1}, + {0xEA, 0, 0}, + {0xEB, 0xee, 1}, + {0xEE, 0, 0}, + {0xEF, 0x7e, 0}, + {0xF0, 0x3f, 0}, + {0xF1, 0x7f, 0}, + {0xF2, 0x78, 0}, + {0xF3, 0x58, 1}, + {0xF4, 0x88, 0}, + {0xF5, 0x8, 0}, + {0xF6, 0xf, 0}, + {0xF7, 0xbc, 0}, + {0xF8, 0x8, 0}, + {0xF9, 0x60, 0}, + {0xFA, 0x13, 1}, + {0xFB, 0x70, 0}, + {0xFC, 0, 0}, + {0xFD, 0, 0}, + {0xFE, 0, 0}, + {0xFF, 0x33, 0}, + {0x100, 0x13, 1}, + {0x101, 0x14, 1}, + {0x102, 0xee, 1}, + {0x105, 0x3c, 0}, + {0x106, 0x1, 1}, + {0x107, 0xa, 0}, + {0x108, 0x9d, 0}, + {0x109, 0xa, 0}, + {0x10A, 0, 0}, + {0x10B, 0x40, 0}, + {0x10C, 0x40, 0}, + {0x10D, 0x88, 0}, + {0x10E, 0x10, 0}, + {0x10F, 0xf0, 0}, + {0x110, 0x10, 0}, + {0x111, 0xf0, 0}, + {0x112, 0, 0}, + {0x113, 0, 0}, + {0x114, 0x10, 0}, + {0x115, 0x55, 0}, + {0x116, 0x3f, 1}, + {0x117, 0x36, 1}, + {0x118, 0, 0}, + {0x119, 0, 0}, + {0x11A, 0, 0}, + {0x11B, 0x87, 0}, + {0x11C, 0x11, 0}, + {0x11D, 0, 0}, + {0x11E, 0x33, 0}, + {0x11F, 0x88, 0}, + {0x120, 0, 0}, + {0x121, 0x87, 0}, + {0x122, 0x11, 0}, + {0x123, 0, 0}, + {0x124, 0x33, 0}, + {0x125, 0x88, 0}, + {0x126, 0x20, 1}, + {0x127, 0x3f, 0}, + {0x128, 0x44, 0}, + {0x129, 0x8c, 0}, + {0x12A, 0x6c, 0}, + {0x12B, 0x22, 0}, + {0x12C, 0xbe, 0}, + {0x12D, 0x55, 0}, + {0x12F, 0xc, 0}, + {0x130, 0xaa, 0}, + {0x131, 0x2, 0}, + {0x132, 0, 0}, + {0x133, 0x10, 0}, + {0x134, 0x1, 0}, + {0x135, 0, 0}, + {0x136, 0, 0}, + {0x137, 0x80, 0}, + {0x138, 0x60, 0}, + {0x139, 0x44, 0}, + {0x13A, 0x55, 0}, + {0x13B, 0x1, 0}, + {0x13C, 0x55, 0}, + {0x13D, 0x1, 0}, + {0x13E, 0x5, 0}, + {0x13F, 0x55, 0}, + {0x140, 0x55, 0}, + {0x146, 0, 0}, + {0x147, 0, 0}, + {0x148, 0, 0}, + {0x149, 0, 0}, + {0x14A, 0, 0}, + {0x14B, 0, 0}, + {0x14C, 0, 0}, + {0x14D, 0, 0}, + {0x14E, 0, 0}, + {0x14F, 0, 0}, + {0x150, 0, 0}, + {0x151, 0, 0}, + {0x154, 0xc, 0}, + {0x155, 0xc, 0}, + {0x156, 0xc, 0}, + {0x157, 0, 0}, + {0x158, 0x2b, 0}, + {0x159, 0x84, 0}, + {0x15A, 0x15, 0}, + {0x15B, 0xf, 0}, + {0x15C, 0, 0}, + {0x15D, 0, 0}, + {0x15E, 0, 1}, + {0x15F, 0, 1}, + {0x160, 0, 1}, + {0x161, 0, 1}, + {0x162, 0, 1}, + {0x163, 0, 1}, + {0x164, 0, 0}, + {0x165, 0, 0}, + {0x166, 0, 0}, + {0x167, 0, 0}, + {0x168, 0, 0}, + {0x169, 0, 0}, + {0x16A, 0, 1}, + {0x16B, 0, 1}, + {0x16C, 0, 1}, + {0x16D, 0, 0}, + {0x170, 0, 0}, + {0x171, 0x77, 0}, + {0x172, 0x77, 0}, + {0x173, 0x77, 0}, + {0x174, 0x77, 0}, + {0x175, 0, 0}, + {0x176, 0x3, 0}, + {0x177, 0x37, 0}, + {0x178, 0x3, 0}, + {0x179, 0, 0}, + {0x17A, 0x21, 0}, + {0x17B, 0x21, 0}, + {0x17C, 0, 0}, + {0x17D, 0xaa, 0}, + {0x17E, 0, 0}, + {0x17F, 0xaa, 0}, + {0x180, 0, 0}, + {0x190, 0, 0}, + {0x191, 0x77, 0}, + {0x192, 0x77, 0}, + {0x193, 0x77, 0}, + {0x194, 0x77, 0}, + {0x195, 0, 0}, + {0x196, 0x3, 0}, + {0x197, 0x37, 0}, + {0x198, 0x3, 0}, + {0x199, 0, 0}, + {0x19A, 0x21, 0}, + {0x19B, 0x21, 0}, + {0x19C, 0, 0}, + {0x19D, 0xaa, 0}, + {0x19E, 0, 0}, + {0x19F, 0xaa, 0}, + {0x1A0, 0, 0}, + {0x1A1, 0x2, 0}, + {0x1A2, 0xf, 0}, + {0x1A3, 0xf, 0}, + {0x1A4, 0, 1}, + {0x1A5, 0, 1}, + {0x1A6, 0, 1}, + {0x1A7, 0x2, 0}, + {0x1A8, 0xf, 0}, + {0x1A9, 0xf, 0}, + {0x1AA, 0, 1}, + {0x1AB, 0, 1}, + {0x1AC, 0, 1}, + {0x1AD, 0x84, 0}, + {0x1AE, 0x60, 0}, + {0x1AF, 0x47, 0}, + {0x1B0, 0x47, 0}, + {0x1B1, 0, 0}, + {0x1B2, 0, 0}, + {0x1B3, 0, 0}, + {0x1B4, 0, 0}, + {0x1B5, 0, 0}, + {0x1B6, 0, 0}, + {0x1B7, 0x5, 1}, + {0x1B8, 0, 0}, + {0x1B9, 0, 0}, + {0x1BA, 0, 0}, + {0x1BB, 0, 0}, + {0x1BC, 0, 0}, + {0x1BD, 0, 0}, + {0x1BE, 0, 0}, + {0x1BF, 0, 0}, + {0x1C0, 0, 0}, + {0x1C1, 0, 0}, + {0x1C2, 0xa0, 1}, + {0x1C3, 0, 0}, + {0x1C4, 0, 0}, + {0x1C5, 0, 0}, + {0x1C6, 0, 0}, + {0x1C7, 0, 0}, + {0x1C8, 0, 0}, + {0x1C9, 0, 0}, + {0x1CA, 0, 0}, + {0xFFFF, 0, 0} +}; + +static struct radio_20xx_regs regs_2057_rev8[] = { + {0x00, 0x8, 1}, + {0x01, 0x57, 1}, + {0x02, 0x20, 1}, + {0x03, 0x1f, 0}, + {0x04, 0x4, 0}, + {0x05, 0x2, 0}, + {0x06, 0x1, 0}, + {0x07, 0x1, 0}, + {0x08, 0x1, 0}, + {0x09, 0x69, 0}, + {0x0A, 0x66, 0}, + {0x0B, 0x6, 0}, + {0x0C, 0x18, 0}, + {0x0D, 0x3, 0}, + {0x0E, 0x20, 0}, + {0x0F, 0x20, 0}, + {0x10, 0, 0}, + {0x11, 0x7c, 0}, + {0x12, 0x42, 0}, + {0x13, 0xbd, 0}, + {0x14, 0x7, 0}, + {0x15, 0x87, 0}, + {0x16, 0x8, 0}, + {0x17, 0x17, 0}, + {0x18, 0x7, 0}, + {0x19, 0, 0}, + {0x1A, 0x2, 0}, + {0x1B, 0x13, 0}, + {0x1C, 0x3e, 0}, + {0x1D, 0x3e, 0}, + {0x1E, 0x96, 0}, + {0x1F, 0x4, 0}, + {0x20, 0, 0}, + {0x21, 0, 0}, + {0x22, 0x17, 0}, + {0x23, 0x6, 0}, + {0x24, 0x1, 0}, + {0x25, 0x6, 0}, + {0x26, 0x4, 0}, + {0x27, 0xd, 0}, + {0x28, 0xd, 0}, + {0x29, 0x30, 0}, + {0x2A, 0x32, 0}, + {0x2B, 0x8, 0}, + {0x2C, 0x1c, 0}, + {0x2D, 0x2, 0}, + {0x2E, 0x4, 0}, + {0x2F, 0x7f, 0}, + {0x30, 0x27, 0}, + {0x31, 0, 1}, + {0x32, 0, 1}, + {0x33, 0, 1}, + {0x34, 0, 0}, + {0x35, 0x20, 0}, + {0x36, 0x18, 0}, + {0x37, 0x7, 0}, + {0x38, 0x66, 0}, + {0x39, 0x66, 0}, + {0x3A, 0x66, 0}, + {0x3B, 0x66, 0}, + {0x3C, 0xff, 0}, + {0x3D, 0xff, 0}, + {0x3E, 0xff, 0}, + {0x3F, 0xff, 0}, + {0x40, 0x16, 0}, + {0x41, 0x7, 0}, + {0x42, 0x19, 0}, + {0x43, 0x7, 0}, + {0x44, 0x6, 0}, + {0x45, 0x3, 0}, + {0x46, 0x1, 0}, + {0x47, 0x7, 0}, + {0x48, 0x33, 0}, + {0x49, 0x5, 0}, + {0x4A, 0x77, 0}, + {0x4B, 0x66, 0}, + {0x4C, 0x66, 0}, + {0x4D, 0, 0}, + {0x4E, 0x4, 0}, + {0x4F, 0xc, 0}, + {0x50, 0, 0}, + {0x51, 0x70, 1}, + {0x56, 0x7, 0}, + {0x57, 0, 0}, + {0x58, 0, 0}, + {0x59, 0x88, 1}, + {0x5A, 0, 0}, + {0x5B, 0x1f, 0}, + {0x5C, 0x20, 1}, + {0x5D, 0x1, 0}, + {0x5E, 0x30, 0}, + {0x5F, 0x70, 0}, + {0x60, 0, 0}, + {0x61, 0, 0}, + {0x62, 0x33, 1}, + {0x63, 0xf, 1}, + {0x64, 0xf, 1}, + {0x65, 0, 0}, + {0x66, 0x11, 0}, + {0x69, 0, 0}, + {0x6A, 0x7e, 0}, + {0x6B, 0x3f, 0}, + {0x6C, 0x7f, 0}, + {0x6D, 0x78, 0}, + {0x6E, 0x58, 1}, + {0x6F, 0x88, 0}, + {0x70, 0x8, 0}, + {0x71, 0xf, 0}, + {0x72, 0xbc, 0}, + {0x73, 0x8, 0}, + {0x74, 0x60, 0}, + {0x75, 0x13, 1}, + {0x76, 0x70, 0}, + {0x77, 0, 0}, + {0x78, 0, 0}, + {0x79, 0, 0}, + {0x7A, 0x33, 0}, + {0x7B, 0x13, 1}, + {0x7C, 0xf, 1}, + {0x7D, 0xee, 1}, + {0x80, 0x3c, 0}, + {0x81, 0x1, 1}, + {0x82, 0xa, 0}, + {0x83, 0x9d, 0}, + {0x84, 0xa, 0}, + {0x85, 0, 0}, + {0x86, 0x40, 0}, + {0x87, 0x40, 0}, + {0x88, 0x88, 0}, + {0x89, 0x10, 0}, + {0x8A, 0xf0, 0}, + {0x8B, 0x10, 0}, + {0x8C, 0xf0, 0}, + {0x8D, 0, 0}, + {0x8E, 0, 0}, + {0x8F, 0x10, 0}, + {0x90, 0x55, 0}, + {0x91, 0x3f, 1}, + {0x92, 0x36, 1}, + {0x93, 0, 0}, + {0x94, 0, 0}, + {0x95, 0, 0}, + {0x96, 0x87, 0}, + {0x97, 0x11, 0}, + {0x98, 0, 0}, + {0x99, 0x33, 0}, + {0x9A, 0x88, 0}, + {0x9B, 0, 0}, + {0x9C, 0x87, 0}, + {0x9D, 0x11, 0}, + {0x9E, 0, 0}, + {0x9F, 0x33, 0}, + {0xA0, 0x88, 0}, + {0xA1, 0x20, 1}, + {0xA2, 0x3f, 0}, + {0xA3, 0x44, 0}, + {0xA4, 0x8c, 0}, + {0xA5, 0x6c, 0}, + {0xA6, 0x22, 0}, + {0xA7, 0xbe, 0}, + {0xA8, 0x55, 0}, + {0xAA, 0xc, 0}, + {0xAB, 0xaa, 0}, + {0xAC, 0x2, 0}, + {0xAD, 0, 0}, + {0xAE, 0x10, 0}, + {0xAF, 0x1, 0}, + {0xB0, 0, 0}, + {0xB1, 0, 0}, + {0xB2, 0x80, 0}, + {0xB3, 0x60, 0}, + {0xB4, 0x44, 0}, + {0xB5, 0x55, 0}, + {0xB6, 0x1, 0}, + {0xB7, 0x55, 0}, + {0xB8, 0x1, 0}, + {0xB9, 0x5, 0}, + {0xBA, 0x55, 0}, + {0xBB, 0x55, 0}, + {0xC1, 0, 0}, + {0xC2, 0, 0}, + {0xC3, 0, 0}, + {0xC4, 0, 0}, + {0xC5, 0, 0}, + {0xC6, 0, 0}, + {0xC7, 0, 0}, + {0xC8, 0, 0}, + {0xC9, 0x1, 1}, + {0xCA, 0, 0}, + {0xCB, 0, 0}, + {0xCC, 0, 0}, + {0xCD, 0, 0}, + {0xCE, 0x5e, 0}, + {0xCF, 0xc, 0}, + {0xD0, 0xc, 0}, + {0xD1, 0xc, 0}, + {0xD2, 0, 0}, + {0xD3, 0x2b, 0}, + {0xD4, 0xc, 0}, + {0xD5, 0, 0}, + {0xD6, 0x70, 1}, + {0xDB, 0x7, 0}, + {0xDC, 0, 0}, + {0xDD, 0, 0}, + {0xDE, 0x88, 1}, + {0xDF, 0, 0}, + {0xE0, 0x1f, 0}, + {0xE1, 0x20, 1}, + {0xE2, 0x1, 0}, + {0xE3, 0x30, 0}, + {0xE4, 0x70, 0}, + {0xE5, 0, 0}, + {0xE6, 0, 0}, + {0xE7, 0x33, 0}, + {0xE8, 0xf, 1}, + {0xE9, 0xf, 1}, + {0xEA, 0, 0}, + {0xEB, 0x11, 0}, + {0xEE, 0, 0}, + {0xEF, 0x7e, 0}, + {0xF0, 0x3f, 0}, + {0xF1, 0x7f, 0}, + {0xF2, 0x78, 0}, + {0xF3, 0x58, 1}, + {0xF4, 0x88, 0}, + {0xF5, 0x8, 0}, + {0xF6, 0xf, 0}, + {0xF7, 0xbc, 0}, + {0xF8, 0x8, 0}, + {0xF9, 0x60, 0}, + {0xFA, 0x13, 1}, + {0xFB, 0x70, 0}, + {0xFC, 0, 0}, + {0xFD, 0, 0}, + {0xFE, 0, 0}, + {0xFF, 0x33, 0}, + {0x100, 0x13, 1}, + {0x101, 0xf, 1}, + {0x102, 0xee, 1}, + {0x105, 0x3c, 0}, + {0x106, 0x1, 1}, + {0x107, 0xa, 0}, + {0x108, 0x9d, 0}, + {0x109, 0xa, 0}, + {0x10A, 0, 0}, + {0x10B, 0x40, 0}, + {0x10C, 0x40, 0}, + {0x10D, 0x88, 0}, + {0x10E, 0x10, 0}, + {0x10F, 0xf0, 0}, + {0x110, 0x10, 0}, + {0x111, 0xf0, 0}, + {0x112, 0, 0}, + {0x113, 0, 0}, + {0x114, 0x10, 0}, + {0x115, 0x55, 0}, + {0x116, 0x3f, 1}, + {0x117, 0x36, 1}, + {0x118, 0, 0}, + {0x119, 0, 0}, + {0x11A, 0, 0}, + {0x11B, 0x87, 0}, + {0x11C, 0x11, 0}, + {0x11D, 0, 0}, + {0x11E, 0x33, 0}, + {0x11F, 0x88, 0}, + {0x120, 0, 0}, + {0x121, 0x87, 0}, + {0x122, 0x11, 0}, + {0x123, 0, 0}, + {0x124, 0x33, 0}, + {0x125, 0x88, 0}, + {0x126, 0x20, 1}, + {0x127, 0x3f, 0}, + {0x128, 0x44, 0}, + {0x129, 0x8c, 0}, + {0x12A, 0x6c, 0}, + {0x12B, 0x22, 0}, + {0x12C, 0xbe, 0}, + {0x12D, 0x55, 0}, + {0x12F, 0xc, 0}, + {0x130, 0xaa, 0}, + {0x131, 0x2, 0}, + {0x132, 0, 0}, + {0x133, 0x10, 0}, + {0x134, 0x1, 0}, + {0x135, 0, 0}, + {0x136, 0, 0}, + {0x137, 0x80, 0}, + {0x138, 0x60, 0}, + {0x139, 0x44, 0}, + {0x13A, 0x55, 0}, + {0x13B, 0x1, 0}, + {0x13C, 0x55, 0}, + {0x13D, 0x1, 0}, + {0x13E, 0x5, 0}, + {0x13F, 0x55, 0}, + {0x140, 0x55, 0}, + {0x146, 0, 0}, + {0x147, 0, 0}, + {0x148, 0, 0}, + {0x149, 0, 0}, + {0x14A, 0, 0}, + {0x14B, 0, 0}, + {0x14C, 0, 0}, + {0x14D, 0, 0}, + {0x14E, 0x1, 1}, + {0x14F, 0, 0}, + {0x150, 0, 0}, + {0x151, 0, 0}, + {0x154, 0xc, 0}, + {0x155, 0xc, 0}, + {0x156, 0xc, 0}, + {0x157, 0, 0}, + {0x158, 0x2b, 0}, + {0x159, 0x84, 0}, + {0x15A, 0x15, 0}, + {0x15B, 0xf, 0}, + {0x15C, 0, 0}, + {0x15D, 0, 0}, + {0x15E, 0, 1}, + {0x15F, 0, 1}, + {0x160, 0, 1}, + {0x161, 0, 1}, + {0x162, 0, 1}, + {0x163, 0, 1}, + {0x164, 0, 0}, + {0x165, 0, 0}, + {0x166, 0, 0}, + {0x167, 0, 0}, + {0x168, 0, 0}, + {0x169, 0, 0}, + {0x16A, 0, 1}, + {0x16B, 0, 1}, + {0x16C, 0, 1}, + {0x16D, 0, 0}, + {0x170, 0, 0}, + {0x171, 0x77, 0}, + {0x172, 0x77, 0}, + {0x173, 0x77, 0}, + {0x174, 0x77, 0}, + {0x175, 0, 0}, + {0x176, 0x3, 0}, + {0x177, 0x37, 0}, + {0x178, 0x3, 0}, + {0x179, 0, 0}, + {0x17A, 0x21, 0}, + {0x17B, 0x21, 0}, + {0x17C, 0, 0}, + {0x17D, 0xaa, 0}, + {0x17E, 0, 0}, + {0x17F, 0xaa, 0}, + {0x180, 0, 0}, + {0x190, 0, 0}, + {0x191, 0x77, 0}, + {0x192, 0x77, 0}, + {0x193, 0x77, 0}, + {0x194, 0x77, 0}, + {0x195, 0, 0}, + {0x196, 0x3, 0}, + {0x197, 0x37, 0}, + {0x198, 0x3, 0}, + {0x199, 0, 0}, + {0x19A, 0x21, 0}, + {0x19B, 0x21, 0}, + {0x19C, 0, 0}, + {0x19D, 0xaa, 0}, + {0x19E, 0, 0}, + {0x19F, 0xaa, 0}, + {0x1A0, 0, 0}, + {0x1A1, 0x2, 0}, + {0x1A2, 0xf, 0}, + {0x1A3, 0xf, 0}, + {0x1A4, 0, 1}, + {0x1A5, 0, 1}, + {0x1A6, 0, 1}, + {0x1A7, 0x2, 0}, + {0x1A8, 0xf, 0}, + {0x1A9, 0xf, 0}, + {0x1AA, 0, 1}, + {0x1AB, 0, 1}, + {0x1AC, 0, 1}, + {0x1AD, 0x84, 0}, + {0x1AE, 0x60, 0}, + {0x1AF, 0x47, 0}, + {0x1B0, 0x47, 0}, + {0x1B1, 0, 0}, + {0x1B2, 0, 0}, + {0x1B3, 0, 0}, + {0x1B4, 0, 0}, + {0x1B5, 0, 0}, + {0x1B6, 0, 0}, + {0x1B7, 0x5, 1}, + {0x1B8, 0, 0}, + {0x1B9, 0, 0}, + {0x1BA, 0, 0}, + {0x1BB, 0, 0}, + {0x1BC, 0, 0}, + {0x1BD, 0, 0}, + {0x1BE, 0, 0}, + {0x1BF, 0, 0}, + {0x1C0, 0, 0}, + {0x1C1, 0, 0}, + {0x1C2, 0xa0, 1}, + {0x1C3, 0, 0}, + {0x1C4, 0, 0}, + {0x1C5, 0, 0}, + {0x1C6, 0, 0}, + {0x1C7, 0, 0}, + {0x1C8, 0, 0}, + {0x1C9, 0, 0}, + {0x1CA, 0, 0}, + {0xFFFF, 0, 0} +}; + +static s16 nphy_def_lnagains[] = { -2, 10, 19, 25 }; + +static s32 nphy_lnagain_est0[] = { -315, 40370 }; +static s32 nphy_lnagain_est1[] = { -224, 23242 }; + +static const u16 tbl_iqcal_gainparams_nphy[2][NPHY_IQCAL_NUMGAINS][8] = { + { + {0x000, 0, 0, 2, 0x69, 0x69, 0x69, 0x69}, + {0x700, 7, 0, 0, 0x69, 0x69, 0x69, 0x69}, + {0x710, 7, 1, 0, 0x68, 0x68, 0x68, 0x68}, + {0x720, 7, 2, 0, 0x67, 0x67, 0x67, 0x67}, + {0x730, 7, 3, 0, 0x66, 0x66, 0x66, 0x66}, + {0x740, 7, 4, 0, 0x65, 0x65, 0x65, 0x65}, + {0x741, 7, 4, 1, 0x65, 0x65, 0x65, 0x65}, + {0x742, 7, 4, 2, 0x65, 0x65, 0x65, 0x65}, + {0x743, 7, 4, 3, 0x65, 0x65, 0x65, 0x65} + }, + { + {0x000, 7, 0, 0, 0x79, 0x79, 0x79, 0x79}, + {0x700, 7, 0, 0, 0x79, 0x79, 0x79, 0x79}, + {0x710, 7, 1, 0, 0x79, 0x79, 0x79, 0x79}, + {0x720, 7, 2, 0, 0x78, 0x78, 0x78, 0x78}, + {0x730, 7, 3, 0, 0x78, 0x78, 0x78, 0x78}, + {0x740, 7, 4, 0, 0x78, 0x78, 0x78, 0x78}, + {0x741, 7, 4, 1, 0x78, 0x78, 0x78, 0x78}, + {0x742, 7, 4, 2, 0x78, 0x78, 0x78, 0x78}, + {0x743, 7, 4, 3, 0x78, 0x78, 0x78, 0x78} + } +}; + +static const u32 nphy_tpc_txgain[] = { + 0x03cc2b44, 0x03cc2b42, 0x03cc2a44, 0x03cc2a42, + 0x03cc2944, 0x03c82b44, 0x03c82b42, 0x03c82a44, + 0x03c82a42, 0x03c82944, 0x03c82942, 0x03c82844, + 0x03c82842, 0x03c42b44, 0x03c42b42, 0x03c42a44, + 0x03c42a42, 0x03c42944, 0x03c42942, 0x03c42844, + 0x03c42842, 0x03c42744, 0x03c42742, 0x03c42644, + 0x03c42642, 0x03c42544, 0x03c42542, 0x03c42444, + 0x03c42442, 0x03c02b44, 0x03c02b42, 0x03c02a44, + 0x03c02a42, 0x03c02944, 0x03c02942, 0x03c02844, + 0x03c02842, 0x03c02744, 0x03c02742, 0x03b02b44, + 0x03b02b42, 0x03b02a44, 0x03b02a42, 0x03b02944, + 0x03b02942, 0x03b02844, 0x03b02842, 0x03b02744, + 0x03b02742, 0x03b02644, 0x03b02642, 0x03b02544, + 0x03b02542, 0x03a02b44, 0x03a02b42, 0x03a02a44, + 0x03a02a42, 0x03a02944, 0x03a02942, 0x03a02844, + 0x03a02842, 0x03a02744, 0x03a02742, 0x03902b44, + 0x03902b42, 0x03902a44, 0x03902a42, 0x03902944, + 0x03902942, 0x03902844, 0x03902842, 0x03902744, + 0x03902742, 0x03902644, 0x03902642, 0x03902544, + 0x03902542, 0x03802b44, 0x03802b42, 0x03802a44, + 0x03802a42, 0x03802944, 0x03802942, 0x03802844, + 0x03802842, 0x03802744, 0x03802742, 0x03802644, + 0x03802642, 0x03802544, 0x03802542, 0x03802444, + 0x03802442, 0x03802344, 0x03802342, 0x03802244, + 0x03802242, 0x03802144, 0x03802142, 0x03802044, + 0x03802042, 0x03801f44, 0x03801f42, 0x03801e44, + 0x03801e42, 0x03801d44, 0x03801d42, 0x03801c44, + 0x03801c42, 0x03801b44, 0x03801b42, 0x03801a44, + 0x03801a42, 0x03801944, 0x03801942, 0x03801844, + 0x03801842, 0x03801744, 0x03801742, 0x03801644, + 0x03801642, 0x03801544, 0x03801542, 0x03801444, + 0x03801442, 0x03801344, 0x03801342, 0x00002b00 +}; + +static const u16 nphy_tpc_loscale[] = { + 256, 256, 271, 271, 287, 256, 256, 271, + 271, 287, 287, 304, 304, 256, 256, 271, + 271, 287, 287, 304, 304, 322, 322, 341, + 341, 362, 362, 383, 383, 256, 256, 271, + 271, 287, 287, 304, 304, 322, 322, 256, + 256, 271, 271, 287, 287, 304, 304, 322, + 322, 341, 341, 362, 362, 256, 256, 271, + 271, 287, 287, 304, 304, 322, 322, 256, + 256, 271, 271, 287, 287, 304, 304, 322, + 322, 341, 341, 362, 362, 256, 256, 271, + 271, 287, 287, 304, 304, 322, 322, 341, + 341, 362, 362, 383, 383, 406, 406, 430, + 430, 455, 455, 482, 482, 511, 511, 541, + 541, 573, 573, 607, 607, 643, 643, 681, + 681, 722, 722, 764, 764, 810, 810, 858, + 858, 908, 908, 962, 962, 1019, 1019, 256 +}; + +static u32 nphy_tpc_txgain_ipa[] = { + 0x5ff7002d, 0x5ff7002b, 0x5ff7002a, 0x5ff70029, + 0x5ff70028, 0x5ff70027, 0x5ff70026, 0x5ff70025, + 0x5ef7002d, 0x5ef7002b, 0x5ef7002a, 0x5ef70029, + 0x5ef70028, 0x5ef70027, 0x5ef70026, 0x5ef70025, + 0x5df7002d, 0x5df7002b, 0x5df7002a, 0x5df70029, + 0x5df70028, 0x5df70027, 0x5df70026, 0x5df70025, + 0x5cf7002d, 0x5cf7002b, 0x5cf7002a, 0x5cf70029, + 0x5cf70028, 0x5cf70027, 0x5cf70026, 0x5cf70025, + 0x5bf7002d, 0x5bf7002b, 0x5bf7002a, 0x5bf70029, + 0x5bf70028, 0x5bf70027, 0x5bf70026, 0x5bf70025, + 0x5af7002d, 0x5af7002b, 0x5af7002a, 0x5af70029, + 0x5af70028, 0x5af70027, 0x5af70026, 0x5af70025, + 0x59f7002d, 0x59f7002b, 0x59f7002a, 0x59f70029, + 0x59f70028, 0x59f70027, 0x59f70026, 0x59f70025, + 0x58f7002d, 0x58f7002b, 0x58f7002a, 0x58f70029, + 0x58f70028, 0x58f70027, 0x58f70026, 0x58f70025, + 0x57f7002d, 0x57f7002b, 0x57f7002a, 0x57f70029, + 0x57f70028, 0x57f70027, 0x57f70026, 0x57f70025, + 0x56f7002d, 0x56f7002b, 0x56f7002a, 0x56f70029, + 0x56f70028, 0x56f70027, 0x56f70026, 0x56f70025, + 0x55f7002d, 0x55f7002b, 0x55f7002a, 0x55f70029, + 0x55f70028, 0x55f70027, 0x55f70026, 0x55f70025, + 0x54f7002d, 0x54f7002b, 0x54f7002a, 0x54f70029, + 0x54f70028, 0x54f70027, 0x54f70026, 0x54f70025, + 0x53f7002d, 0x53f7002b, 0x53f7002a, 0x53f70029, + 0x53f70028, 0x53f70027, 0x53f70026, 0x53f70025, + 0x52f7002d, 0x52f7002b, 0x52f7002a, 0x52f70029, + 0x52f70028, 0x52f70027, 0x52f70026, 0x52f70025, + 0x51f7002d, 0x51f7002b, 0x51f7002a, 0x51f70029, + 0x51f70028, 0x51f70027, 0x51f70026, 0x51f70025, + 0x50f7002d, 0x50f7002b, 0x50f7002a, 0x50f70029, + 0x50f70028, 0x50f70027, 0x50f70026, 0x50f70025 +}; + +static u32 nphy_tpc_txgain_ipa_rev5[] = { + 0x1ff7002d, 0x1ff7002b, 0x1ff7002a, 0x1ff70029, + 0x1ff70028, 0x1ff70027, 0x1ff70026, 0x1ff70025, + 0x1ef7002d, 0x1ef7002b, 0x1ef7002a, 0x1ef70029, + 0x1ef70028, 0x1ef70027, 0x1ef70026, 0x1ef70025, + 0x1df7002d, 0x1df7002b, 0x1df7002a, 0x1df70029, + 0x1df70028, 0x1df70027, 0x1df70026, 0x1df70025, + 0x1cf7002d, 0x1cf7002b, 0x1cf7002a, 0x1cf70029, + 0x1cf70028, 0x1cf70027, 0x1cf70026, 0x1cf70025, + 0x1bf7002d, 0x1bf7002b, 0x1bf7002a, 0x1bf70029, + 0x1bf70028, 0x1bf70027, 0x1bf70026, 0x1bf70025, + 0x1af7002d, 0x1af7002b, 0x1af7002a, 0x1af70029, + 0x1af70028, 0x1af70027, 0x1af70026, 0x1af70025, + 0x19f7002d, 0x19f7002b, 0x19f7002a, 0x19f70029, + 0x19f70028, 0x19f70027, 0x19f70026, 0x19f70025, + 0x18f7002d, 0x18f7002b, 0x18f7002a, 0x18f70029, + 0x18f70028, 0x18f70027, 0x18f70026, 0x18f70025, + 0x17f7002d, 0x17f7002b, 0x17f7002a, 0x17f70029, + 0x17f70028, 0x17f70027, 0x17f70026, 0x17f70025, + 0x16f7002d, 0x16f7002b, 0x16f7002a, 0x16f70029, + 0x16f70028, 0x16f70027, 0x16f70026, 0x16f70025, + 0x15f7002d, 0x15f7002b, 0x15f7002a, 0x15f70029, + 0x15f70028, 0x15f70027, 0x15f70026, 0x15f70025, + 0x14f7002d, 0x14f7002b, 0x14f7002a, 0x14f70029, + 0x14f70028, 0x14f70027, 0x14f70026, 0x14f70025, + 0x13f7002d, 0x13f7002b, 0x13f7002a, 0x13f70029, + 0x13f70028, 0x13f70027, 0x13f70026, 0x13f70025, + 0x12f7002d, 0x12f7002b, 0x12f7002a, 0x12f70029, + 0x12f70028, 0x12f70027, 0x12f70026, 0x12f70025, + 0x11f7002d, 0x11f7002b, 0x11f7002a, 0x11f70029, + 0x11f70028, 0x11f70027, 0x11f70026, 0x11f70025, + 0x10f7002d, 0x10f7002b, 0x10f7002a, 0x10f70029, + 0x10f70028, 0x10f70027, 0x10f70026, 0x10f70025 +}; + +static u32 nphy_tpc_txgain_ipa_rev6[] = { + 0x0ff7002d, 0x0ff7002b, 0x0ff7002a, 0x0ff70029, + 0x0ff70028, 0x0ff70027, 0x0ff70026, 0x0ff70025, + 0x0ef7002d, 0x0ef7002b, 0x0ef7002a, 0x0ef70029, + 0x0ef70028, 0x0ef70027, 0x0ef70026, 0x0ef70025, + 0x0df7002d, 0x0df7002b, 0x0df7002a, 0x0df70029, + 0x0df70028, 0x0df70027, 0x0df70026, 0x0df70025, + 0x0cf7002d, 0x0cf7002b, 0x0cf7002a, 0x0cf70029, + 0x0cf70028, 0x0cf70027, 0x0cf70026, 0x0cf70025, + 0x0bf7002d, 0x0bf7002b, 0x0bf7002a, 0x0bf70029, + 0x0bf70028, 0x0bf70027, 0x0bf70026, 0x0bf70025, + 0x0af7002d, 0x0af7002b, 0x0af7002a, 0x0af70029, + 0x0af70028, 0x0af70027, 0x0af70026, 0x0af70025, + 0x09f7002d, 0x09f7002b, 0x09f7002a, 0x09f70029, + 0x09f70028, 0x09f70027, 0x09f70026, 0x09f70025, + 0x08f7002d, 0x08f7002b, 0x08f7002a, 0x08f70029, + 0x08f70028, 0x08f70027, 0x08f70026, 0x08f70025, + 0x07f7002d, 0x07f7002b, 0x07f7002a, 0x07f70029, + 0x07f70028, 0x07f70027, 0x07f70026, 0x07f70025, + 0x06f7002d, 0x06f7002b, 0x06f7002a, 0x06f70029, + 0x06f70028, 0x06f70027, 0x06f70026, 0x06f70025, + 0x05f7002d, 0x05f7002b, 0x05f7002a, 0x05f70029, + 0x05f70028, 0x05f70027, 0x05f70026, 0x05f70025, + 0x04f7002d, 0x04f7002b, 0x04f7002a, 0x04f70029, + 0x04f70028, 0x04f70027, 0x04f70026, 0x04f70025, + 0x03f7002d, 0x03f7002b, 0x03f7002a, 0x03f70029, + 0x03f70028, 0x03f70027, 0x03f70026, 0x03f70025, + 0x02f7002d, 0x02f7002b, 0x02f7002a, 0x02f70029, + 0x02f70028, 0x02f70027, 0x02f70026, 0x02f70025, + 0x01f7002d, 0x01f7002b, 0x01f7002a, 0x01f70029, + 0x01f70028, 0x01f70027, 0x01f70026, 0x01f70025, + 0x00f7002d, 0x00f7002b, 0x00f7002a, 0x00f70029, + 0x00f70028, 0x00f70027, 0x00f70026, 0x00f70025 +}; + +static u32 nphy_tpc_txgain_ipa_2g_2057rev3[] = { + 0x70ff0040, 0x70f7003e, 0x70ef003b, 0x70e70039, + 0x70df0037, 0x70d70036, 0x70cf0033, 0x70c70032, + 0x70bf0031, 0x70b7002f, 0x70af002e, 0x70a7002d, + 0x709f002d, 0x7097002c, 0x708f002c, 0x7087002c, + 0x707f002b, 0x7077002c, 0x706f002c, 0x7067002d, + 0x705f002e, 0x705f002b, 0x705f0029, 0x7057002a, + 0x70570028, 0x704f002a, 0x7047002c, 0x7047002a, + 0x70470028, 0x70470026, 0x70470024, 0x70470022, + 0x7047001f, 0x70370027, 0x70370024, 0x70370022, + 0x70370020, 0x7037001f, 0x7037001d, 0x7037001b, + 0x7037001a, 0x70370018, 0x70370017, 0x7027001e, + 0x7027001d, 0x7027001a, 0x701f0024, 0x701f0022, + 0x701f0020, 0x701f001f, 0x701f001d, 0x701f001b, + 0x701f001a, 0x701f0018, 0x701f0017, 0x701f0015, + 0x701f0014, 0x701f0013, 0x701f0012, 0x701f0011, + 0x70170019, 0x70170018, 0x70170016, 0x70170015, + 0x70170014, 0x70170013, 0x70170012, 0x70170010, + 0x70170010, 0x7017000f, 0x700f001d, 0x700f001b, + 0x700f001a, 0x700f0018, 0x700f0017, 0x700f0015, + 0x700f0015, 0x700f0013, 0x700f0013, 0x700f0011, + 0x700f0010, 0x700f0010, 0x700f000f, 0x700f000e, + 0x700f000d, 0x700f000c, 0x700f000b, 0x700f000b, + 0x700f000b, 0x700f000a, 0x700f0009, 0x700f0009, + 0x700f0009, 0x700f0008, 0x700f0007, 0x700f0007, + 0x700f0006, 0x700f0006, 0x700f0006, 0x700f0006, + 0x700f0005, 0x700f0005, 0x700f0005, 0x700f0004, + 0x700f0004, 0x700f0004, 0x700f0004, 0x700f0004, + 0x700f0004, 0x700f0003, 0x700f0003, 0x700f0003, + 0x700f0003, 0x700f0002, 0x700f0002, 0x700f0002, + 0x700f0002, 0x700f0002, 0x700f0002, 0x700f0001, + 0x700f0001, 0x700f0001, 0x700f0001, 0x700f0001, + 0x700f0001, 0x700f0001, 0x700f0001, 0x700f0001 +}; + +static u32 nphy_tpc_txgain_ipa_2g_2057rev4n6[] = { + 0xf0ff0040, 0xf0f7003e, 0xf0ef003b, 0xf0e70039, + 0xf0df0037, 0xf0d70036, 0xf0cf0033, 0xf0c70032, + 0xf0bf0031, 0xf0b7002f, 0xf0af002e, 0xf0a7002d, + 0xf09f002d, 0xf097002c, 0xf08f002c, 0xf087002c, + 0xf07f002b, 0xf077002c, 0xf06f002c, 0xf067002d, + 0xf05f002e, 0xf05f002b, 0xf05f0029, 0xf057002a, + 0xf0570028, 0xf04f002a, 0xf047002c, 0xf047002a, + 0xf0470028, 0xf0470026, 0xf0470024, 0xf0470022, + 0xf047001f, 0xf0370027, 0xf0370024, 0xf0370022, + 0xf0370020, 0xf037001f, 0xf037001d, 0xf037001b, + 0xf037001a, 0xf0370018, 0xf0370017, 0xf027001e, + 0xf027001d, 0xf027001a, 0xf01f0024, 0xf01f0022, + 0xf01f0020, 0xf01f001f, 0xf01f001d, 0xf01f001b, + 0xf01f001a, 0xf01f0018, 0xf01f0017, 0xf01f0015, + 0xf01f0014, 0xf01f0013, 0xf01f0012, 0xf01f0011, + 0xf0170019, 0xf0170018, 0xf0170016, 0xf0170015, + 0xf0170014, 0xf0170013, 0xf0170012, 0xf0170010, + 0xf0170010, 0xf017000f, 0xf00f001d, 0xf00f001b, + 0xf00f001a, 0xf00f0018, 0xf00f0017, 0xf00f0015, + 0xf00f0015, 0xf00f0013, 0xf00f0013, 0xf00f0011, + 0xf00f0010, 0xf00f0010, 0xf00f000f, 0xf00f000e, + 0xf00f000d, 0xf00f000c, 0xf00f000b, 0xf00f000b, + 0xf00f000b, 0xf00f000a, 0xf00f0009, 0xf00f0009, + 0xf00f0009, 0xf00f0008, 0xf00f0007, 0xf00f0007, + 0xf00f0006, 0xf00f0006, 0xf00f0006, 0xf00f0006, + 0xf00f0005, 0xf00f0005, 0xf00f0005, 0xf00f0004, + 0xf00f0004, 0xf00f0004, 0xf00f0004, 0xf00f0004, + 0xf00f0004, 0xf00f0003, 0xf00f0003, 0xf00f0003, + 0xf00f0003, 0xf00f0002, 0xf00f0002, 0xf00f0002, + 0xf00f0002, 0xf00f0002, 0xf00f0002, 0xf00f0001, + 0xf00f0001, 0xf00f0001, 0xf00f0001, 0xf00f0001, + 0xf00f0001, 0xf00f0001, 0xf00f0001, 0xf00f0001 +}; + +static u32 nphy_tpc_txgain_ipa_2g_2057rev5[] = { + 0x30ff0031, 0x30e70031, 0x30e7002e, 0x30cf002e, + 0x30bf002e, 0x30af002e, 0x309f002f, 0x307f0033, + 0x307f0031, 0x307f002e, 0x3077002e, 0x306f002e, + 0x3067002e, 0x305f002f, 0x30570030, 0x3057002d, + 0x304f002e, 0x30470031, 0x3047002e, 0x3047002c, + 0x30470029, 0x303f002c, 0x303f0029, 0x3037002d, + 0x3037002a, 0x30370028, 0x302f002c, 0x302f002a, + 0x302f0028, 0x302f0026, 0x3027002c, 0x30270029, + 0x30270027, 0x30270025, 0x30270023, 0x301f002c, + 0x301f002a, 0x301f0028, 0x301f0025, 0x301f0024, + 0x301f0022, 0x301f001f, 0x3017002d, 0x3017002b, + 0x30170028, 0x30170026, 0x30170024, 0x30170022, + 0x30170020, 0x3017001e, 0x3017001d, 0x3017001b, + 0x3017001a, 0x30170018, 0x30170017, 0x30170015, + 0x300f002c, 0x300f0029, 0x300f0027, 0x300f0024, + 0x300f0022, 0x300f0021, 0x300f001f, 0x300f001d, + 0x300f001b, 0x300f001a, 0x300f0018, 0x300f0017, + 0x300f0016, 0x300f0015, 0x300f0115, 0x300f0215, + 0x300f0315, 0x300f0415, 0x300f0515, 0x300f0615, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715 +}; + +static u32 nphy_tpc_txgain_ipa_2g_2057rev7[] = { + 0x30ff0031, 0x30e70031, 0x30e7002e, 0x30cf002e, + 0x30bf002e, 0x30af002e, 0x309f002f, 0x307f0033, + 0x307f0031, 0x307f002e, 0x3077002e, 0x306f002e, + 0x3067002e, 0x305f002f, 0x30570030, 0x3057002d, + 0x304f002e, 0x30470031, 0x3047002e, 0x3047002c, + 0x30470029, 0x303f002c, 0x303f0029, 0x3037002d, + 0x3037002a, 0x30370028, 0x302f002c, 0x302f002a, + 0x302f0028, 0x302f0026, 0x3027002c, 0x30270029, + 0x30270027, 0x30270025, 0x30270023, 0x301f002c, + 0x301f002a, 0x301f0028, 0x301f0025, 0x301f0024, + 0x301f0022, 0x301f001f, 0x3017002d, 0x3017002b, + 0x30170028, 0x30170026, 0x30170024, 0x30170022, + 0x30170020, 0x3017001e, 0x3017001d, 0x3017001b, + 0x3017001a, 0x30170018, 0x30170017, 0x30170015, + 0x300f002c, 0x300f0029, 0x300f0027, 0x300f0024, + 0x300f0022, 0x300f0021, 0x300f001f, 0x300f001d, + 0x300f001b, 0x300f001a, 0x300f0018, 0x300f0017, + 0x300f0016, 0x300f0015, 0x300f0115, 0x300f0215, + 0x300f0315, 0x300f0415, 0x300f0515, 0x300f0615, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715, + 0x300f0715, 0x300f0715, 0x300f0715, 0x300f0715 +}; + +static u32 nphy_tpc_txgain_ipa_5g[] = { + 0x7ff70035, 0x7ff70033, 0x7ff70032, 0x7ff70031, + 0x7ff7002f, 0x7ff7002e, 0x7ff7002d, 0x7ff7002b, + 0x7ff7002a, 0x7ff70029, 0x7ff70028, 0x7ff70027, + 0x7ff70026, 0x7ff70024, 0x7ff70023, 0x7ff70022, + 0x7ef70028, 0x7ef70027, 0x7ef70026, 0x7ef70025, + 0x7ef70024, 0x7ef70023, 0x7df70028, 0x7df70027, + 0x7df70026, 0x7df70025, 0x7df70024, 0x7df70023, + 0x7df70022, 0x7cf70029, 0x7cf70028, 0x7cf70027, + 0x7cf70026, 0x7cf70025, 0x7cf70023, 0x7cf70022, + 0x7bf70029, 0x7bf70028, 0x7bf70026, 0x7bf70025, + 0x7bf70024, 0x7bf70023, 0x7bf70022, 0x7bf70021, + 0x7af70029, 0x7af70028, 0x7af70027, 0x7af70026, + 0x7af70025, 0x7af70024, 0x7af70023, 0x7af70022, + 0x79f70029, 0x79f70028, 0x79f70027, 0x79f70026, + 0x79f70025, 0x79f70024, 0x79f70023, 0x79f70022, + 0x78f70029, 0x78f70028, 0x78f70027, 0x78f70026, + 0x78f70025, 0x78f70024, 0x78f70023, 0x78f70022, + 0x77f70029, 0x77f70028, 0x77f70027, 0x77f70026, + 0x77f70025, 0x77f70024, 0x77f70023, 0x77f70022, + 0x76f70029, 0x76f70028, 0x76f70027, 0x76f70026, + 0x76f70024, 0x76f70023, 0x76f70022, 0x76f70021, + 0x75f70029, 0x75f70028, 0x75f70027, 0x75f70026, + 0x75f70025, 0x75f70024, 0x75f70023, 0x74f70029, + 0x74f70028, 0x74f70026, 0x74f70025, 0x74f70024, + 0x74f70023, 0x74f70022, 0x73f70029, 0x73f70027, + 0x73f70026, 0x73f70025, 0x73f70024, 0x73f70023, + 0x73f70022, 0x72f70028, 0x72f70027, 0x72f70026, + 0x72f70025, 0x72f70024, 0x72f70023, 0x72f70022, + 0x71f70028, 0x71f70027, 0x71f70026, 0x71f70025, + 0x71f70024, 0x71f70023, 0x70f70028, 0x70f70027, + 0x70f70026, 0x70f70024, 0x70f70023, 0x70f70022, + 0x70f70021, 0x70f70020, 0x70f70020, 0x70f7001f +}; + +static u32 nphy_tpc_txgain_ipa_5g_2057[] = { + 0x7f7f0044, 0x7f7f0040, 0x7f7f003c, 0x7f7f0039, + 0x7f7f0036, 0x7e7f003c, 0x7e7f0038, 0x7e7f0035, + 0x7d7f003c, 0x7d7f0039, 0x7d7f0036, 0x7d7f0033, + 0x7c7f003b, 0x7c7f0037, 0x7c7f0034, 0x7b7f003a, + 0x7b7f0036, 0x7b7f0033, 0x7a7f003c, 0x7a7f0039, + 0x7a7f0036, 0x7a7f0033, 0x797f003b, 0x797f0038, + 0x797f0035, 0x797f0032, 0x787f003b, 0x787f0038, + 0x787f0035, 0x787f0032, 0x777f003a, 0x777f0037, + 0x777f0034, 0x777f0031, 0x767f003a, 0x767f0036, + 0x767f0033, 0x767f0031, 0x757f003a, 0x757f0037, + 0x757f0034, 0x747f003c, 0x747f0039, 0x747f0036, + 0x747f0033, 0x737f003b, 0x737f0038, 0x737f0035, + 0x737f0032, 0x727f0039, 0x727f0036, 0x727f0033, + 0x727f0030, 0x717f003a, 0x717f0037, 0x717f0034, + 0x707f003b, 0x707f0038, 0x707f0035, 0x707f0032, + 0x707f002f, 0x707f002d, 0x707f002a, 0x707f0028, + 0x707f0025, 0x707f0023, 0x707f0021, 0x707f0020, + 0x707f001e, 0x707f001c, 0x707f001b, 0x707f0019, + 0x707f0018, 0x707f0016, 0x707f0015, 0x707f0014, + 0x707f0013, 0x707f0012, 0x707f0011, 0x707f0010, + 0x707f000f, 0x707f000e, 0x707f000d, 0x707f000d, + 0x707f000c, 0x707f000b, 0x707f000b, 0x707f000a, + 0x707f0009, 0x707f0009, 0x707f0008, 0x707f0008, + 0x707f0007, 0x707f0007, 0x707f0007, 0x707f0006, + 0x707f0006, 0x707f0006, 0x707f0005, 0x707f0005, + 0x707f0005, 0x707f0004, 0x707f0004, 0x707f0004, + 0x707f0004, 0x707f0004, 0x707f0003, 0x707f0003, + 0x707f0003, 0x707f0003, 0x707f0003, 0x707f0003, + 0x707f0002, 0x707f0002, 0x707f0002, 0x707f0002, + 0x707f0002, 0x707f0002, 0x707f0002, 0x707f0002, + 0x707f0001, 0x707f0001, 0x707f0001, 0x707f0001, + 0x707f0001, 0x707f0001, 0x707f0001, 0x707f0001 +}; + +static u32 nphy_tpc_txgain_ipa_5g_2057rev7[] = { + 0x6f7f0031, 0x6f7f002e, 0x6f7f002c, 0x6f7f002a, + 0x6f7f0027, 0x6e7f002e, 0x6e7f002c, 0x6e7f002a, + 0x6d7f0030, 0x6d7f002d, 0x6d7f002a, 0x6d7f0028, + 0x6c7f0030, 0x6c7f002d, 0x6c7f002b, 0x6b7f002e, + 0x6b7f002c, 0x6b7f002a, 0x6b7f0027, 0x6a7f002e, + 0x6a7f002c, 0x6a7f002a, 0x697f0030, 0x697f002e, + 0x697f002b, 0x697f0029, 0x687f002f, 0x687f002d, + 0x687f002a, 0x687f0027, 0x677f002f, 0x677f002d, + 0x677f002a, 0x667f0031, 0x667f002e, 0x667f002c, + 0x667f002a, 0x657f0030, 0x657f002e, 0x657f002b, + 0x657f0029, 0x647f0030, 0x647f002d, 0x647f002b, + 0x647f0029, 0x637f002f, 0x637f002d, 0x637f002a, + 0x627f0030, 0x627f002d, 0x627f002b, 0x627f0029, + 0x617f0030, 0x617f002e, 0x617f002b, 0x617f0029, + 0x607f002f, 0x607f002d, 0x607f002a, 0x607f0027, + 0x607f0026, 0x607f0023, 0x607f0021, 0x607f0020, + 0x607f001e, 0x607f001c, 0x607f001a, 0x607f0019, + 0x607f0018, 0x607f0016, 0x607f0015, 0x607f0014, + 0x607f0012, 0x607f0012, 0x607f0011, 0x607f000f, + 0x607f000f, 0x607f000e, 0x607f000d, 0x607f000c, + 0x607f000c, 0x607f000b, 0x607f000b, 0x607f000a, + 0x607f0009, 0x607f0009, 0x607f0008, 0x607f0008, + 0x607f0008, 0x607f0007, 0x607f0007, 0x607f0006, + 0x607f0006, 0x607f0005, 0x607f0005, 0x607f0005, + 0x607f0005, 0x607f0005, 0x607f0004, 0x607f0004, + 0x607f0004, 0x607f0004, 0x607f0003, 0x607f0003, + 0x607f0003, 0x607f0003, 0x607f0002, 0x607f0002, + 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002, + 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002, + 0x607f0002, 0x607f0002, 0x607f0002, 0x607f0002, + 0x607f0002, 0x607f0001, 0x607f0001, 0x607f0001, + 0x607f0001, 0x607f0001, 0x607f0001, 0x607f0001 +}; + +static s8 nphy_papd_pga_gain_delta_ipa_2g[] = { + -114, -108, -98, -91, -84, -78, -70, -62, + -54, -46, -39, -31, -23, -15, -8, 0 +}; + +static s8 nphy_papd_pga_gain_delta_ipa_5g[] = { + -100, -95, -89, -83, -77, -70, -63, -56, + -48, -41, -33, -25, -19, -12, -6, 0 +}; + +static s16 nphy_papd_padgain_dlt_2g_2057rev3n4[] = { + -159, -113, -86, -72, -62, -54, -48, -43, + -39, -35, -31, -28, -25, -23, -20, -18, + -17, -15, -13, -11, -10, -8, -7, -6, + -5, -4, -3, -3, -2, -1, -1, 0 +}; + +static s16 nphy_papd_padgain_dlt_2g_2057rev5[] = { + -109, -109, -82, -68, -58, -50, -44, -39, + -35, -31, -28, -26, -23, -21, -19, -17, + -16, -14, -13, -11, -10, -9, -8, -7, + -5, -5, -4, -3, -2, -1, -1, 0 +}; + +static s16 nphy_papd_padgain_dlt_2g_2057rev7[] = { + -122, -122, -95, -80, -69, -61, -54, -49, + -43, -39, -35, -32, -28, -26, -23, -21, + -18, -16, -15, -13, -11, -10, -8, -7, + -6, -5, -4, -3, -2, -1, -1, 0 +}; + +static s8 nphy_papd_pgagain_dlt_5g_2057[] = { + -107, -101, -92, -85, -78, -71, -62, -55, + -47, -39, -32, -24, -19, -12, -6, 0 +}; + +static s8 nphy_papd_pgagain_dlt_5g_2057rev7[] = { + -110, -104, -95, -88, -81, -74, -66, -58, + -50, -44, -36, -28, -23, -15, -8, 0 +}; + +static u8 pad_gain_codes_used_2057rev5[] = { + 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, + 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 +}; + +static u8 pad_gain_codes_used_2057rev7[] = { + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, + 5, 4, 3, 2, 1 +}; + +static u8 pad_all_gain_codes_2057[] = { + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}; + +static u8 pga_all_gain_codes_2057[] = { + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +}; + +static u32 nphy_papd_scaltbl[] = { + 0x0ae2002f, 0x0a3b0032, 0x09a70035, 0x09220038, + 0x0887003c, 0x081f003f, 0x07a20043, 0x07340047, + 0x06d2004b, 0x067a004f, 0x06170054, 0x05bf0059, + 0x0571005e, 0x051e0064, 0x04d3006a, 0x04910070, + 0x044c0077, 0x040f007e, 0x03d90085, 0x03a1008d, + 0x036f0095, 0x033d009e, 0x030b00a8, 0x02e000b2, + 0x02b900bc, 0x029200c7, 0x026d00d3, 0x024900e0, + 0x022900ed, 0x020a00fb, 0x01ec010a, 0x01d0011a, + 0x01b7012a, 0x019e013c, 0x0187014f, 0x01720162, + 0x015d0177, 0x0149018e, 0x013701a5, 0x012601be, + 0x011501d9, 0x010501f5, 0x00f70212, 0x00e90232, + 0x00dc0253, 0x00d00276, 0x00c4029c, 0x00b902c3, + 0x00af02ed, 0x00a5031a, 0x009c0349, 0x0093037a, + 0x008b03af, 0x008303e7, 0x007c0422, 0x00750461, + 0x006e04a3, 0x006804ea, 0x00620534, 0x005d0583, + 0x005805d7, 0x0053062f, 0x004e068d, 0x004a06f1 +}; + +static u32 nphy_tpc_txgain_rev3[] = { + 0x1f410044, 0x1f410042, 0x1f410040, 0x1f41003e, + 0x1f41003c, 0x1f41003b, 0x1f410039, 0x1f410037, + 0x1e410044, 0x1e410042, 0x1e410040, 0x1e41003e, + 0x1e41003c, 0x1e41003b, 0x1e410039, 0x1e410037, + 0x1d410044, 0x1d410042, 0x1d410040, 0x1d41003e, + 0x1d41003c, 0x1d41003b, 0x1d410039, 0x1d410037, + 0x1c410044, 0x1c410042, 0x1c410040, 0x1c41003e, + 0x1c41003c, 0x1c41003b, 0x1c410039, 0x1c410037, + 0x1b410044, 0x1b410042, 0x1b410040, 0x1b41003e, + 0x1b41003c, 0x1b41003b, 0x1b410039, 0x1b410037, + 0x1a410044, 0x1a410042, 0x1a410040, 0x1a41003e, + 0x1a41003c, 0x1a41003b, 0x1a410039, 0x1a410037, + 0x19410044, 0x19410042, 0x19410040, 0x1941003e, + 0x1941003c, 0x1941003b, 0x19410039, 0x19410037, + 0x18410044, 0x18410042, 0x18410040, 0x1841003e, + 0x1841003c, 0x1841003b, 0x18410039, 0x18410037, + 0x17410044, 0x17410042, 0x17410040, 0x1741003e, + 0x1741003c, 0x1741003b, 0x17410039, 0x17410037, + 0x16410044, 0x16410042, 0x16410040, 0x1641003e, + 0x1641003c, 0x1641003b, 0x16410039, 0x16410037, + 0x15410044, 0x15410042, 0x15410040, 0x1541003e, + 0x1541003c, 0x1541003b, 0x15410039, 0x15410037, + 0x14410044, 0x14410042, 0x14410040, 0x1441003e, + 0x1441003c, 0x1441003b, 0x14410039, 0x14410037, + 0x13410044, 0x13410042, 0x13410040, 0x1341003e, + 0x1341003c, 0x1341003b, 0x13410039, 0x13410037, + 0x12410044, 0x12410042, 0x12410040, 0x1241003e, + 0x1241003c, 0x1241003b, 0x12410039, 0x12410037, + 0x11410044, 0x11410042, 0x11410040, 0x1141003e, + 0x1141003c, 0x1141003b, 0x11410039, 0x11410037, + 0x10410044, 0x10410042, 0x10410040, 0x1041003e, + 0x1041003c, 0x1041003b, 0x10410039, 0x10410037 +}; + +static u32 nphy_tpc_txgain_HiPwrEPA[] = { + 0x0f410044, 0x0f410042, 0x0f410040, 0x0f41003e, + 0x0f41003c, 0x0f41003b, 0x0f410039, 0x0f410037, + 0x0e410044, 0x0e410042, 0x0e410040, 0x0e41003e, + 0x0e41003c, 0x0e41003b, 0x0e410039, 0x0e410037, + 0x0d410044, 0x0d410042, 0x0d410040, 0x0d41003e, + 0x0d41003c, 0x0d41003b, 0x0d410039, 0x0d410037, + 0x0c410044, 0x0c410042, 0x0c410040, 0x0c41003e, + 0x0c41003c, 0x0c41003b, 0x0c410039, 0x0c410037, + 0x0b410044, 0x0b410042, 0x0b410040, 0x0b41003e, + 0x0b41003c, 0x0b41003b, 0x0b410039, 0x0b410037, + 0x0a410044, 0x0a410042, 0x0a410040, 0x0a41003e, + 0x0a41003c, 0x0a41003b, 0x0a410039, 0x0a410037, + 0x09410044, 0x09410042, 0x09410040, 0x0941003e, + 0x0941003c, 0x0941003b, 0x09410039, 0x09410037, + 0x08410044, 0x08410042, 0x08410040, 0x0841003e, + 0x0841003c, 0x0841003b, 0x08410039, 0x08410037, + 0x07410044, 0x07410042, 0x07410040, 0x0741003e, + 0x0741003c, 0x0741003b, 0x07410039, 0x07410037, + 0x06410044, 0x06410042, 0x06410040, 0x0641003e, + 0x0641003c, 0x0641003b, 0x06410039, 0x06410037, + 0x05410044, 0x05410042, 0x05410040, 0x0541003e, + 0x0541003c, 0x0541003b, 0x05410039, 0x05410037, + 0x04410044, 0x04410042, 0x04410040, 0x0441003e, + 0x0441003c, 0x0441003b, 0x04410039, 0x04410037, + 0x03410044, 0x03410042, 0x03410040, 0x0341003e, + 0x0341003c, 0x0341003b, 0x03410039, 0x03410037, + 0x02410044, 0x02410042, 0x02410040, 0x0241003e, + 0x0241003c, 0x0241003b, 0x02410039, 0x02410037, + 0x01410044, 0x01410042, 0x01410040, 0x0141003e, + 0x0141003c, 0x0141003b, 0x01410039, 0x01410037, + 0x00410044, 0x00410042, 0x00410040, 0x0041003e, + 0x0041003c, 0x0041003b, 0x00410039, 0x00410037 +}; + +static u32 nphy_tpc_txgain_epa_2057rev3[] = { + 0x80f90040, 0x80e10040, 0x80e1003c, 0x80c9003d, + 0x80b9003c, 0x80a9003d, 0x80a1003c, 0x8099003b, + 0x8091003b, 0x8089003a, 0x8081003a, 0x80790039, + 0x80710039, 0x8069003a, 0x8061003b, 0x8059003d, + 0x8051003f, 0x80490042, 0x8049003e, 0x8049003b, + 0x8041003e, 0x8041003b, 0x8039003e, 0x8039003b, + 0x80390038, 0x80390035, 0x8031003a, 0x80310036, + 0x80310033, 0x8029003a, 0x80290037, 0x80290034, + 0x80290031, 0x80210039, 0x80210036, 0x80210033, + 0x80210030, 0x8019003c, 0x80190039, 0x80190036, + 0x80190033, 0x80190030, 0x8019002d, 0x8019002b, + 0x80190028, 0x8011003a, 0x80110036, 0x80110033, + 0x80110030, 0x8011002e, 0x8011002b, 0x80110029, + 0x80110027, 0x80110024, 0x80110022, 0x80110020, + 0x8011001f, 0x8011001d, 0x8009003a, 0x80090037, + 0x80090034, 0x80090031, 0x8009002e, 0x8009002c, + 0x80090029, 0x80090027, 0x80090025, 0x80090023, + 0x80090021, 0x8009001f, 0x8009001d, 0x8009011d, + 0x8009021d, 0x8009031d, 0x8009041d, 0x8009051d, + 0x8009061d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d, + 0x8009071d, 0x8009071d, 0x8009071d, 0x8009071d +}; + +static u32 nphy_tpc_txgain_epa_2057rev5[] = { + 0x10f90040, 0x10e10040, 0x10e1003c, 0x10c9003d, + 0x10b9003c, 0x10a9003d, 0x10a1003c, 0x1099003b, + 0x1091003b, 0x1089003a, 0x1081003a, 0x10790039, + 0x10710039, 0x1069003a, 0x1061003b, 0x1059003d, + 0x1051003f, 0x10490042, 0x1049003e, 0x1049003b, + 0x1041003e, 0x1041003b, 0x1039003e, 0x1039003b, + 0x10390038, 0x10390035, 0x1031003a, 0x10310036, + 0x10310033, 0x1029003a, 0x10290037, 0x10290034, + 0x10290031, 0x10210039, 0x10210036, 0x10210033, + 0x10210030, 0x1019003c, 0x10190039, 0x10190036, + 0x10190033, 0x10190030, 0x1019002d, 0x1019002b, + 0x10190028, 0x1011003a, 0x10110036, 0x10110033, + 0x10110030, 0x1011002e, 0x1011002b, 0x10110029, + 0x10110027, 0x10110024, 0x10110022, 0x10110020, + 0x1011001f, 0x1011001d, 0x1009003a, 0x10090037, + 0x10090034, 0x10090031, 0x1009002e, 0x1009002c, + 0x10090029, 0x10090027, 0x10090025, 0x10090023, + 0x10090021, 0x1009001f, 0x1009001d, 0x1009001b, + 0x1009001a, 0x10090018, 0x10090017, 0x10090016, + 0x10090015, 0x10090013, 0x10090012, 0x10090011, + 0x10090010, 0x1009000f, 0x1009000f, 0x1009000e, + 0x1009000d, 0x1009000c, 0x1009000c, 0x1009000b, + 0x1009000a, 0x1009000a, 0x10090009, 0x10090009, + 0x10090008, 0x10090008, 0x10090007, 0x10090007, + 0x10090007, 0x10090006, 0x10090006, 0x10090005, + 0x10090005, 0x10090005, 0x10090005, 0x10090004, + 0x10090004, 0x10090004, 0x10090004, 0x10090003, + 0x10090003, 0x10090003, 0x10090003, 0x10090003, + 0x10090003, 0x10090002, 0x10090002, 0x10090002, + 0x10090002, 0x10090002, 0x10090002, 0x10090002, + 0x10090002, 0x10090002, 0x10090001, 0x10090001, + 0x10090001, 0x10090001, 0x10090001, 0x10090001 +}; + +static u32 nphy_tpc_5GHz_txgain_rev3[] = { + 0xcff70044, 0xcff70042, 0xcff70040, 0xcff7003e, + 0xcff7003c, 0xcff7003b, 0xcff70039, 0xcff70037, + 0xcef70044, 0xcef70042, 0xcef70040, 0xcef7003e, + 0xcef7003c, 0xcef7003b, 0xcef70039, 0xcef70037, + 0xcdf70044, 0xcdf70042, 0xcdf70040, 0xcdf7003e, + 0xcdf7003c, 0xcdf7003b, 0xcdf70039, 0xcdf70037, + 0xccf70044, 0xccf70042, 0xccf70040, 0xccf7003e, + 0xccf7003c, 0xccf7003b, 0xccf70039, 0xccf70037, + 0xcbf70044, 0xcbf70042, 0xcbf70040, 0xcbf7003e, + 0xcbf7003c, 0xcbf7003b, 0xcbf70039, 0xcbf70037, + 0xcaf70044, 0xcaf70042, 0xcaf70040, 0xcaf7003e, + 0xcaf7003c, 0xcaf7003b, 0xcaf70039, 0xcaf70037, + 0xc9f70044, 0xc9f70042, 0xc9f70040, 0xc9f7003e, + 0xc9f7003c, 0xc9f7003b, 0xc9f70039, 0xc9f70037, + 0xc8f70044, 0xc8f70042, 0xc8f70040, 0xc8f7003e, + 0xc8f7003c, 0xc8f7003b, 0xc8f70039, 0xc8f70037, + 0xc7f70044, 0xc7f70042, 0xc7f70040, 0xc7f7003e, + 0xc7f7003c, 0xc7f7003b, 0xc7f70039, 0xc7f70037, + 0xc6f70044, 0xc6f70042, 0xc6f70040, 0xc6f7003e, + 0xc6f7003c, 0xc6f7003b, 0xc6f70039, 0xc6f70037, + 0xc5f70044, 0xc5f70042, 0xc5f70040, 0xc5f7003e, + 0xc5f7003c, 0xc5f7003b, 0xc5f70039, 0xc5f70037, + 0xc4f70044, 0xc4f70042, 0xc4f70040, 0xc4f7003e, + 0xc4f7003c, 0xc4f7003b, 0xc4f70039, 0xc4f70037, + 0xc3f70044, 0xc3f70042, 0xc3f70040, 0xc3f7003e, + 0xc3f7003c, 0xc3f7003b, 0xc3f70039, 0xc3f70037, + 0xc2f70044, 0xc2f70042, 0xc2f70040, 0xc2f7003e, + 0xc2f7003c, 0xc2f7003b, 0xc2f70039, 0xc2f70037, + 0xc1f70044, 0xc1f70042, 0xc1f70040, 0xc1f7003e, + 0xc1f7003c, 0xc1f7003b, 0xc1f70039, 0xc1f70037, + 0xc0f70044, 0xc0f70042, 0xc0f70040, 0xc0f7003e, + 0xc0f7003c, 0xc0f7003b, 0xc0f70039, 0xc0f70037 +}; + +static u32 nphy_tpc_5GHz_txgain_rev4[] = { + 0x2ff20044, 0x2ff20042, 0x2ff20040, 0x2ff2003e, + 0x2ff2003c, 0x2ff2003b, 0x2ff20039, 0x2ff20037, + 0x2ef20044, 0x2ef20042, 0x2ef20040, 0x2ef2003e, + 0x2ef2003c, 0x2ef2003b, 0x2ef20039, 0x2ef20037, + 0x2df20044, 0x2df20042, 0x2df20040, 0x2df2003e, + 0x2df2003c, 0x2df2003b, 0x2df20039, 0x2df20037, + 0x2cf20044, 0x2cf20042, 0x2cf20040, 0x2cf2003e, + 0x2cf2003c, 0x2cf2003b, 0x2cf20039, 0x2cf20037, + 0x2bf20044, 0x2bf20042, 0x2bf20040, 0x2bf2003e, + 0x2bf2003c, 0x2bf2003b, 0x2bf20039, 0x2bf20037, + 0x2af20044, 0x2af20042, 0x2af20040, 0x2af2003e, + 0x2af2003c, 0x2af2003b, 0x2af20039, 0x2af20037, + 0x29f20044, 0x29f20042, 0x29f20040, 0x29f2003e, + 0x29f2003c, 0x29f2003b, 0x29f20039, 0x29f20037, + 0x28f20044, 0x28f20042, 0x28f20040, 0x28f2003e, + 0x28f2003c, 0x28f2003b, 0x28f20039, 0x28f20037, + 0x27f20044, 0x27f20042, 0x27f20040, 0x27f2003e, + 0x27f2003c, 0x27f2003b, 0x27f20039, 0x27f20037, + 0x26f20044, 0x26f20042, 0x26f20040, 0x26f2003e, + 0x26f2003c, 0x26f2003b, 0x26f20039, 0x26f20037, + 0x25f20044, 0x25f20042, 0x25f20040, 0x25f2003e, + 0x25f2003c, 0x25f2003b, 0x25f20039, 0x25f20037, + 0x24f20044, 0x24f20042, 0x24f20040, 0x24f2003e, + 0x24f2003c, 0x24f2003b, 0x24f20039, 0x24f20038, + 0x23f20041, 0x23f20040, 0x23f2003f, 0x23f2003e, + 0x23f2003c, 0x23f2003b, 0x23f20039, 0x23f20037, + 0x22f20044, 0x22f20042, 0x22f20040, 0x22f2003e, + 0x22f2003c, 0x22f2003b, 0x22f20039, 0x22f20037, + 0x21f20044, 0x21f20042, 0x21f20040, 0x21f2003e, + 0x21f2003c, 0x21f2003b, 0x21f20039, 0x21f20037, + 0x20d20043, 0x20d20041, 0x20d2003e, 0x20d2003c, + 0x20d2003a, 0x20d20038, 0x20d20036, 0x20d20034 +}; + +static u32 nphy_tpc_5GHz_txgain_rev5[] = { + 0x0f62004a, 0x0f620048, 0x0f620046, 0x0f620044, + 0x0f620042, 0x0f620040, 0x0f62003e, 0x0f62003c, + 0x0e620044, 0x0e620042, 0x0e620040, 0x0e62003e, + 0x0e62003c, 0x0e62003d, 0x0e62003b, 0x0e62003a, + 0x0d620043, 0x0d620041, 0x0d620040, 0x0d62003e, + 0x0d62003d, 0x0d62003c, 0x0d62003b, 0x0d62003a, + 0x0c620041, 0x0c620040, 0x0c62003f, 0x0c62003e, + 0x0c62003c, 0x0c62003b, 0x0c620039, 0x0c620037, + 0x0b620046, 0x0b620044, 0x0b620042, 0x0b620040, + 0x0b62003e, 0x0b62003c, 0x0b62003b, 0x0b62003a, + 0x0a620041, 0x0a620040, 0x0a62003e, 0x0a62003c, + 0x0a62003b, 0x0a62003a, 0x0a620039, 0x0a620038, + 0x0962003e, 0x0962003d, 0x0962003c, 0x0962003b, + 0x09620039, 0x09620037, 0x09620035, 0x09620033, + 0x08620044, 0x08620042, 0x08620040, 0x0862003e, + 0x0862003c, 0x0862003b, 0x0862003a, 0x08620039, + 0x07620043, 0x07620042, 0x07620040, 0x0762003f, + 0x0762003d, 0x0762003b, 0x0762003a, 0x07620039, + 0x0662003e, 0x0662003d, 0x0662003c, 0x0662003b, + 0x06620039, 0x06620037, 0x06620035, 0x06620033, + 0x05620046, 0x05620044, 0x05620042, 0x05620040, + 0x0562003e, 0x0562003c, 0x0562003b, 0x05620039, + 0x04620044, 0x04620042, 0x04620040, 0x0462003e, + 0x0462003c, 0x0462003b, 0x04620039, 0x04620038, + 0x0362003c, 0x0362003b, 0x0362003a, 0x03620039, + 0x03620038, 0x03620037, 0x03620035, 0x03620033, + 0x0262004c, 0x0262004a, 0x02620048, 0x02620047, + 0x02620046, 0x02620044, 0x02620043, 0x02620042, + 0x0162004a, 0x01620048, 0x01620046, 0x01620044, + 0x01620043, 0x01620042, 0x01620041, 0x01620040, + 0x00620042, 0x00620040, 0x0062003e, 0x0062003c, + 0x0062003b, 0x00620039, 0x00620037, 0x00620035 +}; + +static u32 nphy_tpc_5GHz_txgain_HiPwrEPA[] = { + 0x2ff10044, 0x2ff10042, 0x2ff10040, 0x2ff1003e, + 0x2ff1003c, 0x2ff1003b, 0x2ff10039, 0x2ff10037, + 0x2ef10044, 0x2ef10042, 0x2ef10040, 0x2ef1003e, + 0x2ef1003c, 0x2ef1003b, 0x2ef10039, 0x2ef10037, + 0x2df10044, 0x2df10042, 0x2df10040, 0x2df1003e, + 0x2df1003c, 0x2df1003b, 0x2df10039, 0x2df10037, + 0x2cf10044, 0x2cf10042, 0x2cf10040, 0x2cf1003e, + 0x2cf1003c, 0x2cf1003b, 0x2cf10039, 0x2cf10037, + 0x2bf10044, 0x2bf10042, 0x2bf10040, 0x2bf1003e, + 0x2bf1003c, 0x2bf1003b, 0x2bf10039, 0x2bf10037, + 0x2af10044, 0x2af10042, 0x2af10040, 0x2af1003e, + 0x2af1003c, 0x2af1003b, 0x2af10039, 0x2af10037, + 0x29f10044, 0x29f10042, 0x29f10040, 0x29f1003e, + 0x29f1003c, 0x29f1003b, 0x29f10039, 0x29f10037, + 0x28f10044, 0x28f10042, 0x28f10040, 0x28f1003e, + 0x28f1003c, 0x28f1003b, 0x28f10039, 0x28f10037, + 0x27f10044, 0x27f10042, 0x27f10040, 0x27f1003e, + 0x27f1003c, 0x27f1003b, 0x27f10039, 0x27f10037, + 0x26f10044, 0x26f10042, 0x26f10040, 0x26f1003e, + 0x26f1003c, 0x26f1003b, 0x26f10039, 0x26f10037, + 0x25f10044, 0x25f10042, 0x25f10040, 0x25f1003e, + 0x25f1003c, 0x25f1003b, 0x25f10039, 0x25f10037, + 0x24f10044, 0x24f10042, 0x24f10040, 0x24f1003e, + 0x24f1003c, 0x24f1003b, 0x24f10039, 0x24f10038, + 0x23f10041, 0x23f10040, 0x23f1003f, 0x23f1003e, + 0x23f1003c, 0x23f1003b, 0x23f10039, 0x23f10037, + 0x22f10044, 0x22f10042, 0x22f10040, 0x22f1003e, + 0x22f1003c, 0x22f1003b, 0x22f10039, 0x22f10037, + 0x21f10044, 0x21f10042, 0x21f10040, 0x21f1003e, + 0x21f1003c, 0x21f1003b, 0x21f10039, 0x21f10037, + 0x20d10043, 0x20d10041, 0x20d1003e, 0x20d1003c, + 0x20d1003a, 0x20d10038, 0x20d10036, 0x20d10034 +}; + +static u8 ant_sw_ctrl_tbl_rev8_2o3[] = { 0x14, 0x18 }; +static u8 ant_sw_ctrl_tbl_rev8[] = { 0x4, 0x8, 0x4, 0x8, 0x11, 0x12 }; +static u8 ant_sw_ctrl_tbl_rev8_2057v7_core0[] = { + 0x09, 0x0a, 0x15, 0x16, 0x09, 0x0a +}; +static u8 ant_sw_ctrl_tbl_rev8_2057v7_core1[] = { + 0x09, 0x0a, 0x09, 0x0a, 0x15, 0x16 +}; + +bool wlc_phy_bist_check_phy(struct brcms_phy_pub *pih) +{ + struct brcms_phy *pi = (struct brcms_phy *) pih; + u32 phybist0, phybist1, phybist2, phybist3, phybist4; + + if (NREV_GE(pi->pubpi.phy_rev, 16)) + return true; + + phybist0 = read_phy_reg(pi, 0x0e); + phybist1 = read_phy_reg(pi, 0x0f); + phybist2 = read_phy_reg(pi, 0xea); + phybist3 = read_phy_reg(pi, 0xeb); + phybist4 = read_phy_reg(pi, 0x156); + + if ((phybist0 == 0) && (phybist1 == 0x4000) && (phybist2 == 0x1fe0) && + (phybist3 == 0) && (phybist4 == 0)) + return true; + + return false; +} + +static void wlc_phy_bphy_init_nphy(struct brcms_phy *pi) +{ + u16 addr, val; + + val = 0x1e1f; + for (addr = (NPHY_TO_BPHY_OFF + BPHY_RSSI_LUT); + addr <= (NPHY_TO_BPHY_OFF + BPHY_RSSI_LUT_END); addr++) { + write_phy_reg(pi, addr, val); + if (addr == (NPHY_TO_BPHY_OFF + 0x97)) + val = 0x3e3f; + else + val -= 0x0202; + } + + write_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_STEP, 0x668); +} + +void +wlc_phy_table_write_nphy(struct brcms_phy *pi, u32 id, u32 len, u32 offset, + u32 width, const void *data) +{ + struct phytbl_info tbl; + + tbl.tbl_id = id; + tbl.tbl_len = len; + tbl.tbl_offset = offset; + tbl.tbl_width = width; + tbl.tbl_ptr = data; + wlc_phy_write_table_nphy(pi, &tbl); +} + +void +wlc_phy_table_read_nphy(struct brcms_phy *pi, u32 id, u32 len, u32 offset, + u32 width, void *data) +{ + struct phytbl_info tbl; + + tbl.tbl_id = id; + tbl.tbl_len = len; + tbl.tbl_offset = offset; + tbl.tbl_width = width; + tbl.tbl_ptr = data; + wlc_phy_read_table_nphy(pi, &tbl); +} + +static void +wlc_phy_static_table_download_nphy(struct brcms_phy *pi) +{ + uint idx; + + if (NREV_GE(pi->pubpi.phy_rev, 16)) { + for (idx = 0; idx < mimophytbl_info_sz_rev16; idx++) + wlc_phy_write_table_nphy(pi, + &mimophytbl_info_rev16[idx]); + } else if (NREV_GE(pi->pubpi.phy_rev, 7)) { + for (idx = 0; idx < mimophytbl_info_sz_rev7; idx++) + wlc_phy_write_table_nphy(pi, + &mimophytbl_info_rev7[idx]); + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + for (idx = 0; idx < mimophytbl_info_sz_rev3; idx++) + wlc_phy_write_table_nphy(pi, + &mimophytbl_info_rev3[idx]); + } else { + for (idx = 0; idx < mimophytbl_info_sz_rev0; idx++) + wlc_phy_write_table_nphy(pi, + &mimophytbl_info_rev0[idx]); + } +} + +static void wlc_phy_tbl_init_nphy(struct brcms_phy *pi) +{ + uint idx = 0; + u8 antswctrllut; + + if (pi->phy_init_por) + wlc_phy_static_table_download_nphy(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + antswctrllut = CHSPEC_IS2G(pi->radio_chanspec) ? + pi->srom_fem2g.antswctrllut : pi->srom_fem5g. + antswctrllut; + + switch (antswctrllut) { + case 0: + + break; + + case 1: + + if (pi->aa2g == 7) + wlc_phy_table_write_nphy( + pi, + NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x21, 8, + &ant_sw_ctrl_tbl_rev8_2o3[0]); + else + wlc_phy_table_write_nphy( + pi, + NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x21, 8, + &ant_sw_ctrl_tbl_rev8 + [0]); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x25, 8, + &ant_sw_ctrl_tbl_rev8[2]); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x29, 8, + &ant_sw_ctrl_tbl_rev8[4]); + break; + + case 2: + + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x1, 8, + &ant_sw_ctrl_tbl_rev8_2057v7_core0[0]); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x5, 8, + &ant_sw_ctrl_tbl_rev8_2057v7_core0[2]); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x9, 8, + &ant_sw_ctrl_tbl_rev8_2057v7_core0[4]); + + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x21, 8, + &ant_sw_ctrl_tbl_rev8_2057v7_core1[0]); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x25, 8, + &ant_sw_ctrl_tbl_rev8_2057v7_core1[2]); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 2, 0x29, 8, + &ant_sw_ctrl_tbl_rev8_2057v7_core1[4]); + break; + + default: + break; + } + + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + for (idx = 0; idx < mimophytbl_info_sz_rev3_volatile; idx++) { + + if (idx == ANT_SWCTRL_TBL_REV3_IDX) { + antswctrllut = + CHSPEC_IS2G(pi->radio_chanspec) ? + pi->srom_fem2g.antswctrllut : + pi->srom_fem5g.antswctrllut; + switch (antswctrllut) { + case 0: + wlc_phy_write_table_nphy( + pi, + &mimophytbl_info_rev3_volatile + [idx]); + break; + case 1: + wlc_phy_write_table_nphy( + pi, + &mimophytbl_info_rev3_volatile1 + [idx]); + break; + case 2: + wlc_phy_write_table_nphy( + pi, + &mimophytbl_info_rev3_volatile2 + [idx]); + break; + case 3: + wlc_phy_write_table_nphy( + pi, + &mimophytbl_info_rev3_volatile3 + [idx]); + break; + default: + break; + } + } else { + wlc_phy_write_table_nphy( + pi, + &mimophytbl_info_rev3_volatile[idx]); + } + } + } else { + for (idx = 0; idx < mimophytbl_info_sz_rev0_volatile; idx++) + wlc_phy_write_table_nphy(pi, + &mimophytbl_info_rev0_volatile + [idx]); + } +} + +static void +wlc_phy_write_txmacreg_nphy(struct brcms_phy *pi, u16 holdoff, u16 delay) +{ + write_phy_reg(pi, 0x77, holdoff); + write_phy_reg(pi, 0xb4, delay); +} + +void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs) +{ + u16 holdoff, delay; + + if (rifs) { + + holdoff = 0x10; + delay = 0x258; + } else { + + holdoff = 0x15; + delay = 0x320; + } + + wlc_phy_write_txmacreg_nphy(pi, holdoff, delay); + + if (pi && pi->sh && (pi->sh->_rifs_phy != rifs)) + pi->sh->_rifs_phy = rifs; +} + +static void wlc_phy_txpwrctrl_config_nphy(struct brcms_phy *pi) +{ + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + pi->nphy_txpwrctrl = PHY_TPC_HW_ON; + pi->phy_5g_pwrgain = true; + return; + } + + pi->nphy_txpwrctrl = PHY_TPC_HW_OFF; + pi->phy_5g_pwrgain = false; + + if ((pi->sh->boardflags2 & BFL2_TXPWRCTRL_EN) && + NREV_GE(pi->pubpi.phy_rev, 2) && (pi->sh->sromrev >= 4)) + pi->nphy_txpwrctrl = PHY_TPC_HW_ON; + else if ((pi->sh->sromrev >= 4) + && (pi->sh->boardflags2 & BFL2_5G_PWRGAIN)) + pi->phy_5g_pwrgain = true; +} + +static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi) +{ + u16 bw40po, cddpo, stbcpo, bwduppo; + uint band_num; + struct phy_shim_info *shim = pi->sh->physhim; + + if (pi->sh->sromrev >= 9) + return; + + bw40po = (u16) wlapi_getintvar(shim, BRCMS_SROM_BW40PO); + pi->bw402gpo = bw40po & 0xf; + pi->bw405gpo = (bw40po & 0xf0) >> 4; + pi->bw405glpo = (bw40po & 0xf00) >> 8; + pi->bw405ghpo = (bw40po & 0xf000) >> 12; + + cddpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_CDDPO); + pi->cdd2gpo = cddpo & 0xf; + pi->cdd5gpo = (cddpo & 0xf0) >> 4; + pi->cdd5glpo = (cddpo & 0xf00) >> 8; + pi->cdd5ghpo = (cddpo & 0xf000) >> 12; + + stbcpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_STBCPO); + pi->stbc2gpo = stbcpo & 0xf; + pi->stbc5gpo = (stbcpo & 0xf0) >> 4; + pi->stbc5glpo = (stbcpo & 0xf00) >> 8; + pi->stbc5ghpo = (stbcpo & 0xf000) >> 12; + + bwduppo = (u16) wlapi_getintvar(shim, BRCMS_SROM_BWDUPPO); + pi->bwdup2gpo = bwduppo & 0xf; + pi->bwdup5gpo = (bwduppo & 0xf0) >> 4; + pi->bwdup5glpo = (bwduppo & 0xf00) >> 8; + pi->bwdup5ghpo = (bwduppo & 0xf000) >> 12; + + for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP); + band_num++) { + switch (band_num) { + case 0: + + pi->nphy_txpid2g[PHY_CORE_0] = + (u8) wlapi_getintvar(shim, + BRCMS_SROM_TXPID2GA0); + pi->nphy_txpid2g[PHY_CORE_1] = + (u8) wlapi_getintvar(shim, + BRCMS_SROM_TXPID2GA1); + pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g = + (s8) wlapi_getintvar(shim, + BRCMS_SROM_MAXP2GA0); + pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g = + (s8) wlapi_getintvar(shim, + BRCMS_SROM_MAXP2GA1); + pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA2GW0A0); + pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA2GW0A1); + pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA2GW1A0); + pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA2GW1A1); + pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA2GW2A0); + pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA2GW2A1); + pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g = + (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA0); + pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g = + (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA1); + + pi->cck2gpo = (u16) wlapi_getintvar(shim, + BRCMS_SROM_CCK2GPO); + + pi->ofdm2gpo = + (u32) wlapi_getintvar(shim, + BRCMS_SROM_OFDM2GPO); + + pi->mcs2gpo[0] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO0); + pi->mcs2gpo[1] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO1); + pi->mcs2gpo[2] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO2); + pi->mcs2gpo[3] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO3); + pi->mcs2gpo[4] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO4); + pi->mcs2gpo[5] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO5); + pi->mcs2gpo[6] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO6); + pi->mcs2gpo[7] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS2GPO7); + break; + case 1: + + pi->nphy_txpid5g[PHY_CORE_0] = + (u8) wlapi_getintvar(shim, + BRCMS_SROM_TXPID5GA0); + pi->nphy_txpid5g[PHY_CORE_1] = + (u8) wlapi_getintvar(shim, + BRCMS_SROM_TXPID5GA1); + pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm = + (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0); + pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm = + (s8) wlapi_getintvar(shim, + BRCMS_SROM_MAXP5GA1); + pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GW0A0); + pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GW0A1); + pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GW1A0); + pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GW1A1); + pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GW2A0); + pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GW2A1); + pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm = + (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA0); + pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm = + (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA1); + + pi->ofdm5gpo = + (u32) wlapi_getintvar(shim, + BRCMS_SROM_OFDM5GPO); + + pi->mcs5gpo[0] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GPO0); + pi->mcs5gpo[1] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GPO1); + pi->mcs5gpo[2] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GPO2); + pi->mcs5gpo[3] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GPO3); + pi->mcs5gpo[4] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GPO4); + pi->mcs5gpo[5] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GPO5); + pi->mcs5gpo[6] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GPO6); + pi->mcs5gpo[7] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GPO7); + break; + case 2: + + pi->nphy_txpid5gl[0] = + (u8) wlapi_getintvar(shim, + BRCMS_SROM_TXPID5GLA0); + pi->nphy_txpid5gl[1] = + (u8) wlapi_getintvar(shim, + BRCMS_SROM_TXPID5GLA1); + pi->nphy_pwrctrl_info[0].max_pwr_5gl = + (s8) wlapi_getintvar(shim, + BRCMS_SROM_MAXP5GLA0); + pi->nphy_pwrctrl_info[1].max_pwr_5gl = + (s8) wlapi_getintvar(shim, + BRCMS_SROM_MAXP5GLA1); + pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GLW0A0); + pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GLW0A1); + pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GLW1A0); + pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GLW1A1); + pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GLW2A0); + pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GLW2A1); + pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0; + pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0; + + pi->ofdm5glpo = + (u32) wlapi_getintvar(shim, + BRCMS_SROM_OFDM5GLPO); + + pi->mcs5glpo[0] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GLPO0); + pi->mcs5glpo[1] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GLPO1); + pi->mcs5glpo[2] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GLPO2); + pi->mcs5glpo[3] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GLPO3); + pi->mcs5glpo[4] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GLPO4); + pi->mcs5glpo[5] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GLPO5); + pi->mcs5glpo[6] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GLPO6); + pi->mcs5glpo[7] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GLPO7); + break; + case 3: + + pi->nphy_txpid5gh[0] = + (u8) wlapi_getintvar(shim, + BRCMS_SROM_TXPID5GHA0); + pi->nphy_txpid5gh[1] = + (u8) wlapi_getintvar(shim, + BRCMS_SROM_TXPID5GHA1); + pi->nphy_pwrctrl_info[0].max_pwr_5gh = + (s8) wlapi_getintvar(shim, + BRCMS_SROM_MAXP5GHA0); + pi->nphy_pwrctrl_info[1].max_pwr_5gh = + (s8) wlapi_getintvar(shim, + BRCMS_SROM_MAXP5GHA1); + pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GHW0A0); + pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GHW0A1); + pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GHW1A0); + pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GHW1A1); + pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GHW2A0); + pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 = + (s16) wlapi_getintvar(shim, + BRCMS_SROM_PA5GHW2A1); + pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0; + pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0; + + pi->ofdm5ghpo = + (u32) wlapi_getintvar(shim, + BRCMS_SROM_OFDM5GHPO); + + pi->mcs5ghpo[0] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GHPO0); + pi->mcs5ghpo[1] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GHPO1); + pi->mcs5ghpo[2] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GHPO2); + pi->mcs5ghpo[3] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GHPO3); + pi->mcs5ghpo[4] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GHPO4); + pi->mcs5ghpo[5] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GHPO5); + pi->mcs5ghpo[6] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GHPO6); + pi->mcs5ghpo[7] = + (u16) wlapi_getintvar(shim, + BRCMS_SROM_MCS5GHPO7); + break; + } + } + + wlc_phy_txpwr_apply_nphy(pi); +} + +static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) +{ + struct phy_shim_info *shim = pi->sh->physhim; + + pi->antswitch = (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWITCH); + pi->aa2g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G); + pi->aa5g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA5G); + + pi->srom_fem2g.tssipos = (u8) wlapi_getintvar(shim, + BRCMS_SROM_TSSIPOS2G); + pi->srom_fem2g.extpagain = (u8) wlapi_getintvar(shim, + BRCMS_SROM_EXTPAGAIN2G); + pi->srom_fem2g.pdetrange = (u8) wlapi_getintvar(shim, + BRCMS_SROM_PDETRANGE2G); + pi->srom_fem2g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO2G); + pi->srom_fem2g.antswctrllut = + (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G); + + pi->srom_fem5g.tssipos = (u8) wlapi_getintvar(shim, + BRCMS_SROM_TSSIPOS5G); + pi->srom_fem5g.extpagain = (u8) wlapi_getintvar(shim, + BRCMS_SROM_EXTPAGAIN5G); + pi->srom_fem5g.pdetrange = (u8) wlapi_getintvar(shim, + BRCMS_SROM_PDETRANGE5G); + pi->srom_fem5g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO5G); + if (wlapi_getvar(shim, BRCMS_SROM_ANTSWCTL5G)) + pi->srom_fem5g.antswctrllut = + (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL5G); + else + pi->srom_fem5g.antswctrllut = + (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G); + + wlc_phy_txpower_ipa_upd(pi); + + pi->phy_txcore_disable_temp = + (s16) wlapi_getintvar(shim, BRCMS_SROM_TEMPTHRESH); + if (pi->phy_txcore_disable_temp == 0) + pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP; + + pi->phy_tempsense_offset = (s8) wlapi_getintvar(shim, + BRCMS_SROM_TEMPOFFSET); + if (pi->phy_tempsense_offset != 0) { + if (pi->phy_tempsense_offset > + (NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET)) + pi->phy_tempsense_offset = NPHY_SROM_MAXTEMPOFFSET; + else if (pi->phy_tempsense_offset < (NPHY_SROM_TEMPSHIFT + + NPHY_SROM_MINTEMPOFFSET)) + pi->phy_tempsense_offset = NPHY_SROM_MINTEMPOFFSET; + else + pi->phy_tempsense_offset -= NPHY_SROM_TEMPSHIFT; + } + + pi->phy_txcore_enable_temp = + pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP; + + pi->phycal_tempdelta = + (u8) wlapi_getintvar(shim, BRCMS_SROM_PHYCAL_TEMPDELTA); + if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA) + pi->phycal_tempdelta = 0; + + wlc_phy_txpwr_srom_read_ppr_nphy(pi); + + return true; +} + +bool wlc_phy_attach_nphy(struct brcms_phy *pi) +{ + uint i; + + if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 6)) + pi->phyhang_avoid = true; + + if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) { + pi->nphy_gband_spurwar_en = true; + if (pi->sh->boardflags2 & BFL2_SPUR_WAR) + pi->nphy_aband_spurwar_en = true; + } + if (NREV_GE(pi->pubpi.phy_rev, 6) && NREV_LT(pi->pubpi.phy_rev, 7)) { + if (pi->sh->boardflags2 & BFL2_2G_SPUR_WAR) + pi->nphy_gband_spurwar2_en = true; + } + + pi->n_preamble_override = AUTO; + if (NREV_IS(pi->pubpi.phy_rev, 3) || NREV_IS(pi->pubpi.phy_rev, 4)) + pi->n_preamble_override = BRCMS_N_PREAMBLE_MIXEDMODE; + + pi->nphy_txrx_chain = AUTO; + pi->phy_scraminit = AUTO; + + pi->nphy_rxcalparams = 0x010100B5; + + pi->nphy_perical = PHY_PERICAL_MPHASE; + pi->mphase_cal_phase_id = MPHASE_CAL_STATE_IDLE; + pi->mphase_txcal_numcmds = MPHASE_TXCAL_NUMCMDS; + + pi->nphy_gain_boost = true; + pi->nphy_elna_gain_config = false; + pi->radio_is_on = false; + + for (i = 0; i < pi->pubpi.phy_corenum; i++) + pi->nphy_txpwrindex[i].index = AUTO; + + wlc_phy_txpwrctrl_config_nphy(pi); + if (pi->nphy_txpwrctrl == PHY_TPC_HW_ON) + pi->hwpwrctrl_capable = true; + + pi->pi_fptr.init = wlc_phy_init_nphy; + pi->pi_fptr.calinit = wlc_phy_cal_init_nphy; + pi->pi_fptr.chanset = wlc_phy_chanspec_set_nphy; + pi->pi_fptr.txpwrrecalc = wlc_phy_txpower_recalc_target_nphy; + + if (!wlc_phy_txpwr_srom_read_nphy(pi)) + return false; + + return true; +} + +static s32 get_rf_pwr_offset(struct brcms_phy *pi, s16 pga_gn, s16 pad_gn) +{ + s32 rfpwr_offset = 0; + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if ((pi->pubpi.radiorev == 3) || + (pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) + rfpwr_offset = (s16) + nphy_papd_padgain_dlt_2g_2057rev3n4 + [pad_gn]; + else if (pi->pubpi.radiorev == 5) + rfpwr_offset = (s16) + nphy_papd_padgain_dlt_2g_2057rev5 + [pad_gn]; + else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == + 8)) + rfpwr_offset = (s16) + nphy_papd_padgain_dlt_2g_2057rev7 + [pad_gn]; + } else { + if ((pi->pubpi.radiorev == 3) || + (pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) + rfpwr_offset = (s16) + nphy_papd_pgagain_dlt_5g_2057 + [pga_gn]; + else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == + 8)) + rfpwr_offset = (s16) + nphy_papd_pgagain_dlt_5g_2057rev7 + [pga_gn]; + } + return rfpwr_offset; +} + +static void wlc_phy_update_mimoconfig_nphy(struct brcms_phy *pi, s32 preamble) +{ + bool gf_preamble = false; + u16 val; + + if (preamble == BRCMS_N_PREAMBLE_GF) + gf_preamble = true; + + val = read_phy_reg(pi, 0xed); + + val |= RX_GF_MM_AUTO; + val &= ~RX_GF_OR_MM; + if (gf_preamble) + val |= RX_GF_OR_MM; + + write_phy_reg(pi, 0xed, val); +} + +static void wlc_phy_ipa_set_tx_digi_filts_nphy(struct brcms_phy *pi) +{ + int j, type; + u16 addr_offset[] = { 0x186, 0x195, 0x2c5}; + + for (type = 0; type < 3; type++) { + for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, addr_offset[type] + j, + NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]); + } + + if (pi->bw == WL_CHANSPEC_BW_40) { + for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, 0x186 + j, + NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]); + } else { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, 0x186 + j, + NPHY_IPA_REV4_txdigi_filtcoeffs[5][j]); + } + + if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { + for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, 0x2c5 + j, + NPHY_IPA_REV4_txdigi_filtcoeffs[6][j]); + } + } +} + +static void wlc_phy_ipa_restore_tx_digi_filts_nphy(struct brcms_phy *pi) +{ + int j; + + if (pi->bw == WL_CHANSPEC_BW_40) { + for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, 0x195 + j, + NPHY_IPA_REV4_txdigi_filtcoeffs[4][j]); + } else { + for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, 0x186 + j, + NPHY_IPA_REV4_txdigi_filtcoeffs[3][j]); + } +} + +static void +wlc_phy_set_rfseq_nphy(struct brcms_phy *pi, u8 cmd, u8 *events, u8 *dlys, + u8 len) +{ + u32 t1_offset, t2_offset; + u8 ctr; + u8 end_event = + NREV_GE(pi->pubpi.phy_rev, + 3) ? NPHY_REV3_RFSEQ_CMD_END : NPHY_RFSEQ_CMD_END; + u8 end_dly = 1; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + t1_offset = cmd << 4; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t1_offset, 8, + events); + t2_offset = t1_offset + 0x080; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, len, t2_offset, 8, + dlys); + + for (ctr = len; ctr < 16; ctr++) { + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, + t1_offset + ctr, 8, &end_event); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, + t2_offset + ctr, 8, &end_dly); + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static u16 wlc_phy_read_lpf_bw_ctl_nphy(struct brcms_phy *pi, u16 offset) +{ + u16 lpf_bw_ctl_val = 0; + u16 rx2tx_lpf_rc_lut_offset = 0; + + if (offset == 0) { + if (CHSPEC_IS40(pi->radio_chanspec)) + rx2tx_lpf_rc_lut_offset = 0x159; + else + rx2tx_lpf_rc_lut_offset = 0x154; + } else { + rx2tx_lpf_rc_lut_offset = offset; + } + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, + (u32) rx2tx_lpf_rc_lut_offset, 16, + &lpf_bw_ctl_val); + + lpf_bw_ctl_val = lpf_bw_ctl_val & 0x7; + + return lpf_bw_ctl_val; +} + +static void +wlc_phy_rfctrl_override_nphy_rev7(struct brcms_phy *pi, u16 field, u16 value, + u8 core_mask, u8 off, u8 override_id) +{ + u8 core_num; + u16 addr = 0, en_addr = 0, val_addr = 0, en_mask = 0, val_mask = 0; + u8 val_shift = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + en_mask = field; + for (core_num = 0; core_num < 2; core_num++) { + if (override_id == NPHY_REV7_RFCTRLOVERRIDE_ID0) { + + switch (field) { + case (0x1 << 2): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : + 0x7d; + val_mask = (0x1 << 1); + val_shift = 1; + break; + case (0x1 << 3): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : + 0x7d; + val_mask = (0x1 << 2); + val_shift = 2; + break; + case (0x1 << 4): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : + 0x7d; + val_mask = (0x1 << 4); + val_shift = 4; + break; + case (0x1 << 5): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : + 0x7d; + val_mask = (0x1 << 5); + val_shift = 5; + break; + case (0x1 << 6): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : + 0x7d; + val_mask = (0x1 << 6); + val_shift = 6; + break; + case (0x1 << 7): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : + 0x7d; + val_mask = (0x1 << 7); + val_shift = 7; + break; + case (0x1 << 10): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0xf8 : + 0xfa; + val_mask = (0x7 << 4); + val_shift = 4; + break; + case (0x1 << 11): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7b : + 0x7e; + val_mask = (0xffff << 0); + val_shift = 0; + break; + case (0x1 << 12): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7c : + 0x7f; + val_mask = (0xffff << 0); + val_shift = 0; + break; + case (0x3 << 13): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x348 : + 0x349; + val_mask = (0xff << 0); + val_shift = 0; + break; + case (0x1 << 13): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x348 : + 0x349; + val_mask = (0xf << 0); + val_shift = 0; + break; + default: + addr = 0xffff; + break; + } + } else if (override_id == + NPHY_REV7_RFCTRLOVERRIDE_ID1) { + + switch (field) { + case (0x1 << 1): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 1); + val_shift = 1; + break; + case (0x1 << 3): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 3); + val_shift = 3; + break; + case (0x1 << 5): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 5); + val_shift = 5; + break; + case (0x1 << 4): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 4); + val_shift = 4; + break; + case (0x1 << 2): + + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 2); + val_shift = 2; + break; + case (0x1 << 7): + + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x7 << 8); + val_shift = 8; + break; + case (0x1 << 11): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 14); + val_shift = 14; + break; + case (0x1 << 10): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 13); + val_shift = 13; + break; + case (0x1 << 9): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 12); + val_shift = 12; + break; + case (0x1 << 8): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 11); + val_shift = 11; + break; + case (0x1 << 6): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 6); + val_shift = 6; + break; + case (0x1 << 0): + en_addr = (core_num == 0) ? 0x342 : + 0x343; + val_addr = (core_num == 0) ? 0x340 : + 0x341; + val_mask = (0x1 << 0); + val_shift = 0; + break; + default: + addr = 0xffff; + break; + } + } else if (override_id == + NPHY_REV7_RFCTRLOVERRIDE_ID2) { + + switch (field) { + case (0x1 << 3): + en_addr = (core_num == 0) ? 0x346 : + 0x347; + val_addr = (core_num == 0) ? 0x344 : + 0x345; + val_mask = (0x1 << 3); + val_shift = 3; + break; + case (0x1 << 1): + en_addr = (core_num == 0) ? 0x346 : + 0x347; + val_addr = (core_num == 0) ? 0x344 : + 0x345; + val_mask = (0x1 << 1); + val_shift = 1; + break; + case (0x1 << 0): + en_addr = (core_num == 0) ? 0x346 : + 0x347; + val_addr = (core_num == 0) ? 0x344 : + 0x345; + val_mask = (0x1 << 0); + val_shift = 0; + break; + case (0x1 << 2): + en_addr = (core_num == 0) ? 0x346 : + 0x347; + val_addr = (core_num == 0) ? 0x344 : + 0x345; + val_mask = (0x1 << 2); + val_shift = 2; + break; + case (0x1 << 4): + en_addr = (core_num == 0) ? 0x346 : + 0x347; + val_addr = (core_num == 0) ? 0x344 : + 0x345; + val_mask = (0x1 << 4); + val_shift = 4; + break; + default: + addr = 0xffff; + break; + } + } + + if (off) { + and_phy_reg(pi, en_addr, ~en_mask); + and_phy_reg(pi, val_addr, ~val_mask); + } else { + + if ((core_mask == 0) + || (core_mask & (1 << core_num))) { + or_phy_reg(pi, en_addr, en_mask); + + if (addr != 0xffff) + mod_phy_reg(pi, val_addr, + val_mask, + (value << + val_shift)); + } + } + } + } +} + +static void wlc_phy_adjust_lnagaintbl_nphy(struct brcms_phy *pi) +{ + uint core; + int ctr; + s16 gain_delta[2]; + u8 curr_channel; + u16 minmax_gain[2]; + u16 regval[4]; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + if (pi->nphy_gain_boost) { + if ((CHSPEC_IS2G(pi->radio_chanspec))) { + + gain_delta[0] = 6; + gain_delta[1] = 6; + } else { + + curr_channel = CHSPEC_CHANNEL(pi->radio_chanspec); + gain_delta[0] = + (s16) + PHY_HW_ROUND(((nphy_lnagain_est0[0] * + curr_channel) + + nphy_lnagain_est0[1]), 13); + gain_delta[1] = + (s16) + PHY_HW_ROUND(((nphy_lnagain_est1[0] * + curr_channel) + + nphy_lnagain_est1[1]), 13); + } + } else { + + gain_delta[0] = 0; + gain_delta[1] = 0; + } + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + if (pi->nphy_elna_gain_config) { + + regval[0] = nphy_def_lnagains[2] + gain_delta[core]; + regval[1] = nphy_def_lnagains[3] + gain_delta[core]; + regval[2] = nphy_def_lnagains[3] + gain_delta[core]; + regval[3] = nphy_def_lnagains[3] + gain_delta[core]; + } else { + for (ctr = 0; ctr < 4; ctr++) + regval[ctr] = + nphy_def_lnagains[ctr] + + gain_delta[core]; + } + wlc_phy_table_write_nphy(pi, core, 4, 8, 16, regval); + + minmax_gain[core] = + (u16) (nphy_def_lnagains[2] + gain_delta[core] + 4); + } + + mod_phy_reg(pi, 0x1e, (0xff << 0), (minmax_gain[0] << 0)); + mod_phy_reg(pi, 0x34, (0xff << 0), (minmax_gain[1] << 0)); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static void +wlc_phy_war_force_trsw_to_R_cliplo_nphy(struct brcms_phy *pi, u8 core) +{ + if (core == PHY_CORE_0) { + write_phy_reg(pi, 0x38, 0x4); + if (CHSPEC_IS2G(pi->radio_chanspec)) + write_phy_reg(pi, 0x37, 0x0060); + else + write_phy_reg(pi, 0x37, 0x1080); + } else if (core == PHY_CORE_1) { + write_phy_reg(pi, 0x2ae, 0x4); + if (CHSPEC_IS2G(pi->radio_chanspec)) + write_phy_reg(pi, 0x2ad, 0x0060); + else + write_phy_reg(pi, 0x2ad, 0x1080); + } +} + +static void wlc_phy_war_txchain_upd_nphy(struct brcms_phy *pi, u8 txchain) +{ + u8 txchain0, txchain1; + + txchain0 = txchain & 0x1; + txchain1 = (txchain & 0x2) >> 1; + if (!txchain0) + wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0); + + if (!txchain1) + wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1); +} + +static void wlc_phy_workarounds_nphy_gainctrl_2057_rev5(struct brcms_phy *pi) +{ + s8 lna1_gain_db[] = { 8, 13, 17, 22 }; + s8 lna2_gain_db[] = { -2, 7, 11, 15 }; + s8 tia_gain_db[] = { -4, -1, 2, 5, 5, 5, 5, 5, 5, 5 }; + s8 tia_gainbits[] = { + 0x0, 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; + + mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13)); + mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13)); + + mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0)); + + mod_phy_reg(pi, 0x283, (0xff << 0), (0x3c << 0)); + mod_phy_reg(pi, 0x280, (0xff << 0), (0x3c << 0)); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x8, 8, + lna1_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x8, 8, + lna1_gain_db); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, 8, + lna2_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, 8, + lna2_gain_db); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8, + tia_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8, + tia_gain_db); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8, + tia_gainbits); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8, + tia_gainbits); + + write_phy_reg(pi, 0x37, 0x74); + write_phy_reg(pi, 0x2ad, 0x74); + write_phy_reg(pi, 0x38, 0x18); + write_phy_reg(pi, 0x2ae, 0x18); + + write_phy_reg(pi, 0x2b, 0xe8); + write_phy_reg(pi, 0x41, 0xe8); + + if (CHSPEC_IS20(pi->radio_chanspec)) { + + mod_phy_reg(pi, 0x300, (0x3f << 0), (0x12 << 0)); + mod_phy_reg(pi, 0x301, (0x3f << 0), (0x12 << 0)); + } else { + + mod_phy_reg(pi, 0x300, (0x3f << 0), (0x10 << 0)); + mod_phy_reg(pi, 0x301, (0x3f << 0), (0x10 << 0)); + } +} + +static void wlc_phy_workarounds_nphy_gainctrl_2057_rev6(struct brcms_phy *pi) +{ + u16 currband; + s8 lna1G_gain_db_rev7[] = { 9, 14, 19, 24 }; + s8 *lna1_gain_db = NULL; + s8 *lna1_gain_db_2 = NULL; + s8 *lna2_gain_db = NULL; + s8 tiaA_gain_db_rev7[] = { -9, -6, -3, 0, 3, 3, 3, 3, 3, 3 }; + s8 *tia_gain_db; + s8 tiaA_gainbits_rev7[] = { 0, 1, 2, 3, 4, 4, 4, 4, 4, 4 }; + s8 *tia_gainbits; + u16 rfseqA_init_gain_rev7[] = { 0x624f, 0x624f }; + u16 *rfseq_init_gain; + u16 init_gaincode; + u16 clip1hi_gaincode; + u16 clip1md_gaincode = 0; + u16 clip1md_gaincode_B; + u16 clip1lo_gaincode; + u16 clip1lo_gaincode_B; + u8 crsminl_th = 0; + u8 crsminu_th; + u16 nbclip_th = 0; + u8 w1clip_th; + u16 freq; + s8 nvar_baseline_offset0 = 0, nvar_baseline_offset1 = 0; + u8 chg_nbclip_th = 0; + + mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13)); + mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13)); + + currband = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; + if (currband == 0) { + + lna1_gain_db = lna1G_gain_db_rev7; + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8, + lna1_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8, + lna1_gain_db); + + mod_phy_reg(pi, 0x283, (0xff << 0), (0x40 << 0)); + + if (CHSPEC_IS40(pi->radio_chanspec)) { + mod_phy_reg(pi, 0x280, (0xff << 0), (0x3e << 0)); + mod_phy_reg(pi, 0x283, (0xff << 0), (0x3e << 0)); + } + + mod_phy_reg(pi, 0x289, (0xff << 0), (0x46 << 0)); + + if (CHSPEC_IS20(pi->radio_chanspec)) { + mod_phy_reg(pi, 0x300, (0x3f << 0), (13 << 0)); + mod_phy_reg(pi, 0x301, (0x3f << 0), (13 << 0)); + } + } else { + + init_gaincode = 0x9e; + clip1hi_gaincode = 0x9e; + clip1md_gaincode_B = 0x24; + clip1lo_gaincode = 0x8a; + clip1lo_gaincode_B = 8; + rfseq_init_gain = rfseqA_init_gain_rev7; + + tia_gain_db = tiaA_gain_db_rev7; + tia_gainbits = tiaA_gainbits_rev7; + + freq = CHAN5G_FREQ(CHSPEC_CHANNEL(pi->radio_chanspec)); + if (CHSPEC_IS20(pi->radio_chanspec)) { + + w1clip_th = 25; + clip1md_gaincode = 0x82; + + if ((freq <= 5080) || (freq == 5825)) { + + s8 lna1A_gain_db_rev7[] = { 11, 16, 20, 24 }; + s8 lna1A_gain_db_2_rev7[] = { + 11, 17, 22, 25}; + s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; + + crsminu_th = 0x3e; + lna1_gain_db = lna1A_gain_db_rev7; + lna1_gain_db_2 = lna1A_gain_db_2_rev7; + lna2_gain_db = lna2A_gain_db_rev7; + } else if ((freq >= 5500) && (freq <= 5700)) { + + s8 lna1A_gain_db_rev7[] = { 11, 17, 21, 25 }; + s8 lna1A_gain_db_2_rev7[] = { + 12, 18, 22, 26}; + s8 lna2A_gain_db_rev7[] = { 1, 8, 12, 16 }; + + crsminu_th = 0x45; + clip1md_gaincode_B = 0x14; + nbclip_th = 0xff; + chg_nbclip_th = 1; + lna1_gain_db = lna1A_gain_db_rev7; + lna1_gain_db_2 = lna1A_gain_db_2_rev7; + lna2_gain_db = lna2A_gain_db_rev7; + } else { + + s8 lna1A_gain_db_rev7[] = { 12, 18, 22, 26 }; + s8 lna1A_gain_db_2_rev7[] = { + 12, 18, 22, 26}; + s8 lna2A_gain_db_rev7[] = { -1, 6, 10, 14 }; + + crsminu_th = 0x41; + lna1_gain_db = lna1A_gain_db_rev7; + lna1_gain_db_2 = lna1A_gain_db_2_rev7; + lna2_gain_db = lna2A_gain_db_rev7; + } + + if (freq <= 4920) { + nvar_baseline_offset0 = 5; + nvar_baseline_offset1 = 5; + } else if ((freq > 4920) && (freq <= 5320)) { + nvar_baseline_offset0 = 3; + nvar_baseline_offset1 = 5; + } else if ((freq > 5320) && (freq <= 5700)) { + nvar_baseline_offset0 = 3; + nvar_baseline_offset1 = 2; + } else { + nvar_baseline_offset0 = 4; + nvar_baseline_offset1 = 0; + } + } else { + + crsminu_th = 0x3a; + crsminl_th = 0x3a; + w1clip_th = 20; + + if ((freq >= 4920) && (freq <= 5320)) { + nvar_baseline_offset0 = 4; + nvar_baseline_offset1 = 5; + } else if ((freq > 5320) && (freq <= 5550)) { + nvar_baseline_offset0 = 4; + nvar_baseline_offset1 = 2; + } else { + nvar_baseline_offset0 = 5; + nvar_baseline_offset1 = 3; + } + } + + write_phy_reg(pi, 0x20, init_gaincode); + write_phy_reg(pi, 0x2a7, init_gaincode); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, + pi->pubpi.phy_corenum, 0x106, 16, + rfseq_init_gain); + + write_phy_reg(pi, 0x22, clip1hi_gaincode); + write_phy_reg(pi, 0x2a9, clip1hi_gaincode); + + write_phy_reg(pi, 0x36, clip1md_gaincode_B); + write_phy_reg(pi, 0x2ac, clip1md_gaincode_B); + + write_phy_reg(pi, 0x37, clip1lo_gaincode); + write_phy_reg(pi, 0x2ad, clip1lo_gaincode); + write_phy_reg(pi, 0x38, clip1lo_gaincode_B); + write_phy_reg(pi, 0x2ae, clip1lo_gaincode_B); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, 8, + tia_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, 8, + tia_gain_db); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, 8, + tia_gainbits); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, 8, + tia_gainbits); + + mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0)); + + if (chg_nbclip_th == 1) { + write_phy_reg(pi, 0x2b, nbclip_th); + write_phy_reg(pi, 0x41, nbclip_th); + } + + mod_phy_reg(pi, 0x300, (0x3f << 0), (w1clip_th << 0)); + mod_phy_reg(pi, 0x301, (0x3f << 0), (w1clip_th << 0)); + + mod_phy_reg(pi, 0x2e4, + (0x3f << 0), (nvar_baseline_offset0 << 0)); + + mod_phy_reg(pi, 0x2e4, + (0x3f << 6), (nvar_baseline_offset1 << 6)); + + if (CHSPEC_IS20(pi->radio_chanspec)) { + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, 8, + lna1_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, 8, + lna1_gain_db_2); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, + 8, lna2_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, + 8, lna2_gain_db); + + write_phy_reg(pi, 0x24, clip1md_gaincode); + write_phy_reg(pi, 0x2ab, clip1md_gaincode); + } else { + mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0)); + } + } +} + +static void wlc_phy_workarounds_nphy_gainctrl(struct brcms_phy *pi) +{ + u16 w1th, hpf_code, currband; + int ctr; + u8 rfseq_updategainu_events[] = { + NPHY_RFSEQ_CMD_RX_GAIN, + NPHY_RFSEQ_CMD_CLR_HIQ_DIS, + NPHY_RFSEQ_CMD_SET_HPF_BW + }; + u8 rfseq_updategainu_dlys[] = { 10, 30, 1 }; + s8 lna1G_gain_db[] = { 7, 11, 16, 23 }; + s8 lna1G_gain_db_rev4[] = { 8, 12, 17, 25 }; + s8 lna1G_gain_db_rev5[] = { 9, 13, 18, 26 }; + s8 lna1G_gain_db_rev6[] = { 8, 13, 18, 25 }; + s8 lna1G_gain_db_rev6_224B0[] = { 10, 14, 19, 27 }; + s8 lna1A_gain_db[] = { 7, 11, 17, 23 }; + s8 lna1A_gain_db_rev4[] = { 8, 12, 18, 23 }; + s8 lna1A_gain_db_rev5[] = { 6, 10, 16, 21 }; + s8 lna1A_gain_db_rev6[] = { 6, 10, 16, 21 }; + s8 *lna1_gain_db = NULL; + s8 lna2G_gain_db[] = { -5, 6, 10, 14 }; + s8 lna2G_gain_db_rev5[] = { -3, 7, 11, 16 }; + s8 lna2G_gain_db_rev6[] = { -5, 6, 10, 14 }; + s8 lna2G_gain_db_rev6_224B0[] = { -5, 6, 10, 15 }; + s8 lna2A_gain_db[] = { -6, 2, 6, 10 }; + s8 lna2A_gain_db_rev4[] = { -5, 2, 6, 10 }; + s8 lna2A_gain_db_rev5[] = { -7, 0, 4, 8 }; + s8 lna2A_gain_db_rev6[] = { -7, 0, 4, 8 }; + s8 *lna2_gain_db = NULL; + s8 tiaG_gain_db[] = { + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A }; + s8 tiaA_gain_db[] = { + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13 }; + s8 tiaA_gain_db_rev4[] = { + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; + s8 tiaA_gain_db_rev5[] = { + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; + s8 tiaA_gain_db_rev6[] = { + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d }; + s8 *tia_gain_db; + s8 tiaG_gainbits[] = { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03 }; + s8 tiaA_gainbits[] = { + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06 }; + s8 tiaA_gainbits_rev4[] = { + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; + s8 tiaA_gainbits_rev5[] = { + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; + s8 tiaA_gainbits_rev6[] = { + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }; + s8 *tia_gainbits; + s8 lpf_gain_db[] = { 0x00, 0x06, 0x0c, 0x12, 0x12, 0x12 }; + s8 lpf_gainbits[] = { 0x00, 0x01, 0x02, 0x03, 0x03, 0x03 }; + u16 rfseqG_init_gain[] = { 0x613f, 0x613f, 0x613f, 0x613f }; + u16 rfseqG_init_gain_rev4[] = { 0x513f, 0x513f, 0x513f, 0x513f }; + u16 rfseqG_init_gain_rev5[] = { 0x413f, 0x413f, 0x413f, 0x413f }; + u16 rfseqG_init_gain_rev5_elna[] = { + 0x013f, 0x013f, 0x013f, 0x013f }; + u16 rfseqG_init_gain_rev6[] = { 0x513f, 0x513f }; + u16 rfseqG_init_gain_rev6_224B0[] = { 0x413f, 0x413f }; + u16 rfseqG_init_gain_rev6_elna[] = { 0x113f, 0x113f }; + u16 rfseqA_init_gain[] = { 0x516f, 0x516f, 0x516f, 0x516f }; + u16 rfseqA_init_gain_rev4[] = { 0x614f, 0x614f, 0x614f, 0x614f }; + u16 rfseqA_init_gain_rev4_elna[] = { + 0x314f, 0x314f, 0x314f, 0x314f }; + u16 rfseqA_init_gain_rev5[] = { 0x714f, 0x714f, 0x714f, 0x714f }; + u16 rfseqA_init_gain_rev6[] = { 0x714f, 0x714f }; + u16 *rfseq_init_gain; + u16 initG_gaincode = 0x627e; + u16 initG_gaincode_rev4 = 0x527e; + u16 initG_gaincode_rev5 = 0x427e; + u16 initG_gaincode_rev5_elna = 0x027e; + u16 initG_gaincode_rev6 = 0x527e; + u16 initG_gaincode_rev6_224B0 = 0x427e; + u16 initG_gaincode_rev6_elna = 0x127e; + u16 initA_gaincode = 0x52de; + u16 initA_gaincode_rev4 = 0x629e; + u16 initA_gaincode_rev4_elna = 0x329e; + u16 initA_gaincode_rev5 = 0x729e; + u16 initA_gaincode_rev6 = 0x729e; + u16 init_gaincode; + u16 clip1hiG_gaincode = 0x107e; + u16 clip1hiG_gaincode_rev4 = 0x007e; + u16 clip1hiG_gaincode_rev5 = 0x1076; + u16 clip1hiG_gaincode_rev6 = 0x007e; + u16 clip1hiA_gaincode = 0x00de; + u16 clip1hiA_gaincode_rev4 = 0x029e; + u16 clip1hiA_gaincode_rev5 = 0x029e; + u16 clip1hiA_gaincode_rev6 = 0x029e; + u16 clip1hi_gaincode; + u16 clip1mdG_gaincode = 0x0066; + u16 clip1mdA_gaincode = 0x00ca; + u16 clip1mdA_gaincode_rev4 = 0x1084; + u16 clip1mdA_gaincode_rev5 = 0x2084; + u16 clip1mdA_gaincode_rev6 = 0x2084; + u16 clip1md_gaincode = 0; + u16 clip1loG_gaincode = 0x0074; + u16 clip1loG_gaincode_rev5[] = { + 0x0062, 0x0064, 0x006a, 0x106a, 0x106c, 0x1074, 0x107c, 0x207c + }; + u16 clip1loG_gaincode_rev6[] = { + 0x106a, 0x106c, 0x1074, 0x107c, 0x007e, 0x107e, 0x207e, 0x307e + }; + u16 clip1loG_gaincode_rev6_224B0 = 0x1074; + u16 clip1loA_gaincode = 0x00cc; + u16 clip1loA_gaincode_rev4 = 0x0086; + u16 clip1loA_gaincode_rev5 = 0x2086; + u16 clip1loA_gaincode_rev6 = 0x2086; + u16 clip1lo_gaincode; + u8 crsminG_th = 0x18; + u8 crsminG_th_rev5 = 0x18; + u8 crsminG_th_rev6 = 0x18; + u8 crsminA_th = 0x1e; + u8 crsminA_th_rev4 = 0x24; + u8 crsminA_th_rev5 = 0x24; + u8 crsminA_th_rev6 = 0x24; + u8 crsmin_th; + u8 crsminlG_th = 0x18; + u8 crsminlG_th_rev5 = 0x18; + u8 crsminlG_th_rev6 = 0x18; + u8 crsminlA_th = 0x1e; + u8 crsminlA_th_rev4 = 0x24; + u8 crsminlA_th_rev5 = 0x24; + u8 crsminlA_th_rev6 = 0x24; + u8 crsminl_th = 0; + u8 crsminuG_th = 0x18; + u8 crsminuG_th_rev5 = 0x18; + u8 crsminuG_th_rev6 = 0x18; + u8 crsminuA_th = 0x1e; + u8 crsminuA_th_rev4 = 0x24; + u8 crsminuA_th_rev5 = 0x24; + u8 crsminuA_th_rev6 = 0x24; + u8 crsminuA_th_rev6_224B0 = 0x2d; + u8 crsminu_th; + u16 nbclipG_th = 0x20d; + u16 nbclipG_th_rev4 = 0x1a1; + u16 nbclipG_th_rev5 = 0x1d0; + u16 nbclipG_th_rev6 = 0x1d0; + u16 nbclipA_th = 0x1a1; + u16 nbclipA_th_rev4 = 0x107; + u16 nbclipA_th_rev5 = 0x0a9; + u16 nbclipA_th_rev6 = 0x0f0; + u16 nbclip_th = 0; + u8 w1clipG_th = 5; + u8 w1clipG_th_rev5 = 9; + u8 w1clipG_th_rev6 = 5; + u8 w1clipA_th = 25, w1clip_th; + u8 rssi_gain_default = 0x50; + u8 rssiG_gain_rev6_224B0 = 0x50; + u8 rssiA_gain_rev5 = 0x90; + u8 rssiA_gain_rev6 = 0x90; + u8 rssi_gain; + u16 regval[21]; + u8 triso; + + triso = (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g.triso : + pi->srom_fem2g.triso; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (pi->pubpi.radiorev == 5) { + wlc_phy_workarounds_nphy_gainctrl_2057_rev5(pi); + } else if (pi->pubpi.radiorev == 7) { + wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi); + + mod_phy_reg(pi, 0x283, (0xff << 0), (0x44 << 0)); + mod_phy_reg(pi, 0x280, (0xff << 0), (0x44 << 0)); + + } else if ((pi->pubpi.radiorev == 3) + || (pi->pubpi.radiorev == 8)) { + wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi); + + if (pi->pubpi.radiorev == 8) { + mod_phy_reg(pi, 0x283, + (0xff << 0), (0x44 << 0)); + mod_phy_reg(pi, 0x280, + (0xff << 0), (0x44 << 0)); + } + } else { + wlc_phy_workarounds_nphy_gainctrl_2057_rev6(pi); + } + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + mod_phy_reg(pi, 0xa0, (0x1 << 6), (1 << 6)); + + mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13)); + mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13)); + + currband = + read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; + if (currband == 0) { + if (NREV_GE(pi->pubpi.phy_rev, 6)) { + if (pi->pubpi.radiorev == 11) { + lna1_gain_db = lna1G_gain_db_rev6_224B0; + lna2_gain_db = lna2G_gain_db_rev6_224B0; + rfseq_init_gain = + rfseqG_init_gain_rev6_224B0; + init_gaincode = + initG_gaincode_rev6_224B0; + clip1hi_gaincode = + clip1hiG_gaincode_rev6; + clip1lo_gaincode = + clip1loG_gaincode_rev6_224B0; + nbclip_th = nbclipG_th_rev6; + w1clip_th = w1clipG_th_rev6; + crsmin_th = crsminG_th_rev6; + crsminl_th = crsminlG_th_rev6; + crsminu_th = crsminuG_th_rev6; + rssi_gain = rssiG_gain_rev6_224B0; + } else { + lna1_gain_db = lna1G_gain_db_rev6; + lna2_gain_db = lna2G_gain_db_rev6; + if (pi->sh->boardflags & BFL_EXTLNA) { + + rfseq_init_gain = + rfseqG_init_gain_rev6_elna; + init_gaincode = + initG_gaincode_rev6_elna; + } else { + rfseq_init_gain = + rfseqG_init_gain_rev6; + init_gaincode = + initG_gaincode_rev6; + } + clip1hi_gaincode = + clip1hiG_gaincode_rev6; + switch (triso) { + case 0: + clip1lo_gaincode = + clip1loG_gaincode_rev6 + [0]; + break; + case 1: + clip1lo_gaincode = + clip1loG_gaincode_rev6 + [1]; + break; + case 2: + clip1lo_gaincode = + clip1loG_gaincode_rev6 + [2]; + break; + case 3: + default: + + clip1lo_gaincode = + clip1loG_gaincode_rev6 + [3]; + break; + case 4: + clip1lo_gaincode = + clip1loG_gaincode_rev6 + [4]; + break; + case 5: + clip1lo_gaincode = + clip1loG_gaincode_rev6 + [5]; + break; + case 6: + clip1lo_gaincode = + clip1loG_gaincode_rev6 + [6]; + break; + case 7: + clip1lo_gaincode = + clip1loG_gaincode_rev6 + [7]; + break; + } + nbclip_th = nbclipG_th_rev6; + w1clip_th = w1clipG_th_rev6; + crsmin_th = crsminG_th_rev6; + crsminl_th = crsminlG_th_rev6; + crsminu_th = crsminuG_th_rev6; + rssi_gain = rssi_gain_default; + } + } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { + lna1_gain_db = lna1G_gain_db_rev5; + lna2_gain_db = lna2G_gain_db_rev5; + if (pi->sh->boardflags & BFL_EXTLNA) { + + rfseq_init_gain = + rfseqG_init_gain_rev5_elna; + init_gaincode = + initG_gaincode_rev5_elna; + } else { + rfseq_init_gain = rfseqG_init_gain_rev5; + init_gaincode = initG_gaincode_rev5; + } + clip1hi_gaincode = clip1hiG_gaincode_rev5; + switch (triso) { + case 0: + clip1lo_gaincode = + clip1loG_gaincode_rev5[0]; + break; + case 1: + clip1lo_gaincode = + clip1loG_gaincode_rev5[1]; + break; + case 2: + clip1lo_gaincode = + clip1loG_gaincode_rev5[2]; + break; + case 3: + + clip1lo_gaincode = + clip1loG_gaincode_rev5[3]; + break; + case 4: + clip1lo_gaincode = + clip1loG_gaincode_rev5[4]; + break; + case 5: + clip1lo_gaincode = + clip1loG_gaincode_rev5[5]; + break; + case 6: + clip1lo_gaincode = + clip1loG_gaincode_rev5[6]; + break; + case 7: + clip1lo_gaincode = + clip1loG_gaincode_rev5[7]; + break; + default: + clip1lo_gaincode = + clip1loG_gaincode_rev5[3]; + break; + } + nbclip_th = nbclipG_th_rev5; + w1clip_th = w1clipG_th_rev5; + crsmin_th = crsminG_th_rev5; + crsminl_th = crsminlG_th_rev5; + crsminu_th = crsminuG_th_rev5; + rssi_gain = rssi_gain_default; + } else if (NREV_IS(pi->pubpi.phy_rev, 4)) { + lna1_gain_db = lna1G_gain_db_rev4; + lna2_gain_db = lna2G_gain_db; + rfseq_init_gain = rfseqG_init_gain_rev4; + init_gaincode = initG_gaincode_rev4; + clip1hi_gaincode = clip1hiG_gaincode_rev4; + clip1lo_gaincode = clip1loG_gaincode; + nbclip_th = nbclipG_th_rev4; + w1clip_th = w1clipG_th; + crsmin_th = crsminG_th; + crsminl_th = crsminlG_th; + crsminu_th = crsminuG_th; + rssi_gain = rssi_gain_default; + } else { + lna1_gain_db = lna1G_gain_db; + lna2_gain_db = lna2G_gain_db; + rfseq_init_gain = rfseqG_init_gain; + init_gaincode = initG_gaincode; + clip1hi_gaincode = clip1hiG_gaincode; + clip1lo_gaincode = clip1loG_gaincode; + nbclip_th = nbclipG_th; + w1clip_th = w1clipG_th; + crsmin_th = crsminG_th; + crsminl_th = crsminlG_th; + crsminu_th = crsminuG_th; + rssi_gain = rssi_gain_default; + } + tia_gain_db = tiaG_gain_db; + tia_gainbits = tiaG_gainbits; + clip1md_gaincode = clip1mdG_gaincode; + } else { + if (NREV_GE(pi->pubpi.phy_rev, 6)) { + lna1_gain_db = lna1A_gain_db_rev6; + lna2_gain_db = lna2A_gain_db_rev6; + tia_gain_db = tiaA_gain_db_rev6; + tia_gainbits = tiaA_gainbits_rev6; + rfseq_init_gain = rfseqA_init_gain_rev6; + init_gaincode = initA_gaincode_rev6; + clip1hi_gaincode = clip1hiA_gaincode_rev6; + clip1md_gaincode = clip1mdA_gaincode_rev6; + clip1lo_gaincode = clip1loA_gaincode_rev6; + crsmin_th = crsminA_th_rev6; + crsminl_th = crsminlA_th_rev6; + if ((pi->pubpi.radiorev == 11) && + (CHSPEC_IS40(pi->radio_chanspec) == 0)) + crsminu_th = crsminuA_th_rev6_224B0; + else + crsminu_th = crsminuA_th_rev6; + + nbclip_th = nbclipA_th_rev6; + rssi_gain = rssiA_gain_rev6; + } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { + lna1_gain_db = lna1A_gain_db_rev5; + lna2_gain_db = lna2A_gain_db_rev5; + tia_gain_db = tiaA_gain_db_rev5; + tia_gainbits = tiaA_gainbits_rev5; + rfseq_init_gain = rfseqA_init_gain_rev5; + init_gaincode = initA_gaincode_rev5; + clip1hi_gaincode = clip1hiA_gaincode_rev5; + clip1md_gaincode = clip1mdA_gaincode_rev5; + clip1lo_gaincode = clip1loA_gaincode_rev5; + crsmin_th = crsminA_th_rev5; + crsminl_th = crsminlA_th_rev5; + crsminu_th = crsminuA_th_rev5; + nbclip_th = nbclipA_th_rev5; + rssi_gain = rssiA_gain_rev5; + } else if (NREV_IS(pi->pubpi.phy_rev, 4)) { + lna1_gain_db = lna1A_gain_db_rev4; + lna2_gain_db = lna2A_gain_db_rev4; + tia_gain_db = tiaA_gain_db_rev4; + tia_gainbits = tiaA_gainbits_rev4; + if (pi->sh->boardflags & BFL_EXTLNA_5GHz) { + + rfseq_init_gain = + rfseqA_init_gain_rev4_elna; + init_gaincode = + initA_gaincode_rev4_elna; + } else { + rfseq_init_gain = rfseqA_init_gain_rev4; + init_gaincode = initA_gaincode_rev4; + } + clip1hi_gaincode = clip1hiA_gaincode_rev4; + clip1md_gaincode = clip1mdA_gaincode_rev4; + clip1lo_gaincode = clip1loA_gaincode_rev4; + crsmin_th = crsminA_th_rev4; + crsminl_th = crsminlA_th_rev4; + crsminu_th = crsminuA_th_rev4; + nbclip_th = nbclipA_th_rev4; + rssi_gain = rssi_gain_default; + } else { + lna1_gain_db = lna1A_gain_db; + lna2_gain_db = lna2A_gain_db; + tia_gain_db = tiaA_gain_db; + tia_gainbits = tiaA_gainbits; + rfseq_init_gain = rfseqA_init_gain; + init_gaincode = initA_gaincode; + clip1hi_gaincode = clip1hiA_gaincode; + clip1md_gaincode = clip1mdA_gaincode; + clip1lo_gaincode = clip1loA_gaincode; + crsmin_th = crsminA_th; + crsminl_th = crsminlA_th; + crsminu_th = crsminuA_th; + nbclip_th = nbclipA_th; + rssi_gain = rssi_gain_default; + } + w1clip_th = w1clipA_th; + } + + write_radio_reg(pi, + (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC | + RADIO_2056_RX0), 0x17); + write_radio_reg(pi, + (RADIO_2056_RX_BIASPOLE_LNAG1_IDAC | + RADIO_2056_RX1), 0x17); + + write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX0), + 0xf0); + write_radio_reg(pi, (RADIO_2056_RX_LNAG2_IDAC | RADIO_2056_RX1), + 0xf0); + + write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX0), + 0x0); + write_radio_reg(pi, (RADIO_2056_RX_RSSI_POLE | RADIO_2056_RX1), + 0x0); + + write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX0), + rssi_gain); + write_radio_reg(pi, (RADIO_2056_RX_RSSI_GAIN | RADIO_2056_RX1), + rssi_gain); + + write_radio_reg(pi, + (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC | + RADIO_2056_RX0), 0x17); + write_radio_reg(pi, + (RADIO_2056_RX_BIASPOLE_LNAA1_IDAC | + RADIO_2056_RX1), 0x17); + + write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX0), + 0xFF); + write_radio_reg(pi, (RADIO_2056_RX_LNAA2_IDAC | RADIO_2056_RX1), + 0xFF); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 8, + 8, lna1_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 8, + 8, lna1_gain_db); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 4, 0x10, + 8, lna2_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 4, 0x10, + 8, lna2_gain_db); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 10, 0x20, + 8, tia_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 10, 0x20, + 8, tia_gain_db); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 10, 0x20, + 8, tia_gainbits); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 10, 0x20, + 8, tia_gainbits); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN1, 6, 0x40, + 8, &lpf_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAIN2, 6, 0x40, + 8, &lpf_gain_db); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS1, 6, 0x40, + 8, &lpf_gainbits); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_GAINBITS2, 6, 0x40, + 8, &lpf_gainbits); + + write_phy_reg(pi, 0x20, init_gaincode); + write_phy_reg(pi, 0x2a7, init_gaincode); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, + pi->pubpi.phy_corenum, 0x106, 16, + rfseq_init_gain); + + write_phy_reg(pi, 0x22, clip1hi_gaincode); + write_phy_reg(pi, 0x2a9, clip1hi_gaincode); + + write_phy_reg(pi, 0x24, clip1md_gaincode); + write_phy_reg(pi, 0x2ab, clip1md_gaincode); + + write_phy_reg(pi, 0x37, clip1lo_gaincode); + write_phy_reg(pi, 0x2ad, clip1lo_gaincode); + + mod_phy_reg(pi, 0x27d, (0xff << 0), (crsmin_th << 0)); + mod_phy_reg(pi, 0x280, (0xff << 0), (crsminl_th << 0)); + mod_phy_reg(pi, 0x283, (0xff << 0), (crsminu_th << 0)); + + write_phy_reg(pi, 0x2b, nbclip_th); + write_phy_reg(pi, 0x41, nbclip_th); + + mod_phy_reg(pi, 0x27, (0x3f << 0), (w1clip_th << 0)); + mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1clip_th << 0)); + + write_phy_reg(pi, 0x150, 0x809c); + + } else { + + mod_phy_reg(pi, 0x1c, (0x1 << 13), (1 << 13)); + mod_phy_reg(pi, 0x32, (0x1 << 13), (1 << 13)); + + write_phy_reg(pi, 0x2b, 0x84); + write_phy_reg(pi, 0x41, 0x84); + + if (CHSPEC_IS20(pi->radio_chanspec)) { + write_phy_reg(pi, 0x6b, 0x2b); + write_phy_reg(pi, 0x6c, 0x2b); + write_phy_reg(pi, 0x6d, 0x9); + write_phy_reg(pi, 0x6e, 0x9); + } + + w1th = NPHY_RSSICAL_W1_TARGET - 4; + mod_phy_reg(pi, 0x27, (0x3f << 0), (w1th << 0)); + mod_phy_reg(pi, 0x3d, (0x3f << 0), (w1th << 0)); + + if (CHSPEC_IS20(pi->radio_chanspec)) { + mod_phy_reg(pi, 0x1c, (0x1f << 0), (0x1 << 0)); + mod_phy_reg(pi, 0x32, (0x1f << 0), (0x1 << 0)); + + mod_phy_reg(pi, 0x1d, (0x1f << 0), (0x1 << 0)); + mod_phy_reg(pi, 0x33, (0x1f << 0), (0x1 << 0)); + } + + write_phy_reg(pi, 0x150, 0x809c); + + if (pi->nphy_gain_boost) + if ((CHSPEC_IS2G(pi->radio_chanspec)) && + (CHSPEC_IS40(pi->radio_chanspec))) + hpf_code = 4; + else + hpf_code = 5; + else if (CHSPEC_IS40(pi->radio_chanspec)) + hpf_code = 6; + else + hpf_code = 7; + + mod_phy_reg(pi, 0x20, (0x1f << 7), (hpf_code << 7)); + mod_phy_reg(pi, 0x36, (0x1f << 7), (hpf_code << 7)); + + for (ctr = 0; ctr < 4; ctr++) + regval[ctr] = (hpf_code << 8) | 0x7c; + wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval); + + wlc_phy_adjust_lnagaintbl_nphy(pi); + + if (pi->nphy_elna_gain_config) { + regval[0] = 0; + regval[1] = 1; + regval[2] = 1; + regval[3] = 1; + wlc_phy_table_write_nphy(pi, 2, 4, 8, 16, regval); + wlc_phy_table_write_nphy(pi, 3, 4, 8, 16, regval); + + for (ctr = 0; ctr < 4; ctr++) + regval[ctr] = (hpf_code << 8) | 0x74; + wlc_phy_table_write_nphy(pi, 7, 4, 0x106, 16, regval); + } + + if (NREV_IS(pi->pubpi.phy_rev, 2)) { + for (ctr = 0; ctr < 21; ctr++) + regval[ctr] = 3 * ctr; + wlc_phy_table_write_nphy(pi, 0, 21, 32, 16, regval); + wlc_phy_table_write_nphy(pi, 1, 21, 32, 16, regval); + + for (ctr = 0; ctr < 21; ctr++) + regval[ctr] = (u16) ctr; + wlc_phy_table_write_nphy(pi, 2, 21, 32, 16, regval); + wlc_phy_table_write_nphy(pi, 3, 21, 32, 16, regval); + } + + wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_UPDATEGAINU, + rfseq_updategainu_events, + rfseq_updategainu_dlys, + sizeof(rfseq_updategainu_events) / + sizeof(rfseq_updategainu_events[0])); + + mod_phy_reg(pi, 0x153, (0xff << 8), (90 << 8)); + + if (CHSPEC_IS2G(pi->radio_chanspec)) + mod_phy_reg(pi, + (NPHY_TO_BPHY_OFF + BPHY_OPTIONAL_MODES), + 0x7f, 0x4); + } +} + +static void wlc_phy_workarounds_nphy(struct brcms_phy *pi) +{ + u8 rfseq_rx2tx_events[] = { + NPHY_RFSEQ_CMD_NOP, + NPHY_RFSEQ_CMD_RXG_FBW, + NPHY_RFSEQ_CMD_TR_SWITCH, + NPHY_RFSEQ_CMD_CLR_HIQ_DIS, + NPHY_RFSEQ_CMD_RXPD_TXPD, + NPHY_RFSEQ_CMD_TX_GAIN, + NPHY_RFSEQ_CMD_EXT_PA + }; + u8 rfseq_rx2tx_dlys[] = { 8, 6, 6, 2, 4, 60, 1 }; + u8 rfseq_tx2rx_events[] = { + NPHY_RFSEQ_CMD_NOP, + NPHY_RFSEQ_CMD_EXT_PA, + NPHY_RFSEQ_CMD_TX_GAIN, + NPHY_RFSEQ_CMD_RXPD_TXPD, + NPHY_RFSEQ_CMD_TR_SWITCH, + NPHY_RFSEQ_CMD_RXG_FBW, + NPHY_RFSEQ_CMD_CLR_HIQ_DIS + }; + u8 rfseq_tx2rx_dlys[] = { 8, 6, 2, 4, 4, 6, 1 }; + u8 rfseq_tx2rx_events_rev3[] = { + NPHY_REV3_RFSEQ_CMD_EXT_PA, + NPHY_REV3_RFSEQ_CMD_INT_PA_PU, + NPHY_REV3_RFSEQ_CMD_TX_GAIN, + NPHY_REV3_RFSEQ_CMD_RXPD_TXPD, + NPHY_REV3_RFSEQ_CMD_TR_SWITCH, + NPHY_REV3_RFSEQ_CMD_RXG_FBW, + NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS, + NPHY_REV3_RFSEQ_CMD_END + }; + u8 rfseq_tx2rx_dlys_rev3[] = { 8, 4, 2, 2, 4, 4, 6, 1 }; + u8 rfseq_rx2tx_events_rev3[] = { + NPHY_REV3_RFSEQ_CMD_NOP, + NPHY_REV3_RFSEQ_CMD_RXG_FBW, + NPHY_REV3_RFSEQ_CMD_TR_SWITCH, + NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS, + NPHY_REV3_RFSEQ_CMD_RXPD_TXPD, + NPHY_REV3_RFSEQ_CMD_TX_GAIN, + NPHY_REV3_RFSEQ_CMD_INT_PA_PU, + NPHY_REV3_RFSEQ_CMD_EXT_PA, + NPHY_REV3_RFSEQ_CMD_END + }; + u8 rfseq_rx2tx_dlys_rev3[] = { 8, 6, 6, 4, 4, 18, 42, 1, 1 }; + + u8 rfseq_rx2tx_events_rev3_ipa[] = { + NPHY_REV3_RFSEQ_CMD_NOP, + NPHY_REV3_RFSEQ_CMD_RXG_FBW, + NPHY_REV3_RFSEQ_CMD_TR_SWITCH, + NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS, + NPHY_REV3_RFSEQ_CMD_RXPD_TXPD, + NPHY_REV3_RFSEQ_CMD_TX_GAIN, + NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS, + NPHY_REV3_RFSEQ_CMD_INT_PA_PU, + NPHY_REV3_RFSEQ_CMD_END + }; + u8 rfseq_rx2tx_dlys_rev3_ipa[] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 }; + u16 rfseq_rx2tx_dacbufpu_rev7[] = { 0x10f, 0x10f }; + + s16 alpha0, alpha1, alpha2; + s16 beta0, beta1, beta2; + u32 leg_data_weights, ht_data_weights, nss1_data_weights, + stbc_data_weights; + u8 chan_freq_range = 0; + u16 dac_control = 0x0002; + u16 aux_adc_vmid_rev7_core0[] = { 0x8e, 0x96, 0x96, 0x96 }; + u16 aux_adc_vmid_rev7_core1[] = { 0x8f, 0x9f, 0x9f, 0x96 }; + u16 aux_adc_vmid_rev4[] = { 0xa2, 0xb4, 0xb4, 0x89 }; + u16 aux_adc_vmid_rev3[] = { 0xa2, 0xb4, 0xb4, 0x89 }; + u16 *aux_adc_vmid; + u16 aux_adc_gain_rev7[] = { 0x02, 0x02, 0x02, 0x02 }; + u16 aux_adc_gain_rev4[] = { 0x02, 0x02, 0x02, 0x00 }; + u16 aux_adc_gain_rev3[] = { 0x02, 0x02, 0x02, 0x00 }; + u16 *aux_adc_gain; + u16 sk_adc_vmid[] = { 0xb4, 0xb4, 0xb4, 0x24 }; + u16 sk_adc_gain[] = { 0x02, 0x02, 0x02, 0x02 }; + s32 min_nvar_val = 0x18d; + s32 min_nvar_offset_6mbps = 20; + u8 pdetrange; + u8 triso; + u16 regval; + u16 afectrl_adc_ctrl1_rev7 = 0x20; + u16 afectrl_adc_ctrl2_rev7 = 0x0; + u16 rfseq_rx2tx_lpf_h_hpc_rev7 = 0x77; + u16 rfseq_tx2rx_lpf_h_hpc_rev7 = 0x77; + u16 rfseq_pktgn_lpf_h_hpc_rev7 = 0x77; + u16 rfseq_htpktgn_lpf_hpc_rev7[] = { 0x77, 0x11, 0x11 }; + u16 rfseq_pktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; + u16 rfseq_cckpktgn_lpf_hpc_rev7[] = { 0x11, 0x11 }; + u16 ipalvlshift_3p3_war_en = 0; + u16 rccal_bcap_val, rccal_scap_val; + u16 rccal_tx20_11b_bcap = 0; + u16 rccal_tx20_11b_scap = 0; + u16 rccal_tx20_11n_bcap = 0; + u16 rccal_tx20_11n_scap = 0; + u16 rccal_tx40_11n_bcap = 0; + u16 rccal_tx40_11n_scap = 0; + u16 rx2tx_lpf_rc_lut_tx20_11b = 0; + u16 rx2tx_lpf_rc_lut_tx20_11n = 0; + u16 rx2tx_lpf_rc_lut_tx40_11n = 0; + u16 tx_lpf_bw_ofdm_20mhz = 0; + u16 tx_lpf_bw_ofdm_40mhz = 0; + u16 tx_lpf_bw_11b = 0; + u16 ipa2g_mainbias, ipa2g_casconv, ipa2g_biasfilt; + u16 txgm_idac_bleed = 0; + bool rccal_ovrd = false; + u16 freq; + int coreNum; + + if (CHSPEC_IS5G(pi->radio_chanspec)) + wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_cck_en, 0); + else + wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_cck_en, 1); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + or_phy_reg(pi, 0xb1, NPHY_IQFlip_ADC1 | NPHY_IQFlip_ADC2); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + if (NREV_IS(pi->pubpi.phy_rev, 7)) { + mod_phy_reg(pi, 0x221, (0x1 << 4), (1 << 4)); + + mod_phy_reg(pi, 0x160, (0x7f << 0), (32 << 0)); + mod_phy_reg(pi, 0x160, (0x7f << 8), (39 << 8)); + mod_phy_reg(pi, 0x161, (0x7f << 0), (46 << 0)); + mod_phy_reg(pi, 0x161, (0x7f << 8), (51 << 8)); + mod_phy_reg(pi, 0x162, (0x7f << 0), (55 << 0)); + mod_phy_reg(pi, 0x162, (0x7f << 8), (58 << 8)); + mod_phy_reg(pi, 0x163, (0x7f << 0), (60 << 0)); + mod_phy_reg(pi, 0x163, (0x7f << 8), (62 << 8)); + mod_phy_reg(pi, 0x164, (0x7f << 0), (62 << 0)); + mod_phy_reg(pi, 0x164, (0x7f << 8), (63 << 8)); + mod_phy_reg(pi, 0x165, (0x7f << 0), (63 << 0)); + mod_phy_reg(pi, 0x165, (0x7f << 8), (64 << 8)); + mod_phy_reg(pi, 0x166, (0x7f << 0), (64 << 0)); + mod_phy_reg(pi, 0x166, (0x7f << 8), (64 << 8)); + mod_phy_reg(pi, 0x167, (0x7f << 0), (64 << 0)); + mod_phy_reg(pi, 0x167, (0x7f << 8), (64 << 8)); + } + + if (NREV_LE(pi->pubpi.phy_rev, 8)) { + write_phy_reg(pi, 0x23f, 0x1b0); + write_phy_reg(pi, 0x240, 0x1b0); + } + + if (NREV_GE(pi->pubpi.phy_rev, 8)) + mod_phy_reg(pi, 0xbd, (0xff << 0), (114 << 0)); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x00, 16, + &dac_control); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x10, 16, + &dac_control); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, + 1, 0, 32, &leg_data_weights); + leg_data_weights = leg_data_weights & 0xffffff; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, + 1, 0, 32, &leg_data_weights); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, + 2, 0x15e, 16, + rfseq_rx2tx_dacbufpu_rev7); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x16e, 16, + rfseq_rx2tx_dacbufpu_rev7); + + if (PHY_IPA(pi)) + wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, + rfseq_rx2tx_events_rev3_ipa, + rfseq_rx2tx_dlys_rev3_ipa, + sizeof + (rfseq_rx2tx_events_rev3_ipa) / + sizeof + (rfseq_rx2tx_events_rev3_ipa + [0])); + + mod_phy_reg(pi, 0x299, (0x3 << 14), (0x1 << 14)); + mod_phy_reg(pi, 0x29d, (0x3 << 14), (0x1 << 14)); + + tx_lpf_bw_ofdm_20mhz = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x154); + tx_lpf_bw_ofdm_40mhz = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x159); + tx_lpf_bw_11b = wlc_phy_read_lpf_bw_ctl_nphy(pi, 0x152); + + if (PHY_IPA(pi)) { + + if (((pi->pubpi.radiorev == 5) + && (CHSPEC_IS40(pi->radio_chanspec) == 1)) + || (pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) { + + rccal_bcap_val = + read_radio_reg( + pi, + RADIO_2057_RCCAL_BCAP_VAL); + rccal_scap_val = + read_radio_reg( + pi, + RADIO_2057_RCCAL_SCAP_VAL); + + rccal_tx20_11b_bcap = rccal_bcap_val; + rccal_tx20_11b_scap = rccal_scap_val; + + if ((pi->pubpi.radiorev == 5) && + (CHSPEC_IS40(pi->radio_chanspec) == 1)) { + + rccal_tx20_11n_bcap = rccal_bcap_val; + rccal_tx20_11n_scap = rccal_scap_val; + rccal_tx40_11n_bcap = 0xc; + rccal_tx40_11n_scap = 0xc; + + rccal_ovrd = true; + + } else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) { + + tx_lpf_bw_ofdm_20mhz = 4; + tx_lpf_bw_11b = 1; + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + rccal_tx20_11n_bcap = 0xc; + rccal_tx20_11n_scap = 0xc; + rccal_tx40_11n_bcap = 0xa; + rccal_tx40_11n_scap = 0xa; + } else { + rccal_tx20_11n_bcap = 0x14; + rccal_tx20_11n_scap = 0x14; + rccal_tx40_11n_bcap = 0xf; + rccal_tx40_11n_scap = 0xf; + } + + rccal_ovrd = true; + } + } + + } else { + + if (pi->pubpi.radiorev == 5) { + + tx_lpf_bw_ofdm_20mhz = 1; + tx_lpf_bw_ofdm_40mhz = 3; + + rccal_bcap_val = + read_radio_reg( + pi, + RADIO_2057_RCCAL_BCAP_VAL); + rccal_scap_val = + read_radio_reg( + pi, + RADIO_2057_RCCAL_SCAP_VAL); + + rccal_tx20_11b_bcap = rccal_bcap_val; + rccal_tx20_11b_scap = rccal_scap_val; + + rccal_tx20_11n_bcap = 0x13; + rccal_tx20_11n_scap = 0x11; + rccal_tx40_11n_bcap = 0x13; + rccal_tx40_11n_scap = 0x11; + + rccal_ovrd = true; + } + } + + if (rccal_ovrd) { + + rx2tx_lpf_rc_lut_tx20_11b = + (rccal_tx20_11b_bcap << 8) | + (rccal_tx20_11b_scap << 3) | + tx_lpf_bw_11b; + rx2tx_lpf_rc_lut_tx20_11n = + (rccal_tx20_11n_bcap << 8) | + (rccal_tx20_11n_scap << 3) | + tx_lpf_bw_ofdm_20mhz; + rx2tx_lpf_rc_lut_tx40_11n = + (rccal_tx40_11n_bcap << 8) | + (rccal_tx40_11n_scap << 3) | + tx_lpf_bw_ofdm_40mhz; + + for (coreNum = 0; coreNum <= 1; coreNum++) { + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_RFSEQ, + 1, + 0x152 + coreNum * 0x10, + 16, + &rx2tx_lpf_rc_lut_tx20_11b); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_RFSEQ, + 1, + 0x153 + coreNum * 0x10, + 16, + &rx2tx_lpf_rc_lut_tx20_11n); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_RFSEQ, + 1, + 0x154 + coreNum * 0x10, + 16, + &rx2tx_lpf_rc_lut_tx20_11n); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_RFSEQ, + 1, + 0x155 + coreNum * 0x10, + 16, + &rx2tx_lpf_rc_lut_tx40_11n); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_RFSEQ, + 1, + 0x156 + coreNum * 0x10, + 16, + &rx2tx_lpf_rc_lut_tx40_11n); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_RFSEQ, + 1, + 0x157 + coreNum * 0x10, + 16, + &rx2tx_lpf_rc_lut_tx40_11n); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_RFSEQ, + 1, + 0x158 + coreNum * 0x10, + 16, + &rx2tx_lpf_rc_lut_tx40_11n); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_RFSEQ, + 1, + 0x159 + coreNum * 0x10, + 16, + &rx2tx_lpf_rc_lut_tx40_11n); + } + + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 4), + 1, 0x3, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + } + + write_phy_reg(pi, 0x32f, 0x3); + + if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6)) + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 2), + 1, 0x3, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + + if ((pi->pubpi.radiorev == 3) || (pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) { + if ((pi->sh->sromrev >= 8) + && (pi->sh->boardflags2 & BFL2_IPALVLSHIFT_3P3)) + ipalvlshift_3p3_war_en = 1; + + if (ipalvlshift_3p3_war_en) { + write_radio_reg(pi, RADIO_2057_GPAIO_CONFIG, + 0x5); + write_radio_reg(pi, RADIO_2057_GPAIO_SEL1, + 0x30); + write_radio_reg(pi, RADIO_2057_GPAIO_SEL0, 0x0); + or_radio_reg(pi, + RADIO_2057_RXTXBIAS_CONFIG_CORE0, + 0x1); + or_radio_reg(pi, + RADIO_2057_RXTXBIAS_CONFIG_CORE1, + 0x1); + + ipa2g_mainbias = 0x1f; + + ipa2g_casconv = 0x6f; + + ipa2g_biasfilt = 0xaa; + } else { + + ipa2g_mainbias = 0x2b; + + ipa2g_casconv = 0x7f; + + ipa2g_biasfilt = 0xee; + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + for (coreNum = 0; coreNum <= 1; coreNum++) { + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, + coreNum, IPA2G_IMAIN, + ipa2g_mainbias); + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, + coreNum, IPA2G_CASCONV, + ipa2g_casconv); + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, + coreNum, + IPA2G_BIAS_FILTER, + ipa2g_biasfilt); + } + } + } + + if (PHY_IPA(pi)) { + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if ((pi->pubpi.radiorev == 3) + || (pi->pubpi.radiorev == 4) + || (pi->pubpi.radiorev == 6)) + txgm_idac_bleed = 0x7f; + + for (coreNum = 0; coreNum <= 1; coreNum++) { + if (txgm_idac_bleed != 0) + WRITE_RADIO_REG4( + pi, RADIO_2057, + CORE, coreNum, + TXGM_IDAC_BLEED, + txgm_idac_bleed); + } + + if (pi->pubpi.radiorev == 5) { + + for (coreNum = 0; coreNum <= 1; + coreNum++) { + WRITE_RADIO_REG4(pi, RADIO_2057, + CORE, coreNum, + IPA2G_CASCONV, + 0x13); + WRITE_RADIO_REG4(pi, RADIO_2057, + CORE, coreNum, + IPA2G_IMAIN, + 0x1f); + WRITE_RADIO_REG4( + pi, RADIO_2057, + CORE, coreNum, + IPA2G_BIAS_FILTER, + 0xee); + WRITE_RADIO_REG4(pi, RADIO_2057, + CORE, coreNum, + PAD2G_IDACS, + 0x8a); + WRITE_RADIO_REG4( + pi, RADIO_2057, + CORE, coreNum, + PAD_BIAS_FILTER_BWS, + 0x3e); + } + + } else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) { + + if (CHSPEC_IS40(pi->radio_chanspec) == + 0) { + WRITE_RADIO_REG4(pi, RADIO_2057, + CORE, 0, + IPA2G_IMAIN, + 0x14); + WRITE_RADIO_REG4(pi, RADIO_2057, + CORE, 1, + IPA2G_IMAIN, + 0x12); + } else { + WRITE_RADIO_REG4(pi, RADIO_2057, + CORE, 0, + IPA2G_IMAIN, + 0x16); + WRITE_RADIO_REG4(pi, RADIO_2057, + CORE, 1, + IPA2G_IMAIN, + 0x16); + } + } + + } else { + freq = CHAN5G_FREQ(CHSPEC_CHANNEL( + pi->radio_chanspec)); + if (((freq >= 5180) && (freq <= 5230)) + || ((freq >= 5745) && (freq <= 5805))) { + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, + 0, IPA5G_BIAS_FILTER, + 0xff); + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, + 1, IPA5G_BIAS_FILTER, + 0xff); + } + } + } else { + + if (pi->pubpi.radiorev != 5) { + for (coreNum = 0; coreNum <= 1; coreNum++) { + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, + coreNum, + TXMIX2G_TUNE_BOOST_PU, + 0x61); + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, + coreNum, + TXGM_IDAC_BLEED, 0x70); + } + } + } + + if (pi->pubpi.radiorev == 4) { + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, + 0x05, 16, + &afectrl_adc_ctrl1_rev7); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, + 0x15, 16, + &afectrl_adc_ctrl1_rev7); + + for (coreNum = 0; coreNum <= 1; coreNum++) { + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, + AFE_VCM_CAL_MASTER, 0x0); + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, + AFE_SET_VCM_I, 0x3f); + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, + AFE_SET_VCM_Q, 0x3f); + } + } else { + mod_phy_reg(pi, 0xa6, (0x1 << 2), (0x1 << 2)); + mod_phy_reg(pi, 0x8f, (0x1 << 2), (0x1 << 2)); + mod_phy_reg(pi, 0xa7, (0x1 << 2), (0x1 << 2)); + mod_phy_reg(pi, 0xa5, (0x1 << 2), (0x1 << 2)); + + mod_phy_reg(pi, 0xa6, (0x1 << 0), 0); + mod_phy_reg(pi, 0x8f, (0x1 << 0), (0x1 << 0)); + mod_phy_reg(pi, 0xa7, (0x1 << 0), 0); + mod_phy_reg(pi, 0xa5, (0x1 << 0), (0x1 << 0)); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, + 0x05, 16, + &afectrl_adc_ctrl2_rev7); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, + 0x15, 16, + &afectrl_adc_ctrl2_rev7); + + mod_phy_reg(pi, 0xa6, (0x1 << 2), 0); + mod_phy_reg(pi, 0x8f, (0x1 << 2), 0); + mod_phy_reg(pi, 0xa7, (0x1 << 2), 0); + mod_phy_reg(pi, 0xa5, (0x1 << 2), 0); + } + + write_phy_reg(pi, 0x6a, 0x2); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 256, 32, + &min_nvar_offset_6mbps); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x138, 16, + &rfseq_pktgn_lpf_hpc_rev7); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x141, 16, + &rfseq_pktgn_lpf_h_hpc_rev7); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 3, 0x133, 16, + &rfseq_htpktgn_lpf_hpc_rev7); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x146, 16, + &rfseq_cckpktgn_lpf_hpc_rev7); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x123, 16, + &rfseq_tx2rx_lpf_h_hpc_rev7); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 1, 0x12A, 16, + &rfseq_rx2tx_lpf_h_hpc_rev7); + + if (CHSPEC_IS40(pi->radio_chanspec) == 0) { + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3, + 32, &min_nvar_val); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, + 127, 32, &min_nvar_val); + } else { + min_nvar_val = noise_var_tbl_rev7[3]; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3, + 32, &min_nvar_val); + + min_nvar_val = noise_var_tbl_rev7[127]; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, + 127, 32, &min_nvar_val); + } + + wlc_phy_workarounds_nphy_gainctrl(pi); + + pdetrange = + (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g. + pdetrange : pi->srom_fem2g.pdetrange; + + if (pdetrange == 0) { + chan_freq_range = + wlc_phy_get_chan_freq_range_nphy(pi, 0); + if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { + aux_adc_vmid_rev7_core0[3] = 0x70; + aux_adc_vmid_rev7_core1[3] = 0x70; + aux_adc_gain_rev7[3] = 2; + } else { + aux_adc_vmid_rev7_core0[3] = 0x80; + aux_adc_vmid_rev7_core1[3] = 0x80; + aux_adc_gain_rev7[3] = 3; + } + } else if (pdetrange == 1) { + if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { + aux_adc_vmid_rev7_core0[3] = 0x7c; + aux_adc_vmid_rev7_core1[3] = 0x7c; + aux_adc_gain_rev7[3] = 2; + } else { + aux_adc_vmid_rev7_core0[3] = 0x8c; + aux_adc_vmid_rev7_core1[3] = 0x8c; + aux_adc_gain_rev7[3] = 1; + } + } else if (pdetrange == 2) { + if (pi->pubpi.radioid == BCM2057_ID) { + if ((pi->pubpi.radiorev == 5) + || (pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) { + if (chan_freq_range == + WL_CHAN_FREQ_RANGE_2G) { + aux_adc_vmid_rev7_core0[3] = + 0x8c; + aux_adc_vmid_rev7_core1[3] = + 0x8c; + aux_adc_gain_rev7[3] = 0; + } else { + aux_adc_vmid_rev7_core0[3] = + 0x96; + aux_adc_vmid_rev7_core1[3] = + 0x96; + aux_adc_gain_rev7[3] = 0; + } + } + } + + } else if (pdetrange == 3) { + if (chan_freq_range == WL_CHAN_FREQ_RANGE_2G) { + aux_adc_vmid_rev7_core0[3] = 0x89; + aux_adc_vmid_rev7_core1[3] = 0x89; + aux_adc_gain_rev7[3] = 0; + } + + } else if (pdetrange == 5) { + + if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { + aux_adc_vmid_rev7_core0[3] = 0x80; + aux_adc_vmid_rev7_core1[3] = 0x80; + aux_adc_gain_rev7[3] = 3; + } else { + aux_adc_vmid_rev7_core0[3] = 0x70; + aux_adc_vmid_rev7_core1[3] = 0x70; + aux_adc_gain_rev7[3] = 2; + } + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x08, 16, + &aux_adc_vmid_rev7_core0); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x18, 16, + &aux_adc_vmid_rev7_core1); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x0c, 16, + &aux_adc_gain_rev7); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, 0x1c, 16, + &aux_adc_gain_rev7); + + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + write_phy_reg(pi, 0x23f, 0x1f8); + write_phy_reg(pi, 0x240, 0x1f8); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, + 1, 0, 32, &leg_data_weights); + leg_data_weights = leg_data_weights & 0xffffff; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, + 1, 0, 32, &leg_data_weights); + + alpha0 = 293; + alpha1 = 435; + alpha2 = 261; + beta0 = 366; + beta1 = 205; + beta2 = 32; + write_phy_reg(pi, 0x145, alpha0); + write_phy_reg(pi, 0x146, alpha1); + write_phy_reg(pi, 0x147, alpha2); + write_phy_reg(pi, 0x148, beta0); + write_phy_reg(pi, 0x149, beta1); + write_phy_reg(pi, 0x14a, beta2); + + write_phy_reg(pi, 0x38, 0xC); + write_phy_reg(pi, 0x2ae, 0xC); + + wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX, + rfseq_tx2rx_events_rev3, + rfseq_tx2rx_dlys_rev3, + sizeof(rfseq_tx2rx_events_rev3) / + sizeof(rfseq_tx2rx_events_rev3[0])); + + if (PHY_IPA(pi)) + wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, + rfseq_rx2tx_events_rev3_ipa, + rfseq_rx2tx_dlys_rev3_ipa, + sizeof + (rfseq_rx2tx_events_rev3_ipa) / + sizeof + (rfseq_rx2tx_events_rev3_ipa + [0])); + + if ((pi->sh->hw_phyrxchain != 0x3) && + (pi->sh->hw_phyrxchain != pi->sh->hw_phytxchain)) { + + if (PHY_IPA(pi)) { + rfseq_rx2tx_dlys_rev3[5] = 59; + rfseq_rx2tx_dlys_rev3[6] = 1; + rfseq_rx2tx_events_rev3[7] = + NPHY_REV3_RFSEQ_CMD_END; + } + + wlc_phy_set_rfseq_nphy( + pi, NPHY_RFSEQ_RX2TX, + rfseq_rx2tx_events_rev3, + rfseq_rx2tx_dlys_rev3, + sizeof(rfseq_rx2tx_events_rev3) / + sizeof(rfseq_rx2tx_events_rev3[0])); + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) + write_phy_reg(pi, 0x6a, 0x2); + else + write_phy_reg(pi, 0x6a, 0x9c40); + + mod_phy_reg(pi, 0x294, (0xf << 8), (7 << 8)); + + if (CHSPEC_IS40(pi->radio_chanspec) == 0) { + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3, + 32, &min_nvar_val); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, + 127, 32, &min_nvar_val); + } else { + min_nvar_val = noise_var_tbl_rev3[3]; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, 3, + 32, &min_nvar_val); + + min_nvar_val = noise_var_tbl_rev3[127]; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, + 127, 32, &min_nvar_val); + } + + wlc_phy_workarounds_nphy_gainctrl(pi); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x00, 16, + &dac_control); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x10, 16, + &dac_control); + + pdetrange = + (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g. + pdetrange : pi->srom_fem2g.pdetrange; + + if (pdetrange == 0) { + if (NREV_GE(pi->pubpi.phy_rev, 4)) { + aux_adc_vmid = aux_adc_vmid_rev4; + aux_adc_gain = aux_adc_gain_rev4; + } else { + aux_adc_vmid = aux_adc_vmid_rev3; + aux_adc_gain = aux_adc_gain_rev3; + } + chan_freq_range = + wlc_phy_get_chan_freq_range_nphy(pi, 0); + if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { + switch (chan_freq_range) { + case WL_CHAN_FREQ_RANGE_5GL: + aux_adc_vmid[3] = 0x89; + aux_adc_gain[3] = 0; + break; + case WL_CHAN_FREQ_RANGE_5GM: + aux_adc_vmid[3] = 0x89; + aux_adc_gain[3] = 0; + break; + case WL_CHAN_FREQ_RANGE_5GH: + aux_adc_vmid[3] = 0x89; + aux_adc_gain[3] = 0; + break; + default: + break; + } + } + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x08, 16, aux_adc_vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x18, 16, aux_adc_vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x0c, 16, aux_adc_gain); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x1c, 16, aux_adc_gain); + } else if (pdetrange == 1) { + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x08, 16, sk_adc_vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x18, 16, sk_adc_vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x0c, 16, sk_adc_gain); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x1c, 16, sk_adc_gain); + } else if (pdetrange == 2) { + + u16 bcm_adc_vmid[] = { 0xa2, 0xb4, 0xb4, 0x74 }; + u16 bcm_adc_gain[] = { 0x02, 0x02, 0x02, 0x04 }; + + if (NREV_GE(pi->pubpi.phy_rev, 6)) { + chan_freq_range = + wlc_phy_get_chan_freq_range_nphy(pi, 0); + if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { + bcm_adc_vmid[3] = 0x8e; + bcm_adc_gain[3] = 0x03; + } else { + bcm_adc_vmid[3] = 0x94; + bcm_adc_gain[3] = 0x03; + } + } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { + bcm_adc_vmid[3] = 0x84; + bcm_adc_gain[3] = 0x02; + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x08, 16, bcm_adc_vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x18, 16, bcm_adc_vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x0c, 16, bcm_adc_gain); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x1c, 16, bcm_adc_gain); + } else if (pdetrange == 3) { + chan_freq_range = + wlc_phy_get_chan_freq_range_nphy(pi, 0); + if ((NREV_GE(pi->pubpi.phy_rev, 4)) + && (chan_freq_range == WL_CHAN_FREQ_RANGE_2G)) { + + u16 auxadc_vmid[] = { + 0xa2, 0xb4, 0xb4, 0x270 + }; + u16 auxadc_gain[] = { + 0x02, 0x02, 0x02, 0x00 + }; + + wlc_phy_table_write_nphy(pi, + NPHY_TBL_ID_AFECTRL, 4, + 0x08, 16, auxadc_vmid); + wlc_phy_table_write_nphy(pi, + NPHY_TBL_ID_AFECTRL, 4, + 0x18, 16, auxadc_vmid); + wlc_phy_table_write_nphy(pi, + NPHY_TBL_ID_AFECTRL, 4, + 0x0c, 16, auxadc_gain); + wlc_phy_table_write_nphy(pi, + NPHY_TBL_ID_AFECTRL, 4, + 0x1c, 16, auxadc_gain); + } + } else if ((pdetrange == 4) || (pdetrange == 5)) { + u16 bcm_adc_vmid[] = { 0xa2, 0xb4, 0xb4, 0x0 }; + u16 bcm_adc_gain[] = { 0x02, 0x02, 0x02, 0x0 }; + u16 Vmid[2], Av[2]; + + chan_freq_range = + wlc_phy_get_chan_freq_range_nphy(pi, 0); + if (chan_freq_range != WL_CHAN_FREQ_RANGE_2G) { + Vmid[0] = (pdetrange == 4) ? 0x8e : 0x89; + Vmid[1] = (pdetrange == 4) ? 0x96 : 0x89; + Av[0] = (pdetrange == 4) ? 2 : 0; + Av[1] = (pdetrange == 4) ? 2 : 0; + } else { + Vmid[0] = (pdetrange == 4) ? 0x89 : 0x74; + Vmid[1] = (pdetrange == 4) ? 0x8b : 0x70; + Av[0] = (pdetrange == 4) ? 2 : 0; + Av[1] = (pdetrange == 4) ? 2 : 0; + } + + bcm_adc_vmid[3] = Vmid[0]; + bcm_adc_gain[3] = Av[0]; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x08, 16, bcm_adc_vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x0c, 16, bcm_adc_gain); + + bcm_adc_vmid[3] = Vmid[1]; + bcm_adc_gain[3] = Av[1]; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x18, 16, bcm_adc_vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 4, + 0x1c, 16, bcm_adc_gain); + } + + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_MAST_BIAS | RADIO_2056_RX0), + 0x0); + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_MAST_BIAS | RADIO_2056_RX1), + 0x0); + + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_BIAS_MAIN | RADIO_2056_RX0), + 0x6); + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_BIAS_MAIN | RADIO_2056_RX1), + 0x6); + + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_BIAS_AUX | RADIO_2056_RX0), + 0x7); + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_BIAS_AUX | RADIO_2056_RX1), + 0x7); + + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_LOB_BIAS | RADIO_2056_RX0), + 0x88); + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_LOB_BIAS | RADIO_2056_RX1), + 0x88); + + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_CMFB_IDAC | RADIO_2056_RX0), + 0x0); + write_radio_reg(pi, + (RADIO_2056_RX_MIXA_CMFB_IDAC | RADIO_2056_RX1), + 0x0); + + write_radio_reg(pi, + (RADIO_2056_RX_MIXG_CMFB_IDAC | RADIO_2056_RX0), + 0x0); + write_radio_reg(pi, + (RADIO_2056_RX_MIXG_CMFB_IDAC | RADIO_2056_RX1), + 0x0); + + triso = + (CHSPEC_IS5G(pi->radio_chanspec)) ? pi->srom_fem5g. + triso : pi->srom_fem2g.triso; + if (triso == 7) { + wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_0); + wlc_phy_war_force_trsw_to_R_cliplo_nphy(pi, PHY_CORE_1); + } + + wlc_phy_war_txchain_upd_nphy(pi, pi->sh->hw_phytxchain); + + if (((pi->sh->boardflags2 & BFL2_APLL_WAR) && + (CHSPEC_IS5G(pi->radio_chanspec))) || + (((pi->sh->boardflags2 & BFL2_GPLL_WAR) || + (pi->sh->boardflags2 & BFL2_GPLL_WAR2)) && + (CHSPEC_IS2G(pi->radio_chanspec)))) { + nss1_data_weights = 0x00088888; + ht_data_weights = 0x00088888; + stbc_data_weights = 0x00088888; + } else { + nss1_data_weights = 0x88888888; + ht_data_weights = 0x88888888; + stbc_data_weights = 0x88888888; + } + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, + 1, 1, 32, &nss1_data_weights); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, + 1, 2, 32, &ht_data_weights); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL, + 1, 3, 32, &stbc_data_weights); + + if (NREV_IS(pi->pubpi.phy_rev, 4)) { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + write_radio_reg(pi, + RADIO_2056_TX_GMBB_IDAC | + RADIO_2056_TX0, 0x70); + write_radio_reg(pi, + RADIO_2056_TX_GMBB_IDAC | + RADIO_2056_TX1, 0x70); + } + } + + if (!pi->edcrs_threshold_lock) { + write_phy_reg(pi, 0x224, 0x3eb); + write_phy_reg(pi, 0x225, 0x3eb); + write_phy_reg(pi, 0x226, 0x341); + write_phy_reg(pi, 0x227, 0x341); + write_phy_reg(pi, 0x228, 0x42b); + write_phy_reg(pi, 0x229, 0x42b); + write_phy_reg(pi, 0x22a, 0x381); + write_phy_reg(pi, 0x22b, 0x381); + write_phy_reg(pi, 0x22c, 0x42b); + write_phy_reg(pi, 0x22d, 0x42b); + write_phy_reg(pi, 0x22e, 0x381); + write_phy_reg(pi, 0x22f, 0x381); + } + + if (NREV_GE(pi->pubpi.phy_rev, 6)) { + + if (pi->sh->boardflags2 & BFL2_SINGLEANT_CCK) + wlapi_bmac_mhf(pi->sh->physhim, MHF4, + MHF4_BPHY_TXCORE0, + MHF4_BPHY_TXCORE0, BRCM_BAND_ALL); + } + } else { + + if (pi->sh->boardflags2 & BFL2_SKWRKFEM_BRD || + (pi->sh->boardtype == 0x8b)) { + uint i; + u8 war_dlys[] = { 1, 6, 6, 2, 4, 20, 1 }; + for (i = 0; i < ARRAY_SIZE(rfseq_rx2tx_dlys); i++) + rfseq_rx2tx_dlys[i] = war_dlys[i]; + } + + if (CHSPEC_IS5G(pi->radio_chanspec) && pi->phy_5g_pwrgain) { + and_radio_reg(pi, RADIO_2055_CORE1_TX_RF_SPARE, 0xf7); + and_radio_reg(pi, RADIO_2055_CORE2_TX_RF_SPARE, 0xf7); + } else { + or_radio_reg(pi, RADIO_2055_CORE1_TX_RF_SPARE, 0x8); + or_radio_reg(pi, RADIO_2055_CORE2_TX_RF_SPARE, 0x8); + } + + regval = 0x000a; + wlc_phy_table_write_nphy(pi, 8, 1, 0, 16, ®val); + wlc_phy_table_write_nphy(pi, 8, 1, 0x10, 16, ®val); + + if (NREV_LT(pi->pubpi.phy_rev, 3)) { + regval = 0xcdaa; + wlc_phy_table_write_nphy(pi, 8, 1, 0x02, 16, ®val); + wlc_phy_table_write_nphy(pi, 8, 1, 0x12, 16, ®val); + } + + if (NREV_LT(pi->pubpi.phy_rev, 2)) { + regval = 0x0000; + wlc_phy_table_write_nphy(pi, 8, 1, 0x08, 16, ®val); + wlc_phy_table_write_nphy(pi, 8, 1, 0x18, 16, ®val); + + regval = 0x7aab; + wlc_phy_table_write_nphy(pi, 8, 1, 0x07, 16, ®val); + wlc_phy_table_write_nphy(pi, 8, 1, 0x17, 16, ®val); + + regval = 0x0800; + wlc_phy_table_write_nphy(pi, 8, 1, 0x06, 16, ®val); + wlc_phy_table_write_nphy(pi, 8, 1, 0x16, 16, ®val); + } + + write_phy_reg(pi, 0xf8, 0x02d8); + write_phy_reg(pi, 0xf9, 0x0301); + write_phy_reg(pi, 0xfa, 0x02d8); + write_phy_reg(pi, 0xfb, 0x0301); + + wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX, rfseq_rx2tx_events, + rfseq_rx2tx_dlys, + sizeof(rfseq_rx2tx_events) / + sizeof(rfseq_rx2tx_events[0])); + + wlc_phy_set_rfseq_nphy(pi, NPHY_RFSEQ_TX2RX, rfseq_tx2rx_events, + rfseq_tx2rx_dlys, + sizeof(rfseq_tx2rx_events) / + sizeof(rfseq_tx2rx_events[0])); + + wlc_phy_workarounds_nphy_gainctrl(pi); + + if (NREV_LT(pi->pubpi.phy_rev, 2)) { + + if (read_phy_reg(pi, 0xa0) & NPHY_MLenable) + wlapi_bmac_mhf(pi->sh->physhim, MHF3, + MHF3_NPHY_MLADV_WAR, + MHF3_NPHY_MLADV_WAR, + BRCM_BAND_ALL); + + } else if (NREV_IS(pi->pubpi.phy_rev, 2)) { + write_phy_reg(pi, 0x1e3, 0x0); + write_phy_reg(pi, 0x1e4, 0x0); + } + + if (NREV_LT(pi->pubpi.phy_rev, 2)) + mod_phy_reg(pi, 0x90, (0x1 << 7), 0); + + alpha0 = 293; + alpha1 = 435; + alpha2 = 261; + beta0 = 366; + beta1 = 205; + beta2 = 32; + write_phy_reg(pi, 0x145, alpha0); + write_phy_reg(pi, 0x146, alpha1); + write_phy_reg(pi, 0x147, alpha2); + write_phy_reg(pi, 0x148, beta0); + write_phy_reg(pi, 0x149, beta1); + write_phy_reg(pi, 0x14a, beta2); + + if (NREV_LT(pi->pubpi.phy_rev, 3)) { + mod_phy_reg(pi, 0x142, (0xf << 12), 0); + + write_phy_reg(pi, 0x192, 0xb5); + write_phy_reg(pi, 0x193, 0xa4); + write_phy_reg(pi, 0x194, 0x0); + } + + if (NREV_IS(pi->pubpi.phy_rev, 2)) + mod_phy_reg(pi, 0x221, + NPHY_FORCESIG_DECODEGATEDCLKS, + NPHY_FORCESIG_DECODEGATEDCLKS); + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static void wlc_phy_extpa_set_tx_digi_filts_nphy(struct brcms_phy *pi) +{ + int j, type = 2; + u16 addr_offset = 0x2c5; + + for (j = 0; j < NPHY_NUM_DIG_FILT_COEFFS; j++) + write_phy_reg(pi, addr_offset + j, + NPHY_IPA_REV4_txdigi_filtcoeffs[type][j]); +} + +static void wlc_phy_clip_det_nphy(struct brcms_phy *pi, u8 write, u16 *vals) +{ + + if (write == 0) { + vals[0] = read_phy_reg(pi, 0x2c); + vals[1] = read_phy_reg(pi, 0x42); + } else { + write_phy_reg(pi, 0x2c, vals[0]); + write_phy_reg(pi, 0x42, vals[1]); + } +} + +static void wlc_phy_ipa_internal_tssi_setup_nphy(struct brcms_phy *pi) +{ + u8 core; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + if (CHSPEC_IS2G(pi->radio_chanspec)) { + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MASTER, 0x5); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MUX, 0xe); + + if (pi->pubpi.radiorev != 5) + WRITE_RADIO_REG3(pi, RADIO_2057, TX, + core, TSSIA, 0); + + if (!NREV_IS(pi->pubpi.phy_rev, 7)) + WRITE_RADIO_REG3(pi, RADIO_2057, TX, + core, TSSIG, 0x1); + else + WRITE_RADIO_REG3(pi, RADIO_2057, TX, + core, TSSIG, 0x31); + } else { + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MASTER, 0x9); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MUX, 0xc); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSIG, 0); + + if (pi->pubpi.radiorev != 5) { + if (!NREV_IS(pi->pubpi.phy_rev, 7)) + WRITE_RADIO_REG3(pi, RADIO_2057, + TX, core, + TSSIA, 0x1); + else + WRITE_RADIO_REG3(pi, RADIO_2057, + TX, core, + TSSIA, 0x31); + } + } + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_VCM_HG, + 0); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_IDAC, + 0); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM, + 0x3); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_MISC1, + 0x0); + } + } else { + WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR31, + (CHSPEC_IS2G(pi->radio_chanspec)) ? 0x128 : + 0x80); + WRITE_RADIO_SYN(pi, RADIO_2056, RESERVED_ADDR30, 0x0); + WRITE_RADIO_SYN(pi, RADIO_2056, GPIO_MASTER1, 0x29); + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_VCM_HG, + 0x0); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, IQCAL_IDAC, + 0x0); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_VCM, + 0x3); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TX_AMP_DET, + 0x0); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC1, + 0x8); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC2, + 0x0); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, TSSI_MISC3, + 0x0); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + TX_SSI_MASTER, 0x5); + + if (pi->pubpi.radiorev != 5) + WRITE_RADIO_REG2(pi, RADIO_2056, TX, + core, TSSIA, 0x0); + if (NREV_GE(pi->pubpi.phy_rev, 5)) + WRITE_RADIO_REG2(pi, RADIO_2056, TX, + core, TSSIG, 0x31); + else + WRITE_RADIO_REG2(pi, RADIO_2056, TX, + core, TSSIG, 0x11); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + TX_SSI_MUX, 0xe); + } else { + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + TX_SSI_MASTER, 0x9); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + TSSIA, 0x31); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + TSSIG, 0x0); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + TX_SSI_MUX, 0xc); + } + } + } +} + +static void +wlc_phy_rfctrl_override_nphy(struct brcms_phy *pi, u16 field, u16 value, + u8 core_mask, u8 off) +{ + u8 core_num; + u16 addr = 0, mask = 0, en_addr = 0, val_addr = 0, en_mask = + 0, val_mask = 0; + u8 shift = 0, val_shift = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) { + + en_mask = field; + for (core_num = 0; core_num < 2; core_num++) { + + switch (field) { + case (0x1 << 1): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x1 << 0); + val_shift = 0; + break; + case (0x1 << 2): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x1 << 1); + val_shift = 1; + break; + case (0x1 << 3): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x1 << 2); + val_shift = 2; + break; + case (0x1 << 4): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x1 << 4); + val_shift = 4; + break; + case (0x1 << 5): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x1 << 5); + val_shift = 5; + break; + case (0x1 << 6): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x1 << 6); + val_shift = 6; + break; + case (0x1 << 7): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x1 << 7); + val_shift = 7; + break; + case (0x1 << 8): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x7 << 8); + val_shift = 8; + break; + case (0x1 << 11): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7a : 0x7d; + val_mask = (0x7 << 13); + val_shift = 13; + break; + + case (0x1 << 9): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0xf8 : 0xfa; + val_mask = (0x7 << 0); + val_shift = 0; + break; + + case (0x1 << 10): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0xf8 : 0xfa; + val_mask = (0x7 << 4); + val_shift = 4; + break; + + case (0x1 << 12): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7b : 0x7e; + val_mask = (0xffff << 0); + val_shift = 0; + break; + case (0x1 << 13): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0x7c : 0x7f; + val_mask = (0xffff << 0); + val_shift = 0; + break; + case (0x1 << 14): + en_addr = (core_num == 0) ? 0xe7 : 0xec; + val_addr = (core_num == 0) ? 0xf9 : 0xfb; + val_mask = (0x3 << 6); + val_shift = 6; + break; + case (0x1 << 0): + en_addr = (core_num == 0) ? 0xe5 : 0xe6; + val_addr = (core_num == 0) ? 0xf9 : 0xfb; + val_mask = (0x1 << 15); + val_shift = 15; + break; + default: + addr = 0xffff; + break; + } + + if (off) { + and_phy_reg(pi, en_addr, ~en_mask); + and_phy_reg(pi, val_addr, ~val_mask); + } else { + + if ((core_mask == 0) + || (core_mask & (1 << core_num))) { + or_phy_reg(pi, en_addr, en_mask); + + if (addr != 0xffff) + mod_phy_reg(pi, val_addr, + val_mask, + (value << + val_shift)); + } + } + } + } else { + + if (off) { + and_phy_reg(pi, 0xec, ~field); + value = 0x0; + } else { + or_phy_reg(pi, 0xec, field); + } + + for (core_num = 0; core_num < 2; core_num++) { + + switch (field) { + case (0x1 << 1): + case (0x1 << 9): + case (0x1 << 12): + case (0x1 << 13): + case (0x1 << 14): + addr = 0x78; + + core_mask = 0x1; + break; + case (0x1 << 2): + case (0x1 << 3): + case (0x1 << 4): + case (0x1 << 5): + case (0x1 << 6): + case (0x1 << 7): + case (0x1 << 8): + addr = (core_num == 0) ? 0x7a : 0x7d; + break; + case (0x1 << 10): + addr = (core_num == 0) ? 0x7b : 0x7e; + break; + case (0x1 << 11): + addr = (core_num == 0) ? 0x7c : 0x7f; + break; + default: + addr = 0xffff; + } + + switch (field) { + case (0x1 << 1): + mask = (0x7 << 3); + shift = 3; + break; + case (0x1 << 9): + mask = (0x1 << 2); + shift = 2; + break; + case (0x1 << 12): + mask = (0x1 << 8); + shift = 8; + break; + case (0x1 << 13): + mask = (0x1 << 9); + shift = 9; + break; + case (0x1 << 14): + mask = (0xf << 12); + shift = 12; + break; + case (0x1 << 2): + mask = (0x1 << 0); + shift = 0; + break; + case (0x1 << 3): + mask = (0x1 << 1); + shift = 1; + break; + case (0x1 << 4): + mask = (0x1 << 2); + shift = 2; + break; + case (0x1 << 5): + mask = (0x3 << 4); + shift = 4; + break; + case (0x1 << 6): + mask = (0x3 << 6); + shift = 6; + break; + case (0x1 << 7): + mask = (0x1 << 8); + shift = 8; + break; + case (0x1 << 8): + mask = (0x1 << 9); + shift = 9; + break; + case (0x1 << 10): + mask = 0x1fff; + shift = 0x0; + break; + case (0x1 << 11): + mask = 0x1fff; + shift = 0x0; + break; + default: + mask = 0x0; + shift = 0x0; + break; + } + + if ((addr != 0xffff) && (core_mask & (1 << core_num))) + mod_phy_reg(pi, addr, mask, (value << shift)); + } + + or_phy_reg(pi, 0xec, (0x1 << 0)); + or_phy_reg(pi, 0x78, (0x1 << 0)); + udelay(1); + and_phy_reg(pi, 0xec, ~(0x1 << 0)); + } +} + +static void wlc_phy_txpwrctrl_idle_tssi_nphy(struct brcms_phy *pi) +{ + s32 rssi_buf[4]; + s32 int_val; + + if (SCAN_RM_IN_PROGRESS(pi) || PLT_INPROG_PHY(pi) || PHY_MUTED(pi)) + + return; + + if (PHY_IPA(pi)) + wlc_phy_ipa_internal_tssi_setup_nphy(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), + 0, 0x3, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + else if (NREV_GE(pi->pubpi.phy_rev, 3)) + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 0); + + wlc_phy_stopplayback_nphy(pi); + + wlc_phy_tx_tone_nphy(pi, 4000, 0, 0, 0, false); + + udelay(20); + int_val = + wlc_phy_poll_rssi_nphy(pi, (u8) NPHY_RSSI_SEL_TSSI_2G, rssi_buf, + 1); + wlc_phy_stopplayback_nphy(pi); + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, 0); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), + 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + else if (NREV_GE(pi->pubpi.phy_rev, 3)) + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 3, 1); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g = + (u8) ((int_val >> 24) & 0xff); + pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g = + (u8) ((int_val >> 24) & 0xff); + + pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g = + (u8) ((int_val >> 8) & 0xff); + pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g = + (u8) ((int_val >> 8) & 0xff); + } else { + pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_2g = + (u8) ((int_val >> 24) & 0xff); + + pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_2g = + (u8) ((int_val >> 8) & 0xff); + + pi->nphy_pwrctrl_info[PHY_CORE_0].idle_tssi_5g = + (u8) ((int_val >> 16) & 0xff); + pi->nphy_pwrctrl_info[PHY_CORE_1].idle_tssi_5g = + (u8) ((int_val) & 0xff); + } + +} + +static void wlc_phy_txpwr_limit_to_tbl_nphy(struct brcms_phy *pi) +{ + u8 idx, idx2, i, delta_ind; + + for (idx = TXP_FIRST_CCK; idx <= TXP_LAST_CCK; idx++) + pi->adj_pwr_tbl_nphy[idx] = pi->tx_power_offset[idx]; + + for (i = 0; i < 4; i++) { + idx2 = 0; + + delta_ind = 0; + + switch (i) { + case 0: + + if (CHSPEC_IS40(pi->radio_chanspec) + && NPHY_IS_SROM_REINTERPRET) { + idx = TXP_FIRST_MCS_40_SISO; + } else { + idx = (CHSPEC_IS40(pi->radio_chanspec)) ? + TXP_FIRST_OFDM_40_SISO : TXP_FIRST_OFDM; + delta_ind = 1; + } + break; + + case 1: + + idx = (CHSPEC_IS40(pi->radio_chanspec)) ? + TXP_FIRST_MCS_40_CDD : TXP_FIRST_MCS_20_CDD; + break; + + case 2: + + idx = (CHSPEC_IS40(pi->radio_chanspec)) ? + TXP_FIRST_MCS_40_STBC : TXP_FIRST_MCS_20_STBC; + break; + + case 3: + + idx = (CHSPEC_IS40(pi->radio_chanspec)) ? + TXP_FIRST_MCS_40_SDM : TXP_FIRST_MCS_20_SDM; + break; + } + + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + idx = idx + delta_ind; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx++]; + + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx++]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx++]; + + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx++]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx++]; + + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx++]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + idx = idx + 1 - delta_ind; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + pi->adj_pwr_tbl_nphy[4 + 4 * (idx2++) + i] = + pi->tx_power_offset[idx]; + } +} + +static void wlc_phy_txpwrctrl_pwr_setup_nphy(struct brcms_phy *pi) +{ + u32 idx; + s16 a1[2], b0[2], b1[2]; + s8 target_pwr_qtrdbm[2]; + s32 num, den, pwr_est; + u8 chan_freq_range; + u8 idle_tssi[2]; + u32 tbl_id, tbl_len, tbl_offset; + u32 regval[64]; + u8 core; + + if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { + wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); + (void)R_REG(&pi->regs->maccontrol); + udelay(1); + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + or_phy_reg(pi, 0x122, (0x1 << 0)); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + and_phy_reg(pi, 0x1e7, (u16) (~(0x1 << 15))); + else + or_phy_reg(pi, 0x1e7, (0x1 << 15)); + + if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) + wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0); + + if (pi->sh->sromrev < 4) { + idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; + idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; + target_pwr_qtrdbm[0] = 13 * 4; + target_pwr_qtrdbm[1] = 13 * 4; + a1[0] = -424; + a1[1] = -424; + b0[0] = 5612; + b0[1] = 5612; + b1[1] = -1393; + b1[0] = -1393; + } else { + + chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0); + switch (chan_freq_range) { + case WL_CHAN_FREQ_RANGE_2G: + idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; + idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; + target_pwr_qtrdbm[0] = + pi->nphy_pwrctrl_info[0].max_pwr_2g; + target_pwr_qtrdbm[1] = + pi->nphy_pwrctrl_info[1].max_pwr_2g; + a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_a1; + a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_a1; + b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b0; + b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b0; + b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_2g_b1; + b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_2g_b1; + break; + case WL_CHAN_FREQ_RANGE_5GL: + idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; + idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; + target_pwr_qtrdbm[0] = + pi->nphy_pwrctrl_info[0].max_pwr_5gl; + target_pwr_qtrdbm[1] = + pi->nphy_pwrctrl_info[1].max_pwr_5gl; + a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1; + a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1; + b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0; + b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0; + b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1; + b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1; + break; + case WL_CHAN_FREQ_RANGE_5GM: + idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; + idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; + target_pwr_qtrdbm[0] = + pi->nphy_pwrctrl_info[0].max_pwr_5gm; + target_pwr_qtrdbm[1] = + pi->nphy_pwrctrl_info[1].max_pwr_5gm; + a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_a1; + a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_a1; + b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b0; + b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b0; + b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gm_b1; + b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gm_b1; + break; + case WL_CHAN_FREQ_RANGE_5GH: + idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_5g; + idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_5g; + target_pwr_qtrdbm[0] = + pi->nphy_pwrctrl_info[0].max_pwr_5gh; + target_pwr_qtrdbm[1] = + pi->nphy_pwrctrl_info[1].max_pwr_5gh; + a1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1; + a1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1; + b0[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0; + b0[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0; + b1[0] = pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1; + b1[1] = pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1; + break; + default: + idle_tssi[0] = pi->nphy_pwrctrl_info[0].idle_tssi_2g; + idle_tssi[1] = pi->nphy_pwrctrl_info[1].idle_tssi_2g; + target_pwr_qtrdbm[0] = 13 * 4; + target_pwr_qtrdbm[1] = 13 * 4; + a1[0] = -424; + a1[1] = -424; + b0[0] = 5612; + b0[1] = 5612; + b1[1] = -1393; + b1[0] = -1393; + break; + } + } + + target_pwr_qtrdbm[0] = (s8) pi->tx_power_max; + target_pwr_qtrdbm[1] = (s8) pi->tx_power_max; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (pi->srom_fem2g.tssipos) + or_phy_reg(pi, 0x1e9, (0x1 << 14)); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + for (core = 0; core <= 1; core++) { + if (PHY_IPA(pi)) { + if (CHSPEC_IS2G(pi->radio_chanspec)) + WRITE_RADIO_REG3(pi, RADIO_2057, + TX, core, + TX_SSI_MUX, + 0xe); + else + WRITE_RADIO_REG3(pi, RADIO_2057, + TX, core, + TX_SSI_MUX, + 0xc); + } + } + } else { + if (PHY_IPA(pi)) { + + write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX | + RADIO_2056_TX0, + (CHSPEC_IS5G + (pi->radio_chanspec)) ? + 0xc : 0xe); + write_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MUX | + RADIO_2056_TX1, + (CHSPEC_IS5G + (pi->radio_chanspec)) ? + 0xc : 0xe); + } else { + + write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX | + RADIO_2056_TX0, 0x11); + write_radio_reg(pi, RADIO_2056_TX_TX_SSI_MUX | + RADIO_2056_TX1, 0x11); + } + } + } + + if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { + wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); + (void)R_REG(&pi->regs->maccontrol); + udelay(1); + } + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + mod_phy_reg(pi, 0x1e7, (0x7f << 0), + (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0)); + else + mod_phy_reg(pi, 0x1e7, (0x7f << 0), + (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0)); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + mod_phy_reg(pi, 0x222, (0xff << 0), + (NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 << 0)); + else if (NREV_GT(pi->pubpi.phy_rev, 1)) + mod_phy_reg(pi, 0x222, (0xff << 0), + (NPHY_TxPwrCtrlCmd_pwrIndex_init << 0)); + + if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) + wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0); + + write_phy_reg(pi, 0x1e8, (0x3 << 8) | (240 << 0)); + + write_phy_reg(pi, 0x1e9, + (1 << 15) | (idle_tssi[0] << 0) | (idle_tssi[1] << 8)); + + write_phy_reg(pi, 0x1ea, + (target_pwr_qtrdbm[0] << 0) | + (target_pwr_qtrdbm[1] << 8)); + + tbl_len = 64; + tbl_offset = 0; + for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL; + tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) { + + for (idx = 0; idx < tbl_len; idx++) { + num = 8 * + (16 * b0[tbl_id - 26] + b1[tbl_id - 26] * idx); + den = 32768 + a1[tbl_id - 26] * idx; + pwr_est = max(((4 * num + den / 2) / den), -8); + if (NREV_LT(pi->pubpi.phy_rev, 3)) { + if (idx <= + (uint) (31 - idle_tssi[tbl_id - 26] + 1)) + pwr_est = + max(pwr_est, + target_pwr_qtrdbm + [tbl_id - 26] + 1); + } + regval[idx] = (u32) pwr_est; + } + wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32, + regval); + } + + wlc_phy_txpwr_limit_to_tbl_nphy(pi); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 84, 64, 8, + pi->adj_pwr_tbl_nphy); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 84, 64, 8, + pi->adj_pwr_tbl_nphy); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static u32 *wlc_phy_get_ipa_gaintbl_nphy(struct brcms_phy *pi) +{ + u32 *tx_pwrctrl_tbl = NULL; + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if ((pi->pubpi.radiorev == 4) + || (pi->pubpi.radiorev == 6)) + tx_pwrctrl_tbl = + nphy_tpc_txgain_ipa_2g_2057rev4n6; + else if (pi->pubpi.radiorev == 3) + tx_pwrctrl_tbl = + nphy_tpc_txgain_ipa_2g_2057rev3; + else if (pi->pubpi.radiorev == 5) + tx_pwrctrl_tbl = + nphy_tpc_txgain_ipa_2g_2057rev5; + else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) + tx_pwrctrl_tbl = + nphy_tpc_txgain_ipa_2g_2057rev7; + } else if (NREV_IS(pi->pubpi.phy_rev, 6)) { + tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6; + } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { + tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5; + } else { + tx_pwrctrl_tbl = nphy_tpc_txgain_ipa; + } + } else { + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if ((pi->pubpi.radiorev == 3) || + (pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) + tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g_2057; + else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) + tx_pwrctrl_tbl = + nphy_tpc_txgain_ipa_5g_2057rev7; + } else { + tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_5g; + } + } + + return tx_pwrctrl_tbl; +} + +static void wlc_phy_restore_rssical_nphy(struct brcms_phy *pi) +{ + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (pi->nphy_rssical_chanspec_2G == 0) + return; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0, + RADIO_2057_VCM_MASK, + pi->rssical_cache. + rssical_radio_regs_2G[0]); + mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1, + RADIO_2057_VCM_MASK, + pi->rssical_cache. + rssical_radio_regs_2G[1]); + } else { + mod_radio_reg(pi, + RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0, + RADIO_2056_VCM_MASK, + pi->rssical_cache. + rssical_radio_regs_2G[0]); + mod_radio_reg(pi, + RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1, + RADIO_2056_VCM_MASK, + pi->rssical_cache. + rssical_radio_regs_2G[1]); + } + + write_phy_reg(pi, 0x1a6, + pi->rssical_cache.rssical_phyregs_2G[0]); + write_phy_reg(pi, 0x1ac, + pi->rssical_cache.rssical_phyregs_2G[1]); + write_phy_reg(pi, 0x1b2, + pi->rssical_cache.rssical_phyregs_2G[2]); + write_phy_reg(pi, 0x1b8, + pi->rssical_cache.rssical_phyregs_2G[3]); + write_phy_reg(pi, 0x1a4, + pi->rssical_cache.rssical_phyregs_2G[4]); + write_phy_reg(pi, 0x1aa, + pi->rssical_cache.rssical_phyregs_2G[5]); + write_phy_reg(pi, 0x1b0, + pi->rssical_cache.rssical_phyregs_2G[6]); + write_phy_reg(pi, 0x1b6, + pi->rssical_cache.rssical_phyregs_2G[7]); + write_phy_reg(pi, 0x1a5, + pi->rssical_cache.rssical_phyregs_2G[8]); + write_phy_reg(pi, 0x1ab, + pi->rssical_cache.rssical_phyregs_2G[9]); + write_phy_reg(pi, 0x1b1, + pi->rssical_cache.rssical_phyregs_2G[10]); + write_phy_reg(pi, 0x1b7, + pi->rssical_cache.rssical_phyregs_2G[11]); + + } else { + if (pi->nphy_rssical_chanspec_5G == 0) + return; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0, + RADIO_2057_VCM_MASK, + pi->rssical_cache. + rssical_radio_regs_5G[0]); + mod_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1, + RADIO_2057_VCM_MASK, + pi->rssical_cache. + rssical_radio_regs_5G[1]); + } else { + mod_radio_reg(pi, + RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX0, + RADIO_2056_VCM_MASK, + pi->rssical_cache. + rssical_radio_regs_5G[0]); + mod_radio_reg(pi, + RADIO_2056_RX_RSSI_MISC | RADIO_2056_RX1, + RADIO_2056_VCM_MASK, + pi->rssical_cache. + rssical_radio_regs_5G[1]); + } + + write_phy_reg(pi, 0x1a6, + pi->rssical_cache.rssical_phyregs_5G[0]); + write_phy_reg(pi, 0x1ac, + pi->rssical_cache.rssical_phyregs_5G[1]); + write_phy_reg(pi, 0x1b2, + pi->rssical_cache.rssical_phyregs_5G[2]); + write_phy_reg(pi, 0x1b8, + pi->rssical_cache.rssical_phyregs_5G[3]); + write_phy_reg(pi, 0x1a4, + pi->rssical_cache.rssical_phyregs_5G[4]); + write_phy_reg(pi, 0x1aa, + pi->rssical_cache.rssical_phyregs_5G[5]); + write_phy_reg(pi, 0x1b0, + pi->rssical_cache.rssical_phyregs_5G[6]); + write_phy_reg(pi, 0x1b6, + pi->rssical_cache.rssical_phyregs_5G[7]); + write_phy_reg(pi, 0x1a5, + pi->rssical_cache.rssical_phyregs_5G[8]); + write_phy_reg(pi, 0x1ab, + pi->rssical_cache.rssical_phyregs_5G[9]); + write_phy_reg(pi, 0x1b1, + pi->rssical_cache.rssical_phyregs_5G[10]); + write_phy_reg(pi, 0x1b7, + pi->rssical_cache.rssical_phyregs_5G[11]); + } +} + +static void wlc_phy_internal_cal_txgain_nphy(struct brcms_phy *pi) +{ + u16 txcal_gain[2]; + + pi->nphy_txcal_pwr_idx[0] = pi->nphy_cal_orig_pwr_idx[0]; + pi->nphy_txcal_pwr_idx[1] = pi->nphy_cal_orig_pwr_idx[0]; + wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true); + wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, + txcal_gain); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F40; + txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F40; + } else { + txcal_gain[0] = (txcal_gain[0] & 0xF000) | 0x0F60; + txcal_gain[1] = (txcal_gain[1] & 0xF000) | 0x0F60; + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, + txcal_gain); +} + +static void wlc_phy_precal_txgain_nphy(struct brcms_phy *pi) +{ + bool save_bbmult = false; + u8 txcal_index_2057_rev5n7 = 0; + u8 txcal_index_2057_rev3n4n6 = 10; + + if (pi->use_int_tx_iqlo_cal_nphy) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if ((pi->pubpi.radiorev == 3) || + (pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) { + + pi->nphy_txcal_pwr_idx[0] = + txcal_index_2057_rev3n4n6; + pi->nphy_txcal_pwr_idx[1] = + txcal_index_2057_rev3n4n6; + wlc_phy_txpwr_index_nphy( + pi, 3, + txcal_index_2057_rev3n4n6, + false); + } else { + + pi->nphy_txcal_pwr_idx[0] = + txcal_index_2057_rev5n7; + pi->nphy_txcal_pwr_idx[1] = + txcal_index_2057_rev5n7; + wlc_phy_txpwr_index_nphy( + pi, 3, + txcal_index_2057_rev5n7, + false); + } + save_bbmult = true; + + } else if (NREV_LT(pi->pubpi.phy_rev, 5)) { + wlc_phy_cal_txgainctrl_nphy(pi, 11, false); + if (pi->sh->hw_phytxchain != 3) { + pi->nphy_txcal_pwr_idx[1] = + pi->nphy_txcal_pwr_idx[0]; + wlc_phy_txpwr_index_nphy(pi, 3, + pi-> + nphy_txcal_pwr_idx[0], + true); + save_bbmult = true; + } + + } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { + if (PHY_IPA(pi)) { + if (CHSPEC_IS2G(pi->radio_chanspec)) { + wlc_phy_cal_txgainctrl_nphy(pi, 12, + false); + } else { + pi->nphy_txcal_pwr_idx[0] = 80; + pi->nphy_txcal_pwr_idx[1] = 80; + wlc_phy_txpwr_index_nphy(pi, 3, 80, + false); + save_bbmult = true; + } + } else { + wlc_phy_internal_cal_txgain_nphy(pi); + save_bbmult = true; + } + + } else if (NREV_IS(pi->pubpi.phy_rev, 6)) { + if (PHY_IPA(pi)) { + if (CHSPEC_IS2G(pi->radio_chanspec)) + wlc_phy_cal_txgainctrl_nphy(pi, 12, + false); + else + wlc_phy_cal_txgainctrl_nphy(pi, 14, + false); + } else { + wlc_phy_internal_cal_txgain_nphy(pi); + save_bbmult = true; + } + } + + } else { + wlc_phy_cal_txgainctrl_nphy(pi, 10, false); + } + + if (save_bbmult) + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, + &pi->nphy_txcal_bbmult); +} + +static void +wlc_phy_rfctrlintc_override_nphy(struct brcms_phy *pi, u8 field, u16 value, + u8 core_code) +{ + u16 mask; + u16 val; + u8 core; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + if (core_code == RADIO_MIMO_CORESEL_CORE1 + && core == PHY_CORE_1) + continue; + else if (core_code == RADIO_MIMO_CORESEL_CORE2 + && core == PHY_CORE_0) + continue; + + if (NREV_LT(pi->pubpi.phy_rev, 7)) { + + mask = (0x1 << 10); + val = 1 << 10; + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 : + 0x92, mask, val); + } + + if (field == NPHY_RfctrlIntc_override_OFF) { + + write_phy_reg(pi, (core == PHY_CORE_0) ? 0x91 : + 0x92, 0); + + wlc_phy_force_rfseq_nphy(pi, + NPHY_RFSEQ_RESET2RX); + } else if (field == NPHY_RfctrlIntc_override_TRSW) { + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + mask = (0x1 << 6) | (0x1 << 7); + + val = value << 6; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + mask, val); + + or_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + (0x1 << 10)); + + and_phy_reg(pi, 0x2ff, (u16) + ~(0x3 << 14)); + or_phy_reg(pi, 0x2ff, (0x1 << 13)); + or_phy_reg(pi, 0x2ff, (0x1 << 0)); + } else { + + mask = (0x1 << 6) | + (0x1 << 7) | + (0x1 << 8) | (0x1 << 9); + val = value << 6; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + mask, val); + + mask = (0x1 << 0); + val = 1 << 0; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xe7 : 0xec, + mask, val); + + mask = (core == PHY_CORE_0) ? + (0x1 << 0) : (0x1 << 1); + val = 1 << ((core == PHY_CORE_0) ? + 0 : 1); + mod_phy_reg(pi, 0x78, mask, val); + + SPINWAIT(((read_phy_reg(pi, 0x78) & val) + != 0), 10000); + if (WARN(read_phy_reg(pi, 0x78) & val, + "HW error: override failed")) + return; + + mask = (0x1 << 0); + val = 0 << 0; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xe7 : 0xec, + mask, val); + } + } else if (field == NPHY_RfctrlIntc_override_PA) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + mask = (0x1 << 4) | (0x1 << 5); + + if (CHSPEC_IS5G(pi->radio_chanspec)) + val = value << 5; + else + val = value << 4; + + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + mask, val); + + or_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + (0x1 << 12)); + } else { + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + mask = (0x1 << 5); + val = value << 5; + } else { + mask = (0x1 << 4); + val = value << 4; + } + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + mask, val); + } + } else if (field == + NPHY_RfctrlIntc_override_EXT_LNA_PU) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + + mask = (0x1 << 0); + val = value << 0; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 + : 0x92, mask, val); + + mask = (0x1 << 2); + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 + : 0x92, mask, 0); + } else { + + mask = (0x1 << 2); + val = value << 2; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 + : 0x92, mask, val); + + mask = (0x1 << 0); + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 + : 0x92, mask, 0); + } + + mask = (0x1 << 11); + val = 1 << 11; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + mask, val); + } else { + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + mask = (0x1 << 0); + val = value << 0; + } else { + mask = (0x1 << 2); + val = value << 2; + } + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + mask, val); + } + } else if (field == + NPHY_RfctrlIntc_override_EXT_LNA_GAIN) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + + mask = (0x1 << 1); + val = value << 1; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 + : 0x92, mask, val); + + mask = (0x1 << 3); + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 + : 0x92, mask, 0); + } else { + + mask = (0x1 << 3); + val = value << 3; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 + : 0x92, mask, val); + + mask = (0x1 << 1); + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 + : 0x92, mask, 0); + } + + mask = (0x1 << 11); + val = 1 << 11; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + mask, val); + } else { + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + mask = (0x1 << 1); + val = value << 1; + } else { + mask = (0x1 << 3); + val = value << 3; + } + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x91 : 0x92, + mask, val); + } + } + } + } +} + +void +wlc_phy_cal_txgainctrl_nphy(struct brcms_phy *pi, s32 dBm_targetpower, + bool debug) +{ + int gainctrl_loopidx; + uint core; + u16 m0m1, curr_m0m1; + s32 delta_power; + s32 txpwrindex; + s32 qdBm_power[2]; + u16 orig_BBConfig; + u16 phy_saveregs[4]; + u32 freq_test; + u16 ampl_test = 250; + uint stepsize; + bool phyhang_avoid_state = false; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + stepsize = 2; + else + stepsize = 1; + + if (CHSPEC_IS40(pi->radio_chanspec)) + freq_test = 5000; + else + freq_test = 2500; + + wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_cal_orig_pwr_idx[0], true); + wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_cal_orig_pwr_idx[1], true); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + phyhang_avoid_state = pi->phyhang_avoid; + pi->phyhang_avoid = false; + + phy_saveregs[0] = read_phy_reg(pi, 0x91); + phy_saveregs[1] = read_phy_reg(pi, 0x92); + phy_saveregs[2] = read_phy_reg(pi, 0xe7); + phy_saveregs[3] = read_phy_reg(pi, 0xec); + wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_PA, 1, + RADIO_MIMO_CORESEL_CORE1 | + RADIO_MIMO_CORESEL_CORE2); + + if (!debug) { + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + 0x2, RADIO_MIMO_CORESEL_CORE1); + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + 0x8, RADIO_MIMO_CORESEL_CORE2); + } else { + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + 0x1, RADIO_MIMO_CORESEL_CORE1); + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + 0x7, RADIO_MIMO_CORESEL_CORE2); + } + + orig_BBConfig = read_phy_reg(pi, 0x01); + mod_phy_reg(pi, 0x01, (0x1 << 15), 0); + + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1); + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + txpwrindex = (s32) pi->nphy_cal_orig_pwr_idx[core]; + + for (gainctrl_loopidx = 0; gainctrl_loopidx < 2; + gainctrl_loopidx++) { + wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0, + false); + + if (core == PHY_CORE_0) + curr_m0m1 = m0m1 & 0xff00; + else + curr_m0m1 = m0m1 & 0x00ff; + + wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &curr_m0m1); + wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &curr_m0m1); + + udelay(50); + + wlc_phy_est_tonepwr_nphy(pi, qdBm_power, + NPHY_CAL_TSSISAMPS); + + pi->nphy_bb_mult_save = 0; + wlc_phy_stopplayback_nphy(pi); + + delta_power = (dBm_targetpower * 4) - qdBm_power[core]; + + txpwrindex -= stepsize * delta_power; + if (txpwrindex < 0) + txpwrindex = 0; + else if (txpwrindex > 127) + txpwrindex = 127; + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (NREV_IS(pi->pubpi.phy_rev, 4) && + (pi->srom_fem5g.extpagain == 3)) { + if (txpwrindex < 30) + txpwrindex = 30; + } + } else { + if (NREV_GE(pi->pubpi.phy_rev, 5) && + (pi->srom_fem2g.extpagain == 3)) { + if (txpwrindex < 50) + txpwrindex = 50; + } + } + + wlc_phy_txpwr_index_nphy(pi, (1 << core), + (u8) txpwrindex, true); + } + + pi->nphy_txcal_pwr_idx[core] = (u8) txpwrindex; + + if (debug) { + u16 radio_gain; + u16 dbg_m0m1; + + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &dbg_m0m1); + + wlc_phy_tx_tone_nphy(pi, freq_test, ampl_test, 0, 0, + false); + + wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &dbg_m0m1); + wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &dbg_m0m1); + + udelay(100); + + wlc_phy_est_tonepwr_nphy(pi, qdBm_power, + NPHY_CAL_TSSISAMPS); + + wlc_phy_table_read_nphy(pi, 7, 1, (0x110 + core), 16, + &radio_gain); + + mdelay(4000); + pi->nphy_bb_mult_save = 0; + wlc_phy_stopplayback_nphy(pi); + } + } + + wlc_phy_txpwr_index_nphy(pi, 1, pi->nphy_txcal_pwr_idx[0], true); + wlc_phy_txpwr_index_nphy(pi, 2, pi->nphy_txcal_pwr_idx[1], true); + + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &pi->nphy_txcal_bbmult); + + write_phy_reg(pi, 0x01, orig_BBConfig); + + write_phy_reg(pi, 0x91, phy_saveregs[0]); + write_phy_reg(pi, 0x92, phy_saveregs[1]); + write_phy_reg(pi, 0xe7, phy_saveregs[2]); + write_phy_reg(pi, 0xec, phy_saveregs[3]); + + pi->phyhang_avoid = phyhang_avoid_state; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static void wlc_phy_savecal_nphy(struct brcms_phy *pi) +{ + void *tbl_ptr; + int coreNum; + u16 *txcal_radio_regs = NULL; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + + wlc_phy_rx_iq_coeffs_nphy(pi, 0, + &pi->calibration_cache. + rxcal_coeffs_2G); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + txcal_radio_regs = + pi->calibration_cache.txcal_radio_regs_2G; + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + pi->calibration_cache.txcal_radio_regs_2G[0] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_I | + RADIO_2056_TX0); + pi->calibration_cache.txcal_radio_regs_2G[1] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_Q | + RADIO_2056_TX0); + pi->calibration_cache.txcal_radio_regs_2G[2] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_I | + RADIO_2056_TX1); + pi->calibration_cache.txcal_radio_regs_2G[3] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_Q | + RADIO_2056_TX1); + + pi->calibration_cache.txcal_radio_regs_2G[4] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_I | + RADIO_2056_TX0); + pi->calibration_cache.txcal_radio_regs_2G[5] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_Q | + RADIO_2056_TX0); + pi->calibration_cache.txcal_radio_regs_2G[6] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_I | + RADIO_2056_TX1); + pi->calibration_cache.txcal_radio_regs_2G[7] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_Q | + RADIO_2056_TX1); + } else { + pi->calibration_cache.txcal_radio_regs_2G[0] = + read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL); + pi->calibration_cache.txcal_radio_regs_2G[1] = + read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL); + pi->calibration_cache.txcal_radio_regs_2G[2] = + read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM); + pi->calibration_cache.txcal_radio_regs_2G[3] = + read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM); + } + + pi->nphy_iqcal_chanspec_2G = pi->radio_chanspec; + tbl_ptr = pi->calibration_cache.txcal_coeffs_2G; + } else { + + wlc_phy_rx_iq_coeffs_nphy(pi, 0, + &pi->calibration_cache. + rxcal_coeffs_5G); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + txcal_radio_regs = + pi->calibration_cache.txcal_radio_regs_5G; + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + pi->calibration_cache.txcal_radio_regs_5G[0] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_I | + RADIO_2056_TX0); + pi->calibration_cache.txcal_radio_regs_5G[1] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_Q | + RADIO_2056_TX0); + pi->calibration_cache.txcal_radio_regs_5G[2] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_I | + RADIO_2056_TX1); + pi->calibration_cache.txcal_radio_regs_5G[3] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_Q | + RADIO_2056_TX1); + + pi->calibration_cache.txcal_radio_regs_5G[4] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_I | + RADIO_2056_TX0); + pi->calibration_cache.txcal_radio_regs_5G[5] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_Q | + RADIO_2056_TX0); + pi->calibration_cache.txcal_radio_regs_5G[6] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_I | + RADIO_2056_TX1); + pi->calibration_cache.txcal_radio_regs_5G[7] = + read_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_Q | + RADIO_2056_TX1); + } else { + pi->calibration_cache.txcal_radio_regs_5G[0] = + read_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL); + pi->calibration_cache.txcal_radio_regs_5G[1] = + read_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL); + pi->calibration_cache.txcal_radio_regs_5G[2] = + read_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM); + pi->calibration_cache.txcal_radio_regs_5G[3] = + read_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM); + } + + pi->nphy_iqcal_chanspec_5G = pi->radio_chanspec; + tbl_ptr = pi->calibration_cache.txcal_coeffs_5G; + } + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + for (coreNum = 0; coreNum <= 1; coreNum++) { + + txcal_radio_regs[2 * coreNum] = + READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum, + LOFT_FINE_I); + txcal_radio_regs[2 * coreNum + 1] = + READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum, + LOFT_FINE_Q); + + txcal_radio_regs[2 * coreNum + 4] = + READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum, + LOFT_COARSE_I); + txcal_radio_regs[2 * coreNum + 5] = + READ_RADIO_REG3(pi, RADIO_2057, TX, coreNum, + LOFT_COARSE_Q); + } + } + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 8, 80, 16, tbl_ptr); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static void wlc_phy_tx_iq_war_nphy(struct brcms_phy *pi) +{ + struct nphy_iq_comp tx_comp; + + wlc_phy_table_read_nphy(pi, 15, 4, 0x50, 16, &tx_comp); + + wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ, tx_comp.a0); + wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 2, tx_comp.b0); + wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 4, tx_comp.a1); + wlapi_bmac_write_shm(pi->sh->physhim, M_20IN40_IQ + 6, tx_comp.b1); +} + +static void wlc_phy_restorecal_nphy(struct brcms_phy *pi) +{ + u16 *loft_comp; + u16 txcal_coeffs_bphy[4]; + u16 *tbl_ptr; + int coreNum; + u16 *txcal_radio_regs = NULL; + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (pi->nphy_iqcal_chanspec_2G == 0) + return; + + tbl_ptr = pi->calibration_cache.txcal_coeffs_2G; + loft_comp = &pi->calibration_cache.txcal_coeffs_2G[5]; + } else { + if (pi->nphy_iqcal_chanspec_5G == 0) + return; + + tbl_ptr = pi->calibration_cache.txcal_coeffs_5G; + loft_comp = &pi->calibration_cache.txcal_coeffs_5G[5]; + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, 16, tbl_ptr); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + txcal_coeffs_bphy[0] = tbl_ptr[0]; + txcal_coeffs_bphy[1] = tbl_ptr[1]; + txcal_coeffs_bphy[2] = tbl_ptr[2]; + txcal_coeffs_bphy[3] = tbl_ptr[3]; + } else { + txcal_coeffs_bphy[0] = 0; + txcal_coeffs_bphy[1] = 0; + txcal_coeffs_bphy[2] = 0; + txcal_coeffs_bphy[3] = 0; + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, 16, + txcal_coeffs_bphy); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, 16, loft_comp); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, 16, loft_comp); + + if (NREV_LT(pi->pubpi.phy_rev, 2)) + wlc_phy_tx_iq_war_nphy(pi); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + txcal_radio_regs = + pi->calibration_cache.txcal_radio_regs_2G; + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + write_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_I | + RADIO_2056_TX0, + pi->calibration_cache. + txcal_radio_regs_2G[0]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_Q | + RADIO_2056_TX0, + pi->calibration_cache. + txcal_radio_regs_2G[1]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_I | + RADIO_2056_TX1, + pi->calibration_cache. + txcal_radio_regs_2G[2]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_Q | + RADIO_2056_TX1, + pi->calibration_cache. + txcal_radio_regs_2G[3]); + + write_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_I | + RADIO_2056_TX0, + pi->calibration_cache. + txcal_radio_regs_2G[4]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_Q | + RADIO_2056_TX0, + pi->calibration_cache. + txcal_radio_regs_2G[5]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_I | + RADIO_2056_TX1, + pi->calibration_cache. + txcal_radio_regs_2G[6]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_Q | + RADIO_2056_TX1, + pi->calibration_cache. + txcal_radio_regs_2G[7]); + } else { + write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL, + pi->calibration_cache. + txcal_radio_regs_2G[0]); + write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL, + pi->calibration_cache. + txcal_radio_regs_2G[1]); + write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, + pi->calibration_cache. + txcal_radio_regs_2G[2]); + write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, + pi->calibration_cache. + txcal_radio_regs_2G[3]); + } + + wlc_phy_rx_iq_coeffs_nphy(pi, 1, + &pi->calibration_cache. + rxcal_coeffs_2G); + } else { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + txcal_radio_regs = + pi->calibration_cache.txcal_radio_regs_5G; + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + write_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_I | + RADIO_2056_TX0, + pi->calibration_cache. + txcal_radio_regs_5G[0]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_Q | + RADIO_2056_TX0, + pi->calibration_cache. + txcal_radio_regs_5G[1]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_I | + RADIO_2056_TX1, + pi->calibration_cache. + txcal_radio_regs_5G[2]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_FINE_Q | + RADIO_2056_TX1, + pi->calibration_cache. + txcal_radio_regs_5G[3]); + + write_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_I | + RADIO_2056_TX0, + pi->calibration_cache. + txcal_radio_regs_5G[4]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_Q | + RADIO_2056_TX0, + pi->calibration_cache. + txcal_radio_regs_5G[5]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_I | + RADIO_2056_TX1, + pi->calibration_cache. + txcal_radio_regs_5G[6]); + write_radio_reg(pi, + RADIO_2056_TX_LOFT_COARSE_Q | + RADIO_2056_TX1, + pi->calibration_cache. + txcal_radio_regs_5G[7]); + } else { + write_radio_reg(pi, RADIO_2055_CORE1_TX_VOS_CNCL, + pi->calibration_cache. + txcal_radio_regs_5G[0]); + write_radio_reg(pi, RADIO_2055_CORE2_TX_VOS_CNCL, + pi->calibration_cache. + txcal_radio_regs_5G[1]); + write_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, + pi->calibration_cache. + txcal_radio_regs_5G[2]); + write_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, + pi->calibration_cache. + txcal_radio_regs_5G[3]); + } + + wlc_phy_rx_iq_coeffs_nphy(pi, 1, + &pi->calibration_cache. + rxcal_coeffs_5G); + } + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + for (coreNum = 0; coreNum <= 1; coreNum++) { + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum, + LOFT_FINE_I, + txcal_radio_regs[2 * coreNum]); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum, + LOFT_FINE_Q, + txcal_radio_regs[2 * coreNum + 1]); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum, + LOFT_COARSE_I, + txcal_radio_regs[2 * coreNum + 4]); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, coreNum, + LOFT_COARSE_Q, + txcal_radio_regs[2 * coreNum + 5]); + } + } +} + +static void wlc_phy_txpwrctrl_coeff_setup_nphy(struct brcms_phy *pi) +{ + u32 idx; + u16 iqloCalbuf[7]; + u32 iqcomp, locomp, curr_locomp; + s8 locomp_i, locomp_q; + s8 curr_locomp_i, curr_locomp_q; + u32 tbl_id, tbl_len, tbl_offset; + u32 regval[128]; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + wlc_phy_table_read_nphy(pi, 15, 7, 80, 16, iqloCalbuf); + + tbl_len = 128; + tbl_offset = 320; + for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL; + tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) { + iqcomp = + (tbl_id == + 26) ? (((u32) (iqloCalbuf[0] & 0x3ff)) << 10) | + (iqloCalbuf[1] & 0x3ff) + : (((u32) (iqloCalbuf[2] & 0x3ff)) << 10) | + (iqloCalbuf[3] & 0x3ff); + + for (idx = 0; idx < tbl_len; idx++) + regval[idx] = iqcomp; + wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32, + regval); + } + + tbl_offset = 448; + for (tbl_id = NPHY_TBL_ID_CORE1TXPWRCTL; + tbl_id <= NPHY_TBL_ID_CORE2TXPWRCTL; tbl_id++) { + + locomp = + (u32) ((tbl_id == 26) ? iqloCalbuf[5] : iqloCalbuf[6]); + locomp_i = (s8) ((locomp >> 8) & 0xff); + locomp_q = (s8) ((locomp) & 0xff); + for (idx = 0; idx < tbl_len; idx++) { + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + curr_locomp_i = locomp_i; + curr_locomp_q = locomp_q; + } else { + curr_locomp_i = (s8) ((locomp_i * + nphy_tpc_loscale[idx] + + 128) >> 8); + curr_locomp_q = + (s8) ((locomp_q * + nphy_tpc_loscale[idx] + + 128) >> 8); + } + curr_locomp = (u32) ((curr_locomp_i & 0xff) << 8); + curr_locomp |= (u32) (curr_locomp_q & 0xff); + regval[idx] = curr_locomp; + } + wlc_phy_table_write_nphy(pi, tbl_id, tbl_len, tbl_offset, 32, + regval); + } + + if (NREV_LT(pi->pubpi.phy_rev, 2)) { + + wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX1, 0xFFFF); + wlapi_bmac_write_shm(pi->sh->physhim, M_CURR_IDX2, 0xFFFF); + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static void wlc_phy_txlpfbw_nphy(struct brcms_phy *pi) +{ + u8 tx_lpf_bw = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) { + if (CHSPEC_IS40(pi->radio_chanspec)) + tx_lpf_bw = 3; + else + tx_lpf_bw = 1; + + if (PHY_IPA(pi)) { + if (CHSPEC_IS40(pi->radio_chanspec)) + tx_lpf_bw = 5; + else + tx_lpf_bw = 4; + } + + write_phy_reg(pi, 0xe8, + (tx_lpf_bw << 0) | + (tx_lpf_bw << 3) | + (tx_lpf_bw << 6) | (tx_lpf_bw << 9)); + + if (PHY_IPA(pi)) { + + if (CHSPEC_IS40(pi->radio_chanspec)) + tx_lpf_bw = 4; + else + tx_lpf_bw = 1; + + write_phy_reg(pi, 0xe9, + (tx_lpf_bw << 0) | + (tx_lpf_bw << 3) | + (tx_lpf_bw << 6) | (tx_lpf_bw << 9)); + } + } +} + +static void +wlc_phy_adjust_rx_analpfbw_nphy(struct brcms_phy *pi, u16 reduction_factr) +{ + if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LT(pi->pubpi.phy_rev, 7)) { + if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) && + CHSPEC_IS40(pi->radio_chanspec)) { + if (!pi->nphy_anarxlpf_adjusted) { + write_radio_reg(pi, + (RADIO_2056_RX_RXLPF_RCCAL_LPC | + RADIO_2056_RX0), + ((pi->nphy_rccal_value + + reduction_factr) | 0x80)); + + pi->nphy_anarxlpf_adjusted = true; + } + } else { + if (pi->nphy_anarxlpf_adjusted) { + write_radio_reg(pi, + (RADIO_2056_RX_RXLPF_RCCAL_LPC | + RADIO_2056_RX0), + (pi->nphy_rccal_value | 0x80)); + + pi->nphy_anarxlpf_adjusted = false; + } + } + } +} + +static void +wlc_phy_adjust_min_noisevar_nphy(struct brcms_phy *pi, int ntones, + int *tone_id_buf, u32 *noise_var_buf) +{ + int i; + u32 offset; + int tone_id; + int tbllen = + CHSPEC_IS40(pi->radio_chanspec) ? + NPHY_NOISEVAR_TBLLEN40 : NPHY_NOISEVAR_TBLLEN20; + + if (pi->nphy_noisevars_adjusted) { + for (i = 0; i < pi->nphy_saved_noisevars.bufcount; i++) { + tone_id = pi->nphy_saved_noisevars.tone_id[i]; + offset = (tone_id >= 0) ? + ((tone_id * + 2) + 1) : (tbllen + (tone_id * 2) + 1); + wlc_phy_table_write_nphy( + pi, NPHY_TBL_ID_NOISEVAR, 1, + offset, 32, + &pi->nphy_saved_noisevars.min_noise_vars[i]); + } + + pi->nphy_saved_noisevars.bufcount = 0; + pi->nphy_noisevars_adjusted = false; + } + + if ((noise_var_buf != NULL) && (tone_id_buf != NULL)) { + pi->nphy_saved_noisevars.bufcount = 0; + + for (i = 0; i < ntones; i++) { + tone_id = tone_id_buf[i]; + offset = (tone_id >= 0) ? + ((tone_id * 2) + 1) : + (tbllen + (tone_id * 2) + 1); + pi->nphy_saved_noisevars.tone_id[i] = tone_id; + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, + offset, 32, + &pi->nphy_saved_noisevars. + min_noise_vars[i]); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_NOISEVAR, 1, + offset, 32, &noise_var_buf[i]); + pi->nphy_saved_noisevars.bufcount++; + } + + pi->nphy_noisevars_adjusted = true; + } +} + +static void wlc_phy_adjust_crsminpwr_nphy(struct brcms_phy *pi, u8 minpwr) +{ + u16 regval; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if ((CHSPEC_CHANNEL(pi->radio_chanspec) == 11) && + CHSPEC_IS40(pi->radio_chanspec)) { + if (!pi->nphy_crsminpwr_adjusted) { + regval = read_phy_reg(pi, 0x27d); + pi->nphy_crsminpwr[0] = regval & 0xff; + regval &= 0xff00; + regval |= (u16) minpwr; + write_phy_reg(pi, 0x27d, regval); + + regval = read_phy_reg(pi, 0x280); + pi->nphy_crsminpwr[1] = regval & 0xff; + regval &= 0xff00; + regval |= (u16) minpwr; + write_phy_reg(pi, 0x280, regval); + + regval = read_phy_reg(pi, 0x283); + pi->nphy_crsminpwr[2] = regval & 0xff; + regval &= 0xff00; + regval |= (u16) minpwr; + write_phy_reg(pi, 0x283, regval); + + pi->nphy_crsminpwr_adjusted = true; + } + } else { + if (pi->nphy_crsminpwr_adjusted) { + regval = read_phy_reg(pi, 0x27d); + regval &= 0xff00; + regval |= pi->nphy_crsminpwr[0]; + write_phy_reg(pi, 0x27d, regval); + + regval = read_phy_reg(pi, 0x280); + regval &= 0xff00; + regval |= pi->nphy_crsminpwr[1]; + write_phy_reg(pi, 0x280, regval); + + regval = read_phy_reg(pi, 0x283); + regval &= 0xff00; + regval |= pi->nphy_crsminpwr[2]; + write_phy_reg(pi, 0x283, regval); + + pi->nphy_crsminpwr_adjusted = false; + } + } + } +} + +static void wlc_phy_spurwar_nphy(struct brcms_phy *pi) +{ + u16 cur_channel = 0; + int nphy_adj_tone_id_buf[] = { 57, 58 }; + u32 nphy_adj_noise_var_buf[] = { 0x3ff, 0x3ff }; + bool isAdjustNoiseVar = false; + uint numTonesAdjust = 0; + u32 tempval = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + cur_channel = CHSPEC_CHANNEL(pi->radio_chanspec); + + if (pi->nphy_gband_spurwar_en) { + + wlc_phy_adjust_rx_analpfbw_nphy( + pi, + NPHY_ANARXLPFBW_REDUCTIONFACT); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if ((cur_channel == 11) + && CHSPEC_IS40(pi->radio_chanspec)) + wlc_phy_adjust_min_noisevar_nphy( + pi, 2, + nphy_adj_tone_id_buf, + nphy_adj_noise_var_buf); + else + wlc_phy_adjust_min_noisevar_nphy(pi, 0, + NULL, + NULL); + } + + wlc_phy_adjust_crsminpwr_nphy(pi, + NPHY_ADJUSTED_MINCRSPOWER); + } + + if ((pi->nphy_gband_spurwar2_en) + && CHSPEC_IS2G(pi->radio_chanspec)) { + + if (CHSPEC_IS40(pi->radio_chanspec)) { + switch (cur_channel) { + case 3: + nphy_adj_tone_id_buf[0] = 57; + nphy_adj_tone_id_buf[1] = 58; + nphy_adj_noise_var_buf[0] = 0x22f; + nphy_adj_noise_var_buf[1] = 0x25f; + isAdjustNoiseVar = true; + break; + case 4: + nphy_adj_tone_id_buf[0] = 41; + nphy_adj_tone_id_buf[1] = 42; + nphy_adj_noise_var_buf[0] = 0x22f; + nphy_adj_noise_var_buf[1] = 0x25f; + isAdjustNoiseVar = true; + break; + case 5: + nphy_adj_tone_id_buf[0] = 25; + nphy_adj_tone_id_buf[1] = 26; + nphy_adj_noise_var_buf[0] = 0x24f; + nphy_adj_noise_var_buf[1] = 0x25f; + isAdjustNoiseVar = true; + break; + case 6: + nphy_adj_tone_id_buf[0] = 9; + nphy_adj_tone_id_buf[1] = 10; + nphy_adj_noise_var_buf[0] = 0x22f; + nphy_adj_noise_var_buf[1] = 0x24f; + isAdjustNoiseVar = true; + break; + case 7: + nphy_adj_tone_id_buf[0] = 121; + nphy_adj_tone_id_buf[1] = 122; + nphy_adj_noise_var_buf[0] = 0x18f; + nphy_adj_noise_var_buf[1] = 0x24f; + isAdjustNoiseVar = true; + break; + case 8: + nphy_adj_tone_id_buf[0] = 105; + nphy_adj_tone_id_buf[1] = 106; + nphy_adj_noise_var_buf[0] = 0x22f; + nphy_adj_noise_var_buf[1] = 0x25f; + isAdjustNoiseVar = true; + break; + case 9: + nphy_adj_tone_id_buf[0] = 89; + nphy_adj_tone_id_buf[1] = 90; + nphy_adj_noise_var_buf[0] = 0x22f; + nphy_adj_noise_var_buf[1] = 0x24f; + isAdjustNoiseVar = true; + break; + case 10: + nphy_adj_tone_id_buf[0] = 73; + nphy_adj_tone_id_buf[1] = 74; + nphy_adj_noise_var_buf[0] = 0x22f; + nphy_adj_noise_var_buf[1] = 0x24f; + isAdjustNoiseVar = true; + break; + default: + isAdjustNoiseVar = false; + break; + } + } + + if (isAdjustNoiseVar) { + numTonesAdjust = sizeof(nphy_adj_tone_id_buf) / + sizeof(nphy_adj_tone_id_buf[0]); + + wlc_phy_adjust_min_noisevar_nphy( + pi, + numTonesAdjust, + nphy_adj_tone_id_buf, + nphy_adj_noise_var_buf); + + tempval = 0; + + } else { + wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL, + NULL); + } + } + + if ((pi->nphy_aband_spurwar_en) && + (CHSPEC_IS5G(pi->radio_chanspec))) { + switch (cur_channel) { + case 54: + nphy_adj_tone_id_buf[0] = 32; + nphy_adj_noise_var_buf[0] = 0x25f; + break; + case 38: + case 102: + case 118: + nphy_adj_tone_id_buf[0] = 0; + nphy_adj_noise_var_buf[0] = 0x0; + break; + case 134: + nphy_adj_tone_id_buf[0] = 32; + nphy_adj_noise_var_buf[0] = 0x21f; + break; + case 151: + nphy_adj_tone_id_buf[0] = 16; + nphy_adj_noise_var_buf[0] = 0x23f; + break; + case 153: + case 161: + nphy_adj_tone_id_buf[0] = 48; + nphy_adj_noise_var_buf[0] = 0x23f; + break; + default: + nphy_adj_tone_id_buf[0] = 0; + nphy_adj_noise_var_buf[0] = 0x0; + break; + } + + if (nphy_adj_tone_id_buf[0] + && nphy_adj_noise_var_buf[0]) + wlc_phy_adjust_min_noisevar_nphy( + pi, 1, + nphy_adj_tone_id_buf, + nphy_adj_noise_var_buf); + else + wlc_phy_adjust_min_noisevar_nphy(pi, 0, NULL, + NULL); + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); + } +} + +void wlc_phy_init_nphy(struct brcms_phy *pi) +{ + u16 val; + u16 clip1_ths[2]; + struct nphy_txgains target_gain; + u8 tx_pwr_ctrl_state; + bool do_nphy_cal = false; + uint core; + uint origidx, intr_val; + struct d11regs __iomem *regs; + u32 d11_clk_ctl_st; + bool do_rssi_cal = false; + + core = 0; + + if (!(pi->measure_hold & PHY_HOLD_FOR_SCAN)) + pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; + + if ((ISNPHY(pi)) && (NREV_GE(pi->pubpi.phy_rev, 5)) && + ((pi->sh->chippkg == BCM4717_PKG_ID) || + (pi->sh->chippkg == BCM4718_PKG_ID))) { + if ((pi->sh->boardflags & BFL_EXTLNA) && + (CHSPEC_IS2G(pi->radio_chanspec))) + ai_corereg(pi->sh->sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol), + 0x40, 0x40); + } + + if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) && + CHSPEC_IS40(pi->radio_chanspec)) { + + regs = (struct d11regs __iomem *) + ai_switch_core(pi->sh->sih, + D11_CORE_ID, &origidx, + &intr_val); + d11_clk_ctl_st = R_REG(®s->clk_ctl_st); + AND_REG(®s->clk_ctl_st, + ~(CCS_FORCEHT | CCS_HTAREQ)); + + W_REG(®s->clk_ctl_st, d11_clk_ctl_st); + + ai_restore_core(pi->sh->sih, origidx, intr_val); + } + + pi->use_int_tx_iqlo_cal_nphy = + (PHY_IPA(pi) || + (NREV_GE(pi->pubpi.phy_rev, 7) || + (NREV_GE(pi->pubpi.phy_rev, 5) + && pi->sh->boardflags2 & BFL2_INTERNDET_TXIQCAL))); + + pi->internal_tx_iqlo_cal_tapoff_intpa_nphy = false; + + pi->nphy_deaf_count = 0; + + wlc_phy_tbl_init_nphy(pi); + + pi->nphy_crsminpwr_adjusted = false; + pi->nphy_noisevars_adjusted = false; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + write_phy_reg(pi, 0xe7, 0); + write_phy_reg(pi, 0xec, 0); + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + write_phy_reg(pi, 0x342, 0); + write_phy_reg(pi, 0x343, 0); + write_phy_reg(pi, 0x346, 0); + write_phy_reg(pi, 0x347, 0); + } + write_phy_reg(pi, 0xe5, 0); + write_phy_reg(pi, 0xe6, 0); + } else { + write_phy_reg(pi, 0xec, 0); + } + + write_phy_reg(pi, 0x91, 0); + write_phy_reg(pi, 0x92, 0); + if (NREV_LT(pi->pubpi.phy_rev, 6)) { + write_phy_reg(pi, 0x93, 0); + write_phy_reg(pi, 0x94, 0); + } + + and_phy_reg(pi, 0xa1, ~3); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + write_phy_reg(pi, 0x8f, 0); + write_phy_reg(pi, 0xa5, 0); + } else { + write_phy_reg(pi, 0xa5, 0); + } + + if (NREV_IS(pi->pubpi.phy_rev, 2)) + mod_phy_reg(pi, 0xdc, 0x00ff, 0x3b); + else if (NREV_LT(pi->pubpi.phy_rev, 2)) + mod_phy_reg(pi, 0xdc, 0x00ff, 0x40); + + write_phy_reg(pi, 0x203, 32); + write_phy_reg(pi, 0x201, 32); + + if (pi->sh->boardflags2 & BFL2_SKWRKFEM_BRD) + write_phy_reg(pi, 0x20d, 160); + else + write_phy_reg(pi, 0x20d, 184); + + write_phy_reg(pi, 0x13a, 200); + + write_phy_reg(pi, 0x70, 80); + + write_phy_reg(pi, 0x1ff, 48); + + if (NREV_LT(pi->pubpi.phy_rev, 8)) + wlc_phy_update_mimoconfig_nphy(pi, pi->n_preamble_override); + + wlc_phy_stf_chain_upd_nphy(pi); + + if (NREV_LT(pi->pubpi.phy_rev, 2)) { + write_phy_reg(pi, 0x180, 0xaa8); + write_phy_reg(pi, 0x181, 0x9a4); + } + + if (PHY_IPA(pi)) { + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (1) << 0); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x298 : + 0x29c, (0x1ff << 7), + (pi->nphy_papd_epsilon_offset[core]) << 7); + + } + + wlc_phy_ipa_set_tx_digi_filts_nphy(pi); + } else if (NREV_GE(pi->pubpi.phy_rev, 5)) { + wlc_phy_extpa_set_tx_digi_filts_nphy(pi); + } + + wlc_phy_workarounds_nphy(pi); + + wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON); + + val = read_phy_reg(pi, 0x01); + write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA); + write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA)); + wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF); + + wlapi_bmac_macphyclk_set(pi->sh->physhim, ON); + + wlc_phy_pa_override_nphy(pi, OFF); + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX); + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); + wlc_phy_pa_override_nphy(pi, ON); + + wlc_phy_classifier_nphy(pi, 0, 0); + wlc_phy_clip_det_nphy(pi, 0, clip1_ths); + + if (CHSPEC_IS2G(pi->radio_chanspec)) + wlc_phy_bphy_init_nphy(pi); + + tx_pwr_ctrl_state = pi->nphy_txpwrctrl; + wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF); + + wlc_phy_txpwr_fixpower_nphy(pi); + + wlc_phy_txpwrctrl_idle_tssi_nphy(pi); + + wlc_phy_txpwrctrl_pwr_setup_nphy(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + u32 *tx_pwrctrl_tbl = NULL; + u16 idx; + s16 pga_gn = 0; + s16 pad_gn = 0; + s32 rfpwr_offset; + + if (PHY_IPA(pi)) { + tx_pwrctrl_tbl = wlc_phy_get_ipa_gaintbl_nphy(pi); + } else { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (NREV_IS(pi->pubpi.phy_rev, 3)) + tx_pwrctrl_tbl = + nphy_tpc_5GHz_txgain_rev3; + else if (NREV_IS(pi->pubpi.phy_rev, 4)) + tx_pwrctrl_tbl = + (pi->srom_fem5g.extpagain == + 3) ? + nphy_tpc_5GHz_txgain_HiPwrEPA : + nphy_tpc_5GHz_txgain_rev4; + else + tx_pwrctrl_tbl = + nphy_tpc_5GHz_txgain_rev5; + } else { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (pi->pubpi.radiorev == 5) + tx_pwrctrl_tbl = + nphy_tpc_txgain_epa_2057rev5; + else if (pi->pubpi.radiorev == 3) + tx_pwrctrl_tbl = + nphy_tpc_txgain_epa_2057rev3; + } else { + if (NREV_GE(pi->pubpi.phy_rev, 5) && + (pi->srom_fem2g.extpagain == 3)) + tx_pwrctrl_tbl = + nphy_tpc_txgain_HiPwrEPA; + else + tx_pwrctrl_tbl = + nphy_tpc_txgain_rev3; + } + } + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128, + 192, 32, tx_pwrctrl_tbl); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128, + 192, 32, tx_pwrctrl_tbl); + + pi->nphy_gmval = (u16) ((*tx_pwrctrl_tbl >> 16) & 0x7000); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + for (idx = 0; idx < 128; idx++) { + pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf; + pad_gn = (tx_pwrctrl_tbl[idx] >> 19) & 0x1f; + rfpwr_offset = get_rf_pwr_offset(pi, pga_gn, + pad_gn); + wlc_phy_table_write_nphy( + pi, + NPHY_TBL_ID_CORE1TXPWRCTL, + 1, 576 + idx, 32, + &rfpwr_offset); + wlc_phy_table_write_nphy( + pi, + NPHY_TBL_ID_CORE2TXPWRCTL, + 1, 576 + idx, 32, + &rfpwr_offset); + } + } else { + + for (idx = 0; idx < 128; idx++) { + pga_gn = (tx_pwrctrl_tbl[idx] >> 24) & 0xf; + if (CHSPEC_IS2G(pi->radio_chanspec)) + rfpwr_offset = (s16) + nphy_papd_pga_gain_delta_ipa_2g + [pga_gn]; + else + rfpwr_offset = (s16) + nphy_papd_pga_gain_delta_ipa_5g + [pga_gn]; + + wlc_phy_table_write_nphy( + pi, + NPHY_TBL_ID_CORE1TXPWRCTL, + 1, 576 + idx, 32, + &rfpwr_offset); + wlc_phy_table_write_nphy( + pi, + NPHY_TBL_ID_CORE2TXPWRCTL, + 1, 576 + idx, 32, + &rfpwr_offset); + } + + } + } else { + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 128, + 192, 32, nphy_tpc_txgain); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 128, + 192, 32, nphy_tpc_txgain); + } + + if (pi->sh->phyrxchain != 0x3) + wlc_phy_rxcore_setstate_nphy((struct brcms_phy_pub *) pi, + pi->sh->phyrxchain); + + if (PHY_PERICAL_MPHASE_PENDING(pi)) + wlc_phy_cal_perical_mphase_restart(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + do_rssi_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ? + (pi->nphy_rssical_chanspec_2G == 0) : + (pi->nphy_rssical_chanspec_5G == 0); + + if (do_rssi_cal) + wlc_phy_rssi_cal_nphy(pi); + else + wlc_phy_restore_rssical_nphy(pi); + } else { + wlc_phy_rssi_cal_nphy(pi); + } + + if (!SCAN_RM_IN_PROGRESS(pi)) + do_nphy_cal = (CHSPEC_IS2G(pi->radio_chanspec)) ? + (pi->nphy_iqcal_chanspec_2G == 0) : + (pi->nphy_iqcal_chanspec_5G == 0); + + if (!pi->do_initcal) + do_nphy_cal = false; + + if (do_nphy_cal) { + + target_gain = wlc_phy_get_tx_gain_nphy(pi); + + if (pi->antsel_type == ANTSEL_2x3) + wlc_phy_antsel_init((struct brcms_phy_pub *) pi, + true); + + if (pi->nphy_perical != PHY_PERICAL_MPHASE) { + wlc_phy_rssi_cal_nphy(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + pi->nphy_cal_orig_pwr_idx[0] = + pi->nphy_txpwrindex[PHY_CORE_0] + . + index_internal; + pi->nphy_cal_orig_pwr_idx[1] = + pi->nphy_txpwrindex[PHY_CORE_1] + . + index_internal; + + wlc_phy_precal_txgain_nphy(pi); + target_gain = + wlc_phy_get_tx_gain_nphy(pi); + } + + if (wlc_phy_cal_txiqlo_nphy + (pi, target_gain, true, + false) == 0) { + if (wlc_phy_cal_rxiq_nphy + (pi, target_gain, 2, + false) == 0) + wlc_phy_savecal_nphy(pi); + + } + } else if (pi->mphase_cal_phase_id == + MPHASE_CAL_STATE_IDLE) { + wlc_phy_cal_perical((struct brcms_phy_pub *) pi, + PHY_PERICAL_PHYINIT); + } + } else { + wlc_phy_restorecal_nphy(pi); + } + + wlc_phy_txpwrctrl_coeff_setup_nphy(pi); + + wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state); + + wlc_phy_nphy_tkip_rifs_war(pi, pi->sh->_rifs_phy); + + if (NREV_GE(pi->pubpi.phy_rev, 3) && NREV_LE(pi->pubpi.phy_rev, 6)) + + write_phy_reg(pi, 0x70, 50); + + wlc_phy_txlpfbw_nphy(pi); + + wlc_phy_spurwar_nphy(pi); + +} + +static void wlc_phy_resetcca_nphy(struct brcms_phy *pi) +{ + u16 val; + + wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON); + + val = read_phy_reg(pi, 0x01); + write_phy_reg(pi, 0x01, val | BBCFG_RESETCCA); + udelay(1); + write_phy_reg(pi, 0x01, val & (~BBCFG_RESETCCA)); + + wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF); + + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); +} + +void wlc_phy_pa_override_nphy(struct brcms_phy *pi, bool en) +{ + u16 rfctrlintc_override_val; + + if (!en) { + + pi->rfctrlIntc1_save = read_phy_reg(pi, 0x91); + pi->rfctrlIntc2_save = read_phy_reg(pi, 0x92); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + rfctrlintc_override_val = 0x1480; + else if (NREV_GE(pi->pubpi.phy_rev, 3)) + rfctrlintc_override_val = + CHSPEC_IS5G(pi->radio_chanspec) ? 0x600 : 0x480; + else + rfctrlintc_override_val = + CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 : 0x120; + + write_phy_reg(pi, 0x91, rfctrlintc_override_val); + write_phy_reg(pi, 0x92, rfctrlintc_override_val); + } else { + write_phy_reg(pi, 0x91, pi->rfctrlIntc1_save); + write_phy_reg(pi, 0x92, pi->rfctrlIntc2_save); + } + +} + +void wlc_phy_stf_chain_upd_nphy(struct brcms_phy *pi) +{ + + u16 txrx_chain = + (NPHY_RfseqCoreActv_TxRxChain0 | NPHY_RfseqCoreActv_TxRxChain1); + bool CoreActv_override = false; + + if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN0) { + txrx_chain = NPHY_RfseqCoreActv_TxRxChain0; + CoreActv_override = true; + + if (NREV_LE(pi->pubpi.phy_rev, 2)) + and_phy_reg(pi, 0xa0, ~0x20); + } else if (pi->nphy_txrx_chain == BRCMS_N_TXRX_CHAIN1) { + txrx_chain = NPHY_RfseqCoreActv_TxRxChain1; + CoreActv_override = true; + + if (NREV_LE(pi->pubpi.phy_rev, 2)) + or_phy_reg(pi, 0xa0, 0x20); + } + + mod_phy_reg(pi, 0xa2, ((0xf << 0) | (0xf << 4)), txrx_chain); + + if (CoreActv_override) { + pi->nphy_perical = PHY_PERICAL_DISABLE; + or_phy_reg(pi, 0xa1, NPHY_RfseqMode_CoreActv_override); + } else { + pi->nphy_perical = PHY_PERICAL_MPHASE; + and_phy_reg(pi, 0xa1, ~NPHY_RfseqMode_CoreActv_override); + } +} + +void wlc_phy_rxcore_setstate_nphy(struct brcms_phy_pub *pih, u8 rxcore_bitmask) +{ + u16 regval; + u16 tbl_buf[16]; + uint i; + struct brcms_phy *pi = (struct brcms_phy *) pih; + u16 tbl_opcode; + bool suspend; + + pi->sh->phyrxchain = rxcore_bitmask; + + if (!pi->sh->clk) + return; + + suspend = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!suspend) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + regval = read_phy_reg(pi, 0xa2); + regval &= ~(0xf << 4); + regval |= ((u16) (rxcore_bitmask & 0x3)) << 4; + write_phy_reg(pi, 0xa2, regval); + + if ((rxcore_bitmask & 0x3) != 0x3) { + + write_phy_reg(pi, 0x20e, 1); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (pi->rx2tx_biasentry == -1) { + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, + ARRAY_SIZE(tbl_buf), 80, + 16, tbl_buf); + + for (i = 0; i < ARRAY_SIZE(tbl_buf); i++) { + if (tbl_buf[i] == + NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS) { + pi->rx2tx_biasentry = (u8) i; + tbl_opcode = + NPHY_REV3_RFSEQ_CMD_NOP; + wlc_phy_table_write_nphy( + pi, + NPHY_TBL_ID_RFSEQ, + 1, i, + 16, + &tbl_opcode); + break; + } else if (tbl_buf[i] == + NPHY_REV3_RFSEQ_CMD_END) + break; + } + } + } + } else { + + write_phy_reg(pi, 0x20e, 30); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (pi->rx2tx_biasentry != -1) { + tbl_opcode = NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, + 1, pi->rx2tx_biasentry, + 16, &tbl_opcode); + pi->rx2tx_biasentry = -1; + } + } + } + + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); + + if (!suspend) + wlapi_enable_mac(pi->sh->physhim); +} + +u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih) +{ + u16 regval, rxen_bits; + struct brcms_phy *pi = (struct brcms_phy *) pih; + + regval = read_phy_reg(pi, 0xa2); + rxen_bits = (regval >> 4) & 0xf; + + return (u8) rxen_bits; +} + +bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pi) +{ + return PHY_IPA(pi); +} + +void wlc_phy_cal_init_nphy(struct brcms_phy *pi) +{ +} + +static void wlc_phy_radio_preinit_205x(struct brcms_phy *pi) +{ + + and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU); + and_phy_reg(pi, 0x78, RFCC_OE_POR_FORCE); + + or_phy_reg(pi, 0x78, ~RFCC_OE_POR_FORCE); + or_phy_reg(pi, 0x78, RFCC_CHIP0_PU); + +} + +static void wlc_phy_radio_init_2057(struct brcms_phy *pi) +{ + struct radio_20xx_regs *regs_2057_ptr = NULL; + + if (NREV_IS(pi->pubpi.phy_rev, 7)) { + regs_2057_ptr = regs_2057_rev4; + } else if (NREV_IS(pi->pubpi.phy_rev, 8) + || NREV_IS(pi->pubpi.phy_rev, 9)) { + switch (pi->pubpi.radiorev) { + case 5: + + if (pi->pubpi.radiover == 0x0) + regs_2057_ptr = regs_2057_rev5; + else if (pi->pubpi.radiover == 0x1) + regs_2057_ptr = regs_2057_rev5v1; + else + break; + + case 7: + + regs_2057_ptr = regs_2057_rev7; + break; + + case 8: + + regs_2057_ptr = regs_2057_rev8; + break; + + default: + break; + } + } + + wlc_phy_init_radio_regs_allbands(pi, regs_2057_ptr); +} + +static u16 wlc_phy_radio205x_rcal(struct brcms_phy *pi) +{ + u16 rcal_reg = 0; + int i; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + if (pi->pubpi.radiorev == 5) { + + and_phy_reg(pi, 0x342, ~(0x1 << 1)); + + udelay(10); + + mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x1); + mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2, + 0x1); + } + mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x1); + + udelay(10); + + mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x3, 0x3); + + for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { + rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS); + if (rcal_reg & 0x1) + break; + + udelay(100); + } + + if (WARN(i == MAX_205x_RCAL_WAITLOOPS, + "HW error: radio calib2")) + return 0; + + mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x2, 0x0); + + rcal_reg = read_radio_reg(pi, RADIO_2057_RCAL_STATUS) & 0x3e; + + mod_radio_reg(pi, RADIO_2057_RCAL_CONFIG, 0x1, 0x0); + if (pi->pubpi.radiorev == 5) { + + mod_radio_reg(pi, RADIO_2057_IQTEST_SEL_PU, 0x1, 0x0); + mod_radio_reg(pi, RADIO_2057v7_IQTEST_SEL_PU2, 0x2, + 0x0); + } + + if ((pi->pubpi.radiorev <= 4) || (pi->pubpi.radiorev == 6)) { + + mod_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x3c, + rcal_reg); + mod_radio_reg(pi, RADIO_2057_BANDGAP_RCAL_TRIM, 0xf0, + rcal_reg << 2); + } + + } else if (NREV_IS(pi->pubpi.phy_rev, 3)) { + u16 savereg; + + savereg = + read_radio_reg( + pi, + RADIO_2056_SYN_PLL_MAST2 | + RADIO_2056_SYN); + write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN, + savereg | 0x7); + udelay(10); + + write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN, + 0x1); + udelay(10); + + write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN, + 0x9); + + for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { + rcal_reg = read_radio_reg( + pi, + RADIO_2056_SYN_RCAL_CODE_OUT | + RADIO_2056_SYN); + if (rcal_reg & 0x80) + break; + + udelay(100); + } + + if (WARN(i == MAX_205x_RCAL_WAITLOOPS, + "HW error: radio calib3")) + return 0; + + write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN, + 0x1); + + rcal_reg = + read_radio_reg(pi, + RADIO_2056_SYN_RCAL_CODE_OUT | + RADIO_2056_SYN); + + write_radio_reg(pi, RADIO_2056_SYN_RCAL_MASTER | RADIO_2056_SYN, + 0x0); + + write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2 | RADIO_2056_SYN, + savereg); + + return rcal_reg & 0x1f; + } + return rcal_reg & 0x3e; +} + +static u16 wlc_phy_radio2057_rccal(struct brcms_phy *pi) +{ + u16 rccal_valid; + int i; + bool chip43226_6362A0; + + chip43226_6362A0 = ((pi->pubpi.radiorev == 3) + || (pi->pubpi.radiorev == 4) + || (pi->pubpi.radiorev == 6)); + + rccal_valid = 0; + if (chip43226_6362A0) { + write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x61); + write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xc0); + } else { + write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x61); + + write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xe9); + } + write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e); + write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55); + + for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { + rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP); + if (rccal_valid & 0x2) + break; + + udelay(500); + } + + write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15); + + rccal_valid = 0; + if (chip43226_6362A0) { + write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x69); + write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0); + } else { + write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x69); + + write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xd5); + } + write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e); + write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55); + + for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { + rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP); + if (rccal_valid & 0x2) + break; + + udelay(500); + } + + write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15); + + rccal_valid = 0; + if (chip43226_6362A0) { + write_radio_reg(pi, RADIO_2057_RCCAL_MASTER, 0x73); + + write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x28); + write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0xb0); + } else { + write_radio_reg(pi, RADIO_2057v7_RCCAL_MASTER, 0x73); + write_radio_reg(pi, RADIO_2057_RCCAL_X1, 0x6e); + write_radio_reg(pi, RADIO_2057_RCCAL_TRC0, 0x99); + } + write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x55); + + for (i = 0; i < MAX_205x_RCAL_WAITLOOPS; i++) { + rccal_valid = read_radio_reg(pi, RADIO_2057_RCCAL_DONE_OSCCAP); + if (rccal_valid & 0x2) + break; + + udelay(500); + } + + if (WARN(!(rccal_valid & 0x2), "HW error: radio calib4")) + return 0; + + write_radio_reg(pi, RADIO_2057_RCCAL_START_R1_Q1_P1, 0x15); + + return rccal_valid; +} + +static void wlc_phy_radio_postinit_2057(struct brcms_phy *pi) +{ + + mod_radio_reg(pi, RADIO_2057_XTALPUOVR_PINCTRL, 0x1, 0x1); + + mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x78); + mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x80); + mdelay(2); + mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x78, 0x0); + mod_radio_reg(pi, RADIO_2057_XTAL_CONFIG2, 0x80, 0x0); + + if (pi->phy_init_por) { + wlc_phy_radio205x_rcal(pi); + wlc_phy_radio2057_rccal(pi); + } + + mod_radio_reg(pi, RADIO_2057_RFPLL_MASTER, 0x8, 0x0); +} + +static void wlc_phy_radio_init_2056(struct brcms_phy *pi) +{ + const struct radio_regs *regs_SYN_2056_ptr = NULL; + const struct radio_regs *regs_TX_2056_ptr = NULL; + const struct radio_regs *regs_RX_2056_ptr = NULL; + + if (NREV_IS(pi->pubpi.phy_rev, 3)) { + regs_SYN_2056_ptr = regs_SYN_2056; + regs_TX_2056_ptr = regs_TX_2056; + regs_RX_2056_ptr = regs_RX_2056; + } else if (NREV_IS(pi->pubpi.phy_rev, 4)) { + regs_SYN_2056_ptr = regs_SYN_2056_A1; + regs_TX_2056_ptr = regs_TX_2056_A1; + regs_RX_2056_ptr = regs_RX_2056_A1; + } else { + switch (pi->pubpi.radiorev) { + case 5: + regs_SYN_2056_ptr = regs_SYN_2056_rev5; + regs_TX_2056_ptr = regs_TX_2056_rev5; + regs_RX_2056_ptr = regs_RX_2056_rev5; + break; + + case 6: + regs_SYN_2056_ptr = regs_SYN_2056_rev6; + regs_TX_2056_ptr = regs_TX_2056_rev6; + regs_RX_2056_ptr = regs_RX_2056_rev6; + break; + + case 7: + case 9: + regs_SYN_2056_ptr = regs_SYN_2056_rev7; + regs_TX_2056_ptr = regs_TX_2056_rev7; + regs_RX_2056_ptr = regs_RX_2056_rev7; + break; + + case 8: + regs_SYN_2056_ptr = regs_SYN_2056_rev8; + regs_TX_2056_ptr = regs_TX_2056_rev8; + regs_RX_2056_ptr = regs_RX_2056_rev8; + break; + + case 11: + regs_SYN_2056_ptr = regs_SYN_2056_rev11; + regs_TX_2056_ptr = regs_TX_2056_rev11; + regs_RX_2056_ptr = regs_RX_2056_rev11; + break; + + default: + break; + } + } + + wlc_phy_init_radio_regs(pi, regs_SYN_2056_ptr, (u16) RADIO_2056_SYN); + + wlc_phy_init_radio_regs(pi, regs_TX_2056_ptr, (u16) RADIO_2056_TX0); + + wlc_phy_init_radio_regs(pi, regs_TX_2056_ptr, (u16) RADIO_2056_TX1); + + wlc_phy_init_radio_regs(pi, regs_RX_2056_ptr, (u16) RADIO_2056_RX0); + + wlc_phy_init_radio_regs(pi, regs_RX_2056_ptr, (u16) RADIO_2056_RX1); +} + +static void wlc_phy_radio_postinit_2056(struct brcms_phy *pi) +{ + mod_radio_reg(pi, RADIO_2056_SYN_COM_CTRL, 0xb, 0xb); + + mod_radio_reg(pi, RADIO_2056_SYN_COM_PU, 0x2, 0x2); + mod_radio_reg(pi, RADIO_2056_SYN_COM_RESET, 0x2, 0x2); + udelay(1000); + mod_radio_reg(pi, RADIO_2056_SYN_COM_RESET, 0x2, 0x0); + + if ((pi->sh->boardflags2 & BFL2_LEGACY) + || (pi->sh->boardflags2 & BFL2_XTALBUFOUTEN)) + mod_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2, 0xf4, 0x0); + else + mod_radio_reg(pi, RADIO_2056_SYN_PLL_MAST2, 0xfc, 0x0); + + mod_radio_reg(pi, RADIO_2056_SYN_RCCAL_CTRL0, 0x1, 0x0); + + if (pi->phy_init_por) + wlc_phy_radio205x_rcal(pi); +} + +static void wlc_phy_radio_preinit_2055(struct brcms_phy *pi) +{ + + and_phy_reg(pi, 0x78, ~RFCC_POR_FORCE); + or_phy_reg(pi, 0x78, RFCC_CHIP0_PU | RFCC_OE_POR_FORCE); + + or_phy_reg(pi, 0x78, RFCC_POR_FORCE); +} + +static void wlc_phy_radio_init_2055(struct brcms_phy *pi) +{ + wlc_phy_init_radio_regs(pi, regs_2055, RADIO_DEFAULT_CORE); +} + +static void wlc_phy_radio_postinit_2055(struct brcms_phy *pi) +{ + + and_radio_reg(pi, RADIO_2055_MASTER_CNTRL1, + ~(RADIO_2055_JTAGCTRL_MASK | RADIO_2055_JTAGSYNC_MASK)); + + if (((pi->sh->sromrev >= 4) + && !(pi->sh->boardflags2 & BFL2_RXBB_INT_REG_DIS)) + || ((pi->sh->sromrev < 4))) { + and_radio_reg(pi, RADIO_2055_CORE1_RXBB_REGULATOR, 0x7F); + and_radio_reg(pi, RADIO_2055_CORE2_RXBB_REGULATOR, 0x7F); + } + + mod_radio_reg(pi, RADIO_2055_RRCCAL_N_OPT_SEL, 0x3F, 0x2C); + write_radio_reg(pi, RADIO_2055_CAL_MISC, 0x3C); + + and_radio_reg(pi, RADIO_2055_CAL_MISC, + ~(RADIO_2055_RRCAL_START | RADIO_2055_RRCAL_RST_N)); + + or_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL, RADIO_2055_CAL_LPO_ENABLE); + + or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_RST_N); + + udelay(1000); + + or_radio_reg(pi, RADIO_2055_CAL_MISC, RADIO_2055_RRCAL_START); + + SPINWAIT(((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) & + RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE), 2000); + + if (WARN((read_radio_reg(pi, RADIO_2055_CAL_COUNTER_OUT2) & + RADIO_2055_RCAL_DONE) != RADIO_2055_RCAL_DONE, + "HW error: radio calibration1\n")) + return; + + and_radio_reg(pi, RADIO_2055_CAL_LPO_CNTRL, + ~(RADIO_2055_CAL_LPO_ENABLE)); + + wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, pi->radio_chanspec); + + write_radio_reg(pi, RADIO_2055_CORE1_RXBB_LPF, 9); + write_radio_reg(pi, RADIO_2055_CORE2_RXBB_LPF, 9); + + write_radio_reg(pi, RADIO_2055_CORE1_RXBB_MIDAC_HIPAS, 0x83); + write_radio_reg(pi, RADIO_2055_CORE2_RXBB_MIDAC_HIPAS, 0x83); + + mod_radio_reg(pi, RADIO_2055_CORE1_LNA_GAINBST, + RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE); + mod_radio_reg(pi, RADIO_2055_CORE2_LNA_GAINBST, + RADIO_2055_GAINBST_VAL_MASK, RADIO_2055_GAINBST_CODE); + if (pi->nphy_gain_boost) { + and_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1, + ~(RADIO_2055_GAINBST_DISABLE)); + and_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1, + ~(RADIO_2055_GAINBST_DISABLE)); + } else { + or_radio_reg(pi, RADIO_2055_CORE1_RXRF_SPC1, + RADIO_2055_GAINBST_DISABLE); + or_radio_reg(pi, RADIO_2055_CORE2_RXRF_SPC1, + RADIO_2055_GAINBST_DISABLE); + } + + udelay(2); +} + +void wlc_phy_switch_radio_nphy(struct brcms_phy *pi, bool on) +{ + if (on) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (!pi->radio_is_on) { + wlc_phy_radio_preinit_205x(pi); + wlc_phy_radio_init_2057(pi); + wlc_phy_radio_postinit_2057(pi); + } + + wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, + pi->radio_chanspec); + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + wlc_phy_radio_preinit_205x(pi); + wlc_phy_radio_init_2056(pi); + wlc_phy_radio_postinit_2056(pi); + + wlc_phy_chanspec_set((struct brcms_phy_pub *) pi, + pi->radio_chanspec); + } else { + wlc_phy_radio_preinit_2055(pi); + wlc_phy_radio_init_2055(pi); + wlc_phy_radio_postinit_2055(pi); + } + + pi->radio_is_on = true; + + } else { + + if (NREV_GE(pi->pubpi.phy_rev, 3) + && NREV_LT(pi->pubpi.phy_rev, 7)) { + and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU); + mod_radio_reg(pi, RADIO_2056_SYN_COM_PU, 0x2, 0x0); + + write_radio_reg(pi, + RADIO_2056_TX_PADA_BOOST_TUNE | + RADIO_2056_TX0, 0); + write_radio_reg(pi, + RADIO_2056_TX_PADG_BOOST_TUNE | + RADIO_2056_TX0, 0); + write_radio_reg(pi, + RADIO_2056_TX_PGAA_BOOST_TUNE | + RADIO_2056_TX0, 0); + write_radio_reg(pi, + RADIO_2056_TX_PGAG_BOOST_TUNE | + RADIO_2056_TX0, 0); + mod_radio_reg(pi, + RADIO_2056_TX_MIXA_BOOST_TUNE | + RADIO_2056_TX0, 0xf0, 0); + write_radio_reg(pi, + RADIO_2056_TX_MIXG_BOOST_TUNE | + RADIO_2056_TX0, 0); + + write_radio_reg(pi, + RADIO_2056_TX_PADA_BOOST_TUNE | + RADIO_2056_TX1, 0); + write_radio_reg(pi, + RADIO_2056_TX_PADG_BOOST_TUNE | + RADIO_2056_TX1, 0); + write_radio_reg(pi, + RADIO_2056_TX_PGAA_BOOST_TUNE | + RADIO_2056_TX1, 0); + write_radio_reg(pi, + RADIO_2056_TX_PGAG_BOOST_TUNE | + RADIO_2056_TX1, 0); + mod_radio_reg(pi, + RADIO_2056_TX_MIXA_BOOST_TUNE | + RADIO_2056_TX1, 0xf0, 0); + write_radio_reg(pi, + RADIO_2056_TX_MIXG_BOOST_TUNE | + RADIO_2056_TX1, 0); + + pi->radio_is_on = false; + } + + if (NREV_GE(pi->pubpi.phy_rev, 8)) { + and_phy_reg(pi, 0x78, ~RFCC_CHIP0_PU); + pi->radio_is_on = false; + } + + } +} + +static bool +wlc_phy_chan2freq_nphy(struct brcms_phy *pi, uint channel, int *f, + const struct chan_info_nphy_radio2057 **t0, + const struct chan_info_nphy_radio205x **t1, + const struct chan_info_nphy_radio2057_rev5 **t2, + const struct chan_info_nphy_2055 **t3) +{ + uint i; + const struct chan_info_nphy_radio2057 *chan_info_tbl_p_0 = NULL; + const struct chan_info_nphy_radio205x *chan_info_tbl_p_1 = NULL; + const struct chan_info_nphy_radio2057_rev5 *chan_info_tbl_p_2 = NULL; + u32 tbl_len = 0; + + int freq = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + if (NREV_IS(pi->pubpi.phy_rev, 7)) { + + chan_info_tbl_p_0 = chan_info_nphyrev7_2057_rev4; + tbl_len = ARRAY_SIZE(chan_info_nphyrev7_2057_rev4); + + } else if (NREV_IS(pi->pubpi.phy_rev, 8) + || NREV_IS(pi->pubpi.phy_rev, 9)) { + switch (pi->pubpi.radiorev) { + + case 5: + + if (pi->pubpi.radiover == 0x0) { + + chan_info_tbl_p_2 = + chan_info_nphyrev8_2057_rev5; + tbl_len = ARRAY_SIZE( + chan_info_nphyrev8_2057_rev5); + + } else if (pi->pubpi.radiover == 0x1) { + + chan_info_tbl_p_2 = + chan_info_nphyrev9_2057_rev5v1; + tbl_len = ARRAY_SIZE( + chan_info_nphyrev9_2057_rev5v1); + + } + break; + + case 7: + chan_info_tbl_p_0 = + chan_info_nphyrev8_2057_rev7; + tbl_len = ARRAY_SIZE( + chan_info_nphyrev8_2057_rev7); + break; + + case 8: + chan_info_tbl_p_0 = + chan_info_nphyrev8_2057_rev8; + tbl_len = ARRAY_SIZE( + chan_info_nphyrev8_2057_rev8); + break; + + default: + break; + } + } else if (NREV_IS(pi->pubpi.phy_rev, 16)) { + + chan_info_tbl_p_0 = chan_info_nphyrev8_2057_rev8; + tbl_len = ARRAY_SIZE(chan_info_nphyrev8_2057_rev8); + } else { + goto fail; + } + + for (i = 0; i < tbl_len; i++) { + if (pi->pubpi.radiorev == 5) { + + if (chan_info_tbl_p_2[i].chan == channel) + break; + } else { + + if (chan_info_tbl_p_0[i].chan == channel) + break; + } + } + + if (i >= tbl_len) + goto fail; + + if (pi->pubpi.radiorev == 5) { + *t2 = &chan_info_tbl_p_2[i]; + freq = chan_info_tbl_p_2[i].freq; + } else { + *t0 = &chan_info_tbl_p_0[i]; + freq = chan_info_tbl_p_0[i].freq; + } + + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (NREV_IS(pi->pubpi.phy_rev, 3)) { + chan_info_tbl_p_1 = chan_info_nphyrev3_2056; + tbl_len = ARRAY_SIZE(chan_info_nphyrev3_2056); + } else if (NREV_IS(pi->pubpi.phy_rev, 4)) { + chan_info_tbl_p_1 = chan_info_nphyrev4_2056_A1; + tbl_len = ARRAY_SIZE(chan_info_nphyrev4_2056_A1); + } else if (NREV_IS(pi->pubpi.phy_rev, 5) + || NREV_IS(pi->pubpi.phy_rev, 6)) { + switch (pi->pubpi.radiorev) { + case 5: + chan_info_tbl_p_1 = chan_info_nphyrev5_2056v5; + tbl_len = ARRAY_SIZE(chan_info_nphyrev5_2056v5); + break; + case 6: + chan_info_tbl_p_1 = chan_info_nphyrev6_2056v6; + tbl_len = ARRAY_SIZE(chan_info_nphyrev6_2056v6); + break; + case 7: + case 9: + chan_info_tbl_p_1 = chan_info_nphyrev5n6_2056v7; + tbl_len = + ARRAY_SIZE(chan_info_nphyrev5n6_2056v7); + break; + case 8: + chan_info_tbl_p_1 = chan_info_nphyrev6_2056v8; + tbl_len = ARRAY_SIZE(chan_info_nphyrev6_2056v8); + break; + case 11: + chan_info_tbl_p_1 = chan_info_nphyrev6_2056v11; + tbl_len = ARRAY_SIZE( + chan_info_nphyrev6_2056v11); + break; + default: + break; + } + } + + for (i = 0; i < tbl_len; i++) { + if (chan_info_tbl_p_1[i].chan == channel) + break; + } + + if (i >= tbl_len) + goto fail; + + *t1 = &chan_info_tbl_p_1[i]; + freq = chan_info_tbl_p_1[i].freq; + + } else { + for (i = 0; i < ARRAY_SIZE(chan_info_nphy_2055); i++) + if (chan_info_nphy_2055[i].chan == channel) + break; + + if (i >= ARRAY_SIZE(chan_info_nphy_2055)) + goto fail; + + *t3 = &chan_info_nphy_2055[i]; + freq = chan_info_nphy_2055[i].freq; + } + + *f = freq; + return true; + +fail: + *f = WL_CHAN_FREQ_RANGE_2G; + return false; +} + +u8 wlc_phy_get_chan_freq_range_nphy(struct brcms_phy *pi, uint channel) +{ + int freq; + const struct chan_info_nphy_radio2057 *t0 = NULL; + const struct chan_info_nphy_radio205x *t1 = NULL; + const struct chan_info_nphy_radio2057_rev5 *t2 = NULL; + const struct chan_info_nphy_2055 *t3 = NULL; + + if (channel == 0) + channel = CHSPEC_CHANNEL(pi->radio_chanspec); + + wlc_phy_chan2freq_nphy(pi, channel, &freq, &t0, &t1, &t2, &t3); + + if (CHSPEC_IS2G(pi->radio_chanspec)) + return WL_CHAN_FREQ_RANGE_2G; + + if ((freq >= BASE_LOW_5G_CHAN) && (freq < BASE_MID_5G_CHAN)) + return WL_CHAN_FREQ_RANGE_5GL; + else if ((freq >= BASE_MID_5G_CHAN) && (freq < BASE_HIGH_5G_CHAN)) + return WL_CHAN_FREQ_RANGE_5GM; + else + return WL_CHAN_FREQ_RANGE_5GH; +} + +static void +wlc_phy_chanspec_radio2055_setup(struct brcms_phy *pi, + const struct chan_info_nphy_2055 *ci) +{ + + write_radio_reg(pi, RADIO_2055_PLL_REF, ci->RF_pll_ref); + write_radio_reg(pi, RADIO_2055_RF_PLL_MOD0, ci->RF_rf_pll_mod0); + write_radio_reg(pi, RADIO_2055_RF_PLL_MOD1, ci->RF_rf_pll_mod1); + write_radio_reg(pi, RADIO_2055_VCO_CAP_TAIL, ci->RF_vco_cap_tail); + + BRCMS_PHY_WAR_PR51571(pi); + + write_radio_reg(pi, RADIO_2055_VCO_CAL1, ci->RF_vco_cal1); + write_radio_reg(pi, RADIO_2055_VCO_CAL2, ci->RF_vco_cal2); + write_radio_reg(pi, RADIO_2055_PLL_LF_C1, ci->RF_pll_lf_c1); + write_radio_reg(pi, RADIO_2055_PLL_LF_R1, ci->RF_pll_lf_r1); + + BRCMS_PHY_WAR_PR51571(pi); + + write_radio_reg(pi, RADIO_2055_PLL_LF_C2, ci->RF_pll_lf_c2); + write_radio_reg(pi, RADIO_2055_LGBUF_CEN_BUF, ci->RF_lgbuf_cen_buf); + write_radio_reg(pi, RADIO_2055_LGEN_TUNE1, ci->RF_lgen_tune1); + write_radio_reg(pi, RADIO_2055_LGEN_TUNE2, ci->RF_lgen_tune2); + + BRCMS_PHY_WAR_PR51571(pi); + + write_radio_reg(pi, RADIO_2055_CORE1_LGBUF_A_TUNE, + ci->RF_core1_lgbuf_a_tune); + write_radio_reg(pi, RADIO_2055_CORE1_LGBUF_G_TUNE, + ci->RF_core1_lgbuf_g_tune); + write_radio_reg(pi, RADIO_2055_CORE1_RXRF_REG1, ci->RF_core1_rxrf_reg1); + write_radio_reg(pi, RADIO_2055_CORE1_TX_PGA_PAD_TN, + ci->RF_core1_tx_pga_pad_tn); + + BRCMS_PHY_WAR_PR51571(pi); + + write_radio_reg(pi, RADIO_2055_CORE1_TX_MX_BGTRIM, + ci->RF_core1_tx_mx_bgtrim); + write_radio_reg(pi, RADIO_2055_CORE2_LGBUF_A_TUNE, + ci->RF_core2_lgbuf_a_tune); + write_radio_reg(pi, RADIO_2055_CORE2_LGBUF_G_TUNE, + ci->RF_core2_lgbuf_g_tune); + write_radio_reg(pi, RADIO_2055_CORE2_RXRF_REG1, ci->RF_core2_rxrf_reg1); + + BRCMS_PHY_WAR_PR51571(pi); + + write_radio_reg(pi, RADIO_2055_CORE2_TX_PGA_PAD_TN, + ci->RF_core2_tx_pga_pad_tn); + write_radio_reg(pi, RADIO_2055_CORE2_TX_MX_BGTRIM, + ci->RF_core2_tx_mx_bgtrim); + + udelay(50); + + write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x05); + write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x45); + + BRCMS_PHY_WAR_PR51571(pi); + + write_radio_reg(pi, RADIO_2055_VCO_CAL10, 0x65); + + udelay(300); +} + +static void +wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi, + const struct chan_info_nphy_radio205x *ci) +{ + const struct radio_regs *regs_SYN_2056_ptr = NULL; + + write_radio_reg(pi, + RADIO_2056_SYN_PLL_VCOCAL1 | RADIO_2056_SYN, + ci->RF_SYN_pll_vcocal1); + write_radio_reg(pi, RADIO_2056_SYN_PLL_VCOCAL2 | RADIO_2056_SYN, + ci->RF_SYN_pll_vcocal2); + write_radio_reg(pi, RADIO_2056_SYN_PLL_REFDIV | RADIO_2056_SYN, + ci->RF_SYN_pll_refdiv); + write_radio_reg(pi, RADIO_2056_SYN_PLL_MMD2 | RADIO_2056_SYN, + ci->RF_SYN_pll_mmd2); + write_radio_reg(pi, RADIO_2056_SYN_PLL_MMD1 | RADIO_2056_SYN, + ci->RF_SYN_pll_mmd1); + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 | RADIO_2056_SYN, + ci->RF_SYN_pll_loopfilter1); + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | RADIO_2056_SYN, + ci->RF_SYN_pll_loopfilter2); + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER3 | RADIO_2056_SYN, + ci->RF_SYN_pll_loopfilter3); + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER4 | RADIO_2056_SYN, + ci->RF_SYN_pll_loopfilter4); + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER5 | RADIO_2056_SYN, + ci->RF_SYN_pll_loopfilter5); + write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR27 | RADIO_2056_SYN, + ci->RF_SYN_reserved_addr27); + write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR28 | RADIO_2056_SYN, + ci->RF_SYN_reserved_addr28); + write_radio_reg(pi, RADIO_2056_SYN_RESERVED_ADDR29 | RADIO_2056_SYN, + ci->RF_SYN_reserved_addr29); + write_radio_reg(pi, RADIO_2056_SYN_LOGEN_VCOBUF1 | RADIO_2056_SYN, + ci->RF_SYN_logen_VCOBUF1); + write_radio_reg(pi, RADIO_2056_SYN_LOGEN_MIXER2 | RADIO_2056_SYN, + ci->RF_SYN_logen_MIXER2); + write_radio_reg(pi, RADIO_2056_SYN_LOGEN_BUF3 | RADIO_2056_SYN, + ci->RF_SYN_logen_BUF3); + write_radio_reg(pi, RADIO_2056_SYN_LOGEN_BUF4 | RADIO_2056_SYN, + ci->RF_SYN_logen_BUF4); + + write_radio_reg(pi, + RADIO_2056_RX_LNAA_TUNE | RADIO_2056_RX0, + ci->RF_RX0_lnaa_tune); + write_radio_reg(pi, RADIO_2056_RX_LNAG_TUNE | RADIO_2056_RX0, + ci->RF_RX0_lnag_tune); + write_radio_reg(pi, RADIO_2056_TX_INTPAA_BOOST_TUNE | RADIO_2056_TX0, + ci->RF_TX0_intpaa_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_INTPAG_BOOST_TUNE | RADIO_2056_TX0, + ci->RF_TX0_intpag_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_PADA_BOOST_TUNE | RADIO_2056_TX0, + ci->RF_TX0_pada_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_PADG_BOOST_TUNE | RADIO_2056_TX0, + ci->RF_TX0_padg_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_PGAA_BOOST_TUNE | RADIO_2056_TX0, + ci->RF_TX0_pgaa_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_PGAG_BOOST_TUNE | RADIO_2056_TX0, + ci->RF_TX0_pgag_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_MIXA_BOOST_TUNE | RADIO_2056_TX0, + ci->RF_TX0_mixa_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_MIXG_BOOST_TUNE | RADIO_2056_TX0, + ci->RF_TX0_mixg_boost_tune); + + write_radio_reg(pi, + RADIO_2056_RX_LNAA_TUNE | RADIO_2056_RX1, + ci->RF_RX1_lnaa_tune); + write_radio_reg(pi, RADIO_2056_RX_LNAG_TUNE | RADIO_2056_RX1, + ci->RF_RX1_lnag_tune); + write_radio_reg(pi, RADIO_2056_TX_INTPAA_BOOST_TUNE | RADIO_2056_TX1, + ci->RF_TX1_intpaa_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_INTPAG_BOOST_TUNE | RADIO_2056_TX1, + ci->RF_TX1_intpag_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_PADA_BOOST_TUNE | RADIO_2056_TX1, + ci->RF_TX1_pada_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_PADG_BOOST_TUNE | RADIO_2056_TX1, + ci->RF_TX1_padg_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_PGAA_BOOST_TUNE | RADIO_2056_TX1, + ci->RF_TX1_pgaa_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_PGAG_BOOST_TUNE | RADIO_2056_TX1, + ci->RF_TX1_pgag_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_MIXA_BOOST_TUNE | RADIO_2056_TX1, + ci->RF_TX1_mixa_boost_tune); + write_radio_reg(pi, RADIO_2056_TX_MIXG_BOOST_TUNE | RADIO_2056_TX1, + ci->RF_TX1_mixg_boost_tune); + + if (NREV_IS(pi->pubpi.phy_rev, 3)) + regs_SYN_2056_ptr = regs_SYN_2056; + else if (NREV_IS(pi->pubpi.phy_rev, 4)) + regs_SYN_2056_ptr = regs_SYN_2056_A1; + else { + switch (pi->pubpi.radiorev) { + case 5: + regs_SYN_2056_ptr = regs_SYN_2056_rev5; + break; + case 6: + regs_SYN_2056_ptr = regs_SYN_2056_rev6; + break; + case 7: + case 9: + regs_SYN_2056_ptr = regs_SYN_2056_rev7; + break; + case 8: + regs_SYN_2056_ptr = regs_SYN_2056_rev8; + break; + case 11: + regs_SYN_2056_ptr = regs_SYN_2056_rev11; + break; + } + } + if (CHSPEC_IS2G(pi->radio_chanspec)) + write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | + RADIO_2056_SYN, + (u16) regs_SYN_2056_ptr[0x49 - 2].init_g); + else + write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | + RADIO_2056_SYN, + (u16) regs_SYN_2056_ptr[0x49 - 2].init_a); + + if (pi->sh->boardflags2 & BFL2_GPLL_WAR) { + if (CHSPEC_IS2G(pi->radio_chanspec)) { + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 | + RADIO_2056_SYN, 0x1f); + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | + RADIO_2056_SYN, 0x1f); + + write_radio_reg(pi, + RADIO_2056_SYN_PLL_LOOPFILTER4 | + RADIO_2056_SYN, 0xb); + write_radio_reg(pi, + RADIO_2056_SYN_PLL_CP2 | + RADIO_2056_SYN, 0x14); + } + } + + if ((pi->sh->boardflags2 & BFL2_GPLL_WAR2) && + (CHSPEC_IS2G(pi->radio_chanspec))) { + write_radio_reg(pi, + RADIO_2056_SYN_PLL_LOOPFILTER1 | RADIO_2056_SYN, + 0x1f); + write_radio_reg(pi, + RADIO_2056_SYN_PLL_LOOPFILTER2 | RADIO_2056_SYN, + 0x1f); + write_radio_reg(pi, + RADIO_2056_SYN_PLL_LOOPFILTER4 | RADIO_2056_SYN, + 0xb); + write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | RADIO_2056_SYN, + 0x20); + } + + if (pi->sh->boardflags2 & BFL2_APLL_WAR) { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER1 | + RADIO_2056_SYN, 0x1f); + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | + RADIO_2056_SYN, 0x1f); + write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER4 | + RADIO_2056_SYN, 0x5); + write_radio_reg(pi, RADIO_2056_SYN_PLL_CP2 | + RADIO_2056_SYN, 0xc); + } + } + + if (PHY_IPA(pi) && CHSPEC_IS2G(pi->radio_chanspec)) { + u16 pag_boost_tune; + u16 padg_boost_tune; + u16 pgag_boost_tune; + u16 mixg_boost_tune; + u16 bias, cascbias; + uint core; + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + + if (NREV_GE(pi->pubpi.phy_rev, 5)) { + + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + PADG_IDAC, 0xcc); + + bias = 0x25; + cascbias = 0x20; + + if ((pi->sh->chip == + BCM43224_CHIP_ID) + || (pi->sh->chip == + BCM43225_CHIP_ID)) { + if (pi->sh->chippkg == + BCM43224_FAB_SMIC) { + bias = 0x2a; + cascbias = 0x38; + } + } + + pag_boost_tune = 0x4; + pgag_boost_tune = 0x03; + padg_boost_tune = 0x77; + mixg_boost_tune = 0x65; + + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_IMAIN_STAT, bias); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_IAUX_STAT, bias); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_CASCBIAS, cascbias); + + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_BOOST_TUNE, + pag_boost_tune); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + PGAG_BOOST_TUNE, + pgag_boost_tune); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + PADG_BOOST_TUNE, + padg_boost_tune); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + MIXG_BOOST_TUNE, + mixg_boost_tune); + } else { + + bias = (pi->bw == WL_CHANSPEC_BW_40) ? + 0x40 : 0x20; + + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_IMAIN_STAT, bias); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_IAUX_STAT, bias); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_CASCBIAS, 0x30); + } + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, PA_SPARE1, + 0xee); + } + } + + if (PHY_IPA(pi) && NREV_IS(pi->pubpi.phy_rev, 6) + && CHSPEC_IS5G(pi->radio_chanspec)) { + u16 paa_boost_tune; + u16 pada_boost_tune; + u16 pgaa_boost_tune; + u16 mixa_boost_tune; + u16 freq, pabias, cascbias; + uint core; + + freq = CHAN5G_FREQ(CHSPEC_CHANNEL(pi->radio_chanspec)); + + if (freq < 5150) { + + paa_boost_tune = 0xa; + pada_boost_tune = 0x77; + pgaa_boost_tune = 0xf; + mixa_boost_tune = 0xf; + } else if (freq < 5340) { + + paa_boost_tune = 0x8; + pada_boost_tune = 0x77; + pgaa_boost_tune = 0xfb; + mixa_boost_tune = 0xf; + } else if (freq < 5650) { + + paa_boost_tune = 0x0; + pada_boost_tune = 0x77; + pgaa_boost_tune = 0xb; + mixa_boost_tune = 0xf; + } else { + + paa_boost_tune = 0x0; + pada_boost_tune = 0x77; + if (freq != 5825) + pgaa_boost_tune = -(int)(freq - 18) / 36 + 168; + else + pgaa_boost_tune = 6; + + mixa_boost_tune = 0xf; + } + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAA_BOOST_TUNE, paa_boost_tune); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + PADA_BOOST_TUNE, pada_boost_tune); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + PGAA_BOOST_TUNE, pgaa_boost_tune); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + MIXA_BOOST_TUNE, mixa_boost_tune); + + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + TXSPARE1, 0x30); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + PA_SPARE2, 0xee); + + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + PADA_CASCBIAS, 0x3); + + cascbias = 0x30; + + if ((pi->sh->chip == BCM43224_CHIP_ID) || + (pi->sh->chip == BCM43225_CHIP_ID)) { + if (pi->sh->chippkg == BCM43224_FAB_SMIC) + cascbias = 0x35; + } + + pabias = (pi->phy_pabias == 0) ? 0x30 : pi->phy_pabias; + + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAA_IAUX_STAT, pabias); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAA_IMAIN_STAT, pabias); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAA_CASCBIAS, cascbias); + } + } + + udelay(50); + + wlc_phy_radio205x_vcocal_nphy(pi); +} + +void wlc_phy_radio205x_vcocal_nphy(struct brcms_phy *pi) +{ + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_EN, 0x01, 0x0); + mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x04, 0x0); + mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_CAL_RESETN, 0x04, + (1 << 2)); + mod_radio_reg(pi, RADIO_2057_RFPLL_MISC_EN, 0x01, 0x01); + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + write_radio_reg(pi, RADIO_2056_SYN_PLL_VCOCAL12, 0x0); + write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x38); + write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x18); + write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x38); + write_radio_reg(pi, RADIO_2056_SYN_PLL_MAST3, 0x39); + } + + udelay(300); +} + +static void +wlc_phy_chanspec_radio2057_setup( + struct brcms_phy *pi, + const struct chan_info_nphy_radio2057 *ci, + const struct chan_info_nphy_radio2057_rev5 * + ci2) +{ + int coreNum; + u16 txmix2g_tune_boost_pu = 0; + u16 pad2g_tune_pus = 0; + + if (pi->pubpi.radiorev == 5) { + + write_radio_reg(pi, + RADIO_2057_VCOCAL_COUNTVAL0, + ci2->RF_vcocal_countval0); + write_radio_reg(pi, RADIO_2057_VCOCAL_COUNTVAL1, + ci2->RF_vcocal_countval1); + write_radio_reg(pi, RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE, + ci2->RF_rfpll_refmaster_sparextalsize); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, + ci2->RF_rfpll_loopfilter_r1); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, + ci2->RF_rfpll_loopfilter_c2); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, + ci2->RF_rfpll_loopfilter_c1); + write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, + ci2->RF_cp_kpd_idac); + write_radio_reg(pi, RADIO_2057_RFPLL_MMD0, ci2->RF_rfpll_mmd0); + write_radio_reg(pi, RADIO_2057_RFPLL_MMD1, ci2->RF_rfpll_mmd1); + write_radio_reg(pi, + RADIO_2057_VCOBUF_TUNE, ci2->RF_vcobuf_tune); + write_radio_reg(pi, + RADIO_2057_LOGEN_MX2G_TUNE, + ci2->RF_logen_mx2g_tune); + write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF2G_TUNE, + ci2->RF_logen_indbuf2g_tune); + + write_radio_reg(pi, + RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0, + ci2->RF_txmix2g_tune_boost_pu_core0); + write_radio_reg(pi, + RADIO_2057_PAD2G_TUNE_PUS_CORE0, + ci2->RF_pad2g_tune_pus_core0); + write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE0, + ci2->RF_lna2g_tune_core0); + + write_radio_reg(pi, + RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1, + ci2->RF_txmix2g_tune_boost_pu_core1); + write_radio_reg(pi, + RADIO_2057_PAD2G_TUNE_PUS_CORE1, + ci2->RF_pad2g_tune_pus_core1); + write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE1, + ci2->RF_lna2g_tune_core1); + + } else { + + write_radio_reg(pi, + RADIO_2057_VCOCAL_COUNTVAL0, + ci->RF_vcocal_countval0); + write_radio_reg(pi, RADIO_2057_VCOCAL_COUNTVAL1, + ci->RF_vcocal_countval1); + write_radio_reg(pi, RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE, + ci->RF_rfpll_refmaster_sparextalsize); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, + ci->RF_rfpll_loopfilter_r1); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, + ci->RF_rfpll_loopfilter_c2); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, + ci->RF_rfpll_loopfilter_c1); + write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, ci->RF_cp_kpd_idac); + write_radio_reg(pi, RADIO_2057_RFPLL_MMD0, ci->RF_rfpll_mmd0); + write_radio_reg(pi, RADIO_2057_RFPLL_MMD1, ci->RF_rfpll_mmd1); + write_radio_reg(pi, RADIO_2057_VCOBUF_TUNE, ci->RF_vcobuf_tune); + write_radio_reg(pi, + RADIO_2057_LOGEN_MX2G_TUNE, + ci->RF_logen_mx2g_tune); + write_radio_reg(pi, RADIO_2057_LOGEN_MX5G_TUNE, + ci->RF_logen_mx5g_tune); + write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF2G_TUNE, + ci->RF_logen_indbuf2g_tune); + write_radio_reg(pi, RADIO_2057_LOGEN_INDBUF5G_TUNE, + ci->RF_logen_indbuf5g_tune); + + write_radio_reg(pi, + RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0, + ci->RF_txmix2g_tune_boost_pu_core0); + write_radio_reg(pi, + RADIO_2057_PAD2G_TUNE_PUS_CORE0, + ci->RF_pad2g_tune_pus_core0); + write_radio_reg(pi, RADIO_2057_PGA_BOOST_TUNE_CORE0, + ci->RF_pga_boost_tune_core0); + write_radio_reg(pi, RADIO_2057_TXMIX5G_BOOST_TUNE_CORE0, + ci->RF_txmix5g_boost_tune_core0); + write_radio_reg(pi, RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE0, + ci->RF_pad5g_tune_misc_pus_core0); + write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE0, + ci->RF_lna2g_tune_core0); + write_radio_reg(pi, RADIO_2057_LNA5G_TUNE_CORE0, + ci->RF_lna5g_tune_core0); + + write_radio_reg(pi, + RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1, + ci->RF_txmix2g_tune_boost_pu_core1); + write_radio_reg(pi, + RADIO_2057_PAD2G_TUNE_PUS_CORE1, + ci->RF_pad2g_tune_pus_core1); + write_radio_reg(pi, RADIO_2057_PGA_BOOST_TUNE_CORE1, + ci->RF_pga_boost_tune_core1); + write_radio_reg(pi, RADIO_2057_TXMIX5G_BOOST_TUNE_CORE1, + ci->RF_txmix5g_boost_tune_core1); + write_radio_reg(pi, RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE1, + ci->RF_pad5g_tune_misc_pus_core1); + write_radio_reg(pi, RADIO_2057_LNA2G_TUNE_CORE1, + ci->RF_lna2g_tune_core1); + write_radio_reg(pi, RADIO_2057_LNA5G_TUNE_CORE1, + ci->RF_lna5g_tune_core1); + } + + if ((pi->pubpi.radiorev <= 4) || (pi->pubpi.radiorev == 6)) { + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, + 0x3f); + write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, + 0x8); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, + 0x8); + } else { + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, + 0x1f); + write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, + 0x8); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, + 0x8); + } + } else if ((pi->pubpi.radiorev == 5) || (pi->pubpi.radiorev == 7) || + (pi->pubpi.radiorev == 8)) { + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, + 0x1b); + write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x30); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, + 0xa); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, + 0xa); + } else { + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_R1, + 0x1f); + write_radio_reg(pi, RADIO_2057_CP_KPD_IDAC, 0x3f); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C1, + 0x8); + write_radio_reg(pi, RADIO_2057_RFPLL_LOOPFILTER_C2, + 0x8); + } + + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (PHY_IPA(pi)) { + if (pi->pubpi.radiorev == 3) + txmix2g_tune_boost_pu = 0x6b; + + if (pi->pubpi.radiorev == 5) + pad2g_tune_pus = 0x73; + + } else { + if (pi->pubpi.radiorev != 5) { + pad2g_tune_pus = 0x3; + + txmix2g_tune_boost_pu = 0x61; + } + } + + for (coreNum = 0; coreNum <= 1; coreNum++) { + + if (txmix2g_tune_boost_pu != 0) + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, + TXMIX2G_TUNE_BOOST_PU, + txmix2g_tune_boost_pu); + + if (pad2g_tune_pus != 0) + WRITE_RADIO_REG4(pi, RADIO_2057, CORE, coreNum, + PAD2G_TUNE_PUS, + pad2g_tune_pus); + } + } + + udelay(50); + + wlc_phy_radio205x_vcocal_nphy(pi); +} + +static void +wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, + const struct nphy_sfo_cfg *ci) +{ + u16 val; + + val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; + if (CHSPEC_IS5G(chanspec) && !val) { + + val = R_REG(&pi->regs->psm_phy_hdr_param); + W_REG(&pi->regs->psm_phy_hdr_param, + (val | MAC_PHY_FORCE_CLK)); + + or_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG), + (BBCFG_RESETCCA | BBCFG_RESETRX)); + + W_REG(&pi->regs->psm_phy_hdr_param, val); + + or_phy_reg(pi, 0x09, NPHY_BandControl_currentBand); + } else if (!CHSPEC_IS5G(chanspec) && val) { + + and_phy_reg(pi, 0x09, ~NPHY_BandControl_currentBand); + + val = R_REG(&pi->regs->psm_phy_hdr_param); + W_REG(&pi->regs->psm_phy_hdr_param, + (val | MAC_PHY_FORCE_CLK)); + + and_phy_reg(pi, (NPHY_TO_BPHY_OFF + BPHY_BB_CONFIG), + (u16) (~(BBCFG_RESETCCA | BBCFG_RESETRX))); + + W_REG(&pi->regs->psm_phy_hdr_param, val); + } + + write_phy_reg(pi, 0x1ce, ci->PHY_BW1a); + write_phy_reg(pi, 0x1cf, ci->PHY_BW2); + write_phy_reg(pi, 0x1d0, ci->PHY_BW3); + + write_phy_reg(pi, 0x1d1, ci->PHY_BW4); + write_phy_reg(pi, 0x1d2, ci->PHY_BW5); + write_phy_reg(pi, 0x1d3, ci->PHY_BW6); + + if (CHSPEC_CHANNEL(pi->radio_chanspec) == 14) { + wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_ofdm_en, 0); + + or_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_TEST, 0x800); + } else { + wlc_phy_classifier_nphy(pi, NPHY_ClassifierCtrl_ofdm_en, + NPHY_ClassifierCtrl_ofdm_en); + + if (CHSPEC_IS2G(chanspec)) + and_phy_reg(pi, NPHY_TO_BPHY_OFF + BPHY_TEST, ~0x840); + } + + if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) + wlc_phy_txpwr_fixpower_nphy(pi); + + if (NREV_LT(pi->pubpi.phy_rev, 3)) + wlc_phy_adjust_lnagaintbl_nphy(pi); + + wlc_phy_txlpfbw_nphy(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 3) + && (pi->phy_spuravoid != SPURAVOID_DISABLE)) { + u8 spuravoid = 0; + + val = CHSPEC_CHANNEL(chanspec); + if (!CHSPEC_IS40(pi->radio_chanspec)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if ((val == 13) || (val == 14) || (val == 153)) + spuravoid = 1; + } else if (((val >= 5) && (val <= 8)) || (val == 13) + || (val == 14)) { + spuravoid = 1; + } + } else if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (val == 54) + spuravoid = 1; + } else { + if (pi->nphy_aband_spurwar_en && + ((val == 38) || (val == 102) + || (val == 118))) + spuravoid = 1; + } + + if (pi->phy_spuravoid == SPURAVOID_FORCEON) + spuravoid = 1; + + wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false); + si_pmu_spuravoid(pi->sh->sih, spuravoid); + wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true); + + if ((pi->sh->chip == BCM43224_CHIP_ID) || + (pi->sh->chip == BCM43225_CHIP_ID)) { + + if (spuravoid == 1) { + + W_REG(&pi->regs->tsf_clk_frac_l, + 0x5341); + W_REG(&pi->regs->tsf_clk_frac_h, + 0x8); + } else { + + W_REG(&pi->regs->tsf_clk_frac_l, + 0x8889); + W_REG(&pi->regs->tsf_clk_frac_h, + 0x8); + } + } + + wlapi_bmac_core_phypll_reset(pi->sh->physhim); + + mod_phy_reg(pi, 0x01, (0x1 << 15), + ((spuravoid > 0) ? (0x1 << 15) : 0)); + + wlc_phy_resetcca_nphy(pi); + + pi->phy_isspuravoid = (spuravoid > 0); + } + + if (NREV_LT(pi->pubpi.phy_rev, 7)) + write_phy_reg(pi, 0x17e, 0x3830); + + wlc_phy_spurwar_nphy(pi); +} + +void wlc_phy_chanspec_set_nphy(struct brcms_phy *pi, u16 chanspec) +{ + int freq; + const struct chan_info_nphy_radio2057 *t0 = NULL; + const struct chan_info_nphy_radio205x *t1 = NULL; + const struct chan_info_nphy_radio2057_rev5 *t2 = NULL; + const struct chan_info_nphy_2055 *t3 = NULL; + + if (!wlc_phy_chan2freq_nphy + (pi, CHSPEC_CHANNEL(chanspec), &freq, &t0, &t1, &t2, &t3)) + return; + + wlc_phy_chanspec_radio_set((struct brcms_phy_pub *) pi, chanspec); + + if (CHSPEC_BW(chanspec) != pi->bw) + wlapi_bmac_bw_set(pi->sh->physhim, CHSPEC_BW(chanspec)); + + if (CHSPEC_IS40(chanspec)) { + if (CHSPEC_SB_UPPER(chanspec)) { + or_phy_reg(pi, 0xa0, BPHY_BAND_SEL_UP20); + if (NREV_GE(pi->pubpi.phy_rev, 7)) + or_phy_reg(pi, 0x310, PRIM_SEL_UP20); + } else { + and_phy_reg(pi, 0xa0, ~BPHY_BAND_SEL_UP20); + if (NREV_GE(pi->pubpi.phy_rev, 7)) + and_phy_reg(pi, 0x310, + (~PRIM_SEL_UP20 & 0xffff)); + } + } + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + if ((pi->pubpi.radiorev <= 4) + || (pi->pubpi.radiorev == 6)) { + mod_radio_reg(pi, RADIO_2057_TIA_CONFIG_CORE0, + 0x2, + (CHSPEC_IS5G(chanspec) ? (1 << 1) + : 0)); + mod_radio_reg(pi, RADIO_2057_TIA_CONFIG_CORE1, + 0x2, + (CHSPEC_IS5G(chanspec) ? (1 << 1) + : 0)); + } + + wlc_phy_chanspec_radio2057_setup(pi, t0, t2); + wlc_phy_chanspec_nphy_setup(pi, chanspec, + (pi->pubpi.radiorev == 5) ? + (const struct nphy_sfo_cfg *)&(t2->PHY_BW1a) : + (const struct nphy_sfo_cfg *)&(t0->PHY_BW1a)); + + } else { + + mod_radio_reg(pi, + RADIO_2056_SYN_COM_CTRL | RADIO_2056_SYN, + 0x4, + (CHSPEC_IS5G(chanspec) ? (0x1 << 2) : 0)); + wlc_phy_chanspec_radio2056_setup(pi, t1); + + wlc_phy_chanspec_nphy_setup(pi, chanspec, + (const struct nphy_sfo_cfg *) &(t1->PHY_BW1a)); + } + + } else { + + mod_radio_reg(pi, RADIO_2055_MASTER_CNTRL1, 0x70, + (CHSPEC_IS5G(chanspec) ? (0x02 << 4) + : (0x05 << 4))); + + wlc_phy_chanspec_radio2055_setup(pi, t3); + wlc_phy_chanspec_nphy_setup(pi, chanspec, + (const struct nphy_sfo_cfg *) + &(t3->PHY_BW1a)); + } + +} + +void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init) +{ + struct brcms_phy *pi = (struct brcms_phy *) ppi; + u16 mask = 0xfc00; + u32 mc = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + return; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + u16 v0 = 0x211, v1 = 0x222, v2 = 0x144, v3 = 0x188; + + if (lut_init == false) + return; + + if (pi->srom_fem2g.antswctrllut == 0) { + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 1, 0x02, 16, &v0); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 1, 0x03, 16, &v1); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 1, 0x08, 16, &v2); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 1, 0x0C, 16, &v3); + } + + if (pi->srom_fem5g.antswctrllut == 0) { + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 1, 0x12, 16, &v0); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 1, 0x13, 16, &v1); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 1, 0x18, 16, &v2); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_ANTSWCTRLLUT, + 1, 0x1C, 16, &v3); + } + } else { + + write_phy_reg(pi, 0xc8, 0x0); + write_phy_reg(pi, 0xc9, 0x0); + + ai_gpiocontrol(pi->sh->sih, mask, mask, GPIO_DRV_PRIORITY); + + mc = R_REG(&pi->regs->maccontrol); + mc &= ~MCTL_GPOUT_SEL_MASK; + W_REG(&pi->regs->maccontrol, mc); + + OR_REG(&pi->regs->psm_gpio_oe, mask); + + AND_REG(&pi->regs->psm_gpio_out, ~mask); + + if (lut_init) { + write_phy_reg(pi, 0xf8, 0x02d8); + write_phy_reg(pi, 0xf9, 0x0301); + write_phy_reg(pi, 0xfa, 0x02d8); + write_phy_reg(pi, 0xfb, 0x0301); + } + } +} + +u16 wlc_phy_classifier_nphy(struct brcms_phy *pi, u16 mask, u16 val) +{ + u16 curr_ctl, new_ctl; + bool suspended = false; + + if (D11REV_IS(pi->sh->corerev, 16)) { + suspended = + (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC) ? + false : true; + if (!suspended) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + } + + curr_ctl = read_phy_reg(pi, 0xb0) & (0x7 << 0); + + new_ctl = (curr_ctl & (~mask)) | (val & mask); + + mod_phy_reg(pi, 0xb0, (0x7 << 0), new_ctl); + + if (D11REV_IS(pi->sh->corerev, 16) && !suspended) + wlapi_enable_mac(pi->sh->physhim); + + return new_ctl; +} + +void wlc_phy_force_rfseq_nphy(struct brcms_phy *pi, u8 cmd) +{ + u16 trigger_mask, status_mask; + u16 orig_RfseqCoreActv; + + switch (cmd) { + case NPHY_RFSEQ_RX2TX: + trigger_mask = NPHY_RfseqTrigger_rx2tx; + status_mask = NPHY_RfseqStatus_rx2tx; + break; + case NPHY_RFSEQ_TX2RX: + trigger_mask = NPHY_RfseqTrigger_tx2rx; + status_mask = NPHY_RfseqStatus_tx2rx; + break; + case NPHY_RFSEQ_RESET2RX: + trigger_mask = NPHY_RfseqTrigger_reset2rx; + status_mask = NPHY_RfseqStatus_reset2rx; + break; + case NPHY_RFSEQ_UPDATEGAINH: + trigger_mask = NPHY_RfseqTrigger_updategainh; + status_mask = NPHY_RfseqStatus_updategainh; + break; + case NPHY_RFSEQ_UPDATEGAINL: + trigger_mask = NPHY_RfseqTrigger_updategainl; + status_mask = NPHY_RfseqStatus_updategainl; + break; + case NPHY_RFSEQ_UPDATEGAINU: + trigger_mask = NPHY_RfseqTrigger_updategainu; + status_mask = NPHY_RfseqStatus_updategainu; + break; + default: + return; + } + + orig_RfseqCoreActv = read_phy_reg(pi, 0xa1); + or_phy_reg(pi, 0xa1, + (NPHY_RfseqMode_CoreActv_override | + NPHY_RfseqMode_Trigger_override)); + or_phy_reg(pi, 0xa3, trigger_mask); + SPINWAIT((read_phy_reg(pi, 0xa4) & status_mask), 200000); + write_phy_reg(pi, 0xa1, orig_RfseqCoreActv); + WARN(read_phy_reg(pi, 0xa4) & status_mask, "HW error in rf"); +} + +static void +wlc_phy_rfctrl_override_1tomany_nphy(struct brcms_phy *pi, u16 cmd, u16 value, + u8 core_mask, u8 off) +{ + u16 rfmxgain = 0, lpfgain = 0; + u16 tgain = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + switch (cmd) { + case NPHY_REV7_RfctrlOverride_cmd_rxrf_pu: + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 5), + value, core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 4), value, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 3), value, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + break; + case NPHY_REV7_RfctrlOverride_cmd_rx_pu: + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 2), + value, core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 1), value, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 0), value, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 1), value, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 11), 0, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + break; + case NPHY_REV7_RfctrlOverride_cmd_tx_pu: + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 2), + value, core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 1), value, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 0), value, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 2), value, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 11), 1, + core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + break; + case NPHY_REV7_RfctrlOverride_cmd_rxgain: + rfmxgain = value & 0x000ff; + lpfgain = value & 0x0ff00; + lpfgain = lpfgain >> 8; + + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 11), + rfmxgain, core_mask, + off, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x3 << 13), + lpfgain, core_mask, + off, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + break; + case NPHY_REV7_RfctrlOverride_cmd_txgain: + tgain = value & 0x7fff; + lpfgain = value & 0x8000; + lpfgain = lpfgain >> 14; + + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 12), + tgain, core_mask, off, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 13), + lpfgain, core_mask, + off, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + break; + } + } +} + +static void +wlc_phy_scale_offset_rssi_nphy(struct brcms_phy *pi, u16 scale, s8 offset, + u8 coresel, u8 rail, u8 rssi_type) +{ + u16 valuetostuff; + + offset = (offset > NPHY_RSSICAL_MAXREAD) ? + NPHY_RSSICAL_MAXREAD : offset; + offset = (offset < (-NPHY_RSSICAL_MAXREAD - 1)) ? + -NPHY_RSSICAL_MAXREAD - 1 : offset; + + valuetostuff = ((scale & 0x3f) << 8) | (offset & 0x3f); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB)) + write_phy_reg(pi, 0x1a6, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB)) + write_phy_reg(pi, 0x1ac, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_NB)) + write_phy_reg(pi, 0x1b2, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_NB)) + write_phy_reg(pi, 0x1b8, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1)) + write_phy_reg(pi, 0x1a4, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1)) + write_phy_reg(pi, 0x1aa, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W1)) + write_phy_reg(pi, 0x1b0, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W1)) + write_phy_reg(pi, 0x1b6, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2)) + write_phy_reg(pi, 0x1a5, valuetostuff); + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2)) + write_phy_reg(pi, 0x1ab, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_W2)) + write_phy_reg(pi, 0x1b1, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_W2)) + write_phy_reg(pi, 0x1b7, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD)) + write_phy_reg(pi, 0x1a7, valuetostuff); + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD)) + write_phy_reg(pi, 0x1ad, valuetostuff); + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_TBD)) + write_phy_reg(pi, 0x1b3, valuetostuff); + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_TBD)) + write_phy_reg(pi, 0x1b9, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ)) + write_phy_reg(pi, 0x1a8, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ)) + write_phy_reg(pi, 0x1ae, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_I) && (rssi_type == NPHY_RSSI_SEL_IQ)) + write_phy_reg(pi, 0x1b4, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rail == NPHY_RAIL_Q) && (rssi_type == NPHY_RSSI_SEL_IQ)) + write_phy_reg(pi, 0x1ba, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rssi_type == NPHY_RSSI_SEL_TSSI_2G)) + write_phy_reg(pi, 0x1a9, valuetostuff); + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rssi_type == NPHY_RSSI_SEL_TSSI_2G)) + write_phy_reg(pi, 0x1b5, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE1) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rssi_type == NPHY_RSSI_SEL_TSSI_5G)) + write_phy_reg(pi, 0x1af, valuetostuff); + + if (((coresel == RADIO_MIMO_CORESEL_CORE2) || + (coresel == RADIO_MIMO_CORESEL_ALLRX)) && + (rssi_type == NPHY_RSSI_SEL_TSSI_5G)) + write_phy_reg(pi, 0x1bb, valuetostuff); +} + +static void brcms_phy_wr_tx_mux(struct brcms_phy *pi, u8 core) +{ + if (PHY_IPA(pi)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) + write_radio_reg(pi, + ((core == PHY_CORE_0) ? + RADIO_2057_TX0_TX_SSI_MUX : + RADIO_2057_TX1_TX_SSI_MUX), + (CHSPEC_IS5G(pi->radio_chanspec) ? + 0xc : 0xe)); + else + write_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MUX | + ((core == PHY_CORE_0) ? + RADIO_2056_TX0 : RADIO_2056_TX1), + (CHSPEC_IS5G(pi->radio_chanspec) ? + 0xc : 0xe)); + } else { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + write_radio_reg(pi, + ((core == PHY_CORE_0) ? + RADIO_2057_TX0_TX_SSI_MUX : + RADIO_2057_TX1_TX_SSI_MUX), + 0x11); + + if (pi->pubpi.radioid == BCM2057_ID) + write_radio_reg(pi, + RADIO_2057_IQTEST_SEL_PU, 0x1); + + } else { + write_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MUX | + ((core == PHY_CORE_0) ? + RADIO_2056_TX0 : RADIO_2056_TX1), + 0x11); + } + } +} + +void wlc_phy_rssisel_nphy(struct brcms_phy *pi, u8 core_code, u8 rssi_type) +{ + u16 mask, val; + u16 afectrlovr_rssi_val, rfctrlcmd_rxen_val, rfctrlcmd_coresel_val, + startseq; + u16 rfctrlovr_rssi_val, rfctrlovr_rxen_val, rfctrlovr_coresel_val, + rfctrlovr_trigger_val; + u16 afectrlovr_rssi_mask, rfctrlcmd_mask, rfctrlovr_mask; + u16 rfctrlcmd_val, rfctrlovr_val; + u8 core; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (core_code == RADIO_MIMO_CORESEL_OFF) { + mod_phy_reg(pi, 0x8f, (0x1 << 9), 0); + mod_phy_reg(pi, 0xa5, (0x1 << 9), 0); + + mod_phy_reg(pi, 0xa6, (0x3 << 8), 0); + mod_phy_reg(pi, 0xa7, (0x3 << 8), 0); + + mod_phy_reg(pi, 0xe5, (0x1 << 5), 0); + mod_phy_reg(pi, 0xe6, (0x1 << 5), 0); + + mask = (0x1 << 2) | + (0x1 << 3) | (0x1 << 4) | (0x1 << 5); + mod_phy_reg(pi, 0xf9, mask, 0); + mod_phy_reg(pi, 0xfb, mask, 0); + + } else { + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + if (core_code == RADIO_MIMO_CORESEL_CORE1 + && core == PHY_CORE_1) + continue; + else if (core_code == RADIO_MIMO_CORESEL_CORE2 + && core == PHY_CORE_0) + continue; + + mod_phy_reg(pi, (core == PHY_CORE_0) ? + 0x8f : 0xa5, (0x1 << 9), 1 << 9); + + if (rssi_type == NPHY_RSSI_SEL_W1 || + rssi_type == NPHY_RSSI_SEL_W2 || + rssi_type == NPHY_RSSI_SEL_NB) { + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xa6 : 0xa7, + (0x3 << 8), 0); + + mask = (0x1 << 2) | + (0x1 << 3) | + (0x1 << 4) | (0x1 << 5); + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xf9 : 0xfb, + mask, 0); + + if (rssi_type == NPHY_RSSI_SEL_W1) { + if (CHSPEC_IS5G( + pi->radio_chanspec)) { + mask = (0x1 << 2); + val = 1 << 2; + } else { + mask = (0x1 << 3); + val = 1 << 3; + } + } else if (rssi_type == + NPHY_RSSI_SEL_W2) { + mask = (0x1 << 4); + val = 1 << 4; + } else { + mask = (0x1 << 5); + val = 1 << 5; + } + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xf9 : 0xfb, + mask, val); + + mask = (0x1 << 5); + val = 1 << 5; + mod_phy_reg(pi, (core == PHY_CORE_0) ? + 0xe5 : 0xe6, mask, val); + } else { + if (rssi_type == NPHY_RSSI_SEL_TBD) { + mask = (0x3 << 8); + val = 1 << 8; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xa6 + : 0xa7, mask, val); + mask = (0x3 << 10); + val = 1 << 10; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xa6 + : 0xa7, mask, val); + } else if (rssi_type == + NPHY_RSSI_SEL_IQ) { + mask = (0x3 << 8); + val = 2 << 8; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xa6 + : 0xa7, mask, val); + mask = (0x3 << 10); + val = 2 << 10; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xa6 + : 0xa7, mask, val); + } else { + mask = (0x3 << 8); + val = 3 << 8; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xa6 + : 0xa7, mask, val); + mask = (0x3 << 10); + val = 3 << 10; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0xa6 + : 0xa7, mask, val); + brcms_phy_wr_tx_mux(pi, core); + afectrlovr_rssi_val = 1 << 9; + mod_phy_reg(pi, + (core == + PHY_CORE_0) ? 0x8f + : 0xa5, (0x1 << 9), + afectrlovr_rssi_val); + } + } + } + } + } else { + + if ((rssi_type == NPHY_RSSI_SEL_W1) || + (rssi_type == NPHY_RSSI_SEL_W2) || + (rssi_type == NPHY_RSSI_SEL_NB)) + val = 0x0; + else if (rssi_type == NPHY_RSSI_SEL_TBD) + val = 0x1; + else if (rssi_type == NPHY_RSSI_SEL_IQ) + val = 0x2; + else + val = 0x3; + + mask = ((0x3 << 12) | (0x3 << 14)); + val = (val << 12) | (val << 14); + mod_phy_reg(pi, 0xa6, mask, val); + mod_phy_reg(pi, 0xa7, mask, val); + + if ((rssi_type == NPHY_RSSI_SEL_W1) || + (rssi_type == NPHY_RSSI_SEL_W2) || + (rssi_type == NPHY_RSSI_SEL_NB)) { + if (rssi_type == NPHY_RSSI_SEL_W1) + val = 0x1; + if (rssi_type == NPHY_RSSI_SEL_W2) + val = 0x2; + if (rssi_type == NPHY_RSSI_SEL_NB) + val = 0x3; + + mask = (0x3 << 4); + val = (val << 4); + mod_phy_reg(pi, 0x7a, mask, val); + mod_phy_reg(pi, 0x7d, mask, val); + } + + if (core_code == RADIO_MIMO_CORESEL_OFF) { + afectrlovr_rssi_val = 0; + rfctrlcmd_rxen_val = 0; + rfctrlcmd_coresel_val = 0; + rfctrlovr_rssi_val = 0; + rfctrlovr_rxen_val = 0; + rfctrlovr_coresel_val = 0; + rfctrlovr_trigger_val = 0; + startseq = 0; + } else { + afectrlovr_rssi_val = 1; + rfctrlcmd_rxen_val = 1; + rfctrlcmd_coresel_val = core_code; + rfctrlovr_rssi_val = 1; + rfctrlovr_rxen_val = 1; + rfctrlovr_coresel_val = 1; + rfctrlovr_trigger_val = 1; + startseq = 1; + } + + afectrlovr_rssi_mask = ((0x1 << 12) | (0x1 << 13)); + afectrlovr_rssi_val = (afectrlovr_rssi_val << + 12) | (afectrlovr_rssi_val << 13); + mod_phy_reg(pi, 0xa5, afectrlovr_rssi_mask, + afectrlovr_rssi_val); + + if ((rssi_type == NPHY_RSSI_SEL_W1) || + (rssi_type == NPHY_RSSI_SEL_W2) || + (rssi_type == NPHY_RSSI_SEL_NB)) { + rfctrlcmd_mask = ((0x1 << 8) | (0x7 << 3)); + rfctrlcmd_val = (rfctrlcmd_rxen_val << 8) | + (rfctrlcmd_coresel_val << 3); + + rfctrlovr_mask = ((0x1 << 5) | + (0x1 << 12) | + (0x1 << 1) | (0x1 << 0)); + rfctrlovr_val = (rfctrlovr_rssi_val << + 5) | + (rfctrlovr_rxen_val << 12) | + (rfctrlovr_coresel_val << 1) | + (rfctrlovr_trigger_val << 0); + + mod_phy_reg(pi, 0x78, rfctrlcmd_mask, rfctrlcmd_val); + mod_phy_reg(pi, 0xec, rfctrlovr_mask, rfctrlovr_val); + + mod_phy_reg(pi, 0x78, (0x1 << 0), (startseq << 0)); + udelay(20); + + mod_phy_reg(pi, 0xec, (0x1 << 0), 0); + } + } +} + +int +wlc_phy_poll_rssi_nphy(struct brcms_phy *pi, u8 rssi_type, s32 *rssi_buf, + u8 nsamps) +{ + s16 rssi0, rssi1; + u16 afectrlCore1_save = 0; + u16 afectrlCore2_save = 0; + u16 afectrlOverride1_save = 0; + u16 afectrlOverride2_save = 0; + u16 rfctrlOverrideAux0_save = 0; + u16 rfctrlOverrideAux1_save = 0; + u16 rfctrlMiscReg1_save = 0; + u16 rfctrlMiscReg2_save = 0; + u16 rfctrlcmd_save = 0; + u16 rfctrloverride_save = 0; + u16 rfctrlrssiothers1_save = 0; + u16 rfctrlrssiothers2_save = 0; + s8 tmp_buf[4]; + u8 ctr = 0, samp = 0; + s32 rssi_out_val; + u16 gpiosel_orig; + + afectrlCore1_save = read_phy_reg(pi, 0xa6); + afectrlCore2_save = read_phy_reg(pi, 0xa7); + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + rfctrlMiscReg1_save = read_phy_reg(pi, 0xf9); + rfctrlMiscReg2_save = read_phy_reg(pi, 0xfb); + afectrlOverride1_save = read_phy_reg(pi, 0x8f); + afectrlOverride2_save = read_phy_reg(pi, 0xa5); + rfctrlOverrideAux0_save = read_phy_reg(pi, 0xe5); + rfctrlOverrideAux1_save = read_phy_reg(pi, 0xe6); + } else { + afectrlOverride1_save = read_phy_reg(pi, 0xa5); + rfctrlcmd_save = read_phy_reg(pi, 0x78); + rfctrloverride_save = read_phy_reg(pi, 0xec); + rfctrlrssiothers1_save = read_phy_reg(pi, 0x7a); + rfctrlrssiothers2_save = read_phy_reg(pi, 0x7d); + } + + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type); + + gpiosel_orig = read_phy_reg(pi, 0xca); + if (NREV_LT(pi->pubpi.phy_rev, 2)) + write_phy_reg(pi, 0xca, 5); + + for (ctr = 0; ctr < 4; ctr++) + rssi_buf[ctr] = 0; + + for (samp = 0; samp < nsamps; samp++) { + if (NREV_LT(pi->pubpi.phy_rev, 2)) { + rssi0 = read_phy_reg(pi, 0x1c9); + rssi1 = read_phy_reg(pi, 0x1ca); + } else { + rssi0 = read_phy_reg(pi, 0x219); + rssi1 = read_phy_reg(pi, 0x21a); + } + + ctr = 0; + tmp_buf[ctr++] = ((s8) ((rssi0 & 0x3f) << 2)) >> 2; + tmp_buf[ctr++] = ((s8) (((rssi0 >> 8) & 0x3f) << 2)) >> 2; + tmp_buf[ctr++] = ((s8) ((rssi1 & 0x3f) << 2)) >> 2; + tmp_buf[ctr++] = ((s8) (((rssi1 >> 8) & 0x3f) << 2)) >> 2; + + for (ctr = 0; ctr < 4; ctr++) + rssi_buf[ctr] += tmp_buf[ctr]; + + } + + rssi_out_val = rssi_buf[3] & 0xff; + rssi_out_val |= (rssi_buf[2] & 0xff) << 8; + rssi_out_val |= (rssi_buf[1] & 0xff) << 16; + rssi_out_val |= (rssi_buf[0] & 0xff) << 24; + + if (NREV_LT(pi->pubpi.phy_rev, 2)) + write_phy_reg(pi, 0xca, gpiosel_orig); + + write_phy_reg(pi, 0xa6, afectrlCore1_save); + write_phy_reg(pi, 0xa7, afectrlCore2_save); + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + write_phy_reg(pi, 0xf9, rfctrlMiscReg1_save); + write_phy_reg(pi, 0xfb, rfctrlMiscReg2_save); + write_phy_reg(pi, 0x8f, afectrlOverride1_save); + write_phy_reg(pi, 0xa5, afectrlOverride2_save); + write_phy_reg(pi, 0xe5, rfctrlOverrideAux0_save); + write_phy_reg(pi, 0xe6, rfctrlOverrideAux1_save); + } else { + write_phy_reg(pi, 0xa5, afectrlOverride1_save); + write_phy_reg(pi, 0x78, rfctrlcmd_save); + write_phy_reg(pi, 0xec, rfctrloverride_save); + write_phy_reg(pi, 0x7a, rfctrlrssiothers1_save); + write_phy_reg(pi, 0x7d, rfctrlrssiothers2_save); + } + + return rssi_out_val; +} + +s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi) +{ + u16 core1_txrf_iqcal1_save, core1_txrf_iqcal2_save; + u16 core2_txrf_iqcal1_save, core2_txrf_iqcal2_save; + u16 pwrdet_rxtx_core1_save; + u16 pwrdet_rxtx_core2_save; + u16 afectrlCore1_save; + u16 afectrlCore2_save; + u16 afectrlOverride_save; + u16 afectrlOverride2_save; + u16 pd_pll_ts_save; + u16 gpioSel_save; + s32 radio_temp[4]; + s32 radio_temp2[4]; + u16 syn_tempprocsense_save; + s16 offset = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + u16 auxADC_Vmid, auxADC_Av, auxADC_Vmid_save, auxADC_Av_save; + u16 auxADC_rssi_ctrlL_save, auxADC_rssi_ctrlH_save; + u16 auxADC_rssi_ctrlL, auxADC_rssi_ctrlH; + s32 auxADC_Vl; + u16 RfctrlOverride5_save, RfctrlOverride6_save; + u16 RfctrlMiscReg5_save, RfctrlMiscReg6_save; + u16 RSSIMultCoef0QPowerDet_save; + u16 tempsense_Rcal; + + syn_tempprocsense_save = + read_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG); + + afectrlCore1_save = read_phy_reg(pi, 0xa6); + afectrlCore2_save = read_phy_reg(pi, 0xa7); + afectrlOverride_save = read_phy_reg(pi, 0x8f); + afectrlOverride2_save = read_phy_reg(pi, 0xa5); + RSSIMultCoef0QPowerDet_save = read_phy_reg(pi, 0x1ae); + RfctrlOverride5_save = read_phy_reg(pi, 0x346); + RfctrlOverride6_save = read_phy_reg(pi, 0x347); + RfctrlMiscReg5_save = read_phy_reg(pi, 0x344); + RfctrlMiscReg6_save = read_phy_reg(pi, 0x345); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16, + &auxADC_Vmid_save); + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16, + &auxADC_Av_save); + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16, + &auxADC_rssi_ctrlL_save); + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, + &auxADC_rssi_ctrlH_save); + + write_phy_reg(pi, 0x1ae, 0x0); + + auxADC_rssi_ctrlL = 0x0; + auxADC_rssi_ctrlH = 0x20; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16, + &auxADC_rssi_ctrlL); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, + &auxADC_rssi_ctrlH); + + tempsense_Rcal = syn_tempprocsense_save & 0x1c; + + write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, + tempsense_Rcal | 0x01); + + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), + 1, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + mod_phy_reg(pi, 0xa6, (0x1 << 7), 0); + mod_phy_reg(pi, 0xa7, (0x1 << 7), 0); + mod_phy_reg(pi, 0x8f, (0x1 << 7), (0x1 << 7)); + mod_phy_reg(pi, 0xa5, (0x1 << 7), (0x1 << 7)); + + mod_phy_reg(pi, 0xa6, (0x1 << 2), (0x1 << 2)); + mod_phy_reg(pi, 0xa7, (0x1 << 2), (0x1 << 2)); + mod_phy_reg(pi, 0x8f, (0x1 << 2), (0x1 << 2)); + mod_phy_reg(pi, 0xa5, (0x1 << 2), (0x1 << 2)); + udelay(5); + mod_phy_reg(pi, 0xa6, (0x1 << 2), 0); + mod_phy_reg(pi, 0xa7, (0x1 << 2), 0); + mod_phy_reg(pi, 0xa6, (0x1 << 3), 0); + mod_phy_reg(pi, 0xa7, (0x1 << 3), 0); + mod_phy_reg(pi, 0x8f, (0x1 << 3), (0x1 << 3)); + mod_phy_reg(pi, 0xa5, (0x1 << 3), (0x1 << 3)); + mod_phy_reg(pi, 0xa6, (0x1 << 6), 0); + mod_phy_reg(pi, 0xa7, (0x1 << 6), 0); + mod_phy_reg(pi, 0x8f, (0x1 << 6), (0x1 << 6)); + mod_phy_reg(pi, 0xa5, (0x1 << 6), (0x1 << 6)); + + auxADC_Vmid = 0xA3; + auxADC_Av = 0x0; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16, + &auxADC_Vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16, + &auxADC_Av); + + udelay(3); + + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); + write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, + tempsense_Rcal | 0x03); + + udelay(5); + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1); + + auxADC_Av = 0x7; + if (radio_temp[1] + radio_temp2[1] < -30) { + auxADC_Vmid = 0x45; + auxADC_Vl = 263; + } else if (radio_temp[1] + radio_temp2[1] < -9) { + auxADC_Vmid = 0x200; + auxADC_Vl = 467; + } else if (radio_temp[1] + radio_temp2[1] < 11) { + auxADC_Vmid = 0x266; + auxADC_Vl = 634; + } else { + auxADC_Vmid = 0x2D5; + auxADC_Vl = 816; + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16, + &auxADC_Vmid); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16, + &auxADC_Av); + + udelay(3); + + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1); + write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, + tempsense_Rcal | 0x01); + + udelay(5); + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); + + write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, + syn_tempprocsense_save); + + write_phy_reg(pi, 0xa6, afectrlCore1_save); + write_phy_reg(pi, 0xa7, afectrlCore2_save); + write_phy_reg(pi, 0x8f, afectrlOverride_save); + write_phy_reg(pi, 0xa5, afectrlOverride2_save); + write_phy_reg(pi, 0x1ae, RSSIMultCoef0QPowerDet_save); + write_phy_reg(pi, 0x346, RfctrlOverride5_save); + write_phy_reg(pi, 0x347, RfctrlOverride6_save); + write_phy_reg(pi, 0x344, RfctrlMiscReg5_save); + write_phy_reg(pi, 0x345, RfctrlMiscReg5_save); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0A, 16, + &auxADC_Vmid_save); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x0E, 16, + &auxADC_Av_save); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x02, 16, + &auxADC_rssi_ctrlL_save); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, + &auxADC_rssi_ctrlH_save); + + radio_temp[0] = (179 * (radio_temp[1] + radio_temp2[1]) + + 82 * (auxADC_Vl) - 28861 + + 128) / 256; + + offset = (s16) pi->phy_tempsense_offset; + + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + syn_tempprocsense_save = + read_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE); + + afectrlCore1_save = read_phy_reg(pi, 0xa6); + afectrlCore2_save = read_phy_reg(pi, 0xa7); + afectrlOverride_save = read_phy_reg(pi, 0x8f); + afectrlOverride2_save = read_phy_reg(pi, 0xa5); + gpioSel_save = read_phy_reg(pi, 0xca); + + write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x01); + + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); + if (NREV_LT(pi->pubpi.phy_rev, 7)) + write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x05); + + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1); + if (NREV_GE(pi->pubpi.phy_rev, 7)) + write_radio_reg(pi, RADIO_2057_TEMPSENSE_CONFIG, 0x01); + else + write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, 0x01); + + radio_temp[0] = + (126 * (radio_temp[1] + radio_temp2[1]) + 3987) / 64; + + write_radio_reg(pi, RADIO_2056_SYN_TEMPPROCSENSE, + syn_tempprocsense_save); + + write_phy_reg(pi, 0xca, gpioSel_save); + write_phy_reg(pi, 0xa6, afectrlCore1_save); + write_phy_reg(pi, 0xa7, afectrlCore2_save); + write_phy_reg(pi, 0x8f, afectrlOverride_save); + write_phy_reg(pi, 0xa5, afectrlOverride2_save); + + offset = (s16) pi->phy_tempsense_offset; + } else { + + pwrdet_rxtx_core1_save = + read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1); + pwrdet_rxtx_core2_save = + read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2); + core1_txrf_iqcal1_save = + read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1); + core1_txrf_iqcal2_save = + read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2); + core2_txrf_iqcal1_save = + read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1); + core2_txrf_iqcal2_save = + read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2); + pd_pll_ts_save = read_radio_reg(pi, RADIO_2055_PD_PLL_TS); + + afectrlCore1_save = read_phy_reg(pi, 0xa6); + afectrlCore2_save = read_phy_reg(pi, 0xa7); + afectrlOverride_save = read_phy_reg(pi, 0xa5); + gpioSel_save = read_phy_reg(pi, 0xca); + + write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, 0x01); + write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, 0x01); + write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, 0x08); + write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, 0x08); + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x04); + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x04); + write_radio_reg(pi, RADIO_2055_PD_PLL_TS, 0x00); + + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); + xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80); + + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp, 1); + xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80); + + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_IQ, radio_temp2, 1); + xor_radio_reg(pi, RADIO_2055_CAL_TS, 0x80); + + radio_temp[0] = (radio_temp[0] + radio_temp2[0]); + radio_temp[1] = (radio_temp[1] + radio_temp2[1]); + radio_temp[2] = (radio_temp[2] + radio_temp2[2]); + radio_temp[3] = (radio_temp[3] + radio_temp2[3]); + + radio_temp[0] = + (radio_temp[0] + radio_temp[1] + radio_temp[2] + + radio_temp[3]); + + radio_temp[0] = + (radio_temp[0] + + (8 * 32)) * (950 - 350) / 63 + (350 * 8); + + radio_temp[0] = (radio_temp[0] - (8 * 420)) / 38; + + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, + pwrdet_rxtx_core1_save); + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, + pwrdet_rxtx_core2_save); + write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, + core1_txrf_iqcal1_save); + write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, + core2_txrf_iqcal1_save); + write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, + core1_txrf_iqcal2_save); + write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, + core2_txrf_iqcal2_save); + write_radio_reg(pi, RADIO_2055_PD_PLL_TS, pd_pll_ts_save); + + write_phy_reg(pi, 0xca, gpioSel_save); + write_phy_reg(pi, 0xa6, afectrlCore1_save); + write_phy_reg(pi, 0xa7, afectrlCore2_save); + write_phy_reg(pi, 0xa5, afectrlOverride_save); + } + + return (s16) radio_temp[0] + offset; +} + +static void +wlc_phy_set_rssi_2055_vcm(struct brcms_phy *pi, u8 rssi_type, u8 *vcm_buf) +{ + u8 core; + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + if (rssi_type == NPHY_RSSI_SEL_NB) { + if (core == PHY_CORE_0) { + mod_radio_reg(pi, + RADIO_2055_CORE1_B0_NBRSSI_VCM, + RADIO_2055_NBRSSI_VCM_I_MASK, + vcm_buf[2 * + core] << + RADIO_2055_NBRSSI_VCM_I_SHIFT); + mod_radio_reg(pi, + RADIO_2055_CORE1_RXBB_RSSI_CTRL5, + RADIO_2055_NBRSSI_VCM_Q_MASK, + vcm_buf[2 * core + + 1] << + RADIO_2055_NBRSSI_VCM_Q_SHIFT); + } else { + mod_radio_reg(pi, + RADIO_2055_CORE2_B0_NBRSSI_VCM, + RADIO_2055_NBRSSI_VCM_I_MASK, + vcm_buf[2 * + core] << + RADIO_2055_NBRSSI_VCM_I_SHIFT); + mod_radio_reg(pi, + RADIO_2055_CORE2_RXBB_RSSI_CTRL5, + RADIO_2055_NBRSSI_VCM_Q_MASK, + vcm_buf[2 * core + + 1] << + RADIO_2055_NBRSSI_VCM_Q_SHIFT); + } + } else { + if (core == PHY_CORE_0) + mod_radio_reg(pi, + RADIO_2055_CORE1_RXBB_RSSI_CTRL5, + RADIO_2055_WBRSSI_VCM_IQ_MASK, + vcm_buf[2 * + core] << + RADIO_2055_WBRSSI_VCM_IQ_SHIFT); + else + mod_radio_reg(pi, + RADIO_2055_CORE2_RXBB_RSSI_CTRL5, + RADIO_2055_WBRSSI_VCM_IQ_MASK, + vcm_buf[2 * + core] << + RADIO_2055_WBRSSI_VCM_IQ_SHIFT); + } + } +} + +static void wlc_phy_rssi_cal_nphy_rev3(struct brcms_phy *pi) +{ + u16 classif_state; + u16 clip_state[2]; + u16 clip_off[] = { 0xffff, 0xffff }; + s32 target_code; + u8 vcm, min_vcm; + u8 vcm_final = 0; + u8 result_idx; + s32 poll_results[8][4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }; + s32 poll_result_core[4] = { 0, 0, 0, 0 }; + s32 min_d = NPHY_RSSICAL_MAXD, curr_d; + s32 fine_digital_offset[4]; + s32 poll_results_min[4] = { 0, 0, 0, 0 }; + s32 min_poll; + u8 vcm_level_max; + u8 core; + u8 wb_cnt; + u8 rssi_type; + u16 NPHY_Rfctrlintc1_save, NPHY_Rfctrlintc2_save; + u16 NPHY_AfectrlOverride1_save, NPHY_AfectrlOverride2_save; + u16 NPHY_AfectrlCore1_save, NPHY_AfectrlCore2_save; + u16 NPHY_RfctrlOverride0_save, NPHY_RfctrlOverride1_save; + u16 NPHY_RfctrlOverrideAux0_save, NPHY_RfctrlOverrideAux1_save; + u16 NPHY_RfctrlCmd_save; + u16 NPHY_RfctrlMiscReg1_save, NPHY_RfctrlMiscReg2_save; + u16 NPHY_RfctrlRSSIOTHERS1_save, NPHY_RfctrlRSSIOTHERS2_save; + u8 rxcore_state; + u16 NPHY_REV7_RfctrlOverride3_save, NPHY_REV7_RfctrlOverride4_save; + u16 NPHY_REV7_RfctrlOverride5_save, NPHY_REV7_RfctrlOverride6_save; + u16 NPHY_REV7_RfctrlMiscReg3_save, NPHY_REV7_RfctrlMiscReg4_save; + u16 NPHY_REV7_RfctrlMiscReg5_save, NPHY_REV7_RfctrlMiscReg6_save; + + NPHY_REV7_RfctrlOverride3_save = + NPHY_REV7_RfctrlOverride4_save = + NPHY_REV7_RfctrlOverride5_save = + NPHY_REV7_RfctrlOverride6_save = + NPHY_REV7_RfctrlMiscReg3_save = + NPHY_REV7_RfctrlMiscReg4_save = + NPHY_REV7_RfctrlMiscReg5_save = + NPHY_REV7_RfctrlMiscReg6_save = 0; + + classif_state = wlc_phy_classifier_nphy(pi, 0, 0); + wlc_phy_classifier_nphy(pi, (0x7 << 0), 4); + wlc_phy_clip_det_nphy(pi, 0, clip_state); + wlc_phy_clip_det_nphy(pi, 1, clip_off); + + NPHY_Rfctrlintc1_save = read_phy_reg(pi, 0x91); + NPHY_Rfctrlintc2_save = read_phy_reg(pi, 0x92); + NPHY_AfectrlOverride1_save = read_phy_reg(pi, 0x8f); + NPHY_AfectrlOverride2_save = read_phy_reg(pi, 0xa5); + NPHY_AfectrlCore1_save = read_phy_reg(pi, 0xa6); + NPHY_AfectrlCore2_save = read_phy_reg(pi, 0xa7); + NPHY_RfctrlOverride0_save = read_phy_reg(pi, 0xe7); + NPHY_RfctrlOverride1_save = read_phy_reg(pi, 0xec); + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + NPHY_REV7_RfctrlOverride3_save = read_phy_reg(pi, 0x342); + NPHY_REV7_RfctrlOverride4_save = read_phy_reg(pi, 0x343); + NPHY_REV7_RfctrlOverride5_save = read_phy_reg(pi, 0x346); + NPHY_REV7_RfctrlOverride6_save = read_phy_reg(pi, 0x347); + } + NPHY_RfctrlOverrideAux0_save = read_phy_reg(pi, 0xe5); + NPHY_RfctrlOverrideAux1_save = read_phy_reg(pi, 0xe6); + NPHY_RfctrlCmd_save = read_phy_reg(pi, 0x78); + NPHY_RfctrlMiscReg1_save = read_phy_reg(pi, 0xf9); + NPHY_RfctrlMiscReg2_save = read_phy_reg(pi, 0xfb); + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + NPHY_REV7_RfctrlMiscReg3_save = read_phy_reg(pi, 0x340); + NPHY_REV7_RfctrlMiscReg4_save = read_phy_reg(pi, 0x341); + NPHY_REV7_RfctrlMiscReg5_save = read_phy_reg(pi, 0x344); + NPHY_REV7_RfctrlMiscReg6_save = read_phy_reg(pi, 0x345); + } + NPHY_RfctrlRSSIOTHERS1_save = read_phy_reg(pi, 0x7a); + NPHY_RfctrlRSSIOTHERS2_save = read_phy_reg(pi, 0x7d); + + wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_OFF, 0, + RADIO_MIMO_CORESEL_ALLRXTX); + wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_TRSW, 1, + RADIO_MIMO_CORESEL_ALLRXTX); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_rxrf_pu, + 0, 0, 0); + else + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0, 0); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_rx_pu, + 1, 0, 0); + else + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0, 0); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7), + 1, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 6), 1, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + } else { + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 7), 1, 0, 0); + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 6), 1, 0, 0); + } + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 5), + 0, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 4), 1, 0, + 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + } else { + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 5), 0, 0, 0); + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 4), 1, 0, 0); + } + + } else { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 4), + 0, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 5), 1, 0, + 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + } else { + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 4), 0, 0, 0); + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 5), 1, 0, 0); + } + } + + rxcore_state = wlc_phy_rxcore_getstate_nphy( + (struct brcms_phy_pub *) pi); + + vcm_level_max = 8; + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + + if ((rxcore_state & (1 << core)) == 0) + continue; + + wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, + core == + PHY_CORE_0 ? + RADIO_MIMO_CORESEL_CORE1 : + RADIO_MIMO_CORESEL_CORE2, + NPHY_RAIL_I, NPHY_RSSI_SEL_NB); + wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, + core == + PHY_CORE_0 ? + RADIO_MIMO_CORESEL_CORE1 : + RADIO_MIMO_CORESEL_CORE2, + NPHY_RAIL_Q, NPHY_RSSI_SEL_NB); + + for (vcm = 0; vcm < vcm_level_max; vcm++) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) + mod_radio_reg(pi, (core == PHY_CORE_0) ? + RADIO_2057_NB_MASTER_CORE0 : + RADIO_2057_NB_MASTER_CORE1, + RADIO_2057_VCM_MASK, vcm); + else + mod_radio_reg(pi, RADIO_2056_RX_RSSI_MISC | + ((core == + PHY_CORE_0) ? RADIO_2056_RX0 : + RADIO_2056_RX1), + RADIO_2056_VCM_MASK, + vcm << RADIO_2056_RSSI_VCM_SHIFT); + + wlc_phy_poll_rssi_nphy(pi, NPHY_RSSI_SEL_NB, + &poll_results[vcm][0], + NPHY_RSSICAL_NPOLL); + } + + for (result_idx = 0; result_idx < 4; result_idx++) { + if ((core == result_idx / 2) && + (result_idx % 2 == 0)) { + + min_d = NPHY_RSSICAL_MAXD; + min_vcm = 0; + min_poll = + NPHY_RSSICAL_MAXREAD * + NPHY_RSSICAL_NPOLL + 1; + for (vcm = 0; vcm < vcm_level_max; vcm++) { + curr_d = + poll_results[vcm][result_idx] * + poll_results[vcm][result_idx] + + poll_results[vcm][result_idx + + 1] * + poll_results[vcm][result_idx + + 1]; + if (curr_d < min_d) { + min_d = curr_d; + min_vcm = vcm; + } + if (poll_results[vcm][result_idx] < + min_poll) + min_poll = + poll_results[vcm] + [result_idx]; + } + vcm_final = min_vcm; + poll_results_min[result_idx] = min_poll; + } + } + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + mod_radio_reg(pi, (core == PHY_CORE_0) ? + RADIO_2057_NB_MASTER_CORE0 : + RADIO_2057_NB_MASTER_CORE1, + RADIO_2057_VCM_MASK, vcm_final); + else + mod_radio_reg(pi, RADIO_2056_RX_RSSI_MISC | + ((core == + PHY_CORE_0) ? RADIO_2056_RX0 : + RADIO_2056_RX1), RADIO_2056_VCM_MASK, + vcm_final << RADIO_2056_RSSI_VCM_SHIFT); + + for (result_idx = 0; result_idx < 4; result_idx++) { + if (core == result_idx / 2) { + fine_digital_offset[result_idx] = + (NPHY_RSSICAL_NB_TARGET * + NPHY_RSSICAL_NPOLL) - + poll_results[vcm_final][result_idx]; + if (fine_digital_offset[result_idx] < 0) { + fine_digital_offset[result_idx] = + abs(fine_digital_offset + [result_idx]); + fine_digital_offset[result_idx] += + (NPHY_RSSICAL_NPOLL / 2); + fine_digital_offset[result_idx] /= + NPHY_RSSICAL_NPOLL; + fine_digital_offset[result_idx] = + -fine_digital_offset[ + result_idx]; + } else { + fine_digital_offset[result_idx] += + (NPHY_RSSICAL_NPOLL / 2); + fine_digital_offset[result_idx] /= + NPHY_RSSICAL_NPOLL; + } + + if (poll_results_min[result_idx] == + NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL) + fine_digital_offset[result_idx] = + (NPHY_RSSICAL_NB_TARGET - + NPHY_RSSICAL_MAXREAD - 1); + + wlc_phy_scale_offset_rssi_nphy( + pi, 0x0, + (s8) + fine_digital_offset + [result_idx], + (result_idx / 2 == 0) ? + RADIO_MIMO_CORESEL_CORE1 : + RADIO_MIMO_CORESEL_CORE2, + (result_idx % 2 == 0) ? + NPHY_RAIL_I : NPHY_RAIL_Q, + NPHY_RSSI_SEL_NB); + } + } + + } + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + + if ((rxcore_state & (1 << core)) == 0) + continue; + + for (wb_cnt = 0; wb_cnt < 2; wb_cnt++) { + if (wb_cnt == 0) { + rssi_type = NPHY_RSSI_SEL_W1; + target_code = NPHY_RSSICAL_W1_TARGET_REV3; + } else { + rssi_type = NPHY_RSSI_SEL_W2; + target_code = NPHY_RSSICAL_W2_TARGET_REV3; + } + + wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, + core == + PHY_CORE_0 ? + RADIO_MIMO_CORESEL_CORE1 + : + RADIO_MIMO_CORESEL_CORE2, + NPHY_RAIL_I, rssi_type); + wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, + core == + PHY_CORE_0 ? + RADIO_MIMO_CORESEL_CORE1 + : + RADIO_MIMO_CORESEL_CORE2, + NPHY_RAIL_Q, rssi_type); + + wlc_phy_poll_rssi_nphy(pi, rssi_type, poll_result_core, + NPHY_RSSICAL_NPOLL); + + for (result_idx = 0; result_idx < 4; result_idx++) { + if (core == result_idx / 2) { + fine_digital_offset[result_idx] = + (target_code * + NPHY_RSSICAL_NPOLL) - + poll_result_core[result_idx]; + if (fine_digital_offset[result_idx] < + 0) { + fine_digital_offset[result_idx] + = abs( + fine_digital_offset + [result_idx]); + fine_digital_offset[result_idx] + += (NPHY_RSSICAL_NPOLL + / 2); + fine_digital_offset[result_idx] + /= NPHY_RSSICAL_NPOLL; + fine_digital_offset[result_idx] + = -fine_digital_offset + [result_idx]; + } else { + fine_digital_offset[result_idx] + += (NPHY_RSSICAL_NPOLL + / 2); + fine_digital_offset[result_idx] + /= NPHY_RSSICAL_NPOLL; + } + + wlc_phy_scale_offset_rssi_nphy( + pi, 0x0, + (s8) + fine_digital_offset + [core * + 2], + (core == PHY_CORE_0) ? + RADIO_MIMO_CORESEL_CORE1 : + RADIO_MIMO_CORESEL_CORE2, + (result_idx % 2 == 0) ? + NPHY_RAIL_I : + NPHY_RAIL_Q, + rssi_type); + } + } + + } + } + + write_phy_reg(pi, 0x91, NPHY_Rfctrlintc1_save); + write_phy_reg(pi, 0x92, NPHY_Rfctrlintc2_save); + + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); + + mod_phy_reg(pi, 0xe7, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x78, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0xe7, (0x1 << 0), 0); + + mod_phy_reg(pi, 0xec, (0x1 << 0), 1 << 0); + mod_phy_reg(pi, 0x78, (0x1 << 1), 1 << 1); + mod_phy_reg(pi, 0xec, (0x1 << 0), 0); + + write_phy_reg(pi, 0x8f, NPHY_AfectrlOverride1_save); + write_phy_reg(pi, 0xa5, NPHY_AfectrlOverride2_save); + write_phy_reg(pi, 0xa6, NPHY_AfectrlCore1_save); + write_phy_reg(pi, 0xa7, NPHY_AfectrlCore2_save); + write_phy_reg(pi, 0xe7, NPHY_RfctrlOverride0_save); + write_phy_reg(pi, 0xec, NPHY_RfctrlOverride1_save); + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + write_phy_reg(pi, 0x342, NPHY_REV7_RfctrlOverride3_save); + write_phy_reg(pi, 0x343, NPHY_REV7_RfctrlOverride4_save); + write_phy_reg(pi, 0x346, NPHY_REV7_RfctrlOverride5_save); + write_phy_reg(pi, 0x347, NPHY_REV7_RfctrlOverride6_save); + } + write_phy_reg(pi, 0xe5, NPHY_RfctrlOverrideAux0_save); + write_phy_reg(pi, 0xe6, NPHY_RfctrlOverrideAux1_save); + write_phy_reg(pi, 0x78, NPHY_RfctrlCmd_save); + write_phy_reg(pi, 0xf9, NPHY_RfctrlMiscReg1_save); + write_phy_reg(pi, 0xfb, NPHY_RfctrlMiscReg2_save); + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + write_phy_reg(pi, 0x340, NPHY_REV7_RfctrlMiscReg3_save); + write_phy_reg(pi, 0x341, NPHY_REV7_RfctrlMiscReg4_save); + write_phy_reg(pi, 0x344, NPHY_REV7_RfctrlMiscReg5_save); + write_phy_reg(pi, 0x345, NPHY_REV7_RfctrlMiscReg6_save); + } + write_phy_reg(pi, 0x7a, NPHY_RfctrlRSSIOTHERS1_save); + write_phy_reg(pi, 0x7d, NPHY_RfctrlRSSIOTHERS2_save); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + pi->rssical_cache.rssical_radio_regs_2G[0] = + read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0); + pi->rssical_cache.rssical_radio_regs_2G[1] = + read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1); + } else { + pi->rssical_cache.rssical_radio_regs_2G[0] = + read_radio_reg(pi, + RADIO_2056_RX_RSSI_MISC | + RADIO_2056_RX0); + pi->rssical_cache.rssical_radio_regs_2G[1] = + read_radio_reg(pi, + RADIO_2056_RX_RSSI_MISC | + RADIO_2056_RX1); + } + + pi->rssical_cache.rssical_phyregs_2G[0] = + read_phy_reg(pi, 0x1a6); + pi->rssical_cache.rssical_phyregs_2G[1] = + read_phy_reg(pi, 0x1ac); + pi->rssical_cache.rssical_phyregs_2G[2] = + read_phy_reg(pi, 0x1b2); + pi->rssical_cache.rssical_phyregs_2G[3] = + read_phy_reg(pi, 0x1b8); + pi->rssical_cache.rssical_phyregs_2G[4] = + read_phy_reg(pi, 0x1a4); + pi->rssical_cache.rssical_phyregs_2G[5] = + read_phy_reg(pi, 0x1aa); + pi->rssical_cache.rssical_phyregs_2G[6] = + read_phy_reg(pi, 0x1b0); + pi->rssical_cache.rssical_phyregs_2G[7] = + read_phy_reg(pi, 0x1b6); + pi->rssical_cache.rssical_phyregs_2G[8] = + read_phy_reg(pi, 0x1a5); + pi->rssical_cache.rssical_phyregs_2G[9] = + read_phy_reg(pi, 0x1ab); + pi->rssical_cache.rssical_phyregs_2G[10] = + read_phy_reg(pi, 0x1b1); + pi->rssical_cache.rssical_phyregs_2G[11] = + read_phy_reg(pi, 0x1b7); + + pi->nphy_rssical_chanspec_2G = pi->radio_chanspec; + } else { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + pi->rssical_cache.rssical_radio_regs_5G[0] = + read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE0); + pi->rssical_cache.rssical_radio_regs_5G[1] = + read_radio_reg(pi, RADIO_2057_NB_MASTER_CORE1); + } else { + pi->rssical_cache.rssical_radio_regs_5G[0] = + read_radio_reg(pi, + RADIO_2056_RX_RSSI_MISC | + RADIO_2056_RX0); + pi->rssical_cache.rssical_radio_regs_5G[1] = + read_radio_reg(pi, + RADIO_2056_RX_RSSI_MISC | + RADIO_2056_RX1); + } + + pi->rssical_cache.rssical_phyregs_5G[0] = + read_phy_reg(pi, 0x1a6); + pi->rssical_cache.rssical_phyregs_5G[1] = + read_phy_reg(pi, 0x1ac); + pi->rssical_cache.rssical_phyregs_5G[2] = + read_phy_reg(pi, 0x1b2); + pi->rssical_cache.rssical_phyregs_5G[3] = + read_phy_reg(pi, 0x1b8); + pi->rssical_cache.rssical_phyregs_5G[4] = + read_phy_reg(pi, 0x1a4); + pi->rssical_cache.rssical_phyregs_5G[5] = + read_phy_reg(pi, 0x1aa); + pi->rssical_cache.rssical_phyregs_5G[6] = + read_phy_reg(pi, 0x1b0); + pi->rssical_cache.rssical_phyregs_5G[7] = + read_phy_reg(pi, 0x1b6); + pi->rssical_cache.rssical_phyregs_5G[8] = + read_phy_reg(pi, 0x1a5); + pi->rssical_cache.rssical_phyregs_5G[9] = + read_phy_reg(pi, 0x1ab); + pi->rssical_cache.rssical_phyregs_5G[10] = + read_phy_reg(pi, 0x1b1); + pi->rssical_cache.rssical_phyregs_5G[11] = + read_phy_reg(pi, 0x1b7); + + pi->nphy_rssical_chanspec_5G = pi->radio_chanspec; + } + + wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state); + wlc_phy_clip_det_nphy(pi, 1, clip_state); +} + +static void wlc_phy_rssi_cal_nphy_rev2(struct brcms_phy *pi, u8 rssi_type) +{ + s32 target_code; + u16 classif_state; + u16 clip_state[2]; + u16 rssi_ctrl_state[2], pd_state[2]; + u16 rfctrlintc_state[2], rfpdcorerxtx_state[2]; + u16 rfctrlintc_override_val; + u16 clip_off[] = { 0xffff, 0xffff }; + u16 rf_pd_val, pd_mask, rssi_ctrl_mask; + u8 vcm, min_vcm, vcm_tmp[4]; + u8 vcm_final[4] = { 0, 0, 0, 0 }; + u8 result_idx, ctr; + s32 poll_results[4][4] = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} + }; + s32 poll_miniq[4][2] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} + }; + s32 min_d, curr_d; + s32 fine_digital_offset[4]; + s32 poll_results_min[4] = { 0, 0, 0, 0 }; + s32 min_poll; + + switch (rssi_type) { + case NPHY_RSSI_SEL_NB: + target_code = NPHY_RSSICAL_NB_TARGET; + break; + case NPHY_RSSI_SEL_W1: + target_code = NPHY_RSSICAL_W1_TARGET; + break; + case NPHY_RSSI_SEL_W2: + target_code = NPHY_RSSICAL_W2_TARGET; + break; + default: + return; + break; + } + + classif_state = wlc_phy_classifier_nphy(pi, 0, 0); + wlc_phy_classifier_nphy(pi, (0x7 << 0), 4); + wlc_phy_clip_det_nphy(pi, 0, clip_state); + wlc_phy_clip_det_nphy(pi, 1, clip_off); + + rf_pd_val = (rssi_type == NPHY_RSSI_SEL_NB) ? 0x6 : 0x4; + rfctrlintc_override_val = + CHSPEC_IS5G(pi->radio_chanspec) ? 0x140 : 0x110; + + rfctrlintc_state[0] = read_phy_reg(pi, 0x91); + rfpdcorerxtx_state[0] = read_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX); + write_phy_reg(pi, 0x91, rfctrlintc_override_val); + write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rf_pd_val); + + rfctrlintc_state[1] = read_phy_reg(pi, 0x92); + rfpdcorerxtx_state[1] = read_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX); + write_phy_reg(pi, 0x92, rfctrlintc_override_val); + write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rf_pd_val); + + pd_mask = RADIO_2055_NBRSSI_PD | RADIO_2055_WBRSSI_G1_PD | + RADIO_2055_WBRSSI_G2_PD; + pd_state[0] = + read_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC) & pd_mask; + pd_state[1] = + read_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC) & pd_mask; + mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, 0); + mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, 0); + rssi_ctrl_mask = RADIO_2055_NBRSSI_SEL | RADIO_2055_WBRSSI_G1_SEL | + RADIO_2055_WBRSSI_G2_SEL; + rssi_ctrl_state[0] = + read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE1) & rssi_ctrl_mask; + rssi_ctrl_state[1] = + read_radio_reg(pi, RADIO_2055_SP_RSSI_CORE2) & rssi_ctrl_mask; + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_ALLRX, rssi_type); + + wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX, + NPHY_RAIL_I, rssi_type); + wlc_phy_scale_offset_rssi_nphy(pi, 0x0, 0x0, RADIO_MIMO_CORESEL_ALLRX, + NPHY_RAIL_Q, rssi_type); + + for (vcm = 0; vcm < 4; vcm++) { + + vcm_tmp[0] = vcm_tmp[1] = vcm_tmp[2] = vcm_tmp[3] = vcm; + if (rssi_type != NPHY_RSSI_SEL_W2) + wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_tmp); + + wlc_phy_poll_rssi_nphy(pi, rssi_type, &poll_results[vcm][0], + NPHY_RSSICAL_NPOLL); + + if ((rssi_type == NPHY_RSSI_SEL_W1) + || (rssi_type == NPHY_RSSI_SEL_W2)) { + for (ctr = 0; ctr < 2; ctr++) + poll_miniq[vcm][ctr] = + min(poll_results[vcm][ctr * 2 + 0], + poll_results[vcm][ctr * 2 + 1]); + } + } + + for (result_idx = 0; result_idx < 4; result_idx++) { + min_d = NPHY_RSSICAL_MAXD; + min_vcm = 0; + min_poll = NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL + 1; + for (vcm = 0; vcm < 4; vcm++) { + curr_d = abs(((rssi_type == NPHY_RSSI_SEL_NB) ? + poll_results[vcm][result_idx] : + poll_miniq[vcm][result_idx / 2]) - + (target_code * NPHY_RSSICAL_NPOLL)); + if (curr_d < min_d) { + min_d = curr_d; + min_vcm = vcm; + } + if (poll_results[vcm][result_idx] < min_poll) + min_poll = poll_results[vcm][result_idx]; + } + vcm_final[result_idx] = min_vcm; + poll_results_min[result_idx] = min_poll; + } + + if (rssi_type != NPHY_RSSI_SEL_W2) + wlc_phy_set_rssi_2055_vcm(pi, rssi_type, vcm_final); + + for (result_idx = 0; result_idx < 4; result_idx++) { + fine_digital_offset[result_idx] = + (target_code * NPHY_RSSICAL_NPOLL) - + poll_results[vcm_final[result_idx]][result_idx]; + if (fine_digital_offset[result_idx] < 0) { + fine_digital_offset[result_idx] = + abs(fine_digital_offset[result_idx]); + fine_digital_offset[result_idx] += + (NPHY_RSSICAL_NPOLL / 2); + fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL; + fine_digital_offset[result_idx] = + -fine_digital_offset[result_idx]; + } else { + fine_digital_offset[result_idx] += + (NPHY_RSSICAL_NPOLL / 2); + fine_digital_offset[result_idx] /= NPHY_RSSICAL_NPOLL; + } + + if (poll_results_min[result_idx] == + NPHY_RSSICAL_MAXREAD * NPHY_RSSICAL_NPOLL) + fine_digital_offset[result_idx] = + (target_code - NPHY_RSSICAL_MAXREAD - 1); + + wlc_phy_scale_offset_rssi_nphy(pi, 0x0, + (s8) + fine_digital_offset[result_idx], + (result_idx / 2 == + 0) ? RADIO_MIMO_CORESEL_CORE1 : + RADIO_MIMO_CORESEL_CORE2, + (result_idx % 2 == + 0) ? NPHY_RAIL_I : NPHY_RAIL_Q, + rssi_type); + } + + mod_radio_reg(pi, RADIO_2055_PD_CORE1_RSSI_MISC, pd_mask, pd_state[0]); + mod_radio_reg(pi, RADIO_2055_PD_CORE2_RSSI_MISC, pd_mask, pd_state[1]); + if (rssi_ctrl_state[0] == RADIO_2055_NBRSSI_SEL) + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1, + NPHY_RSSI_SEL_NB); + else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G1_SEL) + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1, + NPHY_RSSI_SEL_W1); + else if (rssi_ctrl_state[0] == RADIO_2055_WBRSSI_G2_SEL) + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1, + NPHY_RSSI_SEL_W2); + else + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE1, + NPHY_RSSI_SEL_W2); + if (rssi_ctrl_state[1] == RADIO_2055_NBRSSI_SEL) + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2, + NPHY_RSSI_SEL_NB); + else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G1_SEL) + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2, + NPHY_RSSI_SEL_W1); + else if (rssi_ctrl_state[1] == RADIO_2055_WBRSSI_G2_SEL) + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2, + NPHY_RSSI_SEL_W2); + else + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_CORE2, + NPHY_RSSI_SEL_W2); + + wlc_phy_rssisel_nphy(pi, RADIO_MIMO_CORESEL_OFF, rssi_type); + + write_phy_reg(pi, 0x91, rfctrlintc_state[0]); + write_radio_reg(pi, RADIO_2055_PD_CORE1_RXTX, rfpdcorerxtx_state[0]); + write_phy_reg(pi, 0x92, rfctrlintc_state[1]); + write_radio_reg(pi, RADIO_2055_PD_CORE2_RXTX, rfpdcorerxtx_state[1]); + + wlc_phy_classifier_nphy(pi, (0x7 << 0), classif_state); + wlc_phy_clip_det_nphy(pi, 1, clip_state); + + wlc_phy_resetcca_nphy(pi); +} + +void wlc_phy_rssi_cal_nphy(struct brcms_phy *pi) +{ + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + wlc_phy_rssi_cal_nphy_rev3(pi); + } else { + wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_NB); + wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W1); + wlc_phy_rssi_cal_nphy_rev2(pi, NPHY_RSSI_SEL_W2); + } +} + +int +wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, struct d11rxhdr *rxh) +{ + s16 rxpwr, rxpwr0, rxpwr1; + s16 phyRx0_l, phyRx2_l; + + rxpwr = 0; + rxpwr0 = rxh->PhyRxStatus_1 & PRXS1_nphy_PWR0_MASK; + rxpwr1 = (rxh->PhyRxStatus_1 & PRXS1_nphy_PWR1_MASK) >> 8; + + if (rxpwr0 > 127) + rxpwr0 -= 256; + if (rxpwr1 > 127) + rxpwr1 -= 256; + + phyRx0_l = rxh->PhyRxStatus_0 & 0x00ff; + phyRx2_l = rxh->PhyRxStatus_2 & 0x00ff; + if (phyRx2_l > 127) + phyRx2_l -= 256; + + if (((rxpwr0 == 16) || (rxpwr0 == 32))) { + rxpwr0 = rxpwr1; + rxpwr1 = phyRx2_l; + } + + if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MAX) + rxpwr = (rxpwr0 > rxpwr1) ? rxpwr0 : rxpwr1; + else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_MIN) + rxpwr = (rxpwr0 < rxpwr1) ? rxpwr0 : rxpwr1; + else if (pi->sh->rssi_mode == RSSI_ANT_MERGE_AVG) + rxpwr = (rxpwr0 + rxpwr1) >> 1; + + return rxpwr; +} + +static void +wlc_phy_loadsampletable_nphy(struct brcms_phy *pi, struct cordic_iq *tone_buf, + u16 num_samps) +{ + u16 t; + u32 *data_buf = NULL; + + data_buf = kmalloc(sizeof(u32) * num_samps, GFP_ATOMIC); + if (data_buf == NULL) + return; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + for (t = 0; t < num_samps; t++) + data_buf[t] = ((((unsigned int)tone_buf[t].i) & 0x3ff) << 10) | + (((unsigned int)tone_buf[t].q) & 0x3ff); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SAMPLEPLAY, num_samps, 0, 32, + data_buf); + + kfree(data_buf); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static u16 +wlc_phy_gen_load_samples_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, + u8 dac_test_mode) +{ + u8 phy_bw, is_phybw40; + u16 num_samps, t, spur; + s32 theta = 0, rot = 0; + u32 tbl_len; + struct cordic_iq *tone_buf = NULL; + + is_phybw40 = CHSPEC_IS40(pi->radio_chanspec); + phy_bw = (is_phybw40 == 1) ? 40 : 20; + tbl_len = (phy_bw << 3); + + if (dac_test_mode == 1) { + spur = read_phy_reg(pi, 0x01); + spur = (spur >> 15) & 1; + phy_bw = (spur == 1) ? 82 : 80; + phy_bw = (is_phybw40 == 1) ? (phy_bw << 1) : phy_bw; + + tbl_len = (phy_bw << 1); + } + + tone_buf = kmalloc(sizeof(struct cordic_iq) * tbl_len, GFP_ATOMIC); + if (tone_buf == NULL) + return 0; + + num_samps = (u16) tbl_len; + rot = ((f_kHz * 36) / phy_bw) / 100; + theta = 0; + + for (t = 0; t < num_samps; t++) { + + tone_buf[t] = cordic_calc_iq(theta); + + theta += rot; + + tone_buf[t].q = (s32) FLOAT(tone_buf[t].q * max_val); + tone_buf[t].i = (s32) FLOAT(tone_buf[t].i * max_val); + } + + wlc_phy_loadsampletable_nphy(pi, tone_buf, num_samps); + + kfree(tone_buf); + + return num_samps; +} + +static void +wlc_phy_runsamples_nphy(struct brcms_phy *pi, u16 num_samps, u16 loops, + u16 wait, u8 iqmode, u8 dac_test_mode, + bool modify_bbmult) +{ + u16 bb_mult; + u8 phy_bw, sample_cmd; + u16 orig_RfseqCoreActv; + u16 lpf_bw_ctl_override3, lpf_bw_ctl_override4, lpf_bw_ctl_miscreg3, + lpf_bw_ctl_miscreg4; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + phy_bw = 20; + if (CHSPEC_IS40(pi->radio_chanspec)) + phy_bw = 40; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + lpf_bw_ctl_override3 = read_phy_reg(pi, 0x342) & (0x1 << 7); + lpf_bw_ctl_override4 = read_phy_reg(pi, 0x343) & (0x1 << 7); + if (lpf_bw_ctl_override3 | lpf_bw_ctl_override4) { + lpf_bw_ctl_miscreg3 = read_phy_reg(pi, 0x340) & + (0x7 << 8); + lpf_bw_ctl_miscreg4 = read_phy_reg(pi, 0x341) & + (0x7 << 8); + } else { + wlc_phy_rfctrl_override_nphy_rev7( + pi, + (0x1 << 7), + wlc_phy_read_lpf_bw_ctl_nphy + (pi, + 0), 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + + pi->nphy_sample_play_lpf_bw_ctl_ovr = true; + + lpf_bw_ctl_miscreg3 = read_phy_reg(pi, 0x340) & + (0x7 << 8); + lpf_bw_ctl_miscreg4 = read_phy_reg(pi, 0x341) & + (0x7 << 8); + } + } + + if ((pi->nphy_bb_mult_save & BB_MULT_VALID_MASK) == 0) { + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16, + &bb_mult); + pi->nphy_bb_mult_save = + BB_MULT_VALID_MASK | (bb_mult & BB_MULT_MASK); + } + + if (modify_bbmult) { + bb_mult = (phy_bw == 20) ? 100 : 71; + bb_mult = (bb_mult << 8) + bb_mult; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16, + &bb_mult); + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); + + write_phy_reg(pi, 0xc6, num_samps - 1); + + if (loops != 0xffff) + write_phy_reg(pi, 0xc4, loops - 1); + else + write_phy_reg(pi, 0xc4, loops); + + write_phy_reg(pi, 0xc5, wait); + + orig_RfseqCoreActv = read_phy_reg(pi, 0xa1); + or_phy_reg(pi, 0xa1, NPHY_RfseqMode_CoreActv_override); + if (iqmode) { + + and_phy_reg(pi, 0xc2, 0x7FFF); + + or_phy_reg(pi, 0xc2, 0x8000); + } else { + + sample_cmd = (dac_test_mode == 1) ? 0x5 : 0x1; + write_phy_reg(pi, 0xc3, sample_cmd); + } + + SPINWAIT(((read_phy_reg(pi, 0xa4) & 0x1) == 1), 1000); + + write_phy_reg(pi, 0xa1, orig_RfseqCoreActv); +} + +int +wlc_phy_tx_tone_nphy(struct brcms_phy *pi, u32 f_kHz, u16 max_val, + u8 iqmode, u8 dac_test_mode, bool modify_bbmult) +{ + u16 num_samps; + u16 loops = 0xffff; + u16 wait = 0; + + num_samps = wlc_phy_gen_load_samples_nphy(pi, f_kHz, max_val, + dac_test_mode); + if (num_samps == 0) + return -EBADE; + + wlc_phy_runsamples_nphy(pi, num_samps, loops, wait, iqmode, + dac_test_mode, modify_bbmult); + + return 0; +} + +void wlc_phy_stopplayback_nphy(struct brcms_phy *pi) +{ + u16 playback_status; + u16 bb_mult; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + playback_status = read_phy_reg(pi, 0xc7); + if (playback_status & 0x1) + or_phy_reg(pi, 0xc3, NPHY_sampleCmd_STOP); + else if (playback_status & 0x2) + and_phy_reg(pi, 0xc2, + (u16) ~NPHY_iqloCalCmdGctl_IQLO_CAL_EN); + + and_phy_reg(pi, 0xc3, (u16) ~(0x1 << 2)); + + if ((pi->nphy_bb_mult_save & BB_MULT_VALID_MASK) != 0) { + + bb_mult = pi->nphy_bb_mult_save & BB_MULT_MASK; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, 87, 16, + &bb_mult); + + pi->nphy_bb_mult_save = 0; + } + + if (NREV_IS(pi->pubpi.phy_rev, 7) || NREV_GE(pi->pubpi.phy_rev, 8)) { + if (pi->nphy_sample_play_lpf_bw_ctl_ovr) { + wlc_phy_rfctrl_override_nphy_rev7( + pi, + (0x1 << 7), + 0, 0, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + pi->nphy_sample_play_lpf_bw_ctl_ovr = false; + } + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static u32 *brcms_phy_get_tx_pwrctrl_tbl(struct brcms_phy *pi) +{ + u32 *tx_pwrctrl_tbl = NULL; + uint phyrev = pi->pubpi.phy_rev; + + if (PHY_IPA(pi)) { + tx_pwrctrl_tbl = + wlc_phy_get_ipa_gaintbl_nphy(pi); + } else { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (NREV_IS(phyrev, 3)) + tx_pwrctrl_tbl = nphy_tpc_5GHz_txgain_rev3; + else if (NREV_IS(phyrev, 4)) + tx_pwrctrl_tbl = + (pi->srom_fem5g.extpagain == 3) ? + nphy_tpc_5GHz_txgain_HiPwrEPA : + nphy_tpc_5GHz_txgain_rev4; + else + tx_pwrctrl_tbl = nphy_tpc_5GHz_txgain_rev5; + } else { + if (NREV_GE(phyrev, 7)) { + if (pi->pubpi.radiorev == 3) + tx_pwrctrl_tbl = + nphy_tpc_txgain_epa_2057rev3; + else if (pi->pubpi.radiorev == 5) + tx_pwrctrl_tbl = + nphy_tpc_txgain_epa_2057rev5; + } else { + if (NREV_GE(phyrev, 5) && + (pi->srom_fem2g.extpagain == 3)) + tx_pwrctrl_tbl = + nphy_tpc_txgain_HiPwrEPA; + else + tx_pwrctrl_tbl = + nphy_tpc_txgain_rev3; + } + } + } + return tx_pwrctrl_tbl; +} + +struct nphy_txgains wlc_phy_get_tx_gain_nphy(struct brcms_phy *pi) +{ + u16 base_idx[2], curr_gain[2]; + u8 core_no; + struct nphy_txgains target_gain; + u32 *tx_pwrctrl_tbl = NULL; + + if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) { + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, + curr_gain); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); + + for (core_no = 0; core_no < 2; core_no++) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + target_gain.ipa[core_no] = + curr_gain[core_no] & 0x0007; + target_gain.pad[core_no] = + ((curr_gain[core_no] & 0x00F8) >> 3); + target_gain.pga[core_no] = + ((curr_gain[core_no] & 0x0F00) >> 8); + target_gain.txgm[core_no] = + ((curr_gain[core_no] & 0x7000) >> 12); + target_gain.txlpf[core_no] = + ((curr_gain[core_no] & 0x8000) >> 15); + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + target_gain.ipa[core_no] = + curr_gain[core_no] & 0x000F; + target_gain.pad[core_no] = + ((curr_gain[core_no] & 0x00F0) >> 4); + target_gain.pga[core_no] = + ((curr_gain[core_no] & 0x0F00) >> 8); + target_gain.txgm[core_no] = + ((curr_gain[core_no] & 0x7000) >> 12); + } else { + target_gain.ipa[core_no] = + curr_gain[core_no] & 0x0003; + target_gain.pad[core_no] = + ((curr_gain[core_no] & 0x000C) >> 2); + target_gain.pga[core_no] = + ((curr_gain[core_no] & 0x0070) >> 4); + target_gain.txgm[core_no] = + ((curr_gain[core_no] & 0x0380) >> 7); + } + } + } else { + uint phyrev = pi->pubpi.phy_rev; + + base_idx[0] = (read_phy_reg(pi, 0x1ed) >> 8) & 0x7f; + base_idx[1] = (read_phy_reg(pi, 0x1ee) >> 8) & 0x7f; + for (core_no = 0; core_no < 2; core_no++) { + if (NREV_GE(phyrev, 3)) { + tx_pwrctrl_tbl = + brcms_phy_get_tx_pwrctrl_tbl(pi); + if (NREV_GE(phyrev, 7)) { + target_gain.ipa[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 16) & 0x7; + target_gain.pad[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 19) & 0x1f; + target_gain.pga[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 24) & 0xf; + target_gain.txgm[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 28) & 0x7; + target_gain.txlpf[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 31) & 0x1; + } else { + target_gain.ipa[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 16) & 0xf; + target_gain.pad[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 20) & 0xf; + target_gain.pga[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 24) & 0xf; + target_gain.txgm[core_no] = + (tx_pwrctrl_tbl + [base_idx[core_no]] + >> 28) & 0x7; + } + } else { + target_gain.ipa[core_no] = + (nphy_tpc_txgain[base_idx[core_no]] >> + 16) & 0x3; + target_gain.pad[core_no] = + (nphy_tpc_txgain[base_idx[core_no]] >> + 18) & 0x3; + target_gain.pga[core_no] = + (nphy_tpc_txgain[base_idx[core_no]] >> + 20) & 0x7; + target_gain.txgm[core_no] = + (nphy_tpc_txgain[base_idx[core_no]] >> + 23) & 0x7; + } + } + } + + return target_gain; +} + +static void +wlc_phy_iqcal_gainparams_nphy(struct brcms_phy *pi, u16 core_no, + struct nphy_txgains target_gain, + struct nphy_iqcal_params *params) +{ + u8 k; + int idx; + u16 gain_index; + u8 band_idx = (CHSPEC_IS5G(pi->radio_chanspec) ? 1 : 0); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) + params->txlpf = target_gain.txlpf[core_no]; + + params->txgm = target_gain.txgm[core_no]; + params->pga = target_gain.pga[core_no]; + params->pad = target_gain.pad[core_no]; + params->ipa = target_gain.ipa[core_no]; + if (NREV_GE(pi->pubpi.phy_rev, 7)) + params->cal_gain = + ((params->txlpf << 15) | (params->txgm << 12) | + (params->pga << 8) | + (params->pad << 3) | (params->ipa)); + else + params->cal_gain = + ((params->txgm << 12) | (params->pga << 8) | + (params->pad << 4) | (params->ipa)); + + params->ncorr[0] = 0x79; + params->ncorr[1] = 0x79; + params->ncorr[2] = 0x79; + params->ncorr[3] = 0x79; + params->ncorr[4] = 0x79; + } else { + + gain_index = ((target_gain.pad[core_no] << 0) | + (target_gain.pga[core_no] << 4) | + (target_gain.txgm[core_no] << 8)); + + idx = -1; + for (k = 0; k < NPHY_IQCAL_NUMGAINS; k++) { + if (tbl_iqcal_gainparams_nphy[band_idx][k][0] == + gain_index) { + idx = k; + break; + } + } + + params->txgm = tbl_iqcal_gainparams_nphy[band_idx][k][1]; + params->pga = tbl_iqcal_gainparams_nphy[band_idx][k][2]; + params->pad = tbl_iqcal_gainparams_nphy[band_idx][k][3]; + params->cal_gain = ((params->txgm << 7) | (params->pga << 4) | + (params->pad << 2)); + params->ncorr[0] = tbl_iqcal_gainparams_nphy[band_idx][k][4]; + params->ncorr[1] = tbl_iqcal_gainparams_nphy[band_idx][k][5]; + params->ncorr[2] = tbl_iqcal_gainparams_nphy[band_idx][k][6]; + params->ncorr[3] = tbl_iqcal_gainparams_nphy[band_idx][k][7]; + } +} + +static void wlc_phy_txcal_radio_setup_nphy(struct brcms_phy *pi) +{ + u16 jtag_core, core; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + for (core = 0; core <= 1; core++) { + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 0] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MASTER); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 1] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + IQCAL_VCM_HG); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 2] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + IQCAL_IDAC); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 3] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSI_VCM); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 4] = 0; + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 5] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MUX); + + if (pi->pubpi.radiorev != 5) + pi->tx_rx_cal_radio_saveregs[(core * 11) + 6] = + READ_RADIO_REG3(pi, RADIO_2057, TX, + core, + TSSIA); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 7] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 8] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSI_MISC1); + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MASTER, 0x0a); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + IQCAL_VCM_HG, 0x43); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + IQCAL_IDAC, 0x55); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSI_VCM, 0x00); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSIG, 0x00); + if (pi->use_int_tx_iqlo_cal_nphy) { + WRITE_RADIO_REG3(pi, RADIO_2057, TX, + core, TX_SSI_MUX, 0x4); + if (!(pi-> + internal_tx_iqlo_cal_tapoff_intpa_nphy)) + WRITE_RADIO_REG3(pi, RADIO_2057, + TX, core, + TSSIA, 0x31); + else + WRITE_RADIO_REG3(pi, RADIO_2057, + TX, core, + TSSIA, 0x21); + } + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSI_MISC1, 0x00); + } else { + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MASTER, 0x06); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + IQCAL_VCM_HG, 0x43); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + IQCAL_IDAC, 0x55); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSI_VCM, 0x00); + + if (pi->pubpi.radiorev != 5) + WRITE_RADIO_REG3(pi, RADIO_2057, TX, + core, TSSIA, 0x00); + if (pi->use_int_tx_iqlo_cal_nphy) { + WRITE_RADIO_REG3(pi, RADIO_2057, TX, + core, TX_SSI_MUX, + 0x06); + if (!(pi-> + internal_tx_iqlo_cal_tapoff_intpa_nphy)) + WRITE_RADIO_REG3(pi, RADIO_2057, + TX, core, + TSSIG, 0x31); + else + WRITE_RADIO_REG3(pi, RADIO_2057, + TX, core, + TSSIG, 0x21); + } + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSI_MISC1, 0x00); + } + } + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + for (core = 0; core <= 1; core++) { + jtag_core = + (core == + PHY_CORE_0) ? RADIO_2056_TX0 : RADIO_2056_TX1; + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 0] = + read_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MASTER | + jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 1] = + read_radio_reg(pi, + RADIO_2056_TX_IQCAL_VCM_HG | + jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 2] = + read_radio_reg(pi, + RADIO_2056_TX_IQCAL_IDAC | + jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 3] = + read_radio_reg( + pi, + RADIO_2056_TX_TSSI_VCM | + jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 4] = + read_radio_reg(pi, + RADIO_2056_TX_TX_AMP_DET | + jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 5] = + read_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MUX | + jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 6] = + read_radio_reg(pi, + RADIO_2056_TX_TSSIA | jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 7] = + read_radio_reg(pi, + RADIO_2056_TX_TSSIG | jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 8] = + read_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC1 | + jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 9] = + read_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC2 | + jtag_core); + + pi->tx_rx_cal_radio_saveregs[(core * 11) + 10] = + read_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC3 | + jtag_core); + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + write_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MASTER | + jtag_core, 0x0a); + write_radio_reg(pi, + RADIO_2056_TX_IQCAL_VCM_HG | + jtag_core, 0x40); + write_radio_reg(pi, + RADIO_2056_TX_IQCAL_IDAC | + jtag_core, 0x55); + write_radio_reg(pi, + RADIO_2056_TX_TSSI_VCM | + jtag_core, 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TX_AMP_DET | + jtag_core, 0x00); + + if (PHY_IPA(pi)) { + write_radio_reg( + pi, + RADIO_2056_TX_TX_SSI_MUX + | jtag_core, 0x4); + write_radio_reg(pi, + RADIO_2056_TX_TSSIA | + jtag_core, 0x1); + } else { + write_radio_reg( + pi, + RADIO_2056_TX_TX_SSI_MUX + | jtag_core, 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TSSIA | + jtag_core, 0x2f); + } + write_radio_reg(pi, + RADIO_2056_TX_TSSIG | jtag_core, + 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC1 | + jtag_core, 0x00); + + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC2 | + jtag_core, 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC3 | + jtag_core, 0x00); + } else { + write_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MASTER | + jtag_core, 0x06); + write_radio_reg(pi, + RADIO_2056_TX_IQCAL_VCM_HG | + jtag_core, 0x40); + write_radio_reg(pi, + RADIO_2056_TX_IQCAL_IDAC | + jtag_core, 0x55); + write_radio_reg(pi, + RADIO_2056_TX_TSSI_VCM | + jtag_core, 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TX_AMP_DET | + jtag_core, 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TSSIA | jtag_core, + 0x00); + + if (PHY_IPA(pi)) { + + write_radio_reg( + pi, + RADIO_2056_TX_TX_SSI_MUX + | jtag_core, 0x06); + if (NREV_LT(pi->pubpi.phy_rev, 5)) + write_radio_reg( + pi, + RADIO_2056_TX_TSSIG + | jtag_core, + 0x11); + else + write_radio_reg( + pi, + RADIO_2056_TX_TSSIG + | jtag_core, + 0x1); + } else { + write_radio_reg( + pi, + RADIO_2056_TX_TX_SSI_MUX + | jtag_core, 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TSSIG | + jtag_core, 0x20); + } + + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC1 | + jtag_core, 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC2 | + jtag_core, 0x00); + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC3 | + jtag_core, 0x00); + } + } + } else { + + pi->tx_rx_cal_radio_saveregs[0] = + read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1); + write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, 0x29); + pi->tx_rx_cal_radio_saveregs[1] = + read_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2); + write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, 0x54); + + pi->tx_rx_cal_radio_saveregs[2] = + read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1); + write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, 0x29); + pi->tx_rx_cal_radio_saveregs[3] = + read_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2); + write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, 0x54); + + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1); + pi->tx_rx_cal_radio_saveregs[5] = + read_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2); + + if ((read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand) == + 0) { + + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x04); + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x04); + } else { + + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, 0x20); + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, 0x20); + } + + if (NREV_LT(pi->pubpi.phy_rev, 2)) { + + or_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, 0x20); + or_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, 0x20); + } else { + + and_radio_reg(pi, RADIO_2055_CORE1_TX_BB_MXGM, 0xdf); + and_radio_reg(pi, RADIO_2055_CORE2_TX_BB_MXGM, 0xdf); + } + } +} + +static void wlc_phy_txcal_radio_cleanup_nphy(struct brcms_phy *pi) +{ + u16 jtag_core, core; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + for (core = 0; core <= 1; core++) { + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TX_SSI_MASTER, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 0]); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_VCM_HG, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 1]); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, IQCAL_IDAC, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 2]); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_VCM, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 3]); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TX_SSI_MUX, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 5]); + + if (pi->pubpi.radiorev != 5) + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TSSIA, + pi->tx_rx_cal_radio_saveregs + [(core * 11) + 6]); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSIG, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 7]); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, TSSI_MISC1, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 8]); + } + } else if (NREV_GE(pi->pubpi.phy_rev, 3)) { + for (core = 0; core <= 1; core++) { + jtag_core = (core == PHY_CORE_0) ? + RADIO_2056_TX0 : RADIO_2056_TX1; + + write_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MASTER | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 0]); + + write_radio_reg(pi, + RADIO_2056_TX_IQCAL_VCM_HG | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 1]); + + write_radio_reg(pi, + RADIO_2056_TX_IQCAL_IDAC | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 2]); + + write_radio_reg(pi, RADIO_2056_TX_TSSI_VCM | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 3]); + + write_radio_reg(pi, + RADIO_2056_TX_TX_AMP_DET | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 4]); + + write_radio_reg(pi, + RADIO_2056_TX_TX_SSI_MUX | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 5]); + + write_radio_reg(pi, RADIO_2056_TX_TSSIA | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 6]); + + write_radio_reg(pi, RADIO_2056_TX_TSSIG | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 7]); + + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC1 | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 8]); + + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC2 | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 9]); + + write_radio_reg(pi, + RADIO_2056_TX_TSSI_MISC3 | jtag_core, + pi-> + tx_rx_cal_radio_saveregs[(core * 11) + + 10]); + } + } else { + + write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL1, + pi->tx_rx_cal_radio_saveregs[0]); + write_radio_reg(pi, RADIO_2055_CORE1_TXRF_IQCAL2, + pi->tx_rx_cal_radio_saveregs[1]); + write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL1, + pi->tx_rx_cal_radio_saveregs[2]); + write_radio_reg(pi, RADIO_2055_CORE2_TXRF_IQCAL2, + pi->tx_rx_cal_radio_saveregs[3]); + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE1, + pi->tx_rx_cal_radio_saveregs[4]); + write_radio_reg(pi, RADIO_2055_PWRDET_RXTX_CORE2, + pi->tx_rx_cal_radio_saveregs[5]); + } +} + +static void wlc_phy_txcal_physetup_nphy(struct brcms_phy *pi) +{ + u16 val, mask; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa6); + pi->tx_rx_cal_phy_saveregs[1] = read_phy_reg(pi, 0xa7); + + mask = ((0x3 << 8) | (0x3 << 10)); + val = (0x2 << 8); + val |= (0x2 << 10); + mod_phy_reg(pi, 0xa6, mask, val); + mod_phy_reg(pi, 0xa7, mask, val); + + val = read_phy_reg(pi, 0x8f); + pi->tx_rx_cal_phy_saveregs[2] = val; + val |= ((0x1 << 9) | (0x1 << 10)); + write_phy_reg(pi, 0x8f, val); + + val = read_phy_reg(pi, 0xa5); + pi->tx_rx_cal_phy_saveregs[3] = val; + val |= ((0x1 << 9) | (0x1 << 10)); + write_phy_reg(pi, 0xa5, val); + + pi->tx_rx_cal_phy_saveregs[4] = read_phy_reg(pi, 0x01); + mod_phy_reg(pi, 0x01, (0x1 << 15), 0); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16, + &val); + pi->tx_rx_cal_phy_saveregs[5] = val; + val = 0; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16, + &val); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16, + &val); + pi->tx_rx_cal_phy_saveregs[6] = val; + val = 0; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16, + &val); + + pi->tx_rx_cal_phy_saveregs[7] = read_phy_reg(pi, 0x91); + pi->tx_rx_cal_phy_saveregs[8] = read_phy_reg(pi, 0x92); + + if (!(pi->use_int_tx_iqlo_cal_nphy)) + wlc_phy_rfctrlintc_override_nphy( + pi, + NPHY_RfctrlIntc_override_PA, + 1, + RADIO_MIMO_CORESEL_CORE1 + | + RADIO_MIMO_CORESEL_CORE2); + else + wlc_phy_rfctrlintc_override_nphy( + pi, + NPHY_RfctrlIntc_override_PA, + 0, + RADIO_MIMO_CORESEL_CORE1 + | + RADIO_MIMO_CORESEL_CORE2); + + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + 0x2, RADIO_MIMO_CORESEL_CORE1); + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + 0x8, RADIO_MIMO_CORESEL_CORE2); + + pi->tx_rx_cal_phy_saveregs[9] = read_phy_reg(pi, 0x297); + pi->tx_rx_cal_phy_saveregs[10] = read_phy_reg(pi, 0x29b); + mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (0) << 0); + + mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (0) << 0); + + if (NREV_IS(pi->pubpi.phy_rev, 7) + || NREV_GE(pi->pubpi.phy_rev, 8)) + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 7), + wlc_phy_read_lpf_bw_ctl_nphy + (pi, + 0), 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + + if (pi->use_int_tx_iqlo_cal_nphy + && !(pi->internal_tx_iqlo_cal_tapoff_intpa_nphy)) { + + if (NREV_IS(pi->pubpi.phy_rev, 7)) { + + mod_radio_reg(pi, RADIO_2057_OVR_REG0, 1 << 4, + 1 << 4); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + mod_radio_reg( + pi, + RADIO_2057_PAD2G_TUNE_PUS_CORE0, + 1, 0); + mod_radio_reg( + pi, + RADIO_2057_PAD2G_TUNE_PUS_CORE1, + 1, 0); + } else { + mod_radio_reg( + pi, + RADIO_2057_IPA5G_CASCOFFV_PU_CORE0, + 1, 0); + mod_radio_reg( + pi, + RADIO_2057_IPA5G_CASCOFFV_PU_CORE1, + 1, 0); + } + } else if (NREV_GE(pi->pubpi.phy_rev, 8)) { + wlc_phy_rfctrl_override_nphy_rev7( + pi, + (0x1 << 3), 0, + 0x3, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + } + } + } else { + pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa6); + pi->tx_rx_cal_phy_saveregs[1] = read_phy_reg(pi, 0xa7); + + mask = ((0x3 << 12) | (0x3 << 14)); + val = (0x2 << 12); + val |= (0x2 << 14); + mod_phy_reg(pi, 0xa6, mask, val); + mod_phy_reg(pi, 0xa7, mask, val); + + val = read_phy_reg(pi, 0xa5); + pi->tx_rx_cal_phy_saveregs[2] = val; + val |= ((0x1 << 12) | (0x1 << 13)); + write_phy_reg(pi, 0xa5, val); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16, + &val); + pi->tx_rx_cal_phy_saveregs[3] = val; + val |= 0x2000; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16, + &val); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16, + &val); + pi->tx_rx_cal_phy_saveregs[4] = val; + val |= 0x2000; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16, + &val); + + pi->tx_rx_cal_phy_saveregs[5] = read_phy_reg(pi, 0x91); + pi->tx_rx_cal_phy_saveregs[6] = read_phy_reg(pi, 0x92); + val = CHSPEC_IS5G(pi->radio_chanspec) ? 0x180 : 0x120; + write_phy_reg(pi, 0x91, val); + write_phy_reg(pi, 0x92, val); + } +} + +static void wlc_phy_txcal_phycleanup_nphy(struct brcms_phy *pi) +{ + u16 mask; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + write_phy_reg(pi, 0xa6, pi->tx_rx_cal_phy_saveregs[0]); + write_phy_reg(pi, 0xa7, pi->tx_rx_cal_phy_saveregs[1]); + write_phy_reg(pi, 0x8f, pi->tx_rx_cal_phy_saveregs[2]); + write_phy_reg(pi, 0xa5, pi->tx_rx_cal_phy_saveregs[3]); + write_phy_reg(pi, 0x01, pi->tx_rx_cal_phy_saveregs[4]); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 3, 16, + &pi->tx_rx_cal_phy_saveregs[5]); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 19, 16, + &pi->tx_rx_cal_phy_saveregs[6]); + + write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[7]); + write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[8]); + + write_phy_reg(pi, 0x297, pi->tx_rx_cal_phy_saveregs[9]); + write_phy_reg(pi, 0x29b, pi->tx_rx_cal_phy_saveregs[10]); + + if (NREV_IS(pi->pubpi.phy_rev, 7) + || NREV_GE(pi->pubpi.phy_rev, 8)) + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 7), 0, 0, + 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + + wlc_phy_resetcca_nphy(pi); + + if (pi->use_int_tx_iqlo_cal_nphy + && !(pi->internal_tx_iqlo_cal_tapoff_intpa_nphy)) { + + if (NREV_IS(pi->pubpi.phy_rev, 7)) { + if (CHSPEC_IS2G(pi->radio_chanspec)) { + mod_radio_reg( + pi, + RADIO_2057_PAD2G_TUNE_PUS_CORE0, + 1, 1); + mod_radio_reg( + pi, + RADIO_2057_PAD2G_TUNE_PUS_CORE1, + 1, 1); + } else { + mod_radio_reg( + pi, + RADIO_2057_IPA5G_CASCOFFV_PU_CORE0, + 1, 1); + mod_radio_reg( + pi, + RADIO_2057_IPA5G_CASCOFFV_PU_CORE1, + 1, 1); + } + + mod_radio_reg(pi, RADIO_2057_OVR_REG0, 1 << 4, + 0); + } else if (NREV_GE(pi->pubpi.phy_rev, 8)) { + wlc_phy_rfctrl_override_nphy_rev7( + pi, + (0x1 << 3), 0, + 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + } + } + } else { + mask = ((0x3 << 12) | (0x3 << 14)); + mod_phy_reg(pi, 0xa6, mask, pi->tx_rx_cal_phy_saveregs[0]); + mod_phy_reg(pi, 0xa7, mask, pi->tx_rx_cal_phy_saveregs[1]); + write_phy_reg(pi, 0xa5, pi->tx_rx_cal_phy_saveregs[2]); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 2, 16, + &pi->tx_rx_cal_phy_saveregs[3]); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 18, 16, + &pi->tx_rx_cal_phy_saveregs[4]); + + write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[5]); + write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[6]); + } +} + +void +wlc_phy_est_tonepwr_nphy(struct brcms_phy *pi, s32 *qdBm_pwrbuf, u8 num_samps) +{ + u16 tssi_reg; + s32 temp, pwrindex[2]; + s32 idle_tssi[2]; + s32 rssi_buf[4]; + s32 tssival[2]; + u8 tssi_type; + + tssi_reg = read_phy_reg(pi, 0x1e9); + + temp = (s32) (tssi_reg & 0x3f); + idle_tssi[0] = (temp <= 31) ? temp : (temp - 64); + + temp = (s32) ((tssi_reg >> 8) & 0x3f); + idle_tssi[1] = (temp <= 31) ? temp : (temp - 64); + + tssi_type = + CHSPEC_IS5G(pi->radio_chanspec) ? + (u8)NPHY_RSSI_SEL_TSSI_5G : (u8)NPHY_RSSI_SEL_TSSI_2G; + + wlc_phy_poll_rssi_nphy(pi, tssi_type, rssi_buf, num_samps); + + tssival[0] = rssi_buf[0] / ((s32) num_samps); + tssival[1] = rssi_buf[2] / ((s32) num_samps); + + pwrindex[0] = idle_tssi[0] - tssival[0] + 64; + pwrindex[1] = idle_tssi[1] - tssival[1] + 64; + + if (pwrindex[0] < 0) + pwrindex[0] = 0; + else if (pwrindex[0] > 63) + pwrindex[0] = 63; + + if (pwrindex[1] < 0) + pwrindex[1] = 0; + else if (pwrindex[1] > 63) + pwrindex[1] = 63; + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 1, + (u32) pwrindex[0], 32, &qdBm_pwrbuf[0]); + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 1, + (u32) pwrindex[1], 32, &qdBm_pwrbuf[1]); +} + +static void wlc_phy_update_txcal_ladder_nphy(struct brcms_phy *pi, u16 core) +{ + int index; + u32 bbmult_scale; + u16 bbmult; + u16 tblentry; + + struct nphy_txiqcal_ladder ladder_lo[] = { + {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0}, + {25, 0}, {25, 1}, {25, 2}, {25, 3}, {25, 4}, {25, 5}, + {25, 6}, {25, 7}, {35, 7}, {50, 7}, {71, 7}, {100, 7} + }; + + struct nphy_txiqcal_ladder ladder_iq[] = { + {3, 0}, {4, 0}, {6, 0}, {9, 0}, {13, 0}, {18, 0}, + {25, 0}, {35, 0}, {50, 0}, {71, 0}, {100, 0}, {100, 1}, + {100, 2}, {100, 3}, {100, 4}, {100, 5}, {100, 6}, {100, 7} + }; + + bbmult = (core == PHY_CORE_0) ? + ((pi->nphy_txcal_bbmult >> 8) & 0xff) : + (pi->nphy_txcal_bbmult & 0xff); + + for (index = 0; index < 18; index++) { + bbmult_scale = ladder_lo[index].percent * bbmult; + bbmult_scale /= 100; + + tblentry = + ((bbmult_scale & 0xff) << 8) | ladder_lo[index].g_env; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index, 16, + &tblentry); + + bbmult_scale = ladder_iq[index].percent * bbmult; + bbmult_scale /= 100; + + tblentry = + ((bbmult_scale & 0xff) << 8) | ladder_iq[index].g_env; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 1, index + 32, + 16, &tblentry); + } +} + +static u8 wlc_phy_txpwr_idx_cur_get_nphy(struct brcms_phy *pi, u8 core) +{ + u16 tmp; + tmp = read_phy_reg(pi, ((core == PHY_CORE_0) ? 0x1ed : 0x1ee)); + + tmp = (tmp & (0x7f << 8)) >> 8; + return (u8) tmp; +} + +static void +wlc_phy_txpwr_idx_cur_set_nphy(struct brcms_phy *pi, u8 idx0, u8 idx1) +{ + mod_phy_reg(pi, 0x1e7, (0x7f << 0), idx0); + + if (NREV_GT(pi->pubpi.phy_rev, 1)) + mod_phy_reg(pi, 0x222, (0xff << 0), idx1); +} + +static u16 wlc_phy_ipa_get_bbmult_nphy(struct brcms_phy *pi) +{ + u16 m0m1; + + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m0m1); + + return m0m1; +} + +static void wlc_phy_ipa_set_bbmult_nphy(struct brcms_phy *pi, u8 m0, u8 m1) +{ + u16 m0m1 = (u16) ((m0 << 8) | m1); + + wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m0m1); + wlc_phy_table_write_nphy(pi, 15, 1, 95, 16, &m0m1); +} + +static void +wlc_phy_papd_cal_setup_nphy(struct brcms_phy *pi, + struct nphy_papd_restore_state *state, u8 core) +{ + s32 tone_freq; + u8 off_core; + u16 mixgain = 0; + + off_core = core ^ 0x1; + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + if (NREV_IS(pi->pubpi.phy_rev, 7) + || NREV_GE(pi->pubpi.phy_rev, 8)) + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 7), + wlc_phy_read_lpf_bw_ctl_nphy + (pi, + 0), 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (pi->pubpi.radiorev == 5) + mixgain = (core == 0) ? 0x20 : 0x00; + else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) + mixgain = 0x00; + else if ((pi->pubpi.radiorev <= 4) + || (pi->pubpi.radiorev == 6)) + mixgain = 0x00; + } else { + if ((pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) + mixgain = 0x50; + else if ((pi->pubpi.radiorev == 3) + || (pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) + mixgain = 0x0; + } + + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), + mixgain, (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_tx_pu, + 1, (1 << core), 0); + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_tx_pu, + 0, (1 << off_core), 0); + + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), + 0, 0x3, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1, + (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, + (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, + (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0, + (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1, + (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0, + (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1, + (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), + 0, (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0, + (1 << core), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + + state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ? + 0xa6 : 0xa7); + state->afeoverride[core] = + read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5); + state->afectrl[off_core] = + read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa7 : 0xa6); + state->afeoverride[off_core] = + read_phy_reg(pi, (core == PHY_CORE_0) ? 0xa5 : 0x8f); + + mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7), + (0x1 << 2), 0); + mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f : + 0xa5), (0x1 << 2), (0x1 << 2)); + + mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa7 : 0xa6), + (0x1 << 2), (0x1 << 2)); + mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa5 : + 0x8f), (0x1 << 2), (0x1 << 2)); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + state->pwrup[core] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_2G_PWRUP); + state->atten[core] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_2G_ATTEN); + state->pwrup[off_core] = + READ_RADIO_REG3(pi, RADIO_2057, TX, off_core, + TXRXCOUPLE_2G_PWRUP); + state->atten[off_core] = + READ_RADIO_REG3(pi, RADIO_2057, TX, off_core, + TXRXCOUPLE_2G_ATTEN); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_2G_PWRUP, 0xc); + + if ((pi->pubpi.radiorev == 3) || + (pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_2G_ATTEN, 0xf0); + else if (pi->pubpi.radiorev == 5) + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_2G_ATTEN, + (core == 0) ? 0xf7 : 0xf2); + else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_2G_ATTEN, 0xf0); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core, + TXRXCOUPLE_2G_PWRUP, 0x0); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core, + TXRXCOUPLE_2G_ATTEN, 0xff); + } else { + state->pwrup[core] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_5G_PWRUP); + state->atten[core] = + READ_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_5G_ATTEN); + state->pwrup[off_core] = + READ_RADIO_REG3(pi, RADIO_2057, TX, off_core, + TXRXCOUPLE_5G_PWRUP); + state->atten[off_core] = + READ_RADIO_REG3(pi, RADIO_2057, TX, off_core, + TXRXCOUPLE_5G_ATTEN); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_5G_PWRUP, 0xc); + + if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_5G_ATTEN, 0xf4); + + else + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_5G_ATTEN, 0xf0); + + WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core, + TXRXCOUPLE_5G_PWRUP, 0x0); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, off_core, + TXRXCOUPLE_5G_ATTEN, 0xff); + } + + tone_freq = 4000; + + wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 13), (1) << 13); + + mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_OFF) << 0); + + mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 13), (0) << 13); + + } else { + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 0); + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0, 0); + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 0); + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 1, 0x3, 0); + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 1, 0x3, 0); + + state->afectrl[core] = read_phy_reg(pi, (core == PHY_CORE_0) ? + 0xa6 : 0xa7); + state->afeoverride[core] = + read_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : 0xa5); + + mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0xa6 : 0xa7), + (0x1 << 0) | (0x1 << 1) | (0x1 << 2), 0); + mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f : + 0xa5), + (0x1 << 0) | + (0x1 << 1) | + (0x1 << 2), (0x1 << 0) | (0x1 << 1) | (0x1 << 2)); + + state->vga_master[core] = + READ_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER); + WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER, 0x2b); + if (CHSPEC_IS2G(pi->radio_chanspec)) { + state->fbmix[core] = + READ_RADIO_REG2(pi, RADIO_2056, RX, core, + TXFBMIX_G); + state->intpa_master[core] = + READ_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_MASTER); + + WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_G, + 0x03); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_MASTER, 0x04); + } else { + state->fbmix[core] = + READ_RADIO_REG2(pi, RADIO_2056, RX, core, + TXFBMIX_A); + state->intpa_master[core] = + READ_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAA_MASTER); + + WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, TXFBMIX_A, + 0x03); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAA_MASTER, 0x04); + + } + + tone_freq = 4000; + + wlc_phy_tx_tone_nphy(pi, tone_freq, 181, 0, 0, false); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (1) << 0); + + mod_phy_reg(pi, (off_core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (0) << 0); + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0); + } +} + +static void +wlc_phy_papd_cal_cleanup_nphy(struct brcms_phy *pi, + struct nphy_papd_restore_state *state) +{ + u8 core; + + wlc_phy_stopplayback_nphy(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_2G_PWRUP, 0); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_2G_ATTEN, + state->atten[core]); + } else { + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_5G_PWRUP, 0); + WRITE_RADIO_REG3(pi, RADIO_2057, TX, core, + TXRXCOUPLE_5G_ATTEN, + state->atten[core]); + } + } + + if ((pi->pubpi.radiorev == 4) || (pi->pubpi.radiorev == 6)) + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 2), + 1, 0x3, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + else + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 2), + 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), + 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 1, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 12), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 2), 1, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 8), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 1, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), 1, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 4), 0, 0x3, 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + + write_phy_reg(pi, (core == PHY_CORE_0) ? + 0xa6 : 0xa7, state->afectrl[core]); + write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : + 0xa5, state->afeoverride[core]); + } + + wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff, + (state->mm & 0xff)); + + if (NREV_IS(pi->pubpi.phy_rev, 7) + || NREV_GE(pi->pubpi.phy_rev, 8)) + wlc_phy_rfctrl_override_nphy_rev7( + pi, (0x1 << 7), 0, 0, + 1, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + } else { + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1); + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 13), 0, 0x3, 1); + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 0), 0, 0x3, 1); + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 2), 0, 0x3, 1); + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 1), 0, 0x3, 1); + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + + WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, VGA_MASTER, + state->vga_master[core]); + if (CHSPEC_IS2G(pi->radio_chanspec)) { + WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, + TXFBMIX_G, state->fbmix[core]); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAG_MASTER, + state->intpa_master[core]); + } else { + WRITE_RADIO_REG2(pi, RADIO_2056, RX, core, + TXFBMIX_A, state->fbmix[core]); + WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, + INTPAA_MASTER, + state->intpa_master[core]); + } + + write_phy_reg(pi, (core == PHY_CORE_0) ? + 0xa6 : 0xa7, state->afectrl[core]); + write_phy_reg(pi, (core == PHY_CORE_0) ? 0x8f : + 0xa5, state->afeoverride[core]); + } + + wlc_phy_ipa_set_bbmult_nphy(pi, (state->mm >> 8) & 0xff, + (state->mm & 0xff)); + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 1); + } +} + +static void +wlc_phy_a1_nphy(struct brcms_phy *pi, u8 core, u32 winsz, u32 start, + u32 end) +{ + u32 *buf, *src, *dst, sz; + + sz = end - start + 1; + + buf = kmalloc(2 * sizeof(u32) * NPHY_PAPD_EPS_TBL_SIZE, GFP_ATOMIC); + if (NULL == buf) + return; + + src = buf; + dst = buf + NPHY_PAPD_EPS_TBL_SIZE; + + wlc_phy_table_read_nphy(pi, + (core == + PHY_CORE_0 ? NPHY_TBL_ID_EPSILONTBL0 : + NPHY_TBL_ID_EPSILONTBL1), + NPHY_PAPD_EPS_TBL_SIZE, 0, 32, src); + + do { + u32 phy_a1, phy_a2; + s32 phy_a3, phy_a4, phy_a5, phy_a6, phy_a7; + + phy_a1 = end - min(end, (winsz >> 1)); + phy_a2 = min_t(u32, NPHY_PAPD_EPS_TBL_SIZE - 1, + end + (winsz >> 1)); + phy_a3 = phy_a2 - phy_a1 + 1; + phy_a6 = 0; + phy_a7 = 0; + + do { + wlc_phy_papd_decode_epsilon(src[phy_a2], &phy_a4, + &phy_a5); + phy_a6 += phy_a4; + phy_a7 += phy_a5; + } while (phy_a2-- != phy_a1); + + phy_a6 /= phy_a3; + phy_a7 /= phy_a3; + dst[end] = ((u32) phy_a7 << 13) | ((u32) phy_a6 & 0x1fff); + } while (end-- != start); + + wlc_phy_table_write_nphy(pi, + (core == + PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 : + NPHY_TBL_ID_EPSILONTBL1, sz, start, 32, dst); + + kfree(buf); +} + +static void +wlc_phy_a2_nphy(struct brcms_phy *pi, struct nphy_ipa_txcalgains *txgains, + enum phy_cal_mode cal_mode, u8 core) +{ + u16 phy_a1, phy_a2, phy_a3; + u16 phy_a4, phy_a5; + bool phy_a6; + u8 phy_a7, m[2]; + u32 phy_a8 = 0; + struct nphy_txgains phy_a9; + + if (NREV_LT(pi->pubpi.phy_rev, 3)) + return; + + phy_a7 = (core == PHY_CORE_0) ? 1 : 0; + + phy_a6 = ((cal_mode == CAL_GCTRL) + || (cal_mode == CAL_SOFT)) ? true : false; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + phy_a9 = wlc_phy_get_tx_gain_nphy(pi); + + if (CHSPEC_IS2G(pi->radio_chanspec)) + phy_a5 = ((phy_a9.txlpf[core] << 15) | + (phy_a9.txgm[core] << 12) | + (phy_a9.pga[core] << 8) | + (txgains->gains.pad[core] << 3) | + (phy_a9.ipa[core])); + else + phy_a5 = ((phy_a9.txlpf[core] << 15) | + (phy_a9.txgm[core] << 12) | + (txgains->gains.pga[core] << 8) | + (phy_a9.pad[core] << 3) | (phy_a9.ipa[core])); + + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_txgain, + phy_a5, (1 << core), 0); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if ((pi->pubpi.radiorev <= 4) + || (pi->pubpi.radiorev == 6)) + m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? + 60 : 79; + else + m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? + 45 : 64; + } else { + m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 75 : 107; + } + + m[phy_a7] = 0; + wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]); + + phy_a2 = 63; + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if ((pi->pubpi.radiorev == 4) + || (pi->pubpi.radiorev == 6)) { + phy_a1 = 30; + phy_a3 = 30; + } else { + phy_a1 = 25; + phy_a3 = 25; + } + } else { + if ((pi->pubpi.radiorev == 5) + || (pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) { + phy_a1 = 25; + phy_a3 = 25; + } else { + phy_a1 = 35; + phy_a3 = 35; + } + } + + if (cal_mode == CAL_GCTRL) { + if ((pi->pubpi.radiorev == 5) + && (CHSPEC_IS2G(pi->radio_chanspec))) + phy_a1 = 55; + else if (((pi->pubpi.radiorev == 7) && + (CHSPEC_IS2G(pi->radio_chanspec))) || + ((pi->pubpi.radiorev == 8) && + (CHSPEC_IS2G(pi->radio_chanspec)))) + phy_a1 = 60; + else + phy_a1 = 63; + + } else if ((cal_mode != CAL_FULL) && (cal_mode != CAL_SOFT)) { + + phy_a1 = 35; + phy_a3 = 35; + } + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (1) << 0); + + mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (0) << 0); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 13), (1) << 13); + + mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 13), (0) << 13); + + write_phy_reg(pi, 0x2a1, 0x80); + write_phy_reg(pi, 0x2a2, 0x100); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x7 << 4), (11) << 4); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x7 << 8), (11) << 8); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x7 << 0), (0x3) << 0); + + write_phy_reg(pi, 0x2e5, 0x20); + + mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0); + + mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0); + + mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8); + + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), + 1, ((core == 0) ? 1 : 2), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), + 0, ((core == 0) ? 2 : 1), 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + + write_phy_reg(pi, 0x2be, 1); + SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000); + + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), + 0, 0x3, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + + wlc_phy_table_write_nphy(pi, + (core == + PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 + : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3, + 32, &phy_a8); + + if (cal_mode != CAL_GCTRL) { + if (CHSPEC_IS5G(pi->radio_chanspec)) + wlc_phy_a1_nphy(pi, core, 5, 0, 35); + } + + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_txgain, + phy_a5, (1 << core), 1); + + } else { + + if (txgains) { + if (txgains->useindex) { + phy_a4 = 15 - ((txgains->index) >> 3); + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (NREV_GE(pi->pubpi.phy_rev, 6)) + phy_a5 = 0x00f7 | (phy_a4 << 8); + + else + if (NREV_IS(pi->pubpi.phy_rev, 5)) + phy_a5 = 0x10f7 | (phy_a4 << 8); + else + phy_a5 = 0x50f7 | (phy_a4 << 8); + } else { + phy_a5 = 0x70f7 | (phy_a4 << 8); + } + wlc_phy_rfctrl_override_nphy(pi, + (0x1 << 13), + phy_a5, + (1 << core), 0); + } else { + wlc_phy_rfctrl_override_nphy(pi, + (0x1 << 13), + 0x5bf7, + (1 << core), 0); + } + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) + m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 45 : 64; + else + m[core] = (pi->bw == WL_CHANSPEC_BW_40) ? 75 : 107; + + m[phy_a7] = 0; + wlc_phy_ipa_set_bbmult_nphy(pi, m[0], m[1]); + + phy_a2 = 63; + + if (cal_mode == CAL_FULL) { + phy_a1 = 25; + phy_a3 = 25; + } else if (cal_mode == CAL_SOFT) { + phy_a1 = 25; + phy_a3 = 25; + } else if (cal_mode == CAL_GCTRL) { + phy_a1 = 63; + phy_a3 = 25; + } else { + + phy_a1 = 25; + phy_a3 = 25; + } + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (1) << 0); + + mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (0) << 0); + + if (NREV_GE(pi->pubpi.phy_rev, 6)) { + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 13), (1) << 13); + + mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 13), (0) << 13); + + write_phy_reg(pi, 0x2a1, 0x20); + write_phy_reg(pi, 0x2a2, 0x60); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0xf << 4), (9) << 4); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0xf << 8), (9) << 8); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0xf << 0), (0x2) << 0); + + write_phy_reg(pi, 0x2e5, 0x20); + } else { + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 11), (1) << 11); + + mod_phy_reg(pi, (phy_a7 == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 11), (0) << 11); + + write_phy_reg(pi, 0x2a1, 0x80); + write_phy_reg(pi, 0x2a2, 0x600); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x7 << 4), (0) << 4); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x7 << 8), (0) << 8); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x7 << 0), (0x3) << 0); + + mod_phy_reg(pi, 0x2a0, (0x3f << 8), (0x20) << 8); + + } + + mod_phy_reg(pi, 0x2a0, (0x3f << 0), (phy_a3) << 0); + + mod_phy_reg(pi, 0x29f, (0x3f << 0), (phy_a1) << 0); + + mod_phy_reg(pi, 0x29f, (0x3f << 8), (phy_a2) << 8); + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 1, 0x3, 0); + + write_phy_reg(pi, 0x2be, 1); + SPINWAIT(read_phy_reg(pi, 0x2be), 10 * 1000 * 1000); + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 0x3, 0); + + wlc_phy_table_write_nphy(pi, + (core == + PHY_CORE_0) ? NPHY_TBL_ID_EPSILONTBL0 + : NPHY_TBL_ID_EPSILONTBL1, 1, phy_a3, + 32, &phy_a8); + + if (cal_mode != CAL_GCTRL) + wlc_phy_a1_nphy(pi, core, 5, 0, 40); + } +} + +static u8 wlc_phy_a3_nphy(struct brcms_phy *pi, u8 start_gain, u8 core) +{ + int phy_a1; + int phy_a2; + bool phy_a3; + struct nphy_ipa_txcalgains phy_a4; + bool phy_a5 = false; + bool phy_a6 = true; + s32 phy_a7, phy_a8; + u32 phy_a9; + int phy_a10; + bool phy_a11 = false; + int phy_a12; + u8 phy_a13 = 0; + u8 phy_a14; + u8 *phy_a15 = NULL; + + phy_a4.useindex = true; + phy_a12 = start_gain; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + phy_a2 = 20; + phy_a1 = 1; + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (pi->pubpi.radiorev == 5) { + + phy_a15 = pad_gain_codes_used_2057rev5; + phy_a13 = + sizeof(pad_gain_codes_used_2057rev5) / + sizeof(pad_gain_codes_used_2057rev5 + [0]) - 1; + + } else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) { + + phy_a15 = pad_gain_codes_used_2057rev7; + phy_a13 = + sizeof(pad_gain_codes_used_2057rev7) / + sizeof(pad_gain_codes_used_2057rev7 + [0]) - 1; + + } else { + + phy_a15 = pad_all_gain_codes_2057; + phy_a13 = sizeof(pad_all_gain_codes_2057) / + sizeof(pad_all_gain_codes_2057[0]) - + 1; + } + + } else { + + phy_a15 = pga_all_gain_codes_2057; + phy_a13 = sizeof(pga_all_gain_codes_2057) / + sizeof(pga_all_gain_codes_2057[0]) - 1; + } + + phy_a14 = 0; + + for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) { + if (CHSPEC_IS2G(pi->radio_chanspec)) + phy_a4.gains.pad[core] = + (u16) phy_a15[phy_a12]; + else + phy_a4.gains.pga[core] = + (u16) phy_a15[phy_a12]; + + wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core); + + wlc_phy_table_read_nphy(pi, + (core == + PHY_CORE_0 ? + NPHY_TBL_ID_EPSILONTBL0 : + NPHY_TBL_ID_EPSILONTBL1), 1, + 63, 32, &phy_a9); + + wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8); + + phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) || + (phy_a8 == 4095) || (phy_a8 == -4096)); + + if (!phy_a6 && (phy_a3 != phy_a5)) { + if (!phy_a3) + phy_a12 -= (u8) phy_a1; + + phy_a11 = true; + break; + } + + if (phy_a3) + phy_a12 += (u8) phy_a1; + else + phy_a12 -= (u8) phy_a1; + + if ((phy_a12 < phy_a14) || (phy_a12 > phy_a13)) { + if (phy_a12 < phy_a14) + phy_a12 = phy_a14; + else + phy_a12 = phy_a13; + + phy_a11 = true; + break; + } + + phy_a6 = false; + phy_a5 = phy_a3; + } + + } else { + phy_a2 = 10; + phy_a1 = 8; + for (phy_a10 = 0; phy_a10 < phy_a2; phy_a10++) { + phy_a4.index = (u8) phy_a12; + wlc_phy_a2_nphy(pi, &phy_a4, CAL_GCTRL, core); + + wlc_phy_table_read_nphy(pi, + (core == + PHY_CORE_0 ? + NPHY_TBL_ID_EPSILONTBL0 : + NPHY_TBL_ID_EPSILONTBL1), 1, + 63, 32, &phy_a9); + + wlc_phy_papd_decode_epsilon(phy_a9, &phy_a7, &phy_a8); + + phy_a3 = ((phy_a7 == 4095) || (phy_a7 == -4096) || + (phy_a8 == 4095) || (phy_a8 == -4096)); + + if (!phy_a6 && (phy_a3 != phy_a5)) { + if (!phy_a3) + phy_a12 -= (u8) phy_a1; + + phy_a11 = true; + break; + } + + if (phy_a3) + phy_a12 += (u8) phy_a1; + else + phy_a12 -= (u8) phy_a1; + + if ((phy_a12 < 0) || (phy_a12 > 127)) { + if (phy_a12 < 0) + phy_a12 = 0; + else + phy_a12 = 127; + + phy_a11 = true; + break; + } + + phy_a6 = false; + phy_a5 = phy_a3; + } + + } + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + return (u8) phy_a15[phy_a12]; + else + return (u8) phy_a12; + +} + +static void wlc_phy_a4(struct brcms_phy *pi, bool full_cal) +{ + struct nphy_ipa_txcalgains phy_b1[2]; + struct nphy_papd_restore_state phy_b2; + bool phy_b3; + u8 phy_b4; + u8 phy_b5; + s16 phy_b6, phy_b7, phy_b8; + u16 phy_b9; + s16 phy_b10, phy_b11, phy_b12; + + phy_b11 = 0; + phy_b12 = 0; + phy_b7 = 0; + phy_b8 = 0; + phy_b6 = 0; + + if (pi->nphy_papd_skip == 1) + return; + + phy_b3 = (0 == (R_REG(&pi->regs->maccontrol) & MCTL_EN_MAC)); + if (!phy_b3) + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + pi->nphy_force_papd_cal = false; + + for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) + pi->nphy_papd_tx_gain_at_last_cal[phy_b5] = + wlc_phy_txpwr_idx_cur_get_nphy(pi, phy_b5); + + pi->nphy_papd_last_cal = pi->sh->now; + pi->nphy_papd_recal_counter++; + + phy_b4 = pi->nphy_txpwrctrl; + wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL0, 64, 0, 32, + nphy_papd_scaltbl); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_SCALARTBL1, 64, 0, 32, + nphy_papd_scaltbl); + + phy_b9 = read_phy_reg(pi, 0x01); + mod_phy_reg(pi, 0x01, (0x1 << 15), 0); + + for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) { + s32 i, val = 0; + for (i = 0; i < 64; i++) + wlc_phy_table_write_nphy(pi, + ((phy_b5 == + PHY_CORE_0) ? + NPHY_TBL_ID_EPSILONTBL0 : + NPHY_TBL_ID_EPSILONTBL1), 1, + i, 32, &val); + } + + wlc_phy_ipa_restore_tx_digi_filts_nphy(pi); + + phy_b2.mm = wlc_phy_ipa_get_bbmult_nphy(pi); + for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) { + wlc_phy_papd_cal_setup_nphy(pi, &phy_b2, phy_b5); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if ((pi->pubpi.radiorev == 3) + || (pi->pubpi.radiorev == 4) + || (pi->pubpi.radiorev == 6)) { + pi->nphy_papd_cal_gain_index[phy_b5] = + 23; + } else if (pi->pubpi.radiorev == 5) { + pi->nphy_papd_cal_gain_index[phy_b5] = + 0; + pi->nphy_papd_cal_gain_index[phy_b5] = + wlc_phy_a3_nphy( + pi, + pi-> + nphy_papd_cal_gain_index + [phy_b5], + phy_b5); + + } else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) { + + pi->nphy_papd_cal_gain_index[phy_b5] = + 0; + pi->nphy_papd_cal_gain_index[phy_b5] = + wlc_phy_a3_nphy( + pi, + pi-> + nphy_papd_cal_gain_index + [phy_b5], + phy_b5); + + } + + phy_b1[phy_b5].gains.pad[phy_b5] = + pi->nphy_papd_cal_gain_index[phy_b5]; + + } else { + pi->nphy_papd_cal_gain_index[phy_b5] = 0; + pi->nphy_papd_cal_gain_index[phy_b5] = + wlc_phy_a3_nphy( + pi, + pi-> + nphy_papd_cal_gain_index + [phy_b5], phy_b5); + phy_b1[phy_b5].gains.pga[phy_b5] = + pi->nphy_papd_cal_gain_index[phy_b5]; + } + } else { + phy_b1[phy_b5].useindex = true; + phy_b1[phy_b5].index = 16; + phy_b1[phy_b5].index = + wlc_phy_a3_nphy(pi, phy_b1[phy_b5].index, + phy_b5); + + pi->nphy_papd_cal_gain_index[phy_b5] = + 15 - ((phy_b1[phy_b5].index) >> 3); + } + + switch (pi->nphy_papd_cal_type) { + case 0: + wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_FULL, phy_b5); + break; + case 1: + wlc_phy_a2_nphy(pi, &phy_b1[phy_b5], CAL_SOFT, phy_b5); + break; + } + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2); + } + + if (NREV_LT(pi->pubpi.phy_rev, 7)) + wlc_phy_papd_cal_cleanup_nphy(pi, &phy_b2); + + for (phy_b5 = 0; phy_b5 < pi->pubpi.phy_corenum; phy_b5++) { + int eps_offset = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (CHSPEC_IS2G(pi->radio_chanspec)) { + if (pi->pubpi.radiorev == 3) + eps_offset = -2; + else if (pi->pubpi.radiorev == 5) + eps_offset = 3; + else + eps_offset = -1; + } else { + eps_offset = 2; + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + phy_b8 = phy_b1[phy_b5].gains.pad[phy_b5]; + phy_b10 = 0; + if ((pi->pubpi.radiorev == 3) || + (pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) { + phy_b12 = -( + nphy_papd_padgain_dlt_2g_2057rev3n4 + [phy_b8] + 1) / 2; + phy_b10 = -1; + } else if (pi->pubpi.radiorev == 5) { + phy_b12 = -( + nphy_papd_padgain_dlt_2g_2057rev5 + [phy_b8] + 1) / 2; + } else if ((pi->pubpi.radiorev == 7) || + (pi->pubpi.radiorev == 8)) { + phy_b12 = -( + nphy_papd_padgain_dlt_2g_2057rev7 + [phy_b8] + 1) / 2; + } + } else { + phy_b7 = phy_b1[phy_b5].gains.pga[phy_b5]; + if ((pi->pubpi.radiorev == 3) || + (pi->pubpi.radiorev == 4) || + (pi->pubpi.radiorev == 6)) + phy_b11 = + -(nphy_papd_pgagain_dlt_5g_2057 + [phy_b7] + + 1) / 2; + else if ((pi->pubpi.radiorev == 7) + || (pi->pubpi.radiorev == 8)) + phy_b11 = -( + nphy_papd_pgagain_dlt_5g_2057rev7 + [phy_b7] + 1) / 2; + + phy_b10 = -9; + } + + if (CHSPEC_IS2G(pi->radio_chanspec)) + phy_b6 = + -60 + 27 + eps_offset + phy_b12 + + phy_b10; + else + phy_b6 = + -60 + 27 + eps_offset + phy_b11 + + phy_b10; + + mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 : + 0x29c, (0x1ff << 7), (phy_b6) << 7); + + pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6; + } else { + if (NREV_LT(pi->pubpi.phy_rev, 5)) + eps_offset = 4; + else + eps_offset = 2; + + phy_b7 = 15 - ((phy_b1[phy_b5].index) >> 3); + + if (CHSPEC_IS2G(pi->radio_chanspec)) { + phy_b11 = + -(nphy_papd_pga_gain_delta_ipa_2g[ + phy_b7] + + 1) / 2; + phy_b10 = 0; + } else { + phy_b11 = + -(nphy_papd_pga_gain_delta_ipa_5g[ + phy_b7] + + 1) / 2; + phy_b10 = -9; + } + + phy_b6 = -60 + 27 + eps_offset + phy_b11 + phy_b10; + + mod_phy_reg(pi, (phy_b5 == PHY_CORE_0) ? 0x298 : + 0x29c, (0x1ff << 7), (phy_b6) << 7); + + pi->nphy_papd_epsilon_offset[phy_b5] = phy_b6; + } + } + + mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0); + + mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (NPHY_PAPD_COMP_ON) << 0); + + if (NREV_GE(pi->pubpi.phy_rev, 6)) { + mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 13), (0) << 13); + + mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 13), (0) << 13); + + } else { + mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 11), (0) << 11); + + mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x2a3 : + 0x2a4, (0x1 << 11), (0) << 11); + + } + pi->nphy_papdcomp = NPHY_PAPD_COMP_ON; + + write_phy_reg(pi, 0x01, phy_b9); + + wlc_phy_ipa_set_tx_digi_filts_nphy(pi); + + wlc_phy_txpwrctrl_enable_nphy(pi, phy_b4); + if (phy_b4 == PHY_TPC_HW_OFF) { + wlc_phy_txpwr_index_nphy(pi, (1 << 0), + (s8) (pi->nphy_txpwrindex[0]. + index_internal), false); + wlc_phy_txpwr_index_nphy(pi, (1 << 1), + (s8) (pi->nphy_txpwrindex[1]. + index_internal), false); + } + + wlc_phy_stay_in_carriersearch_nphy(pi, false); + + if (!phy_b3) + wlapi_enable_mac(pi->sh->physhim); +} + +void wlc_phy_cal_perical_nphy_run(struct brcms_phy *pi, u8 caltype) +{ + struct nphy_txgains target_gain; + u8 tx_pwr_ctrl_state; + bool fullcal = true; + bool restore_tx_gain = false; + bool mphase; + + if (PHY_MUTED(pi)) + return; + + if (caltype == PHY_PERICAL_AUTO) + fullcal = (pi->radio_chanspec != pi->nphy_txiqlocal_chanspec); + else if (caltype == PHY_PERICAL_PARTIAL) + fullcal = false; + + if (pi->cal_type_override != PHY_PERICAL_AUTO) + fullcal = + (pi->cal_type_override == + PHY_PERICAL_FULL) ? true : false; + + if ((pi->mphase_cal_phase_id > MPHASE_CAL_STATE_INIT)) { + if (pi->nphy_txiqlocal_chanspec != pi->radio_chanspec) + wlc_phy_cal_perical_mphase_restart(pi); + } + + if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_RXCAL)) + wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, 10000); + + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + wlc_phyreg_enter((struct brcms_phy_pub *) pi); + + if ((pi->mphase_cal_phase_id == MPHASE_CAL_STATE_IDLE) || + (pi->mphase_cal_phase_id == MPHASE_CAL_STATE_INIT)) { + pi->nphy_cal_orig_pwr_idx[0] = + (u8) ((read_phy_reg(pi, 0x1ed) >> 8) & 0x7f); + pi->nphy_cal_orig_pwr_idx[1] = + (u8) ((read_phy_reg(pi, 0x1ee) >> 8) & 0x7f); + + if (pi->nphy_txpwrctrl != PHY_TPC_HW_OFF) { + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, + 0x110, 16, + pi->nphy_cal_orig_tx_gain); + } else { + pi->nphy_cal_orig_tx_gain[0] = 0; + pi->nphy_cal_orig_tx_gain[1] = 0; + } + } + target_gain = wlc_phy_get_tx_gain_nphy(pi); + tx_pwr_ctrl_state = pi->nphy_txpwrctrl; + wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF); + + if (pi->antsel_type == ANTSEL_2x3) + wlc_phy_antsel_init((struct brcms_phy_pub *) pi, true); + + mphase = (pi->mphase_cal_phase_id != MPHASE_CAL_STATE_IDLE); + if (!mphase) { + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + wlc_phy_precal_txgain_nphy(pi); + pi->nphy_cal_target_gain = wlc_phy_get_tx_gain_nphy(pi); + restore_tx_gain = true; + + target_gain = pi->nphy_cal_target_gain; + } + if (0 == + wlc_phy_cal_txiqlo_nphy(pi, target_gain, fullcal, + mphase)) { + if (PHY_IPA(pi)) + wlc_phy_a4(pi, true); + + wlc_phyreg_exit((struct brcms_phy_pub *) pi); + wlapi_enable_mac(pi->sh->physhim); + wlapi_bmac_write_shm(pi->sh->physhim, M_CTS_DURATION, + 10000); + wlapi_suspend_mac_and_wait(pi->sh->physhim); + wlc_phyreg_enter((struct brcms_phy_pub *) pi); + + if (0 == wlc_phy_cal_rxiq_nphy(pi, target_gain, + (pi->first_cal_after_assoc || + (pi->cal_type_override == + PHY_PERICAL_FULL)) ? 2 : 0, false)) { + wlc_phy_savecal_nphy(pi); + + wlc_phy_txpwrctrl_coeff_setup_nphy(pi); + + pi->nphy_perical_last = pi->sh->now; + } + } + if (caltype != PHY_PERICAL_AUTO) + wlc_phy_rssi_cal_nphy(pi); + + if (pi->first_cal_after_assoc + || (pi->cal_type_override == PHY_PERICAL_FULL)) { + pi->first_cal_after_assoc = false; + wlc_phy_txpwrctrl_idle_tssi_nphy(pi); + wlc_phy_txpwrctrl_pwr_setup_nphy(pi); + } + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + wlc_phy_radio205x_vcocal_nphy(pi); + } else { + switch (pi->mphase_cal_phase_id) { + case MPHASE_CAL_STATE_INIT: + pi->nphy_perical_last = pi->sh->now; + pi->nphy_txiqlocal_chanspec = pi->radio_chanspec; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + wlc_phy_precal_txgain_nphy(pi); + + pi->nphy_cal_target_gain = wlc_phy_get_tx_gain_nphy(pi); + pi->mphase_cal_phase_id++; + break; + + case MPHASE_CAL_STATE_TXPHASE0: + case MPHASE_CAL_STATE_TXPHASE1: + case MPHASE_CAL_STATE_TXPHASE2: + case MPHASE_CAL_STATE_TXPHASE3: + case MPHASE_CAL_STATE_TXPHASE4: + case MPHASE_CAL_STATE_TXPHASE5: + if ((pi->radar_percal_mask & 0x10) != 0) + pi->nphy_rxcal_active = true; + + if (wlc_phy_cal_txiqlo_nphy + (pi, pi->nphy_cal_target_gain, fullcal, + true) != 0) { + + wlc_phy_cal_perical_mphase_reset(pi); + break; + } + + if (NREV_LE(pi->pubpi.phy_rev, 2) && + (pi->mphase_cal_phase_id == + MPHASE_CAL_STATE_TXPHASE4)) + pi->mphase_cal_phase_id += 2; + else + pi->mphase_cal_phase_id++; + break; + + case MPHASE_CAL_STATE_PAPDCAL: + if ((pi->radar_percal_mask & 0x2) != 0) + pi->nphy_rxcal_active = true; + + if (PHY_IPA(pi)) + wlc_phy_a4(pi, true); + + pi->mphase_cal_phase_id++; + break; + + case MPHASE_CAL_STATE_RXCAL: + if ((pi->radar_percal_mask & 0x1) != 0) + pi->nphy_rxcal_active = true; + if (wlc_phy_cal_rxiq_nphy(pi, target_gain, + (pi->first_cal_after_assoc || + (pi->cal_type_override == + PHY_PERICAL_FULL)) ? 2 : 0, + false) == 0) + wlc_phy_savecal_nphy(pi); + + pi->mphase_cal_phase_id++; + break; + + case MPHASE_CAL_STATE_RSSICAL: + if ((pi->radar_percal_mask & 0x4) != 0) + pi->nphy_rxcal_active = true; + wlc_phy_txpwrctrl_coeff_setup_nphy(pi); + wlc_phy_rssi_cal_nphy(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + wlc_phy_radio205x_vcocal_nphy(pi); + + restore_tx_gain = true; + + if (pi->first_cal_after_assoc) + pi->mphase_cal_phase_id++; + else + wlc_phy_cal_perical_mphase_reset(pi); + + break; + + case MPHASE_CAL_STATE_IDLETSSI: + if ((pi->radar_percal_mask & 0x8) != 0) + pi->nphy_rxcal_active = true; + + if (pi->first_cal_after_assoc) { + pi->first_cal_after_assoc = false; + wlc_phy_txpwrctrl_idle_tssi_nphy(pi); + wlc_phy_txpwrctrl_pwr_setup_nphy(pi); + } + + wlc_phy_cal_perical_mphase_reset(pi); + break; + + default: + wlc_phy_cal_perical_mphase_reset(pi); + break; + } + } + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if (restore_tx_gain) { + if (tx_pwr_ctrl_state != PHY_TPC_HW_OFF) { + + wlc_phy_txpwr_index_nphy(pi, 1, + pi-> + nphy_cal_orig_pwr_idx + [0], false); + wlc_phy_txpwr_index_nphy(pi, 2, + pi-> + nphy_cal_orig_pwr_idx + [1], false); + + pi->nphy_txpwrindex[0].index = -1; + pi->nphy_txpwrindex[1].index = -1; + } else { + wlc_phy_txpwr_index_nphy(pi, (1 << 0), + (s8) (pi-> + nphy_txpwrindex + [0]. + index_internal), + false); + wlc_phy_txpwr_index_nphy(pi, (1 << 1), + (s8) (pi-> + nphy_txpwrindex + [1]. + index_internal), + false); + } + } + } + + wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state); + wlc_phyreg_exit((struct brcms_phy_pub *) pi); + wlapi_enable_mac(pi->sh->physhim); +} + +int +wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, + bool fullcal, bool mphase) +{ + u16 val; + u16 tbl_buf[11]; + u8 cal_cnt; + u16 cal_cmd; + u8 num_cals, max_cal_cmds; + u16 core_no, cal_type; + u16 diq_start = 0; + u8 phy_bw; + u16 max_val; + u16 tone_freq; + u16 gain_save[2]; + u16 cal_gain[2]; + struct nphy_iqcal_params cal_params[2]; + u32 tbl_len; + void *tbl_ptr; + bool ladder_updated[2]; + u8 mphase_cal_lastphase = 0; + int bcmerror = 0; + bool phyhang_avoid_state = false; + + u16 tbl_tx_iqlo_cal_loft_ladder_20[] = { + 0x0300, 0x0500, 0x0700, 0x0900, 0x0d00, 0x1100, 0x1900, 0x1901, + 0x1902, + 0x1903, 0x1904, 0x1905, 0x1906, 0x1907, 0x2407, 0x3207, 0x4607, + 0x6407 + }; + + u16 tbl_tx_iqlo_cal_iqimb_ladder_20[] = { + 0x0200, 0x0300, 0x0600, 0x0900, 0x0d00, 0x1100, 0x1900, 0x2400, + 0x3200, + 0x4600, 0x6400, 0x6401, 0x6402, 0x6403, 0x6404, 0x6405, 0x6406, + 0x6407 + }; + + u16 tbl_tx_iqlo_cal_loft_ladder_40[] = { + 0x0200, 0x0300, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1201, + 0x1202, + 0x1203, 0x1204, 0x1205, 0x1206, 0x1207, 0x1907, 0x2307, 0x3207, + 0x4707 + }; + + u16 tbl_tx_iqlo_cal_iqimb_ladder_40[] = { + 0x0100, 0x0200, 0x0400, 0x0700, 0x0900, 0x0c00, 0x1200, 0x1900, + 0x2300, + 0x3200, 0x4700, 0x4701, 0x4702, 0x4703, 0x4704, 0x4705, 0x4706, + 0x4707 + }; + + u16 tbl_tx_iqlo_cal_startcoefs[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000 + }; + + u16 tbl_tx_iqlo_cal_cmds_fullcal[] = { + 0x8123, 0x8264, 0x8086, 0x8245, 0x8056, + 0x9123, 0x9264, 0x9086, 0x9245, 0x9056 + }; + + u16 tbl_tx_iqlo_cal_cmds_recal[] = { + 0x8101, 0x8253, 0x8053, 0x8234, 0x8034, + 0x9101, 0x9253, 0x9053, 0x9234, 0x9034 + }; + + u16 tbl_tx_iqlo_cal_startcoefs_nphyrev3[] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000 + }; + + u16 tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3[] = { + 0x8434, 0x8334, 0x8084, 0x8267, 0x8056, 0x8234, + 0x9434, 0x9334, 0x9084, 0x9267, 0x9056, 0x9234 + }; + + u16 tbl_tx_iqlo_cal_cmds_recal_nphyrev3[] = { + 0x8423, 0x8323, 0x8073, 0x8256, 0x8045, 0x8223, + 0x9423, 0x9323, 0x9073, 0x9256, 0x9045, 0x9223 + }; + + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + if (NREV_GE(pi->pubpi.phy_rev, 4)) { + phyhang_avoid_state = pi->phyhang_avoid; + pi->phyhang_avoid = false; + } + + if (CHSPEC_IS40(pi->radio_chanspec)) + phy_bw = 40; + else + phy_bw = 20; + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save); + + for (core_no = 0; core_no <= 1; core_no++) { + wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain, + &cal_params[core_no]); + cal_gain[core_no] = cal_params[core_no].cal_gain; + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain); + + wlc_phy_txcal_radio_setup_nphy(pi); + + wlc_phy_txcal_physetup_nphy(pi); + + ladder_updated[0] = ladder_updated[1] = false; + if (!(NREV_GE(pi->pubpi.phy_rev, 6) || + (NREV_IS(pi->pubpi.phy_rev, 5) && PHY_IPA(pi) + && (CHSPEC_IS2G(pi->radio_chanspec))))) { + + if (phy_bw == 40) { + tbl_ptr = tbl_tx_iqlo_cal_loft_ladder_40; + tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_loft_ladder_40); + } else { + tbl_ptr = tbl_tx_iqlo_cal_loft_ladder_20; + tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_loft_ladder_20); + } + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 0, + 16, tbl_ptr); + + if (phy_bw == 40) { + tbl_ptr = tbl_tx_iqlo_cal_iqimb_ladder_40; + tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_iqimb_ladder_40); + } else { + tbl_ptr = tbl_tx_iqlo_cal_iqimb_ladder_20; + tbl_len = ARRAY_SIZE(tbl_tx_iqlo_cal_iqimb_ladder_20); + } + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 32, + 16, tbl_ptr); + } + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + write_phy_reg(pi, 0xc2, 0x8ad9); + else + write_phy_reg(pi, 0xc2, 0x8aa9); + + max_val = 250; + tone_freq = (phy_bw == 20) ? 2500 : 5000; + + if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_TXPHASE0) { + wlc_phy_runsamples_nphy(pi, phy_bw * 8, 0xffff, 0, 1, 0, false); + bcmerror = 0; + } else { + bcmerror = + wlc_phy_tx_tone_nphy(pi, tone_freq, max_val, 1, 0, + false); + } + + if (bcmerror == 0) { + + if (pi->mphase_cal_phase_id > MPHASE_CAL_STATE_TXPHASE0) { + tbl_ptr = pi->mphase_txcal_bestcoeffs; + tbl_len = ARRAY_SIZE(pi->mphase_txcal_bestcoeffs); + if (NREV_LT(pi->pubpi.phy_rev, 3)) + tbl_len -= 2; + } else { + if ((!fullcal) && (pi->nphy_txiqlocal_coeffsvalid)) { + + tbl_ptr = pi->nphy_txiqlocal_bestc; + tbl_len = ARRAY_SIZE(pi->nphy_txiqlocal_bestc); + if (NREV_LT(pi->pubpi.phy_rev, 3)) + tbl_len -= 2; + } else { + + fullcal = true; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + tbl_ptr = + tbl_tx_iqlo_cal_startcoefs_nphyrev3; + tbl_len = ARRAY_SIZE( + tbl_tx_iqlo_cal_startcoefs_nphyrev3); + } else { + tbl_ptr = tbl_tx_iqlo_cal_startcoefs; + tbl_len = ARRAY_SIZE( + tbl_tx_iqlo_cal_startcoefs); + } + } + } + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, tbl_len, 64, + 16, tbl_ptr); + + if (fullcal) { + max_cal_cmds = (NREV_GE(pi->pubpi.phy_rev, 3)) ? + ARRAY_SIZE( + tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3) : + ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_fullcal); + } else { + max_cal_cmds = (NREV_GE(pi->pubpi.phy_rev, 3)) ? + ARRAY_SIZE( + tbl_tx_iqlo_cal_cmds_recal_nphyrev3) : + ARRAY_SIZE(tbl_tx_iqlo_cal_cmds_recal); + } + + if (mphase) { + cal_cnt = pi->mphase_txcal_cmdidx; + if ((cal_cnt + pi->mphase_txcal_numcmds) < max_cal_cmds) + num_cals = cal_cnt + pi->mphase_txcal_numcmds; + else + num_cals = max_cal_cmds; + } else { + cal_cnt = 0; + num_cals = max_cal_cmds; + } + + for (; cal_cnt < num_cals; cal_cnt++) { + + if (fullcal) { + cal_cmd = (NREV_GE(pi->pubpi.phy_rev, 3)) ? + tbl_tx_iqlo_cal_cmds_fullcal_nphyrev3 + [cal_cnt] : + tbl_tx_iqlo_cal_cmds_fullcal[cal_cnt]; + } else { + cal_cmd = (NREV_GE(pi->pubpi.phy_rev, 3)) ? + tbl_tx_iqlo_cal_cmds_recal_nphyrev3[ + cal_cnt] + : tbl_tx_iqlo_cal_cmds_recal[cal_cnt]; + } + + core_no = ((cal_cmd & 0x3000) >> 12); + cal_type = ((cal_cmd & 0x0F00) >> 8); + + if (NREV_GE(pi->pubpi.phy_rev, 6) || + (NREV_IS(pi->pubpi.phy_rev, 5) && + PHY_IPA(pi) + && (CHSPEC_IS2G(pi->radio_chanspec)))) { + if (!ladder_updated[core_no]) { + wlc_phy_update_txcal_ladder_nphy( + pi, + core_no); + ladder_updated[core_no] = true; + } + } + + val = + (cal_params[core_no]. + ncorr[cal_type] << 8) | NPHY_N_GCTL; + write_phy_reg(pi, 0xc1, val); + + if ((cal_type == 1) || (cal_type == 3) + || (cal_type == 4)) { + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, + 1, 69 + core_no, 16, + tbl_buf); + + diq_start = tbl_buf[0]; + + tbl_buf[0] = 0; + wlc_phy_table_write_nphy(pi, + NPHY_TBL_ID_IQLOCAL, 1, + 69 + core_no, 16, + tbl_buf); + } + + write_phy_reg(pi, 0xc0, cal_cmd); + + SPINWAIT(((read_phy_reg(pi, 0xc0) & 0xc000) != 0), + 20000); + if (WARN(read_phy_reg(pi, 0xc0) & 0xc000, + "HW error: txiq calib")) + return -EIO; + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, + tbl_len, 96, 16, tbl_buf); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, + tbl_len, 64, 16, tbl_buf); + + if ((cal_type == 1) || (cal_type == 3) + || (cal_type == 4)) { + + tbl_buf[0] = diq_start; + + } + + } + + if (mphase) { + pi->mphase_txcal_cmdidx = num_cals; + if (pi->mphase_txcal_cmdidx >= max_cal_cmds) + pi->mphase_txcal_cmdidx = 0; + } + + mphase_cal_lastphase = + (NREV_LE(pi->pubpi.phy_rev, 2)) ? + MPHASE_CAL_STATE_TXPHASE4 : MPHASE_CAL_STATE_TXPHASE5; + + if (!mphase + || (pi->mphase_cal_phase_id == mphase_cal_lastphase)) { + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 96, + 16, tbl_buf); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, + 16, tbl_buf); + + if (NREV_LT(pi->pubpi.phy_rev, 2)) { + + tbl_buf[0] = 0; + tbl_buf[1] = 0; + tbl_buf[2] = 0; + tbl_buf[3] = 0; + + } + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, + 16, tbl_buf); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 101, + 16, tbl_buf); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, + 16, tbl_buf); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, + 16, tbl_buf); + + tbl_len = ARRAY_SIZE(pi->nphy_txiqlocal_bestc); + if (NREV_LT(pi->pubpi.phy_rev, 3)) + tbl_len -= 2; + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, + tbl_len, 96, 16, + pi->nphy_txiqlocal_bestc); + + pi->nphy_txiqlocal_coeffsvalid = true; + pi->nphy_txiqlocal_chanspec = pi->radio_chanspec; + } else { + tbl_len = ARRAY_SIZE(pi->mphase_txcal_bestcoeffs); + if (NREV_LT(pi->pubpi.phy_rev, 3)) + tbl_len -= 2; + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, + tbl_len, 96, 16, + pi->mphase_txcal_bestcoeffs); + } + + wlc_phy_stopplayback_nphy(pi); + + write_phy_reg(pi, 0xc2, 0x0000); + + } + + wlc_phy_txcal_phycleanup_nphy(pi); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, + gain_save); + + wlc_phy_txcal_radio_cleanup_nphy(pi); + + if (NREV_LT(pi->pubpi.phy_rev, 2)) { + if (!mphase + || (pi->mphase_cal_phase_id == mphase_cal_lastphase)) + wlc_phy_tx_iq_war_nphy(pi); + } + + if (NREV_GE(pi->pubpi.phy_rev, 4)) + pi->phyhang_avoid = phyhang_avoid_state; + + wlc_phy_stay_in_carriersearch_nphy(pi, false); + + return bcmerror; +} + +static void wlc_phy_reapply_txcal_coeffs_nphy(struct brcms_phy *pi) +{ + u16 tbl_buf[7]; + + if ((pi->nphy_txiqlocal_chanspec == pi->radio_chanspec) && + (pi->nphy_txiqlocal_coeffsvalid)) { + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_IQLOCAL, + ARRAY_SIZE(tbl_buf), 80, 16, tbl_buf); + + if ((pi->nphy_txiqlocal_bestc[0] != tbl_buf[0]) || + (pi->nphy_txiqlocal_bestc[1] != tbl_buf[1]) || + (pi->nphy_txiqlocal_bestc[2] != tbl_buf[2]) || + (pi->nphy_txiqlocal_bestc[3] != tbl_buf[3])) { + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 80, + 16, pi->nphy_txiqlocal_bestc); + + tbl_buf[0] = 0; + tbl_buf[1] = 0; + tbl_buf[2] = 0; + tbl_buf[3] = 0; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 4, 88, + 16, tbl_buf); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 85, + 16, + &pi->nphy_txiqlocal_bestc[5]); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_IQLOCAL, 2, 93, + 16, + &pi->nphy_txiqlocal_bestc[5]); + } + } +} + +void +wlc_phy_rx_iq_coeffs_nphy(struct brcms_phy *pi, u8 write, + struct nphy_iq_comp *pcomp) +{ + if (write) { + write_phy_reg(pi, 0x9a, pcomp->a0); + write_phy_reg(pi, 0x9b, pcomp->b0); + write_phy_reg(pi, 0x9c, pcomp->a1); + write_phy_reg(pi, 0x9d, pcomp->b1); + } else { + pcomp->a0 = read_phy_reg(pi, 0x9a); + pcomp->b0 = read_phy_reg(pi, 0x9b); + pcomp->a1 = read_phy_reg(pi, 0x9c); + pcomp->b1 = read_phy_reg(pi, 0x9d); + } +} + +void +wlc_phy_rx_iq_est_nphy(struct brcms_phy *pi, struct phy_iq_est *est, + u16 num_samps, u8 wait_time, u8 wait_for_crs) +{ + u8 core; + + write_phy_reg(pi, 0x12b, num_samps); + mod_phy_reg(pi, 0x12a, (0xff << 0), (wait_time << 0)); + mod_phy_reg(pi, 0x129, NPHY_IqestCmd_iqMode, + (wait_for_crs) ? NPHY_IqestCmd_iqMode : 0); + + mod_phy_reg(pi, 0x129, NPHY_IqestCmd_iqstart, NPHY_IqestCmd_iqstart); + + SPINWAIT(((read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart) != 0), + 10000); + if (WARN(read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart, + "HW error: rxiq est")) + return; + + if ((read_phy_reg(pi, 0x129) & NPHY_IqestCmd_iqstart) == 0) { + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + est[core].i_pwr = + (read_phy_reg(pi, + NPHY_IqestipwrAccHi(core)) << 16) + | read_phy_reg(pi, NPHY_IqestipwrAccLo(core)); + est[core].q_pwr = + (read_phy_reg(pi, + NPHY_IqestqpwrAccHi(core)) << 16) + | read_phy_reg(pi, NPHY_IqestqpwrAccLo(core)); + est[core].iq_prod = + (read_phy_reg(pi, + NPHY_IqestIqAccHi(core)) << 16) | + read_phy_reg(pi, NPHY_IqestIqAccLo(core)); + } + } +} + +#define CAL_RETRY_CNT 2 +static void wlc_phy_calc_rx_iq_comp_nphy(struct brcms_phy *pi, u8 core_mask) +{ + u8 curr_core; + struct phy_iq_est est[PHY_CORE_MAX]; + struct nphy_iq_comp old_comp, new_comp; + s32 iq = 0; + u32 ii = 0, qq = 0; + s16 iq_nbits, qq_nbits, brsh, arsh; + s32 a, b, temp; + int bcmerror = 0; + uint cal_retry = 0; + + if (core_mask == 0x0) + return; + + wlc_phy_rx_iq_coeffs_nphy(pi, 0, &old_comp); + new_comp.a0 = new_comp.b0 = new_comp.a1 = new_comp.b1 = 0x0; + wlc_phy_rx_iq_coeffs_nphy(pi, 1, &new_comp); + +cal_try: + wlc_phy_rx_iq_est_nphy(pi, est, 0x4000, 32, 0); + + new_comp = old_comp; + + for (curr_core = 0; curr_core < pi->pubpi.phy_corenum; curr_core++) { + + if ((curr_core == PHY_CORE_0) && (core_mask & 0x1)) { + iq = est[curr_core].iq_prod; + ii = est[curr_core].i_pwr; + qq = est[curr_core].q_pwr; + } else if ((curr_core == PHY_CORE_1) && (core_mask & 0x2)) { + iq = est[curr_core].iq_prod; + ii = est[curr_core].i_pwr; + qq = est[curr_core].q_pwr; + } else { + continue; + } + + if ((ii + qq) < NPHY_MIN_RXIQ_PWR) { + bcmerror = -EBADE; + break; + } + + iq_nbits = wlc_phy_nbits(iq); + qq_nbits = wlc_phy_nbits(qq); + + arsh = 10 - (30 - iq_nbits); + if (arsh >= 0) { + a = (-(iq << (30 - iq_nbits)) + (ii >> (1 + arsh))); + temp = (s32) (ii >> arsh); + if (temp == 0) { + bcmerror = -EBADE; + break; + } + } else { + a = (-(iq << (30 - iq_nbits)) + (ii << (-1 - arsh))); + temp = (s32) (ii << -arsh); + if (temp == 0) { + bcmerror = -EBADE; + break; + } + } + + a /= temp; + + brsh = qq_nbits - 31 + 20; + if (brsh >= 0) { + b = (qq << (31 - qq_nbits)); + temp = (s32) (ii >> brsh); + if (temp == 0) { + bcmerror = -EBADE; + break; + } + } else { + b = (qq << (31 - qq_nbits)); + temp = (s32) (ii << -brsh); + if (temp == 0) { + bcmerror = -EBADE; + break; + } + } + b /= temp; + b -= a * a; + b = (s32) int_sqrt((unsigned long) b); + b -= (1 << 10); + + if ((curr_core == PHY_CORE_0) && (core_mask & 0x1)) { + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + new_comp.a0 = (s16) a & 0x3ff; + new_comp.b0 = (s16) b & 0x3ff; + } else { + + new_comp.a0 = (s16) b & 0x3ff; + new_comp.b0 = (s16) a & 0x3ff; + } + } + if ((curr_core == PHY_CORE_1) && (core_mask & 0x2)) { + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + new_comp.a1 = (s16) a & 0x3ff; + new_comp.b1 = (s16) b & 0x3ff; + } else { + + new_comp.a1 = (s16) b & 0x3ff; + new_comp.b1 = (s16) a & 0x3ff; + } + } + } + + if (bcmerror != 0) { + printk(KERN_DEBUG "%s: Failed, cnt = %d\n", __func__, + cal_retry); + + if (cal_retry < CAL_RETRY_CNT) { + cal_retry++; + goto cal_try; + } + + new_comp = old_comp; + } + + wlc_phy_rx_iq_coeffs_nphy(pi, 1, &new_comp); +} + +static void wlc_phy_rxcal_radio_setup_nphy(struct brcms_phy *pi, u8 rx_core) +{ + u16 offtune_val; + u16 bias_g = 0; + u16 bias_a = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (rx_core == PHY_CORE_0) { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + pi->tx_rx_cal_radio_saveregs[0] = + read_radio_reg(pi, + RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP); + pi->tx_rx_cal_radio_saveregs[1] = + read_radio_reg(pi, + RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN); + + write_radio_reg(pi, + RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP, + 0x3); + write_radio_reg(pi, + RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN, + 0xaf); + + } else { + pi->tx_rx_cal_radio_saveregs[0] = + read_radio_reg(pi, + RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP); + pi->tx_rx_cal_radio_saveregs[1] = + read_radio_reg(pi, + RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN); + + write_radio_reg( + pi, + RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP, + 0x3); + write_radio_reg( + pi, + RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN, + 0x7f); + } + + } else { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + pi->tx_rx_cal_radio_saveregs[0] = + read_radio_reg(pi, + RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP); + pi->tx_rx_cal_radio_saveregs[1] = + read_radio_reg(pi, + RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN); + + write_radio_reg( + pi, + RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP, + 0x3); + write_radio_reg( + pi, + RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN, + 0xaf); + + } else { + pi->tx_rx_cal_radio_saveregs[0] = + read_radio_reg(pi, + RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP); + pi->tx_rx_cal_radio_saveregs[1] = + read_radio_reg(pi, + RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN); + + write_radio_reg(pi, + RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP, + 0x3); + write_radio_reg(pi, + RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN, + 0x7f); + } + } + + } else { + if (rx_core == PHY_CORE_0) { + pi->tx_rx_cal_radio_saveregs[0] = + read_radio_reg(pi, + RADIO_2056_TX_RXIQCAL_TXMUX | + RADIO_2056_TX1); + pi->tx_rx_cal_radio_saveregs[1] = + read_radio_reg(pi, + RADIO_2056_RX_RXIQCAL_RXMUX | + RADIO_2056_RX0); + + if (pi->pubpi.radiorev >= 5) { + pi->tx_rx_cal_radio_saveregs[2] = + read_radio_reg(pi, + RADIO_2056_RX_RXSPARE2 | + RADIO_2056_RX0); + pi->tx_rx_cal_radio_saveregs[3] = + read_radio_reg(pi, + RADIO_2056_TX_TXSPARE2 | + RADIO_2056_TX1); + } + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + + if (pi->pubpi.radiorev >= 5) { + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg(pi, + RADIO_2056_RX_LNAA_MASTER + | RADIO_2056_RX0); + + write_radio_reg( + pi, + RADIO_2056_RX_LNAA_MASTER + | RADIO_2056_RX0, 0x40); + + write_radio_reg(pi, + RADIO_2056_TX_TXSPARE2 | + RADIO_2056_TX1, bias_a); + + write_radio_reg(pi, + RADIO_2056_RX_RXSPARE2 | + RADIO_2056_RX0, bias_a); + } else { + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg(pi, + RADIO_2056_RX_LNAA_TUNE + | RADIO_2056_RX0); + + offtune_val = + (pi->tx_rx_cal_radio_saveregs + [2] & 0xF0) >> 8; + offtune_val = + (offtune_val <= 0x7) ? 0xF : 0; + + mod_radio_reg(pi, + RADIO_2056_RX_LNAA_TUNE | + RADIO_2056_RX0, 0xF0, + (offtune_val << 8)); + } + + write_radio_reg(pi, + RADIO_2056_TX_RXIQCAL_TXMUX | + RADIO_2056_TX1, 0x9); + write_radio_reg(pi, + RADIO_2056_RX_RXIQCAL_RXMUX | + RADIO_2056_RX0, 0x9); + } else { + if (pi->pubpi.radiorev >= 5) { + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg( + pi, + RADIO_2056_RX_LNAG_MASTER + | RADIO_2056_RX0); + + write_radio_reg( + pi, + RADIO_2056_RX_LNAG_MASTER + | RADIO_2056_RX0, 0x40); + + write_radio_reg( + pi, + RADIO_2056_TX_TXSPARE2 + | + RADIO_2056_TX1, bias_g); + + write_radio_reg( + pi, + RADIO_2056_RX_RXSPARE2 + | + RADIO_2056_RX0, bias_g); + + } else { + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg( + pi, + RADIO_2056_RX_LNAG_TUNE + | RADIO_2056_RX0); + + offtune_val = + (pi-> + tx_rx_cal_radio_saveregs[2] & + 0xF0) >> 8; + offtune_val = + (offtune_val <= 0x7) ? 0xF : 0; + + mod_radio_reg(pi, + RADIO_2056_RX_LNAG_TUNE | + RADIO_2056_RX0, 0xF0, + (offtune_val << 8)); + } + + write_radio_reg(pi, + RADIO_2056_TX_RXIQCAL_TXMUX | + RADIO_2056_TX1, 0x6); + write_radio_reg(pi, + RADIO_2056_RX_RXIQCAL_RXMUX | + RADIO_2056_RX0, 0x6); + } + + } else { + pi->tx_rx_cal_radio_saveregs[0] = + read_radio_reg(pi, + RADIO_2056_TX_RXIQCAL_TXMUX | + RADIO_2056_TX0); + pi->tx_rx_cal_radio_saveregs[1] = + read_radio_reg(pi, + RADIO_2056_RX_RXIQCAL_RXMUX | + RADIO_2056_RX1); + + if (pi->pubpi.radiorev >= 5) { + pi->tx_rx_cal_radio_saveregs[2] = + read_radio_reg(pi, + RADIO_2056_RX_RXSPARE2 | + RADIO_2056_RX1); + pi->tx_rx_cal_radio_saveregs[3] = + read_radio_reg(pi, + RADIO_2056_TX_TXSPARE2 | + RADIO_2056_TX0); + } + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + + if (pi->pubpi.radiorev >= 5) { + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg( + pi, + RADIO_2056_RX_LNAA_MASTER + | RADIO_2056_RX1); + + write_radio_reg( + pi, + RADIO_2056_RX_LNAA_MASTER | + RADIO_2056_RX1, 0x40); + + write_radio_reg( + pi, + RADIO_2056_TX_TXSPARE2 + | + RADIO_2056_TX0, bias_a); + + write_radio_reg( + pi, + RADIO_2056_RX_RXSPARE2 + | + RADIO_2056_RX1, bias_a); + } else { + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg( + pi, + RADIO_2056_RX_LNAA_TUNE + | RADIO_2056_RX1); + + offtune_val = + (pi-> + tx_rx_cal_radio_saveregs[2] & + 0xF0) >> 8; + offtune_val = + (offtune_val <= 0x7) ? 0xF : 0; + + mod_radio_reg(pi, + RADIO_2056_RX_LNAA_TUNE | + RADIO_2056_RX1, 0xF0, + (offtune_val << 8)); + } + + write_radio_reg(pi, + RADIO_2056_TX_RXIQCAL_TXMUX | + RADIO_2056_TX0, 0x9); + write_radio_reg(pi, + RADIO_2056_RX_RXIQCAL_RXMUX | + RADIO_2056_RX1, 0x9); + } else { + if (pi->pubpi.radiorev >= 5) { + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg( + pi, + RADIO_2056_RX_LNAG_MASTER + | RADIO_2056_RX1); + + write_radio_reg( + pi, + RADIO_2056_RX_LNAG_MASTER + | RADIO_2056_RX1, 0x40); + + write_radio_reg( + pi, + RADIO_2056_TX_TXSPARE2 + | + RADIO_2056_TX0, bias_g); + + write_radio_reg( + pi, + RADIO_2056_RX_RXSPARE2 + | + RADIO_2056_RX1, bias_g); + } else { + pi->tx_rx_cal_radio_saveregs[4] = + read_radio_reg( + pi, + RADIO_2056_RX_LNAG_TUNE + | RADIO_2056_RX1); + + offtune_val = + (pi-> + tx_rx_cal_radio_saveregs[2] & + 0xF0) >> 8; + offtune_val = + (offtune_val <= 0x7) ? 0xF : 0; + + mod_radio_reg(pi, + RADIO_2056_RX_LNAG_TUNE | + RADIO_2056_RX1, 0xF0, + (offtune_val << 8)); + } + + write_radio_reg(pi, + RADIO_2056_TX_RXIQCAL_TXMUX | + RADIO_2056_TX0, 0x6); + write_radio_reg(pi, + RADIO_2056_RX_RXIQCAL_RXMUX | + RADIO_2056_RX1, 0x6); + } + } + } +} + +static void wlc_phy_rxcal_radio_cleanup_nphy(struct brcms_phy *pi, u8 rx_core) +{ + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + if (rx_core == PHY_CORE_0) { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + write_radio_reg( + pi, + RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP, + pi-> + tx_rx_cal_radio_saveregs[0]); + write_radio_reg( + pi, + RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN, + pi-> + tx_rx_cal_radio_saveregs[1]); + + } else { + write_radio_reg( + pi, + RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP, + pi-> + tx_rx_cal_radio_saveregs[0]); + write_radio_reg( + pi, + RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN, + pi-> + tx_rx_cal_radio_saveregs[1]); + } + + } else { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + write_radio_reg( + pi, + RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP, + pi-> + tx_rx_cal_radio_saveregs[0]); + write_radio_reg( + pi, + RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN, + pi-> + tx_rx_cal_radio_saveregs[1]); + + } else { + write_radio_reg( + pi, + RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP, + pi-> + tx_rx_cal_radio_saveregs[0]); + write_radio_reg( + pi, + RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN, + pi-> + tx_rx_cal_radio_saveregs[1]); + } + } + + } else { + if (rx_core == PHY_CORE_0) { + write_radio_reg(pi, + RADIO_2056_TX_RXIQCAL_TXMUX | + RADIO_2056_TX1, + pi->tx_rx_cal_radio_saveregs[0]); + + write_radio_reg(pi, + RADIO_2056_RX_RXIQCAL_RXMUX | + RADIO_2056_RX0, + pi->tx_rx_cal_radio_saveregs[1]); + + if (pi->pubpi.radiorev >= 5) { + write_radio_reg(pi, + RADIO_2056_RX_RXSPARE2 | + RADIO_2056_RX0, + pi-> + tx_rx_cal_radio_saveregs[2]); + + write_radio_reg(pi, + RADIO_2056_TX_TXSPARE2 | + RADIO_2056_TX1, + pi-> + tx_rx_cal_radio_saveregs[3]); + } + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (pi->pubpi.radiorev >= 5) + write_radio_reg( + pi, + RADIO_2056_RX_LNAA_MASTER + | RADIO_2056_RX0, + pi-> + tx_rx_cal_radio_saveregs + [4]); + else + write_radio_reg( + pi, + RADIO_2056_RX_LNAA_TUNE + | RADIO_2056_RX0, + pi-> + tx_rx_cal_radio_saveregs + [4]); + } else { + if (pi->pubpi.radiorev >= 5) + write_radio_reg( + pi, + RADIO_2056_RX_LNAG_MASTER + | RADIO_2056_RX0, + pi-> + tx_rx_cal_radio_saveregs + [4]); + else + write_radio_reg( + pi, + RADIO_2056_RX_LNAG_TUNE + | RADIO_2056_RX0, + pi-> + tx_rx_cal_radio_saveregs + [4]); + } + + } else { + write_radio_reg(pi, + RADIO_2056_TX_RXIQCAL_TXMUX | + RADIO_2056_TX0, + pi->tx_rx_cal_radio_saveregs[0]); + + write_radio_reg(pi, + RADIO_2056_RX_RXIQCAL_RXMUX | + RADIO_2056_RX1, + pi->tx_rx_cal_radio_saveregs[1]); + + if (pi->pubpi.radiorev >= 5) { + write_radio_reg(pi, + RADIO_2056_RX_RXSPARE2 | + RADIO_2056_RX1, + pi-> + tx_rx_cal_radio_saveregs[2]); + + write_radio_reg(pi, + RADIO_2056_TX_TXSPARE2 | + RADIO_2056_TX0, + pi-> + tx_rx_cal_radio_saveregs[3]); + } + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (pi->pubpi.radiorev >= 5) + write_radio_reg( + pi, + RADIO_2056_RX_LNAA_MASTER + | RADIO_2056_RX1, + pi-> + tx_rx_cal_radio_saveregs + [4]); + else + write_radio_reg( + pi, + RADIO_2056_RX_LNAA_TUNE + | RADIO_2056_RX1, + pi-> + tx_rx_cal_radio_saveregs + [4]); + } else { + if (pi->pubpi.radiorev >= 5) + write_radio_reg( + pi, + RADIO_2056_RX_LNAG_MASTER + | RADIO_2056_RX1, + pi-> + tx_rx_cal_radio_saveregs + [4]); + else + write_radio_reg( + pi, + RADIO_2056_RX_LNAG_TUNE + | RADIO_2056_RX1, + pi-> + tx_rx_cal_radio_saveregs + [4]); + } + } + } +} + +static void wlc_phy_rxcal_physetup_nphy(struct brcms_phy *pi, u8 rx_core) +{ + u8 tx_core; + u16 rx_antval, tx_antval; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + tx_core = rx_core; + else + tx_core = (rx_core == PHY_CORE_0) ? 1 : 0; + + pi->tx_rx_cal_phy_saveregs[0] = read_phy_reg(pi, 0xa2); + pi->tx_rx_cal_phy_saveregs[1] = + read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : 0xa7); + pi->tx_rx_cal_phy_saveregs[2] = + read_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5); + pi->tx_rx_cal_phy_saveregs[3] = read_phy_reg(pi, 0x91); + pi->tx_rx_cal_phy_saveregs[4] = read_phy_reg(pi, 0x92); + pi->tx_rx_cal_phy_saveregs[5] = read_phy_reg(pi, 0x7a); + pi->tx_rx_cal_phy_saveregs[6] = read_phy_reg(pi, 0x7d); + pi->tx_rx_cal_phy_saveregs[7] = read_phy_reg(pi, 0xe7); + pi->tx_rx_cal_phy_saveregs[8] = read_phy_reg(pi, 0xec); + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + pi->tx_rx_cal_phy_saveregs[11] = read_phy_reg(pi, 0x342); + pi->tx_rx_cal_phy_saveregs[12] = read_phy_reg(pi, 0x343); + pi->tx_rx_cal_phy_saveregs[13] = read_phy_reg(pi, 0x346); + pi->tx_rx_cal_phy_saveregs[14] = read_phy_reg(pi, 0x347); + } + + pi->tx_rx_cal_phy_saveregs[9] = read_phy_reg(pi, 0x297); + pi->tx_rx_cal_phy_saveregs[10] = read_phy_reg(pi, 0x29b); + mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (0) << 0); + + mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 0), (0) << 0); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0); + + mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << (1 - rx_core)) << 12); + + } else { + + mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << tx_core) << 12); + mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0); + mod_phy_reg(pi, 0xa2, (0xf << 4), (1 << rx_core) << 4); + mod_phy_reg(pi, 0xa2, (0xf << 8), (1 << rx_core) << 8); + } + + mod_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7), (0x1 << 2), 0); + mod_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5, + (0x1 << 2), (0x1 << 2)); + if (NREV_LT(pi->pubpi.phy_rev, 7)) { + mod_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7), + (0x1 << 0) | (0x1 << 1), 0); + mod_phy_reg(pi, (rx_core == PHY_CORE_0) ? + 0x8f : 0xa5, + (0x1 << 0) | (0x1 << 1), (0x1 << 0) | (0x1 << 1)); + } + + wlc_phy_rfctrlintc_override_nphy(pi, NPHY_RfctrlIntc_override_PA, 0, + RADIO_MIMO_CORESEL_CORE1 | + RADIO_MIMO_CORESEL_CORE2); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 3), + 0, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID0); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 9), 0, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 10), 1, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 0), 1, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 1), 1, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID2); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 11), 0, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + if (CHSPEC_IS40(pi->radio_chanspec)) + wlc_phy_rfctrl_override_nphy_rev7( + pi, + (0x1 << 7), + 2, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + else + wlc_phy_rfctrl_override_nphy_rev7( + pi, + (0x1 << 7), + 0, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 7), + 0, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + wlc_phy_rfctrl_override_nphy_rev7(pi, (0x1 << 5), 0, 0, 0, + NPHY_REV7_RFCTRLOVERRIDE_ID1); + } else { + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 3), 0, 3, 0); + } + + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RX2TX); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + 0x1, rx_core + 1); + } else { + + if (rx_core == PHY_CORE_0) { + rx_antval = 0x1; + tx_antval = 0x8; + } else { + rx_antval = 0x4; + tx_antval = 0x2; + } + + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + rx_antval, rx_core + 1); + wlc_phy_rfctrlintc_override_nphy(pi, + NPHY_RfctrlIntc_override_TRSW, + tx_antval, tx_core + 1); + } +} + +static void wlc_phy_rxcal_phycleanup_nphy(struct brcms_phy *pi, u8 rx_core) +{ + + write_phy_reg(pi, 0xa2, pi->tx_rx_cal_phy_saveregs[0]); + write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : 0xa7, + pi->tx_rx_cal_phy_saveregs[1]); + write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x8f : 0xa5, + pi->tx_rx_cal_phy_saveregs[2]); + write_phy_reg(pi, 0x91, pi->tx_rx_cal_phy_saveregs[3]); + write_phy_reg(pi, 0x92, pi->tx_rx_cal_phy_saveregs[4]); + + write_phy_reg(pi, 0x7a, pi->tx_rx_cal_phy_saveregs[5]); + write_phy_reg(pi, 0x7d, pi->tx_rx_cal_phy_saveregs[6]); + write_phy_reg(pi, 0xe7, pi->tx_rx_cal_phy_saveregs[7]); + write_phy_reg(pi, 0xec, pi->tx_rx_cal_phy_saveregs[8]); + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + write_phy_reg(pi, 0x342, pi->tx_rx_cal_phy_saveregs[11]); + write_phy_reg(pi, 0x343, pi->tx_rx_cal_phy_saveregs[12]); + write_phy_reg(pi, 0x346, pi->tx_rx_cal_phy_saveregs[13]); + write_phy_reg(pi, 0x347, pi->tx_rx_cal_phy_saveregs[14]); + } + + write_phy_reg(pi, 0x297, pi->tx_rx_cal_phy_saveregs[9]); + write_phy_reg(pi, 0x29b, pi->tx_rx_cal_phy_saveregs[10]); +} + +static void +wlc_phy_rxcal_gainctrl_nphy_rev5(struct brcms_phy *pi, u8 rx_core, + u16 *rxgain, u8 cal_type) +{ + + u16 num_samps; + struct phy_iq_est est[PHY_CORE_MAX]; + u8 tx_core; + struct nphy_iq_comp save_comp, zero_comp; + u32 i_pwr, q_pwr, curr_pwr, optim_pwr = 0, prev_pwr = 0, + thresh_pwr = 10000; + s16 desired_log2_pwr, actual_log2_pwr, delta_pwr; + bool gainctrl_done = false; + u8 mix_tia_gain = 3; + s8 optim_gaintbl_index = 0, prev_gaintbl_index = 0; + s8 curr_gaintbl_index = 3; + u8 gainctrl_dirn = NPHY_RXCAL_GAIN_INIT; + const struct nphy_ipa_txrxgain *nphy_rxcal_gaintbl; + u16 hpvga, lpf_biq1, lpf_biq0, lna2, lna1; + int fine_gain_idx; + s8 txpwrindex; + u16 nphy_rxcal_txgain[2]; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + tx_core = rx_core; + else + tx_core = 1 - rx_core; + + num_samps = 1024; + desired_log2_pwr = (cal_type == 0) ? 13 : 13; + + wlc_phy_rx_iq_coeffs_nphy(pi, 0, &save_comp); + zero_comp.a0 = zero_comp.b0 = zero_comp.a1 = zero_comp.b1 = 0x0; + wlc_phy_rx_iq_coeffs_nphy(pi, 1, &zero_comp); + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) + mix_tia_gain = 3; + else if (NREV_GE(pi->pubpi.phy_rev, 4)) + mix_tia_gain = 4; + else + mix_tia_gain = 6; + if (NREV_GE(pi->pubpi.phy_rev, 7)) + nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_5GHz_rev7; + else + nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_5GHz; + } else { + if (NREV_GE(pi->pubpi.phy_rev, 7)) + nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_2GHz_rev7; + else + nphy_rxcal_gaintbl = nphy_ipa_rxcal_gaintbl_2GHz; + } + + do { + + hpvga = (NREV_GE(pi->pubpi.phy_rev, 7)) ? + 0 : nphy_rxcal_gaintbl[curr_gaintbl_index].hpvga; + lpf_biq1 = nphy_rxcal_gaintbl[curr_gaintbl_index].lpf_biq1; + lpf_biq0 = nphy_rxcal_gaintbl[curr_gaintbl_index].lpf_biq0; + lna2 = nphy_rxcal_gaintbl[curr_gaintbl_index].lna2; + lna1 = nphy_rxcal_gaintbl[curr_gaintbl_index].lna1; + txpwrindex = nphy_rxcal_gaintbl[curr_gaintbl_index].txpwrindex; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_rxgain, + ((lpf_biq1 << 12) | + (lpf_biq0 << 8) | + (mix_tia_gain << 4) | (lna2 << 2) + | lna1), 0x3, 0); + else + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), + ((hpvga << 12) | + (lpf_biq1 << 10) | + (lpf_biq0 << 8) | + (mix_tia_gain << 4) | + (lna2 << 2) | lna1), 0x3, + 0); + + pi->nphy_rxcal_pwr_idx[tx_core] = txpwrindex; + + if (txpwrindex == -1) { + nphy_rxcal_txgain[0] = 0x8ff0 | pi->nphy_gmval; + nphy_rxcal_txgain[1] = 0x8ff0 | pi->nphy_gmval; + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, + 2, 0x110, 16, + nphy_rxcal_txgain); + } else { + wlc_phy_txpwr_index_nphy(pi, tx_core + 1, txpwrindex, + false); + } + + wlc_phy_tx_tone_nphy(pi, (CHSPEC_IS40(pi->radio_chanspec)) ? + NPHY_RXCAL_TONEFREQ_40MHz : + NPHY_RXCAL_TONEFREQ_20MHz, + NPHY_RXCAL_TONEAMP, 0, cal_type, false); + + wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0); + i_pwr = (est[rx_core].i_pwr + num_samps / 2) / num_samps; + q_pwr = (est[rx_core].q_pwr + num_samps / 2) / num_samps; + curr_pwr = i_pwr + q_pwr; + + switch (gainctrl_dirn) { + case NPHY_RXCAL_GAIN_INIT: + if (curr_pwr > thresh_pwr) { + gainctrl_dirn = NPHY_RXCAL_GAIN_DOWN; + prev_gaintbl_index = curr_gaintbl_index; + curr_gaintbl_index--; + } else { + gainctrl_dirn = NPHY_RXCAL_GAIN_UP; + prev_gaintbl_index = curr_gaintbl_index; + curr_gaintbl_index++; + } + break; + + case NPHY_RXCAL_GAIN_UP: + if (curr_pwr > thresh_pwr) { + gainctrl_done = true; + optim_pwr = prev_pwr; + optim_gaintbl_index = prev_gaintbl_index; + } else { + prev_gaintbl_index = curr_gaintbl_index; + curr_gaintbl_index++; + } + break; + + case NPHY_RXCAL_GAIN_DOWN: + if (curr_pwr > thresh_pwr) { + prev_gaintbl_index = curr_gaintbl_index; + curr_gaintbl_index--; + } else { + gainctrl_done = true; + optim_pwr = curr_pwr; + optim_gaintbl_index = curr_gaintbl_index; + } + break; + + default: + break; + } + + if ((curr_gaintbl_index < 0) || + (curr_gaintbl_index > NPHY_IPA_RXCAL_MAXGAININDEX)) { + gainctrl_done = true; + optim_pwr = curr_pwr; + optim_gaintbl_index = prev_gaintbl_index; + } else { + prev_pwr = curr_pwr; + } + + wlc_phy_stopplayback_nphy(pi); + } while (!gainctrl_done); + + hpvga = nphy_rxcal_gaintbl[optim_gaintbl_index].hpvga; + lpf_biq1 = nphy_rxcal_gaintbl[optim_gaintbl_index].lpf_biq1; + lpf_biq0 = nphy_rxcal_gaintbl[optim_gaintbl_index].lpf_biq0; + lna2 = nphy_rxcal_gaintbl[optim_gaintbl_index].lna2; + lna1 = nphy_rxcal_gaintbl[optim_gaintbl_index].lna1; + txpwrindex = nphy_rxcal_gaintbl[optim_gaintbl_index].txpwrindex; + + actual_log2_pwr = wlc_phy_nbits(optim_pwr); + delta_pwr = desired_log2_pwr - actual_log2_pwr; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + fine_gain_idx = (int)lpf_biq1 + delta_pwr; + + if (fine_gain_idx + (int)lpf_biq0 > 10) + lpf_biq1 = 10 - lpf_biq0; + else + lpf_biq1 = (u16) max(fine_gain_idx, 0); + + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_rxgain, + ((lpf_biq1 << 12) | + (lpf_biq0 << 8) | + (mix_tia_gain << 4) | + (lna2 << 2) | lna1), 0x3, + 0); + } else { + hpvga = (u16) max(min(((int)hpvga) + delta_pwr, 10), 0); + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), + ((hpvga << 12) | + (lpf_biq1 << 10) | + (lpf_biq0 << 8) | + (mix_tia_gain << 4) | + (lna2 << 2) | + lna1), 0x3, 0); + } + + if (rxgain != NULL) { + *rxgain++ = lna1; + *rxgain++ = lna2; + *rxgain++ = mix_tia_gain; + *rxgain++ = lpf_biq0; + *rxgain++ = lpf_biq1; + *rxgain = hpvga; + } + + wlc_phy_rx_iq_coeffs_nphy(pi, 1, &save_comp); +} + +static void +wlc_phy_rxcal_gainctrl_nphy(struct brcms_phy *pi, u8 rx_core, u16 *rxgain, + u8 cal_type) +{ + wlc_phy_rxcal_gainctrl_nphy_rev5(pi, rx_core, rxgain, cal_type); +} + +static u8 +wlc_phy_rc_sweep_nphy(struct brcms_phy *pi, u8 core_idx, u8 loopback_type) +{ + u32 target_bws[2] = { 9500, 21000 }; + u32 ref_tones[2] = { 3000, 6000 }; + u32 target_bw, ref_tone; + + u32 target_pwr_ratios[2] = { 28606, 18468 }; + u32 target_pwr_ratio, pwr_ratio, last_pwr_ratio = 0; + + u16 start_rccal_ovr_val = 128; + u16 txlpf_rccal_lpc_ovr_val = 128; + u16 rxlpf_rccal_hpc_ovr_val = 159; + + u16 orig_txlpf_rccal_lpc_ovr_val; + u16 orig_rxlpf_rccal_hpc_ovr_val; + u16 radio_addr_offset_rx; + u16 radio_addr_offset_tx; + u16 orig_dcBypass; + u16 orig_RxStrnFilt40Num[6]; + u16 orig_RxStrnFilt40Den[4]; + u16 orig_rfctrloverride[2]; + u16 orig_rfctrlauxreg[2]; + u16 orig_rfctrlrssiothers; + u16 tx_lpf_bw = 4; + + u16 rx_lpf_bw, rx_lpf_bws[2] = { 2, 4 }; + u16 lpf_hpc = 7, hpvga_hpc = 7; + + s8 rccal_stepsize; + u16 rccal_val, last_rccal_val = 0, best_rccal_val = 0; + u32 ref_iq_vals = 0, target_iq_vals = 0; + u16 num_samps, log_num_samps = 10; + struct phy_iq_est est[PHY_CORE_MAX]; + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + return 0; + + num_samps = (1 << log_num_samps); + + if (CHSPEC_IS40(pi->radio_chanspec)) { + target_bw = target_bws[1]; + target_pwr_ratio = target_pwr_ratios[1]; + ref_tone = ref_tones[1]; + rx_lpf_bw = rx_lpf_bws[1]; + } else { + target_bw = target_bws[0]; + target_pwr_ratio = target_pwr_ratios[0]; + ref_tone = ref_tones[0]; + rx_lpf_bw = rx_lpf_bws[0]; + } + + if (core_idx == 0) { + radio_addr_offset_rx = RADIO_2056_RX0; + radio_addr_offset_tx = + (loopback_type == 0) ? RADIO_2056_TX0 : RADIO_2056_TX1; + } else { + radio_addr_offset_rx = RADIO_2056_RX1; + radio_addr_offset_tx = + (loopback_type == 0) ? RADIO_2056_TX1 : RADIO_2056_TX0; + } + + orig_txlpf_rccal_lpc_ovr_val = + read_radio_reg(pi, + (RADIO_2056_TX_TXLPF_RCCAL | + radio_addr_offset_tx)); + orig_rxlpf_rccal_hpc_ovr_val = + read_radio_reg(pi, + (RADIO_2056_RX_RXLPF_RCCAL_HPC | + radio_addr_offset_rx)); + + orig_dcBypass = ((read_phy_reg(pi, 0x48) >> 8) & 1); + + orig_RxStrnFilt40Num[0] = read_phy_reg(pi, 0x267); + orig_RxStrnFilt40Num[1] = read_phy_reg(pi, 0x268); + orig_RxStrnFilt40Num[2] = read_phy_reg(pi, 0x269); + orig_RxStrnFilt40Den[0] = read_phy_reg(pi, 0x26a); + orig_RxStrnFilt40Den[1] = read_phy_reg(pi, 0x26b); + orig_RxStrnFilt40Num[3] = read_phy_reg(pi, 0x26c); + orig_RxStrnFilt40Num[4] = read_phy_reg(pi, 0x26d); + orig_RxStrnFilt40Num[5] = read_phy_reg(pi, 0x26e); + orig_RxStrnFilt40Den[2] = read_phy_reg(pi, 0x26f); + orig_RxStrnFilt40Den[3] = read_phy_reg(pi, 0x270); + + orig_rfctrloverride[0] = read_phy_reg(pi, 0xe7); + orig_rfctrloverride[1] = read_phy_reg(pi, 0xec); + orig_rfctrlauxreg[0] = read_phy_reg(pi, 0xf8); + orig_rfctrlauxreg[1] = read_phy_reg(pi, 0xfa); + orig_rfctrlrssiothers = read_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d); + + write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL | radio_addr_offset_tx), + txlpf_rccal_lpc_ovr_val); + + write_radio_reg(pi, + (RADIO_2056_RX_RXLPF_RCCAL_HPC | radio_addr_offset_rx), + rxlpf_rccal_hpc_ovr_val); + + mod_phy_reg(pi, 0x48, (0x1 << 8), (0x1 << 8)); + + write_phy_reg(pi, 0x267, 0x02d4); + write_phy_reg(pi, 0x268, 0x0000); + write_phy_reg(pi, 0x269, 0x0000); + write_phy_reg(pi, 0x26a, 0x0000); + write_phy_reg(pi, 0x26b, 0x0000); + write_phy_reg(pi, 0x26c, 0x02d4); + write_phy_reg(pi, 0x26d, 0x0000); + write_phy_reg(pi, 0x26e, 0x0000); + write_phy_reg(pi, 0x26f, 0x0000); + write_phy_reg(pi, 0x270, 0x0000); + + or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 8)); + or_phy_reg(pi, (core_idx == 0) ? 0xec : 0xe7, (0x1 << 15)); + or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 9)); + or_phy_reg(pi, (core_idx == 0) ? 0xe7 : 0xec, (0x1 << 10)); + + mod_phy_reg(pi, (core_idx == 0) ? 0xfa : 0xf8, + (0x7 << 10), (tx_lpf_bw << 10)); + mod_phy_reg(pi, (core_idx == 0) ? 0xf8 : 0xfa, + (0x7 << 0), (hpvga_hpc << 0)); + mod_phy_reg(pi, (core_idx == 0) ? 0xf8 : 0xfa, + (0x7 << 4), (lpf_hpc << 4)); + mod_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d, + (0x7 << 8), (rx_lpf_bw << 8)); + + rccal_stepsize = 16; + rccal_val = start_rccal_ovr_val + rccal_stepsize; + + while (rccal_stepsize >= 0) { + write_radio_reg(pi, + (RADIO_2056_RX_RXLPF_RCCAL_LPC | + radio_addr_offset_rx), rccal_val); + + if (rccal_stepsize == 16) { + + wlc_phy_tx_tone_nphy(pi, ref_tone, NPHY_RXCAL_TONEAMP, + 0, 1, false); + udelay(2); + + wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0); + + if (core_idx == 0) + ref_iq_vals = + max_t(u32, (est[0].i_pwr + + est[0].q_pwr) >> + (log_num_samps + 1), + 1); + else + ref_iq_vals = + max_t(u32, (est[1].i_pwr + + est[1].q_pwr) >> + (log_num_samps + 1), + 1); + + wlc_phy_tx_tone_nphy(pi, target_bw, NPHY_RXCAL_TONEAMP, + 0, 1, false); + udelay(2); + } + + wlc_phy_rx_iq_est_nphy(pi, est, num_samps, 32, 0); + + if (core_idx == 0) + target_iq_vals = (est[0].i_pwr + est[0].q_pwr) >> + (log_num_samps + 1); + else + target_iq_vals = + (est[1].i_pwr + + est[1].q_pwr) >> (log_num_samps + 1); + + pwr_ratio = (uint) ((target_iq_vals << 16) / ref_iq_vals); + + if (rccal_stepsize == 0) + rccal_stepsize--; + else if (rccal_stepsize == 1) { + last_rccal_val = rccal_val; + rccal_val += (pwr_ratio > target_pwr_ratio) ? 1 : -1; + last_pwr_ratio = pwr_ratio; + rccal_stepsize--; + } else { + rccal_stepsize = (rccal_stepsize >> 1); + rccal_val += ((pwr_ratio > target_pwr_ratio) ? + rccal_stepsize : (-rccal_stepsize)); + } + + if (rccal_stepsize == -1) { + best_rccal_val = + (abs((int)last_pwr_ratio - + (int)target_pwr_ratio) < + abs((int)pwr_ratio - + (int)target_pwr_ratio)) ? last_rccal_val : + rccal_val; + + if (CHSPEC_IS40(pi->radio_chanspec)) { + if ((best_rccal_val > 140) + || (best_rccal_val < 135)) + best_rccal_val = 138; + } else { + if ((best_rccal_val > 142) + || (best_rccal_val < 137)) + best_rccal_val = 140; + } + + write_radio_reg(pi, + (RADIO_2056_RX_RXLPF_RCCAL_LPC | + radio_addr_offset_rx), best_rccal_val); + } + } + + wlc_phy_stopplayback_nphy(pi); + + write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL | radio_addr_offset_tx), + orig_txlpf_rccal_lpc_ovr_val); + write_radio_reg(pi, + (RADIO_2056_RX_RXLPF_RCCAL_HPC | radio_addr_offset_rx), + orig_rxlpf_rccal_hpc_ovr_val); + + mod_phy_reg(pi, 0x48, (0x1 << 8), (orig_dcBypass << 8)); + + write_phy_reg(pi, 0x267, orig_RxStrnFilt40Num[0]); + write_phy_reg(pi, 0x268, orig_RxStrnFilt40Num[1]); + write_phy_reg(pi, 0x269, orig_RxStrnFilt40Num[2]); + write_phy_reg(pi, 0x26a, orig_RxStrnFilt40Den[0]); + write_phy_reg(pi, 0x26b, orig_RxStrnFilt40Den[1]); + write_phy_reg(pi, 0x26c, orig_RxStrnFilt40Num[3]); + write_phy_reg(pi, 0x26d, orig_RxStrnFilt40Num[4]); + write_phy_reg(pi, 0x26e, orig_RxStrnFilt40Num[5]); + write_phy_reg(pi, 0x26f, orig_RxStrnFilt40Den[2]); + write_phy_reg(pi, 0x270, orig_RxStrnFilt40Den[3]); + + write_phy_reg(pi, 0xe7, orig_rfctrloverride[0]); + write_phy_reg(pi, 0xec, orig_rfctrloverride[1]); + write_phy_reg(pi, 0xf8, orig_rfctrlauxreg[0]); + write_phy_reg(pi, 0xfa, orig_rfctrlauxreg[1]); + write_phy_reg(pi, (core_idx == 0) ? 0x7a : 0x7d, orig_rfctrlrssiothers); + + pi->nphy_anarxlpf_adjusted = false; + + return best_rccal_val - 0x80; +} + +#define WAIT_FOR_SCOPE 4000 +static int wlc_phy_cal_rxiq_nphy_rev3(struct brcms_phy *pi, + struct nphy_txgains target_gain, + u8 cal_type, bool debug) +{ + u16 orig_BBConfig; + u8 core_no, rx_core; + u8 best_rccal[2]; + u16 gain_save[2]; + u16 cal_gain[2]; + struct nphy_iqcal_params cal_params[2]; + u8 rxcore_state; + s8 rxlpf_rccal_hpc, txlpf_rccal_lpc; + s8 txlpf_idac; + bool phyhang_avoid_state = false; + bool skip_rxiqcal = false; + + orig_BBConfig = read_phy_reg(pi, 0x01); + mod_phy_reg(pi, 0x01, (0x1 << 15), 0); + + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + if (NREV_GE(pi->pubpi.phy_rev, 4)) { + phyhang_avoid_state = pi->phyhang_avoid; + pi->phyhang_avoid = false; + } + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save); + + for (core_no = 0; core_no <= 1; core_no++) { + wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain, + &cal_params[core_no]); + cal_gain[core_no] = cal_params[core_no].cal_gain; + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain); + + rxcore_state = wlc_phy_rxcore_getstate_nphy( + (struct brcms_phy_pub *) pi); + + for (rx_core = 0; rx_core < pi->pubpi.phy_corenum; rx_core++) { + + skip_rxiqcal = + ((rxcore_state & (1 << rx_core)) == 0) ? true : false; + + wlc_phy_rxcal_physetup_nphy(pi, rx_core); + + wlc_phy_rxcal_radio_setup_nphy(pi, rx_core); + + if ((!skip_rxiqcal) && ((cal_type == 0) || (cal_type == 2))) { + + wlc_phy_rxcal_gainctrl_nphy(pi, rx_core, NULL, 0); + + wlc_phy_tx_tone_nphy(pi, + (CHSPEC_IS40( + pi->radio_chanspec)) ? + NPHY_RXCAL_TONEFREQ_40MHz : + NPHY_RXCAL_TONEFREQ_20MHz, + NPHY_RXCAL_TONEAMP, 0, cal_type, + false); + + if (debug) + mdelay(WAIT_FOR_SCOPE); + + wlc_phy_calc_rx_iq_comp_nphy(pi, rx_core + 1); + wlc_phy_stopplayback_nphy(pi); + } + + if (((cal_type == 1) || (cal_type == 2)) + && NREV_LT(pi->pubpi.phy_rev, 7)) { + + if (rx_core == PHY_CORE_1) { + + if (rxcore_state == 1) + wlc_phy_rxcore_setstate_nphy( + (struct brcms_phy_pub *) pi, 3); + + wlc_phy_rxcal_gainctrl_nphy(pi, rx_core, NULL, + 1); + + best_rccal[rx_core] = + wlc_phy_rc_sweep_nphy(pi, rx_core, 1); + pi->nphy_rccal_value = best_rccal[rx_core]; + + if (rxcore_state == 1) + wlc_phy_rxcore_setstate_nphy( + (struct brcms_phy_pub *) pi, + rxcore_state); + } + } + + wlc_phy_rxcal_radio_cleanup_nphy(pi, rx_core); + + wlc_phy_rxcal_phycleanup_nphy(pi, rx_core); + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); + } + + if ((cal_type == 1) || (cal_type == 2)) { + + best_rccal[0] = best_rccal[1]; + write_radio_reg(pi, + (RADIO_2056_RX_RXLPF_RCCAL_LPC | + RADIO_2056_RX0), (best_rccal[0] | 0x80)); + + for (rx_core = 0; rx_core < pi->pubpi.phy_corenum; rx_core++) { + rxlpf_rccal_hpc = + (((int)best_rccal[rx_core] - 12) >> 1) + 10; + txlpf_rccal_lpc = ((int)best_rccal[rx_core] - 12) + 10; + + if (PHY_IPA(pi)) { + txlpf_rccal_lpc += + (pi->bw == WL_CHANSPEC_BW_40) ? 24 : 12; + txlpf_idac = (pi->bw == WL_CHANSPEC_BW_40) ? + 0x0e : 0x13; + WRITE_RADIO_REG2(pi, RADIO_2056, TX, rx_core, + TXLPF_IDAC_4, txlpf_idac); + } + + rxlpf_rccal_hpc = max(min_t(u8, rxlpf_rccal_hpc, 31), + 0); + txlpf_rccal_lpc = max(min_t(u8, txlpf_rccal_lpc, 31), + 0); + + write_radio_reg(pi, (RADIO_2056_RX_RXLPF_RCCAL_HPC | + ((rx_core == + PHY_CORE_0) ? RADIO_2056_RX0 : + RADIO_2056_RX1)), + (rxlpf_rccal_hpc | 0x80)); + + write_radio_reg(pi, (RADIO_2056_TX_TXLPF_RCCAL | + ((rx_core == + PHY_CORE_0) ? RADIO_2056_TX0 : + RADIO_2056_TX1)), + (txlpf_rccal_lpc | 0x80)); + } + } + + write_phy_reg(pi, 0x01, orig_BBConfig); + + wlc_phy_resetcca_nphy(pi); + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + wlc_phy_rfctrl_override_1tomany_nphy( + pi, + NPHY_REV7_RfctrlOverride_cmd_rxgain, + 0, 0x3, 1); + else + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 12), 0, 0x3, 1); + + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, + gain_save); + + if (NREV_GE(pi->pubpi.phy_rev, 4)) + pi->phyhang_avoid = phyhang_avoid_state; + + wlc_phy_stay_in_carriersearch_nphy(pi, false); + + return 0; +} + +static int +wlc_phy_cal_rxiq_nphy_rev2(struct brcms_phy *pi, + struct nphy_txgains target_gain, bool debug) +{ + struct phy_iq_est est[PHY_CORE_MAX]; + u8 core_num, rx_core, tx_core; + u16 lna_vals[] = { 0x3, 0x3, 0x1 }; + u16 hpf1_vals[] = { 0x7, 0x2, 0x0 }; + u16 hpf2_vals[] = { 0x2, 0x0, 0x0 }; + s16 curr_hpf1, curr_hpf2, curr_hpf, curr_lna; + s16 desired_log2_pwr, actual_log2_pwr, hpf_change; + u16 orig_RfseqCoreActv, orig_AfectrlCore, orig_AfectrlOverride; + u16 orig_RfctrlIntcRx, orig_RfctrlIntcTx; + u16 num_samps; + u32 i_pwr, q_pwr, tot_pwr[3]; + u8 gain_pass, use_hpf_num; + u16 mask, val1, val2; + u16 core_no; + u16 gain_save[2]; + u16 cal_gain[2]; + struct nphy_iqcal_params cal_params[2]; + u8 phy_bw; + int bcmerror = 0; + bool first_playtone = true; + + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + if (NREV_LT(pi->pubpi.phy_rev, 2)) + wlc_phy_reapply_txcal_coeffs_nphy(pi); + + wlc_phy_table_read_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, gain_save); + + for (core_no = 0; core_no <= 1; core_no++) { + wlc_phy_iqcal_gainparams_nphy(pi, core_no, target_gain, + &cal_params[core_no]); + cal_gain[core_no] = cal_params[core_no].cal_gain; + } + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, cal_gain); + + num_samps = 1024; + desired_log2_pwr = 13; + + for (core_num = 0; core_num < 2; core_num++) { + + rx_core = core_num; + tx_core = 1 - core_num; + + orig_RfseqCoreActv = read_phy_reg(pi, 0xa2); + orig_AfectrlCore = read_phy_reg(pi, (rx_core == PHY_CORE_0) ? + 0xa6 : 0xa7); + orig_AfectrlOverride = read_phy_reg(pi, 0xa5); + orig_RfctrlIntcRx = read_phy_reg(pi, (rx_core == PHY_CORE_0) ? + 0x91 : 0x92); + orig_RfctrlIntcTx = read_phy_reg(pi, (tx_core == PHY_CORE_0) ? + 0x91 : 0x92); + + mod_phy_reg(pi, 0xa2, (0xf << 12), (1 << tx_core) << 12); + mod_phy_reg(pi, 0xa2, (0xf << 0), (1 << tx_core) << 0); + + or_phy_reg(pi, ((rx_core == PHY_CORE_0) ? 0xa6 : 0xa7), + ((0x1 << 1) | (0x1 << 2))); + or_phy_reg(pi, 0xa5, ((0x1 << 1) | (0x1 << 2))); + + if (((pi->nphy_rxcalparams) & 0xff000000)) + write_phy_reg(pi, + (rx_core == PHY_CORE_0) ? 0x91 : 0x92, + (CHSPEC_IS5G(pi->radio_chanspec) ? + 0x140 : 0x110)); + else + write_phy_reg(pi, + (rx_core == PHY_CORE_0) ? 0x91 : 0x92, + (CHSPEC_IS5G(pi->radio_chanspec) ? + 0x180 : 0x120)); + + write_phy_reg(pi, (tx_core == PHY_CORE_0) ? 0x91 : 0x92, + (CHSPEC_IS5G(pi->radio_chanspec) ? 0x148 : + 0x114)); + + mask = RADIO_2055_COUPLE_RX_MASK | RADIO_2055_COUPLE_TX_MASK; + if (rx_core == PHY_CORE_0) { + val1 = RADIO_2055_COUPLE_RX_MASK; + val2 = RADIO_2055_COUPLE_TX_MASK; + } else { + val1 = RADIO_2055_COUPLE_TX_MASK; + val2 = RADIO_2055_COUPLE_RX_MASK; + } + + if ((pi->nphy_rxcalparams & 0x10000)) { + mod_radio_reg(pi, RADIO_2055_CORE1_GEN_SPARE2, mask, + val1); + mod_radio_reg(pi, RADIO_2055_CORE2_GEN_SPARE2, mask, + val2); + } + + for (gain_pass = 0; gain_pass < 4; gain_pass++) { + + if (debug) + mdelay(WAIT_FOR_SCOPE); + + if (gain_pass < 3) { + curr_lna = lna_vals[gain_pass]; + curr_hpf1 = hpf1_vals[gain_pass]; + curr_hpf2 = hpf2_vals[gain_pass]; + } else { + + if (tot_pwr[1] > 10000) { + curr_lna = lna_vals[2]; + curr_hpf1 = hpf1_vals[2]; + curr_hpf2 = hpf2_vals[2]; + use_hpf_num = 1; + curr_hpf = curr_hpf1; + actual_log2_pwr = + wlc_phy_nbits(tot_pwr[2]); + } else { + if (tot_pwr[0] > 10000) { + curr_lna = lna_vals[1]; + curr_hpf1 = hpf1_vals[1]; + curr_hpf2 = hpf2_vals[1]; + use_hpf_num = 1; + curr_hpf = curr_hpf1; + actual_log2_pwr = + wlc_phy_nbits( + tot_pwr[1]); + } else { + curr_lna = lna_vals[0]; + curr_hpf1 = hpf1_vals[0]; + curr_hpf2 = hpf2_vals[0]; + use_hpf_num = 2; + curr_hpf = curr_hpf2; + actual_log2_pwr = + wlc_phy_nbits( + tot_pwr[0]); + } + } + + hpf_change = desired_log2_pwr - actual_log2_pwr; + curr_hpf += hpf_change; + curr_hpf = max(min_t(u16, curr_hpf, 10), 0); + if (use_hpf_num == 1) + curr_hpf1 = curr_hpf; + else + curr_hpf2 = curr_hpf; + } + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 10), + ((curr_hpf2 << 8) | + (curr_hpf1 << 4) | + (curr_lna << 2)), 0x3, 0); + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); + + wlc_phy_stopplayback_nphy(pi); + + if (first_playtone) { + bcmerror = wlc_phy_tx_tone_nphy(pi, 4000, + (u16) (pi->nphy_rxcalparams & + 0xffff), 0, 0, true); + first_playtone = false; + } else { + phy_bw = (CHSPEC_IS40(pi->radio_chanspec)) ? + 40 : 20; + wlc_phy_runsamples_nphy(pi, phy_bw * 8, 0xffff, + 0, 0, 0, true); + } + + if (bcmerror == 0) { + if (gain_pass < 3) { + + wlc_phy_rx_iq_est_nphy(pi, est, + num_samps, 32, + 0); + i_pwr = (est[rx_core].i_pwr + + num_samps / 2) / num_samps; + q_pwr = (est[rx_core].q_pwr + + num_samps / 2) / num_samps; + tot_pwr[gain_pass] = i_pwr + q_pwr; + } else { + + wlc_phy_calc_rx_iq_comp_nphy(pi, + (1 << + rx_core)); + } + + wlc_phy_stopplayback_nphy(pi); + } + + if (bcmerror != 0) + break; + } + + and_radio_reg(pi, RADIO_2055_CORE1_GEN_SPARE2, ~mask); + and_radio_reg(pi, RADIO_2055_CORE2_GEN_SPARE2, ~mask); + + write_phy_reg(pi, (tx_core == PHY_CORE_0) ? 0x91 : + 0x92, orig_RfctrlIntcTx); + write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0x91 : + 0x92, orig_RfctrlIntcRx); + write_phy_reg(pi, 0xa5, orig_AfectrlOverride); + write_phy_reg(pi, (rx_core == PHY_CORE_0) ? 0xa6 : + 0xa7, orig_AfectrlCore); + write_phy_reg(pi, 0xa2, orig_RfseqCoreActv); + + if (bcmerror != 0) + break; + } + + wlc_phy_rfctrl_override_nphy(pi, (0x1 << 10), 0, 0x3, 1); + wlc_phy_force_rfseq_nphy(pi, NPHY_RFSEQ_RESET2RX); + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_RFSEQ, 2, 0x110, 16, + gain_save); + + wlc_phy_stay_in_carriersearch_nphy(pi, false); + + return bcmerror; +} + +int +wlc_phy_cal_rxiq_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, + u8 cal_type, bool debug) +{ + if (NREV_GE(pi->pubpi.phy_rev, 7)) + cal_type = 0; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + return wlc_phy_cal_rxiq_nphy_rev3(pi, target_gain, cal_type, + debug); + else + return wlc_phy_cal_rxiq_nphy_rev2(pi, target_gain, debug); +} + +void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi) +{ + uint core; + u32 txgain; + u16 rad_gain, dac_gain, bbmult, m1m2; + u8 txpi[2], chan_freq_range; + s32 rfpwr_offset; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + if (pi->sh->sromrev < 4) { + txpi[0] = txpi[1] = 72; + } else { + + chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0); + switch (chan_freq_range) { + case WL_CHAN_FREQ_RANGE_2G: + txpi[0] = pi->nphy_txpid2g[0]; + txpi[1] = pi->nphy_txpid2g[1]; + break; + case WL_CHAN_FREQ_RANGE_5GL: + txpi[0] = pi->nphy_txpid5gl[0]; + txpi[1] = pi->nphy_txpid5gl[1]; + break; + case WL_CHAN_FREQ_RANGE_5GM: + txpi[0] = pi->nphy_txpid5g[0]; + txpi[1] = pi->nphy_txpid5g[1]; + break; + case WL_CHAN_FREQ_RANGE_5GH: + txpi[0] = pi->nphy_txpid5gh[0]; + txpi[1] = pi->nphy_txpid5gh[1]; + break; + default: + txpi[0] = txpi[1] = 91; + break; + } + } + + if (NREV_GE(pi->pubpi.phy_rev, 7)) + txpi[0] = txpi[1] = 30; + else if (NREV_GE(pi->pubpi.phy_rev, 3)) + txpi[0] = txpi[1] = 40; + + if (NREV_LT(pi->pubpi.phy_rev, 7)) { + + if ((txpi[0] < 40) || (txpi[0] > 100) || + (txpi[1] < 40) || (txpi[1] > 100)) + txpi[0] = txpi[1] = 91; + } + + pi->nphy_txpwrindex[PHY_CORE_0].index_internal = txpi[0]; + pi->nphy_txpwrindex[PHY_CORE_1].index_internal = txpi[1]; + pi->nphy_txpwrindex[PHY_CORE_0].index_internal_save = txpi[0]; + pi->nphy_txpwrindex[PHY_CORE_1].index_internal_save = txpi[1]; + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + uint phyrev = pi->pubpi.phy_rev; + + if (NREV_GE(phyrev, 3)) { + if (PHY_IPA(pi)) { + u32 *tx_gaintbl = + wlc_phy_get_ipa_gaintbl_nphy(pi); + txgain = tx_gaintbl[txpi[core]]; + } else { + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (NREV_IS(phyrev, 3)) { + txgain = + nphy_tpc_5GHz_txgain_rev3 + [txpi[core]]; + } else if (NREV_IS(phyrev, 4)) { + txgain = ( + pi->srom_fem5g.extpagain == + 3) ? + nphy_tpc_5GHz_txgain_HiPwrEPA + [txpi[core]] : + nphy_tpc_5GHz_txgain_rev4 + [txpi[core]]; + } else { + txgain = + nphy_tpc_5GHz_txgain_rev5 + [txpi[core]]; + } + } else { + if (NREV_GE(phyrev, 5) && + (pi->srom_fem2g.extpagain == 3)) { + txgain = + nphy_tpc_txgain_HiPwrEPA + [txpi[core]]; + } else { + txgain = nphy_tpc_txgain_rev3 + [txpi[core]]; + } + } + } + } else { + txgain = nphy_tpc_txgain[txpi[core]]; + } + + if (NREV_GE(phyrev, 3)) + rad_gain = (txgain >> 16) & ((1 << (32 - 16 + 1)) - 1); + else + rad_gain = (txgain >> 16) & ((1 << (28 - 16 + 1)) - 1); + + if (NREV_GE(phyrev, 7)) + dac_gain = (txgain >> 8) & ((1 << (10 - 8 + 1)) - 1); + else + dac_gain = (txgain >> 8) & ((1 << (13 - 8 + 1)) - 1); + + bbmult = (txgain >> 0) & ((1 << (7 - 0 + 1)) - 1); + + if (NREV_GE(phyrev, 3)) + mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f : + 0xa5), (0x1 << 8), (0x1 << 8)); + else + mod_phy_reg(pi, 0xa5, (0x1 << 14), (0x1 << 14)); + + write_phy_reg(pi, (core == PHY_CORE_0) ? 0xaa : 0xab, dac_gain); + + wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16, + &rad_gain); + + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2); + m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00); + m1m2 |= ((core == PHY_CORE_0) ? (bbmult << 8) : (bbmult << 0)); + wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2); + + if (PHY_IPA(pi)) { + wlc_phy_table_read_nphy(pi, + (core == + PHY_CORE_0 ? + NPHY_TBL_ID_CORE1TXPWRCTL : + NPHY_TBL_ID_CORE2TXPWRCTL), 1, + 576 + txpi[core], 32, + &rfpwr_offset); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1ff << 4), + ((s16) rfpwr_offset) << 4); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 2), (1) << 2); + + } + } + + and_phy_reg(pi, 0xbf, (u16) (~(0x1f << 0))); + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +static void +wlc_phy_txpwr_nphy_srom_convert(u8 *srom_max, u16 *pwr_offset, + u8 tmp_max_pwr, u8 rate_start, + u8 rate_end) +{ + u8 rate; + u8 word_num, nibble_num; + u8 tmp_nibble; + + for (rate = rate_start; rate <= rate_end; rate++) { + word_num = (rate - rate_start) >> 2; + nibble_num = (rate - rate_start) & 0x3; + tmp_nibble = (pwr_offset[word_num] >> 4 * nibble_num) & 0xf; + + srom_max[rate] = tmp_max_pwr - 2 * tmp_nibble; + } +} + +static void +wlc_phy_txpwr_nphy_po_apply(u8 *srom_max, u8 pwr_offset, + u8 rate_start, u8 rate_end) +{ + u8 rate; + + for (rate = rate_start; rate <= rate_end; rate++) + srom_max[rate] -= 2 * pwr_offset; +} + +void +wlc_phy_ofdm_to_mcs_powers_nphy(u8 *power, u8 rate_mcs_start, + u8 rate_mcs_end, u8 rate_ofdm_start) +{ + u8 rate1, rate2; + + rate2 = rate_ofdm_start; + for (rate1 = rate_mcs_start; rate1 <= rate_mcs_end - 1; rate1++) { + power[rate1] = power[rate2]; + rate2 += (rate1 == rate_mcs_start) ? 2 : 1; + } + power[rate_mcs_end] = power[rate_mcs_end - 1]; +} + +void +wlc_phy_mcs_to_ofdm_powers_nphy(u8 *power, u8 rate_ofdm_start, + u8 rate_ofdm_end, u8 rate_mcs_start) +{ + u8 rate1, rate2; + + for (rate1 = rate_ofdm_start, rate2 = rate_mcs_start; + rate1 <= rate_ofdm_end; rate1++, rate2++) { + power[rate1] = power[rate2]; + if (rate1 == rate_ofdm_start) + power[++rate1] = power[rate2]; + } +} + +void wlc_phy_txpwr_apply_nphy(struct brcms_phy *pi) +{ + uint rate1, rate2, band_num; + u8 tmp_bw40po = 0, tmp_cddpo = 0, tmp_stbcpo = 0; + u8 tmp_max_pwr = 0; + u16 pwr_offsets1[2], *pwr_offsets2 = NULL; + u8 *tx_srom_max_rate = NULL; + + for (band_num = 0; band_num < (CH_2G_GROUP + CH_5G_GROUP); + band_num++) { + switch (band_num) { + case 0: + + tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_2g, + pi->nphy_pwrctrl_info[1].max_pwr_2g); + + pwr_offsets1[0] = pi->cck2gpo; + wlc_phy_txpwr_nphy_srom_convert(pi->tx_srom_max_rate_2g, + pwr_offsets1, + tmp_max_pwr, + TXP_FIRST_CCK, + TXP_LAST_CCK); + + pwr_offsets1[0] = (u16) (pi->ofdm2gpo & 0xffff); + pwr_offsets1[1] = + (u16) (pi->ofdm2gpo >> 16) & 0xffff; + + pwr_offsets2 = pi->mcs2gpo; + + tmp_cddpo = pi->cdd2gpo; + tmp_stbcpo = pi->stbc2gpo; + tmp_bw40po = pi->bw402gpo; + + tx_srom_max_rate = pi->tx_srom_max_rate_2g; + break; + case 1: + + tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gm, + pi->nphy_pwrctrl_info[1].max_pwr_5gm); + + pwr_offsets1[0] = (u16) (pi->ofdm5gpo & 0xffff); + pwr_offsets1[1] = + (u16) (pi->ofdm5gpo >> 16) & 0xffff; + + pwr_offsets2 = pi->mcs5gpo; + + tmp_cddpo = pi->cdd5gpo; + tmp_stbcpo = pi->stbc5gpo; + tmp_bw40po = pi->bw405gpo; + + tx_srom_max_rate = pi->tx_srom_max_rate_5g_mid; + break; + case 2: + + tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gl, + pi->nphy_pwrctrl_info[1].max_pwr_5gl); + + pwr_offsets1[0] = (u16) (pi->ofdm5glpo & 0xffff); + pwr_offsets1[1] = + (u16) (pi->ofdm5glpo >> 16) & 0xffff; + + pwr_offsets2 = pi->mcs5glpo; + + tmp_cddpo = pi->cdd5glpo; + tmp_stbcpo = pi->stbc5glpo; + tmp_bw40po = pi->bw405glpo; + + tx_srom_max_rate = pi->tx_srom_max_rate_5g_low; + break; + case 3: + + tmp_max_pwr = min(pi->nphy_pwrctrl_info[0].max_pwr_5gh, + pi->nphy_pwrctrl_info[1].max_pwr_5gh); + + pwr_offsets1[0] = (u16) (pi->ofdm5ghpo & 0xffff); + pwr_offsets1[1] = + (u16) (pi->ofdm5ghpo >> 16) & 0xffff; + + pwr_offsets2 = pi->mcs5ghpo; + + tmp_cddpo = pi->cdd5ghpo; + tmp_stbcpo = pi->stbc5ghpo; + tmp_bw40po = pi->bw405ghpo; + + tx_srom_max_rate = pi->tx_srom_max_rate_5g_hi; + break; + } + + wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets1, + tmp_max_pwr, TXP_FIRST_OFDM, + TXP_LAST_OFDM); + + wlc_phy_ofdm_to_mcs_powers_nphy(tx_srom_max_rate, + TXP_FIRST_MCS_20_SISO, + TXP_LAST_MCS_20_SISO, + TXP_FIRST_OFDM); + + wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets2, + tmp_max_pwr, + TXP_FIRST_MCS_20_CDD, + TXP_LAST_MCS_20_CDD); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, tmp_cddpo, + TXP_FIRST_MCS_20_CDD, + TXP_LAST_MCS_20_CDD); + + wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate, + TXP_FIRST_OFDM_20_CDD, + TXP_LAST_OFDM_20_CDD, + TXP_FIRST_MCS_20_CDD); + + wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, pwr_offsets2, + tmp_max_pwr, + TXP_FIRST_MCS_20_STBC, + TXP_LAST_MCS_20_STBC); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, + tmp_stbcpo, + TXP_FIRST_MCS_20_STBC, + TXP_LAST_MCS_20_STBC); + + wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, + &pwr_offsets2[2], tmp_max_pwr, + TXP_FIRST_MCS_20_SDM, + TXP_LAST_MCS_20_SDM); + + if (NPHY_IS_SROM_REINTERPRET) { + + wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, + &pwr_offsets2[4], + tmp_max_pwr, + TXP_FIRST_MCS_40_SISO, + TXP_LAST_MCS_40_SISO); + + wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate, + TXP_FIRST_OFDM_40_SISO, + TXP_LAST_OFDM_40_SISO, + TXP_FIRST_MCS_40_SISO); + + wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, + &pwr_offsets2[4], + tmp_max_pwr, + TXP_FIRST_MCS_40_CDD, + TXP_LAST_MCS_40_CDD); + + wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, tmp_cddpo, + TXP_FIRST_MCS_40_CDD, + TXP_LAST_MCS_40_CDD); + + wlc_phy_mcs_to_ofdm_powers_nphy(tx_srom_max_rate, + TXP_FIRST_OFDM_40_CDD, + TXP_LAST_OFDM_40_CDD, + TXP_FIRST_MCS_40_CDD); + + wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, + &pwr_offsets2[4], + tmp_max_pwr, + TXP_FIRST_MCS_40_STBC, + TXP_LAST_MCS_40_STBC); + + wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, + tmp_stbcpo, + TXP_FIRST_MCS_40_STBC, + TXP_LAST_MCS_40_STBC); + + wlc_phy_txpwr_nphy_srom_convert(tx_srom_max_rate, + &pwr_offsets2[6], + tmp_max_pwr, + TXP_FIRST_MCS_40_SDM, + TXP_LAST_MCS_40_SDM); + } else { + + for (rate1 = TXP_FIRST_OFDM_40_SISO, rate2 = + TXP_FIRST_OFDM; + rate1 <= TXP_LAST_MCS_40_SDM; + rate1++, rate2++) + tx_srom_max_rate[rate1] = + tx_srom_max_rate[rate2]; + } + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + wlc_phy_txpwr_nphy_po_apply(tx_srom_max_rate, + tmp_bw40po, + TXP_FIRST_OFDM_40_SISO, + TXP_LAST_MCS_40_SDM); + + tx_srom_max_rate[TXP_MCS_32] = + tx_srom_max_rate[TXP_FIRST_MCS_40_CDD]; + } + + return; +} + +void wlc_phy_txpower_recalc_target_nphy(struct brcms_phy *pi) +{ + u8 tx_pwr_ctrl_state; + wlc_phy_txpwr_limit_to_tbl_nphy(pi); + wlc_phy_txpwrctrl_pwr_setup_nphy(pi); + + tx_pwr_ctrl_state = pi->nphy_txpwrctrl; + + if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) { + wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, MCTL_PHYLOCK); + (void)R_REG(&pi->regs->maccontrol); + udelay(1); + } + + wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state); + + if (D11REV_IS(pi->sh->corerev, 11) || D11REV_IS(pi->sh->corerev, 12)) + wlapi_bmac_mctrl(pi->sh->physhim, MCTL_PHYLOCK, 0); +} + +static bool wlc_phy_txpwr_ison_nphy(struct brcms_phy *pi) +{ + return read_phy_reg((pi), 0x1e7) & ((0x1 << 15) | + (0x1 << 14) | (0x1 << 13)); +} + +u16 wlc_phy_txpwr_idx_get_nphy(struct brcms_phy *pi) +{ + u16 tmp; + u16 pwr_idx[2]; + + if (wlc_phy_txpwr_ison_nphy(pi)) { + pwr_idx[0] = wlc_phy_txpwr_idx_cur_get_nphy(pi, PHY_CORE_0); + pwr_idx[1] = wlc_phy_txpwr_idx_cur_get_nphy(pi, PHY_CORE_1); + + tmp = (pwr_idx[0] << 8) | pwr_idx[1]; + } else { + tmp = ((pi->nphy_txpwrindex[PHY_CORE_0].index_internal & 0xff) + << 8) | + (pi->nphy_txpwrindex[PHY_CORE_1].index_internal & 0xff); + } + + return tmp; +} + +void wlc_phy_txpwr_papd_cal_nphy(struct brcms_phy *pi) +{ + if (PHY_IPA(pi) + && (pi->nphy_force_papd_cal + || (wlc_phy_txpwr_ison_nphy(pi) + && + (((u32) + abs(wlc_phy_txpwr_idx_cur_get_nphy(pi, 0) - + pi->nphy_papd_tx_gain_at_last_cal[0]) >= 4) + || ((u32) + abs(wlc_phy_txpwr_idx_cur_get_nphy(pi, 1) - + pi->nphy_papd_tx_gain_at_last_cal[1]) >= 4))))) + wlc_phy_a4(pi, true); +} + +void wlc_phy_txpwrctrl_enable_nphy(struct brcms_phy *pi, u8 ctrl_type) +{ + u16 mask = 0, val = 0, ishw = 0; + u8 ctr; + uint core; + u32 tbl_offset; + u32 tbl_len; + u16 regval[84]; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + switch (ctrl_type) { + case PHY_TPC_HW_OFF: + case PHY_TPC_HW_ON: + pi->nphy_txpwrctrl = ctrl_type; + break; + default: + break; + } + + if (ctrl_type == PHY_TPC_HW_OFF) { + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + + if (wlc_phy_txpwr_ison_nphy(pi)) { + for (core = 0; core < pi->pubpi.phy_corenum; + core++) + pi->nphy_txpwr_idx[core] = + wlc_phy_txpwr_idx_cur_get_nphy( + pi, + (u8) core); + } + + } + + tbl_len = 84; + tbl_offset = 64; + for (ctr = 0; ctr < tbl_len; ctr++) + regval[ctr] = 0; + wlc_phy_table_write_nphy(pi, 26, tbl_len, tbl_offset, 16, + regval); + wlc_phy_table_write_nphy(pi, 27, tbl_len, tbl_offset, 16, + regval); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + and_phy_reg(pi, 0x1e7, + (u16) (~((0x1 << 15) | + (0x1 << 14) | (0x1 << 13)))); + else + and_phy_reg(pi, 0x1e7, + (u16) (~((0x1 << 14) | (0x1 << 13)))); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + or_phy_reg(pi, 0x8f, (0x1 << 8)); + or_phy_reg(pi, 0xa5, (0x1 << 8)); + } else { + or_phy_reg(pi, 0xa5, (0x1 << 14)); + } + + if (NREV_IS(pi->pubpi.phy_rev, 2)) + mod_phy_reg(pi, 0xdc, 0x00ff, 0x53); + else if (NREV_LT(pi->pubpi.phy_rev, 2)) + mod_phy_reg(pi, 0xdc, 0x00ff, 0x5a); + + if (NREV_LT(pi->pubpi.phy_rev, 2) && + pi->bw == WL_CHANSPEC_BW_40) + wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_IQSWAP_WAR, + MHF1_IQSWAP_WAR, BRCM_BAND_ALL); + + } else { + + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE1TXPWRCTL, 84, 64, + 8, pi->adj_pwr_tbl_nphy); + wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_CORE2TXPWRCTL, 84, 64, + 8, pi->adj_pwr_tbl_nphy); + + ishw = (ctrl_type == PHY_TPC_HW_ON) ? 0x1 : 0x0; + mask = (0x1 << 14) | (0x1 << 13); + val = (ishw << 14) | (ishw << 13); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + mask |= (0x1 << 15); + val |= (ishw << 15); + } + + mod_phy_reg(pi, 0x1e7, mask, val); + + if (CHSPEC_IS5G(pi->radio_chanspec)) { + if (NREV_GE(pi->pubpi.phy_rev, 7)) { + mod_phy_reg(pi, 0x1e7, (0x7f << 0), 0x32); + mod_phy_reg(pi, 0x222, (0xff << 0), 0x32); + } else { + mod_phy_reg(pi, 0x1e7, (0x7f << 0), 0x64); + if (NREV_GT(pi->pubpi.phy_rev, 1)) + mod_phy_reg(pi, 0x222, + (0xff << 0), 0x64); + } + } + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + if ((pi->nphy_txpwr_idx[0] != 128) + && (pi->nphy_txpwr_idx[1] != 128)) + wlc_phy_txpwr_idx_cur_set_nphy(pi, + pi-> + nphy_txpwr_idx + [0], + pi-> + nphy_txpwr_idx + [1]); + } + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + and_phy_reg(pi, 0x8f, ~(0x1 << 8)); + and_phy_reg(pi, 0xa5, ~(0x1 << 8)); + } else { + and_phy_reg(pi, 0xa5, ~(0x1 << 14)); + } + + if (NREV_IS(pi->pubpi.phy_rev, 2)) + mod_phy_reg(pi, 0xdc, 0x00ff, 0x3b); + else if (NREV_LT(pi->pubpi.phy_rev, 2)) + mod_phy_reg(pi, 0xdc, 0x00ff, 0x40); + + if (NREV_LT(pi->pubpi.phy_rev, 2) && + pi->bw == WL_CHANSPEC_BW_40) + wlapi_bmac_mhf(pi->sh->physhim, MHF1, MHF1_IQSWAP_WAR, + 0x0, BRCM_BAND_ALL); + + if (PHY_IPA(pi)) { + mod_phy_reg(pi, (0 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 2), (0) << 2); + + mod_phy_reg(pi, (1 == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 2), (0) << 2); + + } + + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +void +wlc_phy_txpwr_index_nphy(struct brcms_phy *pi, u8 core_mask, s8 txpwrindex, + bool restore_cals) +{ + u8 core, txpwrctl_tbl; + u16 tx_ind0, iq_ind0, lo_ind0; + u16 m1m2; + u32 txgain; + u16 rad_gain, dac_gain; + u8 bbmult; + u32 iqcomp; + u16 iqcomp_a, iqcomp_b; + u32 locomp; + u16 tmpval; + u8 tx_pwr_ctrl_state; + s32 rfpwr_offset; + u16 regval[2]; + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + + tx_ind0 = 192; + iq_ind0 = 320; + lo_ind0 = 448; + + for (core = 0; core < pi->pubpi.phy_corenum; core++) { + + if ((core_mask & (1 << core)) == 0) + continue; + + txpwrctl_tbl = (core == PHY_CORE_0) ? 26 : 27; + + if (txpwrindex < 0) { + if (pi->nphy_txpwrindex[core].index < 0) + continue; + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + mod_phy_reg(pi, 0x8f, + (0x1 << 8), + pi->nphy_txpwrindex[core]. + AfectrlOverride); + mod_phy_reg(pi, 0xa5, (0x1 << 8), + pi->nphy_txpwrindex[core]. + AfectrlOverride); + } else { + mod_phy_reg(pi, 0xa5, + (0x1 << 14), + pi->nphy_txpwrindex[core]. + AfectrlOverride); + } + + write_phy_reg(pi, (core == PHY_CORE_0) ? + 0xaa : 0xab, + pi->nphy_txpwrindex[core].AfeCtrlDacGain); + + wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16, + &pi->nphy_txpwrindex[core]. + rad_gain); + + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2); + m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00); + m1m2 |= ((core == PHY_CORE_0) ? + (pi->nphy_txpwrindex[core].bbmult << 8) : + (pi->nphy_txpwrindex[core].bbmult << 0)); + wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2); + + if (restore_cals) { + wlc_phy_table_write_nphy( + pi, 15, 2, (80 + 2 * core), 16, + &pi->nphy_txpwrindex[core].iqcomp_a); + wlc_phy_table_write_nphy( + pi, 15, 1, (85 + core), 16, + &pi->nphy_txpwrindex[core].locomp); + wlc_phy_table_write_nphy( + pi, 15, 1, (93 + core), 16, + &pi->nphy_txpwrindex[core].locomp); + } + + wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl); + + pi->nphy_txpwrindex[core].index_internal = + pi->nphy_txpwrindex[core].index_internal_save; + } else { + + if (pi->nphy_txpwrindex[core].index < 0) { + + if (NREV_GE(pi->pubpi.phy_rev, 3)) { + mod_phy_reg(pi, 0x8f, + (0x1 << 8), + pi->nphy_txpwrindex[core]. + AfectrlOverride); + mod_phy_reg(pi, 0xa5, (0x1 << 8), + pi->nphy_txpwrindex[core]. + AfectrlOverride); + } else { + pi->nphy_txpwrindex[core]. + AfectrlOverride = + read_phy_reg(pi, 0xa5); + } + + pi->nphy_txpwrindex[core].AfeCtrlDacGain = + read_phy_reg(pi, (core == PHY_CORE_0) ? + 0xaa : 0xab); + + wlc_phy_table_read_nphy(pi, 7, 1, + (0x110 + core), 16, + &pi-> + nphy_txpwrindex[core]. + rad_gain); + + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, + &tmpval); + tmpval >>= ((core == PHY_CORE_0) ? 8 : 0); + tmpval &= 0xff; + pi->nphy_txpwrindex[core].bbmult = (u8) tmpval; + + wlc_phy_table_read_nphy(pi, 15, 2, + (80 + 2 * core), 16, + &pi-> + nphy_txpwrindex[core]. + iqcomp_a); + + wlc_phy_table_read_nphy(pi, 15, 1, (85 + core), + 16, + &pi-> + nphy_txpwrindex[core]. + locomp); + + pi->nphy_txpwrindex[core].index_internal_save = + pi->nphy_txpwrindex[core]. + index_internal; + } + + tx_pwr_ctrl_state = pi->nphy_txpwrctrl; + wlc_phy_txpwrctrl_enable_nphy(pi, PHY_TPC_HW_OFF); + + if (NREV_IS(pi->pubpi.phy_rev, 1)) + wlapi_bmac_phyclk_fgc(pi->sh->physhim, ON); + + wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1, + (tx_ind0 + txpwrindex), 32, + &txgain); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + rad_gain = (txgain >> 16) & + ((1 << (32 - 16 + 1)) - 1); + else + rad_gain = (txgain >> 16) & + ((1 << (28 - 16 + 1)) - 1); + + dac_gain = (txgain >> 8) & ((1 << (13 - 8 + 1)) - 1); + bbmult = (txgain >> 0) & ((1 << (7 - 0 + 1)) - 1); + + if (NREV_GE(pi->pubpi.phy_rev, 3)) + mod_phy_reg(pi, ((core == PHY_CORE_0) ? 0x8f : + 0xa5), (0x1 << 8), (0x1 << 8)); + else + mod_phy_reg(pi, 0xa5, (0x1 << 14), (0x1 << 14)); + + write_phy_reg(pi, (core == PHY_CORE_0) ? + 0xaa : 0xab, dac_gain); + + wlc_phy_table_write_nphy(pi, 7, 1, (0x110 + core), 16, + &rad_gain); + + wlc_phy_table_read_nphy(pi, 15, 1, 87, 16, &m1m2); + m1m2 &= ((core == PHY_CORE_0) ? 0x00ff : 0xff00); + m1m2 |= ((core == PHY_CORE_0) ? + (bbmult << 8) : (bbmult << 0)); + + wlc_phy_table_write_nphy(pi, 15, 1, 87, 16, &m1m2); + + wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1, + (iq_ind0 + txpwrindex), 32, + &iqcomp); + iqcomp_a = (iqcomp >> 10) & ((1 << (19 - 10 + 1)) - 1); + iqcomp_b = (iqcomp >> 0) & ((1 << (9 - 0 + 1)) - 1); + + if (restore_cals) { + regval[0] = (u16) iqcomp_a; + regval[1] = (u16) iqcomp_b; + wlc_phy_table_write_nphy(pi, 15, 2, + (80 + 2 * core), 16, + regval); + } + + wlc_phy_table_read_nphy(pi, txpwrctl_tbl, 1, + (lo_ind0 + txpwrindex), 32, + &locomp); + if (restore_cals) + wlc_phy_table_write_nphy(pi, 15, 1, (85 + core), + 16, &locomp); + + if (NREV_IS(pi->pubpi.phy_rev, 1)) + wlapi_bmac_phyclk_fgc(pi->sh->physhim, OFF); + + if (PHY_IPA(pi)) { + wlc_phy_table_read_nphy(pi, + (core == PHY_CORE_0 ? + NPHY_TBL_ID_CORE1TXPWRCTL : + NPHY_TBL_ID_CORE2TXPWRCTL), + 1, 576 + txpwrindex, 32, + &rfpwr_offset); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1ff << 4), + ((s16) rfpwr_offset) << 4); + + mod_phy_reg(pi, (core == PHY_CORE_0) ? 0x297 : + 0x29b, (0x1 << 2), (1) << 2); + + } + + wlc_phy_txpwrctrl_enable_nphy(pi, tx_pwr_ctrl_state); + } + + pi->nphy_txpwrindex[core].index = txpwrindex; + } + + if (pi->phyhang_avoid) + wlc_phy_stay_in_carriersearch_nphy(pi, false); +} + +void +wlc_phy_txpower_sromlimit_get_nphy(struct brcms_phy *pi, uint chan, u8 *max_pwr, + u8 txp_rate_idx) +{ + u8 chan_freq_range; + + chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, chan); + switch (chan_freq_range) { + case WL_CHAN_FREQ_RANGE_2G: + *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx]; + break; + case WL_CHAN_FREQ_RANGE_5GM: + *max_pwr = pi->tx_srom_max_rate_5g_mid[txp_rate_idx]; + break; + case WL_CHAN_FREQ_RANGE_5GL: + *max_pwr = pi->tx_srom_max_rate_5g_low[txp_rate_idx]; + break; + case WL_CHAN_FREQ_RANGE_5GH: + *max_pwr = pi->tx_srom_max_rate_5g_hi[txp_rate_idx]; + break; + default: + *max_pwr = pi->tx_srom_max_rate_2g[txp_rate_idx]; + break; + } + + return; +} + +void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable) +{ + u16 clip_off[] = { 0xffff, 0xffff }; + + if (enable) { + if (pi->nphy_deaf_count == 0) { + pi->classifier_state = + wlc_phy_classifier_nphy(pi, 0, 0); + wlc_phy_classifier_nphy(pi, (0x7 << 0), 4); + wlc_phy_clip_det_nphy(pi, 0, pi->clip_state); + wlc_phy_clip_det_nphy(pi, 1, clip_off); + } + + pi->nphy_deaf_count++; + + wlc_phy_resetcca_nphy(pi); + + } else { + pi->nphy_deaf_count--; + + if (pi->nphy_deaf_count == 0) { + wlc_phy_classifier_nphy(pi, (0x7 << 0), + pi->classifier_state); + wlc_phy_clip_det_nphy(pi, 1, pi->clip_state); + } + } +} + +void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode) +{ + wlapi_suspend_mac_and_wait(pi->sh->physhim); + + if (mode) { + if (pi->nphy_deaf_count == 0) + wlc_phy_stay_in_carriersearch_nphy(pi, true); + } else if (pi->nphy_deaf_count > 0) { + wlc_phy_stay_in_carriersearch_nphy(pi, false); + } + + wlapi_enable_mac(pi->sh->physhim); +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c new file mode 100644 index 000000000000..faf1ebe76068 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 "phy_qmath.h" + +/* + * Description: This function make 16 bit unsigned multiplication. + * To fit the output into 16 bits the 32 bit multiplication result is right + * shifted by 16 bits. + */ +u16 qm_mulu16(u16 op1, u16 op2) +{ + return (u16) (((u32) op1 * (u32) op2) >> 16); +} + +/* + * Description: This function make 16 bit multiplication and return the result + * in 16 bits. To fit the multiplication result into 16 bits the multiplication + * result is right shifted by 15 bits. Right shifting 15 bits instead of 16 bits + * is done to remove the extra sign bit formed due to the multiplication. + * When both the 16bit inputs are 0x8000 then the output is saturated to + * 0x7fffffff. + */ +s16 qm_muls16(s16 op1, s16 op2) +{ + s32 result; + if (op1 == (s16) 0x8000 && op2 == (s16) 0x8000) + result = 0x7fffffff; + else + result = ((s32) (op1) * (s32) (op2)); + + return (s16) (result >> 15); +} + +/* + * Description: This function add two 32 bit numbers and return the 32bit + * result. If the result overflow 32 bits, the output will be saturated to + * 32bits. + */ +s32 qm_add32(s32 op1, s32 op2) +{ + s32 result; + result = op1 + op2; + if (op1 < 0 && op2 < 0 && result > 0) + result = 0x80000000; + else if (op1 > 0 && op2 > 0 && result < 0) + result = 0x7fffffff; + + return result; +} + +/* + * Description: This function add two 16 bit numbers and return the 16bit + * result. If the result overflow 16 bits, the output will be saturated to + * 16bits. + */ +s16 qm_add16(s16 op1, s16 op2) +{ + s16 result; + s32 temp = (s32) op1 + (s32) op2; + if (temp > (s32) 0x7fff) + result = (s16) 0x7fff; + else if (temp < (s32) 0xffff8000) + result = (s16) 0xffff8000; + else + result = (s16) temp; + + return result; +} + +/* + * Description: This function make 16 bit subtraction and return the 16bit + * result. If the result overflow 16 bits, the output will be saturated to + * 16bits. + */ +s16 qm_sub16(s16 op1, s16 op2) +{ + s16 result; + s32 temp = (s32) op1 - (s32) op2; + if (temp > (s32) 0x7fff) + result = (s16) 0x7fff; + else if (temp < (s32) 0xffff8000) + result = (s16) 0xffff8000; + else + result = (s16) temp; + + return result; +} + +/* + * Description: This function make a 32 bit saturated left shift when the + * specified shift is +ve. This function will make a 32 bit right shift when + * the specified shift is -ve. This function return the result after shifting + * operation. + */ +s32 qm_shl32(s32 op, int shift) +{ + int i; + s32 result; + result = op; + if (shift > 31) + shift = 31; + else if (shift < -31) + shift = -31; + if (shift >= 0) { + for (i = 0; i < shift; i++) + result = qm_add32(result, result); + } else { + result = result >> (-shift); + } + + return result; +} + +/* + * Description: This function make a 16 bit saturated left shift when the + * specified shift is +ve. This function will make a 16 bit right shift when + * the specified shift is -ve. This function return the result after shifting + * operation. + */ +s16 qm_shl16(s16 op, int shift) +{ + int i; + s16 result; + result = op; + if (shift > 15) + shift = 15; + else if (shift < -15) + shift = -15; + if (shift > 0) { + for (i = 0; i < shift; i++) + result = qm_add16(result, result); + } else { + result = result >> (-shift); + } + + return result; +} + +/* + * Description: This function make a 16 bit right shift when shift is +ve. + * This function make a 16 bit saturated left shift when shift is -ve. This + * function return the result of the shift operation. + */ +s16 qm_shr16(s16 op, int shift) +{ + return qm_shl16(op, -shift); +} + +/* + * Description: This function return the number of redundant sign bits in a + * 32 bit number. Example: qm_norm32(0x00000080) = 23 + */ +s16 qm_norm32(s32 op) +{ + u16 u16extraSignBits; + if (op == 0) { + return 31; + } else { + u16extraSignBits = 0; + while ((op >> 31) == (op >> 30)) { + u16extraSignBits++; + op = op << 1; + } + } + return u16extraSignBits; +} + +/* This table is log2(1+(i/32)) where i=[0:1:31], in q.15 format */ +static const s16 log_table[] = { + 0, + 1455, + 2866, + 4236, + 5568, + 6863, + 8124, + 9352, + 10549, + 11716, + 12855, + 13968, + 15055, + 16117, + 17156, + 18173, + 19168, + 20143, + 21098, + 22034, + 22952, + 23852, + 24736, + 25604, + 26455, + 27292, + 28114, + 28922, + 29717, + 30498, + 31267, + 32024 +}; + +#define LOG_TABLE_SIZE 32 /* log_table size */ +#define LOG2_LOG_TABLE_SIZE 5 /* log2(log_table size) */ +#define Q_LOG_TABLE 15 /* qformat of log_table */ +#define LOG10_2 19728 /* log10(2) in q.16 */ + +/* + * Description: + * This routine takes the input number N and its q format qN and compute + * the log10(N). This routine first normalizes the input no N. Then N is in + * mag*(2^x) format. mag is any number in the range 2^30-(2^31 - 1). + * Then log2(mag * 2^x) = log2(mag) + x is computed. From that + * log10(mag * 2^x) = log2(mag * 2^x) * log10(2) is computed. + * This routine looks the log2 value in the table considering + * LOG2_LOG_TABLE_SIZE+1 MSBs. As the MSB is always 1, only next + * LOG2_OF_LOG_TABLE_SIZE MSBs are used for table lookup. Next 16 MSBs are used + * for interpolation. + * Inputs: + * N - number to which log10 has to be found. + * qN - q format of N + * log10N - address where log10(N) will be written. + * qLog10N - address where log10N qformat will be written. + * Note/Problem: + * For accurate results input should be in normalized or near normalized form. + */ +void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N) +{ + s16 s16norm, s16tableIndex, s16errorApproximation; + u16 u16offset; + s32 s32log; + + /* normalize the N. */ + s16norm = qm_norm32(N); + N = N << s16norm; + + /* The qformat of N after normalization. + * -30 is added to treat the no as between 1.0 to 2.0 + * i.e. after adding the -30 to the qformat the decimal point will be + * just rigtht of the MSB. (i.e. after sign bit and 1st MSB). i.e. + * at the right side of 30th bit. + */ + qN = qN + s16norm - 30; + + /* take the table index as the LOG2_OF_LOG_TABLE_SIZE bits right of the + * MSB */ + s16tableIndex = (s16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE))); + + /* remove the MSB. the MSB is always 1 after normalization. */ + s16tableIndex = + s16tableIndex & (s16) ((1 << LOG2_LOG_TABLE_SIZE) - 1); + + /* remove the (1+LOG2_OF_LOG_TABLE_SIZE) MSBs in the N. */ + N = N & ((1 << (32 - (2 + LOG2_LOG_TABLE_SIZE))) - 1); + + /* take the offset as the 16 MSBS after table index. + */ + u16offset = (u16) (N >> (32 - (2 + LOG2_LOG_TABLE_SIZE + 16))); + + /* look the log value in the table. */ + s32log = log_table[s16tableIndex]; /* q.15 format */ + + /* interpolate using the offset. q.15 format. */ + s16errorApproximation = (s16) qm_mulu16(u16offset, + (u16) (log_table[s16tableIndex + 1] - + log_table[s16tableIndex])); + + /* q.15 format */ + s32log = qm_add16((s16) s32log, s16errorApproximation); + + /* adjust for the qformat of the N as + * log2(mag * 2^x) = log2(mag) + x + */ + s32log = qm_add32(s32log, ((s32) -qN) << 15); /* q.15 format */ + + /* normalize the result. */ + s16norm = qm_norm32(s32log); + + /* bring all the important bits into lower 16 bits */ + /* q.15+s16norm-16 format */ + s32log = qm_shl32(s32log, s16norm - 16); + + /* compute the log10(N) by multiplying log2(N) with log10(2). + * as log10(mag * 2^x) = log2(mag * 2^x) * log10(2) + * log10N in q.15+s16norm-16+1 (LOG10_2 is in q.16) + */ + *log10N = qm_muls16((s16) s32log, (s16) LOG10_2); + + /* write the q format of the result. */ + *qLog10N = 15 + s16norm - 16 + 1; + + return; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h new file mode 100644 index 000000000000..20e3783f921b --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_qmath.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_QMATH_H_ +#define _BRCM_QMATH_H_ + +#include <types.h> + +u16 qm_mulu16(u16 op1, u16 op2); + +s16 qm_muls16(s16 op1, s16 op2); + +s32 qm_add32(s32 op1, s32 op2); + +s16 qm_add16(s16 op1, s16 op2); + +s16 qm_sub16(s16 op1, s16 op2); + +s32 qm_shl32(s32 op, int shift); + +s16 qm_shl16(s16 op, int shift); + +s16 qm_shr16(s16 op, int shift); + +s16 qm_norm32(s32 op); + +void qm_log10(s32 N, s16 qN, s16 *log10N, s16 *qLog10N); + +#endif /* #ifndef _BRCM_QMATH_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h new file mode 100644 index 000000000000..c3a675455ff5 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_radio.h @@ -0,0 +1,1533 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_PHY_RADIO_H_ +#define _BRCM_PHY_RADIO_H_ + +#define RADIO_IDCODE 0x01 + +#define RADIO_DEFAULT_CORE 0 + +#define RXC0_RSSI_RST 0x80 +#define RXC0_MODE_RSSI 0x40 +#define RXC0_MODE_OFF 0x20 +#define RXC0_MODE_CM 0x10 +#define RXC0_LAN_LOAD 0x08 +#define RXC0_OFF_ADJ_MASK 0x07 + +#define TXC0_MODE_TXLPF 0x04 +#define TXC0_PA_TSSI_EN 0x02 +#define TXC0_TSSI_EN 0x01 + +#define TXC1_PA_GAIN_MASK 0x60 +#define TXC1_PA_GAIN_3DB 0x40 +#define TXC1_PA_GAIN_2DB 0x20 +#define TXC1_TX_MIX_GAIN 0x10 +#define TXC1_OFF_I_MASK 0x0c +#define TXC1_OFF_Q_MASK 0x03 + +#define RADIO_2055_READ_OFF 0x100 +#define RADIO_2057_READ_OFF 0x200 + +#define RADIO_2055_GEN_SPARE 0x00 +#define RADIO_2055_SP_PIN_PD 0x02 +#define RADIO_2055_SP_RSSI_CORE1 0x03 +#define RADIO_2055_SP_PD_MISC_CORE1 0x04 +#define RADIO_2055_SP_RSSI_CORE2 0x05 +#define RADIO_2055_SP_PD_MISC_CORE2 0x06 +#define RADIO_2055_SP_RX_GC1_CORE1 0x07 +#define RADIO_2055_SP_RX_GC2_CORE1 0x08 +#define RADIO_2055_SP_RX_GC1_CORE2 0x09 +#define RADIO_2055_SP_RX_GC2_CORE2 0x0a +#define RADIO_2055_SP_LPF_BW_SELECT_CORE1 0x0b +#define RADIO_2055_SP_LPF_BW_SELECT_CORE2 0x0c +#define RADIO_2055_SP_TX_GC1_CORE1 0x0d +#define RADIO_2055_SP_TX_GC2_CORE1 0x0e +#define RADIO_2055_SP_TX_GC1_CORE2 0x0f +#define RADIO_2055_SP_TX_GC2_CORE2 0x10 +#define RADIO_2055_MASTER_CNTRL1 0x11 +#define RADIO_2055_MASTER_CNTRL2 0x12 +#define RADIO_2055_PD_LGEN 0x13 +#define RADIO_2055_PD_PLL_TS 0x14 +#define RADIO_2055_PD_CORE1_LGBUF 0x15 +#define RADIO_2055_PD_CORE1_TX 0x16 +#define RADIO_2055_PD_CORE1_RXTX 0x17 +#define RADIO_2055_PD_CORE1_RSSI_MISC 0x18 +#define RADIO_2055_PD_CORE2_LGBUF 0x19 +#define RADIO_2055_PD_CORE2_TX 0x1a +#define RADIO_2055_PD_CORE2_RXTX 0x1b +#define RADIO_2055_PD_CORE2_RSSI_MISC 0x1c +#define RADIO_2055_PWRDET_LGEN 0x1d +#define RADIO_2055_PWRDET_LGBUF_CORE1 0x1e +#define RADIO_2055_PWRDET_RXTX_CORE1 0x1f +#define RADIO_2055_PWRDET_LGBUF_CORE2 0x20 +#define RADIO_2055_PWRDET_RXTX_CORE2 0x21 +#define RADIO_2055_RRCCAL_CNTRL_SPARE 0x22 +#define RADIO_2055_RRCCAL_N_OPT_SEL 0x23 +#define RADIO_2055_CAL_MISC 0x24 +#define RADIO_2055_CAL_COUNTER_OUT 0x25 +#define RADIO_2055_CAL_COUNTER_OUT2 0x26 +#define RADIO_2055_CAL_CVAR_CNTRL 0x27 +#define RADIO_2055_CAL_RVAR_CNTRL 0x28 +#define RADIO_2055_CAL_LPO_CNTRL 0x29 +#define RADIO_2055_CAL_TS 0x2a +#define RADIO_2055_CAL_RCCAL_READ_TS 0x2b +#define RADIO_2055_CAL_RCAL_READ_TS 0x2c +#define RADIO_2055_PAD_DRIVER 0x2d +#define RADIO_2055_XO_CNTRL1 0x2e +#define RADIO_2055_XO_CNTRL2 0x2f +#define RADIO_2055_XO_REGULATOR 0x30 +#define RADIO_2055_XO_MISC 0x31 +#define RADIO_2055_PLL_LF_C1 0x32 +#define RADIO_2055_PLL_CAL_VTH 0x33 +#define RADIO_2055_PLL_LF_C2 0x34 +#define RADIO_2055_PLL_REF 0x35 +#define RADIO_2055_PLL_LF_R1 0x36 +#define RADIO_2055_PLL_PFD_CP 0x37 +#define RADIO_2055_PLL_IDAC_CPOPAMP 0x38 +#define RADIO_2055_PLL_CP_REGULATOR 0x39 +#define RADIO_2055_PLL_RCAL 0x3a +#define RADIO_2055_RF_PLL_MOD0 0x3b +#define RADIO_2055_RF_PLL_MOD1 0x3c +#define RADIO_2055_RF_MMD_IDAC1 0x3d +#define RADIO_2055_RF_MMD_IDAC0 0x3e +#define RADIO_2055_RF_MMD_SPARE 0x3f +#define RADIO_2055_VCO_CAL1 0x40 +#define RADIO_2055_VCO_CAL2 0x41 +#define RADIO_2055_VCO_CAL3 0x42 +#define RADIO_2055_VCO_CAL4 0x43 +#define RADIO_2055_VCO_CAL5 0x44 +#define RADIO_2055_VCO_CAL6 0x45 +#define RADIO_2055_VCO_CAL7 0x46 +#define RADIO_2055_VCO_CAL8 0x47 +#define RADIO_2055_VCO_CAL9 0x48 +#define RADIO_2055_VCO_CAL10 0x49 +#define RADIO_2055_VCO_CAL11 0x4a +#define RADIO_2055_VCO_CAL12 0x4b +#define RADIO_2055_VCO_CAL13 0x4c +#define RADIO_2055_VCO_CAL14 0x4d +#define RADIO_2055_VCO_CAL15 0x4e +#define RADIO_2055_VCO_CAL16 0x4f +#define RADIO_2055_VCO_KVCO 0x50 +#define RADIO_2055_VCO_CAP_TAIL 0x51 +#define RADIO_2055_VCO_IDAC_VCO 0x52 +#define RADIO_2055_VCO_REGULATOR 0x53 +#define RADIO_2055_PLL_RF_VTH 0x54 +#define RADIO_2055_LGBUF_CEN_BUF 0x55 +#define RADIO_2055_LGEN_TUNE1 0x56 +#define RADIO_2055_LGEN_TUNE2 0x57 +#define RADIO_2055_LGEN_IDAC1 0x58 +#define RADIO_2055_LGEN_IDAC2 0x59 +#define RADIO_2055_LGEN_BIAS_CNT 0x5a +#define RADIO_2055_LGEN_BIAS_IDAC 0x5b +#define RADIO_2055_LGEN_RCAL 0x5c +#define RADIO_2055_LGEN_DIV 0x5d +#define RADIO_2055_LGEN_SPARE2 0x5e +#define RADIO_2055_CORE1_LGBUF_A_TUNE 0x5f +#define RADIO_2055_CORE1_LGBUF_G_TUNE 0x60 +#define RADIO_2055_CORE1_LGBUF_DIV 0x61 +#define RADIO_2055_CORE1_LGBUF_A_IDAC 0x62 +#define RADIO_2055_CORE1_LGBUF_G_IDAC 0x63 +#define RADIO_2055_CORE1_LGBUF_IDACFIL_OVR 0x64 +#define RADIO_2055_CORE1_LGBUF_SPARE 0x65 +#define RADIO_2055_CORE1_RXRF_SPC1 0x66 +#define RADIO_2055_CORE1_RXRF_REG1 0x67 +#define RADIO_2055_CORE1_RXRF_REG2 0x68 +#define RADIO_2055_CORE1_RXRF_RCAL 0x69 +#define RADIO_2055_CORE1_RXBB_BUFI_LPFCMP 0x6a +#define RADIO_2055_CORE1_RXBB_LPF 0x6b +#define RADIO_2055_CORE1_RXBB_MIDAC_HIPAS 0x6c +#define RADIO_2055_CORE1_RXBB_VGA1_IDAC 0x6d +#define RADIO_2055_CORE1_RXBB_VGA2_IDAC 0x6e +#define RADIO_2055_CORE1_RXBB_VGA3_IDAC 0x6f +#define RADIO_2055_CORE1_RXBB_BUFO_CTRL 0x70 +#define RADIO_2055_CORE1_RXBB_RCCAL_CTRL 0x71 +#define RADIO_2055_CORE1_RXBB_RSSI_CTRL1 0x72 +#define RADIO_2055_CORE1_RXBB_RSSI_CTRL2 0x73 +#define RADIO_2055_CORE1_RXBB_RSSI_CTRL3 0x74 +#define RADIO_2055_CORE1_RXBB_RSSI_CTRL4 0x75 +#define RADIO_2055_CORE1_RXBB_RSSI_CTRL5 0x76 +#define RADIO_2055_CORE1_RXBB_REGULATOR 0x77 +#define RADIO_2055_CORE1_RXBB_SPARE1 0x78 +#define RADIO_2055_CORE1_RXTXBB_RCAL 0x79 +#define RADIO_2055_CORE1_TXRF_SGM_PGA 0x7a +#define RADIO_2055_CORE1_TXRF_SGM_PAD 0x7b +#define RADIO_2055_CORE1_TXRF_CNTR_PGA1 0x7c +#define RADIO_2055_CORE1_TXRF_CNTR_PAD1 0x7d +#define RADIO_2055_CORE1_TX_RFPGA_IDAC 0x7e +#define RADIO_2055_CORE1_TX_PGA_PAD_TN 0x7f +#define RADIO_2055_CORE1_TX_PAD_IDAC1 0x80 +#define RADIO_2055_CORE1_TX_PAD_IDAC2 0x81 +#define RADIO_2055_CORE1_TX_MX_BGTRIM 0x82 +#define RADIO_2055_CORE1_TXRF_RCAL 0x83 +#define RADIO_2055_CORE1_TXRF_PAD_TSSI1 0x84 +#define RADIO_2055_CORE1_TXRF_PAD_TSSI2 0x85 +#define RADIO_2055_CORE1_TX_RF_SPARE 0x86 +#define RADIO_2055_CORE1_TXRF_IQCAL1 0x87 +#define RADIO_2055_CORE1_TXRF_IQCAL2 0x88 +#define RADIO_2055_CORE1_TXBB_RCCAL_CTRL 0x89 +#define RADIO_2055_CORE1_TXBB_LPF1 0x8a +#define RADIO_2055_CORE1_TX_VOS_CNCL 0x8b +#define RADIO_2055_CORE1_TX_LPF_MXGM_IDAC 0x8c +#define RADIO_2055_CORE1_TX_BB_MXGM 0x8d +#define RADIO_2055_CORE2_LGBUF_A_TUNE 0x8e +#define RADIO_2055_CORE2_LGBUF_G_TUNE 0x8f +#define RADIO_2055_CORE2_LGBUF_DIV 0x90 +#define RADIO_2055_CORE2_LGBUF_A_IDAC 0x91 +#define RADIO_2055_CORE2_LGBUF_G_IDAC 0x92 +#define RADIO_2055_CORE2_LGBUF_IDACFIL_OVR 0x93 +#define RADIO_2055_CORE2_LGBUF_SPARE 0x94 +#define RADIO_2055_CORE2_RXRF_SPC1 0x95 +#define RADIO_2055_CORE2_RXRF_REG1 0x96 +#define RADIO_2055_CORE2_RXRF_REG2 0x97 +#define RADIO_2055_CORE2_RXRF_RCAL 0x98 +#define RADIO_2055_CORE2_RXBB_BUFI_LPFCMP 0x99 +#define RADIO_2055_CORE2_RXBB_LPF 0x9a +#define RADIO_2055_CORE2_RXBB_MIDAC_HIPAS 0x9b +#define RADIO_2055_CORE2_RXBB_VGA1_IDAC 0x9c +#define RADIO_2055_CORE2_RXBB_VGA2_IDAC 0x9d +#define RADIO_2055_CORE2_RXBB_VGA3_IDAC 0x9e +#define RADIO_2055_CORE2_RXBB_BUFO_CTRL 0x9f +#define RADIO_2055_CORE2_RXBB_RCCAL_CTRL 0xa0 +#define RADIO_2055_CORE2_RXBB_RSSI_CTRL1 0xa1 +#define RADIO_2055_CORE2_RXBB_RSSI_CTRL2 0xa2 +#define RADIO_2055_CORE2_RXBB_RSSI_CTRL3 0xa3 +#define RADIO_2055_CORE2_RXBB_RSSI_CTRL4 0xa4 +#define RADIO_2055_CORE2_RXBB_RSSI_CTRL5 0xa5 +#define RADIO_2055_CORE2_RXBB_REGULATOR 0xa6 +#define RADIO_2055_CORE2_RXBB_SPARE1 0xa7 +#define RADIO_2055_CORE2_RXTXBB_RCAL 0xa8 +#define RADIO_2055_CORE2_TXRF_SGM_PGA 0xa9 +#define RADIO_2055_CORE2_TXRF_SGM_PAD 0xaa +#define RADIO_2055_CORE2_TXRF_CNTR_PGA1 0xab +#define RADIO_2055_CORE2_TXRF_CNTR_PAD1 0xac +#define RADIO_2055_CORE2_TX_RFPGA_IDAC 0xad +#define RADIO_2055_CORE2_TX_PGA_PAD_TN 0xae +#define RADIO_2055_CORE2_TX_PAD_IDAC1 0xaf +#define RADIO_2055_CORE2_TX_PAD_IDAC2 0xb0 +#define RADIO_2055_CORE2_TX_MX_BGTRIM 0xb1 +#define RADIO_2055_CORE2_TXRF_RCAL 0xb2 +#define RADIO_2055_CORE2_TXRF_PAD_TSSI1 0xb3 +#define RADIO_2055_CORE2_TXRF_PAD_TSSI2 0xb4 +#define RADIO_2055_CORE2_TX_RF_SPARE 0xb5 +#define RADIO_2055_CORE2_TXRF_IQCAL1 0xb6 +#define RADIO_2055_CORE2_TXRF_IQCAL2 0xb7 +#define RADIO_2055_CORE2_TXBB_RCCAL_CTRL 0xb8 +#define RADIO_2055_CORE2_TXBB_LPF1 0xb9 +#define RADIO_2055_CORE2_TX_VOS_CNCL 0xba +#define RADIO_2055_CORE2_TX_LPF_MXGM_IDAC 0xbb +#define RADIO_2055_CORE2_TX_BB_MXGM 0xbc +#define RADIO_2055_PRG_GC_HPVGA23_21 0xbd +#define RADIO_2055_PRG_GC_HPVGA23_22 0xbe +#define RADIO_2055_PRG_GC_HPVGA23_23 0xbf +#define RADIO_2055_PRG_GC_HPVGA23_24 0xc0 +#define RADIO_2055_PRG_GC_HPVGA23_25 0xc1 +#define RADIO_2055_PRG_GC_HPVGA23_26 0xc2 +#define RADIO_2055_PRG_GC_HPVGA23_27 0xc3 +#define RADIO_2055_PRG_GC_HPVGA23_28 0xc4 +#define RADIO_2055_PRG_GC_HPVGA23_29 0xc5 +#define RADIO_2055_PRG_GC_HPVGA23_30 0xc6 +#define RADIO_2055_CORE1_LNA_GAINBST 0xcd +#define RADIO_2055_CORE1_B0_NBRSSI_VCM 0xd2 +#define RADIO_2055_CORE1_GEN_SPARE2 0xd6 +#define RADIO_2055_CORE2_LNA_GAINBST 0xd9 +#define RADIO_2055_CORE2_B0_NBRSSI_VCM 0xde +#define RADIO_2055_CORE2_GEN_SPARE2 0xe2 + +#define RADIO_2055_GAINBST_GAIN_DB 6 +#define RADIO_2055_GAINBST_CODE 0x6 + +#define RADIO_2055_JTAGCTRL_MASK 0x04 +#define RADIO_2055_JTAGSYNC_MASK 0x08 +#define RADIO_2055_RRCAL_START 0x40 +#define RADIO_2055_RRCAL_RST_N 0x01 +#define RADIO_2055_CAL_LPO_ENABLE 0x80 +#define RADIO_2055_RCAL_DONE 0x80 +#define RADIO_2055_NBRSSI_VCM_I_MASK 0x03 +#define RADIO_2055_NBRSSI_VCM_I_SHIFT 0x00 +#define RADIO_2055_NBRSSI_VCM_Q_MASK 0x03 +#define RADIO_2055_NBRSSI_VCM_Q_SHIFT 0x00 +#define RADIO_2055_WBRSSI_VCM_IQ_MASK 0x0c +#define RADIO_2055_WBRSSI_VCM_IQ_SHIFT 0x02 +#define RADIO_2055_NBRSSI_PD 0x01 +#define RADIO_2055_WBRSSI_G1_PD 0x04 +#define RADIO_2055_WBRSSI_G2_PD 0x02 +#define RADIO_2055_NBRSSI_SEL 0x01 +#define RADIO_2055_WBRSSI_G1_SEL 0x04 +#define RADIO_2055_WBRSSI_G2_SEL 0x02 +#define RADIO_2055_COUPLE_RX_MASK 0x01 +#define RADIO_2055_COUPLE_TX_MASK 0x02 +#define RADIO_2055_GAINBST_DISABLE 0x02 +#define RADIO_2055_GAINBST_VAL_MASK 0x07 +#define RADIO_2055_RXMX_GC_MASK 0x0c + +#define RADIO_MIMO_CORESEL_OFF 0x0 +#define RADIO_MIMO_CORESEL_CORE1 0x1 +#define RADIO_MIMO_CORESEL_CORE2 0x2 +#define RADIO_MIMO_CORESEL_CORE3 0x3 +#define RADIO_MIMO_CORESEL_CORE4 0x4 +#define RADIO_MIMO_CORESEL_ALLRX 0x5 +#define RADIO_MIMO_CORESEL_ALLTX 0x6 +#define RADIO_MIMO_CORESEL_ALLRXTX 0x7 + +#define RADIO_2064_READ_OFF 0x200 + +#define RADIO_2064_REG000 0x0 +#define RADIO_2064_REG001 0x1 +#define RADIO_2064_REG002 0x2 +#define RADIO_2064_REG003 0x3 +#define RADIO_2064_REG004 0x4 +#define RADIO_2064_REG005 0x5 +#define RADIO_2064_REG006 0x6 +#define RADIO_2064_REG007 0x7 +#define RADIO_2064_REG008 0x8 +#define RADIO_2064_REG009 0x9 +#define RADIO_2064_REG00A 0xa +#define RADIO_2064_REG00B 0xb +#define RADIO_2064_REG00C 0xc +#define RADIO_2064_REG00D 0xd +#define RADIO_2064_REG00E 0xe +#define RADIO_2064_REG00F 0xf +#define RADIO_2064_REG010 0x10 +#define RADIO_2064_REG011 0x11 +#define RADIO_2064_REG012 0x12 +#define RADIO_2064_REG013 0x13 +#define RADIO_2064_REG014 0x14 +#define RADIO_2064_REG015 0x15 +#define RADIO_2064_REG016 0x16 +#define RADIO_2064_REG017 0x17 +#define RADIO_2064_REG018 0x18 +#define RADIO_2064_REG019 0x19 +#define RADIO_2064_REG01A 0x1a +#define RADIO_2064_REG01B 0x1b +#define RADIO_2064_REG01C 0x1c +#define RADIO_2064_REG01D 0x1d +#define RADIO_2064_REG01E 0x1e +#define RADIO_2064_REG01F 0x1f +#define RADIO_2064_REG020 0x20 +#define RADIO_2064_REG021 0x21 +#define RADIO_2064_REG022 0x22 +#define RADIO_2064_REG023 0x23 +#define RADIO_2064_REG024 0x24 +#define RADIO_2064_REG025 0x25 +#define RADIO_2064_REG026 0x26 +#define RADIO_2064_REG027 0x27 +#define RADIO_2064_REG028 0x28 +#define RADIO_2064_REG029 0x29 +#define RADIO_2064_REG02A 0x2a +#define RADIO_2064_REG02B 0x2b +#define RADIO_2064_REG02C 0x2c +#define RADIO_2064_REG02D 0x2d +#define RADIO_2064_REG02E 0x2e +#define RADIO_2064_REG02F 0x2f +#define RADIO_2064_REG030 0x30 +#define RADIO_2064_REG031 0x31 +#define RADIO_2064_REG032 0x32 +#define RADIO_2064_REG033 0x33 +#define RADIO_2064_REG034 0x34 +#define RADIO_2064_REG035 0x35 +#define RADIO_2064_REG036 0x36 +#define RADIO_2064_REG037 0x37 +#define RADIO_2064_REG038 0x38 +#define RADIO_2064_REG039 0x39 +#define RADIO_2064_REG03A 0x3a +#define RADIO_2064_REG03B 0x3b +#define RADIO_2064_REG03C 0x3c +#define RADIO_2064_REG03D 0x3d +#define RADIO_2064_REG03E 0x3e +#define RADIO_2064_REG03F 0x3f +#define RADIO_2064_REG040 0x40 +#define RADIO_2064_REG041 0x41 +#define RADIO_2064_REG042 0x42 +#define RADIO_2064_REG043 0x43 +#define RADIO_2064_REG044 0x44 +#define RADIO_2064_REG045 0x45 +#define RADIO_2064_REG046 0x46 +#define RADIO_2064_REG047 0x47 +#define RADIO_2064_REG048 0x48 +#define RADIO_2064_REG049 0x49 +#define RADIO_2064_REG04A 0x4a +#define RADIO_2064_REG04B 0x4b +#define RADIO_2064_REG04C 0x4c +#define RADIO_2064_REG04D 0x4d +#define RADIO_2064_REG04E 0x4e +#define RADIO_2064_REG04F 0x4f +#define RADIO_2064_REG050 0x50 +#define RADIO_2064_REG051 0x51 +#define RADIO_2064_REG052 0x52 +#define RADIO_2064_REG053 0x53 +#define RADIO_2064_REG054 0x54 +#define RADIO_2064_REG055 0x55 +#define RADIO_2064_REG056 0x56 +#define RADIO_2064_REG057 0x57 +#define RADIO_2064_REG058 0x58 +#define RADIO_2064_REG059 0x59 +#define RADIO_2064_REG05A 0x5a +#define RADIO_2064_REG05B 0x5b +#define RADIO_2064_REG05C 0x5c +#define RADIO_2064_REG05D 0x5d +#define RADIO_2064_REG05E 0x5e +#define RADIO_2064_REG05F 0x5f +#define RADIO_2064_REG060 0x60 +#define RADIO_2064_REG061 0x61 +#define RADIO_2064_REG062 0x62 +#define RADIO_2064_REG063 0x63 +#define RADIO_2064_REG064 0x64 +#define RADIO_2064_REG065 0x65 +#define RADIO_2064_REG066 0x66 +#define RADIO_2064_REG067 0x67 +#define RADIO_2064_REG068 0x68 +#define RADIO_2064_REG069 0x69 +#define RADIO_2064_REG06A 0x6a +#define RADIO_2064_REG06B 0x6b +#define RADIO_2064_REG06C 0x6c +#define RADIO_2064_REG06D 0x6d +#define RADIO_2064_REG06E 0x6e +#define RADIO_2064_REG06F 0x6f +#define RADIO_2064_REG070 0x70 +#define RADIO_2064_REG071 0x71 +#define RADIO_2064_REG072 0x72 +#define RADIO_2064_REG073 0x73 +#define RADIO_2064_REG074 0x74 +#define RADIO_2064_REG075 0x75 +#define RADIO_2064_REG076 0x76 +#define RADIO_2064_REG077 0x77 +#define RADIO_2064_REG078 0x78 +#define RADIO_2064_REG079 0x79 +#define RADIO_2064_REG07A 0x7a +#define RADIO_2064_REG07B 0x7b +#define RADIO_2064_REG07C 0x7c +#define RADIO_2064_REG07D 0x7d +#define RADIO_2064_REG07E 0x7e +#define RADIO_2064_REG07F 0x7f +#define RADIO_2064_REG080 0x80 +#define RADIO_2064_REG081 0x81 +#define RADIO_2064_REG082 0x82 +#define RADIO_2064_REG083 0x83 +#define RADIO_2064_REG084 0x84 +#define RADIO_2064_REG085 0x85 +#define RADIO_2064_REG086 0x86 +#define RADIO_2064_REG087 0x87 +#define RADIO_2064_REG088 0x88 +#define RADIO_2064_REG089 0x89 +#define RADIO_2064_REG08A 0x8a +#define RADIO_2064_REG08B 0x8b +#define RADIO_2064_REG08C 0x8c +#define RADIO_2064_REG08D 0x8d +#define RADIO_2064_REG08E 0x8e +#define RADIO_2064_REG08F 0x8f +#define RADIO_2064_REG090 0x90 +#define RADIO_2064_REG091 0x91 +#define RADIO_2064_REG092 0x92 +#define RADIO_2064_REG093 0x93 +#define RADIO_2064_REG094 0x94 +#define RADIO_2064_REG095 0x95 +#define RADIO_2064_REG096 0x96 +#define RADIO_2064_REG097 0x97 +#define RADIO_2064_REG098 0x98 +#define RADIO_2064_REG099 0x99 +#define RADIO_2064_REG09A 0x9a +#define RADIO_2064_REG09B 0x9b +#define RADIO_2064_REG09C 0x9c +#define RADIO_2064_REG09D 0x9d +#define RADIO_2064_REG09E 0x9e +#define RADIO_2064_REG09F 0x9f +#define RADIO_2064_REG0A0 0xa0 +#define RADIO_2064_REG0A1 0xa1 +#define RADIO_2064_REG0A2 0xa2 +#define RADIO_2064_REG0A3 0xa3 +#define RADIO_2064_REG0A4 0xa4 +#define RADIO_2064_REG0A5 0xa5 +#define RADIO_2064_REG0A6 0xa6 +#define RADIO_2064_REG0A7 0xa7 +#define RADIO_2064_REG0A8 0xa8 +#define RADIO_2064_REG0A9 0xa9 +#define RADIO_2064_REG0AA 0xaa +#define RADIO_2064_REG0AB 0xab +#define RADIO_2064_REG0AC 0xac +#define RADIO_2064_REG0AD 0xad +#define RADIO_2064_REG0AE 0xae +#define RADIO_2064_REG0AF 0xaf +#define RADIO_2064_REG0B0 0xb0 +#define RADIO_2064_REG0B1 0xb1 +#define RADIO_2064_REG0B2 0xb2 +#define RADIO_2064_REG0B3 0xb3 +#define RADIO_2064_REG0B4 0xb4 +#define RADIO_2064_REG0B5 0xb5 +#define RADIO_2064_REG0B6 0xb6 +#define RADIO_2064_REG0B7 0xb7 +#define RADIO_2064_REG0B8 0xb8 +#define RADIO_2064_REG0B9 0xb9 +#define RADIO_2064_REG0BA 0xba +#define RADIO_2064_REG0BB 0xbb +#define RADIO_2064_REG0BC 0xbc +#define RADIO_2064_REG0BD 0xbd +#define RADIO_2064_REG0BE 0xbe +#define RADIO_2064_REG0BF 0xbf +#define RADIO_2064_REG0C0 0xc0 +#define RADIO_2064_REG0C1 0xc1 +#define RADIO_2064_REG0C2 0xc2 +#define RADIO_2064_REG0C3 0xc3 +#define RADIO_2064_REG0C4 0xc4 +#define RADIO_2064_REG0C5 0xc5 +#define RADIO_2064_REG0C6 0xc6 +#define RADIO_2064_REG0C7 0xc7 +#define RADIO_2064_REG0C8 0xc8 +#define RADIO_2064_REG0C9 0xc9 +#define RADIO_2064_REG0CA 0xca +#define RADIO_2064_REG0CB 0xcb +#define RADIO_2064_REG0CC 0xcc +#define RADIO_2064_REG0CD 0xcd +#define RADIO_2064_REG0CE 0xce +#define RADIO_2064_REG0CF 0xcf +#define RADIO_2064_REG0D0 0xd0 +#define RADIO_2064_REG0D1 0xd1 +#define RADIO_2064_REG0D2 0xd2 +#define RADIO_2064_REG0D3 0xd3 +#define RADIO_2064_REG0D4 0xd4 +#define RADIO_2064_REG0D5 0xd5 +#define RADIO_2064_REG0D6 0xd6 +#define RADIO_2064_REG0D7 0xd7 +#define RADIO_2064_REG0D8 0xd8 +#define RADIO_2064_REG0D9 0xd9 +#define RADIO_2064_REG0DA 0xda +#define RADIO_2064_REG0DB 0xdb +#define RADIO_2064_REG0DC 0xdc +#define RADIO_2064_REG0DD 0xdd +#define RADIO_2064_REG0DE 0xde +#define RADIO_2064_REG0DF 0xdf +#define RADIO_2064_REG0E0 0xe0 +#define RADIO_2064_REG0E1 0xe1 +#define RADIO_2064_REG0E2 0xe2 +#define RADIO_2064_REG0E3 0xe3 +#define RADIO_2064_REG0E4 0xe4 +#define RADIO_2064_REG0E5 0xe5 +#define RADIO_2064_REG0E6 0xe6 +#define RADIO_2064_REG0E7 0xe7 +#define RADIO_2064_REG0E8 0xe8 +#define RADIO_2064_REG0E9 0xe9 +#define RADIO_2064_REG0EA 0xea +#define RADIO_2064_REG0EB 0xeb +#define RADIO_2064_REG0EC 0xec +#define RADIO_2064_REG0ED 0xed +#define RADIO_2064_REG0EE 0xee +#define RADIO_2064_REG0EF 0xef +#define RADIO_2064_REG0F0 0xf0 +#define RADIO_2064_REG0F1 0xf1 +#define RADIO_2064_REG0F2 0xf2 +#define RADIO_2064_REG0F3 0xf3 +#define RADIO_2064_REG0F4 0xf4 +#define RADIO_2064_REG0F5 0xf5 +#define RADIO_2064_REG0F6 0xf6 +#define RADIO_2064_REG0F7 0xf7 +#define RADIO_2064_REG0F8 0xf8 +#define RADIO_2064_REG0F9 0xf9 +#define RADIO_2064_REG0FA 0xfa +#define RADIO_2064_REG0FB 0xfb +#define RADIO_2064_REG0FC 0xfc +#define RADIO_2064_REG0FD 0xfd +#define RADIO_2064_REG0FE 0xfe +#define RADIO_2064_REG0FF 0xff +#define RADIO_2064_REG100 0x100 +#define RADIO_2064_REG101 0x101 +#define RADIO_2064_REG102 0x102 +#define RADIO_2064_REG103 0x103 +#define RADIO_2064_REG104 0x104 +#define RADIO_2064_REG105 0x105 +#define RADIO_2064_REG106 0x106 +#define RADIO_2064_REG107 0x107 +#define RADIO_2064_REG108 0x108 +#define RADIO_2064_REG109 0x109 +#define RADIO_2064_REG10A 0x10a +#define RADIO_2064_REG10B 0x10b +#define RADIO_2064_REG10C 0x10c +#define RADIO_2064_REG10D 0x10d +#define RADIO_2064_REG10E 0x10e +#define RADIO_2064_REG10F 0x10f +#define RADIO_2064_REG110 0x110 +#define RADIO_2064_REG111 0x111 +#define RADIO_2064_REG112 0x112 +#define RADIO_2064_REG113 0x113 +#define RADIO_2064_REG114 0x114 +#define RADIO_2064_REG115 0x115 +#define RADIO_2064_REG116 0x116 +#define RADIO_2064_REG117 0x117 +#define RADIO_2064_REG118 0x118 +#define RADIO_2064_REG119 0x119 +#define RADIO_2064_REG11A 0x11a +#define RADIO_2064_REG11B 0x11b +#define RADIO_2064_REG11C 0x11c +#define RADIO_2064_REG11D 0x11d +#define RADIO_2064_REG11E 0x11e +#define RADIO_2064_REG11F 0x11f +#define RADIO_2064_REG120 0x120 +#define RADIO_2064_REG121 0x121 +#define RADIO_2064_REG122 0x122 +#define RADIO_2064_REG123 0x123 +#define RADIO_2064_REG124 0x124 +#define RADIO_2064_REG125 0x125 +#define RADIO_2064_REG126 0x126 +#define RADIO_2064_REG127 0x127 +#define RADIO_2064_REG128 0x128 +#define RADIO_2064_REG129 0x129 +#define RADIO_2064_REG12A 0x12a +#define RADIO_2064_REG12B 0x12b +#define RADIO_2064_REG12C 0x12c +#define RADIO_2064_REG12D 0x12d +#define RADIO_2064_REG12E 0x12e +#define RADIO_2064_REG12F 0x12f +#define RADIO_2064_REG130 0x130 + +#define RADIO_2056_SYN (0x0 << 12) +#define RADIO_2056_TX0 (0x2 << 12) +#define RADIO_2056_TX1 (0x3 << 12) +#define RADIO_2056_RX0 (0x6 << 12) +#define RADIO_2056_RX1 (0x7 << 12) +#define RADIO_2056_ALLTX (0xe << 12) +#define RADIO_2056_ALLRX (0xf << 12) + +#define RADIO_2056_SYN_RESERVED_ADDR0 0x0 +#define RADIO_2056_SYN_IDCODE 0x1 +#define RADIO_2056_SYN_RESERVED_ADDR2 0x2 +#define RADIO_2056_SYN_RESERVED_ADDR3 0x3 +#define RADIO_2056_SYN_RESERVED_ADDR4 0x4 +#define RADIO_2056_SYN_RESERVED_ADDR5 0x5 +#define RADIO_2056_SYN_RESERVED_ADDR6 0x6 +#define RADIO_2056_SYN_RESERVED_ADDR7 0x7 +#define RADIO_2056_SYN_COM_CTRL 0x8 +#define RADIO_2056_SYN_COM_PU 0x9 +#define RADIO_2056_SYN_COM_OVR 0xa +#define RADIO_2056_SYN_COM_RESET 0xb +#define RADIO_2056_SYN_COM_RCAL 0xc +#define RADIO_2056_SYN_COM_RC_RXLPF 0xd +#define RADIO_2056_SYN_COM_RC_TXLPF 0xe +#define RADIO_2056_SYN_COM_RC_RXHPF 0xf +#define RADIO_2056_SYN_RESERVED_ADDR16 0x10 +#define RADIO_2056_SYN_RESERVED_ADDR17 0x11 +#define RADIO_2056_SYN_RESERVED_ADDR18 0x12 +#define RADIO_2056_SYN_RESERVED_ADDR19 0x13 +#define RADIO_2056_SYN_RESERVED_ADDR20 0x14 +#define RADIO_2056_SYN_RESERVED_ADDR21 0x15 +#define RADIO_2056_SYN_RESERVED_ADDR22 0x16 +#define RADIO_2056_SYN_RESERVED_ADDR23 0x17 +#define RADIO_2056_SYN_RESERVED_ADDR24 0x18 +#define RADIO_2056_SYN_RESERVED_ADDR25 0x19 +#define RADIO_2056_SYN_RESERVED_ADDR26 0x1a +#define RADIO_2056_SYN_RESERVED_ADDR27 0x1b +#define RADIO_2056_SYN_RESERVED_ADDR28 0x1c +#define RADIO_2056_SYN_RESERVED_ADDR29 0x1d +#define RADIO_2056_SYN_RESERVED_ADDR30 0x1e +#define RADIO_2056_SYN_RESERVED_ADDR31 0x1f +#define RADIO_2056_SYN_GPIO_MASTER1 0x20 +#define RADIO_2056_SYN_GPIO_MASTER2 0x21 +#define RADIO_2056_SYN_TOPBIAS_MASTER 0x22 +#define RADIO_2056_SYN_TOPBIAS_RCAL 0x23 +#define RADIO_2056_SYN_AFEREG 0x24 +#define RADIO_2056_SYN_TEMPPROCSENSE 0x25 +#define RADIO_2056_SYN_TEMPPROCSENSEIDAC 0x26 +#define RADIO_2056_SYN_TEMPPROCSENSERCAL 0x27 +#define RADIO_2056_SYN_LPO 0x28 +#define RADIO_2056_SYN_VDDCAL_MASTER 0x29 +#define RADIO_2056_SYN_VDDCAL_IDAC 0x2a +#define RADIO_2056_SYN_VDDCAL_STATUS 0x2b +#define RADIO_2056_SYN_RCAL_MASTER 0x2c +#define RADIO_2056_SYN_RCAL_CODE_OUT 0x2d +#define RADIO_2056_SYN_RCCAL_CTRL0 0x2e +#define RADIO_2056_SYN_RCCAL_CTRL1 0x2f +#define RADIO_2056_SYN_RCCAL_CTRL2 0x30 +#define RADIO_2056_SYN_RCCAL_CTRL3 0x31 +#define RADIO_2056_SYN_RCCAL_CTRL4 0x32 +#define RADIO_2056_SYN_RCCAL_CTRL5 0x33 +#define RADIO_2056_SYN_RCCAL_CTRL6 0x34 +#define RADIO_2056_SYN_RCCAL_CTRL7 0x35 +#define RADIO_2056_SYN_RCCAL_CTRL8 0x36 +#define RADIO_2056_SYN_RCCAL_CTRL9 0x37 +#define RADIO_2056_SYN_RCCAL_CTRL10 0x38 +#define RADIO_2056_SYN_RCCAL_CTRL11 0x39 +#define RADIO_2056_SYN_ZCAL_SPARE1 0x3a +#define RADIO_2056_SYN_ZCAL_SPARE2 0x3b +#define RADIO_2056_SYN_PLL_MAST1 0x3c +#define RADIO_2056_SYN_PLL_MAST2 0x3d +#define RADIO_2056_SYN_PLL_MAST3 0x3e +#define RADIO_2056_SYN_PLL_BIAS_RESET 0x3f +#define RADIO_2056_SYN_PLL_XTAL0 0x40 +#define RADIO_2056_SYN_PLL_XTAL1 0x41 +#define RADIO_2056_SYN_PLL_XTAL3 0x42 +#define RADIO_2056_SYN_PLL_XTAL4 0x43 +#define RADIO_2056_SYN_PLL_XTAL5 0x44 +#define RADIO_2056_SYN_PLL_XTAL6 0x45 +#define RADIO_2056_SYN_PLL_REFDIV 0x46 +#define RADIO_2056_SYN_PLL_PFD 0x47 +#define RADIO_2056_SYN_PLL_CP1 0x48 +#define RADIO_2056_SYN_PLL_CP2 0x49 +#define RADIO_2056_SYN_PLL_CP3 0x4a +#define RADIO_2056_SYN_PLL_LOOPFILTER1 0x4b +#define RADIO_2056_SYN_PLL_LOOPFILTER2 0x4c +#define RADIO_2056_SYN_PLL_LOOPFILTER3 0x4d +#define RADIO_2056_SYN_PLL_LOOPFILTER4 0x4e +#define RADIO_2056_SYN_PLL_LOOPFILTER5 0x4f +#define RADIO_2056_SYN_PLL_MMD1 0x50 +#define RADIO_2056_SYN_PLL_MMD2 0x51 +#define RADIO_2056_SYN_PLL_VCO1 0x52 +#define RADIO_2056_SYN_PLL_VCO2 0x53 +#define RADIO_2056_SYN_PLL_MONITOR1 0x54 +#define RADIO_2056_SYN_PLL_MONITOR2 0x55 +#define RADIO_2056_SYN_PLL_VCOCAL1 0x56 +#define RADIO_2056_SYN_PLL_VCOCAL2 0x57 +#define RADIO_2056_SYN_PLL_VCOCAL4 0x58 +#define RADIO_2056_SYN_PLL_VCOCAL5 0x59 +#define RADIO_2056_SYN_PLL_VCOCAL6 0x5a +#define RADIO_2056_SYN_PLL_VCOCAL7 0x5b +#define RADIO_2056_SYN_PLL_VCOCAL8 0x5c +#define RADIO_2056_SYN_PLL_VCOCAL9 0x5d +#define RADIO_2056_SYN_PLL_VCOCAL10 0x5e +#define RADIO_2056_SYN_PLL_VCOCAL11 0x5f +#define RADIO_2056_SYN_PLL_VCOCAL12 0x60 +#define RADIO_2056_SYN_PLL_VCOCAL13 0x61 +#define RADIO_2056_SYN_PLL_VREG 0x62 +#define RADIO_2056_SYN_PLL_STATUS1 0x63 +#define RADIO_2056_SYN_PLL_STATUS2 0x64 +#define RADIO_2056_SYN_PLL_STATUS3 0x65 +#define RADIO_2056_SYN_LOGEN_PU0 0x66 +#define RADIO_2056_SYN_LOGEN_PU1 0x67 +#define RADIO_2056_SYN_LOGEN_PU2 0x68 +#define RADIO_2056_SYN_LOGEN_PU3 0x69 +#define RADIO_2056_SYN_LOGEN_PU5 0x6a +#define RADIO_2056_SYN_LOGEN_PU6 0x6b +#define RADIO_2056_SYN_LOGEN_PU7 0x6c +#define RADIO_2056_SYN_LOGEN_PU8 0x6d +#define RADIO_2056_SYN_LOGEN_BIAS_RESET 0x6e +#define RADIO_2056_SYN_LOGEN_RCCR1 0x6f +#define RADIO_2056_SYN_LOGEN_VCOBUF1 0x70 +#define RADIO_2056_SYN_LOGEN_MIXER1 0x71 +#define RADIO_2056_SYN_LOGEN_MIXER2 0x72 +#define RADIO_2056_SYN_LOGEN_BUF1 0x73 +#define RADIO_2056_SYN_LOGENBUF2 0x74 +#define RADIO_2056_SYN_LOGEN_BUF3 0x75 +#define RADIO_2056_SYN_LOGEN_BUF4 0x76 +#define RADIO_2056_SYN_LOGEN_DIV1 0x77 +#define RADIO_2056_SYN_LOGEN_DIV2 0x78 +#define RADIO_2056_SYN_LOGEN_DIV3 0x79 +#define RADIO_2056_SYN_LOGEN_ACL1 0x7a +#define RADIO_2056_SYN_LOGEN_ACL2 0x7b +#define RADIO_2056_SYN_LOGEN_ACL3 0x7c +#define RADIO_2056_SYN_LOGEN_ACL4 0x7d +#define RADIO_2056_SYN_LOGEN_ACL5 0x7e +#define RADIO_2056_SYN_LOGEN_ACL6 0x7f +#define RADIO_2056_SYN_LOGEN_ACLOUT 0x80 +#define RADIO_2056_SYN_LOGEN_ACLCAL1 0x81 +#define RADIO_2056_SYN_LOGEN_ACLCAL2 0x82 +#define RADIO_2056_SYN_LOGEN_ACLCAL3 0x83 +#define RADIO_2056_SYN_CALEN 0x84 +#define RADIO_2056_SYN_LOGEN_PEAKDET1 0x85 +#define RADIO_2056_SYN_LOGEN_CORE_ACL_OVR 0x86 +#define RADIO_2056_SYN_LOGEN_RX_DIFF_ACL_OVR 0x87 +#define RADIO_2056_SYN_LOGEN_TX_DIFF_ACL_OVR 0x88 +#define RADIO_2056_SYN_LOGEN_RX_CMOS_ACL_OVR 0x89 +#define RADIO_2056_SYN_LOGEN_TX_CMOS_ACL_OVR 0x8a +#define RADIO_2056_SYN_LOGEN_VCOBUF2 0x8b +#define RADIO_2056_SYN_LOGEN_MIXER3 0x8c +#define RADIO_2056_SYN_LOGEN_BUF5 0x8d +#define RADIO_2056_SYN_LOGEN_BUF6 0x8e +#define RADIO_2056_SYN_LOGEN_CBUFRX1 0x8f +#define RADIO_2056_SYN_LOGEN_CBUFRX2 0x90 +#define RADIO_2056_SYN_LOGEN_CBUFRX3 0x91 +#define RADIO_2056_SYN_LOGEN_CBUFRX4 0x92 +#define RADIO_2056_SYN_LOGEN_CBUFTX1 0x93 +#define RADIO_2056_SYN_LOGEN_CBUFTX2 0x94 +#define RADIO_2056_SYN_LOGEN_CBUFTX3 0x95 +#define RADIO_2056_SYN_LOGEN_CBUFTX4 0x96 +#define RADIO_2056_SYN_LOGEN_CMOSRX1 0x97 +#define RADIO_2056_SYN_LOGEN_CMOSRX2 0x98 +#define RADIO_2056_SYN_LOGEN_CMOSRX3 0x99 +#define RADIO_2056_SYN_LOGEN_CMOSRX4 0x9a +#define RADIO_2056_SYN_LOGEN_CMOSTX1 0x9b +#define RADIO_2056_SYN_LOGEN_CMOSTX2 0x9c +#define RADIO_2056_SYN_LOGEN_CMOSTX3 0x9d +#define RADIO_2056_SYN_LOGEN_CMOSTX4 0x9e +#define RADIO_2056_SYN_LOGEN_VCOBUF2_OVRVAL 0x9f +#define RADIO_2056_SYN_LOGEN_MIXER3_OVRVAL 0xa0 +#define RADIO_2056_SYN_LOGEN_BUF5_OVRVAL 0xa1 +#define RADIO_2056_SYN_LOGEN_BUF6_OVRVAL 0xa2 +#define RADIO_2056_SYN_LOGEN_CBUFRX1_OVRVAL 0xa3 +#define RADIO_2056_SYN_LOGEN_CBUFRX2_OVRVAL 0xa4 +#define RADIO_2056_SYN_LOGEN_CBUFRX3_OVRVAL 0xa5 +#define RADIO_2056_SYN_LOGEN_CBUFRX4_OVRVAL 0xa6 +#define RADIO_2056_SYN_LOGEN_CBUFTX1_OVRVAL 0xa7 +#define RADIO_2056_SYN_LOGEN_CBUFTX2_OVRVAL 0xa8 +#define RADIO_2056_SYN_LOGEN_CBUFTX3_OVRVAL 0xa9 +#define RADIO_2056_SYN_LOGEN_CBUFTX4_OVRVAL 0xaa +#define RADIO_2056_SYN_LOGEN_CMOSRX1_OVRVAL 0xab +#define RADIO_2056_SYN_LOGEN_CMOSRX2_OVRVAL 0xac +#define RADIO_2056_SYN_LOGEN_CMOSRX3_OVRVAL 0xad +#define RADIO_2056_SYN_LOGEN_CMOSRX4_OVRVAL 0xae +#define RADIO_2056_SYN_LOGEN_CMOSTX1_OVRVAL 0xaf +#define RADIO_2056_SYN_LOGEN_CMOSTX2_OVRVAL 0xb0 +#define RADIO_2056_SYN_LOGEN_CMOSTX3_OVRVAL 0xb1 +#define RADIO_2056_SYN_LOGEN_CMOSTX4_OVRVAL 0xb2 +#define RADIO_2056_SYN_LOGEN_ACL_WAITCNT 0xb3 +#define RADIO_2056_SYN_LOGEN_CORE_CALVALID 0xb4 +#define RADIO_2056_SYN_LOGEN_RX_CMOS_CALVALID 0xb5 +#define RADIO_2056_SYN_LOGEN_TX_CMOS_VALID 0xb6 + +#define RADIO_2056_TX_RESERVED_ADDR0 0x0 +#define RADIO_2056_TX_IDCODE 0x1 +#define RADIO_2056_TX_RESERVED_ADDR2 0x2 +#define RADIO_2056_TX_RESERVED_ADDR3 0x3 +#define RADIO_2056_TX_RESERVED_ADDR4 0x4 +#define RADIO_2056_TX_RESERVED_ADDR5 0x5 +#define RADIO_2056_TX_RESERVED_ADDR6 0x6 +#define RADIO_2056_TX_RESERVED_ADDR7 0x7 +#define RADIO_2056_TX_COM_CTRL 0x8 +#define RADIO_2056_TX_COM_PU 0x9 +#define RADIO_2056_TX_COM_OVR 0xa +#define RADIO_2056_TX_COM_RESET 0xb +#define RADIO_2056_TX_COM_RCAL 0xc +#define RADIO_2056_TX_COM_RC_RXLPF 0xd +#define RADIO_2056_TX_COM_RC_TXLPF 0xe +#define RADIO_2056_TX_COM_RC_RXHPF 0xf +#define RADIO_2056_TX_RESERVED_ADDR16 0x10 +#define RADIO_2056_TX_RESERVED_ADDR17 0x11 +#define RADIO_2056_TX_RESERVED_ADDR18 0x12 +#define RADIO_2056_TX_RESERVED_ADDR19 0x13 +#define RADIO_2056_TX_RESERVED_ADDR20 0x14 +#define RADIO_2056_TX_RESERVED_ADDR21 0x15 +#define RADIO_2056_TX_RESERVED_ADDR22 0x16 +#define RADIO_2056_TX_RESERVED_ADDR23 0x17 +#define RADIO_2056_TX_RESERVED_ADDR24 0x18 +#define RADIO_2056_TX_RESERVED_ADDR25 0x19 +#define RADIO_2056_TX_RESERVED_ADDR26 0x1a +#define RADIO_2056_TX_RESERVED_ADDR27 0x1b +#define RADIO_2056_TX_RESERVED_ADDR28 0x1c +#define RADIO_2056_TX_RESERVED_ADDR29 0x1d +#define RADIO_2056_TX_RESERVED_ADDR30 0x1e +#define RADIO_2056_TX_RESERVED_ADDR31 0x1f +#define RADIO_2056_TX_IQCAL_GAIN_BW 0x20 +#define RADIO_2056_TX_LOFT_FINE_I 0x21 +#define RADIO_2056_TX_LOFT_FINE_Q 0x22 +#define RADIO_2056_TX_LOFT_COARSE_I 0x23 +#define RADIO_2056_TX_LOFT_COARSE_Q 0x24 +#define RADIO_2056_TX_TX_COM_MASTER1 0x25 +#define RADIO_2056_TX_TX_COM_MASTER2 0x26 +#define RADIO_2056_TX_RXIQCAL_TXMUX 0x27 +#define RADIO_2056_TX_TX_SSI_MASTER 0x28 +#define RADIO_2056_TX_IQCAL_VCM_HG 0x29 +#define RADIO_2056_TX_IQCAL_IDAC 0x2a +#define RADIO_2056_TX_TSSI_VCM 0x2b +#define RADIO_2056_TX_TX_AMP_DET 0x2c +#define RADIO_2056_TX_TX_SSI_MUX 0x2d +#define RADIO_2056_TX_TSSIA 0x2e +#define RADIO_2056_TX_TSSIG 0x2f +#define RADIO_2056_TX_TSSI_MISC1 0x30 +#define RADIO_2056_TX_TSSI_MISC2 0x31 +#define RADIO_2056_TX_TSSI_MISC3 0x32 +#define RADIO_2056_TX_PA_SPARE1 0x33 +#define RADIO_2056_TX_PA_SPARE2 0x34 +#define RADIO_2056_TX_INTPAA_MASTER 0x35 +#define RADIO_2056_TX_INTPAA_GAIN 0x36 +#define RADIO_2056_TX_INTPAA_BOOST_TUNE 0x37 +#define RADIO_2056_TX_INTPAA_IAUX_STAT 0x38 +#define RADIO_2056_TX_INTPAA_IAUX_DYN 0x39 +#define RADIO_2056_TX_INTPAA_IMAIN_STAT 0x3a +#define RADIO_2056_TX_INTPAA_IMAIN_DYN 0x3b +#define RADIO_2056_TX_INTPAA_CASCBIAS 0x3c +#define RADIO_2056_TX_INTPAA_PASLOPE 0x3d +#define RADIO_2056_TX_INTPAA_PA_MISC 0x3e +#define RADIO_2056_TX_INTPAG_MASTER 0x3f +#define RADIO_2056_TX_INTPAG_GAIN 0x40 +#define RADIO_2056_TX_INTPAG_BOOST_TUNE 0x41 +#define RADIO_2056_TX_INTPAG_IAUX_STAT 0x42 +#define RADIO_2056_TX_INTPAG_IAUX_DYN 0x43 +#define RADIO_2056_TX_INTPAG_IMAIN_STAT 0x44 +#define RADIO_2056_TX_INTPAG_IMAIN_DYN 0x45 +#define RADIO_2056_TX_INTPAG_CASCBIAS 0x46 +#define RADIO_2056_TX_INTPAG_PASLOPE 0x47 +#define RADIO_2056_TX_INTPAG_PA_MISC 0x48 +#define RADIO_2056_TX_PADA_MASTER 0x49 +#define RADIO_2056_TX_PADA_IDAC 0x4a +#define RADIO_2056_TX_PADA_CASCBIAS 0x4b +#define RADIO_2056_TX_PADA_GAIN 0x4c +#define RADIO_2056_TX_PADA_BOOST_TUNE 0x4d +#define RADIO_2056_TX_PADA_SLOPE 0x4e +#define RADIO_2056_TX_PADG_MASTER 0x4f +#define RADIO_2056_TX_PADG_IDAC 0x50 +#define RADIO_2056_TX_PADG_CASCBIAS 0x51 +#define RADIO_2056_TX_PADG_GAIN 0x52 +#define RADIO_2056_TX_PADG_BOOST_TUNE 0x53 +#define RADIO_2056_TX_PADG_SLOPE 0x54 +#define RADIO_2056_TX_PGAA_MASTER 0x55 +#define RADIO_2056_TX_PGAA_IDAC 0x56 +#define RADIO_2056_TX_PGAA_GAIN 0x57 +#define RADIO_2056_TX_PGAA_BOOST_TUNE 0x58 +#define RADIO_2056_TX_PGAA_SLOPE 0x59 +#define RADIO_2056_TX_PGAA_MISC 0x5a +#define RADIO_2056_TX_PGAG_MASTER 0x5b +#define RADIO_2056_TX_PGAG_IDAC 0x5c +#define RADIO_2056_TX_PGAG_GAIN 0x5d +#define RADIO_2056_TX_PGAG_BOOST_TUNE 0x5e +#define RADIO_2056_TX_PGAG_SLOPE 0x5f +#define RADIO_2056_TX_PGAG_MISC 0x60 +#define RADIO_2056_TX_MIXA_MASTER 0x61 +#define RADIO_2056_TX_MIXA_BOOST_TUNE 0x62 +#define RADIO_2056_TX_MIXG 0x63 +#define RADIO_2056_TX_MIXG_BOOST_TUNE 0x64 +#define RADIO_2056_TX_BB_GM_MASTER 0x65 +#define RADIO_2056_TX_GMBB_GM 0x66 +#define RADIO_2056_TX_GMBB_IDAC 0x67 +#define RADIO_2056_TX_TXLPF_MASTER 0x68 +#define RADIO_2056_TX_TXLPF_RCCAL 0x69 +#define RADIO_2056_TX_TXLPF_RCCAL_OFF0 0x6a +#define RADIO_2056_TX_TXLPF_RCCAL_OFF1 0x6b +#define RADIO_2056_TX_TXLPF_RCCAL_OFF2 0x6c +#define RADIO_2056_TX_TXLPF_RCCAL_OFF3 0x6d +#define RADIO_2056_TX_TXLPF_RCCAL_OFF4 0x6e +#define RADIO_2056_TX_TXLPF_RCCAL_OFF5 0x6f +#define RADIO_2056_TX_TXLPF_RCCAL_OFF6 0x70 +#define RADIO_2056_TX_TXLPF_BW 0x71 +#define RADIO_2056_TX_TXLPF_GAIN 0x72 +#define RADIO_2056_TX_TXLPF_IDAC 0x73 +#define RADIO_2056_TX_TXLPF_IDAC_0 0x74 +#define RADIO_2056_TX_TXLPF_IDAC_1 0x75 +#define RADIO_2056_TX_TXLPF_IDAC_2 0x76 +#define RADIO_2056_TX_TXLPF_IDAC_3 0x77 +#define RADIO_2056_TX_TXLPF_IDAC_4 0x78 +#define RADIO_2056_TX_TXLPF_IDAC_5 0x79 +#define RADIO_2056_TX_TXLPF_IDAC_6 0x7a +#define RADIO_2056_TX_TXLPF_OPAMP_IDAC 0x7b +#define RADIO_2056_TX_TXLPF_MISC 0x7c +#define RADIO_2056_TX_TXSPARE1 0x7d +#define RADIO_2056_TX_TXSPARE2 0x7e +#define RADIO_2056_TX_TXSPARE3 0x7f +#define RADIO_2056_TX_TXSPARE4 0x80 +#define RADIO_2056_TX_TXSPARE5 0x81 +#define RADIO_2056_TX_TXSPARE6 0x82 +#define RADIO_2056_TX_TXSPARE7 0x83 +#define RADIO_2056_TX_TXSPARE8 0x84 +#define RADIO_2056_TX_TXSPARE9 0x85 +#define RADIO_2056_TX_TXSPARE10 0x86 +#define RADIO_2056_TX_TXSPARE11 0x87 +#define RADIO_2056_TX_TXSPARE12 0x88 +#define RADIO_2056_TX_TXSPARE13 0x89 +#define RADIO_2056_TX_TXSPARE14 0x8a +#define RADIO_2056_TX_TXSPARE15 0x8b +#define RADIO_2056_TX_TXSPARE16 0x8c +#define RADIO_2056_TX_STATUS_INTPA_GAIN 0x8d +#define RADIO_2056_TX_STATUS_PAD_GAIN 0x8e +#define RADIO_2056_TX_STATUS_PGA_GAIN 0x8f +#define RADIO_2056_TX_STATUS_GM_TXLPF_GAIN 0x90 +#define RADIO_2056_TX_STATUS_TXLPF_BW 0x91 +#define RADIO_2056_TX_STATUS_TXLPF_RC 0x92 +#define RADIO_2056_TX_GMBB_IDAC0 0x93 +#define RADIO_2056_TX_GMBB_IDAC1 0x94 +#define RADIO_2056_TX_GMBB_IDAC2 0x95 +#define RADIO_2056_TX_GMBB_IDAC3 0x96 +#define RADIO_2056_TX_GMBB_IDAC4 0x97 +#define RADIO_2056_TX_GMBB_IDAC5 0x98 +#define RADIO_2056_TX_GMBB_IDAC6 0x99 +#define RADIO_2056_TX_GMBB_IDAC7 0x9a + +#define RADIO_2056_RX_RESERVED_ADDR0 0x0 +#define RADIO_2056_RX_IDCODE 0x1 +#define RADIO_2056_RX_RESERVED_ADDR2 0x2 +#define RADIO_2056_RX_RESERVED_ADDR3 0x3 +#define RADIO_2056_RX_RESERVED_ADDR4 0x4 +#define RADIO_2056_RX_RESERVED_ADDR5 0x5 +#define RADIO_2056_RX_RESERVED_ADDR6 0x6 +#define RADIO_2056_RX_RESERVED_ADDR7 0x7 +#define RADIO_2056_RX_COM_CTRL 0x8 +#define RADIO_2056_RX_COM_PU 0x9 +#define RADIO_2056_RX_COM_OVR 0xa +#define RADIO_2056_RX_COM_RESET 0xb +#define RADIO_2056_RX_COM_RCAL 0xc +#define RADIO_2056_RX_COM_RC_RXLPF 0xd +#define RADIO_2056_RX_COM_RC_TXLPF 0xe +#define RADIO_2056_RX_COM_RC_RXHPF 0xf +#define RADIO_2056_RX_RESERVED_ADDR16 0x10 +#define RADIO_2056_RX_RESERVED_ADDR17 0x11 +#define RADIO_2056_RX_RESERVED_ADDR18 0x12 +#define RADIO_2056_RX_RESERVED_ADDR19 0x13 +#define RADIO_2056_RX_RESERVED_ADDR20 0x14 +#define RADIO_2056_RX_RESERVED_ADDR21 0x15 +#define RADIO_2056_RX_RESERVED_ADDR22 0x16 +#define RADIO_2056_RX_RESERVED_ADDR23 0x17 +#define RADIO_2056_RX_RESERVED_ADDR24 0x18 +#define RADIO_2056_RX_RESERVED_ADDR25 0x19 +#define RADIO_2056_RX_RESERVED_ADDR26 0x1a +#define RADIO_2056_RX_RESERVED_ADDR27 0x1b +#define RADIO_2056_RX_RESERVED_ADDR28 0x1c +#define RADIO_2056_RX_RESERVED_ADDR29 0x1d +#define RADIO_2056_RX_RESERVED_ADDR30 0x1e +#define RADIO_2056_RX_RESERVED_ADDR31 0x1f +#define RADIO_2056_RX_RXIQCAL_RXMUX 0x20 +#define RADIO_2056_RX_RSSI_PU 0x21 +#define RADIO_2056_RX_RSSI_SEL 0x22 +#define RADIO_2056_RX_RSSI_GAIN 0x23 +#define RADIO_2056_RX_RSSI_NB_IDAC 0x24 +#define RADIO_2056_RX_RSSI_WB2I_IDAC_1 0x25 +#define RADIO_2056_RX_RSSI_WB2I_IDAC_2 0x26 +#define RADIO_2056_RX_RSSI_WB2Q_IDAC_1 0x27 +#define RADIO_2056_RX_RSSI_WB2Q_IDAC_2 0x28 +#define RADIO_2056_RX_RSSI_POLE 0x29 +#define RADIO_2056_RX_RSSI_WB1_IDAC 0x2a +#define RADIO_2056_RX_RSSI_MISC 0x2b +#define RADIO_2056_RX_LNAA_MASTER 0x2c +#define RADIO_2056_RX_LNAA_TUNE 0x2d +#define RADIO_2056_RX_LNAA_GAIN 0x2e +#define RADIO_2056_RX_LNA_A_SLOPE 0x2f +#define RADIO_2056_RX_BIASPOLE_LNAA1_IDAC 0x30 +#define RADIO_2056_RX_LNAA2_IDAC 0x31 +#define RADIO_2056_RX_LNA1A_MISC 0x32 +#define RADIO_2056_RX_LNAG_MASTER 0x33 +#define RADIO_2056_RX_LNAG_TUNE 0x34 +#define RADIO_2056_RX_LNAG_GAIN 0x35 +#define RADIO_2056_RX_LNA_G_SLOPE 0x36 +#define RADIO_2056_RX_BIASPOLE_LNAG1_IDAC 0x37 +#define RADIO_2056_RX_LNAG2_IDAC 0x38 +#define RADIO_2056_RX_LNA1G_MISC 0x39 +#define RADIO_2056_RX_MIXA_MASTER 0x3a +#define RADIO_2056_RX_MIXA_VCM 0x3b +#define RADIO_2056_RX_MIXA_CTRLPTAT 0x3c +#define RADIO_2056_RX_MIXA_LOB_BIAS 0x3d +#define RADIO_2056_RX_MIXA_CORE_IDAC 0x3e +#define RADIO_2056_RX_MIXA_CMFB_IDAC 0x3f +#define RADIO_2056_RX_MIXA_BIAS_AUX 0x40 +#define RADIO_2056_RX_MIXA_BIAS_MAIN 0x41 +#define RADIO_2056_RX_MIXA_BIAS_MISC 0x42 +#define RADIO_2056_RX_MIXA_MAST_BIAS 0x43 +#define RADIO_2056_RX_MIXG_MASTER 0x44 +#define RADIO_2056_RX_MIXG_VCM 0x45 +#define RADIO_2056_RX_MIXG_CTRLPTAT 0x46 +#define RADIO_2056_RX_MIXG_LOB_BIAS 0x47 +#define RADIO_2056_RX_MIXG_CORE_IDAC 0x48 +#define RADIO_2056_RX_MIXG_CMFB_IDAC 0x49 +#define RADIO_2056_RX_MIXG_BIAS_AUX 0x4a +#define RADIO_2056_RX_MIXG_BIAS_MAIN 0x4b +#define RADIO_2056_RX_MIXG_BIAS_MISC 0x4c +#define RADIO_2056_RX_MIXG_MAST_BIAS 0x4d +#define RADIO_2056_RX_TIA_MASTER 0x4e +#define RADIO_2056_RX_TIA_IOPAMP 0x4f +#define RADIO_2056_RX_TIA_QOPAMP 0x50 +#define RADIO_2056_RX_TIA_IMISC 0x51 +#define RADIO_2056_RX_TIA_QMISC 0x52 +#define RADIO_2056_RX_TIA_GAIN 0x53 +#define RADIO_2056_RX_TIA_SPARE1 0x54 +#define RADIO_2056_RX_TIA_SPARE2 0x55 +#define RADIO_2056_RX_BB_LPF_MASTER 0x56 +#define RADIO_2056_RX_AACI_MASTER 0x57 +#define RADIO_2056_RX_RXLPF_IDAC 0x58 +#define RADIO_2056_RX_RXLPF_OPAMPBIAS_LOWQ 0x59 +#define RADIO_2056_RX_RXLPF_OPAMPBIAS_HIGHQ 0x5a +#define RADIO_2056_RX_RXLPF_BIAS_DCCANCEL 0x5b +#define RADIO_2056_RX_RXLPF_OUTVCM 0x5c +#define RADIO_2056_RX_RXLPF_INVCM_BODY 0x5d +#define RADIO_2056_RX_RXLPF_CC_OP 0x5e +#define RADIO_2056_RX_RXLPF_GAIN 0x5f +#define RADIO_2056_RX_RXLPF_Q_BW 0x60 +#define RADIO_2056_RX_RXLPF_HP_CORNER_BW 0x61 +#define RADIO_2056_RX_RXLPF_RCCAL_HPC 0x62 +#define RADIO_2056_RX_RXHPF_OFF0 0x63 +#define RADIO_2056_RX_RXHPF_OFF1 0x64 +#define RADIO_2056_RX_RXHPF_OFF2 0x65 +#define RADIO_2056_RX_RXHPF_OFF3 0x66 +#define RADIO_2056_RX_RXHPF_OFF4 0x67 +#define RADIO_2056_RX_RXHPF_OFF5 0x68 +#define RADIO_2056_RX_RXHPF_OFF6 0x69 +#define RADIO_2056_RX_RXHPF_OFF7 0x6a +#define RADIO_2056_RX_RXLPF_RCCAL_LPC 0x6b +#define RADIO_2056_RX_RXLPF_OFF_0 0x6c +#define RADIO_2056_RX_RXLPF_OFF_1 0x6d +#define RADIO_2056_RX_RXLPF_OFF_2 0x6e +#define RADIO_2056_RX_RXLPF_OFF_3 0x6f +#define RADIO_2056_RX_RXLPF_OFF_4 0x70 +#define RADIO_2056_RX_UNUSED 0x71 +#define RADIO_2056_RX_VGA_MASTER 0x72 +#define RADIO_2056_RX_VGA_BIAS 0x73 +#define RADIO_2056_RX_VGA_BIAS_DCCANCEL 0x74 +#define RADIO_2056_RX_VGA_GAIN 0x75 +#define RADIO_2056_RX_VGA_HP_CORNER_BW 0x76 +#define RADIO_2056_RX_VGABUF_BIAS 0x77 +#define RADIO_2056_RX_VGABUF_GAIN_BW 0x78 +#define RADIO_2056_RX_TXFBMIX_A 0x79 +#define RADIO_2056_RX_TXFBMIX_G 0x7a +#define RADIO_2056_RX_RXSPARE1 0x7b +#define RADIO_2056_RX_RXSPARE2 0x7c +#define RADIO_2056_RX_RXSPARE3 0x7d +#define RADIO_2056_RX_RXSPARE4 0x7e +#define RADIO_2056_RX_RXSPARE5 0x7f +#define RADIO_2056_RX_RXSPARE6 0x80 +#define RADIO_2056_RX_RXSPARE7 0x81 +#define RADIO_2056_RX_RXSPARE8 0x82 +#define RADIO_2056_RX_RXSPARE9 0x83 +#define RADIO_2056_RX_RXSPARE10 0x84 +#define RADIO_2056_RX_RXSPARE11 0x85 +#define RADIO_2056_RX_RXSPARE12 0x86 +#define RADIO_2056_RX_RXSPARE13 0x87 +#define RADIO_2056_RX_RXSPARE14 0x88 +#define RADIO_2056_RX_RXSPARE15 0x89 +#define RADIO_2056_RX_RXSPARE16 0x8a +#define RADIO_2056_RX_STATUS_LNAA_GAIN 0x8b +#define RADIO_2056_RX_STATUS_LNAG_GAIN 0x8c +#define RADIO_2056_RX_STATUS_MIXTIA_GAIN 0x8d +#define RADIO_2056_RX_STATUS_RXLPF_GAIN 0x8e +#define RADIO_2056_RX_STATUS_VGA_BUF_GAIN 0x8f +#define RADIO_2056_RX_STATUS_RXLPF_Q 0x90 +#define RADIO_2056_RX_STATUS_RXLPF_BUF_BW 0x91 +#define RADIO_2056_RX_STATUS_RXLPF_VGA_HPC 0x92 +#define RADIO_2056_RX_STATUS_RXLPF_RC 0x93 +#define RADIO_2056_RX_STATUS_HPC_RC 0x94 + +#define RADIO_2056_LNA1_A_PU 0x01 +#define RADIO_2056_LNA2_A_PU 0x02 +#define RADIO_2056_LNA1_G_PU 0x01 +#define RADIO_2056_LNA2_G_PU 0x02 +#define RADIO_2056_MIXA_PU_I 0x01 +#define RADIO_2056_MIXA_PU_Q 0x02 +#define RADIO_2056_MIXA_PU_GM 0x10 +#define RADIO_2056_MIXG_PU_I 0x01 +#define RADIO_2056_MIXG_PU_Q 0x02 +#define RADIO_2056_MIXG_PU_GM 0x10 +#define RADIO_2056_TIA_PU 0x01 +#define RADIO_2056_BB_LPF_PU 0x20 +#define RADIO_2056_W1_PU 0x02 +#define RADIO_2056_W2_PU 0x04 +#define RADIO_2056_NB_PU 0x08 +#define RADIO_2056_RSSI_W1_SEL 0x02 +#define RADIO_2056_RSSI_W2_SEL 0x04 +#define RADIO_2056_RSSI_NB_SEL 0x08 +#define RADIO_2056_VCM_MASK 0x1c +#define RADIO_2056_RSSI_VCM_SHIFT 0x02 + +#define RADIO_2057_DACBUF_VINCM_CORE0 0x0 +#define RADIO_2057_IDCODE 0x1 +#define RADIO_2057_RCCAL_MASTER 0x2 +#define RADIO_2057_RCCAL_CAP_SIZE 0x3 +#define RADIO_2057_RCAL_CONFIG 0x4 +#define RADIO_2057_GPAIO_CONFIG 0x5 +#define RADIO_2057_GPAIO_SEL1 0x6 +#define RADIO_2057_GPAIO_SEL0 0x7 +#define RADIO_2057_CLPO_CONFIG 0x8 +#define RADIO_2057_BANDGAP_CONFIG 0x9 +#define RADIO_2057_BANDGAP_RCAL_TRIM 0xa +#define RADIO_2057_AFEREG_CONFIG 0xb +#define RADIO_2057_TEMPSENSE_CONFIG 0xc +#define RADIO_2057_XTAL_CONFIG1 0xd +#define RADIO_2057_XTAL_ICORE_SIZE 0xe +#define RADIO_2057_XTAL_BUF_SIZE 0xf +#define RADIO_2057_XTAL_PULLCAP_SIZE 0x10 +#define RADIO_2057_RFPLL_MASTER 0x11 +#define RADIO_2057_VCOMONITOR_VTH_L 0x12 +#define RADIO_2057_VCOMONITOR_VTH_H 0x13 +#define RADIO_2057_VCOCAL_BIASRESET_RFPLLREG_VOUT 0x14 +#define RADIO_2057_VCO_VARCSIZE_IDAC 0x15 +#define RADIO_2057_VCOCAL_COUNTVAL0 0x16 +#define RADIO_2057_VCOCAL_COUNTVAL1 0x17 +#define RADIO_2057_VCOCAL_INTCLK_COUNT 0x18 +#define RADIO_2057_VCOCAL_MASTER 0x19 +#define RADIO_2057_VCOCAL_NUMCAPCHANGE 0x1a +#define RADIO_2057_VCOCAL_WINSIZE 0x1b +#define RADIO_2057_VCOCAL_DELAY_AFTER_REFRESH 0x1c +#define RADIO_2057_VCOCAL_DELAY_AFTER_CLOSELOOP 0x1d +#define RADIO_2057_VCOCAL_DELAY_AFTER_OPENLOOP 0x1e +#define RADIO_2057_VCOCAL_DELAY_BEFORE_OPENLOOP 0x1f +#define RADIO_2057_VCO_FORCECAPEN_FORCECAP1 0x20 +#define RADIO_2057_VCO_FORCECAP0 0x21 +#define RADIO_2057_RFPLL_REFMASTER_SPAREXTALSIZE 0x22 +#define RADIO_2057_RFPLL_PFD_RESET_PW 0x23 +#define RADIO_2057_RFPLL_LOOPFILTER_R2 0x24 +#define RADIO_2057_RFPLL_LOOPFILTER_R1 0x25 +#define RADIO_2057_RFPLL_LOOPFILTER_C3 0x26 +#define RADIO_2057_RFPLL_LOOPFILTER_C2 0x27 +#define RADIO_2057_RFPLL_LOOPFILTER_C1 0x28 +#define RADIO_2057_CP_KPD_IDAC 0x29 +#define RADIO_2057_RFPLL_IDACS 0x2a +#define RADIO_2057_RFPLL_MISC_EN 0x2b +#define RADIO_2057_RFPLL_MMD0 0x2c +#define RADIO_2057_RFPLL_MMD1 0x2d +#define RADIO_2057_RFPLL_MISC_CAL_RESETN 0x2e +#define RADIO_2057_JTAGXTAL_SIZE_CPBIAS_FILTRES 0x2f +#define RADIO_2057_VCO_ALCREF_BBPLLXTAL_SIZE 0x30 +#define RADIO_2057_VCOCAL_READCAP0 0x31 +#define RADIO_2057_VCOCAL_READCAP1 0x32 +#define RADIO_2057_VCOCAL_STATUS 0x33 +#define RADIO_2057_LOGEN_PUS 0x34 +#define RADIO_2057_LOGEN_PTAT_RESETS 0x35 +#define RADIO_2057_VCOBUF_IDACS 0x36 +#define RADIO_2057_VCOBUF_TUNE 0x37 +#define RADIO_2057_CMOSBUF_TX2GQ_IDACS 0x38 +#define RADIO_2057_CMOSBUF_TX2GI_IDACS 0x39 +#define RADIO_2057_CMOSBUF_TX5GQ_IDACS 0x3a +#define RADIO_2057_CMOSBUF_TX5GI_IDACS 0x3b +#define RADIO_2057_CMOSBUF_RX2GQ_IDACS 0x3c +#define RADIO_2057_CMOSBUF_RX2GI_IDACS 0x3d +#define RADIO_2057_CMOSBUF_RX5GQ_IDACS 0x3e +#define RADIO_2057_CMOSBUF_RX5GI_IDACS 0x3f +#define RADIO_2057_LOGEN_MX2G_IDACS 0x40 +#define RADIO_2057_LOGEN_MX2G_TUNE 0x41 +#define RADIO_2057_LOGEN_MX5G_IDACS 0x42 +#define RADIO_2057_LOGEN_MX5G_TUNE 0x43 +#define RADIO_2057_LOGEN_MX5G_RCCR 0x44 +#define RADIO_2057_LOGEN_INDBUF2G_IDAC 0x45 +#define RADIO_2057_LOGEN_INDBUF2G_IBOOST 0x46 +#define RADIO_2057_LOGEN_INDBUF2G_TUNE 0x47 +#define RADIO_2057_LOGEN_INDBUF5G_IDAC 0x48 +#define RADIO_2057_LOGEN_INDBUF5G_IBOOST 0x49 +#define RADIO_2057_LOGEN_INDBUF5G_TUNE 0x4a +#define RADIO_2057_CMOSBUF_TX_RCCR 0x4b +#define RADIO_2057_CMOSBUF_RX_RCCR 0x4c +#define RADIO_2057_LOGEN_SEL_PKDET 0x4d +#define RADIO_2057_CMOSBUF_SHAREIQ_PTAT 0x4e +#define RADIO_2057_RXTXBIAS_CONFIG_CORE0 0x4f +#define RADIO_2057_TXGM_TXRF_PUS_CORE0 0x50 +#define RADIO_2057_TXGM_IDAC_BLEED_CORE0 0x51 +#define RADIO_2057_TXGM_GAIN_CORE0 0x56 +#define RADIO_2057_TXGM2G_PKDET_PUS_CORE0 0x57 +#define RADIO_2057_PAD2G_PTATS_CORE0 0x58 +#define RADIO_2057_PAD2G_IDACS_CORE0 0x59 +#define RADIO_2057_PAD2G_BOOST_PU_CORE0 0x5a +#define RADIO_2057_PAD2G_CASCV_GAIN_CORE0 0x5b +#define RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE0 0x5c +#define RADIO_2057_TXMIX2G_LODC_CORE0 0x5d +#define RADIO_2057_PAD2G_TUNE_PUS_CORE0 0x5e +#define RADIO_2057_IPA2G_GAIN_CORE0 0x5f +#define RADIO_2057_TSSI2G_SPARE1_CORE0 0x60 +#define RADIO_2057_TSSI2G_SPARE2_CORE0 0x61 +#define RADIO_2057_IPA2G_TUNEV_CASCV_PTAT_CORE0 0x62 +#define RADIO_2057_IPA2G_IMAIN_CORE0 0x63 +#define RADIO_2057_IPA2G_CASCONV_CORE0 0x64 +#define RADIO_2057_IPA2G_CASCOFFV_CORE0 0x65 +#define RADIO_2057_IPA2G_BIAS_FILTER_CORE0 0x66 +#define RADIO_2057_TX5G_PKDET_CORE0 0x69 +#define RADIO_2057_PGA_PTAT_TXGM5G_PU_CORE0 0x6a +#define RADIO_2057_PAD5G_PTATS1_CORE0 0x6b +#define RADIO_2057_PAD5G_CLASS_PTATS2_CORE0 0x6c +#define RADIO_2057_PGA_BOOSTPTAT_IMAIN_CORE0 0x6d +#define RADIO_2057_PAD5G_CASCV_IMAIN_CORE0 0x6e +#define RADIO_2057_TXMIX5G_IBOOST_PAD_IAUX_CORE0 0x6f +#define RADIO_2057_PGA_BOOST_TUNE_CORE0 0x70 +#define RADIO_2057_PGA_GAIN_CORE0 0x71 +#define RADIO_2057_PAD5G_CASCOFFV_GAIN_PUS_CORE0 0x72 +#define RADIO_2057_TXMIX5G_BOOST_TUNE_CORE0 0x73 +#define RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE0 0x74 +#define RADIO_2057_IPA5G_IAUX_CORE0 0x75 +#define RADIO_2057_IPA5G_GAIN_CORE0 0x76 +#define RADIO_2057_TSSI5G_SPARE1_CORE0 0x77 +#define RADIO_2057_TSSI5G_SPARE2_CORE0 0x78 +#define RADIO_2057_IPA5G_CASCOFFV_PU_CORE0 0x79 +#define RADIO_2057_IPA5G_PTAT_CORE0 0x7a +#define RADIO_2057_IPA5G_IMAIN_CORE0 0x7b +#define RADIO_2057_IPA5G_CASCONV_CORE0 0x7c +#define RADIO_2057_IPA5G_BIAS_FILTER_CORE0 0x7d +#define RADIO_2057_PAD_BIAS_FILTER_BWS_CORE0 0x80 +#define RADIO_2057_TR2G_CONFIG1_CORE0_NU 0x81 +#define RADIO_2057_TR2G_CONFIG2_CORE0_NU 0x82 +#define RADIO_2057_LNA5G_RFEN_CORE0 0x83 +#define RADIO_2057_TR5G_CONFIG2_CORE0_NU 0x84 +#define RADIO_2057_RXRFBIAS_IBOOST_PU_CORE0 0x85 +#define RADIO_2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE0 0x86 +#define RADIO_2057_RXGM_CMFBITAIL_AUXPTAT_CORE0 0x87 +#define RADIO_2057_RXMIX_ICORE_RXGM_IAUX_CORE0 0x88 +#define RADIO_2057_RXMIX_CMFBITAIL_PU_CORE0 0x89 +#define RADIO_2057_LNA2_IMAIN_PTAT_PU_CORE0 0x8a +#define RADIO_2057_LNA2_IAUX_PTAT_CORE0 0x8b +#define RADIO_2057_LNA1_IMAIN_PTAT_PU_CORE0 0x8c +#define RADIO_2057_LNA15G_INPUT_MATCH_TUNE_CORE0 0x8d +#define RADIO_2057_RXRFBIAS_BANDSEL_CORE0 0x8e +#define RADIO_2057_TIA_CONFIG_CORE0 0x8f +#define RADIO_2057_TIA_IQGAIN_CORE0 0x90 +#define RADIO_2057_TIA_IBIAS2_CORE0 0x91 +#define RADIO_2057_TIA_IBIAS1_CORE0 0x92 +#define RADIO_2057_TIA_SPARE_Q_CORE0 0x93 +#define RADIO_2057_TIA_SPARE_I_CORE0 0x94 +#define RADIO_2057_RXMIX2G_PUS_CORE0 0x95 +#define RADIO_2057_RXMIX2G_VCMREFS_CORE0 0x96 +#define RADIO_2057_RXMIX2G_LODC_QI_CORE0 0x97 +#define RADIO_2057_W12G_BW_LNA2G_PUS_CORE0 0x98 +#define RADIO_2057_LNA2G_GAIN_CORE0 0x99 +#define RADIO_2057_LNA2G_TUNE_CORE0 0x9a +#define RADIO_2057_RXMIX5G_PUS_CORE0 0x9b +#define RADIO_2057_RXMIX5G_VCMREFS_CORE0 0x9c +#define RADIO_2057_RXMIX5G_LODC_QI_CORE0 0x9d +#define RADIO_2057_W15G_BW_LNA5G_PUS_CORE0 0x9e +#define RADIO_2057_LNA5G_GAIN_CORE0 0x9f +#define RADIO_2057_LNA5G_TUNE_CORE0 0xa0 +#define RADIO_2057_LPFSEL_TXRX_RXBB_PUS_CORE0 0xa1 +#define RADIO_2057_RXBB_BIAS_MASTER_CORE0 0xa2 +#define RADIO_2057_RXBB_VGABUF_IDACS_CORE0 0xa3 +#define RADIO_2057_LPF_VCMREF_TXBUF_VCMREF_CORE0 0xa4 +#define RADIO_2057_TXBUF_VINCM_CORE0 0xa5 +#define RADIO_2057_TXBUF_IDACS_CORE0 0xa6 +#define RADIO_2057_LPF_RESP_RXBUF_BW_CORE0 0xa7 +#define RADIO_2057_RXBB_CC_CORE0 0xa8 +#define RADIO_2057_RXBB_SPARE3_CORE0 0xa9 +#define RADIO_2057_RXBB_RCCAL_HPC_CORE0 0xaa +#define RADIO_2057_LPF_IDACS_CORE0 0xab +#define RADIO_2057_LPFBYP_DCLOOP_BYP_IDAC_CORE0 0xac +#define RADIO_2057_TXBUF_GAIN_CORE0 0xad +#define RADIO_2057_AFELOOPBACK_AACI_RESP_CORE0 0xae +#define RADIO_2057_RXBUF_DEGEN_CORE0 0xaf +#define RADIO_2057_RXBB_SPARE2_CORE0 0xb0 +#define RADIO_2057_RXBB_SPARE1_CORE0 0xb1 +#define RADIO_2057_RSSI_MASTER_CORE0 0xb2 +#define RADIO_2057_W2_MASTER_CORE0 0xb3 +#define RADIO_2057_NB_MASTER_CORE0 0xb4 +#define RADIO_2057_W2_IDACS0_Q_CORE0 0xb5 +#define RADIO_2057_W2_IDACS1_Q_CORE0 0xb6 +#define RADIO_2057_W2_IDACS0_I_CORE0 0xb7 +#define RADIO_2057_W2_IDACS1_I_CORE0 0xb8 +#define RADIO_2057_RSSI_GPAIOSEL_W1_IDACS_CORE0 0xb9 +#define RADIO_2057_NB_IDACS_Q_CORE0 0xba +#define RADIO_2057_NB_IDACS_I_CORE0 0xbb +#define RADIO_2057_BACKUP4_CORE0 0xc1 +#define RADIO_2057_BACKUP3_CORE0 0xc2 +#define RADIO_2057_BACKUP2_CORE0 0xc3 +#define RADIO_2057_BACKUP1_CORE0 0xc4 +#define RADIO_2057_SPARE16_CORE0 0xc5 +#define RADIO_2057_SPARE15_CORE0 0xc6 +#define RADIO_2057_SPARE14_CORE0 0xc7 +#define RADIO_2057_SPARE13_CORE0 0xc8 +#define RADIO_2057_SPARE12_CORE0 0xc9 +#define RADIO_2057_SPARE11_CORE0 0xca +#define RADIO_2057_TX2G_BIAS_RESETS_CORE0 0xcb +#define RADIO_2057_TX5G_BIAS_RESETS_CORE0 0xcc +#define RADIO_2057_IQTEST_SEL_PU 0xcd +#define RADIO_2057_XTAL_CONFIG2 0xce +#define RADIO_2057_BUFS_MISC_LPFBW_CORE0 0xcf +#define RADIO_2057_TXLPF_RCCAL_CORE0 0xd0 +#define RADIO_2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE0 0xd1 +#define RADIO_2057_LPF_GAIN_CORE0 0xd2 +#define RADIO_2057_DACBUF_IDACS_BW_CORE0 0xd3 +#define RADIO_2057_RXTXBIAS_CONFIG_CORE1 0xd4 +#define RADIO_2057_TXGM_TXRF_PUS_CORE1 0xd5 +#define RADIO_2057_TXGM_IDAC_BLEED_CORE1 0xd6 +#define RADIO_2057_TXGM_GAIN_CORE1 0xdb +#define RADIO_2057_TXGM2G_PKDET_PUS_CORE1 0xdc +#define RADIO_2057_PAD2G_PTATS_CORE1 0xdd +#define RADIO_2057_PAD2G_IDACS_CORE1 0xde +#define RADIO_2057_PAD2G_BOOST_PU_CORE1 0xdf +#define RADIO_2057_PAD2G_CASCV_GAIN_CORE1 0xe0 +#define RADIO_2057_TXMIX2G_TUNE_BOOST_PU_CORE1 0xe1 +#define RADIO_2057_TXMIX2G_LODC_CORE1 0xe2 +#define RADIO_2057_PAD2G_TUNE_PUS_CORE1 0xe3 +#define RADIO_2057_IPA2G_GAIN_CORE1 0xe4 +#define RADIO_2057_TSSI2G_SPARE1_CORE1 0xe5 +#define RADIO_2057_TSSI2G_SPARE2_CORE1 0xe6 +#define RADIO_2057_IPA2G_TUNEV_CASCV_PTAT_CORE1 0xe7 +#define RADIO_2057_IPA2G_IMAIN_CORE1 0xe8 +#define RADIO_2057_IPA2G_CASCONV_CORE1 0xe9 +#define RADIO_2057_IPA2G_CASCOFFV_CORE1 0xea +#define RADIO_2057_IPA2G_BIAS_FILTER_CORE1 0xeb +#define RADIO_2057_TX5G_PKDET_CORE1 0xee +#define RADIO_2057_PGA_PTAT_TXGM5G_PU_CORE1 0xef +#define RADIO_2057_PAD5G_PTATS1_CORE1 0xf0 +#define RADIO_2057_PAD5G_CLASS_PTATS2_CORE1 0xf1 +#define RADIO_2057_PGA_BOOSTPTAT_IMAIN_CORE1 0xf2 +#define RADIO_2057_PAD5G_CASCV_IMAIN_CORE1 0xf3 +#define RADIO_2057_TXMIX5G_IBOOST_PAD_IAUX_CORE1 0xf4 +#define RADIO_2057_PGA_BOOST_TUNE_CORE1 0xf5 +#define RADIO_2057_PGA_GAIN_CORE1 0xf6 +#define RADIO_2057_PAD5G_CASCOFFV_GAIN_PUS_CORE1 0xf7 +#define RADIO_2057_TXMIX5G_BOOST_TUNE_CORE1 0xf8 +#define RADIO_2057_PAD5G_TUNE_MISC_PUS_CORE1 0xf9 +#define RADIO_2057_IPA5G_IAUX_CORE1 0xfa +#define RADIO_2057_IPA5G_GAIN_CORE1 0xfb +#define RADIO_2057_TSSI5G_SPARE1_CORE1 0xfc +#define RADIO_2057_TSSI5G_SPARE2_CORE1 0xfd +#define RADIO_2057_IPA5G_CASCOFFV_PU_CORE1 0xfe +#define RADIO_2057_IPA5G_PTAT_CORE1 0xff +#define RADIO_2057_IPA5G_IMAIN_CORE1 0x100 +#define RADIO_2057_IPA5G_CASCONV_CORE1 0x101 +#define RADIO_2057_IPA5G_BIAS_FILTER_CORE1 0x102 +#define RADIO_2057_PAD_BIAS_FILTER_BWS_CORE1 0x105 +#define RADIO_2057_TR2G_CONFIG1_CORE1_NU 0x106 +#define RADIO_2057_TR2G_CONFIG2_CORE1_NU 0x107 +#define RADIO_2057_LNA5G_RFEN_CORE1 0x108 +#define RADIO_2057_TR5G_CONFIG2_CORE1_NU 0x109 +#define RADIO_2057_RXRFBIAS_IBOOST_PU_CORE1 0x10a +#define RADIO_2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE1 0x10b +#define RADIO_2057_RXGM_CMFBITAIL_AUXPTAT_CORE1 0x10c +#define RADIO_2057_RXMIX_ICORE_RXGM_IAUX_CORE1 0x10d +#define RADIO_2057_RXMIX_CMFBITAIL_PU_CORE1 0x10e +#define RADIO_2057_LNA2_IMAIN_PTAT_PU_CORE1 0x10f +#define RADIO_2057_LNA2_IAUX_PTAT_CORE1 0x110 +#define RADIO_2057_LNA1_IMAIN_PTAT_PU_CORE1 0x111 +#define RADIO_2057_LNA15G_INPUT_MATCH_TUNE_CORE1 0x112 +#define RADIO_2057_RXRFBIAS_BANDSEL_CORE1 0x113 +#define RADIO_2057_TIA_CONFIG_CORE1 0x114 +#define RADIO_2057_TIA_IQGAIN_CORE1 0x115 +#define RADIO_2057_TIA_IBIAS2_CORE1 0x116 +#define RADIO_2057_TIA_IBIAS1_CORE1 0x117 +#define RADIO_2057_TIA_SPARE_Q_CORE1 0x118 +#define RADIO_2057_TIA_SPARE_I_CORE1 0x119 +#define RADIO_2057_RXMIX2G_PUS_CORE1 0x11a +#define RADIO_2057_RXMIX2G_VCMREFS_CORE1 0x11b +#define RADIO_2057_RXMIX2G_LODC_QI_CORE1 0x11c +#define RADIO_2057_W12G_BW_LNA2G_PUS_CORE1 0x11d +#define RADIO_2057_LNA2G_GAIN_CORE1 0x11e +#define RADIO_2057_LNA2G_TUNE_CORE1 0x11f +#define RADIO_2057_RXMIX5G_PUS_CORE1 0x120 +#define RADIO_2057_RXMIX5G_VCMREFS_CORE1 0x121 +#define RADIO_2057_RXMIX5G_LODC_QI_CORE1 0x122 +#define RADIO_2057_W15G_BW_LNA5G_PUS_CORE1 0x123 +#define RADIO_2057_LNA5G_GAIN_CORE1 0x124 +#define RADIO_2057_LNA5G_TUNE_CORE1 0x125 +#define RADIO_2057_LPFSEL_TXRX_RXBB_PUS_CORE1 0x126 +#define RADIO_2057_RXBB_BIAS_MASTER_CORE1 0x127 +#define RADIO_2057_RXBB_VGABUF_IDACS_CORE1 0x128 +#define RADIO_2057_LPF_VCMREF_TXBUF_VCMREF_CORE1 0x129 +#define RADIO_2057_TXBUF_VINCM_CORE1 0x12a +#define RADIO_2057_TXBUF_IDACS_CORE1 0x12b +#define RADIO_2057_LPF_RESP_RXBUF_BW_CORE1 0x12c +#define RADIO_2057_RXBB_CC_CORE1 0x12d +#define RADIO_2057_RXBB_SPARE3_CORE1 0x12e +#define RADIO_2057_RXBB_RCCAL_HPC_CORE1 0x12f +#define RADIO_2057_LPF_IDACS_CORE1 0x130 +#define RADIO_2057_LPFBYP_DCLOOP_BYP_IDAC_CORE1 0x131 +#define RADIO_2057_TXBUF_GAIN_CORE1 0x132 +#define RADIO_2057_AFELOOPBACK_AACI_RESP_CORE1 0x133 +#define RADIO_2057_RXBUF_DEGEN_CORE1 0x134 +#define RADIO_2057_RXBB_SPARE2_CORE1 0x135 +#define RADIO_2057_RXBB_SPARE1_CORE1 0x136 +#define RADIO_2057_RSSI_MASTER_CORE1 0x137 +#define RADIO_2057_W2_MASTER_CORE1 0x138 +#define RADIO_2057_NB_MASTER_CORE1 0x139 +#define RADIO_2057_W2_IDACS0_Q_CORE1 0x13a +#define RADIO_2057_W2_IDACS1_Q_CORE1 0x13b +#define RADIO_2057_W2_IDACS0_I_CORE1 0x13c +#define RADIO_2057_W2_IDACS1_I_CORE1 0x13d +#define RADIO_2057_RSSI_GPAIOSEL_W1_IDACS_CORE1 0x13e +#define RADIO_2057_NB_IDACS_Q_CORE1 0x13f +#define RADIO_2057_NB_IDACS_I_CORE1 0x140 +#define RADIO_2057_BACKUP4_CORE1 0x146 +#define RADIO_2057_BACKUP3_CORE1 0x147 +#define RADIO_2057_BACKUP2_CORE1 0x148 +#define RADIO_2057_BACKUP1_CORE1 0x149 +#define RADIO_2057_SPARE16_CORE1 0x14a +#define RADIO_2057_SPARE15_CORE1 0x14b +#define RADIO_2057_SPARE14_CORE1 0x14c +#define RADIO_2057_SPARE13_CORE1 0x14d +#define RADIO_2057_SPARE12_CORE1 0x14e +#define RADIO_2057_SPARE11_CORE1 0x14f +#define RADIO_2057_TX2G_BIAS_RESETS_CORE1 0x150 +#define RADIO_2057_TX5G_BIAS_RESETS_CORE1 0x151 +#define RADIO_2057_SPARE8_CORE1 0x152 +#define RADIO_2057_SPARE7_CORE1 0x153 +#define RADIO_2057_BUFS_MISC_LPFBW_CORE1 0x154 +#define RADIO_2057_TXLPF_RCCAL_CORE1 0x155 +#define RADIO_2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE1 0x156 +#define RADIO_2057_LPF_GAIN_CORE1 0x157 +#define RADIO_2057_DACBUF_IDACS_BW_CORE1 0x158 +#define RADIO_2057_DACBUF_VINCM_CORE1 0x159 +#define RADIO_2057_RCCAL_START_R1_Q1_P1 0x15a +#define RADIO_2057_RCCAL_X1 0x15b +#define RADIO_2057_RCCAL_TRC0 0x15c +#define RADIO_2057_RCCAL_TRC1 0x15d +#define RADIO_2057_RCCAL_DONE_OSCCAP 0x15e +#define RADIO_2057_RCCAL_N0_0 0x15f +#define RADIO_2057_RCCAL_N0_1 0x160 +#define RADIO_2057_RCCAL_N1_0 0x161 +#define RADIO_2057_RCCAL_N1_1 0x162 +#define RADIO_2057_RCAL_STATUS 0x163 +#define RADIO_2057_XTALPUOVR_PINCTRL 0x164 +#define RADIO_2057_OVR_REG0 0x165 +#define RADIO_2057_OVR_REG1 0x166 +#define RADIO_2057_OVR_REG2 0x167 +#define RADIO_2057_OVR_REG3 0x168 +#define RADIO_2057_OVR_REG4 0x169 +#define RADIO_2057_RCCAL_SCAP_VAL 0x16a +#define RADIO_2057_RCCAL_BCAP_VAL 0x16b +#define RADIO_2057_RCCAL_HPC_VAL 0x16c +#define RADIO_2057_RCCAL_OVERRIDES 0x16d +#define RADIO_2057_TX0_IQCAL_GAIN_BW 0x170 +#define RADIO_2057_TX0_LOFT_FINE_I 0x171 +#define RADIO_2057_TX0_LOFT_FINE_Q 0x172 +#define RADIO_2057_TX0_LOFT_COARSE_I 0x173 +#define RADIO_2057_TX0_LOFT_COARSE_Q 0x174 +#define RADIO_2057_TX0_TX_SSI_MASTER 0x175 +#define RADIO_2057_TX0_IQCAL_VCM_HG 0x176 +#define RADIO_2057_TX0_IQCAL_IDAC 0x177 +#define RADIO_2057_TX0_TSSI_VCM 0x178 +#define RADIO_2057_TX0_TX_SSI_MUX 0x179 +#define RADIO_2057_TX0_TSSIA 0x17a +#define RADIO_2057_TX0_TSSIG 0x17b +#define RADIO_2057_TX0_TSSI_MISC1 0x17c +#define RADIO_2057_TX0_TXRXCOUPLE_2G_ATTEN 0x17d +#define RADIO_2057_TX0_TXRXCOUPLE_2G_PWRUP 0x17e +#define RADIO_2057_TX0_TXRXCOUPLE_5G_ATTEN 0x17f +#define RADIO_2057_TX0_TXRXCOUPLE_5G_PWRUP 0x180 +#define RADIO_2057_TX1_IQCAL_GAIN_BW 0x190 +#define RADIO_2057_TX1_LOFT_FINE_I 0x191 +#define RADIO_2057_TX1_LOFT_FINE_Q 0x192 +#define RADIO_2057_TX1_LOFT_COARSE_I 0x193 +#define RADIO_2057_TX1_LOFT_COARSE_Q 0x194 +#define RADIO_2057_TX1_TX_SSI_MASTER 0x195 +#define RADIO_2057_TX1_IQCAL_VCM_HG 0x196 +#define RADIO_2057_TX1_IQCAL_IDAC 0x197 +#define RADIO_2057_TX1_TSSI_VCM 0x198 +#define RADIO_2057_TX1_TX_SSI_MUX 0x199 +#define RADIO_2057_TX1_TSSIA 0x19a +#define RADIO_2057_TX1_TSSIG 0x19b +#define RADIO_2057_TX1_TSSI_MISC1 0x19c +#define RADIO_2057_TX1_TXRXCOUPLE_2G_ATTEN 0x19d +#define RADIO_2057_TX1_TXRXCOUPLE_2G_PWRUP 0x19e +#define RADIO_2057_TX1_TXRXCOUPLE_5G_ATTEN 0x19f +#define RADIO_2057_TX1_TXRXCOUPLE_5G_PWRUP 0x1a0 +#define RADIO_2057_AFE_VCM_CAL_MASTER_CORE0 0x1a1 +#define RADIO_2057_AFE_SET_VCM_I_CORE0 0x1a2 +#define RADIO_2057_AFE_SET_VCM_Q_CORE0 0x1a3 +#define RADIO_2057_AFE_STATUS_VCM_IQADC_CORE0 0x1a4 +#define RADIO_2057_AFE_STATUS_VCM_I_CORE0 0x1a5 +#define RADIO_2057_AFE_STATUS_VCM_Q_CORE0 0x1a6 +#define RADIO_2057_AFE_VCM_CAL_MASTER_CORE1 0x1a7 +#define RADIO_2057_AFE_SET_VCM_I_CORE1 0x1a8 +#define RADIO_2057_AFE_SET_VCM_Q_CORE1 0x1a9 +#define RADIO_2057_AFE_STATUS_VCM_IQADC_CORE1 0x1aa +#define RADIO_2057_AFE_STATUS_VCM_I_CORE1 0x1ab +#define RADIO_2057_AFE_STATUS_VCM_Q_CORE1 0x1ac + +#define RADIO_2057v7_DACBUF_VINCM_CORE0 0x1ad +#define RADIO_2057v7_RCCAL_MASTER 0x1ae +#define RADIO_2057v7_TR2G_CONFIG3_CORE0_NU 0x1af +#define RADIO_2057v7_TR2G_CONFIG3_CORE1_NU 0x1b0 +#define RADIO_2057v7_LOGEN_PUS1 0x1b1 +#define RADIO_2057v7_OVR_REG5 0x1b2 +#define RADIO_2057v7_OVR_REG6 0x1b3 +#define RADIO_2057v7_OVR_REG7 0x1b4 +#define RADIO_2057v7_OVR_REG8 0x1b5 +#define RADIO_2057v7_OVR_REG9 0x1b6 +#define RADIO_2057v7_OVR_REG10 0x1b7 +#define RADIO_2057v7_OVR_REG11 0x1b8 +#define RADIO_2057v7_OVR_REG12 0x1b9 +#define RADIO_2057v7_OVR_REG13 0x1ba +#define RADIO_2057v7_OVR_REG14 0x1bb +#define RADIO_2057v7_OVR_REG15 0x1bc +#define RADIO_2057v7_OVR_REG16 0x1bd +#define RADIO_2057v7_OVR_REG1 0x1be +#define RADIO_2057v7_OVR_REG18 0x1bf +#define RADIO_2057v7_OVR_REG19 0x1c0 +#define RADIO_2057v7_OVR_REG20 0x1c1 +#define RADIO_2057v7_OVR_REG21 0x1c2 +#define RADIO_2057v7_OVR_REG2 0x1c3 +#define RADIO_2057v7_OVR_REG23 0x1c4 +#define RADIO_2057v7_OVR_REG24 0x1c5 +#define RADIO_2057v7_OVR_REG25 0x1c6 +#define RADIO_2057v7_OVR_REG26 0x1c7 +#define RADIO_2057v7_OVR_REG27 0x1c8 +#define RADIO_2057v7_OVR_REG28 0x1c9 +#define RADIO_2057v7_IQTEST_SEL_PU2 0x1ca + +#define RADIO_2057_VCM_MASK 0x7 + +#endif /* _BRCM_PHY_RADIO_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h new file mode 100644 index 000000000000..a97c3a799479 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phyreg_n.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +#define NPHY_TBL_ID_GAIN1 0 +#define NPHY_TBL_ID_GAIN2 1 +#define NPHY_TBL_ID_GAINBITS1 2 +#define NPHY_TBL_ID_GAINBITS2 3 +#define NPHY_TBL_ID_GAINLIMIT 4 +#define NPHY_TBL_ID_WRSSIGainLimit 5 +#define NPHY_TBL_ID_RFSEQ 7 +#define NPHY_TBL_ID_AFECTRL 8 +#define NPHY_TBL_ID_ANTSWCTRLLUT 9 +#define NPHY_TBL_ID_IQLOCAL 15 +#define NPHY_TBL_ID_NOISEVAR 16 +#define NPHY_TBL_ID_SAMPLEPLAY 17 +#define NPHY_TBL_ID_CORE1TXPWRCTL 26 +#define NPHY_TBL_ID_CORE2TXPWRCTL 27 +#define NPHY_TBL_ID_CMPMETRICDATAWEIGHTTBL 30 + +#define NPHY_TBL_ID_EPSILONTBL0 31 +#define NPHY_TBL_ID_SCALARTBL0 32 +#define NPHY_TBL_ID_EPSILONTBL1 33 +#define NPHY_TBL_ID_SCALARTBL1 34 + +#define NPHY_TO_BPHY_OFF 0xc00 + +#define NPHY_BandControl_currentBand 0x0001 +#define RFCC_CHIP0_PU 0x0400 +#define RFCC_POR_FORCE 0x0040 +#define RFCC_OE_POR_FORCE 0x0080 +#define NPHY_RfctrlIntc_override_OFF 0 +#define NPHY_RfctrlIntc_override_TRSW 1 +#define NPHY_RfctrlIntc_override_PA 2 +#define NPHY_RfctrlIntc_override_EXT_LNA_PU 3 +#define NPHY_RfctrlIntc_override_EXT_LNA_GAIN 4 +#define RIFS_ENABLE 0x80 +#define BPHY_BAND_SEL_UP20 0x10 +#define NPHY_MLenable 0x02 + +#define NPHY_RfseqMode_CoreActv_override 0x0001 +#define NPHY_RfseqMode_Trigger_override 0x0002 +#define NPHY_RfseqCoreActv_TxRxChain0 (0x11) +#define NPHY_RfseqCoreActv_TxRxChain1 (0x22) + +#define NPHY_RfseqTrigger_rx2tx 0x0001 +#define NPHY_RfseqTrigger_tx2rx 0x0002 +#define NPHY_RfseqTrigger_updategainh 0x0004 +#define NPHY_RfseqTrigger_updategainl 0x0008 +#define NPHY_RfseqTrigger_updategainu 0x0010 +#define NPHY_RfseqTrigger_reset2rx 0x0020 +#define NPHY_RfseqStatus_rx2tx 0x0001 +#define NPHY_RfseqStatus_tx2rx 0x0002 +#define NPHY_RfseqStatus_updategainh 0x0004 +#define NPHY_RfseqStatus_updategainl 0x0008 +#define NPHY_RfseqStatus_updategainu 0x0010 +#define NPHY_RfseqStatus_reset2rx 0x0020 +#define NPHY_ClassifierCtrl_cck_en 0x1 +#define NPHY_ClassifierCtrl_ofdm_en 0x2 +#define NPHY_ClassifierCtrl_waited_en 0x4 +#define NPHY_IQFlip_ADC1 0x0001 +#define NPHY_IQFlip_ADC2 0x0010 +#define NPHY_sampleCmd_STOP 0x0002 + +#define RX_GF_OR_MM 0x0004 +#define RX_GF_MM_AUTO 0x0100 + +#define NPHY_iqloCalCmdGctl_IQLO_CAL_EN 0x8000 + +#define NPHY_IqestCmd_iqstart 0x1 +#define NPHY_IqestCmd_iqMode 0x2 + +#define NPHY_TxPwrCtrlCmd_pwrIndex_init 0x40 +#define NPHY_TxPwrCtrlCmd_pwrIndex_init_rev7 0x19 + +#define PRIM_SEL_UP20 0x8000 + +#define NPHY_RFSEQ_RX2TX 0x0 +#define NPHY_RFSEQ_TX2RX 0x1 +#define NPHY_RFSEQ_RESET2RX 0x2 +#define NPHY_RFSEQ_UPDATEGAINH 0x3 +#define NPHY_RFSEQ_UPDATEGAINL 0x4 +#define NPHY_RFSEQ_UPDATEGAINU 0x5 + +#define NPHY_RFSEQ_CMD_NOP 0x0 +#define NPHY_RFSEQ_CMD_RXG_FBW 0x1 +#define NPHY_RFSEQ_CMD_TR_SWITCH 0x2 +#define NPHY_RFSEQ_CMD_EXT_PA 0x3 +#define NPHY_RFSEQ_CMD_RXPD_TXPD 0x4 +#define NPHY_RFSEQ_CMD_TX_GAIN 0x5 +#define NPHY_RFSEQ_CMD_RX_GAIN 0x6 +#define NPHY_RFSEQ_CMD_SET_HPF_BW 0x7 +#define NPHY_RFSEQ_CMD_CLR_HIQ_DIS 0x8 +#define NPHY_RFSEQ_CMD_END 0xf + +#define NPHY_REV3_RFSEQ_CMD_NOP 0x0 +#define NPHY_REV3_RFSEQ_CMD_RXG_FBW 0x1 +#define NPHY_REV3_RFSEQ_CMD_TR_SWITCH 0x2 +#define NPHY_REV3_RFSEQ_CMD_INT_PA_PU 0x3 +#define NPHY_REV3_RFSEQ_CMD_EXT_PA 0x4 +#define NPHY_REV3_RFSEQ_CMD_RXPD_TXPD 0x5 +#define NPHY_REV3_RFSEQ_CMD_TX_GAIN 0x6 +#define NPHY_REV3_RFSEQ_CMD_RX_GAIN 0x7 +#define NPHY_REV3_RFSEQ_CMD_CLR_HIQ_DIS 0x8 +#define NPHY_REV3_RFSEQ_CMD_SET_HPF_H_HPC 0x9 +#define NPHY_REV3_RFSEQ_CMD_SET_LPF_H_HPC 0xa +#define NPHY_REV3_RFSEQ_CMD_SET_HPF_M_HPC 0xb +#define NPHY_REV3_RFSEQ_CMD_SET_LPF_M_HPC 0xc +#define NPHY_REV3_RFSEQ_CMD_SET_HPF_L_HPC 0xd +#define NPHY_REV3_RFSEQ_CMD_SET_LPF_L_HPC 0xe +#define NPHY_REV3_RFSEQ_CMD_CLR_RXRX_BIAS 0xf +#define NPHY_REV3_RFSEQ_CMD_END 0x1f + +#define NPHY_RSSI_SEL_W1 0x0 +#define NPHY_RSSI_SEL_W2 0x1 +#define NPHY_RSSI_SEL_NB 0x2 +#define NPHY_RSSI_SEL_IQ 0x3 +#define NPHY_RSSI_SEL_TSSI_2G 0x4 +#define NPHY_RSSI_SEL_TSSI_5G 0x5 +#define NPHY_RSSI_SEL_TBD 0x6 + +#define NPHY_RAIL_I 0x0 +#define NPHY_RAIL_Q 0x1 + +#define NPHY_FORCESIG_DECODEGATEDCLKS 0x8 + +#define NPHY_REV7_RfctrlOverride_cmd_rxrf_pu 0x0 +#define NPHY_REV7_RfctrlOverride_cmd_rx_pu 0x1 +#define NPHY_REV7_RfctrlOverride_cmd_tx_pu 0x2 +#define NPHY_REV7_RfctrlOverride_cmd_rxgain 0x3 +#define NPHY_REV7_RfctrlOverride_cmd_txgain 0x4 + +#define NPHY_REV7_RXGAINCODE_RFMXGAIN_MASK 0x000ff +#define NPHY_REV7_RXGAINCODE_LPFGAIN_MASK 0x0ff00 +#define NPHY_REV7_RXGAINCODE_DVGAGAIN_MASK 0xf0000 + +#define NPHY_REV7_TXGAINCODE_TGAIN_MASK 0x7fff +#define NPHY_REV7_TXGAINCODE_LPFGAIN_MASK 0x8000 +#define NPHY_REV7_TXGAINCODE_BIQ0GAIN_SHIFT 14 + +#define NPHY_REV7_RFCTRLOVERRIDE_ID0 0x0 +#define NPHY_REV7_RFCTRLOVERRIDE_ID1 0x1 +#define NPHY_REV7_RFCTRLOVERRIDE_ID2 0x2 + +#define NPHY_IqestIqAccLo(core) ((core == 0) ? 0x12c : 0x134) + +#define NPHY_IqestIqAccHi(core) ((core == 0) ? 0x12d : 0x135) + +#define NPHY_IqestipwrAccLo(core) ((core == 0) ? 0x12e : 0x136) + +#define NPHY_IqestipwrAccHi(core) ((core == 0) ? 0x12f : 0x137) + +#define NPHY_IqestqpwrAccLo(core) ((core == 0) ? 0x130 : 0x138) + +#define NPHY_IqestqpwrAccHi(core) ((core == 0) ? 0x131 : 0x139) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c new file mode 100644 index 000000000000..622c01ca72c5 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.c @@ -0,0 +1,3250 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 <types.h> +#include "phytbl_lcn.h" + +static const u32 dot11lcn_gain_tbl_rev0[] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000004, + 0x00000000, + 0x00000004, + 0x00000008, + 0x00000001, + 0x00000005, + 0x00000009, + 0x0000000d, + 0x0000004d, + 0x0000008d, + 0x0000000d, + 0x0000004d, + 0x0000008d, + 0x000000cd, + 0x0000004f, + 0x0000008f, + 0x000000cf, + 0x000000d3, + 0x00000113, + 0x00000513, + 0x00000913, + 0x00000953, + 0x00000d53, + 0x00001153, + 0x00001193, + 0x00005193, + 0x00009193, + 0x0000d193, + 0x00011193, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000004, + 0x00000000, + 0x00000004, + 0x00000008, + 0x00000001, + 0x00000005, + 0x00000009, + 0x0000000d, + 0x0000004d, + 0x0000008d, + 0x0000000d, + 0x0000004d, + 0x0000008d, + 0x000000cd, + 0x0000004f, + 0x0000008f, + 0x000000cf, + 0x000000d3, + 0x00000113, + 0x00000513, + 0x00000913, + 0x00000953, + 0x00000d53, + 0x00001153, + 0x00005153, + 0x00009153, + 0x0000d153, + 0x00011153, + 0x00015153, + 0x00019153, + 0x0001d153, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 dot11lcn_gain_tbl_rev1[] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x00000004, + 0x00000008, + 0x00000001, + 0x00000005, + 0x00000009, + 0x0000000D, + 0x00000011, + 0x00000051, + 0x00000091, + 0x00000011, + 0x00000051, + 0x00000091, + 0x000000d1, + 0x00000053, + 0x00000093, + 0x000000d3, + 0x000000d7, + 0x00000117, + 0x00000517, + 0x00000917, + 0x00000957, + 0x00000d57, + 0x00001157, + 0x00001197, + 0x00005197, + 0x00009197, + 0x0000d197, + 0x00011197, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x00000004, + 0x00000008, + 0x00000001, + 0x00000005, + 0x00000009, + 0x0000000D, + 0x00000011, + 0x00000051, + 0x00000091, + 0x00000011, + 0x00000051, + 0x00000091, + 0x000000d1, + 0x00000053, + 0x00000093, + 0x000000d3, + 0x000000d7, + 0x00000117, + 0x00000517, + 0x00000917, + 0x00000957, + 0x00000d57, + 0x00001157, + 0x00005157, + 0x00009157, + 0x0000d157, + 0x00011157, + 0x00015157, + 0x00019157, + 0x0001d157, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u16 dot11lcn_aux_gain_idx_tbl_rev0[] = { + 0x0401, + 0x0402, + 0x0403, + 0x0404, + 0x0405, + 0x0406, + 0x0407, + 0x0408, + 0x0409, + 0x040a, + 0x058b, + 0x058c, + 0x058d, + 0x058e, + 0x058f, + 0x0090, + 0x0091, + 0x0092, + 0x0193, + 0x0194, + 0x0195, + 0x0196, + 0x0197, + 0x0198, + 0x0199, + 0x019a, + 0x019b, + 0x019c, + 0x019d, + 0x019e, + 0x019f, + 0x01a0, + 0x01a1, + 0x01a2, + 0x01a3, + 0x01a4, + 0x01a5, + 0x0000, +}; + +static const u32 dot11lcn_gain_idx_tbl_rev0[] = { + 0x00000000, + 0x00000000, + 0x10000000, + 0x00000000, + 0x20000000, + 0x00000000, + 0x30000000, + 0x00000000, + 0x40000000, + 0x00000000, + 0x50000000, + 0x00000000, + 0x60000000, + 0x00000000, + 0x70000000, + 0x00000000, + 0x80000000, + 0x00000000, + 0x90000000, + 0x00000008, + 0xa0000000, + 0x00000008, + 0xb0000000, + 0x00000008, + 0xc0000000, + 0x00000008, + 0xd0000000, + 0x00000008, + 0xe0000000, + 0x00000008, + 0xf0000000, + 0x00000008, + 0x00000000, + 0x00000009, + 0x10000000, + 0x00000009, + 0x20000000, + 0x00000019, + 0x30000000, + 0x00000019, + 0x40000000, + 0x00000019, + 0x50000000, + 0x00000019, + 0x60000000, + 0x00000019, + 0x70000000, + 0x00000019, + 0x80000000, + 0x00000019, + 0x90000000, + 0x00000019, + 0xa0000000, + 0x00000019, + 0xb0000000, + 0x00000019, + 0xc0000000, + 0x00000019, + 0xd0000000, + 0x00000019, + 0xe0000000, + 0x00000019, + 0xf0000000, + 0x00000019, + 0x00000000, + 0x0000001a, + 0x10000000, + 0x0000001a, + 0x20000000, + 0x0000001a, + 0x30000000, + 0x0000001a, + 0x40000000, + 0x0000001a, + 0x50000000, + 0x00000002, + 0x60000000, + 0x00000002, + 0x70000000, + 0x00000002, + 0x80000000, + 0x00000002, + 0x90000000, + 0x00000002, + 0xa0000000, + 0x00000002, + 0xb0000000, + 0x00000002, + 0xc0000000, + 0x0000000a, + 0xd0000000, + 0x0000000a, + 0xe0000000, + 0x0000000a, + 0xf0000000, + 0x0000000a, + 0x00000000, + 0x0000000b, + 0x10000000, + 0x0000000b, + 0x20000000, + 0x0000000b, + 0x30000000, + 0x0000000b, + 0x40000000, + 0x0000000b, + 0x50000000, + 0x0000001b, + 0x60000000, + 0x0000001b, + 0x70000000, + 0x0000001b, + 0x80000000, + 0x0000001b, + 0x90000000, + 0x0000001b, + 0xa0000000, + 0x0000001b, + 0xb0000000, + 0x0000001b, + 0xc0000000, + 0x0000001b, + 0xd0000000, + 0x0000001b, + 0xe0000000, + 0x0000001b, + 0xf0000000, + 0x0000001b, + 0x00000000, + 0x0000001c, + 0x10000000, + 0x0000001c, + 0x20000000, + 0x0000001c, + 0x30000000, + 0x0000001c, + 0x40000000, + 0x0000001c, + 0x50000000, + 0x0000001c, + 0x60000000, + 0x0000001c, + 0x70000000, + 0x0000001c, + 0x80000000, + 0x0000001c, + 0x90000000, + 0x0000001c, +}; + +static const u16 dot11lcn_aux_gain_idx_tbl_2G[] = { + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0001, + 0x0080, + 0x0081, + 0x0100, + 0x0101, + 0x0180, + 0x0181, + 0x0182, + 0x0183, + 0x0184, + 0x0185, + 0x0186, + 0x0187, + 0x0188, + 0x0285, + 0x0289, + 0x028a, + 0x028b, + 0x028c, + 0x028d, + 0x028e, + 0x028f, + 0x0290, + 0x0291, + 0x0292, + 0x0293, + 0x0294, + 0x0295, + 0x0296, + 0x0297, + 0x0298, + 0x0299, + 0x029a, + 0x0000 +}; + +static const u8 dot11lcn_gain_val_tbl_2G[] = { + 0xfc, + 0x02, + 0x08, + 0x0e, + 0x13, + 0x1b, + 0xfc, + 0x02, + 0x08, + 0x0e, + 0x13, + 0x1b, + 0xfc, + 0x00, + 0x0c, + 0x03, + 0xeb, + 0xfe, + 0x07, + 0x0b, + 0x0f, + 0xfb, + 0xfe, + 0x01, + 0x05, + 0x08, + 0x0b, + 0x0e, + 0x11, + 0x14, + 0x17, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x15, + 0x18, + 0x1b, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +static const u32 dot11lcn_gain_idx_tbl_2G[] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x10000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x10000000, + 0x00000008, + 0x00000000, + 0x00000010, + 0x10000000, + 0x00000010, + 0x00000000, + 0x00000018, + 0x10000000, + 0x00000018, + 0x20000000, + 0x00000018, + 0x30000000, + 0x00000018, + 0x40000000, + 0x00000018, + 0x50000000, + 0x00000018, + 0x60000000, + 0x00000018, + 0x70000000, + 0x00000018, + 0x80000000, + 0x00000018, + 0x50000000, + 0x00000028, + 0x90000000, + 0x00000028, + 0xa0000000, + 0x00000028, + 0xb0000000, + 0x00000028, + 0xc0000000, + 0x00000028, + 0xd0000000, + 0x00000028, + 0xe0000000, + 0x00000028, + 0xf0000000, + 0x00000028, + 0x00000000, + 0x00000029, + 0x10000000, + 0x00000029, + 0x20000000, + 0x00000029, + 0x30000000, + 0x00000029, + 0x40000000, + 0x00000029, + 0x50000000, + 0x00000029, + 0x60000000, + 0x00000029, + 0x70000000, + 0x00000029, + 0x80000000, + 0x00000029, + 0x90000000, + 0x00000029, + 0xa0000000, + 0x00000029, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x10000000, + 0x00000000, + 0x00000000, + 0x00000008, + 0x10000000, + 0x00000008, + 0x00000000, + 0x00000010, + 0x10000000, + 0x00000010, + 0x00000000, + 0x00000018, + 0x10000000, + 0x00000018, + 0x20000000, + 0x00000018, + 0x30000000, + 0x00000018, + 0x40000000, + 0x00000018, + 0x50000000, + 0x00000018, + 0x60000000, + 0x00000018, + 0x70000000, + 0x00000018, + 0x80000000, + 0x00000018, + 0x50000000, + 0x00000028, + 0x90000000, + 0x00000028, + 0xa0000000, + 0x00000028, + 0xb0000000, + 0x00000028, + 0xc0000000, + 0x00000028, + 0xd0000000, + 0x00000028, + 0xe0000000, + 0x00000028, + 0xf0000000, + 0x00000028, + 0x00000000, + 0x00000029, + 0x10000000, + 0x00000029, + 0x20000000, + 0x00000029, + 0x30000000, + 0x00000029, + 0x40000000, + 0x00000029, + 0x50000000, + 0x00000029, + 0x60000000, + 0x00000029, + 0x70000000, + 0x00000029, + 0x80000000, + 0x00000029, + 0x90000000, + 0x00000029, + 0xa0000000, + 0x00000029, + 0xb0000000, + 0x00000029, + 0xc0000000, + 0x00000029, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static const u32 dot11lcn_gain_tbl_2G[] = { + 0x00000000, + 0x00000004, + 0x00000008, + 0x00000001, + 0x00000005, + 0x00000009, + 0x0000000d, + 0x0000004d, + 0x0000008d, + 0x00000049, + 0x00000089, + 0x000000c9, + 0x0000004b, + 0x0000008b, + 0x000000cb, + 0x000000cf, + 0x0000010f, + 0x0000050f, + 0x0000090f, + 0x0000094f, + 0x00000d4f, + 0x0000114f, + 0x0000118f, + 0x0000518f, + 0x0000918f, + 0x0000d18f, + 0x0001118f, + 0x0001518f, + 0x0001918f, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static const u32 dot11lcn_gain_tbl_extlna_2G[] = { + 0x00000000, + 0x00000004, + 0x00000008, + 0x00000001, + 0x00000005, + 0x00000009, + 0x0000000d, + 0x00000003, + 0x00000007, + 0x0000000b, + 0x0000000f, + 0x0000004f, + 0x0000008f, + 0x000000cf, + 0x0000010f, + 0x0000014f, + 0x0000018f, + 0x0000058f, + 0x0000098f, + 0x00000d8f, + 0x00008000, + 0x00008004, + 0x00008008, + 0x00008001, + 0x00008005, + 0x00008009, + 0x0000800d, + 0x00008003, + 0x00008007, + 0x0000800b, + 0x0000800f, + 0x0000804f, + 0x0000808f, + 0x000080cf, + 0x0000810f, + 0x0000814f, + 0x0000818f, + 0x0000858f, + 0x0000898f, + 0x00008d8f, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static const u16 dot11lcn_aux_gain_idx_tbl_extlna_2G[] = { + 0x0400, + 0x0400, + 0x0400, + 0x0400, + 0x0400, + 0x0400, + 0x0400, + 0x0400, + 0x0400, + 0x0401, + 0x0402, + 0x0403, + 0x0404, + 0x0483, + 0x0484, + 0x0485, + 0x0486, + 0x0583, + 0x0584, + 0x0585, + 0x0587, + 0x0588, + 0x0589, + 0x058a, + 0x0687, + 0x0688, + 0x0689, + 0x068a, + 0x068b, + 0x068c, + 0x068d, + 0x068e, + 0x068f, + 0x0690, + 0x0691, + 0x0692, + 0x0693, + 0x0000 +}; + +static const u8 dot11lcn_gain_val_tbl_extlna_2G[] = { + 0xfc, + 0x02, + 0x08, + 0x0e, + 0x13, + 0x1b, + 0xfc, + 0x02, + 0x08, + 0x0e, + 0x13, + 0x1b, + 0xfc, + 0x00, + 0x0f, + 0x03, + 0xeb, + 0xfe, + 0x07, + 0x0b, + 0x0f, + 0xfb, + 0xfe, + 0x01, + 0x05, + 0x08, + 0x0b, + 0x0e, + 0x11, + 0x14, + 0x17, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x15, + 0x18, + 0x1b, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +static const u32 dot11lcn_gain_idx_tbl_extlna_2G[] = { + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000040, + 0x00000000, + 0x00000040, + 0x10000000, + 0x00000040, + 0x20000000, + 0x00000040, + 0x30000000, + 0x00000040, + 0x40000000, + 0x00000040, + 0x30000000, + 0x00000048, + 0x40000000, + 0x00000048, + 0x50000000, + 0x00000048, + 0x60000000, + 0x00000048, + 0x30000000, + 0x00000058, + 0x40000000, + 0x00000058, + 0x50000000, + 0x00000058, + 0x70000000, + 0x00000058, + 0x80000000, + 0x00000058, + 0x90000000, + 0x00000058, + 0xa0000000, + 0x00000058, + 0x70000000, + 0x00000068, + 0x80000000, + 0x00000068, + 0x90000000, + 0x00000068, + 0xa0000000, + 0x00000068, + 0xb0000000, + 0x00000068, + 0xc0000000, + 0x00000068, + 0xd0000000, + 0x00000068, + 0xe0000000, + 0x00000068, + 0xf0000000, + 0x00000068, + 0x00000000, + 0x00000069, + 0x10000000, + 0x00000069, + 0x20000000, + 0x00000069, + 0x30000000, + 0x00000069, + 0x40000000, + 0x00000041, + 0x40000000, + 0x00000041, + 0x40000000, + 0x00000041, + 0x40000000, + 0x00000041, + 0x40000000, + 0x00000041, + 0x40000000, + 0x00000041, + 0x40000000, + 0x00000041, + 0x40000000, + 0x00000041, + 0x40000000, + 0x00000041, + 0x50000000, + 0x00000041, + 0x60000000, + 0x00000041, + 0x70000000, + 0x00000041, + 0x80000000, + 0x00000041, + 0x70000000, + 0x00000049, + 0x80000000, + 0x00000049, + 0x90000000, + 0x00000049, + 0xa0000000, + 0x00000049, + 0x70000000, + 0x00000059, + 0x80000000, + 0x00000059, + 0x90000000, + 0x00000059, + 0xb0000000, + 0x00000059, + 0xc0000000, + 0x00000059, + 0xd0000000, + 0x00000059, + 0xe0000000, + 0x00000059, + 0xb0000000, + 0x00000069, + 0xc0000000, + 0x00000069, + 0xd0000000, + 0x00000069, + 0xe0000000, + 0x00000069, + 0xf0000000, + 0x00000069, + 0x00000000, + 0x0000006a, + 0x10000000, + 0x0000006a, + 0x20000000, + 0x0000006a, + 0x30000000, + 0x0000006a, + 0x40000000, + 0x0000006a, + 0x50000000, + 0x0000006a, + 0x60000000, + 0x0000006a, + 0x70000000, + 0x0000006a, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static const u32 dot11lcn_aux_gain_idx_tbl_5G[] = { + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0001, + 0x0002, + 0x0003, + 0x0004, + 0x0083, + 0x0084, + 0x0085, + 0x0086, + 0x0087, + 0x0186, + 0x0187, + 0x0188, + 0x0189, + 0x018a, + 0x018b, + 0x018c, + 0x018d, + 0x018e, + 0x018f, + 0x0190, + 0x0191, + 0x0192, + 0x0193, + 0x0194, + 0x0195, + 0x0196, + 0x0197, + 0x0198, + 0x0199, + 0x019a, + 0x019b, + 0x019c, + 0x019d, + 0x0000 +}; + +static const u32 dot11lcn_gain_val_tbl_5G[] = { + 0xf7, + 0xfd, + 0x00, + 0x04, + 0x04, + 0x04, + 0xf7, + 0xfd, + 0x00, + 0x04, + 0x04, + 0x04, + 0xf6, + 0x00, + 0x0c, + 0x03, + 0xeb, + 0xfe, + 0x06, + 0x0a, + 0x10, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x15, + 0x18, + 0x1b, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x15, + 0x18, + 0x1b, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00 +}; + +static const u32 dot11lcn_gain_idx_tbl_5G[] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x10000000, + 0x00000000, + 0x20000000, + 0x00000000, + 0x30000000, + 0x00000000, + 0x40000000, + 0x00000000, + 0x30000000, + 0x00000008, + 0x40000000, + 0x00000008, + 0x50000000, + 0x00000008, + 0x60000000, + 0x00000008, + 0x70000000, + 0x00000008, + 0x60000000, + 0x00000018, + 0x70000000, + 0x00000018, + 0x80000000, + 0x00000018, + 0x90000000, + 0x00000018, + 0xa0000000, + 0x00000018, + 0xb0000000, + 0x00000018, + 0xc0000000, + 0x00000018, + 0xd0000000, + 0x00000018, + 0xe0000000, + 0x00000018, + 0xf0000000, + 0x00000018, + 0x00000000, + 0x00000019, + 0x10000000, + 0x00000019, + 0x20000000, + 0x00000019, + 0x30000000, + 0x00000019, + 0x40000000, + 0x00000019, + 0x50000000, + 0x00000019, + 0x60000000, + 0x00000019, + 0x70000000, + 0x00000019, + 0x80000000, + 0x00000019, + 0x90000000, + 0x00000019, + 0xa0000000, + 0x00000019, + 0xb0000000, + 0x00000019, + 0xc0000000, + 0x00000019, + 0xd0000000, + 0x00000019, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +static const u32 dot11lcn_gain_tbl_5G[] = { + 0x00000000, + 0x00000040, + 0x00000080, + 0x00000001, + 0x00000005, + 0x00000009, + 0x0000000d, + 0x00000011, + 0x00000015, + 0x00000055, + 0x00000095, + 0x00000017, + 0x0000001b, + 0x0000005b, + 0x0000009b, + 0x000000db, + 0x0000011b, + 0x0000015b, + 0x0000019b, + 0x0000059b, + 0x0000099b, + 0x00000d9b, + 0x0000119b, + 0x0000519b, + 0x0000919b, + 0x0000d19b, + 0x0001119b, + 0x0001519b, + 0x0001919b, + 0x0001d19b, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; + +const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[] = { + {&dot11lcn_gain_tbl_rev0, + sizeof(dot11lcn_gain_tbl_rev0) / sizeof(dot11lcn_gain_tbl_rev0[0]), 18, + 0, 32} + , + {&dot11lcn_aux_gain_idx_tbl_rev0, + sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / + sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} + , + {&dot11lcn_gain_idx_tbl_rev0, + sizeof(dot11lcn_gain_idx_tbl_rev0) / + sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} + , +}; + +static const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev1[] = { + {&dot11lcn_gain_tbl_rev1, + sizeof(dot11lcn_gain_tbl_rev1) / sizeof(dot11lcn_gain_tbl_rev1[0]), 18, + 0, 32} + , + {&dot11lcn_aux_gain_idx_tbl_rev0, + sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / + sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} + , + {&dot11lcn_gain_idx_tbl_rev0, + sizeof(dot11lcn_gain_idx_tbl_rev0) / + sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} + , +}; + +const struct phytbl_info dot11lcnphytbl_rx_gain_info_2G_rev2[] = { + {&dot11lcn_gain_tbl_2G, + sizeof(dot11lcn_gain_tbl_2G) / sizeof(dot11lcn_gain_tbl_2G[0]), 18, 0, + 32} + , + {&dot11lcn_aux_gain_idx_tbl_2G, + sizeof(dot11lcn_aux_gain_idx_tbl_2G) / + sizeof(dot11lcn_aux_gain_idx_tbl_2G[0]), 14, 0, 16} + , + {&dot11lcn_gain_idx_tbl_2G, + sizeof(dot11lcn_gain_idx_tbl_2G) / sizeof(dot11lcn_gain_idx_tbl_2G[0]), + 13, 0, 32} + , + {&dot11lcn_gain_val_tbl_2G, + sizeof(dot11lcn_gain_val_tbl_2G) / sizeof(dot11lcn_gain_val_tbl_2G[0]), + 17, 0, 8} +}; + +const struct phytbl_info dot11lcnphytbl_rx_gain_info_5G_rev2[] = { + {&dot11lcn_gain_tbl_5G, + sizeof(dot11lcn_gain_tbl_5G) / sizeof(dot11lcn_gain_tbl_5G[0]), 18, 0, + 32} + , + {&dot11lcn_aux_gain_idx_tbl_5G, + sizeof(dot11lcn_aux_gain_idx_tbl_5G) / + sizeof(dot11lcn_aux_gain_idx_tbl_5G[0]), 14, 0, 16} + , + {&dot11lcn_gain_idx_tbl_5G, + sizeof(dot11lcn_gain_idx_tbl_5G) / sizeof(dot11lcn_gain_idx_tbl_5G[0]), + 13, 0, 32} + , + {&dot11lcn_gain_val_tbl_5G, + sizeof(dot11lcn_gain_val_tbl_5G) / sizeof(dot11lcn_gain_val_tbl_5G[0]), + 17, 0, 8} +}; + +const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_2G_rev2[] = { + {&dot11lcn_gain_tbl_extlna_2G, + sizeof(dot11lcn_gain_tbl_extlna_2G) / + sizeof(dot11lcn_gain_tbl_extlna_2G[0]), 18, 0, 32} + , + {&dot11lcn_aux_gain_idx_tbl_extlna_2G, + sizeof(dot11lcn_aux_gain_idx_tbl_extlna_2G) / + sizeof(dot11lcn_aux_gain_idx_tbl_extlna_2G[0]), 14, 0, 16} + , + {&dot11lcn_gain_idx_tbl_extlna_2G, + sizeof(dot11lcn_gain_idx_tbl_extlna_2G) / + sizeof(dot11lcn_gain_idx_tbl_extlna_2G[0]), 13, 0, 32} + , + {&dot11lcn_gain_val_tbl_extlna_2G, + sizeof(dot11lcn_gain_val_tbl_extlna_2G) / + sizeof(dot11lcn_gain_val_tbl_extlna_2G[0]), 17, 0, 8} +}; + +const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_5G_rev2[] = { + {&dot11lcn_gain_tbl_5G, + sizeof(dot11lcn_gain_tbl_5G) / sizeof(dot11lcn_gain_tbl_5G[0]), 18, 0, + 32} + , + {&dot11lcn_aux_gain_idx_tbl_5G, + sizeof(dot11lcn_aux_gain_idx_tbl_5G) / + sizeof(dot11lcn_aux_gain_idx_tbl_5G[0]), 14, 0, 16} + , + {&dot11lcn_gain_idx_tbl_5G, + sizeof(dot11lcn_gain_idx_tbl_5G) / sizeof(dot11lcn_gain_idx_tbl_5G[0]), + 13, 0, 32} + , + {&dot11lcn_gain_val_tbl_5G, + sizeof(dot11lcn_gain_val_tbl_5G) / sizeof(dot11lcn_gain_val_tbl_5G[0]), + 17, 0, 8} +}; + +const u32 dot11lcnphytbl_rx_gain_info_sz_rev0 = + sizeof(dot11lcnphytbl_rx_gain_info_rev0) / + sizeof(dot11lcnphytbl_rx_gain_info_rev0[0]); + +const u32 dot11lcnphytbl_rx_gain_info_2G_rev2_sz = + sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2) / + sizeof(dot11lcnphytbl_rx_gain_info_2G_rev2[0]); + +const u32 dot11lcnphytbl_rx_gain_info_5G_rev2_sz = + sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2) / + sizeof(dot11lcnphytbl_rx_gain_info_5G_rev2[0]); + +static const u16 dot11lcn_min_sig_sq_tbl_rev0[] = { + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, + 0x014d, +}; + +static const u16 dot11lcn_noise_scale_tbl_rev0[] = { + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, +}; + +static const u32 dot11lcn_fltr_ctrl_tbl_rev0[] = { + 0x000141f8, + 0x000021f8, + 0x000021fb, + 0x000041fb, + 0x0001fe4b, + 0x0000217b, + 0x00002133, + 0x000040eb, + 0x0001fea3, + 0x0000024b, +}; + +static const u32 dot11lcn_ps_ctrl_tbl_rev0[] = { + 0x00100001, + 0x00200010, + 0x00300001, + 0x00400010, + 0x00500022, + 0x00600122, + 0x00700222, + 0x00800322, + 0x00900422, + 0x00a00522, + 0x00b00622, + 0x00c00722, + 0x00d00822, + 0x00f00922, + 0x00100a22, + 0x00200b22, + 0x00300c22, + 0x00400d22, + 0x00500e22, + 0x00600f22, +}; + +static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[] = { + 0x0007, + 0x0005, + 0x0006, + 0x0004, + 0x0007, + 0x0005, + 0x0006, + 0x0004, + 0x0007, + 0x0005, + 0x0006, + 0x0004, + 0x0007, + 0x0005, + 0x0006, + 0x0004, + 0x000b, + 0x000b, + 0x000a, + 0x000a, + 0x000b, + 0x000b, + 0x000a, + 0x000a, + 0x000b, + 0x000b, + 0x000a, + 0x000a, + 0x000b, + 0x000b, + 0x000a, + 0x000a, + 0x0007, + 0x0005, + 0x0006, + 0x0004, + 0x0007, + 0x0005, + 0x0006, + 0x0004, + 0x0007, + 0x0005, + 0x0006, + 0x0004, + 0x0007, + 0x0005, + 0x0006, + 0x0004, + 0x000b, + 0x000b, + 0x000a, + 0x000a, + 0x000b, + 0x000b, + 0x000a, + 0x000a, + 0x000b, + 0x000b, + 0x000a, + 0x000a, + 0x000b, + 0x000b, + 0x000a, + 0x000a, + +}; + +static const u16 dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[] = { + 0x0007, + 0x0005, + 0x0002, + 0x0000, + 0x0007, + 0x0005, + 0x0002, + 0x0000, + 0x0007, + 0x0005, + 0x0002, + 0x0000, + 0x0007, + 0x0005, + 0x0002, + 0x0000, + 0x0007, + 0x0007, + 0x0002, + 0x0002, + 0x0007, + 0x0007, + 0x0002, + 0x0002, + 0x0007, + 0x0007, + 0x0002, + 0x0002, + 0x0007, + 0x0007, + 0x0002, + 0x0002, + 0x0007, + 0x0005, + 0x0002, + 0x0000, + 0x0007, + 0x0005, + 0x0002, + 0x0000, + 0x0007, + 0x0005, + 0x0002, + 0x0000, + 0x0007, + 0x0005, + 0x0002, + 0x0000, + 0x0007, + 0x0007, + 0x0002, + 0x0002, + 0x0007, + 0x0007, + 0x0002, + 0x0002, + 0x0007, + 0x0007, + 0x0002, + 0x0002, + 0x0007, + 0x0007, + 0x0002, + 0x0002, +}; + +static const u16 dot11lcn_sw_ctrl_tbl_4313_epa_rev0[] = { + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, + 0x0002, + 0x0008, + 0x0004, + 0x0001, +}; + +static const u16 dot11lcn_sw_ctrl_tbl_4313_rev0[] = { + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, + 0x000a, + 0x0009, + 0x0006, + 0x0005, +}; + +static const u16 dot11lcn_sw_ctrl_tbl_rev0[] = { + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, + 0x0004, + 0x0004, + 0x0002, + 0x0002, +}; + +static const u8 dot11lcn_nf_table_rev0[] = { + 0x5f, + 0x36, + 0x29, + 0x1f, + 0x5f, + 0x36, + 0x29, + 0x1f, + 0x5f, + 0x36, + 0x29, + 0x1f, + 0x5f, + 0x36, + 0x29, + 0x1f, +}; + +static const u8 dot11lcn_gain_val_tbl_rev0[] = { + 0x09, + 0x0f, + 0x14, + 0x18, + 0xfe, + 0x07, + 0x0b, + 0x0f, + 0xfb, + 0xfe, + 0x01, + 0x05, + 0x08, + 0x0b, + 0x0e, + 0x11, + 0x14, + 0x17, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0x06, + 0x09, + 0x0c, + 0x0f, + 0x12, + 0x15, + 0x18, + 0x1b, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x03, + 0xeb, + 0x00, + 0x00, +}; + +static const u8 dot11lcn_spur_tbl_rev0[] = { + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x02, + 0x03, + 0x01, + 0x03, + 0x02, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x02, + 0x03, + 0x01, + 0x03, + 0x02, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, + 0x01, +}; + +static const u16 dot11lcn_unsup_mcs_tbl_rev0[] = { + 0x001a, + 0x0034, + 0x004e, + 0x0068, + 0x009c, + 0x00d0, + 0x00ea, + 0x0104, + 0x0034, + 0x0068, + 0x009c, + 0x00d0, + 0x0138, + 0x01a0, + 0x01d4, + 0x0208, + 0x004e, + 0x009c, + 0x00ea, + 0x0138, + 0x01d4, + 0x0270, + 0x02be, + 0x030c, + 0x0068, + 0x00d0, + 0x0138, + 0x01a0, + 0x0270, + 0x0340, + 0x03a8, + 0x0410, + 0x0018, + 0x009c, + 0x00d0, + 0x0104, + 0x00ea, + 0x0138, + 0x0186, + 0x00d0, + 0x0104, + 0x0104, + 0x0138, + 0x016c, + 0x016c, + 0x01a0, + 0x0138, + 0x0186, + 0x0186, + 0x01d4, + 0x0222, + 0x0222, + 0x0270, + 0x0104, + 0x0138, + 0x016c, + 0x0138, + 0x016c, + 0x01a0, + 0x01d4, + 0x01a0, + 0x01d4, + 0x0208, + 0x0208, + 0x023c, + 0x0186, + 0x01d4, + 0x0222, + 0x01d4, + 0x0222, + 0x0270, + 0x02be, + 0x0270, + 0x02be, + 0x030c, + 0x030c, + 0x035a, + 0x0036, + 0x006c, + 0x00a2, + 0x00d8, + 0x0144, + 0x01b0, + 0x01e6, + 0x021c, + 0x006c, + 0x00d8, + 0x0144, + 0x01b0, + 0x0288, + 0x0360, + 0x03cc, + 0x0438, + 0x00a2, + 0x0144, + 0x01e6, + 0x0288, + 0x03cc, + 0x0510, + 0x05b2, + 0x0654, + 0x00d8, + 0x01b0, + 0x0288, + 0x0360, + 0x0510, + 0x06c0, + 0x0798, + 0x0870, + 0x0018, + 0x0144, + 0x01b0, + 0x021c, + 0x01e6, + 0x0288, + 0x032a, + 0x01b0, + 0x021c, + 0x021c, + 0x0288, + 0x02f4, + 0x02f4, + 0x0360, + 0x0288, + 0x032a, + 0x032a, + 0x03cc, + 0x046e, + 0x046e, + 0x0510, + 0x021c, + 0x0288, + 0x02f4, + 0x0288, + 0x02f4, + 0x0360, + 0x03cc, + 0x0360, + 0x03cc, + 0x0438, + 0x0438, + 0x04a4, + 0x032a, + 0x03cc, + 0x046e, + 0x03cc, + 0x046e, + 0x0510, + 0x05b2, + 0x0510, + 0x05b2, + 0x0654, + 0x0654, + 0x06f6, +}; + +static const u16 dot11lcn_iq_local_tbl_rev0[] = { + 0x0200, + 0x0300, + 0x0400, + 0x0600, + 0x0800, + 0x0b00, + 0x1000, + 0x1001, + 0x1002, + 0x1003, + 0x1004, + 0x1005, + 0x1006, + 0x1007, + 0x1707, + 0x2007, + 0x2d07, + 0x4007, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0200, + 0x0300, + 0x0400, + 0x0600, + 0x0800, + 0x0b00, + 0x1000, + 0x1001, + 0x1002, + 0x1003, + 0x1004, + 0x1005, + 0x1006, + 0x1007, + 0x1707, + 0x2007, + 0x2d07, + 0x4007, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x4000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, +}; + +static const u32 dot11lcn_papd_compdelta_tbl_rev0[] = { + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, + 0x00080000, +}; + +const struct phytbl_info dot11lcnphytbl_info_rev0[] = { + {&dot11lcn_min_sig_sq_tbl_rev0, + sizeof(dot11lcn_min_sig_sq_tbl_rev0) / + sizeof(dot11lcn_min_sig_sq_tbl_rev0[0]), 2, 0, 16} + , + {&dot11lcn_noise_scale_tbl_rev0, + sizeof(dot11lcn_noise_scale_tbl_rev0) / + sizeof(dot11lcn_noise_scale_tbl_rev0[0]), 1, 0, 16} + , + {&dot11lcn_fltr_ctrl_tbl_rev0, + sizeof(dot11lcn_fltr_ctrl_tbl_rev0) / + sizeof(dot11lcn_fltr_ctrl_tbl_rev0[0]), 11, 0, 32} + , + {&dot11lcn_ps_ctrl_tbl_rev0, + sizeof(dot11lcn_ps_ctrl_tbl_rev0) / + sizeof(dot11lcn_ps_ctrl_tbl_rev0[0]), 12, 0, 32} + , + {&dot11lcn_gain_idx_tbl_rev0, + sizeof(dot11lcn_gain_idx_tbl_rev0) / + sizeof(dot11lcn_gain_idx_tbl_rev0[0]), 13, 0, 32} + , + {&dot11lcn_aux_gain_idx_tbl_rev0, + sizeof(dot11lcn_aux_gain_idx_tbl_rev0) / + sizeof(dot11lcn_aux_gain_idx_tbl_rev0[0]), 14, 0, 16} + , + {&dot11lcn_sw_ctrl_tbl_rev0, + sizeof(dot11lcn_sw_ctrl_tbl_rev0) / + sizeof(dot11lcn_sw_ctrl_tbl_rev0[0]), 15, 0, 16} + , + {&dot11lcn_nf_table_rev0, + sizeof(dot11lcn_nf_table_rev0) / sizeof(dot11lcn_nf_table_rev0[0]), 16, + 0, 8} + , + {&dot11lcn_gain_val_tbl_rev0, + sizeof(dot11lcn_gain_val_tbl_rev0) / + sizeof(dot11lcn_gain_val_tbl_rev0[0]), 17, 0, 8} + , + {&dot11lcn_gain_tbl_rev0, + sizeof(dot11lcn_gain_tbl_rev0) / sizeof(dot11lcn_gain_tbl_rev0[0]), 18, + 0, 32} + , + {&dot11lcn_spur_tbl_rev0, + sizeof(dot11lcn_spur_tbl_rev0) / sizeof(dot11lcn_spur_tbl_rev0[0]), 20, + 0, 8} + , + {&dot11lcn_unsup_mcs_tbl_rev0, + sizeof(dot11lcn_unsup_mcs_tbl_rev0) / + sizeof(dot11lcn_unsup_mcs_tbl_rev0[0]), 23, 0, 16} + , + {&dot11lcn_iq_local_tbl_rev0, + sizeof(dot11lcn_iq_local_tbl_rev0) / + sizeof(dot11lcn_iq_local_tbl_rev0[0]), 0, 0, 16} + , + {&dot11lcn_papd_compdelta_tbl_rev0, + sizeof(dot11lcn_papd_compdelta_tbl_rev0) / + sizeof(dot11lcn_papd_compdelta_tbl_rev0[0]), 24, 0, 32} + , +}; + +const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313 = { + &dot11lcn_sw_ctrl_tbl_4313_rev0, + sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0) / + sizeof(dot11lcn_sw_ctrl_tbl_4313_rev0[0]), 15, 0, 16 +}; + +const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa = { + &dot11lcn_sw_ctrl_tbl_4313_epa_rev0, + sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0) / + sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0[0]), 15, 0, 16 +}; + +const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa = { + &dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo, + sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo) / + sizeof(dot11lcn_sw_ctrl_tbl_4313_epa_rev0_combo[0]), 15, 0, 16 +}; + +const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250 = { + &dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0, + sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0) / + sizeof(dot11lcn_sw_ctrl_tbl_4313_bt_epa_p250_rev0[0]), 15, 0, 16 +}; + +const u32 dot11lcnphytbl_info_sz_rev0 = + sizeof(dot11lcnphytbl_info_rev0) / sizeof(dot11lcnphytbl_info_rev0[0]); + +const struct lcnphy_tx_gain_tbl_entry +dot11lcnphy_2GHz_extPA_gaintable_rev0[128] = { + {3, 0, 31, 0, 72}, + {3, 0, 31, 0, 70}, + {3, 0, 31, 0, 68}, + {3, 0, 30, 0, 67}, + {3, 0, 29, 0, 68}, + {3, 0, 28, 0, 68}, + {3, 0, 27, 0, 69}, + {3, 0, 26, 0, 70}, + {3, 0, 25, 0, 70}, + {3, 0, 24, 0, 71}, + {3, 0, 23, 0, 72}, + {3, 0, 23, 0, 70}, + {3, 0, 22, 0, 71}, + {3, 0, 21, 0, 72}, + {3, 0, 21, 0, 70}, + {3, 0, 21, 0, 68}, + {3, 0, 21, 0, 66}, + {3, 0, 21, 0, 64}, + {3, 0, 21, 0, 63}, + {3, 0, 20, 0, 64}, + {3, 0, 19, 0, 65}, + {3, 0, 19, 0, 64}, + {3, 0, 18, 0, 65}, + {3, 0, 18, 0, 64}, + {3, 0, 17, 0, 65}, + {3, 0, 17, 0, 64}, + {3, 0, 16, 0, 65}, + {3, 0, 16, 0, 64}, + {3, 0, 16, 0, 62}, + {3, 0, 16, 0, 60}, + {3, 0, 16, 0, 58}, + {3, 0, 15, 0, 61}, + {3, 0, 15, 0, 59}, + {3, 0, 14, 0, 61}, + {3, 0, 14, 0, 60}, + {3, 0, 14, 0, 58}, + {3, 0, 13, 0, 60}, + {3, 0, 13, 0, 59}, + {3, 0, 12, 0, 62}, + {3, 0, 12, 0, 60}, + {3, 0, 12, 0, 58}, + {3, 0, 11, 0, 62}, + {3, 0, 11, 0, 60}, + {3, 0, 11, 0, 59}, + {3, 0, 11, 0, 57}, + {3, 0, 10, 0, 61}, + {3, 0, 10, 0, 59}, + {3, 0, 10, 0, 57}, + {3, 0, 9, 0, 62}, + {3, 0, 9, 0, 60}, + {3, 0, 9, 0, 58}, + {3, 0, 9, 0, 57}, + {3, 0, 8, 0, 62}, + {3, 0, 8, 0, 60}, + {3, 0, 8, 0, 58}, + {3, 0, 8, 0, 57}, + {3, 0, 8, 0, 55}, + {3, 0, 7, 0, 61}, + {3, 0, 7, 0, 60}, + {3, 0, 7, 0, 58}, + {3, 0, 7, 0, 56}, + {3, 0, 7, 0, 55}, + {3, 0, 6, 0, 62}, + {3, 0, 6, 0, 60}, + {3, 0, 6, 0, 58}, + {3, 0, 6, 0, 57}, + {3, 0, 6, 0, 55}, + {3, 0, 6, 0, 54}, + {3, 0, 6, 0, 52}, + {3, 0, 5, 0, 61}, + {3, 0, 5, 0, 59}, + {3, 0, 5, 0, 57}, + {3, 0, 5, 0, 56}, + {3, 0, 5, 0, 54}, + {3, 0, 5, 0, 53}, + {3, 0, 5, 0, 51}, + {3, 0, 4, 0, 62}, + {3, 0, 4, 0, 60}, + {3, 0, 4, 0, 58}, + {3, 0, 4, 0, 57}, + {3, 0, 4, 0, 55}, + {3, 0, 4, 0, 54}, + {3, 0, 4, 0, 52}, + {3, 0, 4, 0, 51}, + {3, 0, 4, 0, 49}, + {3, 0, 4, 0, 48}, + {3, 0, 4, 0, 46}, + {3, 0, 3, 0, 60}, + {3, 0, 3, 0, 58}, + {3, 0, 3, 0, 57}, + {3, 0, 3, 0, 55}, + {3, 0, 3, 0, 54}, + {3, 0, 3, 0, 52}, + {3, 0, 3, 0, 51}, + {3, 0, 3, 0, 49}, + {3, 0, 3, 0, 48}, + {3, 0, 3, 0, 46}, + {3, 0, 3, 0, 45}, + {3, 0, 3, 0, 44}, + {3, 0, 3, 0, 43}, + {3, 0, 3, 0, 41}, + {3, 0, 2, 0, 61}, + {3, 0, 2, 0, 59}, + {3, 0, 2, 0, 57}, + {3, 0, 2, 0, 56}, + {3, 0, 2, 0, 54}, + {3, 0, 2, 0, 53}, + {3, 0, 2, 0, 51}, + {3, 0, 2, 0, 50}, + {3, 0, 2, 0, 48}, + {3, 0, 2, 0, 47}, + {3, 0, 2, 0, 46}, + {3, 0, 2, 0, 44}, + {3, 0, 2, 0, 43}, + {3, 0, 2, 0, 42}, + {3, 0, 2, 0, 41}, + {3, 0, 2, 0, 39}, + {3, 0, 2, 0, 38}, + {3, 0, 2, 0, 37}, + {3, 0, 2, 0, 36}, + {3, 0, 2, 0, 35}, + {3, 0, 2, 0, 34}, + {3, 0, 2, 0, 33}, + {3, 0, 2, 0, 32}, + {3, 0, 1, 0, 63}, + {3, 0, 1, 0, 61}, + {3, 0, 1, 0, 59}, + {3, 0, 1, 0, 57}, +}; + +const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_gaintable_rev0[128] = { + {7, 0, 31, 0, 72}, + {7, 0, 31, 0, 70}, + {7, 0, 31, 0, 68}, + {7, 0, 30, 0, 67}, + {7, 0, 29, 0, 68}, + {7, 0, 28, 0, 68}, + {7, 0, 27, 0, 69}, + {7, 0, 26, 0, 70}, + {7, 0, 25, 0, 70}, + {7, 0, 24, 0, 71}, + {7, 0, 23, 0, 72}, + {7, 0, 23, 0, 70}, + {7, 0, 22, 0, 71}, + {7, 0, 21, 0, 72}, + {7, 0, 21, 0, 70}, + {7, 0, 21, 0, 68}, + {7, 0, 21, 0, 66}, + {7, 0, 21, 0, 64}, + {7, 0, 21, 0, 63}, + {7, 0, 20, 0, 64}, + {7, 0, 19, 0, 65}, + {7, 0, 19, 0, 64}, + {7, 0, 18, 0, 65}, + {7, 0, 18, 0, 64}, + {7, 0, 17, 0, 65}, + {7, 0, 17, 0, 64}, + {7, 0, 16, 0, 65}, + {7, 0, 16, 0, 64}, + {7, 0, 16, 0, 62}, + {7, 0, 16, 0, 60}, + {7, 0, 16, 0, 58}, + {7, 0, 15, 0, 61}, + {7, 0, 15, 0, 59}, + {7, 0, 14, 0, 61}, + {7, 0, 14, 0, 60}, + {7, 0, 14, 0, 58}, + {7, 0, 13, 0, 60}, + {7, 0, 13, 0, 59}, + {7, 0, 12, 0, 62}, + {7, 0, 12, 0, 60}, + {7, 0, 12, 0, 58}, + {7, 0, 11, 0, 62}, + {7, 0, 11, 0, 60}, + {7, 0, 11, 0, 59}, + {7, 0, 11, 0, 57}, + {7, 0, 10, 0, 61}, + {7, 0, 10, 0, 59}, + {7, 0, 10, 0, 57}, + {7, 0, 9, 0, 62}, + {7, 0, 9, 0, 60}, + {7, 0, 9, 0, 58}, + {7, 0, 9, 0, 57}, + {7, 0, 8, 0, 62}, + {7, 0, 8, 0, 60}, + {7, 0, 8, 0, 58}, + {7, 0, 8, 0, 57}, + {7, 0, 8, 0, 55}, + {7, 0, 7, 0, 61}, + {7, 0, 7, 0, 60}, + {7, 0, 7, 0, 58}, + {7, 0, 7, 0, 56}, + {7, 0, 7, 0, 55}, + {7, 0, 6, 0, 62}, + {7, 0, 6, 0, 60}, + {7, 0, 6, 0, 58}, + {7, 0, 6, 0, 57}, + {7, 0, 6, 0, 55}, + {7, 0, 6, 0, 54}, + {7, 0, 6, 0, 52}, + {7, 0, 5, 0, 61}, + {7, 0, 5, 0, 59}, + {7, 0, 5, 0, 57}, + {7, 0, 5, 0, 56}, + {7, 0, 5, 0, 54}, + {7, 0, 5, 0, 53}, + {7, 0, 5, 0, 51}, + {7, 0, 4, 0, 62}, + {7, 0, 4, 0, 60}, + {7, 0, 4, 0, 58}, + {7, 0, 4, 0, 57}, + {7, 0, 4, 0, 55}, + {7, 0, 4, 0, 54}, + {7, 0, 4, 0, 52}, + {7, 0, 4, 0, 51}, + {7, 0, 4, 0, 49}, + {7, 0, 4, 0, 48}, + {7, 0, 4, 0, 46}, + {7, 0, 3, 0, 60}, + {7, 0, 3, 0, 58}, + {7, 0, 3, 0, 57}, + {7, 0, 3, 0, 55}, + {7, 0, 3, 0, 54}, + {7, 0, 3, 0, 52}, + {7, 0, 3, 0, 51}, + {7, 0, 3, 0, 49}, + {7, 0, 3, 0, 48}, + {7, 0, 3, 0, 46}, + {7, 0, 3, 0, 45}, + {7, 0, 3, 0, 44}, + {7, 0, 3, 0, 43}, + {7, 0, 3, 0, 41}, + {7, 0, 2, 0, 61}, + {7, 0, 2, 0, 59}, + {7, 0, 2, 0, 57}, + {7, 0, 2, 0, 56}, + {7, 0, 2, 0, 54}, + {7, 0, 2, 0, 53}, + {7, 0, 2, 0, 51}, + {7, 0, 2, 0, 50}, + {7, 0, 2, 0, 48}, + {7, 0, 2, 0, 47}, + {7, 0, 2, 0, 46}, + {7, 0, 2, 0, 44}, + {7, 0, 2, 0, 43}, + {7, 0, 2, 0, 42}, + {7, 0, 2, 0, 41}, + {7, 0, 2, 0, 39}, + {7, 0, 2, 0, 38}, + {7, 0, 2, 0, 37}, + {7, 0, 2, 0, 36}, + {7, 0, 2, 0, 35}, + {7, 0, 2, 0, 34}, + {7, 0, 2, 0, 33}, + {7, 0, 2, 0, 32}, + {7, 0, 1, 0, 63}, + {7, 0, 1, 0, 61}, + {7, 0, 1, 0, 59}, + {7, 0, 1, 0, 57}, +}; + +const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_5GHz_gaintable_rev0[128] = { + {255, 255, 0xf0, 0, 152}, + {255, 255, 0xf0, 0, 147}, + {255, 255, 0xf0, 0, 143}, + {255, 255, 0xf0, 0, 139}, + {255, 255, 0xf0, 0, 135}, + {255, 255, 0xf0, 0, 131}, + {255, 255, 0xf0, 0, 128}, + {255, 255, 0xf0, 0, 124}, + {255, 255, 0xf0, 0, 121}, + {255, 255, 0xf0, 0, 117}, + {255, 255, 0xf0, 0, 114}, + {255, 255, 0xf0, 0, 111}, + {255, 255, 0xf0, 0, 107}, + {255, 255, 0xf0, 0, 104}, + {255, 255, 0xf0, 0, 101}, + {255, 255, 0xf0, 0, 99}, + {255, 255, 0xf0, 0, 96}, + {255, 255, 0xf0, 0, 93}, + {255, 255, 0xf0, 0, 90}, + {255, 255, 0xf0, 0, 88}, + {255, 255, 0xf0, 0, 85}, + {255, 255, 0xf0, 0, 83}, + {255, 255, 0xf0, 0, 81}, + {255, 255, 0xf0, 0, 78}, + {255, 255, 0xf0, 0, 76}, + {255, 255, 0xf0, 0, 74}, + {255, 255, 0xf0, 0, 72}, + {255, 255, 0xf0, 0, 70}, + {255, 255, 0xf0, 0, 68}, + {255, 255, 0xf0, 0, 66}, + {255, 255, 0xf0, 0, 64}, + {255, 248, 0xf0, 0, 64}, + {255, 241, 0xf0, 0, 64}, + {255, 251, 0xe0, 0, 64}, + {255, 244, 0xe0, 0, 64}, + {255, 254, 0xd0, 0, 64}, + {255, 246, 0xd0, 0, 64}, + {255, 239, 0xd0, 0, 64}, + {255, 249, 0xc0, 0, 64}, + {255, 242, 0xc0, 0, 64}, + {255, 255, 0xb0, 0, 64}, + {255, 248, 0xb0, 0, 64}, + {255, 241, 0xb0, 0, 64}, + {255, 254, 0xa0, 0, 64}, + {255, 246, 0xa0, 0, 64}, + {255, 239, 0xa0, 0, 64}, + {255, 255, 0x90, 0, 64}, + {255, 248, 0x90, 0, 64}, + {255, 241, 0x90, 0, 64}, + {255, 234, 0x90, 0, 64}, + {255, 255, 0x80, 0, 64}, + {255, 248, 0x80, 0, 64}, + {255, 241, 0x80, 0, 64}, + {255, 234, 0x80, 0, 64}, + {255, 255, 0x70, 0, 64}, + {255, 248, 0x70, 0, 64}, + {255, 241, 0x70, 0, 64}, + {255, 234, 0x70, 0, 64}, + {255, 227, 0x70, 0, 64}, + {255, 221, 0x70, 0, 64}, + {255, 215, 0x70, 0, 64}, + {255, 208, 0x70, 0, 64}, + {255, 203, 0x70, 0, 64}, + {255, 197, 0x70, 0, 64}, + {255, 255, 0x60, 0, 64}, + {255, 248, 0x60, 0, 64}, + {255, 241, 0x60, 0, 64}, + {255, 234, 0x60, 0, 64}, + {255, 227, 0x60, 0, 64}, + {255, 221, 0x60, 0, 64}, + {255, 255, 0x50, 0, 64}, + {255, 248, 0x50, 0, 64}, + {255, 241, 0x50, 0, 64}, + {255, 234, 0x50, 0, 64}, + {255, 227, 0x50, 0, 64}, + {255, 221, 0x50, 0, 64}, + {255, 215, 0x50, 0, 64}, + {255, 208, 0x50, 0, 64}, + {255, 255, 0x40, 0, 64}, + {255, 248, 0x40, 0, 64}, + {255, 241, 0x40, 0, 64}, + {255, 234, 0x40, 0, 64}, + {255, 227, 0x40, 0, 64}, + {255, 221, 0x40, 0, 64}, + {255, 215, 0x40, 0, 64}, + {255, 208, 0x40, 0, 64}, + {255, 203, 0x40, 0, 64}, + {255, 197, 0x40, 0, 64}, + {255, 255, 0x30, 0, 64}, + {255, 248, 0x30, 0, 64}, + {255, 241, 0x30, 0, 64}, + {255, 234, 0x30, 0, 64}, + {255, 227, 0x30, 0, 64}, + {255, 221, 0x30, 0, 64}, + {255, 215, 0x30, 0, 64}, + {255, 208, 0x30, 0, 64}, + {255, 203, 0x30, 0, 64}, + {255, 197, 0x30, 0, 64}, + {255, 191, 0x30, 0, 64}, + {255, 186, 0x30, 0, 64}, + {255, 181, 0x30, 0, 64}, + {255, 175, 0x30, 0, 64}, + {255, 255, 0x20, 0, 64}, + {255, 248, 0x20, 0, 64}, + {255, 241, 0x20, 0, 64}, + {255, 234, 0x20, 0, 64}, + {255, 227, 0x20, 0, 64}, + {255, 221, 0x20, 0, 64}, + {255, 215, 0x20, 0, 64}, + {255, 208, 0x20, 0, 64}, + {255, 203, 0x20, 0, 64}, + {255, 197, 0x20, 0, 64}, + {255, 191, 0x20, 0, 64}, + {255, 186, 0x20, 0, 64}, + {255, 181, 0x20, 0, 64}, + {255, 175, 0x20, 0, 64}, + {255, 170, 0x20, 0, 64}, + {255, 166, 0x20, 0, 64}, + {255, 161, 0x20, 0, 64}, + {255, 156, 0x20, 0, 64}, + {255, 152, 0x20, 0, 64}, + {255, 148, 0x20, 0, 64}, + {255, 143, 0x20, 0, 64}, + {255, 139, 0x20, 0, 64}, + {255, 135, 0x20, 0, 64}, + {255, 132, 0x20, 0, 64}, + {255, 255, 0x10, 0, 64}, + {255, 248, 0x10, 0, 64}, +}; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h new file mode 100644 index 000000000000..5f75e16bf5a7 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_lcn.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 <types.h> +#include "phy_int.h" + +extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_rev0[]; +extern const u32 dot11lcnphytbl_rx_gain_info_sz_rev0; +extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313; +extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa; +extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_epa_combo; +extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa; +extern const struct phytbl_info dot11lcn_sw_ctrl_tbl_info_4313_bt_epa_p250; + +extern const struct phytbl_info dot11lcnphytbl_info_rev0[]; +extern const u32 dot11lcnphytbl_info_sz_rev0; + +extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_2G_rev2[]; +extern const u32 dot11lcnphytbl_rx_gain_info_2G_rev2_sz; + +extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_5G_rev2[]; +extern const u32 dot11lcnphytbl_rx_gain_info_5G_rev2_sz; + +extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_2G_rev2[]; + +extern const struct phytbl_info dot11lcnphytbl_rx_gain_info_extlna_5G_rev2[]; + +struct lcnphy_tx_gain_tbl_entry { + unsigned char gm; + unsigned char pga; + unsigned char pad; + unsigned char dac; + unsigned char bb_mult; +}; + +extern const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_gaintable_rev0[]; + +extern const struct +lcnphy_tx_gain_tbl_entry dot11lcnphy_2GHz_extPA_gaintable_rev0[]; + +extern const struct lcnphy_tx_gain_tbl_entry dot11lcnphy_5GHz_gaintable_rev0[]; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c new file mode 100644 index 000000000000..dbf50ef6cd75 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.c @@ -0,0 +1,10630 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 <types.h> +#include "phytbl_n.h" + +static const u32 frame_struct_rev0[] = { + 0x08004a04, + 0x00100000, + 0x01000a05, + 0x00100020, + 0x09804506, + 0x00100030, + 0x09804507, + 0x00100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004a0c, + 0x00100004, + 0x01000a0d, + 0x00100024, + 0x0980450e, + 0x00100034, + 0x0980450f, + 0x00100034, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000a04, + 0x00100000, + 0x11008a05, + 0x00100020, + 0x1980c506, + 0x00100030, + 0x21810506, + 0x00100030, + 0x21810506, + 0x00100030, + 0x01800504, + 0x00100030, + 0x11808505, + 0x00100030, + 0x29814507, + 0x01100030, + 0x00000a04, + 0x00100000, + 0x11008a05, + 0x00100020, + 0x21810506, + 0x00100030, + 0x21810506, + 0x00100030, + 0x29814507, + 0x01100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000a0c, + 0x00100008, + 0x11008a0d, + 0x00100028, + 0x1980c50e, + 0x00100038, + 0x2181050e, + 0x00100038, + 0x2181050e, + 0x00100038, + 0x0180050c, + 0x00100038, + 0x1180850d, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000a0c, + 0x00100008, + 0x11008a0d, + 0x00100028, + 0x2181050e, + 0x00100038, + 0x2181050e, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004a04, + 0x00100000, + 0x01000a05, + 0x00100020, + 0x1980c506, + 0x00100030, + 0x1980c506, + 0x00100030, + 0x11808504, + 0x00100030, + 0x3981ca05, + 0x00100030, + 0x29814507, + 0x01100030, + 0x00000000, + 0x00000000, + 0x10008a04, + 0x00100000, + 0x3981ca05, + 0x00100030, + 0x1980c506, + 0x00100030, + 0x29814507, + 0x01100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004a0c, + 0x00100008, + 0x01000a0d, + 0x00100028, + 0x1980c50e, + 0x00100038, + 0x1980c50e, + 0x00100038, + 0x1180850c, + 0x00100038, + 0x3981ca0d, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x10008a0c, + 0x00100008, + 0x3981ca0d, + 0x00100038, + 0x1980c50e, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40021404, + 0x00100000, + 0x02001405, + 0x00100040, + 0x0b004a06, + 0x01900060, + 0x13008a06, + 0x01900060, + 0x13008a06, + 0x01900060, + 0x43020a04, + 0x00100060, + 0x1b00ca05, + 0x00100060, + 0x23010a07, + 0x01500060, + 0x40021404, + 0x00100000, + 0x1a00d405, + 0x00100040, + 0x13008a06, + 0x01900060, + 0x13008a06, + 0x01900060, + 0x23010a07, + 0x01500060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100010, + 0x0200140d, + 0x00100050, + 0x0b004a0e, + 0x01900070, + 0x13008a0e, + 0x01900070, + 0x13008a0e, + 0x01900070, + 0x43020a0c, + 0x00100070, + 0x1b00ca0d, + 0x00100070, + 0x23010a0f, + 0x01500070, + 0x4002140c, + 0x00100010, + 0x1a00d40d, + 0x00100050, + 0x13008a0e, + 0x01900070, + 0x13008a0e, + 0x01900070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x50029404, + 0x00100000, + 0x32019405, + 0x00100040, + 0x0b004a06, + 0x01900060, + 0x0b004a06, + 0x01900060, + 0x5b02ca04, + 0x00100060, + 0x3b01d405, + 0x00100060, + 0x23010a07, + 0x01500060, + 0x00000000, + 0x00000000, + 0x5802d404, + 0x00100000, + 0x3b01d405, + 0x00100060, + 0x0b004a06, + 0x01900060, + 0x23010a07, + 0x01500060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5002940c, + 0x00100010, + 0x3201940d, + 0x00100050, + 0x0b004a0e, + 0x01900070, + 0x0b004a0e, + 0x01900070, + 0x5b02ca0c, + 0x00100070, + 0x3b01d40d, + 0x00100070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x5802d40c, + 0x00100010, + 0x3b01d40d, + 0x00100070, + 0x0b004a0e, + 0x01900070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40021404, + 0x000f4800, + 0x62031405, + 0x00100040, + 0x53028a06, + 0x01900060, + 0x53028a07, + 0x01900060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x000f4808, + 0x6203140d, + 0x00100048, + 0x53028a0e, + 0x01900068, + 0x53028a0f, + 0x01900068, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000a0c, + 0x00100004, + 0x11008a0d, + 0x00100024, + 0x1980c50e, + 0x00100034, + 0x2181050e, + 0x00100034, + 0x2181050e, + 0x00100034, + 0x0180050c, + 0x00100038, + 0x1180850d, + 0x00100038, + 0x1181850d, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000a0c, + 0x00100008, + 0x11008a0d, + 0x00100028, + 0x2181050e, + 0x00100038, + 0x2181050e, + 0x00100038, + 0x1181850d, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004a04, + 0x00100000, + 0x01000a05, + 0x00100020, + 0x0180c506, + 0x00100030, + 0x0180c506, + 0x00100030, + 0x2180c50c, + 0x00100030, + 0x49820a0d, + 0x0016a130, + 0x41824a0d, + 0x0016a130, + 0x2981450f, + 0x01100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x2000ca0c, + 0x00100000, + 0x49820a0d, + 0x0016a130, + 0x1980c50e, + 0x00100030, + 0x41824a0d, + 0x0016a130, + 0x2981450f, + 0x01100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100008, + 0x0200140d, + 0x00100048, + 0x0b004a0e, + 0x01900068, + 0x13008a0e, + 0x01900068, + 0x13008a0e, + 0x01900068, + 0x43020a0c, + 0x00100070, + 0x1b00ca0d, + 0x00100070, + 0x1b014a0d, + 0x00100070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100010, + 0x1a00d40d, + 0x00100050, + 0x13008a0e, + 0x01900070, + 0x13008a0e, + 0x01900070, + 0x1b014a0d, + 0x00100070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x50029404, + 0x00100000, + 0x32019405, + 0x00100040, + 0x03004a06, + 0x01900060, + 0x03004a06, + 0x01900060, + 0x6b030a0c, + 0x00100060, + 0x4b02140d, + 0x0016a160, + 0x4302540d, + 0x0016a160, + 0x23010a0f, + 0x01500060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x6b03140c, + 0x00100060, + 0x4b02140d, + 0x0016a160, + 0x0b004a0e, + 0x01900060, + 0x4302540d, + 0x0016a160, + 0x23010a0f, + 0x01500060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40021404, + 0x00100000, + 0x1a00d405, + 0x00100040, + 0x53028a06, + 0x01900060, + 0x5b02ca06, + 0x01900060, + 0x5b02ca06, + 0x01900060, + 0x43020a04, + 0x00100060, + 0x1b00ca05, + 0x00100060, + 0x53028a07, + 0x0190c060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100010, + 0x1a00d40d, + 0x00100050, + 0x53028a0e, + 0x01900070, + 0x5b02ca0e, + 0x01900070, + 0x5b02ca0e, + 0x01900070, + 0x43020a0c, + 0x00100070, + 0x1b00ca0d, + 0x00100070, + 0x53028a0f, + 0x0190c070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40021404, + 0x00100000, + 0x1a00d405, + 0x00100040, + 0x5b02ca06, + 0x01900060, + 0x5b02ca06, + 0x01900060, + 0x53028a07, + 0x0190c060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100010, + 0x1a00d40d, + 0x00100050, + 0x5b02ca0e, + 0x01900070, + 0x5b02ca0e, + 0x01900070, + 0x53028a0f, + 0x0190c070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u8 frame_lut_rev0[] = { + 0x02, + 0x04, + 0x14, + 0x14, + 0x03, + 0x05, + 0x16, + 0x16, + 0x0a, + 0x0c, + 0x1c, + 0x1c, + 0x0b, + 0x0d, + 0x1e, + 0x1e, + 0x06, + 0x08, + 0x18, + 0x18, + 0x07, + 0x09, + 0x1a, + 0x1a, + 0x0e, + 0x10, + 0x20, + 0x28, + 0x0f, + 0x11, + 0x22, + 0x2a, +}; + +static const u32 tmap_tbl_rev0[] = { + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00000111, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x000aa888, + 0x88880000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa2222220, + 0x22222222, + 0x22c22222, + 0x00000222, + 0x22000000, + 0x2222a222, + 0x22222222, + 0x222222a2, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00011111, + 0x11110000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0xa8aa88a0, + 0xa88888a8, + 0xa8a8a88a, + 0x00088aaa, + 0xaaaa0000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xaaa8aaa0, + 0x8aaa8aaa, + 0xaa8a8a8a, + 0x000aaa88, + 0x8aaa0000, + 0xaaa8a888, + 0x8aa88a8a, + 0x8a88a888, + 0x08080a00, + 0x0a08080a, + 0x080a0a08, + 0x00080808, + 0x080a0000, + 0x080a0808, + 0x080a0808, + 0x0a0a0a08, + 0xa0a0a0a0, + 0x80a0a080, + 0x8080a0a0, + 0x00008080, + 0x80a00000, + 0x80a080a0, + 0xa080a0a0, + 0x8080a0a0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x99999000, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb90, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00aaa888, + 0x22000000, + 0x2222b222, + 0x22222222, + 0x222222b2, + 0xb2222220, + 0x22222222, + 0x22d22222, + 0x00000222, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x33000000, + 0x3333b333, + 0x33333333, + 0x333333b3, + 0xb3333330, + 0x33333333, + 0x33d33333, + 0x00000333, + 0x22000000, + 0x2222a222, + 0x22222222, + 0x222222a2, + 0xa2222220, + 0x22222222, + 0x22c22222, + 0x00000222, + 0x99b99b00, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb99, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x08aaa888, + 0x22222200, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0x22222222, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x11111111, + 0xf1111111, + 0x11111111, + 0x11f11111, + 0x01111111, + 0xbb9bb900, + 0xb9b9bb99, + 0xb99bbbbb, + 0xbbbb9b9b, + 0xb9bb99bb, + 0xb99999b9, + 0xb9b9b99b, + 0x00000bbb, + 0xaa000000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xa8aa88aa, + 0xa88888a8, + 0xa8a8a88a, + 0x0a888aaa, + 0xaa000000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xa8aa88a0, + 0xa88888a8, + 0xa8a8a88a, + 0x00000aaa, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0xbbbbbb00, + 0x999bbbbb, + 0x9bb99b9b, + 0xb9b9b9bb, + 0xb9b99bbb, + 0xb9b9b9bb, + 0xb9bb9b99, + 0x00000999, + 0x8a000000, + 0xaa88a888, + 0xa88888aa, + 0xa88a8a88, + 0xa88aa88a, + 0x88a8aaaa, + 0xa8aa8aaa, + 0x0888a88a, + 0x0b0b0b00, + 0x090b0b0b, + 0x0b090b0b, + 0x0909090b, + 0x09090b0b, + 0x09090b0b, + 0x09090b09, + 0x00000909, + 0x0a000000, + 0x0a080808, + 0x080a080a, + 0x080a0a08, + 0x080a080a, + 0x0808080a, + 0x0a0a0a08, + 0x0808080a, + 0xb0b0b000, + 0x9090b0b0, + 0x90b09090, + 0xb0b0b090, + 0xb0b090b0, + 0x90b0b0b0, + 0xb0b09090, + 0x00000090, + 0x80000000, + 0xa080a080, + 0xa08080a0, + 0xa0808080, + 0xa080a080, + 0x80a0a0a0, + 0xa0a080a0, + 0x00a0a0a0, + 0x22000000, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0xf2222220, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00000111, + 0x33000000, + 0x3333f333, + 0x33333333, + 0x333333f3, + 0xf3333330, + 0x33333333, + 0x33f33333, + 0x00000333, + 0x22000000, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0xf2222220, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x99000000, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb90, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88888000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00aaa888, + 0x88a88a00, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x08aaa888, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 tdtrn_tbl_rev0[] = { + 0x061c061c, + 0x0050ee68, + 0xf592fe36, + 0xfe5212f6, + 0x00000c38, + 0xfe5212f6, + 0xf592fe36, + 0x0050ee68, + 0x061c061c, + 0xee680050, + 0xfe36f592, + 0x12f6fe52, + 0x0c380000, + 0x12f6fe52, + 0xfe36f592, + 0xee680050, + 0x061c061c, + 0x0050ee68, + 0xf592fe36, + 0xfe5212f6, + 0x00000c38, + 0xfe5212f6, + 0xf592fe36, + 0x0050ee68, + 0x061c061c, + 0xee680050, + 0xfe36f592, + 0x12f6fe52, + 0x0c380000, + 0x12f6fe52, + 0xfe36f592, + 0xee680050, + 0x05e305e3, + 0x004def0c, + 0xf5f3fe47, + 0xfe611246, + 0x00000bc7, + 0xfe611246, + 0xf5f3fe47, + 0x004def0c, + 0x05e305e3, + 0xef0c004d, + 0xfe47f5f3, + 0x1246fe61, + 0x0bc70000, + 0x1246fe61, + 0xfe47f5f3, + 0xef0c004d, + 0x05e305e3, + 0x004def0c, + 0xf5f3fe47, + 0xfe611246, + 0x00000bc7, + 0xfe611246, + 0xf5f3fe47, + 0x004def0c, + 0x05e305e3, + 0xef0c004d, + 0xfe47f5f3, + 0x1246fe61, + 0x0bc70000, + 0x1246fe61, + 0xfe47f5f3, + 0xef0c004d, + 0xfa58fa58, + 0xf895043b, + 0xff4c09c0, + 0xfbc6ffa8, + 0xfb84f384, + 0x0798f6f9, + 0x05760122, + 0x058409f6, + 0x0b500000, + 0x05b7f542, + 0x08860432, + 0x06ddfee7, + 0xfb84f384, + 0xf9d90664, + 0xf7e8025c, + 0x00fff7bd, + 0x05a805a8, + 0xf7bd00ff, + 0x025cf7e8, + 0x0664f9d9, + 0xf384fb84, + 0xfee706dd, + 0x04320886, + 0xf54205b7, + 0x00000b50, + 0x09f60584, + 0x01220576, + 0xf6f90798, + 0xf384fb84, + 0xffa8fbc6, + 0x09c0ff4c, + 0x043bf895, + 0x02d402d4, + 0x07de0270, + 0xfc96079c, + 0xf90afe94, + 0xfe00ff2c, + 0x02d4065d, + 0x092a0096, + 0x0014fbb8, + 0xfd2cfd2c, + 0x076afb3c, + 0x0096f752, + 0xf991fd87, + 0xfb2c0200, + 0xfeb8f960, + 0x08e0fc96, + 0x049802a8, + 0xfd2cfd2c, + 0x02a80498, + 0xfc9608e0, + 0xf960feb8, + 0x0200fb2c, + 0xfd87f991, + 0xf7520096, + 0xfb3c076a, + 0xfd2cfd2c, + 0xfbb80014, + 0x0096092a, + 0x065d02d4, + 0xff2cfe00, + 0xfe94f90a, + 0x079cfc96, + 0x027007de, + 0x02d402d4, + 0x027007de, + 0x079cfc96, + 0xfe94f90a, + 0xff2cfe00, + 0x065d02d4, + 0x0096092a, + 0xfbb80014, + 0xfd2cfd2c, + 0xfb3c076a, + 0xf7520096, + 0xfd87f991, + 0x0200fb2c, + 0xf960feb8, + 0xfc9608e0, + 0x02a80498, + 0xfd2cfd2c, + 0x049802a8, + 0x08e0fc96, + 0xfeb8f960, + 0xfb2c0200, + 0xf991fd87, + 0x0096f752, + 0x076afb3c, + 0xfd2cfd2c, + 0x0014fbb8, + 0x092a0096, + 0x02d4065d, + 0xfe00ff2c, + 0xf90afe94, + 0xfc96079c, + 0x07de0270, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x062a0000, + 0xfefa0759, + 0x08b80908, + 0xf396fc2d, + 0xf9d6045c, + 0xfc4ef608, + 0xf748f596, + 0x07b207bf, + 0x062a062a, + 0xf84ef841, + 0xf748f596, + 0x03b209f8, + 0xf9d6045c, + 0x0c6a03d3, + 0x08b80908, + 0x0106f8a7, + 0x062a0000, + 0xfefaf8a7, + 0x08b8f6f8, + 0xf39603d3, + 0xf9d6fba4, + 0xfc4e09f8, + 0xf7480a6a, + 0x07b2f841, + 0x062af9d6, + 0xf84e07bf, + 0xf7480a6a, + 0x03b2f608, + 0xf9d6fba4, + 0x0c6afc2d, + 0x08b8f6f8, + 0x01060759, + 0x062a0000, + 0xfefa0759, + 0x08b80908, + 0xf396fc2d, + 0xf9d6045c, + 0xfc4ef608, + 0xf748f596, + 0x07b207bf, + 0x062a062a, + 0xf84ef841, + 0xf748f596, + 0x03b209f8, + 0xf9d6045c, + 0x0c6a03d3, + 0x08b80908, + 0x0106f8a7, + 0x062a0000, + 0xfefaf8a7, + 0x08b8f6f8, + 0xf39603d3, + 0xf9d6fba4, + 0xfc4e09f8, + 0xf7480a6a, + 0x07b2f841, + 0x062af9d6, + 0xf84e07bf, + 0xf7480a6a, + 0x03b2f608, + 0xf9d6fba4, + 0x0c6afc2d, + 0x08b8f6f8, + 0x01060759, + 0x061c061c, + 0xff30009d, + 0xffb21141, + 0xfd87fb54, + 0xf65dfe59, + 0x02eef99e, + 0x0166f03c, + 0xfff809b6, + 0x000008a4, + 0x000af42b, + 0x00eff577, + 0xfa840bf2, + 0xfc02ff51, + 0x08260f67, + 0xfff0036f, + 0x0842f9c3, + 0x00000000, + 0x063df7be, + 0xfc910010, + 0xf099f7da, + 0x00af03fe, + 0xf40e057c, + 0x0a89ff11, + 0x0bd5fff6, + 0xf75c0000, + 0xf64a0008, + 0x0fc4fe9a, + 0x0662fd12, + 0x01a709a3, + 0x04ac0279, + 0xeebf004e, + 0xff6300d0, + 0xf9e4f9e4, + 0x00d0ff63, + 0x004eeebf, + 0x027904ac, + 0x09a301a7, + 0xfd120662, + 0xfe9a0fc4, + 0x0008f64a, + 0x0000f75c, + 0xfff60bd5, + 0xff110a89, + 0x057cf40e, + 0x03fe00af, + 0xf7daf099, + 0x0010fc91, + 0xf7be063d, + 0x00000000, + 0xf9c30842, + 0x036ffff0, + 0x0f670826, + 0xff51fc02, + 0x0bf2fa84, + 0xf57700ef, + 0xf42b000a, + 0x08a40000, + 0x09b6fff8, + 0xf03c0166, + 0xf99e02ee, + 0xfe59f65d, + 0xfb54fd87, + 0x1141ffb2, + 0x009dff30, + 0x05e30000, + 0xff060705, + 0x085408a0, + 0xf425fc59, + 0xfa1d042a, + 0xfc78f67a, + 0xf7acf60e, + 0x075a0766, + 0x05e305e3, + 0xf8a6f89a, + 0xf7acf60e, + 0x03880986, + 0xfa1d042a, + 0x0bdb03a7, + 0x085408a0, + 0x00faf8fb, + 0x05e30000, + 0xff06f8fb, + 0x0854f760, + 0xf42503a7, + 0xfa1dfbd6, + 0xfc780986, + 0xf7ac09f2, + 0x075af89a, + 0x05e3fa1d, + 0xf8a60766, + 0xf7ac09f2, + 0x0388f67a, + 0xfa1dfbd6, + 0x0bdbfc59, + 0x0854f760, + 0x00fa0705, + 0x05e30000, + 0xff060705, + 0x085408a0, + 0xf425fc59, + 0xfa1d042a, + 0xfc78f67a, + 0xf7acf60e, + 0x075a0766, + 0x05e305e3, + 0xf8a6f89a, + 0xf7acf60e, + 0x03880986, + 0xfa1d042a, + 0x0bdb03a7, + 0x085408a0, + 0x00faf8fb, + 0x05e30000, + 0xff06f8fb, + 0x0854f760, + 0xf42503a7, + 0xfa1dfbd6, + 0xfc780986, + 0xf7ac09f2, + 0x075af89a, + 0x05e3fa1d, + 0xf8a60766, + 0xf7ac09f2, + 0x0388f67a, + 0xfa1dfbd6, + 0x0bdbfc59, + 0x0854f760, + 0x00fa0705, + 0xfa58fa58, + 0xf8f0fe00, + 0x0448073d, + 0xfdc9fe46, + 0xf9910258, + 0x089d0407, + 0xfd5cf71a, + 0x02affde0, + 0x083e0496, + 0xff5a0740, + 0xff7afd97, + 0x00fe01f1, + 0x0009082e, + 0xfa94ff75, + 0xfecdf8ea, + 0xffb0f693, + 0xfd2cfa58, + 0x0433ff16, + 0xfba405dd, + 0xfa610341, + 0x06a606cb, + 0x0039fd2d, + 0x0677fa97, + 0x01fa05e0, + 0xf896003e, + 0x075a068b, + 0x012cfc3e, + 0xfa23f98d, + 0xfc7cfd43, + 0xff90fc0d, + 0x01c10982, + 0x00c601d6, + 0xfd2cfd2c, + 0x01d600c6, + 0x098201c1, + 0xfc0dff90, + 0xfd43fc7c, + 0xf98dfa23, + 0xfc3e012c, + 0x068b075a, + 0x003ef896, + 0x05e001fa, + 0xfa970677, + 0xfd2d0039, + 0x06cb06a6, + 0x0341fa61, + 0x05ddfba4, + 0xff160433, + 0xfa58fd2c, + 0xf693ffb0, + 0xf8eafecd, + 0xff75fa94, + 0x082e0009, + 0x01f100fe, + 0xfd97ff7a, + 0x0740ff5a, + 0x0496083e, + 0xfde002af, + 0xf71afd5c, + 0x0407089d, + 0x0258f991, + 0xfe46fdc9, + 0x073d0448, + 0xfe00f8f0, + 0xfd2cfd2c, + 0xfce00500, + 0xfc09fddc, + 0xfe680157, + 0x04c70571, + 0xfc3aff21, + 0xfcd70228, + 0x056d0277, + 0x0200fe00, + 0x0022f927, + 0xfe3c032b, + 0xfc44ff3c, + 0x03e9fbdb, + 0x04570313, + 0x04c9ff5c, + 0x000d03b8, + 0xfa580000, + 0xfbe900d2, + 0xf9d0fe0b, + 0x0125fdf9, + 0x042501bf, + 0x0328fa2b, + 0xffa902f0, + 0xfa250157, + 0x0200fe00, + 0x03740438, + 0xff0405fd, + 0x030cfe52, + 0x0037fb39, + 0xff6904c5, + 0x04f8fd23, + 0xfd31fc1b, + 0xfd2cfd2c, + 0xfc1bfd31, + 0xfd2304f8, + 0x04c5ff69, + 0xfb390037, + 0xfe52030c, + 0x05fdff04, + 0x04380374, + 0xfe000200, + 0x0157fa25, + 0x02f0ffa9, + 0xfa2b0328, + 0x01bf0425, + 0xfdf90125, + 0xfe0bf9d0, + 0x00d2fbe9, + 0x0000fa58, + 0x03b8000d, + 0xff5c04c9, + 0x03130457, + 0xfbdb03e9, + 0xff3cfc44, + 0x032bfe3c, + 0xf9270022, + 0xfe000200, + 0x0277056d, + 0x0228fcd7, + 0xff21fc3a, + 0x057104c7, + 0x0157fe68, + 0xfddcfc09, + 0x0500fce0, + 0xfd2cfd2c, + 0x0500fce0, + 0xfddcfc09, + 0x0157fe68, + 0x057104c7, + 0xff21fc3a, + 0x0228fcd7, + 0x0277056d, + 0xfe000200, + 0xf9270022, + 0x032bfe3c, + 0xff3cfc44, + 0xfbdb03e9, + 0x03130457, + 0xff5c04c9, + 0x03b8000d, + 0x0000fa58, + 0x00d2fbe9, + 0xfe0bf9d0, + 0xfdf90125, + 0x01bf0425, + 0xfa2b0328, + 0x02f0ffa9, + 0x0157fa25, + 0xfe000200, + 0x04380374, + 0x05fdff04, + 0xfe52030c, + 0xfb390037, + 0x04c5ff69, + 0xfd2304f8, + 0xfc1bfd31, + 0xfd2cfd2c, + 0xfd31fc1b, + 0x04f8fd23, + 0xff6904c5, + 0x0037fb39, + 0x030cfe52, + 0xff0405fd, + 0x03740438, + 0x0200fe00, + 0xfa250157, + 0xffa902f0, + 0x0328fa2b, + 0x042501bf, + 0x0125fdf9, + 0xf9d0fe0b, + 0xfbe900d2, + 0xfa580000, + 0x000d03b8, + 0x04c9ff5c, + 0x04570313, + 0x03e9fbdb, + 0xfc44ff3c, + 0xfe3c032b, + 0x0022f927, + 0x0200fe00, + 0x056d0277, + 0xfcd70228, + 0xfc3aff21, + 0x04c70571, + 0xfe680157, + 0xfc09fddc, + 0xfce00500, + 0x05a80000, + 0xff1006be, + 0x0800084a, + 0xf49cfc7e, + 0xfa580400, + 0xfc9cf6da, + 0xf800f672, + 0x0710071c, + 0x05a805a8, + 0xf8f0f8e4, + 0xf800f672, + 0x03640926, + 0xfa580400, + 0x0b640382, + 0x0800084a, + 0x00f0f942, + 0x05a80000, + 0xff10f942, + 0x0800f7b6, + 0xf49c0382, + 0xfa58fc00, + 0xfc9c0926, + 0xf800098e, + 0x0710f8e4, + 0x05a8fa58, + 0xf8f0071c, + 0xf800098e, + 0x0364f6da, + 0xfa58fc00, + 0x0b64fc7e, + 0x0800f7b6, + 0x00f006be, + 0x05a80000, + 0xff1006be, + 0x0800084a, + 0xf49cfc7e, + 0xfa580400, + 0xfc9cf6da, + 0xf800f672, + 0x0710071c, + 0x05a805a8, + 0xf8f0f8e4, + 0xf800f672, + 0x03640926, + 0xfa580400, + 0x0b640382, + 0x0800084a, + 0x00f0f942, + 0x05a80000, + 0xff10f942, + 0x0800f7b6, + 0xf49c0382, + 0xfa58fc00, + 0xfc9c0926, + 0xf800098e, + 0x0710f8e4, + 0x05a8fa58, + 0xf8f0071c, + 0xf800098e, + 0x0364f6da, + 0xfa58fc00, + 0x0b64fc7e, + 0x0800f7b6, + 0x00f006be, +}; + +static const u32 intlv_tbl_rev0[] = { + 0x00802070, + 0x0671188d, + 0x0a60192c, + 0x0a300e46, + 0x00c1188d, + 0x080024d2, + 0x00000070, +}; + +static const u16 pilot_tbl_rev0[] = { + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0xff0a, + 0xff82, + 0xffa0, + 0xff28, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xff82, + 0xffa0, + 0xff28, + 0xff0a, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xf83f, + 0xfa1f, + 0xfa97, + 0xfab5, + 0xf2bd, + 0xf0bf, + 0xffff, + 0xffff, + 0xf017, + 0xf815, + 0xf215, + 0xf095, + 0xf035, + 0xf01d, + 0xffff, + 0xffff, + 0xff08, + 0xff02, + 0xff80, + 0xff20, + 0xff08, + 0xff02, + 0xff80, + 0xff20, + 0xf01f, + 0xf817, + 0xfa15, + 0xf295, + 0xf0b5, + 0xf03d, + 0xffff, + 0xffff, + 0xf82a, + 0xfa0a, + 0xfa82, + 0xfaa0, + 0xf2a8, + 0xf0aa, + 0xffff, + 0xffff, + 0xf002, + 0xf800, + 0xf200, + 0xf080, + 0xf020, + 0xf008, + 0xffff, + 0xffff, + 0xf00a, + 0xf802, + 0xfa00, + 0xf280, + 0xf0a0, + 0xf028, + 0xffff, + 0xffff, +}; + +static const u32 pltlut_tbl_rev0[] = { + 0x76540123, + 0x62407351, + 0x76543201, + 0x76540213, + 0x76540123, + 0x76430521, +}; + +static const u32 tdi_tbl20_ant0_rev0[] = { + 0x00091226, + 0x000a1429, + 0x000b56ad, + 0x000c58b0, + 0x000d5ab3, + 0x000e9cb6, + 0x000f9eba, + 0x0000c13d, + 0x00020301, + 0x00030504, + 0x00040708, + 0x0005090b, + 0x00064b8e, + 0x00095291, + 0x000a5494, + 0x000b9718, + 0x000c9927, + 0x000d9b2a, + 0x000edd2e, + 0x000fdf31, + 0x000101b4, + 0x000243b7, + 0x000345bb, + 0x000447be, + 0x00058982, + 0x00068c05, + 0x00099309, + 0x000a950c, + 0x000bd78f, + 0x000cd992, + 0x000ddb96, + 0x000f1d99, + 0x00005fa8, + 0x0001422c, + 0x0002842f, + 0x00038632, + 0x00048835, + 0x0005ca38, + 0x0006ccbc, + 0x0009d3bf, + 0x000b1603, + 0x000c1806, + 0x000d1a0a, + 0x000e1c0d, + 0x000f5e10, + 0x00008093, + 0x00018297, + 0x0002c49a, + 0x0003c680, + 0x0004c880, + 0x00060b00, + 0x00070d00, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 tdi_tbl20_ant1_rev0[] = { + 0x00014b26, + 0x00028d29, + 0x000393ad, + 0x00049630, + 0x0005d833, + 0x0006da36, + 0x00099c3a, + 0x000a9e3d, + 0x000bc081, + 0x000cc284, + 0x000dc488, + 0x000f068b, + 0x0000488e, + 0x00018b91, + 0x0002d214, + 0x0003d418, + 0x0004d6a7, + 0x000618aa, + 0x00071aae, + 0x0009dcb1, + 0x000b1eb4, + 0x000c0137, + 0x000d033b, + 0x000e053e, + 0x000f4702, + 0x00008905, + 0x00020c09, + 0x0003128c, + 0x0004148f, + 0x00051712, + 0x00065916, + 0x00091b19, + 0x000a1d28, + 0x000b5f2c, + 0x000c41af, + 0x000d43b2, + 0x000e85b5, + 0x000f87b8, + 0x0000c9bc, + 0x00024cbf, + 0x00035303, + 0x00045506, + 0x0005978a, + 0x0006998d, + 0x00095b90, + 0x000a5d93, + 0x000b9f97, + 0x000c821a, + 0x000d8400, + 0x000ec600, + 0x000fc800, + 0x00010a00, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 tdi_tbl40_ant0_rev0[] = { + 0x0011a346, + 0x00136ccf, + 0x0014f5d9, + 0x001641e2, + 0x0017cb6b, + 0x00195475, + 0x001b2383, + 0x001cad0c, + 0x001e7616, + 0x0000821f, + 0x00020ba8, + 0x0003d4b2, + 0x00056447, + 0x00072dd0, + 0x0008b6da, + 0x000a02e3, + 0x000b8c6c, + 0x000d15f6, + 0x0011e484, + 0x0013ae0d, + 0x00153717, + 0x00168320, + 0x00180ca9, + 0x00199633, + 0x001b6548, + 0x001ceed1, + 0x001eb7db, + 0x0000c3e4, + 0x00024d6d, + 0x000416f7, + 0x0005a585, + 0x00076f0f, + 0x0008f818, + 0x000a4421, + 0x000bcdab, + 0x000d9734, + 0x00122649, + 0x0013efd2, + 0x001578dc, + 0x0016c4e5, + 0x00184e6e, + 0x001a17f8, + 0x001ba686, + 0x001d3010, + 0x001ef999, + 0x00010522, + 0x00028eac, + 0x00045835, + 0x0005e74a, + 0x0007b0d3, + 0x00093a5d, + 0x000a85e6, + 0x000c0f6f, + 0x000dd8f9, + 0x00126787, + 0x00143111, + 0x0015ba9a, + 0x00170623, + 0x00188fad, + 0x001a5936, + 0x001be84b, + 0x001db1d4, + 0x001f3b5e, + 0x000146e7, + 0x00031070, + 0x000499fa, + 0x00062888, + 0x0007f212, + 0x00097b9b, + 0x000ac7a4, + 0x000c50ae, + 0x000e1a37, + 0x0012a94c, + 0x001472d5, + 0x0015fc5f, + 0x00174868, + 0x0018d171, + 0x001a9afb, + 0x001c2989, + 0x001df313, + 0x001f7c9c, + 0x000188a5, + 0x000351af, + 0x0004db38, + 0x0006aa4d, + 0x000833d7, + 0x0009bd60, + 0x000b0969, + 0x000c9273, + 0x000e5bfc, + 0x00132a8a, + 0x0014b414, + 0x00163d9d, + 0x001789a6, + 0x001912b0, + 0x001adc39, + 0x001c6bce, + 0x001e34d8, + 0x001fbe61, + 0x0001ca6a, + 0x00039374, + 0x00051cfd, + 0x0006ec0b, + 0x00087515, + 0x0009fe9e, + 0x000b4aa7, + 0x000cd3b1, + 0x000e9d3a, + 0x00000000, + 0x00000000, +}; + +static const u32 tdi_tbl40_ant1_rev0[] = { + 0x001edb36, + 0x000129ca, + 0x0002b353, + 0x00047cdd, + 0x0005c8e6, + 0x000791ef, + 0x00091bf9, + 0x000aaa07, + 0x000c3391, + 0x000dfd1a, + 0x00120923, + 0x0013d22d, + 0x00155c37, + 0x0016eacb, + 0x00187454, + 0x001a3dde, + 0x001b89e7, + 0x001d12f0, + 0x001f1cfa, + 0x00016b88, + 0x00033492, + 0x0004be1b, + 0x00060a24, + 0x0007d32e, + 0x00095d38, + 0x000aec4c, + 0x000c7555, + 0x000e3edf, + 0x00124ae8, + 0x001413f1, + 0x0015a37b, + 0x00172c89, + 0x0018b593, + 0x001a419c, + 0x001bcb25, + 0x001d942f, + 0x001f63b9, + 0x0001ad4d, + 0x00037657, + 0x0004c260, + 0x00068be9, + 0x000814f3, + 0x0009a47c, + 0x000b2d8a, + 0x000cb694, + 0x000e429d, + 0x00128c26, + 0x001455b0, + 0x0015e4ba, + 0x00176e4e, + 0x0018f758, + 0x001a8361, + 0x001c0cea, + 0x001dd674, + 0x001fa57d, + 0x0001ee8b, + 0x0003b795, + 0x0005039e, + 0x0006cd27, + 0x000856b1, + 0x0009e5c6, + 0x000b6f4f, + 0x000cf859, + 0x000e8462, + 0x00130deb, + 0x00149775, + 0x00162603, + 0x0017af8c, + 0x00193896, + 0x001ac49f, + 0x001c4e28, + 0x001e17b2, + 0x0000a6c7, + 0x00023050, + 0x0003f9da, + 0x00054563, + 0x00070eec, + 0x00089876, + 0x000a2704, + 0x000bb08d, + 0x000d3a17, + 0x001185a0, + 0x00134f29, + 0x0014d8b3, + 0x001667c8, + 0x0017f151, + 0x00197adb, + 0x001b0664, + 0x001c8fed, + 0x001e5977, + 0x0000e805, + 0x0002718f, + 0x00043b18, + 0x000586a1, + 0x0007502b, + 0x0008d9b4, + 0x000a68c9, + 0x000bf252, + 0x000dbbdc, + 0x0011c7e5, + 0x001390ee, + 0x00151a78, + 0x0016a906, + 0x00183290, + 0x0019bc19, + 0x001b4822, + 0x001cd12c, + 0x001e9ab5, + 0x00000000, + 0x00000000, +}; + +static const u16 bdi_tbl_rev0[] = { + 0x0070, + 0x0126, + 0x012c, + 0x0246, + 0x048d, + 0x04d2, +}; + +static const u32 chanest_tbl_rev0[] = { + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, +}; + +static const u8 mcs_tbl_rev0[] = { + 0x00, + 0x08, + 0x0a, + 0x10, + 0x12, + 0x19, + 0x1a, + 0x1c, + 0x40, + 0x48, + 0x4a, + 0x50, + 0x52, + 0x59, + 0x5a, + 0x5c, + 0x80, + 0x88, + 0x8a, + 0x90, + 0x92, + 0x99, + 0x9a, + 0x9c, + 0xc0, + 0xc8, + 0xca, + 0xd0, + 0xd2, + 0xd9, + 0xda, + 0xdc, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x01, + 0x02, + 0x04, + 0x08, + 0x09, + 0x0a, + 0x0c, + 0x10, + 0x11, + 0x12, + 0x14, + 0x18, + 0x19, + 0x1a, + 0x1c, + 0x20, + 0x21, + 0x22, + 0x24, + 0x40, + 0x41, + 0x42, + 0x44, + 0x48, + 0x49, + 0x4a, + 0x4c, + 0x50, + 0x51, + 0x52, + 0x54, + 0x58, + 0x59, + 0x5a, + 0x5c, + 0x60, + 0x61, + 0x62, + 0x64, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +static const u32 noise_var_tbl0_rev0[] = { + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, +}; + +static const u32 noise_var_tbl1_rev0[] = { + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, +}; + +static const u8 est_pwr_lut_core0_rev0[] = { + 0x50, + 0x4f, + 0x4e, + 0x4d, + 0x4c, + 0x4b, + 0x4a, + 0x49, + 0x48, + 0x47, + 0x46, + 0x45, + 0x44, + 0x43, + 0x42, + 0x41, + 0x40, + 0x3f, + 0x3e, + 0x3d, + 0x3c, + 0x3b, + 0x3a, + 0x39, + 0x38, + 0x37, + 0x36, + 0x35, + 0x34, + 0x33, + 0x32, + 0x31, + 0x30, + 0x2f, + 0x2e, + 0x2d, + 0x2c, + 0x2b, + 0x2a, + 0x29, + 0x28, + 0x27, + 0x26, + 0x25, + 0x24, + 0x23, + 0x22, + 0x21, + 0x20, + 0x1f, + 0x1e, + 0x1d, + 0x1c, + 0x1b, + 0x1a, + 0x19, + 0x18, + 0x17, + 0x16, + 0x15, + 0x14, + 0x13, + 0x12, + 0x11, +}; + +static const u8 est_pwr_lut_core1_rev0[] = { + 0x50, + 0x4f, + 0x4e, + 0x4d, + 0x4c, + 0x4b, + 0x4a, + 0x49, + 0x48, + 0x47, + 0x46, + 0x45, + 0x44, + 0x43, + 0x42, + 0x41, + 0x40, + 0x3f, + 0x3e, + 0x3d, + 0x3c, + 0x3b, + 0x3a, + 0x39, + 0x38, + 0x37, + 0x36, + 0x35, + 0x34, + 0x33, + 0x32, + 0x31, + 0x30, + 0x2f, + 0x2e, + 0x2d, + 0x2c, + 0x2b, + 0x2a, + 0x29, + 0x28, + 0x27, + 0x26, + 0x25, + 0x24, + 0x23, + 0x22, + 0x21, + 0x20, + 0x1f, + 0x1e, + 0x1d, + 0x1c, + 0x1b, + 0x1a, + 0x19, + 0x18, + 0x17, + 0x16, + 0x15, + 0x14, + 0x13, + 0x12, + 0x11, +}; + +static const u8 adj_pwr_lut_core0_rev0[] = { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +static const u8 adj_pwr_lut_core1_rev0[] = { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +static const u32 gainctrl_lut_core0_rev0[] = { + 0x03cc2b44, + 0x03cc2b42, + 0x03cc2b40, + 0x03cc2b3e, + 0x03cc2b3d, + 0x03cc2b3b, + 0x03c82b44, + 0x03c82b42, + 0x03c82b40, + 0x03c82b3e, + 0x03c82b3d, + 0x03c82b3b, + 0x03c82b39, + 0x03c82b38, + 0x03c82b36, + 0x03c82b34, + 0x03c42b44, + 0x03c42b42, + 0x03c42b40, + 0x03c42b3e, + 0x03c42b3d, + 0x03c42b3b, + 0x03c42b39, + 0x03c42b38, + 0x03c42b36, + 0x03c42b34, + 0x03c42b33, + 0x03c42b32, + 0x03c42b30, + 0x03c42b2f, + 0x03c42b2d, + 0x03c02b44, + 0x03c02b42, + 0x03c02b40, + 0x03c02b3e, + 0x03c02b3d, + 0x03c02b3b, + 0x03c02b39, + 0x03c02b38, + 0x03c02b36, + 0x03c02b34, + 0x03b02b44, + 0x03b02b42, + 0x03b02b40, + 0x03b02b3e, + 0x03b02b3d, + 0x03b02b3b, + 0x03b02b39, + 0x03b02b38, + 0x03b02b36, + 0x03b02b34, + 0x03b02b33, + 0x03b02b32, + 0x03b02b30, + 0x03b02b2f, + 0x03b02b2d, + 0x03a02b44, + 0x03a02b42, + 0x03a02b40, + 0x03a02b3e, + 0x03a02b3d, + 0x03a02b3b, + 0x03a02b39, + 0x03a02b38, + 0x03a02b36, + 0x03a02b34, + 0x03902b44, + 0x03902b42, + 0x03902b40, + 0x03902b3e, + 0x03902b3d, + 0x03902b3b, + 0x03902b39, + 0x03902b38, + 0x03902b36, + 0x03902b34, + 0x03902b33, + 0x03902b32, + 0x03902b30, + 0x03802b44, + 0x03802b42, + 0x03802b40, + 0x03802b3e, + 0x03802b3d, + 0x03802b3b, + 0x03802b39, + 0x03802b38, + 0x03802b36, + 0x03802b34, + 0x03802b33, + 0x03802b32, + 0x03802b30, + 0x03802b2f, + 0x03802b2d, + 0x03802b2c, + 0x03802b2b, + 0x03802b2a, + 0x03802b29, + 0x03802b27, + 0x03802b26, + 0x03802b25, + 0x03802b24, + 0x03802b23, + 0x03802b22, + 0x03802b21, + 0x03802b20, + 0x03802b1f, + 0x03802b1e, + 0x03802b1e, + 0x03802b1d, + 0x03802b1c, + 0x03802b1b, + 0x03802b1a, + 0x03802b1a, + 0x03802b19, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x00002b00, +}; + +static const u32 gainctrl_lut_core1_rev0[] = { + 0x03cc2b44, + 0x03cc2b42, + 0x03cc2b40, + 0x03cc2b3e, + 0x03cc2b3d, + 0x03cc2b3b, + 0x03c82b44, + 0x03c82b42, + 0x03c82b40, + 0x03c82b3e, + 0x03c82b3d, + 0x03c82b3b, + 0x03c82b39, + 0x03c82b38, + 0x03c82b36, + 0x03c82b34, + 0x03c42b44, + 0x03c42b42, + 0x03c42b40, + 0x03c42b3e, + 0x03c42b3d, + 0x03c42b3b, + 0x03c42b39, + 0x03c42b38, + 0x03c42b36, + 0x03c42b34, + 0x03c42b33, + 0x03c42b32, + 0x03c42b30, + 0x03c42b2f, + 0x03c42b2d, + 0x03c02b44, + 0x03c02b42, + 0x03c02b40, + 0x03c02b3e, + 0x03c02b3d, + 0x03c02b3b, + 0x03c02b39, + 0x03c02b38, + 0x03c02b36, + 0x03c02b34, + 0x03b02b44, + 0x03b02b42, + 0x03b02b40, + 0x03b02b3e, + 0x03b02b3d, + 0x03b02b3b, + 0x03b02b39, + 0x03b02b38, + 0x03b02b36, + 0x03b02b34, + 0x03b02b33, + 0x03b02b32, + 0x03b02b30, + 0x03b02b2f, + 0x03b02b2d, + 0x03a02b44, + 0x03a02b42, + 0x03a02b40, + 0x03a02b3e, + 0x03a02b3d, + 0x03a02b3b, + 0x03a02b39, + 0x03a02b38, + 0x03a02b36, + 0x03a02b34, + 0x03902b44, + 0x03902b42, + 0x03902b40, + 0x03902b3e, + 0x03902b3d, + 0x03902b3b, + 0x03902b39, + 0x03902b38, + 0x03902b36, + 0x03902b34, + 0x03902b33, + 0x03902b32, + 0x03902b30, + 0x03802b44, + 0x03802b42, + 0x03802b40, + 0x03802b3e, + 0x03802b3d, + 0x03802b3b, + 0x03802b39, + 0x03802b38, + 0x03802b36, + 0x03802b34, + 0x03802b33, + 0x03802b32, + 0x03802b30, + 0x03802b2f, + 0x03802b2d, + 0x03802b2c, + 0x03802b2b, + 0x03802b2a, + 0x03802b29, + 0x03802b27, + 0x03802b26, + 0x03802b25, + 0x03802b24, + 0x03802b23, + 0x03802b22, + 0x03802b21, + 0x03802b20, + 0x03802b1f, + 0x03802b1e, + 0x03802b1e, + 0x03802b1d, + 0x03802b1c, + 0x03802b1b, + 0x03802b1a, + 0x03802b1a, + 0x03802b19, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x03802b18, + 0x00002b00, +}; + +static const u32 iq_lut_core0_rev0[] = { + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, +}; + +static const u32 iq_lut_core1_rev0[] = { + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, + 0x0000007f, +}; + +static const u16 loft_lut_core0_rev0[] = { + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, +}; + +static const u16 loft_lut_core1_rev0[] = { + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, + 0x0000, + 0x0101, + 0x0002, + 0x0103, +}; + +const struct phytbl_info mimophytbl_info_rev0_volatile[] = { + {&bdi_tbl_rev0, sizeof(bdi_tbl_rev0) / sizeof(bdi_tbl_rev0[0]), 21, 0, + 16} + , + {&pltlut_tbl_rev0, sizeof(pltlut_tbl_rev0) / sizeof(pltlut_tbl_rev0[0]), + 20, 0, 32} + , + {&gainctrl_lut_core0_rev0, + sizeof(gainctrl_lut_core0_rev0) / sizeof(gainctrl_lut_core0_rev0[0]), + 26, 192, 32} + , + {&gainctrl_lut_core1_rev0, + sizeof(gainctrl_lut_core1_rev0) / sizeof(gainctrl_lut_core1_rev0[0]), + 27, 192, 32} + , + + {&est_pwr_lut_core0_rev0, + sizeof(est_pwr_lut_core0_rev0) / sizeof(est_pwr_lut_core0_rev0[0]), 26, + 0, 8} + , + {&est_pwr_lut_core1_rev0, + sizeof(est_pwr_lut_core1_rev0) / sizeof(est_pwr_lut_core1_rev0[0]), 27, + 0, 8} + , + {&adj_pwr_lut_core0_rev0, + sizeof(adj_pwr_lut_core0_rev0) / sizeof(adj_pwr_lut_core0_rev0[0]), 26, + 64, 8} + , + {&adj_pwr_lut_core1_rev0, + sizeof(adj_pwr_lut_core1_rev0) / sizeof(adj_pwr_lut_core1_rev0[0]), 27, + 64, 8} + , + {&iq_lut_core0_rev0, + sizeof(iq_lut_core0_rev0) / sizeof(iq_lut_core0_rev0[0]), 26, 320, 32} + , + {&iq_lut_core1_rev0, + sizeof(iq_lut_core1_rev0) / sizeof(iq_lut_core1_rev0[0]), 27, 320, 32} + , + {&loft_lut_core0_rev0, + sizeof(loft_lut_core0_rev0) / sizeof(loft_lut_core0_rev0[0]), 26, 448, + 16} + , + {&loft_lut_core1_rev0, + sizeof(loft_lut_core1_rev0) / sizeof(loft_lut_core1_rev0[0]), 27, 448, + 16} + , +}; + +const struct phytbl_info mimophytbl_info_rev0[] = { + {&frame_struct_rev0, + sizeof(frame_struct_rev0) / sizeof(frame_struct_rev0[0]), 10, 0, 32} + , + {&frame_lut_rev0, sizeof(frame_lut_rev0) / sizeof(frame_lut_rev0[0]), + 24, 0, 8} + , + {&tmap_tbl_rev0, sizeof(tmap_tbl_rev0) / sizeof(tmap_tbl_rev0[0]), 12, + 0, 32} + , + {&tdtrn_tbl_rev0, sizeof(tdtrn_tbl_rev0) / sizeof(tdtrn_tbl_rev0[0]), + 14, 0, 32} + , + {&intlv_tbl_rev0, sizeof(intlv_tbl_rev0) / sizeof(intlv_tbl_rev0[0]), + 13, 0, 32} + , + {&pilot_tbl_rev0, sizeof(pilot_tbl_rev0) / sizeof(pilot_tbl_rev0[0]), + 11, 0, 16} + , + {&tdi_tbl20_ant0_rev0, + sizeof(tdi_tbl20_ant0_rev0) / sizeof(tdi_tbl20_ant0_rev0[0]), 19, 128, + 32} + , + {&tdi_tbl20_ant1_rev0, + sizeof(tdi_tbl20_ant1_rev0) / sizeof(tdi_tbl20_ant1_rev0[0]), 19, 256, + 32} + , + {&tdi_tbl40_ant0_rev0, + sizeof(tdi_tbl40_ant0_rev0) / sizeof(tdi_tbl40_ant0_rev0[0]), 19, 640, + 32} + , + {&tdi_tbl40_ant1_rev0, + sizeof(tdi_tbl40_ant1_rev0) / sizeof(tdi_tbl40_ant1_rev0[0]), 19, 768, + 32} + , + {&chanest_tbl_rev0, + sizeof(chanest_tbl_rev0) / sizeof(chanest_tbl_rev0[0]), 22, 0, 32} + , + {&mcs_tbl_rev0, sizeof(mcs_tbl_rev0) / sizeof(mcs_tbl_rev0[0]), 18, 0, + 8} + , + {&noise_var_tbl0_rev0, + sizeof(noise_var_tbl0_rev0) / sizeof(noise_var_tbl0_rev0[0]), 16, 0, + 32} + , + {&noise_var_tbl1_rev0, + sizeof(noise_var_tbl1_rev0) / sizeof(noise_var_tbl1_rev0[0]), 16, 128, + 32} + , +}; + +const u32 mimophytbl_info_sz_rev0 = + sizeof(mimophytbl_info_rev0) / sizeof(mimophytbl_info_rev0[0]); +const u32 mimophytbl_info_sz_rev0_volatile = + sizeof(mimophytbl_info_rev0_volatile) / + sizeof(mimophytbl_info_rev0_volatile[0]); + +static const u16 ant_swctrl_tbl_rev3[] = { + 0x0082, + 0x0082, + 0x0211, + 0x0222, + 0x0328, + 0x0000, + 0x0000, + 0x0000, + 0x0144, + 0x0000, + 0x0000, + 0x0000, + 0x0188, + 0x0000, + 0x0000, + 0x0000, + 0x0082, + 0x0082, + 0x0211, + 0x0222, + 0x0328, + 0x0000, + 0x0000, + 0x0000, + 0x0144, + 0x0000, + 0x0000, + 0x0000, + 0x0188, + 0x0000, + 0x0000, + 0x0000, +}; + +static const u16 ant_swctrl_tbl_rev3_1[] = { + 0x0022, + 0x0022, + 0x0011, + 0x0022, + 0x0022, + 0x0000, + 0x0000, + 0x0000, + 0x0011, + 0x0000, + 0x0000, + 0x0000, + 0x0022, + 0x0000, + 0x0000, + 0x0000, + 0x0022, + 0x0022, + 0x0011, + 0x0022, + 0x0022, + 0x0000, + 0x0000, + 0x0000, + 0x0011, + 0x0000, + 0x0000, + 0x0000, + 0x0022, + 0x0000, + 0x0000, + 0x0000, +}; + +static const u16 ant_swctrl_tbl_rev3_2[] = { + 0x0088, + 0x0088, + 0x0044, + 0x0088, + 0x0088, + 0x0000, + 0x0000, + 0x0000, + 0x0044, + 0x0000, + 0x0000, + 0x0000, + 0x0088, + 0x0000, + 0x0000, + 0x0000, + 0x0088, + 0x0088, + 0x0044, + 0x0088, + 0x0088, + 0x0000, + 0x0000, + 0x0000, + 0x0044, + 0x0000, + 0x0000, + 0x0000, + 0x0088, + 0x0000, + 0x0000, + 0x0000, +}; + +static const u16 ant_swctrl_tbl_rev3_3[] = { + 0x022, + 0x022, + 0x011, + 0x022, + 0x000, + 0x000, + 0x000, + 0x000, + 0x011, + 0x000, + 0x000, + 0x000, + 0x022, + 0x000, + 0x000, + 0x3cc, + 0x022, + 0x022, + 0x011, + 0x022, + 0x000, + 0x000, + 0x000, + 0x000, + 0x011, + 0x000, + 0x000, + 0x000, + 0x022, + 0x000, + 0x000, + 0x3cc +}; + +static const u32 frame_struct_rev3[] = { + 0x08004a04, + 0x00100000, + 0x01000a05, + 0x00100020, + 0x09804506, + 0x00100030, + 0x09804507, + 0x00100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004a0c, + 0x00100004, + 0x01000a0d, + 0x00100024, + 0x0980450e, + 0x00100034, + 0x0980450f, + 0x00100034, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000a04, + 0x00100000, + 0x11008a05, + 0x00100020, + 0x1980c506, + 0x00100030, + 0x21810506, + 0x00100030, + 0x21810506, + 0x00100030, + 0x01800504, + 0x00100030, + 0x11808505, + 0x00100030, + 0x29814507, + 0x01100030, + 0x00000a04, + 0x00100000, + 0x11008a05, + 0x00100020, + 0x21810506, + 0x00100030, + 0x21810506, + 0x00100030, + 0x29814507, + 0x01100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000a0c, + 0x00100008, + 0x11008a0d, + 0x00100028, + 0x1980c50e, + 0x00100038, + 0x2181050e, + 0x00100038, + 0x2181050e, + 0x00100038, + 0x0180050c, + 0x00100038, + 0x1180850d, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000a0c, + 0x00100008, + 0x11008a0d, + 0x00100028, + 0x2181050e, + 0x00100038, + 0x2181050e, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004a04, + 0x00100000, + 0x01000a05, + 0x00100020, + 0x1980c506, + 0x00100030, + 0x1980c506, + 0x00100030, + 0x11808504, + 0x00100030, + 0x3981ca05, + 0x00100030, + 0x29814507, + 0x01100030, + 0x00000000, + 0x00000000, + 0x10008a04, + 0x00100000, + 0x3981ca05, + 0x00100030, + 0x1980c506, + 0x00100030, + 0x29814507, + 0x01100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004a0c, + 0x00100008, + 0x01000a0d, + 0x00100028, + 0x1980c50e, + 0x00100038, + 0x1980c50e, + 0x00100038, + 0x1180850c, + 0x00100038, + 0x3981ca0d, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x10008a0c, + 0x00100008, + 0x3981ca0d, + 0x00100038, + 0x1980c50e, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40021404, + 0x00100000, + 0x02001405, + 0x00100040, + 0x0b004a06, + 0x01900060, + 0x13008a06, + 0x01900060, + 0x13008a06, + 0x01900060, + 0x43020a04, + 0x00100060, + 0x1b00ca05, + 0x00100060, + 0x23010a07, + 0x01500060, + 0x40021404, + 0x00100000, + 0x1a00d405, + 0x00100040, + 0x13008a06, + 0x01900060, + 0x13008a06, + 0x01900060, + 0x23010a07, + 0x01500060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100010, + 0x0200140d, + 0x00100050, + 0x0b004a0e, + 0x01900070, + 0x13008a0e, + 0x01900070, + 0x13008a0e, + 0x01900070, + 0x43020a0c, + 0x00100070, + 0x1b00ca0d, + 0x00100070, + 0x23010a0f, + 0x01500070, + 0x4002140c, + 0x00100010, + 0x1a00d40d, + 0x00100050, + 0x13008a0e, + 0x01900070, + 0x13008a0e, + 0x01900070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x50029404, + 0x00100000, + 0x32019405, + 0x00100040, + 0x0b004a06, + 0x01900060, + 0x0b004a06, + 0x01900060, + 0x5b02ca04, + 0x00100060, + 0x3b01d405, + 0x00100060, + 0x23010a07, + 0x01500060, + 0x00000000, + 0x00000000, + 0x5802d404, + 0x00100000, + 0x3b01d405, + 0x00100060, + 0x0b004a06, + 0x01900060, + 0x23010a07, + 0x01500060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x5002940c, + 0x00100010, + 0x3201940d, + 0x00100050, + 0x0b004a0e, + 0x01900070, + 0x0b004a0e, + 0x01900070, + 0x5b02ca0c, + 0x00100070, + 0x3b01d40d, + 0x00100070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x5802d40c, + 0x00100010, + 0x3b01d40d, + 0x00100070, + 0x0b004a0e, + 0x01900070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40021404, + 0x000f4800, + 0x62031405, + 0x00100040, + 0x53028a06, + 0x01900060, + 0x53028a07, + 0x01900060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x000f4808, + 0x6203140d, + 0x00100048, + 0x53028a0e, + 0x01900068, + 0x53028a0f, + 0x01900068, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000a0c, + 0x00100004, + 0x11008a0d, + 0x00100024, + 0x1980c50e, + 0x00100034, + 0x2181050e, + 0x00100034, + 0x2181050e, + 0x00100034, + 0x0180050c, + 0x00100038, + 0x1180850d, + 0x00100038, + 0x1181850d, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000a0c, + 0x00100008, + 0x11008a0d, + 0x00100028, + 0x2181050e, + 0x00100038, + 0x2181050e, + 0x00100038, + 0x1181850d, + 0x00100038, + 0x2981450f, + 0x01100038, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x08004a04, + 0x00100000, + 0x01000a05, + 0x00100020, + 0x0180c506, + 0x00100030, + 0x0180c506, + 0x00100030, + 0x2180c50c, + 0x00100030, + 0x49820a0d, + 0x0016a130, + 0x41824a0d, + 0x0016a130, + 0x2981450f, + 0x01100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x2000ca0c, + 0x00100000, + 0x49820a0d, + 0x0016a130, + 0x1980c50e, + 0x00100030, + 0x41824a0d, + 0x0016a130, + 0x2981450f, + 0x01100030, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100008, + 0x0200140d, + 0x00100048, + 0x0b004a0e, + 0x01900068, + 0x13008a0e, + 0x01900068, + 0x13008a0e, + 0x01900068, + 0x43020a0c, + 0x00100070, + 0x1b00ca0d, + 0x00100070, + 0x1b014a0d, + 0x00100070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100010, + 0x1a00d40d, + 0x00100050, + 0x13008a0e, + 0x01900070, + 0x13008a0e, + 0x01900070, + 0x1b014a0d, + 0x00100070, + 0x23010a0f, + 0x01500070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x50029404, + 0x00100000, + 0x32019405, + 0x00100040, + 0x03004a06, + 0x01900060, + 0x03004a06, + 0x01900060, + 0x6b030a0c, + 0x00100060, + 0x4b02140d, + 0x0016a160, + 0x4302540d, + 0x0016a160, + 0x23010a0f, + 0x01500060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x6b03140c, + 0x00100060, + 0x4b02140d, + 0x0016a160, + 0x0b004a0e, + 0x01900060, + 0x4302540d, + 0x0016a160, + 0x23010a0f, + 0x01500060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40021404, + 0x00100000, + 0x1a00d405, + 0x00100040, + 0x53028a06, + 0x01900060, + 0x5b02ca06, + 0x01900060, + 0x5b02ca06, + 0x01900060, + 0x43020a04, + 0x00100060, + 0x1b00ca05, + 0x00100060, + 0x53028a07, + 0x0190c060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100010, + 0x1a00d40d, + 0x00100050, + 0x53028a0e, + 0x01900070, + 0x5b02ca0e, + 0x01900070, + 0x5b02ca0e, + 0x01900070, + 0x43020a0c, + 0x00100070, + 0x1b00ca0d, + 0x00100070, + 0x53028a0f, + 0x0190c070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x40021404, + 0x00100000, + 0x1a00d405, + 0x00100040, + 0x5b02ca06, + 0x01900060, + 0x5b02ca06, + 0x01900060, + 0x53028a07, + 0x0190c060, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x4002140c, + 0x00100010, + 0x1a00d40d, + 0x00100050, + 0x5b02ca0e, + 0x01900070, + 0x5b02ca0e, + 0x01900070, + 0x53028a0f, + 0x0190c070, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u16 pilot_tbl_rev3[] = { + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0xff08, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0x80d5, + 0xff0a, + 0xff82, + 0xffa0, + 0xff28, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xff82, + 0xffa0, + 0xff28, + 0xff0a, + 0xffff, + 0xffff, + 0xffff, + 0xffff, + 0xf83f, + 0xfa1f, + 0xfa97, + 0xfab5, + 0xf2bd, + 0xf0bf, + 0xffff, + 0xffff, + 0xf017, + 0xf815, + 0xf215, + 0xf095, + 0xf035, + 0xf01d, + 0xffff, + 0xffff, + 0xff08, + 0xff02, + 0xff80, + 0xff20, + 0xff08, + 0xff02, + 0xff80, + 0xff20, + 0xf01f, + 0xf817, + 0xfa15, + 0xf295, + 0xf0b5, + 0xf03d, + 0xffff, + 0xffff, + 0xf82a, + 0xfa0a, + 0xfa82, + 0xfaa0, + 0xf2a8, + 0xf0aa, + 0xffff, + 0xffff, + 0xf002, + 0xf800, + 0xf200, + 0xf080, + 0xf020, + 0xf008, + 0xffff, + 0xffff, + 0xf00a, + 0xf802, + 0xfa00, + 0xf280, + 0xf0a0, + 0xf028, + 0xffff, + 0xffff, +}; + +static const u32 tmap_tbl_rev3[] = { + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00000111, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x000aa888, + 0x88880000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa2222220, + 0x22222222, + 0x22c22222, + 0x00000222, + 0x22000000, + 0x2222a222, + 0x22222222, + 0x222222a2, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00011111, + 0x11110000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0xa8aa88a0, + 0xa88888a8, + 0xa8a8a88a, + 0x00088aaa, + 0xaaaa0000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xaaa8aaa0, + 0x8aaa8aaa, + 0xaa8a8a8a, + 0x000aaa88, + 0x8aaa0000, + 0xaaa8a888, + 0x8aa88a8a, + 0x8a88a888, + 0x08080a00, + 0x0a08080a, + 0x080a0a08, + 0x00080808, + 0x080a0000, + 0x080a0808, + 0x080a0808, + 0x0a0a0a08, + 0xa0a0a0a0, + 0x80a0a080, + 0x8080a0a0, + 0x00008080, + 0x80a00000, + 0x80a080a0, + 0xa080a0a0, + 0x8080a0a0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x99999000, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb90, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00aaa888, + 0x22000000, + 0x2222b222, + 0x22222222, + 0x222222b2, + 0xb2222220, + 0x22222222, + 0x22d22222, + 0x00000222, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x33000000, + 0x3333b333, + 0x33333333, + 0x333333b3, + 0xb3333330, + 0x33333333, + 0x33d33333, + 0x00000333, + 0x22000000, + 0x2222a222, + 0x22222222, + 0x222222a2, + 0xa2222220, + 0x22222222, + 0x22c22222, + 0x00000222, + 0x99b99b00, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb99, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x08aaa888, + 0x22222200, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0x22222222, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x11111111, + 0xf1111111, + 0x11111111, + 0x11f11111, + 0x01111111, + 0xbb9bb900, + 0xb9b9bb99, + 0xb99bbbbb, + 0xbbbb9b9b, + 0xb9bb99bb, + 0xb99999b9, + 0xb9b9b99b, + 0x00000bbb, + 0xaa000000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xa8aa88aa, + 0xa88888a8, + 0xa8a8a88a, + 0x0a888aaa, + 0xaa000000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xa8aa88a0, + 0xa88888a8, + 0xa8a8a88a, + 0x00000aaa, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0xbbbbbb00, + 0x999bbbbb, + 0x9bb99b9b, + 0xb9b9b9bb, + 0xb9b99bbb, + 0xb9b9b9bb, + 0xb9bb9b99, + 0x00000999, + 0x8a000000, + 0xaa88a888, + 0xa88888aa, + 0xa88a8a88, + 0xa88aa88a, + 0x88a8aaaa, + 0xa8aa8aaa, + 0x0888a88a, + 0x0b0b0b00, + 0x090b0b0b, + 0x0b090b0b, + 0x0909090b, + 0x09090b0b, + 0x09090b0b, + 0x09090b09, + 0x00000909, + 0x0a000000, + 0x0a080808, + 0x080a080a, + 0x080a0a08, + 0x080a080a, + 0x0808080a, + 0x0a0a0a08, + 0x0808080a, + 0xb0b0b000, + 0x9090b0b0, + 0x90b09090, + 0xb0b0b090, + 0xb0b090b0, + 0x90b0b0b0, + 0xb0b09090, + 0x00000090, + 0x80000000, + 0xa080a080, + 0xa08080a0, + 0xa0808080, + 0xa080a080, + 0x80a0a0a0, + 0xa0a080a0, + 0x00a0a0a0, + 0x22000000, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0xf2222220, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00000111, + 0x33000000, + 0x3333f333, + 0x33333333, + 0x333333f3, + 0xf3333330, + 0x33333333, + 0x33f33333, + 0x00000333, + 0x22000000, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0xf2222220, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x99000000, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb90, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88888000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00aaa888, + 0x88a88a00, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x08aaa888, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 intlv_tbl_rev3[] = { + 0x00802070, + 0x0671188d, + 0x0a60192c, + 0x0a300e46, + 0x00c1188d, + 0x080024d2, + 0x00000070, +}; + +static const u32 tdtrn_tbl_rev3[] = { + 0x061c061c, + 0x0050ee68, + 0xf592fe36, + 0xfe5212f6, + 0x00000c38, + 0xfe5212f6, + 0xf592fe36, + 0x0050ee68, + 0x061c061c, + 0xee680050, + 0xfe36f592, + 0x12f6fe52, + 0x0c380000, + 0x12f6fe52, + 0xfe36f592, + 0xee680050, + 0x061c061c, + 0x0050ee68, + 0xf592fe36, + 0xfe5212f6, + 0x00000c38, + 0xfe5212f6, + 0xf592fe36, + 0x0050ee68, + 0x061c061c, + 0xee680050, + 0xfe36f592, + 0x12f6fe52, + 0x0c380000, + 0x12f6fe52, + 0xfe36f592, + 0xee680050, + 0x05e305e3, + 0x004def0c, + 0xf5f3fe47, + 0xfe611246, + 0x00000bc7, + 0xfe611246, + 0xf5f3fe47, + 0x004def0c, + 0x05e305e3, + 0xef0c004d, + 0xfe47f5f3, + 0x1246fe61, + 0x0bc70000, + 0x1246fe61, + 0xfe47f5f3, + 0xef0c004d, + 0x05e305e3, + 0x004def0c, + 0xf5f3fe47, + 0xfe611246, + 0x00000bc7, + 0xfe611246, + 0xf5f3fe47, + 0x004def0c, + 0x05e305e3, + 0xef0c004d, + 0xfe47f5f3, + 0x1246fe61, + 0x0bc70000, + 0x1246fe61, + 0xfe47f5f3, + 0xef0c004d, + 0xfa58fa58, + 0xf895043b, + 0xff4c09c0, + 0xfbc6ffa8, + 0xfb84f384, + 0x0798f6f9, + 0x05760122, + 0x058409f6, + 0x0b500000, + 0x05b7f542, + 0x08860432, + 0x06ddfee7, + 0xfb84f384, + 0xf9d90664, + 0xf7e8025c, + 0x00fff7bd, + 0x05a805a8, + 0xf7bd00ff, + 0x025cf7e8, + 0x0664f9d9, + 0xf384fb84, + 0xfee706dd, + 0x04320886, + 0xf54205b7, + 0x00000b50, + 0x09f60584, + 0x01220576, + 0xf6f90798, + 0xf384fb84, + 0xffa8fbc6, + 0x09c0ff4c, + 0x043bf895, + 0x02d402d4, + 0x07de0270, + 0xfc96079c, + 0xf90afe94, + 0xfe00ff2c, + 0x02d4065d, + 0x092a0096, + 0x0014fbb8, + 0xfd2cfd2c, + 0x076afb3c, + 0x0096f752, + 0xf991fd87, + 0xfb2c0200, + 0xfeb8f960, + 0x08e0fc96, + 0x049802a8, + 0xfd2cfd2c, + 0x02a80498, + 0xfc9608e0, + 0xf960feb8, + 0x0200fb2c, + 0xfd87f991, + 0xf7520096, + 0xfb3c076a, + 0xfd2cfd2c, + 0xfbb80014, + 0x0096092a, + 0x065d02d4, + 0xff2cfe00, + 0xfe94f90a, + 0x079cfc96, + 0x027007de, + 0x02d402d4, + 0x027007de, + 0x079cfc96, + 0xfe94f90a, + 0xff2cfe00, + 0x065d02d4, + 0x0096092a, + 0xfbb80014, + 0xfd2cfd2c, + 0xfb3c076a, + 0xf7520096, + 0xfd87f991, + 0x0200fb2c, + 0xf960feb8, + 0xfc9608e0, + 0x02a80498, + 0xfd2cfd2c, + 0x049802a8, + 0x08e0fc96, + 0xfeb8f960, + 0xfb2c0200, + 0xf991fd87, + 0x0096f752, + 0x076afb3c, + 0xfd2cfd2c, + 0x0014fbb8, + 0x092a0096, + 0x02d4065d, + 0xfe00ff2c, + 0xf90afe94, + 0xfc96079c, + 0x07de0270, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x062a0000, + 0xfefa0759, + 0x08b80908, + 0xf396fc2d, + 0xf9d6045c, + 0xfc4ef608, + 0xf748f596, + 0x07b207bf, + 0x062a062a, + 0xf84ef841, + 0xf748f596, + 0x03b209f8, + 0xf9d6045c, + 0x0c6a03d3, + 0x08b80908, + 0x0106f8a7, + 0x062a0000, + 0xfefaf8a7, + 0x08b8f6f8, + 0xf39603d3, + 0xf9d6fba4, + 0xfc4e09f8, + 0xf7480a6a, + 0x07b2f841, + 0x062af9d6, + 0xf84e07bf, + 0xf7480a6a, + 0x03b2f608, + 0xf9d6fba4, + 0x0c6afc2d, + 0x08b8f6f8, + 0x01060759, + 0x062a0000, + 0xfefa0759, + 0x08b80908, + 0xf396fc2d, + 0xf9d6045c, + 0xfc4ef608, + 0xf748f596, + 0x07b207bf, + 0x062a062a, + 0xf84ef841, + 0xf748f596, + 0x03b209f8, + 0xf9d6045c, + 0x0c6a03d3, + 0x08b80908, + 0x0106f8a7, + 0x062a0000, + 0xfefaf8a7, + 0x08b8f6f8, + 0xf39603d3, + 0xf9d6fba4, + 0xfc4e09f8, + 0xf7480a6a, + 0x07b2f841, + 0x062af9d6, + 0xf84e07bf, + 0xf7480a6a, + 0x03b2f608, + 0xf9d6fba4, + 0x0c6afc2d, + 0x08b8f6f8, + 0x01060759, + 0x061c061c, + 0xff30009d, + 0xffb21141, + 0xfd87fb54, + 0xf65dfe59, + 0x02eef99e, + 0x0166f03c, + 0xfff809b6, + 0x000008a4, + 0x000af42b, + 0x00eff577, + 0xfa840bf2, + 0xfc02ff51, + 0x08260f67, + 0xfff0036f, + 0x0842f9c3, + 0x00000000, + 0x063df7be, + 0xfc910010, + 0xf099f7da, + 0x00af03fe, + 0xf40e057c, + 0x0a89ff11, + 0x0bd5fff6, + 0xf75c0000, + 0xf64a0008, + 0x0fc4fe9a, + 0x0662fd12, + 0x01a709a3, + 0x04ac0279, + 0xeebf004e, + 0xff6300d0, + 0xf9e4f9e4, + 0x00d0ff63, + 0x004eeebf, + 0x027904ac, + 0x09a301a7, + 0xfd120662, + 0xfe9a0fc4, + 0x0008f64a, + 0x0000f75c, + 0xfff60bd5, + 0xff110a89, + 0x057cf40e, + 0x03fe00af, + 0xf7daf099, + 0x0010fc91, + 0xf7be063d, + 0x00000000, + 0xf9c30842, + 0x036ffff0, + 0x0f670826, + 0xff51fc02, + 0x0bf2fa84, + 0xf57700ef, + 0xf42b000a, + 0x08a40000, + 0x09b6fff8, + 0xf03c0166, + 0xf99e02ee, + 0xfe59f65d, + 0xfb54fd87, + 0x1141ffb2, + 0x009dff30, + 0x05e30000, + 0xff060705, + 0x085408a0, + 0xf425fc59, + 0xfa1d042a, + 0xfc78f67a, + 0xf7acf60e, + 0x075a0766, + 0x05e305e3, + 0xf8a6f89a, + 0xf7acf60e, + 0x03880986, + 0xfa1d042a, + 0x0bdb03a7, + 0x085408a0, + 0x00faf8fb, + 0x05e30000, + 0xff06f8fb, + 0x0854f760, + 0xf42503a7, + 0xfa1dfbd6, + 0xfc780986, + 0xf7ac09f2, + 0x075af89a, + 0x05e3fa1d, + 0xf8a60766, + 0xf7ac09f2, + 0x0388f67a, + 0xfa1dfbd6, + 0x0bdbfc59, + 0x0854f760, + 0x00fa0705, + 0x05e30000, + 0xff060705, + 0x085408a0, + 0xf425fc59, + 0xfa1d042a, + 0xfc78f67a, + 0xf7acf60e, + 0x075a0766, + 0x05e305e3, + 0xf8a6f89a, + 0xf7acf60e, + 0x03880986, + 0xfa1d042a, + 0x0bdb03a7, + 0x085408a0, + 0x00faf8fb, + 0x05e30000, + 0xff06f8fb, + 0x0854f760, + 0xf42503a7, + 0xfa1dfbd6, + 0xfc780986, + 0xf7ac09f2, + 0x075af89a, + 0x05e3fa1d, + 0xf8a60766, + 0xf7ac09f2, + 0x0388f67a, + 0xfa1dfbd6, + 0x0bdbfc59, + 0x0854f760, + 0x00fa0705, + 0xfa58fa58, + 0xf8f0fe00, + 0x0448073d, + 0xfdc9fe46, + 0xf9910258, + 0x089d0407, + 0xfd5cf71a, + 0x02affde0, + 0x083e0496, + 0xff5a0740, + 0xff7afd97, + 0x00fe01f1, + 0x0009082e, + 0xfa94ff75, + 0xfecdf8ea, + 0xffb0f693, + 0xfd2cfa58, + 0x0433ff16, + 0xfba405dd, + 0xfa610341, + 0x06a606cb, + 0x0039fd2d, + 0x0677fa97, + 0x01fa05e0, + 0xf896003e, + 0x075a068b, + 0x012cfc3e, + 0xfa23f98d, + 0xfc7cfd43, + 0xff90fc0d, + 0x01c10982, + 0x00c601d6, + 0xfd2cfd2c, + 0x01d600c6, + 0x098201c1, + 0xfc0dff90, + 0xfd43fc7c, + 0xf98dfa23, + 0xfc3e012c, + 0x068b075a, + 0x003ef896, + 0x05e001fa, + 0xfa970677, + 0xfd2d0039, + 0x06cb06a6, + 0x0341fa61, + 0x05ddfba4, + 0xff160433, + 0xfa58fd2c, + 0xf693ffb0, + 0xf8eafecd, + 0xff75fa94, + 0x082e0009, + 0x01f100fe, + 0xfd97ff7a, + 0x0740ff5a, + 0x0496083e, + 0xfde002af, + 0xf71afd5c, + 0x0407089d, + 0x0258f991, + 0xfe46fdc9, + 0x073d0448, + 0xfe00f8f0, + 0xfd2cfd2c, + 0xfce00500, + 0xfc09fddc, + 0xfe680157, + 0x04c70571, + 0xfc3aff21, + 0xfcd70228, + 0x056d0277, + 0x0200fe00, + 0x0022f927, + 0xfe3c032b, + 0xfc44ff3c, + 0x03e9fbdb, + 0x04570313, + 0x04c9ff5c, + 0x000d03b8, + 0xfa580000, + 0xfbe900d2, + 0xf9d0fe0b, + 0x0125fdf9, + 0x042501bf, + 0x0328fa2b, + 0xffa902f0, + 0xfa250157, + 0x0200fe00, + 0x03740438, + 0xff0405fd, + 0x030cfe52, + 0x0037fb39, + 0xff6904c5, + 0x04f8fd23, + 0xfd31fc1b, + 0xfd2cfd2c, + 0xfc1bfd31, + 0xfd2304f8, + 0x04c5ff69, + 0xfb390037, + 0xfe52030c, + 0x05fdff04, + 0x04380374, + 0xfe000200, + 0x0157fa25, + 0x02f0ffa9, + 0xfa2b0328, + 0x01bf0425, + 0xfdf90125, + 0xfe0bf9d0, + 0x00d2fbe9, + 0x0000fa58, + 0x03b8000d, + 0xff5c04c9, + 0x03130457, + 0xfbdb03e9, + 0xff3cfc44, + 0x032bfe3c, + 0xf9270022, + 0xfe000200, + 0x0277056d, + 0x0228fcd7, + 0xff21fc3a, + 0x057104c7, + 0x0157fe68, + 0xfddcfc09, + 0x0500fce0, + 0xfd2cfd2c, + 0x0500fce0, + 0xfddcfc09, + 0x0157fe68, + 0x057104c7, + 0xff21fc3a, + 0x0228fcd7, + 0x0277056d, + 0xfe000200, + 0xf9270022, + 0x032bfe3c, + 0xff3cfc44, + 0xfbdb03e9, + 0x03130457, + 0xff5c04c9, + 0x03b8000d, + 0x0000fa58, + 0x00d2fbe9, + 0xfe0bf9d0, + 0xfdf90125, + 0x01bf0425, + 0xfa2b0328, + 0x02f0ffa9, + 0x0157fa25, + 0xfe000200, + 0x04380374, + 0x05fdff04, + 0xfe52030c, + 0xfb390037, + 0x04c5ff69, + 0xfd2304f8, + 0xfc1bfd31, + 0xfd2cfd2c, + 0xfd31fc1b, + 0x04f8fd23, + 0xff6904c5, + 0x0037fb39, + 0x030cfe52, + 0xff0405fd, + 0x03740438, + 0x0200fe00, + 0xfa250157, + 0xffa902f0, + 0x0328fa2b, + 0x042501bf, + 0x0125fdf9, + 0xf9d0fe0b, + 0xfbe900d2, + 0xfa580000, + 0x000d03b8, + 0x04c9ff5c, + 0x04570313, + 0x03e9fbdb, + 0xfc44ff3c, + 0xfe3c032b, + 0x0022f927, + 0x0200fe00, + 0x056d0277, + 0xfcd70228, + 0xfc3aff21, + 0x04c70571, + 0xfe680157, + 0xfc09fddc, + 0xfce00500, + 0x05a80000, + 0xff1006be, + 0x0800084a, + 0xf49cfc7e, + 0xfa580400, + 0xfc9cf6da, + 0xf800f672, + 0x0710071c, + 0x05a805a8, + 0xf8f0f8e4, + 0xf800f672, + 0x03640926, + 0xfa580400, + 0x0b640382, + 0x0800084a, + 0x00f0f942, + 0x05a80000, + 0xff10f942, + 0x0800f7b6, + 0xf49c0382, + 0xfa58fc00, + 0xfc9c0926, + 0xf800098e, + 0x0710f8e4, + 0x05a8fa58, + 0xf8f0071c, + 0xf800098e, + 0x0364f6da, + 0xfa58fc00, + 0x0b64fc7e, + 0x0800f7b6, + 0x00f006be, + 0x05a80000, + 0xff1006be, + 0x0800084a, + 0xf49cfc7e, + 0xfa580400, + 0xfc9cf6da, + 0xf800f672, + 0x0710071c, + 0x05a805a8, + 0xf8f0f8e4, + 0xf800f672, + 0x03640926, + 0xfa580400, + 0x0b640382, + 0x0800084a, + 0x00f0f942, + 0x05a80000, + 0xff10f942, + 0x0800f7b6, + 0xf49c0382, + 0xfa58fc00, + 0xfc9c0926, + 0xf800098e, + 0x0710f8e4, + 0x05a8fa58, + 0xf8f0071c, + 0xf800098e, + 0x0364f6da, + 0xfa58fc00, + 0x0b64fc7e, + 0x0800f7b6, + 0x00f006be, +}; + +const u32 noise_var_tbl_rev3[] = { + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, + 0x02110211, + 0x0000014d, +}; + +static const u16 mcs_tbl_rev3[] = { + 0x0000, + 0x0008, + 0x000a, + 0x0010, + 0x0012, + 0x0019, + 0x001a, + 0x001c, + 0x0080, + 0x0088, + 0x008a, + 0x0090, + 0x0092, + 0x0099, + 0x009a, + 0x009c, + 0x0100, + 0x0108, + 0x010a, + 0x0110, + 0x0112, + 0x0119, + 0x011a, + 0x011c, + 0x0180, + 0x0188, + 0x018a, + 0x0190, + 0x0192, + 0x0199, + 0x019a, + 0x019c, + 0x0000, + 0x0098, + 0x00a0, + 0x00a8, + 0x009a, + 0x00a2, + 0x00aa, + 0x0120, + 0x0128, + 0x0128, + 0x0130, + 0x0138, + 0x0138, + 0x0140, + 0x0122, + 0x012a, + 0x012a, + 0x0132, + 0x013a, + 0x013a, + 0x0142, + 0x01a8, + 0x01b0, + 0x01b8, + 0x01b0, + 0x01b8, + 0x01c0, + 0x01c8, + 0x01c0, + 0x01c8, + 0x01d0, + 0x01d0, + 0x01d8, + 0x01aa, + 0x01b2, + 0x01ba, + 0x01b2, + 0x01ba, + 0x01c2, + 0x01ca, + 0x01c2, + 0x01ca, + 0x01d2, + 0x01d2, + 0x01da, + 0x0001, + 0x0002, + 0x0004, + 0x0009, + 0x000c, + 0x0011, + 0x0014, + 0x0018, + 0x0020, + 0x0021, + 0x0022, + 0x0024, + 0x0081, + 0x0082, + 0x0084, + 0x0089, + 0x008c, + 0x0091, + 0x0094, + 0x0098, + 0x00a0, + 0x00a1, + 0x00a2, + 0x00a4, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, + 0x0007, +}; + +static const u32 tdi_tbl20_ant0_rev3[] = { + 0x00091226, + 0x000a1429, + 0x000b56ad, + 0x000c58b0, + 0x000d5ab3, + 0x000e9cb6, + 0x000f9eba, + 0x0000c13d, + 0x00020301, + 0x00030504, + 0x00040708, + 0x0005090b, + 0x00064b8e, + 0x00095291, + 0x000a5494, + 0x000b9718, + 0x000c9927, + 0x000d9b2a, + 0x000edd2e, + 0x000fdf31, + 0x000101b4, + 0x000243b7, + 0x000345bb, + 0x000447be, + 0x00058982, + 0x00068c05, + 0x00099309, + 0x000a950c, + 0x000bd78f, + 0x000cd992, + 0x000ddb96, + 0x000f1d99, + 0x00005fa8, + 0x0001422c, + 0x0002842f, + 0x00038632, + 0x00048835, + 0x0005ca38, + 0x0006ccbc, + 0x0009d3bf, + 0x000b1603, + 0x000c1806, + 0x000d1a0a, + 0x000e1c0d, + 0x000f5e10, + 0x00008093, + 0x00018297, + 0x0002c49a, + 0x0003c680, + 0x0004c880, + 0x00060b00, + 0x00070d00, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 tdi_tbl20_ant1_rev3[] = { + 0x00014b26, + 0x00028d29, + 0x000393ad, + 0x00049630, + 0x0005d833, + 0x0006da36, + 0x00099c3a, + 0x000a9e3d, + 0x000bc081, + 0x000cc284, + 0x000dc488, + 0x000f068b, + 0x0000488e, + 0x00018b91, + 0x0002d214, + 0x0003d418, + 0x0004d6a7, + 0x000618aa, + 0x00071aae, + 0x0009dcb1, + 0x000b1eb4, + 0x000c0137, + 0x000d033b, + 0x000e053e, + 0x000f4702, + 0x00008905, + 0x00020c09, + 0x0003128c, + 0x0004148f, + 0x00051712, + 0x00065916, + 0x00091b19, + 0x000a1d28, + 0x000b5f2c, + 0x000c41af, + 0x000d43b2, + 0x000e85b5, + 0x000f87b8, + 0x0000c9bc, + 0x00024cbf, + 0x00035303, + 0x00045506, + 0x0005978a, + 0x0006998d, + 0x00095b90, + 0x000a5d93, + 0x000b9f97, + 0x000c821a, + 0x000d8400, + 0x000ec600, + 0x000fc800, + 0x00010a00, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 tdi_tbl40_ant0_rev3[] = { + 0x0011a346, + 0x00136ccf, + 0x0014f5d9, + 0x001641e2, + 0x0017cb6b, + 0x00195475, + 0x001b2383, + 0x001cad0c, + 0x001e7616, + 0x0000821f, + 0x00020ba8, + 0x0003d4b2, + 0x00056447, + 0x00072dd0, + 0x0008b6da, + 0x000a02e3, + 0x000b8c6c, + 0x000d15f6, + 0x0011e484, + 0x0013ae0d, + 0x00153717, + 0x00168320, + 0x00180ca9, + 0x00199633, + 0x001b6548, + 0x001ceed1, + 0x001eb7db, + 0x0000c3e4, + 0x00024d6d, + 0x000416f7, + 0x0005a585, + 0x00076f0f, + 0x0008f818, + 0x000a4421, + 0x000bcdab, + 0x000d9734, + 0x00122649, + 0x0013efd2, + 0x001578dc, + 0x0016c4e5, + 0x00184e6e, + 0x001a17f8, + 0x001ba686, + 0x001d3010, + 0x001ef999, + 0x00010522, + 0x00028eac, + 0x00045835, + 0x0005e74a, + 0x0007b0d3, + 0x00093a5d, + 0x000a85e6, + 0x000c0f6f, + 0x000dd8f9, + 0x00126787, + 0x00143111, + 0x0015ba9a, + 0x00170623, + 0x00188fad, + 0x001a5936, + 0x001be84b, + 0x001db1d4, + 0x001f3b5e, + 0x000146e7, + 0x00031070, + 0x000499fa, + 0x00062888, + 0x0007f212, + 0x00097b9b, + 0x000ac7a4, + 0x000c50ae, + 0x000e1a37, + 0x0012a94c, + 0x001472d5, + 0x0015fc5f, + 0x00174868, + 0x0018d171, + 0x001a9afb, + 0x001c2989, + 0x001df313, + 0x001f7c9c, + 0x000188a5, + 0x000351af, + 0x0004db38, + 0x0006aa4d, + 0x000833d7, + 0x0009bd60, + 0x000b0969, + 0x000c9273, + 0x000e5bfc, + 0x00132a8a, + 0x0014b414, + 0x00163d9d, + 0x001789a6, + 0x001912b0, + 0x001adc39, + 0x001c6bce, + 0x001e34d8, + 0x001fbe61, + 0x0001ca6a, + 0x00039374, + 0x00051cfd, + 0x0006ec0b, + 0x00087515, + 0x0009fe9e, + 0x000b4aa7, + 0x000cd3b1, + 0x000e9d3a, + 0x00000000, + 0x00000000, +}; + +static const u32 tdi_tbl40_ant1_rev3[] = { + 0x001edb36, + 0x000129ca, + 0x0002b353, + 0x00047cdd, + 0x0005c8e6, + 0x000791ef, + 0x00091bf9, + 0x000aaa07, + 0x000c3391, + 0x000dfd1a, + 0x00120923, + 0x0013d22d, + 0x00155c37, + 0x0016eacb, + 0x00187454, + 0x001a3dde, + 0x001b89e7, + 0x001d12f0, + 0x001f1cfa, + 0x00016b88, + 0x00033492, + 0x0004be1b, + 0x00060a24, + 0x0007d32e, + 0x00095d38, + 0x000aec4c, + 0x000c7555, + 0x000e3edf, + 0x00124ae8, + 0x001413f1, + 0x0015a37b, + 0x00172c89, + 0x0018b593, + 0x001a419c, + 0x001bcb25, + 0x001d942f, + 0x001f63b9, + 0x0001ad4d, + 0x00037657, + 0x0004c260, + 0x00068be9, + 0x000814f3, + 0x0009a47c, + 0x000b2d8a, + 0x000cb694, + 0x000e429d, + 0x00128c26, + 0x001455b0, + 0x0015e4ba, + 0x00176e4e, + 0x0018f758, + 0x001a8361, + 0x001c0cea, + 0x001dd674, + 0x001fa57d, + 0x0001ee8b, + 0x0003b795, + 0x0005039e, + 0x0006cd27, + 0x000856b1, + 0x0009e5c6, + 0x000b6f4f, + 0x000cf859, + 0x000e8462, + 0x00130deb, + 0x00149775, + 0x00162603, + 0x0017af8c, + 0x00193896, + 0x001ac49f, + 0x001c4e28, + 0x001e17b2, + 0x0000a6c7, + 0x00023050, + 0x0003f9da, + 0x00054563, + 0x00070eec, + 0x00089876, + 0x000a2704, + 0x000bb08d, + 0x000d3a17, + 0x001185a0, + 0x00134f29, + 0x0014d8b3, + 0x001667c8, + 0x0017f151, + 0x00197adb, + 0x001b0664, + 0x001c8fed, + 0x001e5977, + 0x0000e805, + 0x0002718f, + 0x00043b18, + 0x000586a1, + 0x0007502b, + 0x0008d9b4, + 0x000a68c9, + 0x000bf252, + 0x000dbbdc, + 0x0011c7e5, + 0x001390ee, + 0x00151a78, + 0x0016a906, + 0x00183290, + 0x0019bc19, + 0x001b4822, + 0x001cd12c, + 0x001e9ab5, + 0x00000000, + 0x00000000, +}; + +static const u32 pltlut_tbl_rev3[] = { + 0x76540213, + 0x62407351, + 0x76543210, + 0x76540213, + 0x76540213, + 0x76430521, +}; + +static const u32 chanest_tbl_rev3[] = { + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x44444444, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, + 0x10101010, +}; + +static const u8 frame_lut_rev3[] = { + 0x02, + 0x04, + 0x14, + 0x14, + 0x03, + 0x05, + 0x16, + 0x16, + 0x0a, + 0x0c, + 0x1c, + 0x1c, + 0x0b, + 0x0d, + 0x1e, + 0x1e, + 0x06, + 0x08, + 0x18, + 0x18, + 0x07, + 0x09, + 0x1a, + 0x1a, + 0x0e, + 0x10, + 0x20, + 0x28, + 0x0f, + 0x11, + 0x22, + 0x2a, +}; + +static const u8 est_pwr_lut_core0_rev3[] = { + 0x55, + 0x54, + 0x54, + 0x53, + 0x52, + 0x52, + 0x51, + 0x51, + 0x50, + 0x4f, + 0x4f, + 0x4e, + 0x4e, + 0x4d, + 0x4c, + 0x4c, + 0x4b, + 0x4a, + 0x49, + 0x49, + 0x48, + 0x47, + 0x46, + 0x46, + 0x45, + 0x44, + 0x43, + 0x42, + 0x41, + 0x40, + 0x40, + 0x3f, + 0x3e, + 0x3d, + 0x3c, + 0x3a, + 0x39, + 0x38, + 0x37, + 0x36, + 0x35, + 0x33, + 0x32, + 0x31, + 0x2f, + 0x2e, + 0x2c, + 0x2b, + 0x29, + 0x27, + 0x25, + 0x23, + 0x21, + 0x1f, + 0x1d, + 0x1a, + 0x18, + 0x15, + 0x12, + 0x0e, + 0x0b, + 0x07, + 0x02, + 0xfd, +}; + +static const u8 est_pwr_lut_core1_rev3[] = { + 0x55, + 0x54, + 0x54, + 0x53, + 0x52, + 0x52, + 0x51, + 0x51, + 0x50, + 0x4f, + 0x4f, + 0x4e, + 0x4e, + 0x4d, + 0x4c, + 0x4c, + 0x4b, + 0x4a, + 0x49, + 0x49, + 0x48, + 0x47, + 0x46, + 0x46, + 0x45, + 0x44, + 0x43, + 0x42, + 0x41, + 0x40, + 0x40, + 0x3f, + 0x3e, + 0x3d, + 0x3c, + 0x3a, + 0x39, + 0x38, + 0x37, + 0x36, + 0x35, + 0x33, + 0x32, + 0x31, + 0x2f, + 0x2e, + 0x2c, + 0x2b, + 0x29, + 0x27, + 0x25, + 0x23, + 0x21, + 0x1f, + 0x1d, + 0x1a, + 0x18, + 0x15, + 0x12, + 0x0e, + 0x0b, + 0x07, + 0x02, + 0xfd, +}; + +static const u8 adj_pwr_lut_core0_rev3[] = { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +static const u8 adj_pwr_lut_core1_rev3[] = { + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, +}; + +static const u32 gainctrl_lut_core0_rev3[] = { + 0x5bf70044, + 0x5bf70042, + 0x5bf70040, + 0x5bf7003e, + 0x5bf7003c, + 0x5bf7003b, + 0x5bf70039, + 0x5bf70037, + 0x5bf70036, + 0x5bf70034, + 0x5bf70033, + 0x5bf70031, + 0x5bf70030, + 0x5ba70044, + 0x5ba70042, + 0x5ba70040, + 0x5ba7003e, + 0x5ba7003c, + 0x5ba7003b, + 0x5ba70039, + 0x5ba70037, + 0x5ba70036, + 0x5ba70034, + 0x5ba70033, + 0x5b770044, + 0x5b770042, + 0x5b770040, + 0x5b77003e, + 0x5b77003c, + 0x5b77003b, + 0x5b770039, + 0x5b770037, + 0x5b770036, + 0x5b770034, + 0x5b770033, + 0x5b770031, + 0x5b770030, + 0x5b77002f, + 0x5b77002d, + 0x5b77002c, + 0x5b470044, + 0x5b470042, + 0x5b470040, + 0x5b47003e, + 0x5b47003c, + 0x5b47003b, + 0x5b470039, + 0x5b470037, + 0x5b470036, + 0x5b470034, + 0x5b470033, + 0x5b470031, + 0x5b470030, + 0x5b47002f, + 0x5b47002d, + 0x5b47002c, + 0x5b47002b, + 0x5b47002a, + 0x5b270044, + 0x5b270042, + 0x5b270040, + 0x5b27003e, + 0x5b27003c, + 0x5b27003b, + 0x5b270039, + 0x5b270037, + 0x5b270036, + 0x5b270034, + 0x5b270033, + 0x5b270031, + 0x5b270030, + 0x5b27002f, + 0x5b170044, + 0x5b170042, + 0x5b170040, + 0x5b17003e, + 0x5b17003c, + 0x5b17003b, + 0x5b170039, + 0x5b170037, + 0x5b170036, + 0x5b170034, + 0x5b170033, + 0x5b170031, + 0x5b170030, + 0x5b17002f, + 0x5b17002d, + 0x5b17002c, + 0x5b17002b, + 0x5b17002a, + 0x5b170028, + 0x5b170027, + 0x5b170026, + 0x5b170025, + 0x5b170024, + 0x5b170023, + 0x5b070044, + 0x5b070042, + 0x5b070040, + 0x5b07003e, + 0x5b07003c, + 0x5b07003b, + 0x5b070039, + 0x5b070037, + 0x5b070036, + 0x5b070034, + 0x5b070033, + 0x5b070031, + 0x5b070030, + 0x5b07002f, + 0x5b07002d, + 0x5b07002c, + 0x5b07002b, + 0x5b07002a, + 0x5b070028, + 0x5b070027, + 0x5b070026, + 0x5b070025, + 0x5b070024, + 0x5b070023, + 0x5b070022, + 0x5b070021, + 0x5b070020, + 0x5b07001f, + 0x5b07001e, + 0x5b07001d, + 0x5b07001d, + 0x5b07001c, +}; + +static const u32 gainctrl_lut_core1_rev3[] = { + 0x5bf70044, + 0x5bf70042, + 0x5bf70040, + 0x5bf7003e, + 0x5bf7003c, + 0x5bf7003b, + 0x5bf70039, + 0x5bf70037, + 0x5bf70036, + 0x5bf70034, + 0x5bf70033, + 0x5bf70031, + 0x5bf70030, + 0x5ba70044, + 0x5ba70042, + 0x5ba70040, + 0x5ba7003e, + 0x5ba7003c, + 0x5ba7003b, + 0x5ba70039, + 0x5ba70037, + 0x5ba70036, + 0x5ba70034, + 0x5ba70033, + 0x5b770044, + 0x5b770042, + 0x5b770040, + 0x5b77003e, + 0x5b77003c, + 0x5b77003b, + 0x5b770039, + 0x5b770037, + 0x5b770036, + 0x5b770034, + 0x5b770033, + 0x5b770031, + 0x5b770030, + 0x5b77002f, + 0x5b77002d, + 0x5b77002c, + 0x5b470044, + 0x5b470042, + 0x5b470040, + 0x5b47003e, + 0x5b47003c, + 0x5b47003b, + 0x5b470039, + 0x5b470037, + 0x5b470036, + 0x5b470034, + 0x5b470033, + 0x5b470031, + 0x5b470030, + 0x5b47002f, + 0x5b47002d, + 0x5b47002c, + 0x5b47002b, + 0x5b47002a, + 0x5b270044, + 0x5b270042, + 0x5b270040, + 0x5b27003e, + 0x5b27003c, + 0x5b27003b, + 0x5b270039, + 0x5b270037, + 0x5b270036, + 0x5b270034, + 0x5b270033, + 0x5b270031, + 0x5b270030, + 0x5b27002f, + 0x5b170044, + 0x5b170042, + 0x5b170040, + 0x5b17003e, + 0x5b17003c, + 0x5b17003b, + 0x5b170039, + 0x5b170037, + 0x5b170036, + 0x5b170034, + 0x5b170033, + 0x5b170031, + 0x5b170030, + 0x5b17002f, + 0x5b17002d, + 0x5b17002c, + 0x5b17002b, + 0x5b17002a, + 0x5b170028, + 0x5b170027, + 0x5b170026, + 0x5b170025, + 0x5b170024, + 0x5b170023, + 0x5b070044, + 0x5b070042, + 0x5b070040, + 0x5b07003e, + 0x5b07003c, + 0x5b07003b, + 0x5b070039, + 0x5b070037, + 0x5b070036, + 0x5b070034, + 0x5b070033, + 0x5b070031, + 0x5b070030, + 0x5b07002f, + 0x5b07002d, + 0x5b07002c, + 0x5b07002b, + 0x5b07002a, + 0x5b070028, + 0x5b070027, + 0x5b070026, + 0x5b070025, + 0x5b070024, + 0x5b070023, + 0x5b070022, + 0x5b070021, + 0x5b070020, + 0x5b07001f, + 0x5b07001e, + 0x5b07001d, + 0x5b07001d, + 0x5b07001c, +}; + +static const u32 iq_lut_core0_rev3[] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u32 iq_lut_core1_rev3[] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +static const u16 loft_lut_core0_rev3[] = { + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, +}; + +static const u16 loft_lut_core1_rev3[] = { + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, +}; + +static const u16 papd_comp_rfpwr_tbl_core0_rev3[] = { + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, +}; + +static const u16 papd_comp_rfpwr_tbl_core1_rev3[] = { + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x0036, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x002a, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x001e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x000e, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01fc, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01ee, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, + 0x01d6, +}; + +static const u32 papd_comp_epsilon_tbl_core0_rev3[] = { + 0x00000000, + 0x00001fa0, + 0x00019f78, + 0x0001df7e, + 0x03fa9f86, + 0x03fd1f90, + 0x03fe5f8a, + 0x03fb1f94, + 0x03fd9fa0, + 0x00009f98, + 0x03fd1fac, + 0x03ff9fa2, + 0x03fe9fae, + 0x00001fae, + 0x03fddfb4, + 0x03ff1fb8, + 0x03ff9fbc, + 0x03ffdfbe, + 0x03fe9fc2, + 0x03fedfc6, + 0x03fedfc6, + 0x03ff9fc8, + 0x03ff5fc6, + 0x03fedfc2, + 0x03ff9fc0, + 0x03ff5fac, + 0x03ff5fac, + 0x03ff9fa2, + 0x03ff9fa6, + 0x03ff9faa, + 0x03ff5fb0, + 0x03ff5fb4, + 0x03ff1fca, + 0x03ff5fce, + 0x03fcdfdc, + 0x03fb4006, + 0x00000030, + 0x03ff808a, + 0x03ff80da, + 0x0000016c, + 0x03ff8318, + 0x03ff063a, + 0x03fd8bd6, + 0x00014ffe, + 0x00034ffe, + 0x00034ffe, + 0x0003cffe, + 0x00040ffe, + 0x00040ffe, + 0x0003cffe, + 0x0003cffe, + 0x00020ffe, + 0x03fe0ffe, + 0x03fdcffe, + 0x03f94ffe, + 0x03f54ffe, + 0x03f44ffe, + 0x03ef8ffe, + 0x03ee0ffe, + 0x03ebcffe, + 0x03e8cffe, + 0x03e74ffe, + 0x03e4cffe, + 0x03e38ffe, +}; + +static const u32 papd_cal_scalars_tbl_core0_rev3[] = { + 0x05af005a, + 0x0571005e, + 0x05040066, + 0x04bd006c, + 0x047d0072, + 0x04430078, + 0x03f70081, + 0x03cb0087, + 0x03870091, + 0x035e0098, + 0x032e00a1, + 0x030300aa, + 0x02d800b4, + 0x02ae00bf, + 0x028900ca, + 0x026400d6, + 0x024100e3, + 0x022200f0, + 0x020200ff, + 0x01e5010e, + 0x01ca011e, + 0x01b0012f, + 0x01990140, + 0x01830153, + 0x016c0168, + 0x0158017d, + 0x01450193, + 0x013301ab, + 0x012101c5, + 0x011101e0, + 0x010201fc, + 0x00f4021a, + 0x00e6011d, + 0x00d9012e, + 0x00cd0140, + 0x00c20153, + 0x00b70167, + 0x00ac017c, + 0x00a30193, + 0x009a01ab, + 0x009101c4, + 0x008901df, + 0x008101fb, + 0x007a0219, + 0x00730239, + 0x006d025b, + 0x0067027e, + 0x006102a4, + 0x005c02cc, + 0x005602f6, + 0x00520323, + 0x004d0353, + 0x00490385, + 0x004503bb, + 0x004103f3, + 0x003d042f, + 0x003a046f, + 0x003704b2, + 0x003404f9, + 0x00310545, + 0x002e0596, + 0x002b05f5, + 0x00290640, + 0x002606a4, +}; + +static const u32 papd_comp_epsilon_tbl_core1_rev3[] = { + 0x00000000, + 0x00001fa0, + 0x00019f78, + 0x0001df7e, + 0x03fa9f86, + 0x03fd1f90, + 0x03fe5f8a, + 0x03fb1f94, + 0x03fd9fa0, + 0x00009f98, + 0x03fd1fac, + 0x03ff9fa2, + 0x03fe9fae, + 0x00001fae, + 0x03fddfb4, + 0x03ff1fb8, + 0x03ff9fbc, + 0x03ffdfbe, + 0x03fe9fc2, + 0x03fedfc6, + 0x03fedfc6, + 0x03ff9fc8, + 0x03ff5fc6, + 0x03fedfc2, + 0x03ff9fc0, + 0x03ff5fac, + 0x03ff5fac, + 0x03ff9fa2, + 0x03ff9fa6, + 0x03ff9faa, + 0x03ff5fb0, + 0x03ff5fb4, + 0x03ff1fca, + 0x03ff5fce, + 0x03fcdfdc, + 0x03fb4006, + 0x00000030, + 0x03ff808a, + 0x03ff80da, + 0x0000016c, + 0x03ff8318, + 0x03ff063a, + 0x03fd8bd6, + 0x00014ffe, + 0x00034ffe, + 0x00034ffe, + 0x0003cffe, + 0x00040ffe, + 0x00040ffe, + 0x0003cffe, + 0x0003cffe, + 0x00020ffe, + 0x03fe0ffe, + 0x03fdcffe, + 0x03f94ffe, + 0x03f54ffe, + 0x03f44ffe, + 0x03ef8ffe, + 0x03ee0ffe, + 0x03ebcffe, + 0x03e8cffe, + 0x03e74ffe, + 0x03e4cffe, + 0x03e38ffe, +}; + +static const u32 papd_cal_scalars_tbl_core1_rev3[] = { + 0x05af005a, + 0x0571005e, + 0x05040066, + 0x04bd006c, + 0x047d0072, + 0x04430078, + 0x03f70081, + 0x03cb0087, + 0x03870091, + 0x035e0098, + 0x032e00a1, + 0x030300aa, + 0x02d800b4, + 0x02ae00bf, + 0x028900ca, + 0x026400d6, + 0x024100e3, + 0x022200f0, + 0x020200ff, + 0x01e5010e, + 0x01ca011e, + 0x01b0012f, + 0x01990140, + 0x01830153, + 0x016c0168, + 0x0158017d, + 0x01450193, + 0x013301ab, + 0x012101c5, + 0x011101e0, + 0x010201fc, + 0x00f4021a, + 0x00e6011d, + 0x00d9012e, + 0x00cd0140, + 0x00c20153, + 0x00b70167, + 0x00ac017c, + 0x00a30193, + 0x009a01ab, + 0x009101c4, + 0x008901df, + 0x008101fb, + 0x007a0219, + 0x00730239, + 0x006d025b, + 0x0067027e, + 0x006102a4, + 0x005c02cc, + 0x005602f6, + 0x00520323, + 0x004d0353, + 0x00490385, + 0x004503bb, + 0x004103f3, + 0x003d042f, + 0x003a046f, + 0x003704b2, + 0x003404f9, + 0x00310545, + 0x002e0596, + 0x002b05f5, + 0x00290640, + 0x002606a4, +}; + +const struct phytbl_info mimophytbl_info_rev3_volatile[] = { + {&ant_swctrl_tbl_rev3, + sizeof(ant_swctrl_tbl_rev3) / sizeof(ant_swctrl_tbl_rev3[0]), 9, 0, 16} + , +}; + +const struct phytbl_info mimophytbl_info_rev3_volatile1[] = { + {&ant_swctrl_tbl_rev3_1, + sizeof(ant_swctrl_tbl_rev3_1) / sizeof(ant_swctrl_tbl_rev3_1[0]), 9, 0, + 16} + , +}; + +const struct phytbl_info mimophytbl_info_rev3_volatile2[] = { + {&ant_swctrl_tbl_rev3_2, + sizeof(ant_swctrl_tbl_rev3_2) / sizeof(ant_swctrl_tbl_rev3_2[0]), 9, 0, + 16} + , +}; + +const struct phytbl_info mimophytbl_info_rev3_volatile3[] = { + {&ant_swctrl_tbl_rev3_3, + sizeof(ant_swctrl_tbl_rev3_3) / sizeof(ant_swctrl_tbl_rev3_3[0]), 9, 0, + 16} + , +}; + +const struct phytbl_info mimophytbl_info_rev3[] = { + {&frame_struct_rev3, + sizeof(frame_struct_rev3) / sizeof(frame_struct_rev3[0]), 10, 0, 32} + , + {&pilot_tbl_rev3, sizeof(pilot_tbl_rev3) / sizeof(pilot_tbl_rev3[0]), + 11, 0, 16} + , + {&tmap_tbl_rev3, sizeof(tmap_tbl_rev3) / sizeof(tmap_tbl_rev3[0]), 12, + 0, 32} + , + {&intlv_tbl_rev3, sizeof(intlv_tbl_rev3) / sizeof(intlv_tbl_rev3[0]), + 13, 0, 32} + , + {&tdtrn_tbl_rev3, sizeof(tdtrn_tbl_rev3) / sizeof(tdtrn_tbl_rev3[0]), + 14, 0, 32} + , + {&noise_var_tbl_rev3, + sizeof(noise_var_tbl_rev3) / sizeof(noise_var_tbl_rev3[0]), 16, 0, 32} + , + {&mcs_tbl_rev3, sizeof(mcs_tbl_rev3) / sizeof(mcs_tbl_rev3[0]), 18, 0, + 16} + , + {&tdi_tbl20_ant0_rev3, + sizeof(tdi_tbl20_ant0_rev3) / sizeof(tdi_tbl20_ant0_rev3[0]), 19, 128, + 32} + , + {&tdi_tbl20_ant1_rev3, + sizeof(tdi_tbl20_ant1_rev3) / sizeof(tdi_tbl20_ant1_rev3[0]), 19, 256, + 32} + , + {&tdi_tbl40_ant0_rev3, + sizeof(tdi_tbl40_ant0_rev3) / sizeof(tdi_tbl40_ant0_rev3[0]), 19, 640, + 32} + , + {&tdi_tbl40_ant1_rev3, + sizeof(tdi_tbl40_ant1_rev3) / sizeof(tdi_tbl40_ant1_rev3[0]), 19, 768, + 32} + , + {&pltlut_tbl_rev3, sizeof(pltlut_tbl_rev3) / sizeof(pltlut_tbl_rev3[0]), + 20, 0, 32} + , + {&chanest_tbl_rev3, + sizeof(chanest_tbl_rev3) / sizeof(chanest_tbl_rev3[0]), 22, 0, 32} + , + {&frame_lut_rev3, sizeof(frame_lut_rev3) / sizeof(frame_lut_rev3[0]), + 24, 0, 8} + , + {&est_pwr_lut_core0_rev3, + sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26, + 0, 8} + , + {&est_pwr_lut_core1_rev3, + sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27, + 0, 8} + , + {&adj_pwr_lut_core0_rev3, + sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26, + 64, 8} + , + {&adj_pwr_lut_core1_rev3, + sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27, + 64, 8} + , + {&gainctrl_lut_core0_rev3, + sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]), + 26, 192, 32} + , + {&gainctrl_lut_core1_rev3, + sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]), + 27, 192, 32} + , + {&iq_lut_core0_rev3, + sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32} + , + {&iq_lut_core1_rev3, + sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32} + , + {&loft_lut_core0_rev3, + sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448, + 16} + , + {&loft_lut_core1_rev3, + sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448, + 16} +}; + +const u32 mimophytbl_info_sz_rev3 = + sizeof(mimophytbl_info_rev3) / sizeof(mimophytbl_info_rev3[0]); +const u32 mimophytbl_info_sz_rev3_volatile = + sizeof(mimophytbl_info_rev3_volatile) / + sizeof(mimophytbl_info_rev3_volatile[0]); +const u32 mimophytbl_info_sz_rev3_volatile1 = + sizeof(mimophytbl_info_rev3_volatile1) / + sizeof(mimophytbl_info_rev3_volatile1[0]); +const u32 mimophytbl_info_sz_rev3_volatile2 = + sizeof(mimophytbl_info_rev3_volatile2) / + sizeof(mimophytbl_info_rev3_volatile2[0]); +const u32 mimophytbl_info_sz_rev3_volatile3 = + sizeof(mimophytbl_info_rev3_volatile3) / + sizeof(mimophytbl_info_rev3_volatile3[0]); + +static const u32 tmap_tbl_rev7[] = { + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00000111, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x000aa888, + 0x88880000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa2222220, + 0x22222222, + 0x22c22222, + 0x00000222, + 0x22000000, + 0x2222a222, + 0x22222222, + 0x222222a2, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00011111, + 0x11110000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0xa8aa88a0, + 0xa88888a8, + 0xa8a8a88a, + 0x00088aaa, + 0xaaaa0000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xaaa8aaa0, + 0x8aaa8aaa, + 0xaa8a8a8a, + 0x000aaa88, + 0x8aaa0000, + 0xaaa8a888, + 0x8aa88a8a, + 0x8a88a888, + 0x08080a00, + 0x0a08080a, + 0x080a0a08, + 0x00080808, + 0x080a0000, + 0x080a0808, + 0x080a0808, + 0x0a0a0a08, + 0xa0a0a0a0, + 0x80a0a080, + 0x8080a0a0, + 0x00008080, + 0x80a00000, + 0x80a080a0, + 0xa080a0a0, + 0x8080a0a0, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x99999000, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb90, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00aaa888, + 0x22000000, + 0x2222b222, + 0x22222222, + 0x222222b2, + 0xb2222220, + 0x22222222, + 0x22d22222, + 0x00000222, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x33000000, + 0x3333b333, + 0x33333333, + 0x333333b3, + 0xb3333330, + 0x33333333, + 0x33d33333, + 0x00000333, + 0x22000000, + 0x2222a222, + 0x22222222, + 0x222222a2, + 0xa2222220, + 0x22222222, + 0x22c22222, + 0x00000222, + 0x99b99b00, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb99, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x08aaa888, + 0x22222200, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0x22222222, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x11111111, + 0xf1111111, + 0x11111111, + 0x11f11111, + 0x01111111, + 0xbb9bb900, + 0xb9b9bb99, + 0xb99bbbbb, + 0xbbbb9b9b, + 0xb9bb99bb, + 0xb99999b9, + 0xb9b9b99b, + 0x00000bbb, + 0xaa000000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xa8aa88aa, + 0xa88888a8, + 0xa8a8a88a, + 0x0a888aaa, + 0xaa000000, + 0xa8a8aa88, + 0xa88aaaaa, + 0xaaaa8a8a, + 0xa8aa88a0, + 0xa88888a8, + 0xa8a8a88a, + 0x00000aaa, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0xbbbbbb00, + 0x999bbbbb, + 0x9bb99b9b, + 0xb9b9b9bb, + 0xb9b99bbb, + 0xb9b9b9bb, + 0xb9bb9b99, + 0x00000999, + 0x8a000000, + 0xaa88a888, + 0xa88888aa, + 0xa88a8a88, + 0xa88aa88a, + 0x88a8aaaa, + 0xa8aa8aaa, + 0x0888a88a, + 0x0b0b0b00, + 0x090b0b0b, + 0x0b090b0b, + 0x0909090b, + 0x09090b0b, + 0x09090b0b, + 0x09090b09, + 0x00000909, + 0x0a000000, + 0x0a080808, + 0x080a080a, + 0x080a0a08, + 0x080a080a, + 0x0808080a, + 0x0a0a0a08, + 0x0808080a, + 0xb0b0b000, + 0x9090b0b0, + 0x90b09090, + 0xb0b0b090, + 0xb0b090b0, + 0x90b0b0b0, + 0xb0b09090, + 0x00000090, + 0x80000000, + 0xa080a080, + 0xa08080a0, + 0xa0808080, + 0xa080a080, + 0x80a0a0a0, + 0xa0a080a0, + 0x00a0a0a0, + 0x22000000, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0xf2222220, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x11000000, + 0x1111f111, + 0x11111111, + 0x111111f1, + 0xf1111110, + 0x11111111, + 0x11f11111, + 0x00000111, + 0x33000000, + 0x3333f333, + 0x33333333, + 0x333333f3, + 0xf3333330, + 0x33333333, + 0x33f33333, + 0x00000333, + 0x22000000, + 0x2222f222, + 0x22222222, + 0x222222f2, + 0xf2222220, + 0x22222222, + 0x22f22222, + 0x00000222, + 0x99000000, + 0x9b9b99bb, + 0x9bb99999, + 0x9999b9b9, + 0x9b99bb90, + 0x9bbbbb9b, + 0x9b9b9bb9, + 0x00000999, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88888000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00aaa888, + 0x88a88a00, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x000aa888, + 0x88880000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa88, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x08aaa888, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x11000000, + 0x1111a111, + 0x11111111, + 0x111111a1, + 0xa1111110, + 0x11111111, + 0x11c11111, + 0x00000111, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x88000000, + 0x8a8a88aa, + 0x8aa88888, + 0x8888a8a8, + 0x8a88aa80, + 0x8aaaaa8a, + 0x8a8a8aa8, + 0x00000888, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +const u32 noise_var_tbl_rev7[] = { + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, + 0x020c020c, + 0x0000014d, +}; + +static const u32 papd_comp_epsilon_tbl_core0_rev7[] = { + 0x00000000, + 0x00000000, + 0x00016023, + 0x00006028, + 0x00034036, + 0x0003402e, + 0x0007203c, + 0x0006e037, + 0x00070030, + 0x0009401f, + 0x0009a00f, + 0x000b600d, + 0x000c8007, + 0x000ce007, + 0x00101fff, + 0x00121ff9, + 0x0012e004, + 0x0014dffc, + 0x0016dff6, + 0x0018dfe9, + 0x001b3fe5, + 0x001c5fd0, + 0x001ddfc2, + 0x001f1fb6, + 0x00207fa4, + 0x00219f8f, + 0x0022ff7d, + 0x00247f6c, + 0x0024df5b, + 0x00267f4b, + 0x0027df3b, + 0x0029bf3b, + 0x002b5f2f, + 0x002d3f2e, + 0x002f5f2a, + 0x002fff15, + 0x00315f0b, + 0x0032defa, + 0x0033beeb, + 0x0034fed9, + 0x00353ec5, + 0x00361eb0, + 0x00363e9b, + 0x0036be87, + 0x0036be70, + 0x0038fe67, + 0x0044beb2, + 0x00513ef3, + 0x00595f11, + 0x00669f3d, + 0x0078dfdf, + 0x00a143aa, + 0x01642fff, + 0x0162afff, + 0x01620fff, + 0x0160cfff, + 0x015f0fff, + 0x015dafff, + 0x015bcfff, + 0x015bcfff, + 0x015b4fff, + 0x015acfff, + 0x01590fff, + 0x0156cfff, +}; + +static const u32 papd_cal_scalars_tbl_core0_rev7[] = { + 0x0b5e002d, + 0x0ae2002f, + 0x0a3b0032, + 0x09a70035, + 0x09220038, + 0x08ab003b, + 0x081f003f, + 0x07a20043, + 0x07340047, + 0x06d2004b, + 0x067a004f, + 0x06170054, + 0x05bf0059, + 0x0571005e, + 0x051e0064, + 0x04d3006a, + 0x04910070, + 0x044c0077, + 0x040f007e, + 0x03d90085, + 0x03a1008d, + 0x036f0095, + 0x033d009e, + 0x030b00a8, + 0x02e000b2, + 0x02b900bc, + 0x029200c7, + 0x026d00d3, + 0x024900e0, + 0x022900ed, + 0x020a00fb, + 0x01ec010a, + 0x01d20119, + 0x01b7012a, + 0x019e013c, + 0x0188014e, + 0x01720162, + 0x015d0177, + 0x0149018e, + 0x013701a5, + 0x012601be, + 0x011501d8, + 0x010601f4, + 0x00f70212, + 0x00e90231, + 0x00dc0253, + 0x00d00276, + 0x00c4029b, + 0x00b902c3, + 0x00af02ed, + 0x00a50319, + 0x009c0348, + 0x0093037a, + 0x008b03af, + 0x008303e6, + 0x007c0422, + 0x00750460, + 0x006e04a3, + 0x006804e9, + 0x00620533, + 0x005d0582, + 0x005805d6, + 0x0053062e, + 0x004e068c, +}; + +static const u32 papd_comp_epsilon_tbl_core1_rev7[] = { + 0x00000000, + 0x00000000, + 0x00016023, + 0x00006028, + 0x00034036, + 0x0003402e, + 0x0007203c, + 0x0006e037, + 0x00070030, + 0x0009401f, + 0x0009a00f, + 0x000b600d, + 0x000c8007, + 0x000ce007, + 0x00101fff, + 0x00121ff9, + 0x0012e004, + 0x0014dffc, + 0x0016dff6, + 0x0018dfe9, + 0x001b3fe5, + 0x001c5fd0, + 0x001ddfc2, + 0x001f1fb6, + 0x00207fa4, + 0x00219f8f, + 0x0022ff7d, + 0x00247f6c, + 0x0024df5b, + 0x00267f4b, + 0x0027df3b, + 0x0029bf3b, + 0x002b5f2f, + 0x002d3f2e, + 0x002f5f2a, + 0x002fff15, + 0x00315f0b, + 0x0032defa, + 0x0033beeb, + 0x0034fed9, + 0x00353ec5, + 0x00361eb0, + 0x00363e9b, + 0x0036be87, + 0x0036be70, + 0x0038fe67, + 0x0044beb2, + 0x00513ef3, + 0x00595f11, + 0x00669f3d, + 0x0078dfdf, + 0x00a143aa, + 0x01642fff, + 0x0162afff, + 0x01620fff, + 0x0160cfff, + 0x015f0fff, + 0x015dafff, + 0x015bcfff, + 0x015bcfff, + 0x015b4fff, + 0x015acfff, + 0x01590fff, + 0x0156cfff, +}; + +static const u32 papd_cal_scalars_tbl_core1_rev7[] = { + 0x0b5e002d, + 0x0ae2002f, + 0x0a3b0032, + 0x09a70035, + 0x09220038, + 0x08ab003b, + 0x081f003f, + 0x07a20043, + 0x07340047, + 0x06d2004b, + 0x067a004f, + 0x06170054, + 0x05bf0059, + 0x0571005e, + 0x051e0064, + 0x04d3006a, + 0x04910070, + 0x044c0077, + 0x040f007e, + 0x03d90085, + 0x03a1008d, + 0x036f0095, + 0x033d009e, + 0x030b00a8, + 0x02e000b2, + 0x02b900bc, + 0x029200c7, + 0x026d00d3, + 0x024900e0, + 0x022900ed, + 0x020a00fb, + 0x01ec010a, + 0x01d20119, + 0x01b7012a, + 0x019e013c, + 0x0188014e, + 0x01720162, + 0x015d0177, + 0x0149018e, + 0x013701a5, + 0x012601be, + 0x011501d8, + 0x010601f4, + 0x00f70212, + 0x00e90231, + 0x00dc0253, + 0x00d00276, + 0x00c4029b, + 0x00b902c3, + 0x00af02ed, + 0x00a50319, + 0x009c0348, + 0x0093037a, + 0x008b03af, + 0x008303e6, + 0x007c0422, + 0x00750460, + 0x006e04a3, + 0x006804e9, + 0x00620533, + 0x005d0582, + 0x005805d6, + 0x0053062e, + 0x004e068c, +}; + +const struct phytbl_info mimophytbl_info_rev7[] = { + {&frame_struct_rev3, + sizeof(frame_struct_rev3) / sizeof(frame_struct_rev3[0]), 10, 0, 32} + , + {&pilot_tbl_rev3, sizeof(pilot_tbl_rev3) / sizeof(pilot_tbl_rev3[0]), + 11, 0, 16} + , + {&tmap_tbl_rev7, sizeof(tmap_tbl_rev7) / sizeof(tmap_tbl_rev7[0]), 12, + 0, 32} + , + {&intlv_tbl_rev3, sizeof(intlv_tbl_rev3) / sizeof(intlv_tbl_rev3[0]), + 13, 0, 32} + , + {&tdtrn_tbl_rev3, sizeof(tdtrn_tbl_rev3) / sizeof(tdtrn_tbl_rev3[0]), + 14, 0, 32} + , + {&noise_var_tbl_rev7, + sizeof(noise_var_tbl_rev7) / sizeof(noise_var_tbl_rev7[0]), 16, 0, 32} + , + {&mcs_tbl_rev3, sizeof(mcs_tbl_rev3) / sizeof(mcs_tbl_rev3[0]), 18, 0, + 16} + , + {&tdi_tbl20_ant0_rev3, + sizeof(tdi_tbl20_ant0_rev3) / sizeof(tdi_tbl20_ant0_rev3[0]), 19, 128, + 32} + , + {&tdi_tbl20_ant1_rev3, + sizeof(tdi_tbl20_ant1_rev3) / sizeof(tdi_tbl20_ant1_rev3[0]), 19, 256, + 32} + , + {&tdi_tbl40_ant0_rev3, + sizeof(tdi_tbl40_ant0_rev3) / sizeof(tdi_tbl40_ant0_rev3[0]), 19, 640, + 32} + , + {&tdi_tbl40_ant1_rev3, + sizeof(tdi_tbl40_ant1_rev3) / sizeof(tdi_tbl40_ant1_rev3[0]), 19, 768, + 32} + , + {&pltlut_tbl_rev3, sizeof(pltlut_tbl_rev3) / sizeof(pltlut_tbl_rev3[0]), + 20, 0, 32} + , + {&chanest_tbl_rev3, + sizeof(chanest_tbl_rev3) / sizeof(chanest_tbl_rev3[0]), 22, 0, 32} + , + {&frame_lut_rev3, sizeof(frame_lut_rev3) / sizeof(frame_lut_rev3[0]), + 24, 0, 8} + , + {&est_pwr_lut_core0_rev3, + sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26, + 0, 8} + , + {&est_pwr_lut_core1_rev3, + sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27, + 0, 8} + , + {&adj_pwr_lut_core0_rev3, + sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26, + 64, 8} + , + {&adj_pwr_lut_core1_rev3, + sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27, + 64, 8} + , + {&gainctrl_lut_core0_rev3, + sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]), + 26, 192, 32} + , + {&gainctrl_lut_core1_rev3, + sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]), + 27, 192, 32} + , + {&iq_lut_core0_rev3, + sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32} + , + {&iq_lut_core1_rev3, + sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32} + , + {&loft_lut_core0_rev3, + sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448, + 16} + , + {&loft_lut_core1_rev3, + sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448, + 16} + , + {&papd_comp_rfpwr_tbl_core0_rev3, + sizeof(papd_comp_rfpwr_tbl_core0_rev3) / + sizeof(papd_comp_rfpwr_tbl_core0_rev3[0]), 26, 576, 16} + , + {&papd_comp_rfpwr_tbl_core1_rev3, + sizeof(papd_comp_rfpwr_tbl_core1_rev3) / + sizeof(papd_comp_rfpwr_tbl_core1_rev3[0]), 27, 576, 16} + , + {&papd_comp_epsilon_tbl_core0_rev7, + sizeof(papd_comp_epsilon_tbl_core0_rev7) / + sizeof(papd_comp_epsilon_tbl_core0_rev7[0]), 31, 0, 32} + , + {&papd_cal_scalars_tbl_core0_rev7, + sizeof(papd_cal_scalars_tbl_core0_rev7) / + sizeof(papd_cal_scalars_tbl_core0_rev7[0]), 32, 0, 32} + , + {&papd_comp_epsilon_tbl_core1_rev7, + sizeof(papd_comp_epsilon_tbl_core1_rev7) / + sizeof(papd_comp_epsilon_tbl_core1_rev7[0]), 33, 0, 32} + , + {&papd_cal_scalars_tbl_core1_rev7, + sizeof(papd_cal_scalars_tbl_core1_rev7) / + sizeof(papd_cal_scalars_tbl_core1_rev7[0]), 34, 0, 32} + , +}; + +const u32 mimophytbl_info_sz_rev7 = + sizeof(mimophytbl_info_rev7) / sizeof(mimophytbl_info_rev7[0]); + +const struct phytbl_info mimophytbl_info_rev16[] = { + {&noise_var_tbl_rev7, + sizeof(noise_var_tbl_rev7) / sizeof(noise_var_tbl_rev7[0]), 16, 0, 32} + , + {&est_pwr_lut_core0_rev3, + sizeof(est_pwr_lut_core0_rev3) / sizeof(est_pwr_lut_core0_rev3[0]), 26, + 0, 8} + , + {&est_pwr_lut_core1_rev3, + sizeof(est_pwr_lut_core1_rev3) / sizeof(est_pwr_lut_core1_rev3[0]), 27, + 0, 8} + , + {&adj_pwr_lut_core0_rev3, + sizeof(adj_pwr_lut_core0_rev3) / sizeof(adj_pwr_lut_core0_rev3[0]), 26, + 64, 8} + , + {&adj_pwr_lut_core1_rev3, + sizeof(adj_pwr_lut_core1_rev3) / sizeof(adj_pwr_lut_core1_rev3[0]), 27, + 64, 8} + , + {&gainctrl_lut_core0_rev3, + sizeof(gainctrl_lut_core0_rev3) / sizeof(gainctrl_lut_core0_rev3[0]), + 26, 192, 32} + , + {&gainctrl_lut_core1_rev3, + sizeof(gainctrl_lut_core1_rev3) / sizeof(gainctrl_lut_core1_rev3[0]), + 27, 192, 32} + , + {&iq_lut_core0_rev3, + sizeof(iq_lut_core0_rev3) / sizeof(iq_lut_core0_rev3[0]), 26, 320, 32} + , + {&iq_lut_core1_rev3, + sizeof(iq_lut_core1_rev3) / sizeof(iq_lut_core1_rev3[0]), 27, 320, 32} + , + {&loft_lut_core0_rev3, + sizeof(loft_lut_core0_rev3) / sizeof(loft_lut_core0_rev3[0]), 26, 448, + 16} + , + {&loft_lut_core1_rev3, + sizeof(loft_lut_core1_rev3) / sizeof(loft_lut_core1_rev3[0]), 27, 448, + 16} + , +}; + +const u32 mimophytbl_info_sz_rev16 = + sizeof(mimophytbl_info_rev16) / sizeof(mimophytbl_info_rev16[0]); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h new file mode 100644 index 000000000000..dc8a84e85117 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phytbl_n.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +#define ANT_SWCTRL_TBL_REV3_IDX (0) + +#include <types.h> +#include "phy_int.h" + +extern const struct phytbl_info mimophytbl_info_rev0[], + mimophytbl_info_rev0_volatile[]; + +extern const u32 mimophytbl_info_sz_rev0, + mimophytbl_info_sz_rev0_volatile; + +extern const struct phytbl_info mimophytbl_info_rev3[], + mimophytbl_info_rev3_volatile[], + mimophytbl_info_rev3_volatile1[], + mimophytbl_info_rev3_volatile2[], + mimophytbl_info_rev3_volatile3[]; + +extern const u32 mimophytbl_info_sz_rev3, + mimophytbl_info_sz_rev3_volatile, + mimophytbl_info_sz_rev3_volatile1, + mimophytbl_info_sz_rev3_volatile2, + mimophytbl_info_sz_rev3_volatile3; + +extern const u32 noise_var_tbl_rev3[]; + +extern const struct phytbl_info mimophytbl_info_rev7[]; + +extern const u32 mimophytbl_info_sz_rev7; + +extern const u32 noise_var_tbl_rev7[]; + +extern const struct phytbl_info mimophytbl_info_rev16[]; + +extern const u32 mimophytbl_info_sz_rev16; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c new file mode 100644 index 000000000000..5926854f62e2 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +/* + * This is "two-way" interface, acting as the SHIM layer between driver + * and PHY layer. The driver can optionally call this translation layer + * to do some preprocessing, then reach PHY. On the PHY->driver direction, + * all calls go through this layer since PHY doesn't have access to the + * driver's brcms_hardware pointer. + */ +#include <linux/slab.h> +#include <net/mac80211.h> + +#include "main.h" +#include "mac80211_if.h" +#include "phy_shim.h" + +/* PHY SHIM module specific state */ +struct phy_shim_info { + struct brcms_hardware *wlc_hw; /* pointer to main wlc_hw structure */ + struct brcms_c_info *wlc; /* pointer to main wlc structure */ + struct brcms_info *wl; /* pointer to os-specific private state */ +}; + +struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw, + struct brcms_info *wl, + struct brcms_c_info *wlc) { + struct phy_shim_info *physhim = NULL; + + physhim = kzalloc(sizeof(struct phy_shim_info), GFP_ATOMIC); + if (!physhim) + return NULL; + + physhim->wlc_hw = wlc_hw; + physhim->wlc = wlc; + physhim->wl = wl; + + return physhim; +} + +void wlc_phy_shim_detach(struct phy_shim_info *physhim) +{ + kfree(physhim); +} + +struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, + void (*fn)(struct brcms_phy *pi), + void *arg, const char *name) +{ + return (struct wlapi_timer *) + brcms_init_timer(physhim->wl, (void (*)(void *))fn, + arg, name); +} + +void wlapi_free_timer(struct wlapi_timer *t) +{ + brcms_free_timer((struct brcms_timer *)t); +} + +void +wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic) +{ + brcms_add_timer((struct brcms_timer *)t, ms, periodic); +} + +bool wlapi_del_timer(struct wlapi_timer *t) +{ + return brcms_del_timer((struct brcms_timer *)t); +} + +void wlapi_intrson(struct phy_shim_info *physhim) +{ + brcms_intrson(physhim->wl); +} + +u32 wlapi_intrsoff(struct phy_shim_info *physhim) +{ + return brcms_intrsoff(physhim->wl); +} + +void wlapi_intrsrestore(struct phy_shim_info *physhim, u32 macintmask) +{ + brcms_intrsrestore(physhim->wl, macintmask); +} + +void wlapi_bmac_write_shm(struct phy_shim_info *physhim, uint offset, u16 v) +{ + brcms_b_write_shm(physhim->wlc_hw, offset, v); +} + +u16 wlapi_bmac_read_shm(struct phy_shim_info *physhim, uint offset) +{ + return brcms_b_read_shm(physhim->wlc_hw, offset); +} + +void +wlapi_bmac_mhf(struct phy_shim_info *physhim, u8 idx, u16 mask, + u16 val, int bands) +{ + brcms_b_mhf(physhim->wlc_hw, idx, mask, val, bands); +} + +void wlapi_bmac_corereset(struct phy_shim_info *physhim, u32 flags) +{ + brcms_b_corereset(physhim->wlc_hw, flags); +} + +void wlapi_suspend_mac_and_wait(struct phy_shim_info *physhim) +{ + brcms_c_suspend_mac_and_wait(physhim->wlc); +} + +void wlapi_switch_macfreq(struct phy_shim_info *physhim, u8 spurmode) +{ + brcms_b_switch_macfreq(physhim->wlc_hw, spurmode); +} + +void wlapi_enable_mac(struct phy_shim_info *physhim) +{ + brcms_c_enable_mac(physhim->wlc); +} + +void wlapi_bmac_mctrl(struct phy_shim_info *physhim, u32 mask, u32 val) +{ + brcms_b_mctrl(physhim->wlc_hw, mask, val); +} + +void wlapi_bmac_phy_reset(struct phy_shim_info *physhim) +{ + brcms_b_phy_reset(physhim->wlc_hw); +} + +void wlapi_bmac_bw_set(struct phy_shim_info *physhim, u16 bw) +{ + brcms_b_bw_set(physhim->wlc_hw, bw); +} + +u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim) +{ + return brcms_b_get_txant(physhim->wlc_hw); +} + +void wlapi_bmac_phyclk_fgc(struct phy_shim_info *physhim, bool clk) +{ + brcms_b_phyclk_fgc(physhim->wlc_hw, clk); +} + +void wlapi_bmac_macphyclk_set(struct phy_shim_info *physhim, bool clk) +{ + brcms_b_macphyclk_set(physhim->wlc_hw, clk); +} + +void wlapi_bmac_core_phypll_ctl(struct phy_shim_info *physhim, bool on) +{ + brcms_b_core_phypll_ctl(physhim->wlc_hw, on); +} + +void wlapi_bmac_core_phypll_reset(struct phy_shim_info *physhim) +{ + brcms_b_core_phypll_reset(physhim->wlc_hw); +} + +void wlapi_bmac_ucode_wake_override_phyreg_set(struct phy_shim_info *physhim) +{ + brcms_c_ucode_wake_override_set(physhim->wlc_hw, + BRCMS_WAKE_OVERRIDE_PHYREG); +} + +void wlapi_bmac_ucode_wake_override_phyreg_clear(struct phy_shim_info *physhim) +{ + brcms_c_ucode_wake_override_clear(physhim->wlc_hw, + BRCMS_WAKE_OVERRIDE_PHYREG); +} + +void +wlapi_bmac_write_template_ram(struct phy_shim_info *physhim, int offset, + int len, void *buf) +{ + brcms_b_write_template_ram(physhim->wlc_hw, offset, len, buf); +} + +u16 wlapi_bmac_rate_shm_offset(struct phy_shim_info *physhim, u8 rate) +{ + return brcms_b_rate_shm_offset(physhim->wlc_hw, rate); +} + +void wlapi_ucode_sample_init(struct phy_shim_info *physhim) +{ +} + +void +wlapi_copyfrom_objmem(struct phy_shim_info *physhim, uint offset, void *buf, + int len, u32 sel) +{ + brcms_b_copyfrom_objmem(physhim->wlc_hw, offset, buf, len, sel); +} + +void +wlapi_copyto_objmem(struct phy_shim_info *physhim, uint offset, const void *buf, + int l, u32 sel) +{ + brcms_b_copyto_objmem(physhim->wlc_hw, offset, buf, l, sel); +} + +char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id) +{ + return getvar(physhim->wlc_hw->sih, id); +} +int wlapi_getintvar(struct phy_shim_info *physhim, enum brcms_srom_id id) +{ + return getintvar(physhim->wlc_hw->sih, id); +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h new file mode 100644 index 000000000000..9168c459b185 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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. + */ + +/* + * phy_shim.h: stuff defined in phy_shim.c and included only by the phy + */ + +#ifndef _BRCM_PHY_SHIM_H_ +#define _BRCM_PHY_SHIM_H_ + +#include "types.h" + +#define RADAR_TYPE_NONE 0 /* Radar type None */ +#define RADAR_TYPE_ETSI_1 1 /* ETSI 1 Radar type */ +#define RADAR_TYPE_ETSI_2 2 /* ETSI 2 Radar type */ +#define RADAR_TYPE_ETSI_3 3 /* ETSI 3 Radar type */ +#define RADAR_TYPE_ITU_E 4 /* ITU E Radar type */ +#define RADAR_TYPE_ITU_K 5 /* ITU K Radar type */ +#define RADAR_TYPE_UNCLASSIFIED 6 /* Unclassified Radar type */ +#define RADAR_TYPE_BIN5 7 /* long pulse radar type */ +#define RADAR_TYPE_STG2 8 /* staggered-2 radar */ +#define RADAR_TYPE_STG3 9 /* staggered-3 radar */ +#define RADAR_TYPE_FRA 10 /* French radar */ + +/* French radar pulse widths */ +#define FRA_T1_20MHZ 52770 +#define FRA_T2_20MHZ 61538 +#define FRA_T3_20MHZ 66002 +#define FRA_T1_40MHZ 105541 +#define FRA_T2_40MHZ 123077 +#define FRA_T3_40MHZ 132004 +#define FRA_ERR_20MHZ 60 +#define FRA_ERR_40MHZ 120 + +#define ANTSEL_NA 0 /* No boardlevel selection available */ +#define ANTSEL_2x4 1 /* 2x4 boardlevel selection available */ +#define ANTSEL_2x3 2 /* 2x3 CB2 boardlevel selection available */ + +/* Rx Antenna diversity control values */ +#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */ +#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */ +#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */ +#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */ +#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */ +#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0 /* default antdiv setting */ + +#define WL_ANT_RX_MAX 2 /* max 2 receive antennas */ +#define WL_ANT_HT_RX_MAX 3 /* max 3 receive antennas/cores */ +#define WL_ANT_IDX_1 0 /* antenna index 1 */ +#define WL_ANT_IDX_2 1 /* antenna index 2 */ + +/* values for n_preamble_type */ +#define BRCMS_N_PREAMBLE_MIXEDMODE 0 +#define BRCMS_N_PREAMBLE_GF 1 +#define BRCMS_N_PREAMBLE_GF_BRCM 2 + +#define WL_TX_POWER_RATES_LEGACY 45 +#define WL_TX_POWER_MCS20_FIRST 12 +#define WL_TX_POWER_MCS20_NUM 16 +#define WL_TX_POWER_MCS40_FIRST 28 +#define WL_TX_POWER_MCS40_NUM 17 + + +#define WL_TX_POWER_RATES 101 +#define WL_TX_POWER_CCK_FIRST 0 +#define WL_TX_POWER_CCK_NUM 4 +/* Index for first 20MHz OFDM SISO rate */ +#define WL_TX_POWER_OFDM_FIRST 4 +/* Index for first 20MHz OFDM CDD rate */ +#define WL_TX_POWER_OFDM20_CDD_FIRST 12 +/* Index for first 40MHz OFDM SISO rate */ +#define WL_TX_POWER_OFDM40_SISO_FIRST 52 +/* Index for first 40MHz OFDM CDD rate */ +#define WL_TX_POWER_OFDM40_CDD_FIRST 60 +#define WL_TX_POWER_OFDM_NUM 8 +/* Index for first 20MHz MCS SISO rate */ +#define WL_TX_POWER_MCS20_SISO_FIRST 20 +/* Index for first 20MHz MCS CDD rate */ +#define WL_TX_POWER_MCS20_CDD_FIRST 28 +/* Index for first 20MHz MCS STBC rate */ +#define WL_TX_POWER_MCS20_STBC_FIRST 36 +/* Index for first 20MHz MCS SDM rate */ +#define WL_TX_POWER_MCS20_SDM_FIRST 44 +/* Index for first 40MHz MCS SISO rate */ +#define WL_TX_POWER_MCS40_SISO_FIRST 68 +/* Index for first 40MHz MCS CDD rate */ +#define WL_TX_POWER_MCS40_CDD_FIRST 76 +/* Index for first 40MHz MCS STBC rate */ +#define WL_TX_POWER_MCS40_STBC_FIRST 84 +/* Index for first 40MHz MCS SDM rate */ +#define WL_TX_POWER_MCS40_SDM_FIRST 92 +#define WL_TX_POWER_MCS_1_STREAM_NUM 8 +#define WL_TX_POWER_MCS_2_STREAM_NUM 8 +/* Index for 40MHz rate MCS 32 */ +#define WL_TX_POWER_MCS_32 100 +#define WL_TX_POWER_MCS_32_NUM 1 + +/* sslpnphy specifics */ +/* Index for first 20MHz MCS SISO rate */ +#define WL_TX_POWER_MCS20_SISO_FIRST_SSN 12 + +/* struct tx_power::flags bits */ +#define WL_TX_POWER_F_ENABLED 1 +#define WL_TX_POWER_F_HW 2 +#define WL_TX_POWER_F_MIMO 4 +#define WL_TX_POWER_F_SISO 8 + +/* values to force tx/rx chain */ +#define BRCMS_N_TXRX_CHAIN0 0 +#define BRCMS_N_TXRX_CHAIN1 1 + +struct brcms_phy; + +extern struct phy_shim_info *wlc_phy_shim_attach(struct brcms_hardware *wlc_hw, + struct brcms_info *wl, + struct brcms_c_info *wlc); +extern void wlc_phy_shim_detach(struct phy_shim_info *physhim); + +/* PHY to WL utility functions */ +extern struct wlapi_timer *wlapi_init_timer(struct phy_shim_info *physhim, + void (*fn) (struct brcms_phy *pi), + void *arg, const char *name); +extern void wlapi_free_timer(struct wlapi_timer *t); +extern void wlapi_add_timer(struct wlapi_timer *t, uint ms, int periodic); +extern bool wlapi_del_timer(struct wlapi_timer *t); +extern void wlapi_intrson(struct phy_shim_info *physhim); +extern u32 wlapi_intrsoff(struct phy_shim_info *physhim); +extern void wlapi_intrsrestore(struct phy_shim_info *physhim, + u32 macintmask); + +extern void wlapi_bmac_write_shm(struct phy_shim_info *physhim, uint offset, + u16 v); +extern u16 wlapi_bmac_read_shm(struct phy_shim_info *physhim, uint offset); +extern void wlapi_bmac_mhf(struct phy_shim_info *physhim, u8 idx, + u16 mask, u16 val, int bands); +extern void wlapi_bmac_corereset(struct phy_shim_info *physhim, u32 flags); +extern void wlapi_suspend_mac_and_wait(struct phy_shim_info *physhim); +extern void wlapi_switch_macfreq(struct phy_shim_info *physhim, u8 spurmode); +extern void wlapi_enable_mac(struct phy_shim_info *physhim); +extern void wlapi_bmac_mctrl(struct phy_shim_info *physhim, u32 mask, + u32 val); +extern void wlapi_bmac_phy_reset(struct phy_shim_info *physhim); +extern void wlapi_bmac_bw_set(struct phy_shim_info *physhim, u16 bw); +extern void wlapi_bmac_phyclk_fgc(struct phy_shim_info *physhim, bool clk); +extern void wlapi_bmac_macphyclk_set(struct phy_shim_info *physhim, bool clk); +extern void wlapi_bmac_core_phypll_ctl(struct phy_shim_info *physhim, bool on); +extern void wlapi_bmac_core_phypll_reset(struct phy_shim_info *physhim); +extern void wlapi_bmac_ucode_wake_override_phyreg_set(struct phy_shim_info * + physhim); +extern void wlapi_bmac_ucode_wake_override_phyreg_clear(struct phy_shim_info * + physhim); +extern void wlapi_bmac_write_template_ram(struct phy_shim_info *physhim, int o, + int len, void *buf); +extern u16 wlapi_bmac_rate_shm_offset(struct phy_shim_info *physhim, + u8 rate); +extern void wlapi_ucode_sample_init(struct phy_shim_info *physhim); +extern void wlapi_copyfrom_objmem(struct phy_shim_info *physhim, uint, + void *buf, int, u32 sel); +extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint, + const void *buf, int, u32); + +extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim, + u32 phy_mode); +extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim); +extern char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id); +extern int wlapi_getintvar(struct phy_shim_info *physhim, + enum brcms_srom_id id); + +#endif /* _BRCM_PHY_SHIM_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c new file mode 100644 index 000000000000..3b36e3acfd74 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2011 Broadcom Corporation + * + * 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/delay.h> +#include <linux/io.h> + +#include <brcm_hw_ids.h> +#include <chipcommon.h> +#include <brcmu_utils.h> +#include "pub.h" +#include "aiutils.h" +#include "pmu.h" + +/* + * external LPO crystal frequency + */ +#define EXT_ILP_HZ 32768 + +/* + * Duration for ILP clock frequency measurment in milliseconds + * + * remark: 1000 must be an integer multiple of this duration + */ +#define ILP_CALC_DUR 10 + +/* Fields in pmucontrol */ +#define PCTL_ILP_DIV_MASK 0xffff0000 +#define PCTL_ILP_DIV_SHIFT 16 +#define PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */ +#define PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */ +#define PCTL_HT_REQ_EN 0x00000100 +#define PCTL_ALP_REQ_EN 0x00000080 +#define PCTL_XTALFREQ_MASK 0x0000007c +#define PCTL_XTALFREQ_SHIFT 2 +#define PCTL_ILP_DIV_EN 0x00000002 +#define PCTL_LPO_SEL 0x00000001 + +/* ILP clock */ +#define ILP_CLOCK 32000 + +/* ALP clock on pre-PMU chips */ +#define ALP_CLOCK 20000000 + +/* pmustatus */ +#define PST_EXTLPOAVAIL 0x0100 +#define PST_WDRESET 0x0080 +#define PST_INTPEND 0x0040 +#define PST_SBCLKST 0x0030 +#define PST_SBCLKST_ILP 0x0010 +#define PST_SBCLKST_ALP 0x0020 +#define PST_SBCLKST_HT 0x0030 +#define PST_ALPAVAIL 0x0008 +#define PST_HTAVAIL 0x0004 +#define PST_RESINIT 0x0003 + +/* PMU resource bit position */ +#define PMURES_BIT(bit) (1 << (bit)) + +/* PMU corerev and chip specific PLL controls. + * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary + * number to differentiate different PLLs controlled by the same PMU rev. + */ +/* pllcontrol registers: + * ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, + * p1div, p2div, _bypass_sdmod + */ +#define PMU1_PLL0_PLLCTL0 0 +#define PMU1_PLL0_PLLCTL1 1 +#define PMU1_PLL0_PLLCTL2 2 +#define PMU1_PLL0_PLLCTL3 3 +#define PMU1_PLL0_PLLCTL4 4 +#define PMU1_PLL0_PLLCTL5 5 + +/* pmu XtalFreqRatio */ +#define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF +#define PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 +#define PMU_XTALFREQ_REG_MEASURE_SHIFT 31 + +/* 4313 resources */ +#define RES4313_BB_PU_RSRC 0 +#define RES4313_ILP_REQ_RSRC 1 +#define RES4313_XTAL_PU_RSRC 2 +#define RES4313_ALP_AVAIL_RSRC 3 +#define RES4313_RADIO_PU_RSRC 4 +#define RES4313_BG_PU_RSRC 5 +#define RES4313_VREG1P4_PU_RSRC 6 +#define RES4313_AFE_PWRSW_RSRC 7 +#define RES4313_RX_PWRSW_RSRC 8 +#define RES4313_TX_PWRSW_RSRC 9 +#define RES4313_BB_PWRSW_RSRC 10 +#define RES4313_SYNTH_PWRSW_RSRC 11 +#define RES4313_MISC_PWRSW_RSRC 12 +#define RES4313_BB_PLL_PWRSW_RSRC 13 +#define RES4313_HT_AVAIL_RSRC 14 +#define RES4313_MACPHY_CLK_AVAIL_RSRC 15 + +/* Determine min/max rsrc masks. Value 0 leaves hardware at default. */ +static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax) +{ + u32 min_mask = 0, max_mask = 0; + uint rsrcs; + + /* # resources */ + rsrcs = (sih->pmucaps & PCAP_RC_MASK) >> PCAP_RC_SHIFT; + + /* determine min/max rsrc masks */ + switch (sih->chip) { + case BCM43224_CHIP_ID: + case BCM43225_CHIP_ID: + /* ??? */ + break; + + case BCM4313_CHIP_ID: + min_mask = PMURES_BIT(RES4313_BB_PU_RSRC) | + PMURES_BIT(RES4313_XTAL_PU_RSRC) | + PMURES_BIT(RES4313_ALP_AVAIL_RSRC) | + PMURES_BIT(RES4313_BB_PLL_PWRSW_RSRC); + max_mask = 0xffff; + break; + default: + break; + } + + *pmin = min_mask; + *pmax = max_mask; +} + +static void +si_pmu_spuravoid_pllupdate(struct si_pub *sih, struct chipcregs __iomem *cc, + u8 spuravoid) +{ + u32 tmp = 0; + + switch (sih->chip) { + case BCM43224_CHIP_ID: + case BCM43225_CHIP_ID: + if (spuravoid == 1) { + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); + W_REG(&cc->pllcontrol_data, 0x11500010); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); + W_REG(&cc->pllcontrol_data, 0x000C0C06); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); + W_REG(&cc->pllcontrol_data, 0x0F600a08); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); + W_REG(&cc->pllcontrol_data, 0x00000000); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); + W_REG(&cc->pllcontrol_data, 0x2001E920); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); + W_REG(&cc->pllcontrol_data, 0x88888815); + } else { + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); + W_REG(&cc->pllcontrol_data, 0x11100010); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); + W_REG(&cc->pllcontrol_data, 0x000c0c06); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); + W_REG(&cc->pllcontrol_data, 0x03000a08); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); + W_REG(&cc->pllcontrol_data, 0x00000000); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); + W_REG(&cc->pllcontrol_data, 0x200005c0); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); + W_REG(&cc->pllcontrol_data, 0x88888815); + } + tmp = 1 << 10; + break; + + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL0); + W_REG(&cc->pllcontrol_data, 0x11100008); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL1); + W_REG(&cc->pllcontrol_data, 0x0c000c06); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL2); + W_REG(&cc->pllcontrol_data, 0x03000a08); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL3); + W_REG(&cc->pllcontrol_data, 0x00000000); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL4); + W_REG(&cc->pllcontrol_data, 0x200005c0); + W_REG(&cc->pllcontrol_addr, PMU1_PLL0_PLLCTL5); + W_REG(&cc->pllcontrol_data, 0x88888855); + + tmp = 1 << 10; + break; + + default: + /* bail out */ + return; + } + + tmp |= R_REG(&cc->pmucontrol); + W_REG(&cc->pmucontrol, tmp); +} + +u16 si_pmu_fast_pwrup_delay(struct si_pub *sih) +{ + uint delay = PMU_MAX_TRANSITION_DLY; + + switch (sih->chip) { + case BCM43224_CHIP_ID: + case BCM43225_CHIP_ID: + case BCM4313_CHIP_ID: + delay = 3700; + break; + default: + break; + } + + return (u16) delay; +} + +void si_pmu_sprom_enable(struct si_pub *sih, bool enable) +{ + struct chipcregs __iomem *cc; + uint origidx; + + /* Remember original core before switch to chipc */ + origidx = ai_coreidx(sih); + cc = ai_setcoreidx(sih, SI_CC_IDX); + + /* Return to original core */ + ai_setcoreidx(sih, origidx); +} + +/* Read/write a chipcontrol reg */ +u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) +{ + ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, chipcontrol_addr), + ~0, reg); + return ai_corereg(sih, SI_CC_IDX, + offsetof(struct chipcregs, chipcontrol_data), mask, + val); +} + +/* Read/write a regcontrol reg */ +u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) +{ + ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, regcontrol_addr), + ~0, reg); + return ai_corereg(sih, SI_CC_IDX, + offsetof(struct chipcregs, regcontrol_data), mask, + val); +} + +/* Read/write a pllcontrol reg */ +u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val) +{ + ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pllcontrol_addr), + ~0, reg); + return ai_corereg(sih, SI_CC_IDX, + offsetof(struct chipcregs, pllcontrol_data), mask, + val); +} + +/* PMU PLL update */ +void si_pmu_pllupd(struct si_pub *sih) +{ + ai_corereg(sih, SI_CC_IDX, offsetof(struct chipcregs, pmucontrol), + PCTL_PLL_PLLCTL_UPD, PCTL_PLL_PLLCTL_UPD); +} + +/* query alp/xtal clock frequency */ +u32 si_pmu_alp_clock(struct si_pub *sih) +{ + u32 clock = ALP_CLOCK; + + /* bail out with default */ + if (!(sih->cccaps & CC_CAP_PMU)) + return clock; + + switch (sih->chip) { + case BCM43224_CHIP_ID: + case BCM43225_CHIP_ID: + case BCM4313_CHIP_ID: + /* always 20Mhz */ + clock = 20000 * 1000; + break; + default: + break; + } + + return clock; +} + +void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid) +{ + struct chipcregs __iomem *cc; + uint origidx, intr_val; + + /* Remember original core before switch to chipc */ + cc = (struct chipcregs __iomem *) + ai_switch_core(sih, CC_CORE_ID, &origidx, &intr_val); + + /* update the pll changes */ + si_pmu_spuravoid_pllupdate(sih, cc, spuravoid); + + /* Return to original core */ + ai_restore_core(sih, origidx, intr_val); +} + +/* initialize PMU */ +void si_pmu_init(struct si_pub *sih) +{ + struct chipcregs __iomem *cc; + uint origidx; + + /* Remember original core before switch to chipc */ + origidx = ai_coreidx(sih); + cc = ai_setcoreidx(sih, SI_CC_IDX); + + if (sih->pmurev == 1) + AND_REG(&cc->pmucontrol, ~PCTL_NOILP_ON_WAIT); + else if (sih->pmurev >= 2) + OR_REG(&cc->pmucontrol, PCTL_NOILP_ON_WAIT); + + /* Return to original core */ + ai_setcoreidx(sih, origidx); +} + +/* initialize PMU chip controls and other chip level stuff */ +void si_pmu_chip_init(struct si_pub *sih) +{ + uint origidx; + + /* Gate off SPROM clock and chip select signals */ + si_pmu_sprom_enable(sih, false); + + /* Remember original core */ + origidx = ai_coreidx(sih); + + /* Return to original core */ + ai_setcoreidx(sih, origidx); +} + +/* initialize PMU switch/regulators */ +void si_pmu_swreg_init(struct si_pub *sih) +{ +} + +/* initialize PLL */ +void si_pmu_pll_init(struct si_pub *sih, uint xtalfreq) +{ + struct chipcregs __iomem *cc; + uint origidx; + + /* Remember original core before switch to chipc */ + origidx = ai_coreidx(sih); + cc = ai_setcoreidx(sih, SI_CC_IDX); + + switch (sih->chip) { + case BCM4313_CHIP_ID: + case BCM43224_CHIP_ID: + case BCM43225_CHIP_ID: + /* ??? */ + break; + default: + break; + } + + /* Return to original core */ + ai_setcoreidx(sih, origidx); +} + +/* initialize PMU resources */ +void si_pmu_res_init(struct si_pub *sih) +{ + struct chipcregs __iomem *cc; + uint origidx; + u32 min_mask = 0, max_mask = 0; + + /* Remember original core before switch to chipc */ + origidx = ai_coreidx(sih); + cc = ai_setcoreidx(sih, SI_CC_IDX); + + /* Determine min/max rsrc masks */ + si_pmu_res_masks(sih, &min_mask, &max_mask); + + /* It is required to program max_mask first and then min_mask */ + + /* Program max resource mask */ + + if (max_mask) + W_REG(&cc->max_res_mask, max_mask); + + /* Program min resource mask */ + + if (min_mask) + W_REG(&cc->min_res_mask, min_mask); + + /* Add some delay; allow resources to come up and settle. */ + mdelay(2); + + /* Return to original core */ + ai_setcoreidx(sih, origidx); +} + +u32 si_pmu_measure_alpclk(struct si_pub *sih) +{ + struct chipcregs __iomem *cc; + uint origidx; + u32 alp_khz; + + if (sih->pmurev < 10) + return 0; + + /* Remember original core before switch to chipc */ + origidx = ai_coreidx(sih); + cc = ai_setcoreidx(sih, SI_CC_IDX); + + if (R_REG(&cc->pmustatus) & PST_EXTLPOAVAIL) { + u32 ilp_ctr, alp_hz; + + /* + * Enable the reg to measure the freq, + * in case it was disabled before + */ + W_REG(&cc->pmu_xtalfreq, + 1U << PMU_XTALFREQ_REG_MEASURE_SHIFT); + + /* Delay for well over 4 ILP clocks */ + udelay(1000); + + /* Read the latched number of ALP ticks per 4 ILP ticks */ + ilp_ctr = + R_REG(&cc->pmu_xtalfreq) & PMU_XTALFREQ_REG_ILPCTR_MASK; + + /* + * Turn off the PMU_XTALFREQ_REG_MEASURE_SHIFT + * bit to save power + */ + W_REG(&cc->pmu_xtalfreq, 0); + + /* Calculate ALP frequency */ + alp_hz = (ilp_ctr * EXT_ILP_HZ) / 4; + + /* + * Round to nearest 100KHz, and at + * the same time convert to KHz + */ + alp_khz = (alp_hz + 50000) / 100000 * 100; + } else + alp_khz = 0; + + /* Return to original core */ + ai_setcoreidx(sih, origidx); + + return alp_khz; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h new file mode 100644 index 000000000000..3a08c620640e --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_PMU_H_ +#define _BRCM_PMU_H_ + +#include "types.h" + +extern u16 si_pmu_fast_pwrup_delay(struct si_pub *sih); +extern void si_pmu_sprom_enable(struct si_pub *sih, bool enable); +extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); +extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); +extern u32 si_pmu_alp_clock(struct si_pub *sih); +extern void si_pmu_pllupd(struct si_pub *sih); +extern void si_pmu_spuravoid(struct si_pub *sih, u8 spuravoid); +extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); +extern void si_pmu_init(struct si_pub *sih); +extern void si_pmu_chip_init(struct si_pub *sih); +extern void si_pmu_pll_init(struct si_pub *sih, u32 xtalfreq); +extern void si_pmu_res_init(struct si_pub *sih); +extern void si_pmu_swreg_init(struct si_pub *sih); +extern u32 si_pmu_measure_alpclk(struct si_pub *sih); + +#endif /* _BRCM_PMU_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h new file mode 100644 index 000000000000..37bb2dcc113f --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_PUB_H_ +#define _BRCM_PUB_H_ + +#include <brcmu_wifi.h> +#include "types.h" +#include "defs.h" + +enum brcms_srom_id { + BRCMS_SROM_NULL, + BRCMS_SROM_CONT, + BRCMS_SROM_AA2G, + BRCMS_SROM_AA5G, + BRCMS_SROM_AG0, + BRCMS_SROM_AG1, + BRCMS_SROM_AG2, + BRCMS_SROM_AG3, + BRCMS_SROM_ANTSWCTL2G, + BRCMS_SROM_ANTSWCTL5G, + BRCMS_SROM_ANTSWITCH, + BRCMS_SROM_BOARDFLAGS2, + BRCMS_SROM_BOARDFLAGS, + BRCMS_SROM_BOARDNUM, + BRCMS_SROM_BOARDREV, + BRCMS_SROM_BOARDTYPE, + BRCMS_SROM_BW40PO, + BRCMS_SROM_BWDUPPO, + BRCMS_SROM_BXA2G, + BRCMS_SROM_BXA5G, + BRCMS_SROM_CC, + BRCMS_SROM_CCK2GPO, + BRCMS_SROM_CCKBW202GPO, + BRCMS_SROM_CCKBW20UL2GPO, + BRCMS_SROM_CCODE, + BRCMS_SROM_CDDPO, + BRCMS_SROM_DEVID, + BRCMS_SROM_ET1MACADDR, + BRCMS_SROM_EXTPAGAIN2G, + BRCMS_SROM_EXTPAGAIN5G, + BRCMS_SROM_FREQOFFSET_CORR, + BRCMS_SROM_HW_IQCAL_EN, + BRCMS_SROM_IL0MACADDR, + BRCMS_SROM_IQCAL_SWP_DIS, + BRCMS_SROM_LEDBH0, + BRCMS_SROM_LEDBH1, + BRCMS_SROM_LEDBH2, + BRCMS_SROM_LEDBH3, + BRCMS_SROM_LEDDC, + BRCMS_SROM_LEGOFDM40DUPPO, + BRCMS_SROM_LEGOFDMBW202GPO, + BRCMS_SROM_LEGOFDMBW205GHPO, + BRCMS_SROM_LEGOFDMBW205GLPO, + BRCMS_SROM_LEGOFDMBW205GMPO, + BRCMS_SROM_LEGOFDMBW20UL2GPO, + BRCMS_SROM_LEGOFDMBW20UL5GHPO, + BRCMS_SROM_LEGOFDMBW20UL5GLPO, + BRCMS_SROM_LEGOFDMBW20UL5GMPO, + BRCMS_SROM_MACADDR, + BRCMS_SROM_MCS2GPO0, + BRCMS_SROM_MCS2GPO1, + BRCMS_SROM_MCS2GPO2, + BRCMS_SROM_MCS2GPO3, + BRCMS_SROM_MCS2GPO4, + BRCMS_SROM_MCS2GPO5, + BRCMS_SROM_MCS2GPO6, + BRCMS_SROM_MCS2GPO7, + BRCMS_SROM_MCS32PO, + BRCMS_SROM_MCS5GHPO0, + BRCMS_SROM_MCS5GHPO1, + BRCMS_SROM_MCS5GHPO2, + BRCMS_SROM_MCS5GHPO3, + BRCMS_SROM_MCS5GHPO4, + BRCMS_SROM_MCS5GHPO5, + BRCMS_SROM_MCS5GHPO6, + BRCMS_SROM_MCS5GHPO7, + BRCMS_SROM_MCS5GLPO0, + BRCMS_SROM_MCS5GLPO1, + BRCMS_SROM_MCS5GLPO2, + BRCMS_SROM_MCS5GLPO3, + BRCMS_SROM_MCS5GLPO4, + BRCMS_SROM_MCS5GLPO5, + BRCMS_SROM_MCS5GLPO6, + BRCMS_SROM_MCS5GLPO7, + BRCMS_SROM_MCS5GPO0, + BRCMS_SROM_MCS5GPO1, + BRCMS_SROM_MCS5GPO2, + BRCMS_SROM_MCS5GPO3, + BRCMS_SROM_MCS5GPO4, + BRCMS_SROM_MCS5GPO5, + BRCMS_SROM_MCS5GPO6, + BRCMS_SROM_MCS5GPO7, + BRCMS_SROM_MCSBW202GPO, + BRCMS_SROM_MCSBW205GHPO, + BRCMS_SROM_MCSBW205GLPO, + BRCMS_SROM_MCSBW205GMPO, + BRCMS_SROM_MCSBW20UL2GPO, + BRCMS_SROM_MCSBW20UL5GHPO, + BRCMS_SROM_MCSBW20UL5GLPO, + BRCMS_SROM_MCSBW20UL5GMPO, + BRCMS_SROM_MCSBW402GPO, + BRCMS_SROM_MCSBW405GHPO, + BRCMS_SROM_MCSBW405GLPO, + BRCMS_SROM_MCSBW405GMPO, + BRCMS_SROM_MEASPOWER, + BRCMS_SROM_OFDM2GPO, + BRCMS_SROM_OFDM5GHPO, + BRCMS_SROM_OFDM5GLPO, + BRCMS_SROM_OFDM5GPO, + BRCMS_SROM_OPO, + BRCMS_SROM_PA0B0, + BRCMS_SROM_PA0B1, + BRCMS_SROM_PA0B2, + BRCMS_SROM_PA0ITSSIT, + BRCMS_SROM_PA0MAXPWR, + BRCMS_SROM_PA1B0, + BRCMS_SROM_PA1B1, + BRCMS_SROM_PA1B2, + BRCMS_SROM_PA1HIB0, + BRCMS_SROM_PA1HIB1, + BRCMS_SROM_PA1HIB2, + BRCMS_SROM_PA1HIMAXPWR, + BRCMS_SROM_PA1ITSSIT, + BRCMS_SROM_PA1LOB0, + BRCMS_SROM_PA1LOB1, + BRCMS_SROM_PA1LOB2, + BRCMS_SROM_PA1LOMAXPWR, + BRCMS_SROM_PA1MAXPWR, + BRCMS_SROM_PDETRANGE2G, + BRCMS_SROM_PDETRANGE5G, + BRCMS_SROM_PHYCAL_TEMPDELTA, + BRCMS_SROM_RAWTEMPSENSE, + BRCMS_SROM_REGREV, + BRCMS_SROM_REV, + BRCMS_SROM_RSSISAV2G, + BRCMS_SROM_RSSISAV5G, + BRCMS_SROM_RSSISMC2G, + BRCMS_SROM_RSSISMC5G, + BRCMS_SROM_RSSISMF2G, + BRCMS_SROM_RSSISMF5G, + BRCMS_SROM_RXCHAIN, + BRCMS_SROM_RXPO2G, + BRCMS_SROM_RXPO5G, + BRCMS_SROM_STBCPO, + BRCMS_SROM_TEMPCORRX, + BRCMS_SROM_TEMPOFFSET, + BRCMS_SROM_TEMPSENSE_OPTION, + BRCMS_SROM_TEMPSENSE_SLOPE, + BRCMS_SROM_TEMPTHRESH, + BRCMS_SROM_TRI2G, + BRCMS_SROM_TRI5GH, + BRCMS_SROM_TRI5GL, + BRCMS_SROM_TRI5G, + BRCMS_SROM_TRISO2G, + BRCMS_SROM_TRISO5G, + BRCMS_SROM_TSSIPOS2G, + BRCMS_SROM_TSSIPOS5G, + BRCMS_SROM_TXCHAIN, + BRCMS_SROM_TXPID2GA0, + BRCMS_SROM_TXPID2GA1, + BRCMS_SROM_TXPID2GA2, + BRCMS_SROM_TXPID2GA3, + BRCMS_SROM_TXPID5GA0, + BRCMS_SROM_TXPID5GA1, + BRCMS_SROM_TXPID5GA2, + BRCMS_SROM_TXPID5GA3, + BRCMS_SROM_TXPID5GHA0, + BRCMS_SROM_TXPID5GHA1, + BRCMS_SROM_TXPID5GHA2, + BRCMS_SROM_TXPID5GHA3, + BRCMS_SROM_TXPID5GLA0, + BRCMS_SROM_TXPID5GLA1, + BRCMS_SROM_TXPID5GLA2, + BRCMS_SROM_TXPID5GLA3, + /* + * per-path identifiers (see srom.c) + */ + BRCMS_SROM_ITT2GA0, + BRCMS_SROM_ITT2GA1, + BRCMS_SROM_ITT2GA2, + BRCMS_SROM_ITT2GA3, + BRCMS_SROM_ITT5GA0, + BRCMS_SROM_ITT5GA1, + BRCMS_SROM_ITT5GA2, + BRCMS_SROM_ITT5GA3, + BRCMS_SROM_MAXP2GA0, + BRCMS_SROM_MAXP2GA1, + BRCMS_SROM_MAXP2GA2, + BRCMS_SROM_MAXP2GA3, + BRCMS_SROM_MAXP5GA0, + BRCMS_SROM_MAXP5GA1, + BRCMS_SROM_MAXP5GA2, + BRCMS_SROM_MAXP5GA3, + BRCMS_SROM_MAXP5GHA0, + BRCMS_SROM_MAXP5GHA1, + BRCMS_SROM_MAXP5GHA2, + BRCMS_SROM_MAXP5GHA3, + BRCMS_SROM_MAXP5GLA0, + BRCMS_SROM_MAXP5GLA1, + BRCMS_SROM_MAXP5GLA2, + BRCMS_SROM_MAXP5GLA3, + BRCMS_SROM_PA2GW0A0, + BRCMS_SROM_PA2GW0A1, + BRCMS_SROM_PA2GW0A2, + BRCMS_SROM_PA2GW0A3, + BRCMS_SROM_PA2GW1A0, + BRCMS_SROM_PA2GW1A1, + BRCMS_SROM_PA2GW1A2, + BRCMS_SROM_PA2GW1A3, + BRCMS_SROM_PA2GW2A0, + BRCMS_SROM_PA2GW2A1, + BRCMS_SROM_PA2GW2A2, + BRCMS_SROM_PA2GW2A3, + BRCMS_SROM_PA2GW3A0, + BRCMS_SROM_PA2GW3A1, + BRCMS_SROM_PA2GW3A2, + BRCMS_SROM_PA2GW3A3, + BRCMS_SROM_PA5GHW0A0, + BRCMS_SROM_PA5GHW0A1, + BRCMS_SROM_PA5GHW0A2, + BRCMS_SROM_PA5GHW0A3, + BRCMS_SROM_PA5GHW1A0, + BRCMS_SROM_PA5GHW1A1, + BRCMS_SROM_PA5GHW1A2, + BRCMS_SROM_PA5GHW1A3, + BRCMS_SROM_PA5GHW2A0, + BRCMS_SROM_PA5GHW2A1, + BRCMS_SROM_PA5GHW2A2, + BRCMS_SROM_PA5GHW2A3, + BRCMS_SROM_PA5GHW3A0, + BRCMS_SROM_PA5GHW3A1, + BRCMS_SROM_PA5GHW3A2, + BRCMS_SROM_PA5GHW3A3, + BRCMS_SROM_PA5GLW0A0, + BRCMS_SROM_PA5GLW0A1, + BRCMS_SROM_PA5GLW0A2, + BRCMS_SROM_PA5GLW0A3, + BRCMS_SROM_PA5GLW1A0, + BRCMS_SROM_PA5GLW1A1, + BRCMS_SROM_PA5GLW1A2, + BRCMS_SROM_PA5GLW1A3, + BRCMS_SROM_PA5GLW2A0, + BRCMS_SROM_PA5GLW2A1, + BRCMS_SROM_PA5GLW2A2, + BRCMS_SROM_PA5GLW2A3, + BRCMS_SROM_PA5GLW3A0, + BRCMS_SROM_PA5GLW3A1, + BRCMS_SROM_PA5GLW3A2, + BRCMS_SROM_PA5GLW3A3, + BRCMS_SROM_PA5GW0A0, + BRCMS_SROM_PA5GW0A1, + BRCMS_SROM_PA5GW0A2, + BRCMS_SROM_PA5GW0A3, + BRCMS_SROM_PA5GW1A0, + BRCMS_SROM_PA5GW1A1, + BRCMS_SROM_PA5GW1A2, + BRCMS_SROM_PA5GW1A3, + BRCMS_SROM_PA5GW2A0, + BRCMS_SROM_PA5GW2A1, + BRCMS_SROM_PA5GW2A2, + BRCMS_SROM_PA5GW2A3, + BRCMS_SROM_PA5GW3A0, + BRCMS_SROM_PA5GW3A1, + BRCMS_SROM_PA5GW3A2, + BRCMS_SROM_PA5GW3A3, +}; + +#define BRCMS_NUMRATES 16 /* max # of rates in a rateset */ +#define D11_PHY_HDR_LEN 6 /* Phy header length - 6 bytes */ + +/* phy types */ +#define PHY_TYPE_A 0 /* Phy type A */ +#define PHY_TYPE_G 2 /* Phy type G */ +#define PHY_TYPE_N 4 /* Phy type N */ +#define PHY_TYPE_LP 5 /* Phy type Low Power A/B/G */ +#define PHY_TYPE_SSN 6 /* Phy type Single Stream N */ +#define PHY_TYPE_LCN 8 /* Phy type Single Stream N */ +#define PHY_TYPE_LCNXN 9 /* Phy type 2-stream N */ +#define PHY_TYPE_HT 7 /* Phy type 3-Stream N */ + +/* bw */ +#define BRCMS_10_MHZ 10 /* 10Mhz nphy channel bandwidth */ +#define BRCMS_20_MHZ 20 /* 20Mhz nphy channel bandwidth */ +#define BRCMS_40_MHZ 40 /* 40Mhz nphy channel bandwidth */ + +#define BRCMS_RSSI_MINVAL -200 /* Low value, e.g. for forcing roam */ +#define BRCMS_RSSI_NO_SIGNAL -91 /* NDIS RSSI link quality cutoffs */ +#define BRCMS_RSSI_VERY_LOW -80 /* Very low quality cutoffs */ +#define BRCMS_RSSI_LOW -70 /* Low quality cutoffs */ +#define BRCMS_RSSI_GOOD -68 /* Good quality cutoffs */ +#define BRCMS_RSSI_VERY_GOOD -58 /* Very good quality cutoffs */ +#define BRCMS_RSSI_EXCELLENT -57 /* Excellent quality cutoffs */ + +/* a large TX Power as an init value to factor out of min() calculations, + * keep low enough to fit in an s8, units are .25 dBm + */ +#define BRCMS_TXPWR_MAX (127) /* ~32 dBm = 1,500 mW */ + +/* rate related definitions */ +#define BRCMS_RATE_FLAG 0x80 /* Flag to indicate it is a basic rate */ +#define BRCMS_RATE_MASK 0x7f /* Rate value mask w/o basic rate flag */ + +/* legacy rx Antenna diversity for SISO rates */ +#define ANT_RX_DIV_FORCE_0 0 /* Use antenna 0 */ +#define ANT_RX_DIV_FORCE_1 1 /* Use antenna 1 */ +#define ANT_RX_DIV_START_1 2 /* Choose starting with 1 */ +#define ANT_RX_DIV_START_0 3 /* Choose starting with 0 */ +#define ANT_RX_DIV_ENABLE 3 /* APHY bbConfig Enable RX Diversity */ +/* default antdiv setting */ +#define ANT_RX_DIV_DEF ANT_RX_DIV_START_0 + +/* legacy rx Antenna diversity for SISO rates */ +/* Tx on antenna 0, "legacy term Main" */ +#define ANT_TX_FORCE_0 0 +/* Tx on antenna 1, "legacy term Aux" */ +#define ANT_TX_FORCE_1 1 +/* Tx on phy's last good Rx antenna */ +#define ANT_TX_LAST_RX 3 +/* driver's default tx antenna setting */ +#define ANT_TX_DEF 3 + +/* Tx Chain values */ +/* def bitmap of txchain */ +#define TXCHAIN_DEF 0x1 +/* default bitmap of tx chains for nphy */ +#define TXCHAIN_DEF_NPHY 0x3 +/* default bitmap of tx chains for nphy */ +#define TXCHAIN_DEF_HTPHY 0x7 +/* def bitmap of rxchain */ +#define RXCHAIN_DEF 0x1 +/* default bitmap of rx chains for nphy */ +#define RXCHAIN_DEF_NPHY 0x3 +/* default bitmap of rx chains for nphy */ +#define RXCHAIN_DEF_HTPHY 0x7 +/* no antenna switch */ +#define ANTSWITCH_NONE 0 +/* antenna switch on 4321CB2, 2of3 */ +#define ANTSWITCH_TYPE_1 1 +/* antenna switch on 4321MPCI, 2of3 */ +#define ANTSWITCH_TYPE_2 2 +/* antenna switch on 4322, 2of3 */ +#define ANTSWITCH_TYPE_3 3 + +#define RXBUFSZ PKTBUFSZ + +#define MAX_STREAMS_SUPPORTED 4 /* max number of streams supported */ + +struct brcm_rateset { + /* # rates in this set */ + u32 count; + /* rates in 500kbps units w/hi bit set if basic */ + u8 rates[WL_NUMRATES]; +}; + +struct brcms_c_rateset { + uint count; /* number of rates in rates[] */ + /* rates in 500kbps units w/hi bit set if basic */ + u8 rates[BRCMS_NUMRATES]; + u8 htphy_membership; /* HT PHY Membership */ + u8 mcs[MCSSET_LEN]; /* supported mcs index bit map */ +}; + +/* All the HT-specific default advertised capabilities (including AMPDU) + * should be grouped here at one place + */ +#define AMPDU_DEF_MPDU_DENSITY 6 /* default mpdu density (110 ==> 4us) */ + +/* wlc internal bss_info */ +struct brcms_bss_info { + u8 BSSID[ETH_ALEN]; /* network BSSID */ + u16 flags; /* flags for internal attributes */ + u8 SSID_len; /* the length of SSID */ + u8 SSID[32]; /* SSID string */ + s16 RSSI; /* receive signal strength (in dBm) */ + s16 SNR; /* receive signal SNR in dB */ + u16 beacon_period; /* units are Kusec */ + u16 chanspec; /* Channel num, bw, ctrl_sb and band */ + struct brcms_c_rateset rateset; /* supported rates */ +}; + +#define MAC80211_PROMISC_BCNS (1 << 0) +#define MAC80211_SCAN (1 << 1) + +/* + * Public portion of common driver state structure. + * The wlc handle points at this. + */ +struct brcms_pub { + struct brcms_c_info *wlc; + struct ieee80211_hw *ieee_hw; + struct scb_ampdu *global_ampdu; + uint mac80211_state; + uint unit; /* device instance number */ + uint corerev; /* core revision */ + struct si_pub *sih; /* SI handle (cookie for siutils calls) */ + bool up; /* interface up and running */ + bool hw_off; /* HW is off */ + bool hw_up; /* one time hw up/down */ + bool _piomode; /* true if pio mode */ + uint _nbands; /* # bands supported */ + uint now; /* # elapsed seconds */ + + bool promisc; /* promiscuous destination address */ + bool delayed_down; /* down delayed */ + bool associated; /* true:part of [I]BSS, false: not */ + /* (union of stas_associated, aps_associated) */ + bool _ampdu; /* ampdu enabled or not */ + u8 _n_enab; /* bitmap of 11N + HT support */ + + u8 cur_etheraddr[ETH_ALEN]; /* our local ethernet address */ + + int bcmerror; /* last bcm error */ + + u32 radio_disabled; /* bit vector for radio disabled reasons */ + + u16 boardrev; /* version # of particular board */ + u8 sromrev; /* version # of the srom */ + char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */ + u32 boardflags; /* Board specific flags from srom */ + u32 boardflags2; /* More board flags if sromrev >= 4 */ + bool phy_11ncapable; /* the PHY/HW is capable of 802.11N */ + + struct wl_cnt *_cnt; /* low-level counters in driver */ +}; + +enum wlc_par_id { + IOV_MPC = 1, + IOV_RTSTHRESH, + IOV_QTXPOWER, + IOV_BCN_LI_BCN /* Beacon listen interval in # of beacons */ +}; + +/*********************************************** + * Feature-related macros to optimize out code * + * ********************************************* + */ + +#define ENAB_1x1 0x01 +#define ENAB_2x2 0x02 +#define ENAB_3x3 0x04 +#define ENAB_4x4 0x08 +#define SUPPORT_11N (ENAB_1x1|ENAB_2x2) +#define SUPPORT_HT (ENAB_1x1|ENAB_2x2|ENAB_3x3) + +/* WL11N Support */ +#define AMPDU_AGG_HOST 1 + +/* pri is priority encoded in the packet. This maps the Packet priority to + * enqueue precedence as defined in wlc_prec_map + */ +extern const u8 wlc_prio2prec_map[]; +#define BRCMS_PRIO_TO_PREC(pri) wlc_prio2prec_map[(pri) & 7] + +#define BRCMS_PREC_COUNT 16 /* Max precedence level implemented */ + +/* Mask to describe all precedence levels */ +#define BRCMS_PREC_BMP_ALL MAXBITVAL(BRCMS_PREC_COUNT) + +/* + * This maps priority to one precedence higher - Used by PS-Poll response + * packets to simulate enqueue-at-head operation, but still maintain the + * order on the queue + */ +#define BRCMS_PRIO_TO_HI_PREC(pri) min(BRCMS_PRIO_TO_PREC(pri) + 1,\ + BRCMS_PREC_COUNT - 1) + +/* Define a bitmap of precedences comprised by each AC */ +#define BRCMS_PREC_BMP_AC_BE (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BE)) | \ + NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \ + NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_EE)) | \ + NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_EE))) +#define BRCMS_PREC_BMP_AC_BK (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BK)) | \ + NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BK)) | \ + NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NONE)) | \ + NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NONE))) +#define BRCMS_PREC_BMP_AC_VI (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_CL)) | \ + NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_CL)) | \ + NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VI)) | \ + NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VI))) +#define BRCMS_PREC_BMP_AC_VO (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VO)) | \ + NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VO)) | \ + NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NC)) | \ + NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NC))) + +/* network protection config */ +#define BRCMS_PROT_G_SPEC 1 /* SPEC g protection */ +#define BRCMS_PROT_G_OVR 2 /* SPEC g prot override */ +#define BRCMS_PROT_G_USER 3 /* gmode specified by user */ +#define BRCMS_PROT_OVERLAP 4 /* overlap */ +#define BRCMS_PROT_N_USER 10 /* nmode specified by user */ +#define BRCMS_PROT_N_CFG 11 /* n protection */ +#define BRCMS_PROT_N_CFG_OVR 12 /* n protection override */ +#define BRCMS_PROT_N_NONGF 13 /* non-GF protection */ +#define BRCMS_PROT_N_NONGF_OVR 14 /* non-GF protection override */ +#define BRCMS_PROT_N_PAM_OVR 15 /* n preamble override */ +#define BRCMS_PROT_N_OBSS 16 /* non-HT OBSS present */ + +/* + * 54g modes (basic bits may still be overridden) + * + * GMODE_LEGACY_B + * Rateset: 1b, 2b, 5.5, 11 + * Preamble: Long + * Shortslot: Off + * GMODE_AUTO + * Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 + * Extended Rateset: 6, 9, 12, 48 + * Preamble: Long + * Shortslot: Auto + * GMODE_ONLY + * Rateset: 1b, 2b, 5.5b, 11b, 18, 24b, 36, 54 + * Extended Rateset: 6b, 9, 12b, 48 + * Preamble: Short required + * Shortslot: Auto + * GMODE_B_DEFERRED + * Rateset: 1b, 2b, 5.5b, 11b, 18, 24, 36, 54 + * Extended Rateset: 6, 9, 12, 48 + * Preamble: Long + * Shortslot: On + * GMODE_PERFORMANCE + * Rateset: 1b, 2b, 5.5b, 6b, 9, 11b, 12b, 18, 24b, 36, 48, 54 + * Preamble: Short required + * Shortslot: On and required + * GMODE_LRS + * Rateset: 1b, 2b, 5.5b, 11b + * Extended Rateset: 6, 9, 12, 18, 24, 36, 48, 54 + * Preamble: Long + * Shortslot: Auto + */ +#define GMODE_LEGACY_B 0 +#define GMODE_AUTO 1 +#define GMODE_ONLY 2 +#define GMODE_B_DEFERRED 3 +#define GMODE_PERFORMANCE 4 +#define GMODE_LRS 5 +#define GMODE_MAX 6 + +/* MCS values greater than this enable multiple streams */ +#define HIGHEST_SINGLE_STREAM_MCS 7 + +#define MAXBANDS 2 /* Maximum #of bands */ + +/* max number of antenna configurations */ +#define ANT_SELCFG_MAX 4 + +struct brcms_antselcfg { + u8 ant_config[ANT_SELCFG_MAX]; /* antenna configuration */ + u8 num_antcfg; /* number of available antenna configurations */ +}; + +/* common functions for every port */ +extern struct brcms_c_info * +brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit, + bool piomode, void __iomem *regsva, struct pci_dev *btparam, + uint *perr); +extern uint brcms_c_detach(struct brcms_c_info *wlc); +extern int brcms_c_up(struct brcms_c_info *wlc); +extern uint brcms_c_down(struct brcms_c_info *wlc); + +extern bool brcms_c_chipmatch(u16 vendor, u16 device); +extern void brcms_c_init(struct brcms_c_info *wlc); +extern void brcms_c_reset(struct brcms_c_info *wlc); + +extern void brcms_c_intrson(struct brcms_c_info *wlc); +extern u32 brcms_c_intrsoff(struct brcms_c_info *wlc); +extern void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask); +extern bool brcms_c_intrsupd(struct brcms_c_info *wlc); +extern bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc); +extern bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded); +extern void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, + struct sk_buff *sdu, + struct ieee80211_hw *hw); +extern bool brcms_c_aggregatable(struct brcms_c_info *wlc, u8 tid); +extern void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, + int val); +extern int brcms_c_get_header_len(void); +extern void brcms_c_set_addrmatch(struct brcms_c_info *wlc, + int match_reg_offset, + const u8 *addr); +extern void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, + const struct ieee80211_tx_queue_params *arg, + bool suspend); +extern struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc); +extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc, + struct ieee80211_sta *sta, u16 tid); +extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, + u8 ba_wsize, uint max_rx_ampdu_bytes); +extern char *getvar(struct si_pub *sih, enum brcms_srom_id id); +extern int getintvar(struct si_pub *sih, enum brcms_srom_id id); +extern int brcms_c_module_register(struct brcms_pub *pub, + const char *name, struct brcms_info *hdl, + int (*down_fn)(void *handle)); +extern int brcms_c_module_unregister(struct brcms_pub *pub, const char *name, + struct brcms_info *hdl); +extern void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc); +extern void brcms_c_enable_mac(struct brcms_c_info *wlc); +extern void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state); +extern void brcms_c_scan_start(struct brcms_c_info *wlc); +extern void brcms_c_scan_stop(struct brcms_c_info *wlc); +extern int brcms_c_get_curband(struct brcms_c_info *wlc); +extern void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, + bool drop); +extern int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel); +extern int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl); +extern void brcms_c_get_current_rateset(struct brcms_c_info *wlc, + struct brcm_rateset *currs); +extern int brcms_c_set_rateset(struct brcms_c_info *wlc, + struct brcm_rateset *rs); +extern int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period); +extern u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx); +extern void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, + s8 sslot_override); +extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, + u8 interval); +extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr); +extern int brcms_c_get_tx_power(struct brcms_c_info *wlc); +extern void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc); +extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc); + +#endif /* _BRCM_PUB_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/rate.c b/drivers/net/wireless/brcm80211/brcmsmac/rate.c new file mode 100644 index 000000000000..0a0c0ad4f96f --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/rate.c @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 <brcmu_wifi.h> +#include <brcmu_utils.h> + +#include "d11.h" +#include "pub.h" +#include "rate.h" + +/* + * Rate info per rate: It tells whether a rate is ofdm or not and its phy_rate + * value + */ +const u8 rate_info[BRCM_MAXRATE + 1] = { + /* 0 1 2 3 4 5 6 7 8 9 */ +/* 0 */ 0x00, 0x00, 0x0a, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 10 */ 0x00, 0x37, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, +/* 20 */ 0x00, 0x00, 0x6e, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, +/* 40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, +/* 50 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 60 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 70 */ 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, +/* 100 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c +}; + +/* rates are in units of Kbps */ +const struct brcms_mcs_info mcs_table[MCS_TABLE_SIZE] = { + /* MCS 0: SS 1, MOD: BPSK, CR 1/2 */ + {6500, 13500, CEIL(6500 * 10, 9), CEIL(13500 * 10, 9), 0x00, + BRCM_RATE_6M}, + /* MCS 1: SS 1, MOD: QPSK, CR 1/2 */ + {13000, 27000, CEIL(13000 * 10, 9), CEIL(27000 * 10, 9), 0x08, + BRCM_RATE_12M}, + /* MCS 2: SS 1, MOD: QPSK, CR 3/4 */ + {19500, 40500, CEIL(19500 * 10, 9), CEIL(40500 * 10, 9), 0x0A, + BRCM_RATE_18M}, + /* MCS 3: SS 1, MOD: 16QAM, CR 1/2 */ + {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0x10, + BRCM_RATE_24M}, + /* MCS 4: SS 1, MOD: 16QAM, CR 3/4 */ + {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x12, + BRCM_RATE_36M}, + /* MCS 5: SS 1, MOD: 64QAM, CR 2/3 */ + {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0x19, + BRCM_RATE_48M}, + /* MCS 6: SS 1, MOD: 64QAM, CR 3/4 */ + {58500, 121500, CEIL(58500 * 10, 9), CEIL(121500 * 10, 9), 0x1A, + BRCM_RATE_54M}, + /* MCS 7: SS 1, MOD: 64QAM, CR 5/6 */ + {65000, 135000, CEIL(65000 * 10, 9), CEIL(135000 * 10, 9), 0x1C, + BRCM_RATE_54M}, + /* MCS 8: SS 2, MOD: BPSK, CR 1/2 */ + {13000, 27000, CEIL(13000 * 10, 9), CEIL(27000 * 10, 9), 0x40, + BRCM_RATE_6M}, + /* MCS 9: SS 2, MOD: QPSK, CR 1/2 */ + {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0x48, + BRCM_RATE_12M}, + /* MCS 10: SS 2, MOD: QPSK, CR 3/4 */ + {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x4A, + BRCM_RATE_18M}, + /* MCS 11: SS 2, MOD: 16QAM, CR 1/2 */ + {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0x50, + BRCM_RATE_24M}, + /* MCS 12: SS 2, MOD: 16QAM, CR 3/4 */ + {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0x52, + BRCM_RATE_36M}, + /* MCS 13: SS 2, MOD: 64QAM, CR 2/3 */ + {104000, 216000, CEIL(104000 * 10, 9), CEIL(216000 * 10, 9), 0x59, + BRCM_RATE_48M}, + /* MCS 14: SS 2, MOD: 64QAM, CR 3/4 */ + {117000, 243000, CEIL(117000 * 10, 9), CEIL(243000 * 10, 9), 0x5A, + BRCM_RATE_54M}, + /* MCS 15: SS 2, MOD: 64QAM, CR 5/6 */ + {130000, 270000, CEIL(130000 * 10, 9), CEIL(270000 * 10, 9), 0x5C, + BRCM_RATE_54M}, + /* MCS 16: SS 3, MOD: BPSK, CR 1/2 */ + {19500, 40500, CEIL(19500 * 10, 9), CEIL(40500 * 10, 9), 0x80, + BRCM_RATE_6M}, + /* MCS 17: SS 3, MOD: QPSK, CR 1/2 */ + {39000, 81000, CEIL(39000 * 10, 9), CEIL(81000 * 10, 9), 0x88, + BRCM_RATE_12M}, + /* MCS 18: SS 3, MOD: QPSK, CR 3/4 */ + {58500, 121500, CEIL(58500 * 10, 9), CEIL(121500 * 10, 9), 0x8A, + BRCM_RATE_18M}, + /* MCS 19: SS 3, MOD: 16QAM, CR 1/2 */ + {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0x90, + BRCM_RATE_24M}, + /* MCS 20: SS 3, MOD: 16QAM, CR 3/4 */ + {117000, 243000, CEIL(117000 * 10, 9), CEIL(243000 * 10, 9), 0x92, + BRCM_RATE_36M}, + /* MCS 21: SS 3, MOD: 64QAM, CR 2/3 */ + {156000, 324000, CEIL(156000 * 10, 9), CEIL(324000 * 10, 9), 0x99, + BRCM_RATE_48M}, + /* MCS 22: SS 3, MOD: 64QAM, CR 3/4 */ + {175500, 364500, CEIL(175500 * 10, 9), CEIL(364500 * 10, 9), 0x9A, + BRCM_RATE_54M}, + /* MCS 23: SS 3, MOD: 64QAM, CR 5/6 */ + {195000, 405000, CEIL(195000 * 10, 9), CEIL(405000 * 10, 9), 0x9B, + BRCM_RATE_54M}, + /* MCS 24: SS 4, MOD: BPSK, CR 1/2 */ + {26000, 54000, CEIL(26000 * 10, 9), CEIL(54000 * 10, 9), 0xC0, + BRCM_RATE_6M}, + /* MCS 25: SS 4, MOD: QPSK, CR 1/2 */ + {52000, 108000, CEIL(52000 * 10, 9), CEIL(108000 * 10, 9), 0xC8, + BRCM_RATE_12M}, + /* MCS 26: SS 4, MOD: QPSK, CR 3/4 */ + {78000, 162000, CEIL(78000 * 10, 9), CEIL(162000 * 10, 9), 0xCA, + BRCM_RATE_18M}, + /* MCS 27: SS 4, MOD: 16QAM, CR 1/2 */ + {104000, 216000, CEIL(104000 * 10, 9), CEIL(216000 * 10, 9), 0xD0, + BRCM_RATE_24M}, + /* MCS 28: SS 4, MOD: 16QAM, CR 3/4 */ + {156000, 324000, CEIL(156000 * 10, 9), CEIL(324000 * 10, 9), 0xD2, + BRCM_RATE_36M}, + /* MCS 29: SS 4, MOD: 64QAM, CR 2/3 */ + {208000, 432000, CEIL(208000 * 10, 9), CEIL(432000 * 10, 9), 0xD9, + BRCM_RATE_48M}, + /* MCS 30: SS 4, MOD: 64QAM, CR 3/4 */ + {234000, 486000, CEIL(234000 * 10, 9), CEIL(486000 * 10, 9), 0xDA, + BRCM_RATE_54M}, + /* MCS 31: SS 4, MOD: 64QAM, CR 5/6 */ + {260000, 540000, CEIL(260000 * 10, 9), CEIL(540000 * 10, 9), 0xDB, + BRCM_RATE_54M}, + /* MCS 32: SS 1, MOD: BPSK, CR 1/2 */ + {0, 6000, 0, CEIL(6000 * 10, 9), 0x00, BRCM_RATE_6M}, +}; + +/* + * phycfg for legacy OFDM frames: code rate, modulation scheme, spatial streams + * Number of spatial streams: always 1 other fields: refer to table 78 of + * section 17.3.2.2 of the original .11a standard + */ +struct legacy_phycfg { + u32 rate_ofdm; /* ofdm mac rate */ + /* phy ctl byte 3, code rate, modulation type, # of streams */ + u8 tx_phy_ctl3; +}; + +/* Number of legacy_rate_cfg entries in the table */ +#define LEGACY_PHYCFG_TABLE_SIZE 12 + +/* + * In CCK mode LPPHY overloads OFDM Modulation bits with CCK Data Rate + * Eventually MIMOPHY would also be converted to this format + * 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps + */ +static const struct +legacy_phycfg legacy_phycfg_table[LEGACY_PHYCFG_TABLE_SIZE] = { + {BRCM_RATE_1M, 0x00}, /* CCK 1Mbps, data rate 0 */ + {BRCM_RATE_2M, 0x08}, /* CCK 2Mbps, data rate 1 */ + {BRCM_RATE_5M5, 0x10}, /* CCK 5.5Mbps, data rate 2 */ + {BRCM_RATE_11M, 0x18}, /* CCK 11Mbps, data rate 3 */ + /* OFDM 6Mbps, code rate 1/2, BPSK, 1 spatial stream */ + {BRCM_RATE_6M, 0x00}, + /* OFDM 9Mbps, code rate 3/4, BPSK, 1 spatial stream */ + {BRCM_RATE_9M, 0x02}, + /* OFDM 12Mbps, code rate 1/2, QPSK, 1 spatial stream */ + {BRCM_RATE_12M, 0x08}, + /* OFDM 18Mbps, code rate 3/4, QPSK, 1 spatial stream */ + {BRCM_RATE_18M, 0x0A}, + /* OFDM 24Mbps, code rate 1/2, 16-QAM, 1 spatial stream */ + {BRCM_RATE_24M, 0x10}, + /* OFDM 36Mbps, code rate 3/4, 16-QAM, 1 spatial stream */ + {BRCM_RATE_36M, 0x12}, + /* OFDM 48Mbps, code rate 2/3, 64-QAM, 1 spatial stream */ + {BRCM_RATE_48M, 0x19}, + /* OFDM 54Mbps, code rate 3/4, 64-QAM, 1 spatial stream */ + {BRCM_RATE_54M, 0x1A}, +}; + +/* Hardware rates (also encodes default basic rates) */ + +const struct brcms_c_rateset cck_ofdm_mimo_rates = { + 12, + /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48, */ + { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60, + /* 54 Mbps */ + 0x6c}, + 0x00, + { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +const struct brcms_c_rateset ofdm_mimo_rates = { + 8, + /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */ + { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c}, + 0x00, + { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +/* Default ratesets that include MCS32 for 40BW channels */ +static const struct brcms_c_rateset cck_ofdm_40bw_mimo_rates = { + 12, + /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48 */ + { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60, + /* 54 Mbps */ + 0x6c}, + 0x00, + { 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +static const struct brcms_c_rateset ofdm_40bw_mimo_rates = { + 8, + /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */ + { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c}, + 0x00, + { 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +const struct brcms_c_rateset cck_ofdm_rates = { + 12, + /* 1b, 2b, 5.5b, 6, 9, 11b, 12, 18, 24, 36, 48,*/ + { 0x82, 0x84, 0x8b, 0x0c, 0x12, 0x96, 0x18, 0x24, 0x30, 0x48, 0x60, + /*54 Mbps */ + 0x6c}, + 0x00, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +const struct brcms_c_rateset gphy_legacy_rates = { + 4, + /* 1b, 2b, 5.5b, 11b Mbps */ + { 0x82, 0x84, 0x8b, 0x96}, + 0x00, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +const struct brcms_c_rateset ofdm_rates = { + 8, + /* 6b, 9, 12b, 18, 24b, 36, 48, 54 Mbps */ + { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c}, + 0x00, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +const struct brcms_c_rateset cck_rates = { + 4, + /* 1b, 2b, 5.5, 11 Mbps */ + { 0x82, 0x84, 0x0b, 0x16}, + 0x00, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00} +}; + +/* check if rateset is valid. + * if check_brate is true, rateset without a basic rate is considered NOT valid. + */ +static bool brcms_c_rateset_valid(struct brcms_c_rateset *rs, bool check_brate) +{ + uint idx; + + if (!rs->count) + return false; + + if (!check_brate) + return true; + + /* error if no basic rates */ + for (idx = 0; idx < rs->count; idx++) { + if (rs->rates[idx] & BRCMS_RATE_FLAG) + return true; + } + return false; +} + +void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams) +{ + int i; + for (i = txstreams; i < MAX_STREAMS_SUPPORTED; i++) + rs->mcs[i] = 0; +} + +/* + * filter based on hardware rateset, and sort filtered rateset with basic + * bit(s) preserved, and check if resulting rateset is valid. +*/ +bool +brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs, + const struct brcms_c_rateset *hw_rs, + bool check_brate, u8 txstreams) +{ + u8 rateset[BRCM_MAXRATE + 1]; + u8 r; + uint count; + uint i; + + memset(rateset, 0, sizeof(rateset)); + count = rs->count; + + for (i = 0; i < count; i++) { + /* mask off "basic rate" bit, BRCMS_RATE_FLAG */ + r = (int)rs->rates[i] & BRCMS_RATE_MASK; + if ((r > BRCM_MAXRATE) || (rate_info[r] == 0)) + continue; + rateset[r] = rs->rates[i]; /* preserve basic bit! */ + } + + /* fill out the rates in order, looking at only supported rates */ + count = 0; + for (i = 0; i < hw_rs->count; i++) { + r = hw_rs->rates[i] & BRCMS_RATE_MASK; + if (rateset[r]) + rs->rates[count++] = rateset[r]; + } + + rs->count = count; + + /* only set the mcs rate bit if the equivalent hw mcs bit is set */ + for (i = 0; i < MCSSET_LEN; i++) + rs->mcs[i] = (rs->mcs[i] & hw_rs->mcs[i]); + + if (brcms_c_rateset_valid(rs, check_brate)) + return true; + else + return false; +} + +/* calculate the rate of a rx'd frame and return it as a ratespec */ +u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp) +{ + int phy_type; + u32 rspec = PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT; + + phy_type = + ((rxh->RxChan & RXS_CHAN_PHYTYPE_MASK) >> RXS_CHAN_PHYTYPE_SHIFT); + + if ((phy_type == PHY_TYPE_N) || (phy_type == PHY_TYPE_SSN) || + (phy_type == PHY_TYPE_LCN) || (phy_type == PHY_TYPE_HT)) { + switch (rxh->PhyRxStatus_0 & PRXS0_FT_MASK) { + case PRXS0_CCK: + rspec = + cck_phy2mac_rate( + ((struct cck_phy_hdr *) plcp)->signal); + break; + case PRXS0_OFDM: + rspec = + ofdm_phy2mac_rate( + ((struct ofdm_phy_hdr *) plcp)->rlpt[0]); + break; + case PRXS0_PREN: + rspec = (plcp[0] & MIMO_PLCP_MCS_MASK) | RSPEC_MIMORATE; + if (plcp[0] & MIMO_PLCP_40MHZ) { + /* indicate rspec is for 40 MHz mode */ + rspec &= ~RSPEC_BW_MASK; + rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT); + } + break; + case PRXS0_STDN: + /* fallthru */ + default: + /* not supported, error condition */ + break; + } + if (plcp3_issgi(plcp[3])) + rspec |= RSPEC_SHORT_GI; + } else + if ((phy_type == PHY_TYPE_A) || (rxh->PhyRxStatus_0 & PRXS0_OFDM)) + rspec = ofdm_phy2mac_rate( + ((struct ofdm_phy_hdr *) plcp)->rlpt[0]); + else + rspec = cck_phy2mac_rate( + ((struct cck_phy_hdr *) plcp)->signal); + + return rspec; +} + +/* copy rateset src to dst as-is (no masking or sorting) */ +void brcms_c_rateset_copy(const struct brcms_c_rateset *src, + struct brcms_c_rateset *dst) +{ + memcpy(dst, src, sizeof(struct brcms_c_rateset)); +} + +/* + * Copy and selectively filter one rateset to another. + * 'basic_only' means only copy basic rates. + * 'rates' indicates cck (11b) and ofdm rates combinations. + * - 0: cck and ofdm + * - 1: cck only + * - 2: ofdm only + * 'xmask' is the copy mask (typically 0x7f or 0xff). + */ +void +brcms_c_rateset_filter(struct brcms_c_rateset *src, struct brcms_c_rateset *dst, + bool basic_only, u8 rates, uint xmask, bool mcsallow) +{ + uint i; + uint r; + uint count; + + count = 0; + for (i = 0; i < src->count; i++) { + r = src->rates[i]; + if (basic_only && !(r & BRCMS_RATE_FLAG)) + continue; + if (rates == BRCMS_RATES_CCK && + is_ofdm_rate((r & BRCMS_RATE_MASK))) + continue; + if (rates == BRCMS_RATES_OFDM && + is_cck_rate((r & BRCMS_RATE_MASK))) + continue; + dst->rates[count++] = r & xmask; + } + dst->count = count; + dst->htphy_membership = src->htphy_membership; + + if (mcsallow && rates != BRCMS_RATES_CCK) + memcpy(&dst->mcs[0], &src->mcs[0], MCSSET_LEN); + else + brcms_c_rateset_mcs_clear(dst); +} + +/* select rateset for a given phy_type and bandtype and filter it, sort it + * and fill rs_tgt with result + */ +void +brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt, + const struct brcms_c_rateset *rs_hw, + uint phy_type, int bandtype, bool cck_only, + uint rate_mask, bool mcsallow, u8 bw, u8 txstreams) +{ + const struct brcms_c_rateset *rs_dflt; + struct brcms_c_rateset rs_sel; + if ((PHYTYPE_IS(phy_type, PHY_TYPE_HT)) || + (PHYTYPE_IS(phy_type, PHY_TYPE_N)) || + (PHYTYPE_IS(phy_type, PHY_TYPE_LCN)) || + (PHYTYPE_IS(phy_type, PHY_TYPE_SSN))) { + if (bandtype == BRCM_BAND_5G) + rs_dflt = (bw == BRCMS_20_MHZ ? + &ofdm_mimo_rates : &ofdm_40bw_mimo_rates); + else + rs_dflt = (bw == BRCMS_20_MHZ ? + &cck_ofdm_mimo_rates : + &cck_ofdm_40bw_mimo_rates); + } else if (PHYTYPE_IS(phy_type, PHY_TYPE_LP)) { + rs_dflt = (bandtype == BRCM_BAND_5G) ? + &ofdm_rates : &cck_ofdm_rates; + } else if (PHYTYPE_IS(phy_type, PHY_TYPE_A)) { + rs_dflt = &ofdm_rates; + } else if (PHYTYPE_IS(phy_type, PHY_TYPE_G)) { + rs_dflt = &cck_ofdm_rates; + } else { + /* should not happen, error condition */ + rs_dflt = &cck_rates; /* force cck */ + } + + /* if hw rateset is not supplied, assign selected rateset to it */ + if (!rs_hw) + rs_hw = rs_dflt; + + brcms_c_rateset_copy(rs_dflt, &rs_sel); + brcms_c_rateset_mcs_upd(&rs_sel, txstreams); + brcms_c_rateset_filter(&rs_sel, rs_tgt, false, + cck_only ? BRCMS_RATES_CCK : BRCMS_RATES_CCK_OFDM, + rate_mask, mcsallow); + brcms_c_rate_hwrs_filter_sort_validate(rs_tgt, rs_hw, false, + mcsallow ? txstreams : 1); +} + +s16 brcms_c_rate_legacy_phyctl(uint rate) +{ + uint i; + for (i = 0; i < LEGACY_PHYCFG_TABLE_SIZE; i++) + if (rate == legacy_phycfg_table[i].rate_ofdm) + return legacy_phycfg_table[i].tx_phy_ctl3; + + return -1; +} + +void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset) +{ + uint i; + for (i = 0; i < MCSSET_LEN; i++) + rateset->mcs[i] = 0; +} + +void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset, u8 txstreams) +{ + memcpy(&rateset->mcs[0], &cck_ofdm_mimo_rates.mcs[0], MCSSET_LEN); + brcms_c_rateset_mcs_upd(rateset, txstreams); +} + +/* Based on bandwidth passed, allow/disallow MCS 32 in the rateset */ +void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset, u8 bw) +{ + if (bw == BRCMS_40_MHZ) + setbit(rateset->mcs, 32); + else + clrbit(rateset->mcs, 32); +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/rate.h b/drivers/net/wireless/brcm80211/brcmsmac/rate.h new file mode 100644 index 000000000000..e7b9dc2f2731 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/rate.h @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_RATE_H_ +#define _BRCM_RATE_H_ + +#include "types.h" +#include "d11.h" + +extern const u8 rate_info[]; +extern const struct brcms_c_rateset cck_ofdm_mimo_rates; +extern const struct brcms_c_rateset ofdm_mimo_rates; +extern const struct brcms_c_rateset cck_ofdm_rates; +extern const struct brcms_c_rateset ofdm_rates; +extern const struct brcms_c_rateset cck_rates; +extern const struct brcms_c_rateset gphy_legacy_rates; +extern const struct brcms_c_rateset rate_limit_1_2; + +struct brcms_mcs_info { + /* phy rate in kbps [20Mhz] */ + u32 phy_rate_20; + /* phy rate in kbps [40Mhz] */ + u32 phy_rate_40; + /* phy rate in kbps [20Mhz] with SGI */ + u32 phy_rate_20_sgi; + /* phy rate in kbps [40Mhz] with SGI */ + u32 phy_rate_40_sgi; + /* phy ctl byte 3, code rate, modulation type, # of streams */ + u8 tx_phy_ctl3; + /* matching legacy ofdm rate in 500bkps */ + u8 leg_ofdm; +}; + +#define BRCMS_MAXMCS 32 /* max valid mcs index */ +#define MCS_TABLE_SIZE 33 /* Number of mcs entries in the table */ +extern const struct brcms_mcs_info mcs_table[]; + +#define MCS_TXS_MASK 0xc0 /* num tx streams - 1 bit mask */ +#define MCS_TXS_SHIFT 6 /* num tx streams - 1 bit shift */ + +/* returns num tx streams - 1 */ +static inline u8 mcs_2_txstreams(u8 mcs) +{ + return (mcs_table[mcs].tx_phy_ctl3 & MCS_TXS_MASK) >> MCS_TXS_SHIFT; +} + +static inline uint mcs_2_rate(u8 mcs, bool is40, bool sgi) +{ + if (sgi) { + if (is40) + return mcs_table[mcs].phy_rate_40_sgi; + return mcs_table[mcs].phy_rate_20_sgi; + } + if (is40) + return mcs_table[mcs].phy_rate_40; + + return mcs_table[mcs].phy_rate_20; +} + +/* Macro to use the rate_info table */ +#define BRCMS_RATE_MASK_FULL 0xff /* Rate value mask with basic rate flag */ + +/* + * rate spec : holds rate and mode specific information required to generate a + * tx frame. Legacy CCK and OFDM information is held in the same manner as was + * done in the past (in the lower byte) the upper 3 bytes primarily hold MIMO + * specific information + */ + +/* rate spec bit fields */ + +/* Either 500Kbps units or MIMO MCS idx */ +#define RSPEC_RATE_MASK 0x0000007F +/* mimo MCS is stored in RSPEC_RATE_MASK */ +#define RSPEC_MIMORATE 0x08000000 +/* mimo bw mask */ +#define RSPEC_BW_MASK 0x00000700 +/* mimo bw shift */ +#define RSPEC_BW_SHIFT 8 +/* mimo Space/Time/Frequency mode mask */ +#define RSPEC_STF_MASK 0x00003800 +/* mimo Space/Time/Frequency mode shift */ +#define RSPEC_STF_SHIFT 11 +/* mimo coding type mask */ +#define RSPEC_CT_MASK 0x0000C000 +/* mimo coding type shift */ +#define RSPEC_CT_SHIFT 14 +/* mimo num STC streams per PLCP defn. */ +#define RSPEC_STC_MASK 0x00300000 +/* mimo num STC streams per PLCP defn. */ +#define RSPEC_STC_SHIFT 20 +/* mimo bit indicates adv coding in use */ +#define RSPEC_LDPC_CODING 0x00400000 +/* mimo bit indicates short GI in use */ +#define RSPEC_SHORT_GI 0x00800000 +/* bit indicates override both rate & mode */ +#define RSPEC_OVERRIDE 0x80000000 +/* bit indicates override rate only */ +#define RSPEC_OVERRIDE_MCS_ONLY 0x40000000 + +static inline bool rspec_active(u32 rspec) +{ + return rspec & (RSPEC_RATE_MASK | RSPEC_MIMORATE); +} + +static inline u8 rspec_phytxbyte2(u32 rspec) +{ + return (rspec & 0xff00) >> 8; +} + +static inline u32 rspec_get_bw(u32 rspec) +{ + return (rspec & RSPEC_BW_MASK) >> RSPEC_BW_SHIFT; +} + +static inline bool rspec_issgi(u32 rspec) +{ + return (rspec & RSPEC_SHORT_GI) == RSPEC_SHORT_GI; +} + +static inline bool rspec_is40mhz(u32 rspec) +{ + u32 bw = rspec_get_bw(rspec); + + return bw == PHY_TXC1_BW_40MHZ || bw == PHY_TXC1_BW_40MHZ_DUP; +} + +static inline uint rspec2rate(u32 rspec) +{ + if (rspec & RSPEC_MIMORATE) + return mcs_2_rate(rspec & RSPEC_RATE_MASK, rspec_is40mhz(rspec), + rspec_issgi(rspec)); + return rspec & RSPEC_RATE_MASK; +} + +static inline u8 rspec_mimoplcp3(u32 rspec) +{ + return (rspec & 0xf00000) >> 16; +} + +static inline bool plcp3_issgi(u8 plcp) +{ + return (plcp & (RSPEC_SHORT_GI >> 16)) != 0; +} + +static inline uint rspec_stc(u32 rspec) +{ + return (rspec & RSPEC_STC_MASK) >> RSPEC_STC_SHIFT; +} + +static inline uint rspec_stf(u32 rspec) +{ + return (rspec & RSPEC_STF_MASK) >> RSPEC_STF_SHIFT; +} + +static inline bool is_mcs_rate(u32 ratespec) +{ + return (ratespec & RSPEC_MIMORATE) != 0; +} + +static inline bool is_ofdm_rate(u32 ratespec) +{ + return !is_mcs_rate(ratespec) && + (rate_info[ratespec & RSPEC_RATE_MASK] & BRCMS_RATE_FLAG); +} + +static inline bool is_cck_rate(u32 ratespec) +{ + u32 rate = (ratespec & BRCMS_RATE_MASK); + + return !is_mcs_rate(ratespec) && ( + rate == BRCM_RATE_1M || rate == BRCM_RATE_2M || + rate == BRCM_RATE_5M5 || rate == BRCM_RATE_11M); +} + +static inline bool is_single_stream(u8 mcs) +{ + return mcs <= HIGHEST_SINGLE_STREAM_MCS || mcs == 32; +} + +static inline u8 cck_rspec(u8 cck) +{ + return cck & RSPEC_RATE_MASK; +} + +/* Convert encoded rate value in plcp header to numerical rates in 500 KHz + * increments */ +extern const u8 ofdm_rate_lookup[]; + +static inline u8 ofdm_phy2mac_rate(u8 rlpt) +{ + return ofdm_rate_lookup[rlpt & 0x7]; +} + +static inline u8 cck_phy2mac_rate(u8 signal) +{ + return signal/5; +} + +/* Rates specified in brcms_c_rateset_filter() */ +#define BRCMS_RATES_CCK_OFDM 0 +#define BRCMS_RATES_CCK 1 +#define BRCMS_RATES_OFDM 2 + +/* sanitize, and sort a rateset with the basic bit(s) preserved, validate + * rateset */ +extern bool +brcms_c_rate_hwrs_filter_sort_validate(struct brcms_c_rateset *rs, + const struct brcms_c_rateset *hw_rs, + bool check_brate, u8 txstreams); +/* copy rateset src to dst as-is (no masking or sorting) */ +extern void brcms_c_rateset_copy(const struct brcms_c_rateset *src, + struct brcms_c_rateset *dst); + +/* would be nice to have these documented ... */ +extern u32 brcms_c_compute_rspec(struct d11rxhdr *rxh, u8 *plcp); + +extern void brcms_c_rateset_filter(struct brcms_c_rateset *src, + struct brcms_c_rateset *dst, bool basic_only, u8 rates, uint xmask, + bool mcsallow); + +extern void +brcms_c_rateset_default(struct brcms_c_rateset *rs_tgt, + const struct brcms_c_rateset *rs_hw, uint phy_type, + int bandtype, bool cck_only, uint rate_mask, + bool mcsallow, u8 bw, u8 txstreams); + +extern s16 brcms_c_rate_legacy_phyctl(uint rate); + +extern void brcms_c_rateset_mcs_upd(struct brcms_c_rateset *rs, u8 txstreams); +extern void brcms_c_rateset_mcs_clear(struct brcms_c_rateset *rateset); +extern void brcms_c_rateset_mcs_build(struct brcms_c_rateset *rateset, + u8 txstreams); +extern void brcms_c_rateset_bw_mcs_filter(struct brcms_c_rateset *rateset, + u8 bw); + +#endif /* _BRCM_RATE_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/scb.h b/drivers/net/wireless/brcm80211/brcmsmac/scb.h new file mode 100644 index 000000000000..51c79c7239b7 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/scb.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_SCB_H_ +#define _BRCM_SCB_H_ + +#include <linux/if_ether.h> +#include <brcmu_utils.h> +#include <defs.h> +#include "types.h" + +#define AMPDU_TX_BA_MAX_WSIZE 64 /* max Tx ba window size (in pdu) */ + +#define AMPDU_MAX_SCB_TID NUMPRIO + +/* scb flags */ +#define SCB_WMECAP 0x0040 +#define SCB_HTCAP 0x10000 /* HT (MIMO) capable device */ +#define SCB_IS40 0x80000 /* 40MHz capable */ +#define SCB_STBCCAP 0x40000000 /* STBC Capable */ + +#define SCB_MAGIC 0xbeefcafe + +/* structure to store per-tid state for the ampdu initiator */ +struct scb_ampdu_tid_ini { + u8 tx_in_transit; /* number of pending mpdus in transit in driver */ + u8 tid; /* initiator tid for easy lookup */ + /* tx retry count; indexed by seq modulo */ + u8 txretry[AMPDU_TX_BA_MAX_WSIZE]; + struct scb *scb; /* backptr for easy lookup */ + u8 ba_wsize; /* negotiated ba window size (in pdu) */ +}; + +struct scb_ampdu { + struct scb *scb; /* back pointer for easy reference */ + u8 mpdu_density; /* mpdu density */ + u8 max_pdu; /* max pdus allowed in ampdu */ + u8 release; /* # of mpdus released at a time */ + u16 min_len; /* min mpdu len to support the density */ + u32 max_rx_ampdu_bytes; /* max ampdu rcv length; 8k, 16k, 32k, 64k */ + + /* + * This could easily be a ini[] pointer and we keep this info in wl + * itself instead of having mac80211 hold it for us. Also could be made + * dynamic per tid instead of static. + */ + /* initiator info - per tid (NUMPRIO): */ + struct scb_ampdu_tid_ini ini[AMPDU_MAX_SCB_TID]; +}; + +/* station control block - one per remote MAC address */ +struct scb { + u32 magic; + u32 flags; /* various bit flags as defined below */ + u32 flags2; /* various bit flags2 as defined below */ + u8 state; /* current state bitfield of auth/assoc process */ + u8 ea[ETH_ALEN]; /* station address */ + uint fragresid[NUMPRIO];/* #bytes unused in frag buffer per prio */ + + u16 seqctl[NUMPRIO]; /* seqctl of last received frame (for dups) */ + /* seqctl of last received frame (for dups) for non-QoS data and + * management */ + u16 seqctl_nonqos; + u16 seqnum[NUMPRIO];/* WME: driver maintained sw seqnum per priority */ + + struct scb_ampdu scb_ampdu; /* AMPDU state including per tid info */ +}; + +#endif /* _BRCM_SCB_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c new file mode 100644 index 000000000000..99f791048e84 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.c @@ -0,0 +1,1298 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/kernel.h> +#include <linux/string.h> +#include <linux/io.h> +#include <linux/etherdevice.h> +#include <linux/crc8.h> +#include <stdarg.h> + +#include <chipcommon.h> +#include <brcmu_utils.h> +#include "pub.h" +#include "nicpci.h" +#include "aiutils.h" +#include "otp.h" +#include "srom.h" + +/* + * SROM CRC8 polynomial value: + * + * x^8 + x^7 +x^6 + x^4 + x^2 + 1 + */ +#define SROM_CRC8_POLY 0xAB + +/* Maximum srom: 6 Kilobits == 768 bytes */ +#define SROM_MAX 768 + +/* PCI fields */ +#define PCI_F0DEVID 48 + +#define SROM_WORDS 64 + +#define SROM_SSID 2 + +#define SROM_WL1LHMAXP 29 + +#define SROM_WL1LPAB0 30 +#define SROM_WL1LPAB1 31 +#define SROM_WL1LPAB2 32 + +#define SROM_WL1HPAB0 33 +#define SROM_WL1HPAB1 34 +#define SROM_WL1HPAB2 35 + +#define SROM_MACHI_IL0 36 +#define SROM_MACMID_IL0 37 +#define SROM_MACLO_IL0 38 +#define SROM_MACHI_ET1 42 +#define SROM_MACMID_ET1 43 +#define SROM_MACLO_ET1 44 +#define SROM3_MACHI 37 +#define SROM3_MACMID 38 +#define SROM3_MACLO 39 + +#define SROM_BXARSSI2G 40 +#define SROM_BXARSSI5G 41 + +#define SROM_TRI52G 42 +#define SROM_TRI5GHL 43 + +#define SROM_RXPO52G 45 + +#define SROM_AABREV 46 +/* Fields in AABREV */ +#define SROM_BR_MASK 0x00ff +#define SROM_CC_MASK 0x0f00 +#define SROM_CC_SHIFT 8 +#define SROM_AA0_MASK 0x3000 +#define SROM_AA0_SHIFT 12 +#define SROM_AA1_MASK 0xc000 +#define SROM_AA1_SHIFT 14 + +#define SROM_WL0PAB0 47 +#define SROM_WL0PAB1 48 +#define SROM_WL0PAB2 49 + +#define SROM_LEDBH10 50 +#define SROM_LEDBH32 51 + +#define SROM_WL10MAXP 52 + +#define SROM_WL1PAB0 53 +#define SROM_WL1PAB1 54 +#define SROM_WL1PAB2 55 + +#define SROM_ITT 56 + +#define SROM_BFL 57 +#define SROM_BFL2 28 +#define SROM3_BFL2 61 + +#define SROM_AG10 58 + +#define SROM_CCODE 59 + +#define SROM_OPO 60 + +#define SROM3_LEDDC 62 + +#define SROM_CRCREV 63 + +/* SROM Rev 4: Reallocate the software part of the srom to accommodate + * MIMO features. It assumes up to two PCIE functions and 440 bytes + * of usable srom i.e. the usable storage in chips with OTP that + * implements hardware redundancy. + */ + +#define SROM4_WORDS 220 + +#define SROM4_SIGN 32 +#define SROM4_SIGNATURE 0x5372 + +#define SROM4_BREV 33 + +#define SROM4_BFL0 34 +#define SROM4_BFL1 35 +#define SROM4_BFL2 36 +#define SROM4_BFL3 37 +#define SROM5_BFL0 37 +#define SROM5_BFL1 38 +#define SROM5_BFL2 39 +#define SROM5_BFL3 40 + +#define SROM4_MACHI 38 +#define SROM4_MACMID 39 +#define SROM4_MACLO 40 +#define SROM5_MACHI 41 +#define SROM5_MACMID 42 +#define SROM5_MACLO 43 + +#define SROM4_CCODE 41 +#define SROM4_REGREV 42 +#define SROM5_CCODE 34 +#define SROM5_REGREV 35 + +#define SROM4_LEDBH10 43 +#define SROM4_LEDBH32 44 +#define SROM5_LEDBH10 59 +#define SROM5_LEDBH32 60 + +#define SROM4_LEDDC 45 +#define SROM5_LEDDC 45 + +#define SROM4_AA 46 + +#define SROM4_AG10 47 +#define SROM4_AG32 48 + +#define SROM4_TXPID2G 49 +#define SROM4_TXPID5G 51 +#define SROM4_TXPID5GL 53 +#define SROM4_TXPID5GH 55 + +#define SROM4_TXRXC 61 +#define SROM4_TXCHAIN_MASK 0x000f +#define SROM4_TXCHAIN_SHIFT 0 +#define SROM4_RXCHAIN_MASK 0x00f0 +#define SROM4_RXCHAIN_SHIFT 4 +#define SROM4_SWITCH_MASK 0xff00 +#define SROM4_SWITCH_SHIFT 8 + +/* Per-path fields */ +#define MAX_PATH_SROM 4 +#define SROM4_PATH0 64 +#define SROM4_PATH1 87 +#define SROM4_PATH2 110 +#define SROM4_PATH3 133 + +#define SROM4_2G_ITT_MAXP 0 +#define SROM4_2G_PA 1 +#define SROM4_5G_ITT_MAXP 5 +#define SROM4_5GLH_MAXP 6 +#define SROM4_5G_PA 7 +#define SROM4_5GL_PA 11 +#define SROM4_5GH_PA 15 + +/* All the miriad power offsets */ +#define SROM4_2G_CCKPO 156 +#define SROM4_2G_OFDMPO 157 +#define SROM4_5G_OFDMPO 159 +#define SROM4_5GL_OFDMPO 161 +#define SROM4_5GH_OFDMPO 163 +#define SROM4_2G_MCSPO 165 +#define SROM4_5G_MCSPO 173 +#define SROM4_5GL_MCSPO 181 +#define SROM4_5GH_MCSPO 189 +#define SROM4_CDDPO 197 +#define SROM4_STBCPO 198 +#define SROM4_BW40PO 199 +#define SROM4_BWDUPPO 200 + +#define SROM4_CRCREV 219 + +/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6. + * This is acombined srom for both MIMO and SISO boards, usable in + * the .130 4Kilobit OTP with hardware redundancy. + */ +#define SROM8_BREV 65 + +#define SROM8_BFL0 66 +#define SROM8_BFL1 67 +#define SROM8_BFL2 68 +#define SROM8_BFL3 69 + +#define SROM8_MACHI 70 +#define SROM8_MACMID 71 +#define SROM8_MACLO 72 + +#define SROM8_CCODE 73 +#define SROM8_REGREV 74 + +#define SROM8_LEDBH10 75 +#define SROM8_LEDBH32 76 + +#define SROM8_LEDDC 77 + +#define SROM8_AA 78 + +#define SROM8_AG10 79 +#define SROM8_AG32 80 + +#define SROM8_TXRXC 81 + +#define SROM8_BXARSSI2G 82 +#define SROM8_BXARSSI5G 83 +#define SROM8_TRI52G 84 +#define SROM8_TRI5GHL 85 +#define SROM8_RXPO52G 86 + +#define SROM8_FEM2G 87 +#define SROM8_FEM5G 88 +#define SROM8_FEM_ANTSWLUT_MASK 0xf800 +#define SROM8_FEM_ANTSWLUT_SHIFT 11 +#define SROM8_FEM_TR_ISO_MASK 0x0700 +#define SROM8_FEM_TR_ISO_SHIFT 8 +#define SROM8_FEM_PDET_RANGE_MASK 0x00f8 +#define SROM8_FEM_PDET_RANGE_SHIFT 3 +#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006 +#define SROM8_FEM_EXTPA_GAIN_SHIFT 1 +#define SROM8_FEM_TSSIPOS_MASK 0x0001 +#define SROM8_FEM_TSSIPOS_SHIFT 0 + +#define SROM8_THERMAL 89 + +/* Temp sense related entries */ +#define SROM8_MPWR_RAWTS 90 +#define SROM8_TS_SLP_OPT_CORRX 91 +/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, + * IQSWP: IQ CAL swap disable */ +#define SROM8_FOC_HWIQ_IQSWP 92 + +/* Temperature delta for PHY calibration */ +#define SROM8_PHYCAL_TEMPDELTA 93 + +/* Per-path offsets & fields */ +#define SROM8_PATH0 96 +#define SROM8_PATH1 112 +#define SROM8_PATH2 128 +#define SROM8_PATH3 144 + +#define SROM8_2G_ITT_MAXP 0 +#define SROM8_2G_PA 1 +#define SROM8_5G_ITT_MAXP 4 +#define SROM8_5GLH_MAXP 5 +#define SROM8_5G_PA 6 +#define SROM8_5GL_PA 9 +#define SROM8_5GH_PA 12 + +/* All the miriad power offsets */ +#define SROM8_2G_CCKPO 160 + +#define SROM8_2G_OFDMPO 161 +#define SROM8_5G_OFDMPO 163 +#define SROM8_5GL_OFDMPO 165 +#define SROM8_5GH_OFDMPO 167 + +#define SROM8_2G_MCSPO 169 +#define SROM8_5G_MCSPO 177 +#define SROM8_5GL_MCSPO 185 +#define SROM8_5GH_MCSPO 193 + +#define SROM8_CDDPO 201 +#define SROM8_STBCPO 202 +#define SROM8_BW40PO 203 +#define SROM8_BWDUPPO 204 + +/* SISO PA parameters are in the path0 spaces */ +#define SROM8_SISO 96 + +/* Legacy names for SISO PA paramters */ +#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP) +#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA) +#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1) +#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2) +#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP) +#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP) +#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA) +#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1) +#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2) +#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA) +#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1) +#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2) +#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA) +#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1) +#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2) + +/* SROM REV 9 */ +#define SROM9_2GPO_CCKBW20 160 +#define SROM9_2GPO_CCKBW20UL 161 +#define SROM9_2GPO_LOFDMBW20 162 +#define SROM9_2GPO_LOFDMBW20UL 164 + +#define SROM9_5GLPO_LOFDMBW20 166 +#define SROM9_5GLPO_LOFDMBW20UL 168 +#define SROM9_5GMPO_LOFDMBW20 170 +#define SROM9_5GMPO_LOFDMBW20UL 172 +#define SROM9_5GHPO_LOFDMBW20 174 +#define SROM9_5GHPO_LOFDMBW20UL 176 + +#define SROM9_2GPO_MCSBW20 178 +#define SROM9_2GPO_MCSBW20UL 180 +#define SROM9_2GPO_MCSBW40 182 + +#define SROM9_5GLPO_MCSBW20 184 +#define SROM9_5GLPO_MCSBW20UL 186 +#define SROM9_5GLPO_MCSBW40 188 +#define SROM9_5GMPO_MCSBW20 190 +#define SROM9_5GMPO_MCSBW20UL 192 +#define SROM9_5GMPO_MCSBW40 194 +#define SROM9_5GHPO_MCSBW20 196 +#define SROM9_5GHPO_MCSBW20UL 198 +#define SROM9_5GHPO_MCSBW40 200 + +#define SROM9_PO_MCS32 202 +#define SROM9_PO_LOFDM40DUP 203 + +/* SROM flags (see sromvar_t) */ + +/* value continues as described by the next entry */ +#define SRFL_MORE 1 +#define SRFL_NOFFS 2 /* value bits can't be all one's */ +#define SRFL_PRHEX 4 /* value is in hexdecimal format */ +#define SRFL_PRSIGN 8 /* value is in signed decimal format */ +#define SRFL_CCODE 0x10 /* value is in country code format */ +#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */ +#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */ +/* do not generate a nvram param, entry is for mfgc */ +#define SRFL_NOVAR 0x80 + +/* Max. nvram variable table size */ +#define MAXSZ_NVRAM_VARS 4096 + +/* + * indicates type of value. + */ +enum brcms_srom_var_type { + BRCMS_SROM_STRING, + BRCMS_SROM_SNUMBER, + BRCMS_SROM_UNUMBER +}; + +/* + * storage type for srom variable. + * + * var_list: for linked list operations. + * varid: identifier of the variable. + * var_type: type of variable. + * buf: variable value when var_type == BRCMS_SROM_STRING. + * uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER. + * sval: signed variable value when var_type == BRCMS_SROM_SNUMBER. + */ +struct brcms_srom_list_head { + struct list_head var_list; + enum brcms_srom_id varid; + enum brcms_srom_var_type var_type; + union { + char buf[0]; + u32 uval; + s32 sval; + }; +}; + +struct brcms_sromvar { + enum brcms_srom_id varid; + u32 revmask; + u32 flags; + u16 off; + u16 mask; +}; + +struct brcms_varbuf { + char *base; /* pointer to buffer base */ + char *buf; /* pointer to current position */ + unsigned int size; /* current (residual) size in bytes */ +}; + +/* + * Assumptions: + * - Ethernet address spans across 3 consecutive words + * + * Table rules: + * - Add multiple entries next to each other if a value spans across multiple + * words (even multiple fields in the same word) with each entry except the + * last having it's SRFL_MORE bit set. + * - Ethernet address entry does not follow above rule and must not have + * SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words. + * - The last entry's name field must be NULL to indicate the end of the table. + * Other entries must have non-NULL name. + */ +static const struct brcms_sromvar pci_sromvars[] = { + {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID, + 0xffff}, + {BRCMS_SROM_BOARDREV, 0x0000000e, SRFL_PRHEX, SROM_AABREV, + SROM_BR_MASK}, + {BRCMS_SROM_BOARDREV, 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, + {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, + {BRCMS_SROM_BOARDFLAGS, 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, + {BRCMS_SROM_BOARDFLAGS, 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM_BFL2, 0xffff}, + {BRCMS_SROM_BOARDFLAGS, 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM3_BFL2, 0xffff}, + {BRCMS_SROM_BOARDFLAGS, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM4_BFL1, 0xffff}, + {BRCMS_SROM_BOARDFLAGS, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM5_BFL1, 0xffff}, + {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff}, + {BRCMS_SROM_BOARDFLAGS2, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM4_BFL3, 0xffff}, + {BRCMS_SROM_BOARDFLAGS2, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM5_BFL3, 0xffff}, + {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff}, + {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, + {BRCMS_SROM_BOARDNUM, 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, + {BRCMS_SROM_BOARDNUM, 0x00000008, 0, SROM3_MACLO, 0xffff}, + {BRCMS_SROM_BOARDNUM, 0x00000010, 0, SROM4_MACLO, 0xffff}, + {BRCMS_SROM_BOARDNUM, 0x000000e0, 0, SROM5_MACLO, 0xffff}, + {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff}, + {BRCMS_SROM_CC, 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, + {BRCMS_SROM_REGREV, 0x00000008, 0, SROM_OPO, 0xff00}, + {BRCMS_SROM_REGREV, 0x00000010, 0, SROM4_REGREV, 0x00ff}, + {BRCMS_SROM_REGREV, 0x000000e0, 0, SROM5_REGREV, 0x00ff}, + {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff}, + {BRCMS_SROM_LEDBH0, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff}, + {BRCMS_SROM_LEDBH1, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, + {BRCMS_SROM_LEDBH2, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff}, + {BRCMS_SROM_LEDBH3, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, + {BRCMS_SROM_LEDBH0, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff}, + {BRCMS_SROM_LEDBH1, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, + {BRCMS_SROM_LEDBH2, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff}, + {BRCMS_SROM_LEDBH3, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, + {BRCMS_SROM_LEDBH0, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff}, + {BRCMS_SROM_LEDBH1, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, + {BRCMS_SROM_LEDBH2, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff}, + {BRCMS_SROM_LEDBH3, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, + {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, + {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, + {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, + {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, + {BRCMS_SROM_PA0B0, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, + {BRCMS_SROM_PA0B1, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, + {BRCMS_SROM_PA0B2, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, + {BRCMS_SROM_PA0ITSSIT, 0x0000000e, 0, SROM_ITT, 0x00ff}, + {BRCMS_SROM_PA0MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, + {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, + {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, + {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, + {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00}, + {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff}, + {BRCMS_SROM_OPO, 0x0000000c, 0, SROM_OPO, 0x00ff}, + {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff}, + {BRCMS_SROM_AA2G, 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, + {BRCMS_SROM_AA2G, 0x000000f0, 0, SROM4_AA, 0x00ff}, + {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff}, + {BRCMS_SROM_AA5G, 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, + {BRCMS_SROM_AA5G, 0x000000f0, 0, SROM4_AA, 0xff00}, + {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00}, + {BRCMS_SROM_AG0, 0x0000000e, 0, SROM_AG10, 0x00ff}, + {BRCMS_SROM_AG1, 0x0000000e, 0, SROM_AG10, 0xff00}, + {BRCMS_SROM_AG0, 0x000000f0, 0, SROM4_AG10, 0x00ff}, + {BRCMS_SROM_AG1, 0x000000f0, 0, SROM4_AG10, 0xff00}, + {BRCMS_SROM_AG2, 0x000000f0, 0, SROM4_AG32, 0x00ff}, + {BRCMS_SROM_AG3, 0x000000f0, 0, SROM4_AG32, 0xff00}, + {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff}, + {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00}, + {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff}, + {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00}, + {BRCMS_SROM_PA1B0, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, + {BRCMS_SROM_PA1B1, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, + {BRCMS_SROM_PA1B2, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, + {BRCMS_SROM_PA1LOB0, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, + {BRCMS_SROM_PA1LOB1, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, + {BRCMS_SROM_PA1LOB2, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, + {BRCMS_SROM_PA1HIB0, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, + {BRCMS_SROM_PA1HIB1, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, + {BRCMS_SROM_PA1HIB2, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, + {BRCMS_SROM_PA1ITSSIT, 0x0000000e, 0, SROM_ITT, 0xff00}, + {BRCMS_SROM_PA1MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, + {BRCMS_SROM_PA1LOMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, + {BRCMS_SROM_PA1HIMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, + {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, + {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, + {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, + {BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, + {BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, + {BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, + {BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, + {BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, + {BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, + {BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00}, + {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff}, + {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00}, + {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, + {BRCMS_SROM_BXA2G, 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, + {BRCMS_SROM_RSSISAV2G, 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, + {BRCMS_SROM_RSSISMC2G, 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, + {BRCMS_SROM_RSSISMF2G, 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, + {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800}, + {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700}, + {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0}, + {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f}, + {BRCMS_SROM_BXA5G, 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, + {BRCMS_SROM_RSSISAV5G, 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, + {BRCMS_SROM_RSSISMC5G, 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, + {BRCMS_SROM_RSSISMF5G, 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, + {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800}, + {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700}, + {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0}, + {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f}, + {BRCMS_SROM_TRI2G, 0x00000008, 0, SROM_TRI52G, 0x00ff}, + {BRCMS_SROM_TRI5G, 0x00000008, 0, SROM_TRI52G, 0xff00}, + {BRCMS_SROM_TRI5GL, 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, + {BRCMS_SROM_TRI5GH, 0x00000008, 0, SROM_TRI5GHL, 0xff00}, + {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff}, + {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00}, + {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff}, + {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00}, + {BRCMS_SROM_RXPO2G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, + {BRCMS_SROM_RXPO5G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, + {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, + {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, + {BRCMS_SROM_TXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, + SROM4_TXCHAIN_MASK}, + {BRCMS_SROM_RXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, + SROM4_RXCHAIN_MASK}, + {BRCMS_SROM_ANTSWITCH, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, + SROM4_SWITCH_MASK}, + {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, + SROM4_TXCHAIN_MASK}, + {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, + SROM4_RXCHAIN_MASK}, + {BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, + SROM4_SWITCH_MASK}, + {BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G, + SROM8_FEM_TSSIPOS_MASK}, + {BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G, + SROM8_FEM_EXTPA_GAIN_MASK}, + {BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G, + SROM8_FEM_PDET_RANGE_MASK}, + {BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, + {BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G, + SROM8_FEM_ANTSWLUT_MASK}, + {BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G, + SROM8_FEM_TSSIPOS_MASK}, + {BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G, + SROM8_FEM_EXTPA_GAIN_MASK}, + {BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G, + SROM8_FEM_PDET_RANGE_MASK}, + {BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, + {BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G, + SROM8_FEM_ANTSWLUT_MASK}, + {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00}, + {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff}, + {BRCMS_SROM_TXPID2GA0, 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, + {BRCMS_SROM_TXPID2GA1, 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, + {BRCMS_SROM_TXPID2GA2, 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff}, + {BRCMS_SROM_TXPID2GA3, 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00}, + {BRCMS_SROM_TXPID5GA0, 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, + {BRCMS_SROM_TXPID5GA1, 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, + {BRCMS_SROM_TXPID5GA2, 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff}, + {BRCMS_SROM_TXPID5GA3, 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00}, + {BRCMS_SROM_TXPID5GLA0, 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, + {BRCMS_SROM_TXPID5GLA1, 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, + {BRCMS_SROM_TXPID5GLA2, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff}, + {BRCMS_SROM_TXPID5GLA3, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00}, + {BRCMS_SROM_TXPID5GHA0, 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, + {BRCMS_SROM_TXPID5GHA1, 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, + {BRCMS_SROM_TXPID5GHA2, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff}, + {BRCMS_SROM_TXPID5GHA3, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00}, + + {BRCMS_SROM_CCODE, 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, + {BRCMS_SROM_CCODE, 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, + {BRCMS_SROM_CCODE, 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, + {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff}, + {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, + {BRCMS_SROM_MACADDR, 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, + {BRCMS_SROM_MACADDR, 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, + {BRCMS_SROM_MACADDR, 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, + {BRCMS_SROM_IL0MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, + 0xffff}, + {BRCMS_SROM_ET1MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, + 0xffff}, + {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, + 0xffff}, + {BRCMS_SROM_LEDDC, 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC, + 0xffff}, + {BRCMS_SROM_LEDDC, 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC, + 0xffff}, + {BRCMS_SROM_LEDDC, 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC, + 0xffff}, + {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, + 0x01ff}, + {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, + 0xfe00}, + {BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX, + SROM8_TS_SLP_OPT_CORRX, 0x00ff}, + {BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, + 0xfc00}, + {BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX, + SROM8_TS_SLP_OPT_CORRX, 0x0300}, + {BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX, + SROM8_FOC_HWIQ_IQSWP, 0x000f}, + {BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, + 0x0010}, + {BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, + 0x0020}, + {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA, + 0x00ff}, + + {BRCMS_SROM_CCK2GPO, 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, + {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, + {BRCMS_SROM_OFDM2GPO, 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM4_2G_OFDMPO + 1, 0xffff}, + {BRCMS_SROM_OFDM5GPO, 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM4_5G_OFDMPO + 1, 0xffff}, + {BRCMS_SROM_OFDM5GLPO, 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff}, + {BRCMS_SROM_OFDM5GHPO, 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff}, + {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, + {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, + {BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, + {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, + {BRCMS_SROM_MCS2GPO0, 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, + {BRCMS_SROM_MCS2GPO1, 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff}, + {BRCMS_SROM_MCS2GPO2, 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff}, + {BRCMS_SROM_MCS2GPO3, 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff}, + {BRCMS_SROM_MCS2GPO4, 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff}, + {BRCMS_SROM_MCS2GPO5, 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff}, + {BRCMS_SROM_MCS2GPO6, 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff}, + {BRCMS_SROM_MCS2GPO7, 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff}, + {BRCMS_SROM_MCS5GPO0, 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, + {BRCMS_SROM_MCS5GPO1, 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff}, + {BRCMS_SROM_MCS5GPO2, 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff}, + {BRCMS_SROM_MCS5GPO3, 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff}, + {BRCMS_SROM_MCS5GPO4, 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff}, + {BRCMS_SROM_MCS5GPO5, 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff}, + {BRCMS_SROM_MCS5GPO6, 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff}, + {BRCMS_SROM_MCS5GPO7, 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff}, + {BRCMS_SROM_MCS5GLPO0, 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, + {BRCMS_SROM_MCS5GLPO1, 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff}, + {BRCMS_SROM_MCS5GLPO2, 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff}, + {BRCMS_SROM_MCS5GLPO3, 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff}, + {BRCMS_SROM_MCS5GLPO4, 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff}, + {BRCMS_SROM_MCS5GLPO5, 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff}, + {BRCMS_SROM_MCS5GLPO6, 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff}, + {BRCMS_SROM_MCS5GLPO7, 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff}, + {BRCMS_SROM_MCS5GHPO0, 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, + {BRCMS_SROM_MCS5GHPO1, 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff}, + {BRCMS_SROM_MCS5GHPO2, 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff}, + {BRCMS_SROM_MCS5GHPO3, 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff}, + {BRCMS_SROM_MCS5GHPO4, 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff}, + {BRCMS_SROM_MCS5GHPO5, 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff}, + {BRCMS_SROM_MCS5GHPO6, 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff}, + {BRCMS_SROM_MCS5GHPO7, 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff}, + {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, + {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, + {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, + {BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, + {BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, + {BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, + {BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, + {BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, + {BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, + {BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, + {BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, + {BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, + {BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, + {BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, + {BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, + {BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, + {BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, + {BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, + {BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, + {BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, + {BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, + {BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, + {BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, + {BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, + {BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, + {BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, + {BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, + {BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, + {BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, + {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, + {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, + {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, + {BRCMS_SROM_CDDPO, 0x000000f0, 0, SROM4_CDDPO, 0xffff}, + {BRCMS_SROM_STBCPO, 0x000000f0, 0, SROM4_STBCPO, 0xffff}, + {BRCMS_SROM_BW40PO, 0x000000f0, 0, SROM4_BW40PO, 0xffff}, + {BRCMS_SROM_BWDUPPO, 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, + {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff}, + {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff}, + {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff}, + {BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, + + /* power per rate from sromrev 9 */ + {BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff}, + {BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, + {BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE, + SROM9_2GPO_LOFDMBW20, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, + {BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE, + SROM9_2GPO_LOFDMBW20UL, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, + {BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE, + SROM9_5GLPO_LOFDMBW20, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, + {BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE, + SROM9_5GLPO_LOFDMBW20UL, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, + {BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE, + SROM9_5GMPO_LOFDMBW20, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, + {BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE, + SROM9_5GMPO_LOFDMBW20UL, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, + {BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE, + SROM9_5GHPO_LOFDMBW20, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, + {BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE, + SROM9_5GHPO_LOFDMBW20UL, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, + {BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, + {BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, + {BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, + {BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, + {BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE, + SROM9_5GLPO_MCSBW20UL, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, + {BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, + {BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, + {BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE, + SROM9_5GMPO_MCSBW20UL, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, + {BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, + {BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, + {BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE, + SROM9_5GHPO_MCSBW20UL, 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, + {BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40, + 0xffff}, + {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, + {BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff}, + {BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff}, + + {BRCMS_SROM_NULL, 0, 0, 0, 0} +}; + +static const struct brcms_sromvar perpath_pci_sromvars[] = { + {BRCMS_SROM_MAXP2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, + {BRCMS_SROM_ITT2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, + {BRCMS_SROM_ITT5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, + {BRCMS_SROM_PA2GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, + {BRCMS_SROM_PA2GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff}, + {BRCMS_SROM_PA2GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff}, + {BRCMS_SROM_PA2GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff}, + {BRCMS_SROM_MAXP5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, + {BRCMS_SROM_MAXP5GHA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, + {BRCMS_SROM_MAXP5GLA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, + {BRCMS_SROM_PA5GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, + {BRCMS_SROM_PA5GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff}, + {BRCMS_SROM_PA5GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff}, + {BRCMS_SROM_PA5GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff}, + {BRCMS_SROM_PA5GLW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, + {BRCMS_SROM_PA5GLW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1, + 0xffff}, + {BRCMS_SROM_PA5GLW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2, + 0xffff}, + {BRCMS_SROM_PA5GLW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3, + 0xffff}, + {BRCMS_SROM_PA5GHW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, + {BRCMS_SROM_PA5GHW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1, + 0xffff}, + {BRCMS_SROM_PA5GHW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2, + 0xffff}, + {BRCMS_SROM_PA5GHW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3, + 0xffff}, + {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff}, + {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00}, + {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00}, + {BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, + {BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, + {BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, + {BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff}, + {BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff}, + {BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00}, + {BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, + {BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, + {BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, + {BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, + {BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1, + 0xffff}, + {BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2, + 0xffff}, + {BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, + {BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1, + 0xffff}, + {BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2, + 0xffff}, + {BRCMS_SROM_NULL, 0, 0, 0, 0} +}; + +/* crc table has the same contents for every device instance, so it can be + * shared between devices. */ +static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE]; + +static u16 __iomem * +srom_window_address(struct si_pub *sih, u8 __iomem *curmap) +{ + if (sih->ccrev < 32) + return (u16 __iomem *)(curmap + PCI_BAR0_SPROM_OFFSET); + if (sih->cccaps & CC_CAP_SROM) + return (u16 __iomem *) + (curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP); + + return NULL; +} + +/* Parse SROM and create name=value pairs. 'srom' points to + * the SROM word array. 'off' specifies the offset of the + * first word 'srom' points to, which should be either 0 or + * SROM3_SWRG_OFF (full SROM or software region). + */ + +static uint mask_shift(u16 mask) +{ + uint i; + for (i = 0; i < (sizeof(mask) << 3); i++) { + if (mask & (1 << i)) + return i; + } + return 0; +} + +static uint mask_width(u16 mask) +{ + int i; + for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) { + if (mask & (1 << i)) + return (uint) (i - mask_shift(mask) + 1); + } + return 0; +} + +static inline void ltoh16_buf(u16 *buf, unsigned int size) +{ + size /= 2; + while (size--) + *(buf + size) = le16_to_cpu(*(__le16 *)(buf + size)); +} + +static inline void htol16_buf(u16 *buf, unsigned int size) +{ + size /= 2; + while (size--) + *(__le16 *)(buf + size) = cpu_to_le16(*(buf + size)); +} + +/* + * convert binary srom data into linked list of srom variable items. + */ +static void +_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) +{ + struct brcms_srom_list_head *entry; + enum brcms_srom_id id; + u16 w; + u32 val; + const struct brcms_sromvar *srv; + uint width; + uint flags; + u32 sr = (1 << sromrev); + + /* first store the srom revision */ + entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL); + entry->varid = BRCMS_SROM_REV; + entry->var_type = BRCMS_SROM_UNUMBER; + entry->uval = sromrev; + list_add(&entry->var_list, var_list); + + for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) { + enum brcms_srom_var_type type; + u8 ea[ETH_ALEN]; + u8 extra_space = 0; + + if ((srv->revmask & sr) == 0) + continue; + + flags = srv->flags; + id = srv->varid; + + /* This entry is for mfgc only. Don't generate param for it, */ + if (flags & SRFL_NOVAR) + continue; + + if (flags & SRFL_ETHADDR) { + /* + * stored in string format XX:XX:XX:XX:XX:XX (17 chars) + */ + ea[0] = (srom[srv->off] >> 8) & 0xff; + ea[1] = srom[srv->off] & 0xff; + ea[2] = (srom[srv->off + 1] >> 8) & 0xff; + ea[3] = srom[srv->off + 1] & 0xff; + ea[4] = (srom[srv->off + 2] >> 8) & 0xff; + ea[5] = srom[srv->off + 2] & 0xff; + /* 17 characters + string terminator - union size */ + extra_space = 18 - sizeof(s32); + type = BRCMS_SROM_STRING; + } else { + w = srom[srv->off]; + val = (w & srv->mask) >> mask_shift(srv->mask); + width = mask_width(srv->mask); + + while (srv->flags & SRFL_MORE) { + srv++; + if (srv->off == 0) + continue; + + w = srom[srv->off]; + val += + ((w & srv->mask) >> mask_shift(srv-> + mask)) << + width; + width += mask_width(srv->mask); + } + + if ((flags & SRFL_NOFFS) + && ((int)val == (1 << width) - 1)) + continue; + + if (flags & SRFL_CCODE) { + type = BRCMS_SROM_STRING; + } else if (flags & SRFL_LEDDC) { + /* LED Powersave duty cycle has to be scaled: + *(oncount >> 24) (offcount >> 8) + */ + u32 w32 = /* oncount */ + (((val >> 8) & 0xff) << 24) | + /* offcount */ + (((val & 0xff)) << 8); + type = BRCMS_SROM_UNUMBER; + val = w32; + } else if ((flags & SRFL_PRSIGN) + && (val & (1 << (width - 1)))) { + type = BRCMS_SROM_SNUMBER; + val |= ~0 << width; + } else + type = BRCMS_SROM_UNUMBER; + } + + entry = kzalloc(sizeof(struct brcms_srom_list_head) + + extra_space, GFP_KERNEL); + entry->varid = id; + entry->var_type = type; + if (flags & SRFL_ETHADDR) { + snprintf(entry->buf, 18, "%pM", ea); + } else if (flags & SRFL_CCODE) { + if (val == 0) + entry->buf[0] = '\0'; + else + snprintf(entry->buf, 3, "%c%c", + (val >> 8), (val & 0xff)); + } else { + entry->uval = val; + } + + list_add(&entry->var_list, var_list); + } + + if (sromrev >= 4) { + /* Do per-path variables */ + uint p, pb, psz; + + if (sromrev >= 8) { + pb = SROM8_PATH0; + psz = SROM8_PATH1 - SROM8_PATH0; + } else { + pb = SROM4_PATH0; + psz = SROM4_PATH1 - SROM4_PATH0; + } + + for (p = 0; p < MAX_PATH_SROM; p++) { + for (srv = perpath_pci_sromvars; + srv->varid != BRCMS_SROM_NULL; srv++) { + if ((srv->revmask & sr) == 0) + continue; + + if (srv->flags & SRFL_NOVAR) + continue; + + w = srom[pb + srv->off]; + val = (w & srv->mask) >> mask_shift(srv->mask); + width = mask_width(srv->mask); + + /* Cheating: no per-path var is more than + * 1 word */ + if ((srv->flags & SRFL_NOFFS) + && ((int)val == (1 << width) - 1)) + continue; + + entry = + kzalloc(sizeof(struct brcms_srom_list_head), + GFP_KERNEL); + entry->varid = srv->varid+p; + entry->var_type = BRCMS_SROM_UNUMBER; + entry->uval = val; + list_add(&entry->var_list, var_list); + } + pb += psz; + } + } +} + +/* + * Read in and validate sprom. + * Return 0 on success, nonzero on error. + */ +static int +sprom_read_pci(struct si_pub *sih, u16 __iomem *sprom, uint wordoff, + u16 *buf, uint nwords, bool check_crc) +{ + int err = 0; + uint i; + + /* read the sprom */ + for (i = 0; i < nwords; i++) + buf[i] = R_REG(&sprom[wordoff + i]); + + if (check_crc) { + + if (buf[0] == 0xffff) + /* + * The hardware thinks that an srom that starts with + * 0xffff is blank, regardless of the rest of the + * content, so declare it bad. + */ + return -ENODATA; + + /* fixup the endianness so crc8 will pass */ + htol16_buf(buf, nwords * 2); + if (crc8(brcms_srom_crc8_table, (u8 *) buf, nwords * 2, + CRC8_INIT_VALUE) != + CRC8_GOOD_VALUE(brcms_srom_crc8_table)) + /* DBG only pci always read srom4 first, then srom8/9 */ + err = -EIO; + + /* now correct the endianness of the byte array */ + ltoh16_buf(buf, nwords * 2); + } + return err; +} + +static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz) +{ + u8 *otp; + uint sz = OTP_SZ_MAX / 2; /* size in words */ + int err = 0; + + otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC); + if (otp == NULL) + return -ENOMEM; + + err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz); + + memcpy(buf, otp, bufsz); + + kfree(otp); + + /* Check CRC */ + if (buf[0] == 0xffff) + /* The hardware thinks that an srom that starts with 0xffff + * is blank, regardless of the rest of the content, so declare + * it bad. + */ + return -ENODATA; + + /* fixup the endianness so crc8 will pass */ + htol16_buf(buf, bufsz); + if (crc8(brcms_srom_crc8_table, (u8 *) buf, SROM4_WORDS * 2, + CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table)) + err = -EIO; + + /* now correct the endianness of the byte array */ + ltoh16_buf(buf, bufsz); + + return err; +} + +/* + * Initialize nonvolatile variable table from sprom. + * Return 0 on success, nonzero on error. + */ +static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap) +{ + u16 *srom; + u16 __iomem *sromwindow; + u8 sromrev = 0; + u32 sr; + int err = 0; + + /* + * Apply CRC over SROM content regardless SROM is present or not. + */ + srom = kmalloc(SROM_MAX, GFP_ATOMIC); + if (!srom) + return -ENOMEM; + + sromwindow = srom_window_address(sih, curmap); + + crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY); + if (ai_is_sprom_available(sih)) { + err = sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS, + true); + + if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) || + (((sih->buscoretype == PCIE_CORE_ID) + && (sih->buscorerev >= 6)) + || ((sih->buscoretype == PCI_CORE_ID) + && (sih->buscorerev >= 0xe)))) { + /* sromrev >= 4, read more */ + err = sprom_read_pci(sih, sromwindow, 0, srom, + SROM4_WORDS, true); + sromrev = srom[SROM4_CRCREV] & 0xff; + } else if (err == 0) { + /* srom is good and is rev < 4 */ + /* top word of sprom contains version and crc8 */ + sromrev = srom[SROM_CRCREV] & 0xff; + /* bcm4401 sroms misprogrammed */ + if (sromrev == 0x10) + sromrev = 1; + } + } else { + /* Use OTP if SPROM not available */ + err = otp_read_pci(sih, srom, SROM_MAX); + if (err == 0) + /* OTP only contain SROM rev8/rev9 for now */ + sromrev = srom[SROM4_CRCREV] & 0xff; + } + + if (!err) { + struct si_info *sii = (struct si_info *)sih; + + /* Bitmask for the sromrev */ + sr = 1 << sromrev; + + /* + * srom version check: Current valid versions: 1, 2, 3, 4, 5, 8, + * 9 + */ + if ((sr & 0x33e) == 0) { + err = -EINVAL; + goto errout; + } + + INIT_LIST_HEAD(&sii->var_list); + + /* parse SROM into name=value pairs. */ + _initvars_srom_pci(sromrev, srom, &sii->var_list); + } + +errout: + kfree(srom); + return err; +} + +void srom_free_vars(struct si_pub *sih) +{ + struct si_info *sii; + struct brcms_srom_list_head *entry, *next; + + sii = (struct si_info *)sih; + list_for_each_entry_safe(entry, next, &sii->var_list, var_list) { + list_del(&entry->var_list); + kfree(entry); + } +} +/* + * Initialize local vars from the right source for this platform. + * Return 0 on success, nonzero on error. + */ +int srom_var_init(struct si_pub *sih, void __iomem *curmap) +{ + uint len; + + len = 0; + + if (curmap != NULL) + return initvars_srom_pci(sih, curmap); + + return -EINVAL; +} + +/* + * Search the name=value vars for a specific one and return its value. + * Returns NULL if not found. + */ +char *getvar(struct si_pub *sih, enum brcms_srom_id id) +{ + struct si_info *sii; + struct brcms_srom_list_head *entry; + + sii = (struct si_info *)sih; + + list_for_each_entry(entry, &sii->var_list, var_list) + if (entry->varid == id) + return &entry->buf[0]; + + /* nothing found */ + return NULL; +} + +/* + * Search the vars for a specific one and return its value as + * an integer. Returns 0 if not found.- + */ +int getintvar(struct si_pub *sih, enum brcms_srom_id id) +{ + struct si_info *sii; + struct brcms_srom_list_head *entry; + unsigned long res; + + sii = (struct si_info *)sih; + + list_for_each_entry(entry, &sii->var_list, var_list) + if (entry->varid == id) { + if (entry->var_type == BRCMS_SROM_SNUMBER || + entry->var_type == BRCMS_SROM_UNUMBER) + return (int)entry->sval; + else if (!kstrtoul(&entry->buf[0], 0, &res)) + return (int)res; + } + + return 0; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.h b/drivers/net/wireless/brcm80211/brcmsmac/srom.h new file mode 100644 index 000000000000..708c43ff51cc --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/srom.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_SROM_H_ +#define _BRCM_SROM_H_ + +#include "types.h" + +/* Prototypes */ +extern int srom_var_init(struct si_pub *sih, void __iomem *curmap); +extern void srom_free_vars(struct si_pub *sih); + +extern int srom_read(struct si_pub *sih, uint bus, void *curmap, + uint byteoff, uint nbytes, u16 *buf, bool check_crc); + +/* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP + * and extract from it into name=value pairs + */ +extern int srom_parsecis(u8 **pcis, uint ciscnt, + char **vars, uint *count); +#endif /* _BRCM_SROM_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/stf.c b/drivers/net/wireless/brcm80211/brcmsmac/stf.c new file mode 100644 index 000000000000..d8f528eb180c --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/stf.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 <net/mac80211.h> + +#include "types.h" +#include "d11.h" +#include "rate.h" +#include "phy/phy_hal.h" +#include "channel.h" +#include "main.h" +#include "stf.h" + +#define MIN_SPATIAL_EXPANSION 0 +#define MAX_SPATIAL_EXPANSION 1 + +#define BRCMS_STF_SS_STBC_RX(wlc) (BRCMS_ISNPHY(wlc->band) && \ + NREV_GT(wlc->band->phyrev, 3) && NREV_LE(wlc->band->phyrev, 6)) + +#define NSTS_1 1 +#define NSTS_2 2 +#define NSTS_3 3 +#define NSTS_4 4 + +static const u8 txcore_default[5] = { + (0), /* bitmap of the core enabled */ + (0x01), /* For Nsts = 1, enable core 1 */ + (0x03), /* For Nsts = 2, enable core 1 & 2 */ + (0x07), /* For Nsts = 3, enable core 1, 2 & 3 */ + (0x0f) /* For Nsts = 4, enable all cores */ +}; + +static void brcms_c_stf_stbc_rx_ht_update(struct brcms_c_info *wlc, int val) +{ + /* MIMOPHYs rev3-6 cannot receive STBC with only one rx core active */ + if (BRCMS_STF_SS_STBC_RX(wlc)) { + if ((wlc->stf->rxstreams == 1) && (val != HT_CAP_RX_STBC_NO)) + return; + } + + if (wlc->pub->up) { + brcms_c_update_beacon(wlc); + brcms_c_update_probe_resp(wlc, true); + } +} + +/* + * every WLC_TEMPSENSE_PERIOD seconds temperature check to decide whether to + * turn on/off txchain. + */ +void brcms_c_tempsense_upd(struct brcms_c_info *wlc) +{ + struct brcms_phy_pub *pi = wlc->band->pi; + uint active_chains, txchain; + + /* Check if the chip is too hot. Disable one Tx chain, if it is */ + /* high 4 bits are for Rx chain, low 4 bits are for Tx chain */ + active_chains = wlc_phy_stf_chain_active_get(pi); + txchain = active_chains & 0xf; + + if (wlc->stf->txchain == wlc->stf->hw_txchain) { + if (txchain && (txchain < wlc->stf->hw_txchain)) + /* turn off 1 tx chain */ + brcms_c_stf_txchain_set(wlc, txchain, true); + } else if (wlc->stf->txchain < wlc->stf->hw_txchain) { + if (txchain == wlc->stf->hw_txchain) + /* turn back on txchain */ + brcms_c_stf_txchain_set(wlc, txchain, true); + } +} + +void +brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, u16 *ss_algo_channel, + u16 chanspec) +{ + struct tx_power power; + u8 siso_mcs_id, cdd_mcs_id, stbc_mcs_id; + + /* Clear previous settings */ + *ss_algo_channel = 0; + + if (!wlc->pub->up) { + *ss_algo_channel = (u16) -1; + return; + } + + wlc_phy_txpower_get_current(wlc->band->pi, &power, + CHSPEC_CHANNEL(chanspec)); + + siso_mcs_id = (CHSPEC_IS40(chanspec)) ? + WL_TX_POWER_MCS40_SISO_FIRST : WL_TX_POWER_MCS20_SISO_FIRST; + cdd_mcs_id = (CHSPEC_IS40(chanspec)) ? + WL_TX_POWER_MCS40_CDD_FIRST : WL_TX_POWER_MCS20_CDD_FIRST; + stbc_mcs_id = (CHSPEC_IS40(chanspec)) ? + WL_TX_POWER_MCS40_STBC_FIRST : WL_TX_POWER_MCS20_STBC_FIRST; + + /* criteria to choose stf mode */ + + /* + * the "+3dbm (12 0.25db units)" is to account for the fact that with + * CDD, tx occurs on both chains + */ + if (power.target[siso_mcs_id] > (power.target[cdd_mcs_id] + 12)) + setbit(ss_algo_channel, PHY_TXC1_MODE_SISO); + else + setbit(ss_algo_channel, PHY_TXC1_MODE_CDD); + + /* + * STBC is ORed into to algo channel as STBC requires per-packet SCB + * capability check so cannot be default mode of operation. One of + * SISO, CDD have to be set + */ + if (power.target[siso_mcs_id] <= (power.target[stbc_mcs_id] + 12)) + setbit(ss_algo_channel, PHY_TXC1_MODE_STBC); +} + +static bool brcms_c_stf_stbc_tx_set(struct brcms_c_info *wlc, s32 int_val) +{ + if ((int_val != AUTO) && (int_val != OFF) && (int_val != ON)) + return false; + + if ((int_val == ON) && (wlc->stf->txstreams == 1)) + return false; + + wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = (s8) int_val; + wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = (s8) int_val; + + return true; +} + +bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val) +{ + if ((int_val != HT_CAP_RX_STBC_NO) + && (int_val != HT_CAP_RX_STBC_ONE_STREAM)) + return false; + + if (BRCMS_STF_SS_STBC_RX(wlc)) { + if ((int_val != HT_CAP_RX_STBC_NO) + && (wlc->stf->rxstreams == 1)) + return false; + } + + brcms_c_stf_stbc_rx_ht_update(wlc, int_val); + return true; +} + +static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts, + u8 core_mask) +{ + BCMMSG(wlc->wiphy, "wl%d: Nsts %d core_mask %x\n", + wlc->pub->unit, Nsts, core_mask); + + if (hweight8(core_mask) > wlc->stf->txstreams) + core_mask = 0; + + if ((hweight8(core_mask) == wlc->stf->txstreams) && + ((core_mask & ~wlc->stf->txchain) + || !(core_mask & wlc->stf->txchain))) + core_mask = wlc->stf->txchain; + + wlc->stf->txcore[Nsts] = core_mask; + /* Nsts = 1..4, txcore index = 1..4 */ + if (Nsts == 1) { + /* Needs to update beacon and ucode generated response + * frames when 1 stream core map changed + */ + wlc->stf->phytxant = core_mask << PHY_TXC_ANT_SHIFT; + brcms_b_txant_set(wlc->hw, wlc->stf->phytxant); + if (wlc->clk) { + brcms_c_suspend_mac_and_wait(wlc); + brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec); + brcms_c_enable_mac(wlc); + } + } + + return 0; +} + +static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val) +{ + int i; + u8 core_mask = 0; + + BCMMSG(wlc->wiphy, "wl%d: val %x\n", wlc->pub->unit, val); + + wlc->stf->spatial_policy = (s8) val; + for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) { + core_mask = (val == MAX_SPATIAL_EXPANSION) ? + wlc->stf->txchain : txcore_default[i]; + brcms_c_stf_txcore_set(wlc, (u8) i, core_mask); + } + return 0; +} + +/* + * Centralized txant update function. call it whenever wlc->stf->txant and/or + * wlc->stf->txchain change. + * + * Antennas are controlled by ucode indirectly, which drives PHY or GPIO to + * achieve various tx/rx antenna selection schemes + * + * legacy phy, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 + * means auto(last rx). + * for NREV<3, bit 6 and bit 7 means antenna 0 and 1 respectively, bit6+bit7 + * means last rx and do tx-antenna selection for SISO transmissions + * for NREV=3, bit 6 and bit _8_ means antenna 0 and 1 respectively, bit6+bit7 + * means last rx and do tx-antenna selection for SISO transmissions + * for NREV>=7, bit 6 and bit 7 mean antenna 0 and 1 respectively, nit6+bit7 + * means both cores active +*/ +static void _brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc) +{ + s8 txant; + + txant = (s8) wlc->stf->txant; + if (BRCMS_PHY_11N_CAP(wlc->band)) { + if (txant == ANT_TX_FORCE_0) { + wlc->stf->phytxant = PHY_TXC_ANT_0; + } else if (txant == ANT_TX_FORCE_1) { + wlc->stf->phytxant = PHY_TXC_ANT_1; + + if (BRCMS_ISNPHY(wlc->band) && + NREV_GE(wlc->band->phyrev, 3) + && NREV_LT(wlc->band->phyrev, 7)) + wlc->stf->phytxant = PHY_TXC_ANT_2; + } else { + if (BRCMS_ISLCNPHY(wlc->band) || + BRCMS_ISSSLPNPHY(wlc->band)) + wlc->stf->phytxant = PHY_TXC_LCNPHY_ANT_LAST; + else { + /* catch out of sync wlc->stf->txcore */ + WARN_ON(wlc->stf->txchain <= 0); + wlc->stf->phytxant = + wlc->stf->txchain << PHY_TXC_ANT_SHIFT; + } + } + } else { + if (txant == ANT_TX_FORCE_0) + wlc->stf->phytxant = PHY_TXC_OLD_ANT_0; + else if (txant == ANT_TX_FORCE_1) + wlc->stf->phytxant = PHY_TXC_OLD_ANT_1; + else + wlc->stf->phytxant = PHY_TXC_OLD_ANT_LAST; + } + + brcms_b_txant_set(wlc->hw, wlc->stf->phytxant); +} + +int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, bool force) +{ + u8 txchain = (u8) int_val; + u8 txstreams; + uint i; + + if (wlc->stf->txchain == txchain) + return 0; + + if ((txchain & ~wlc->stf->hw_txchain) + || !(txchain & wlc->stf->hw_txchain)) + return -EINVAL; + + /* + * if nrate override is configured to be non-SISO STF mode, reject + * reducing txchain to 1 + */ + txstreams = (u8) hweight8(txchain); + if (txstreams > MAX_STREAMS_SUPPORTED) + return -EINVAL; + + wlc->stf->txchain = txchain; + wlc->stf->txstreams = txstreams; + brcms_c_stf_stbc_tx_set(wlc, wlc->band->band_stf_stbc_tx); + brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); + brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); + wlc->stf->txant = + (wlc->stf->txstreams == 1) ? ANT_TX_FORCE_0 : ANT_TX_DEF; + _brcms_c_stf_phy_txant_upd(wlc); + + wlc_phy_stf_chain_set(wlc->band->pi, wlc->stf->txchain, + wlc->stf->rxchain); + + for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) + brcms_c_stf_txcore_set(wlc, (u8) i, txcore_default[i]); + + return 0; +} + +/* + * update wlc->stf->ss_opmode which represents the operational stf_ss mode + * we're using + */ +int brcms_c_stf_ss_update(struct brcms_c_info *wlc, struct brcms_band *band) +{ + int ret_code = 0; + u8 prev_stf_ss; + u8 upd_stf_ss; + + prev_stf_ss = wlc->stf->ss_opmode; + + /* + * NOTE: opmode can only be SISO or CDD as STBC is decided on a + * per-packet basis + */ + if (BRCMS_STBC_CAP_PHY(wlc) && + wlc->stf->ss_algosel_auto + && (wlc->stf->ss_algo_channel != (u16) -1)) { + upd_stf_ss = (wlc->stf->txstreams == 1 || + isset(&wlc->stf->ss_algo_channel, + PHY_TXC1_MODE_SISO)) ? + PHY_TXC1_MODE_SISO : PHY_TXC1_MODE_CDD; + } else { + if (wlc->band != band) + return ret_code; + upd_stf_ss = (wlc->stf->txstreams == 1) ? + PHY_TXC1_MODE_SISO : band->band_stf_ss_mode; + } + if (prev_stf_ss != upd_stf_ss) { + wlc->stf->ss_opmode = upd_stf_ss; + brcms_b_band_stf_ss_set(wlc->hw, upd_stf_ss); + } + + return ret_code; +} + +int brcms_c_stf_attach(struct brcms_c_info *wlc) +{ + wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_SISO; + wlc->bandstate[BAND_5G_INDEX]->band_stf_ss_mode = PHY_TXC1_MODE_CDD; + + if (BRCMS_ISNPHY(wlc->band) && + (wlc_phy_txpower_hw_ctrl_get(wlc->band->pi) != PHY_TPC_HW_ON)) + wlc->bandstate[BAND_2G_INDEX]->band_stf_ss_mode = + PHY_TXC1_MODE_CDD; + brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); + brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); + + brcms_c_stf_stbc_rx_ht_update(wlc, HT_CAP_RX_STBC_NO); + wlc->bandstate[BAND_2G_INDEX]->band_stf_stbc_tx = OFF; + wlc->bandstate[BAND_5G_INDEX]->band_stf_stbc_tx = OFF; + + if (BRCMS_STBC_CAP_PHY(wlc)) { + wlc->stf->ss_algosel_auto = true; + /* Init the default value */ + wlc->stf->ss_algo_channel = (u16) -1; + } + return 0; +} + +void brcms_c_stf_detach(struct brcms_c_info *wlc) +{ +} + +void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc) +{ + _brcms_c_stf_phy_txant_upd(wlc); +} + +void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc) +{ + /* get available rx/tx chains */ + wlc->stf->hw_txchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_TXCHAIN); + wlc->stf->hw_rxchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_RXCHAIN); + + /* these parameter are intended to be used for all PHY types */ + if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) { + if (BRCMS_ISNPHY(wlc->band)) + wlc->stf->hw_txchain = TXCHAIN_DEF_NPHY; + else + wlc->stf->hw_txchain = TXCHAIN_DEF; + } + + wlc->stf->txchain = wlc->stf->hw_txchain; + wlc->stf->txstreams = (u8) hweight8(wlc->stf->hw_txchain); + + if (wlc->stf->hw_rxchain == 0 || wlc->stf->hw_rxchain == 0xf) { + if (BRCMS_ISNPHY(wlc->band)) + wlc->stf->hw_rxchain = RXCHAIN_DEF_NPHY; + else + wlc->stf->hw_rxchain = RXCHAIN_DEF; + } + + wlc->stf->rxchain = wlc->stf->hw_rxchain; + wlc->stf->rxstreams = (u8) hweight8(wlc->stf->hw_rxchain); + + /* initialize the txcore table */ + memcpy(wlc->stf->txcore, txcore_default, sizeof(wlc->stf->txcore)); + + /* default spatial_policy */ + wlc->stf->spatial_policy = MIN_SPATIAL_EXPANSION; + brcms_c_stf_spatial_policy_set(wlc, MIN_SPATIAL_EXPANSION); +} + +static u16 _brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, + u32 rspec) +{ + u16 phytxant = wlc->stf->phytxant; + + if (rspec_stf(rspec) != PHY_TXC1_MODE_SISO) + phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT; + else if (wlc->stf->txant == ANT_TX_DEF) + phytxant = wlc->stf->txchain << PHY_TXC_ANT_SHIFT; + phytxant &= PHY_TXC_ANT_MASK; + return phytxant; +} + +u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, u32 rspec) +{ + return _brcms_c_stf_phytxchain_sel(wlc, rspec); +} + +u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, u32 rspec) +{ + u16 phytxant = wlc->stf->phytxant; + u16 mask = PHY_TXC_ANT_MASK; + + /* for non-siso rates or default setting, use the available chains */ + if (BRCMS_ISNPHY(wlc->band)) { + phytxant = _brcms_c_stf_phytxchain_sel(wlc, rspec); + mask = PHY_TXC_HTANT_MASK; + } + phytxant |= phytxant & mask; + return phytxant; +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/stf.h b/drivers/net/wireless/brcm80211/brcmsmac/stf.h new file mode 100644 index 000000000000..19f6580f69be --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/stf.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_STF_H_ +#define _BRCM_STF_H_ + +#include "types.h" + +extern int brcms_c_stf_attach(struct brcms_c_info *wlc); +extern void brcms_c_stf_detach(struct brcms_c_info *wlc); + +extern void brcms_c_tempsense_upd(struct brcms_c_info *wlc); +extern void brcms_c_stf_ss_algo_channel_get(struct brcms_c_info *wlc, + u16 *ss_algo_channel, + u16 chanspec); +extern int brcms_c_stf_ss_update(struct brcms_c_info *wlc, + struct brcms_band *band); +extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); +extern int brcms_c_stf_txchain_set(struct brcms_c_info *wlc, s32 int_val, + bool force); +extern bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val); +extern void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc); +extern void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc); +extern u16 brcms_c_stf_phytxchain_sel(struct brcms_c_info *wlc, + u32 rspec); +extern u16 brcms_c_stf_d11hdrs_phyctl_txant(struct brcms_c_info *wlc, + u32 rspec); + +#endif /* _BRCM_STF_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/types.h b/drivers/net/wireless/brcm80211/brcmsmac/types.h new file mode 100644 index 000000000000..27a814b07462 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/types.h @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_TYPES_H_ +#define _BRCM_TYPES_H_ + +#include <linux/types.h> +#include <linux/io.h> + +#define WL_CHAN_FREQ_RANGE_2G 0 +#define WL_CHAN_FREQ_RANGE_5GL 1 +#define WL_CHAN_FREQ_RANGE_5GM 2 +#define WL_CHAN_FREQ_RANGE_5GH 3 + +/* boardflags */ + +/* Board has gpio 9 controlling the PA */ +#define BFL_PACTRL 0x00000002 +/* Not ok to power down the chip pll and oscillator */ +#define BFL_NOPLLDOWN 0x00000020 +/* Board supports the Front End Module */ +#define BFL_FEM 0x00000800 +/* Board has an external LNA in 2.4GHz band */ +#define BFL_EXTLNA 0x00001000 +/* Board has no PA */ +#define BFL_NOPA 0x00010000 +/* Power topology uses BUCKBOOST */ +#define BFL_BUCKBOOST 0x00200000 +/* Board has FEM and switch to share antenna w/ BT */ +#define BFL_FEM_BT 0x00400000 +/* Power topology doesn't use CBUCK */ +#define BFL_NOCBUCK 0x00800000 +/* Power topology uses PALDO */ +#define BFL_PALDO 0x02000000 +/* Board has an external LNA in 5GHz band */ +#define BFL_EXTLNA_5GHz 0x10000000 + +/* boardflags2 */ + +/* Board has an external rxbb regulator */ +#define BFL2_RXBB_INT_REG_DIS 0x00000001 +/* Flag to implement alternative A-band PLL settings */ +#define BFL2_APLL_WAR 0x00000002 +/* Board permits enabling TX Power Control */ +#define BFL2_TXPWRCTRL_EN 0x00000004 +/* Board supports the 2X4 diversity switch */ +#define BFL2_2X4_DIV 0x00000008 +/* Board supports 5G band power gain */ +#define BFL2_5G_PWRGAIN 0x00000010 +/* Board overrides ASPM and Clkreq settings */ +#define BFL2_PCIEWAR_OVR 0x00000020 +#define BFL2_LEGACY 0x00000080 +/* 4321mcm93 board uses Skyworks FEM */ +#define BFL2_SKWRKFEM_BRD 0x00000100 +/* Board has a WAR for clock-harmonic spurs */ +#define BFL2_SPUR_WAR 0x00000200 +/* Flag to narrow G-band PLL loop b/w */ +#define BFL2_GPLL_WAR 0x00000400 +/* Tx CCK pkts on Ant 0 only */ +#define BFL2_SINGLEANT_CCK 0x00001000 +/* WAR to reduce and avoid clock-harmonic spurs in 2G */ +#define BFL2_2G_SPUR_WAR 0x00002000 +/* Flag to widen G-band PLL loop b/w */ +#define BFL2_GPLL_WAR2 0x00010000 +#define BFL2_IPALVLSHIFT_3P3 0x00020000 +/* Use internal envelope detector for TX IQCAL */ +#define BFL2_INTERNDET_TXIQCAL 0x00040000 +/* Keep the buffered Xtal output from radio "ON". Most drivers will turn it + * off without this flag to save power. */ +#define BFL2_XTALBUFOUTEN 0x00080000 + +/* + * board specific GPIO assignment, gpio 0-3 are also customer-configurable + * led + */ + +/* bit 9 controls the PA on new 4306 boards */ +#define BOARD_GPIO_PACTRL 0x200 +#define BOARD_GPIO_12 0x1000 +#define BOARD_GPIO_13 0x2000 + +/* **** Core type/rev defaults **** */ +#define D11CONF 0x0fffffb0 /* Supported D11 revs: 4, 5, 7-27 + * also need to update wlc.h MAXCOREREV + */ + +#define NCONF 0x000001ff /* Supported nphy revs: + * 0 4321a0 + * 1 4321a1 + * 2 4321b0/b1/c0/c1 + * 3 4322a0 + * 4 4322a1 + * 5 4716a0 + * 6 43222a0, 43224a0 + * 7 43226a0 + * 8 5357a0, 43236a0 + */ + +#define LCNCONF 0x00000007 /* Supported lcnphy revs: + * 0 4313a0, 4336a0, 4330a0 + * 1 + * 2 4330a0 + */ + +#define SSLPNCONF 0x0000000f /* Supported sslpnphy revs: + * 0 4329a0/k0 + * 1 4329b0/4329C0 + * 2 4319a0 + * 3 5356a0 + */ + +/******************************************************************** + * Phy/Core Configuration. Defines macros to to check core phy/rev * + * compile-time configuration. Defines default core support. * + * ****************************************************************** + */ + +/* Basic macros to check a configuration bitmask */ + +#define CONF_HAS(config, val) ((config) & (1 << (val))) +#define CONF_MSK(config, mask) ((config) & (mask)) +#define MSK_RANGE(low, hi) ((1 << ((hi)+1)) - (1 << (low))) +#define CONF_RANGE(config, low, hi) (CONF_MSK(config, MSK_RANGE(low, high))) + +#define CONF_IS(config, val) ((config) == (1 << (val))) +#define CONF_GE(config, val) ((config) & (0-(1 << (val)))) +#define CONF_GT(config, val) ((config) & (0-2*(1 << (val)))) +#define CONF_LT(config, val) ((config) & ((1 << (val))-1)) +#define CONF_LE(config, val) ((config) & (2*(1 << (val))-1)) + +/* Wrappers for some of the above, specific to config constants */ + +#define NCONF_HAS(val) CONF_HAS(NCONF, val) +#define NCONF_MSK(mask) CONF_MSK(NCONF, mask) +#define NCONF_IS(val) CONF_IS(NCONF, val) +#define NCONF_GE(val) CONF_GE(NCONF, val) +#define NCONF_GT(val) CONF_GT(NCONF, val) +#define NCONF_LT(val) CONF_LT(NCONF, val) +#define NCONF_LE(val) CONF_LE(NCONF, val) + +#define LCNCONF_HAS(val) CONF_HAS(LCNCONF, val) +#define LCNCONF_MSK(mask) CONF_MSK(LCNCONF, mask) +#define LCNCONF_IS(val) CONF_IS(LCNCONF, val) +#define LCNCONF_GE(val) CONF_GE(LCNCONF, val) +#define LCNCONF_GT(val) CONF_GT(LCNCONF, val) +#define LCNCONF_LT(val) CONF_LT(LCNCONF, val) +#define LCNCONF_LE(val) CONF_LE(LCNCONF, val) + +#define D11CONF_HAS(val) CONF_HAS(D11CONF, val) +#define D11CONF_MSK(mask) CONF_MSK(D11CONF, mask) +#define D11CONF_IS(val) CONF_IS(D11CONF, val) +#define D11CONF_GE(val) CONF_GE(D11CONF, val) +#define D11CONF_GT(val) CONF_GT(D11CONF, val) +#define D11CONF_LT(val) CONF_LT(D11CONF, val) +#define D11CONF_LE(val) CONF_LE(D11CONF, val) + +#define PHYCONF_HAS(val) CONF_HAS(PHYTYPE, val) +#define PHYCONF_IS(val) CONF_IS(PHYTYPE, val) + +#define NREV_IS(var, val) \ + (NCONF_HAS(val) && (NCONF_IS(val) || ((var) == (val)))) + +#define NREV_GE(var, val) \ + (NCONF_GE(val) && (!NCONF_LT(val) || ((var) >= (val)))) + +#define NREV_GT(var, val) \ + (NCONF_GT(val) && (!NCONF_LE(val) || ((var) > (val)))) + +#define NREV_LT(var, val) \ + (NCONF_LT(val) && (!NCONF_GE(val) || ((var) < (val)))) + +#define NREV_LE(var, val) \ + (NCONF_LE(val) && (!NCONF_GT(val) || ((var) <= (val)))) + +#define LCNREV_IS(var, val) \ + (LCNCONF_HAS(val) && (LCNCONF_IS(val) || ((var) == (val)))) + +#define LCNREV_GE(var, val) \ + (LCNCONF_GE(val) && (!LCNCONF_LT(val) || ((var) >= (val)))) + +#define LCNREV_GT(var, val) \ + (LCNCONF_GT(val) && (!LCNCONF_LE(val) || ((var) > (val)))) + +#define LCNREV_LT(var, val) \ + (LCNCONF_LT(val) && (!LCNCONF_GE(val) || ((var) < (val)))) + +#define LCNREV_LE(var, val) \ + (LCNCONF_LE(val) && (!LCNCONF_GT(val) || ((var) <= (val)))) + +#define D11REV_IS(var, val) \ + (D11CONF_HAS(val) && (D11CONF_IS(val) || ((var) == (val)))) + +#define D11REV_GE(var, val) \ + (D11CONF_GE(val) && (!D11CONF_LT(val) || ((var) >= (val)))) + +#define D11REV_GT(var, val) \ + (D11CONF_GT(val) && (!D11CONF_LE(val) || ((var) > (val)))) + +#define D11REV_LT(var, val) \ + (D11CONF_LT(val) && (!D11CONF_GE(val) || ((var) < (val)))) + +#define D11REV_LE(var, val) \ + (D11CONF_LE(val) && (!D11CONF_GT(val) || ((var) <= (val)))) + +#define PHYTYPE_IS(var, val)\ + (PHYCONF_HAS(val) && (PHYCONF_IS(val) || ((var) == (val)))) + +/* Set up PHYTYPE automatically: (depends on PHY_TYPE_X, from d11.h) */ + +#define _PHYCONF_N (1 << PHY_TYPE_N) +#define _PHYCONF_LCN (1 << PHY_TYPE_LCN) +#define _PHYCONF_SSLPN (1 << PHY_TYPE_SSN) + +#define PHYTYPE (_PHYCONF_N | _PHYCONF_LCN | _PHYCONF_SSLPN) + +/* Utility macro to identify 802.11n (HT) capable PHYs */ +#define PHYTYPE_11N_CAP(phytype) \ + (PHYTYPE_IS(phytype, PHY_TYPE_N) || \ + PHYTYPE_IS(phytype, PHY_TYPE_LCN) || \ + PHYTYPE_IS(phytype, PHY_TYPE_SSN)) + +/* Last but not least: shorter wlc-specific var checks */ +#define BRCMS_ISNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_N) +#define BRCMS_ISLCNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_LCN) +#define BRCMS_ISSSLPNPHY(band) PHYTYPE_IS((band)->phytype, PHY_TYPE_SSN) + +#define BRCMS_PHY_11N_CAP(band) PHYTYPE_11N_CAP((band)->phytype) + +/********************************************************************** + * ------------- End of Core phy/rev configuration. ----------------- * + * ******************************************************************** + */ + +#define BCMMSG(dev, fmt, args...) \ +do { \ + if (brcm_msg_level & LOG_TRACE_VAL) \ + wiphy_err(dev, "%s: " fmt, __func__, ##args); \ +} while (0) + +/* + * Register access macros. + * + * These macro's take a pointer to the address to read as one of their + * arguments. The macro itself deduces the size of the IO transaction (u8, u16 + * or u32). Advantage of this approach in combination with using a struct to + * define the registers in a register block, is that access size and access + * location are defined in only one spot. This reduces the risk of the + * programmer trying to use an unsupported transaction size on a register. + * + */ + +#define R_REG(r) \ + ({ \ + __typeof(*(r)) __osl_v; \ + switch (sizeof(*(r))) { \ + case sizeof(u8): \ + __osl_v = readb((u8 __iomem *)(r)); \ + break; \ + case sizeof(u16): \ + __osl_v = readw((u16 __iomem *)(r)); \ + break; \ + case sizeof(u32): \ + __osl_v = readl((u32 __iomem *)(r)); \ + break; \ + } \ + __osl_v; \ + }) + +#define W_REG(r, v) do { \ + switch (sizeof(*(r))) { \ + case sizeof(u8): \ + writeb((u8)((v) & 0xFF), (u8 __iomem *)(r)); \ + break; \ + case sizeof(u16): \ + writew((u16)((v) & 0xFFFF), (u16 __iomem *)(r)); \ + break; \ + case sizeof(u32): \ + writel((u32)(v), (u32 __iomem *)(r)); \ + break; \ + } \ + } while (0) + +#ifdef CONFIG_BCM47XX +/* + * bcm4716 (which includes 4717 & 4718), plus 4706 on PCIe can reorder + * transactions. As a fix, a read after write is performed on certain places + * in the code. Older chips and the newer 5357 family don't require this fix. + */ +#define W_REG_FLUSH(r, v) ({ W_REG((r), (v)); (void)R_REG(r); }) +#else +#define W_REG_FLUSH(r, v) W_REG((r), (v)) +#endif /* CONFIG_BCM47XX */ + +#define AND_REG(r, v) W_REG((r), R_REG(r) & (v)) +#define OR_REG(r, v) W_REG((r), R_REG(r) | (v)) + +#define SET_REG(r, mask, val) \ + W_REG((r), ((R_REG(r) & ~(mask)) | (val))) + +/* multi-bool data type: set of bools, mbool is true if any is set */ + +/* set one bool */ +#define mboolset(mb, bit) ((mb) |= (bit)) +/* clear one bool */ +#define mboolclr(mb, bit) ((mb) &= ~(bit)) +/* true if one bool is set */ +#define mboolisset(mb, bit) (((mb) & (bit)) != 0) +#define mboolmaskset(mb, mask, val) ((mb) = (((mb) & ~(mask)) | (val))) + +#define CEIL(x, y) (((x) + ((y)-1)) / (y)) + +/* forward declarations */ +struct wiphy; +struct ieee80211_sta; +struct ieee80211_tx_queue_params; +struct brcms_info; +struct brcms_c_info; +struct brcms_hardware; +struct brcms_txq_info; +struct brcms_band; +struct dma_pub; +struct si_pub; +struct tx_status; +struct d11rxhdr; +struct txpwr_limits; + +/* iovar structure */ +struct brcmu_iovar { + const char *name; /* name for lookup and display */ + u16 varid; /* id for switch */ + u16 flags; /* driver-specific flag bits */ + u16 type; /* base type of argument */ + u16 minlen; /* min length for buffer vars */ +}; + +/* brcm_msg_level is a bit vector with defs in defs.h */ +extern u32 brcm_msg_level; + +#endif /* _BRCM_TYPES_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c new file mode 100644 index 000000000000..80e3ccf865e3 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 <defs.h> +#include "types.h" +#include <ucode_loader.h> + +enum { + D11UCODE_NAMETAG_START = 0, + D11LCN0BSINITVALS24, + D11LCN0INITVALS24, + D11LCN1BSINITVALS24, + D11LCN1INITVALS24, + D11LCN2BSINITVALS24, + D11LCN2INITVALS24, + D11N0ABSINITVALS16, + D11N0BSINITVALS16, + D11N0INITVALS16, + D11UCODE_OVERSIGHT16_MIMO, + D11UCODE_OVERSIGHT16_MIMOSZ, + D11UCODE_OVERSIGHT24_LCN, + D11UCODE_OVERSIGHT24_LCNSZ, + D11UCODE_OVERSIGHT_BOMMAJOR, + D11UCODE_OVERSIGHT_BOMMINOR +}; + +int brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode) +{ + int rc; + + rc = brcms_check_firmwares(wl); + + rc = rc < 0 ? rc : + brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn0bsinitvals24, + D11LCN0BSINITVALS24); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn0initvals24, + D11LCN0INITVALS24); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn1bsinitvals24, + D11LCN1BSINITVALS24); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn1initvals24, + D11LCN1INITVALS24); + rc = rc < 0 ? rc : + brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn2bsinitvals24, + D11LCN2BSINITVALS24); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11lcn2initvals24, + D11LCN2INITVALS24); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0absinitvals16, + D11N0ABSINITVALS16); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0bsinitvals16, + D11N0BSINITVALS16); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->d11n0initvals16, + D11N0INITVALS16); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_16_mimo, + D11UCODE_OVERSIGHT16_MIMO); + rc = rc < 0 ? + rc : brcms_ucode_init_uint(wl, &ucode->bcm43xx_16_mimosz, + D11UCODE_OVERSIGHT16_MIMOSZ); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_24_lcn, + D11UCODE_OVERSIGHT24_LCN); + rc = rc < 0 ? + rc : brcms_ucode_init_uint(wl, &ucode->bcm43xx_24_lcnsz, + D11UCODE_OVERSIGHT24_LCNSZ); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_bommajor, + D11UCODE_OVERSIGHT_BOMMAJOR); + rc = rc < 0 ? + rc : brcms_ucode_init_buf(wl, (void **)&ucode->bcm43xx_bomminor, + D11UCODE_OVERSIGHT_BOMMINOR); + return rc; +} + +void brcms_ucode_data_free(struct brcms_ucode *ucode) +{ + brcms_ucode_free_buf((void *)ucode->d11lcn0bsinitvals24); + brcms_ucode_free_buf((void *)ucode->d11lcn0initvals24); + brcms_ucode_free_buf((void *)ucode->d11lcn1bsinitvals24); + brcms_ucode_free_buf((void *)ucode->d11lcn1initvals24); + brcms_ucode_free_buf((void *)ucode->d11lcn2bsinitvals24); + brcms_ucode_free_buf((void *)ucode->d11lcn2initvals24); + brcms_ucode_free_buf((void *)ucode->d11n0absinitvals16); + brcms_ucode_free_buf((void *)ucode->d11n0bsinitvals16); + brcms_ucode_free_buf((void *)ucode->d11n0initvals16); + brcms_ucode_free_buf((void *)ucode->bcm43xx_16_mimo); + brcms_ucode_free_buf((void *)ucode->bcm43xx_24_lcn); + brcms_ucode_free_buf((void *)ucode->bcm43xx_bommajor); + brcms_ucode_free_buf((void *)ucode->bcm43xx_bomminor); +} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h new file mode 100644 index 000000000000..18750a814b4f --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmsmac/ucode_loader.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_UCODE_H_ +#define _BRCM_UCODE_H_ + +#include "types.h" /* forward structure declarations */ + +#define MIN_FW_SIZE 40000 /* minimum firmware file size in bytes */ +#define MAX_FW_SIZE 150000 + +#define UCODE_LOADER_API_VER 0 + +struct d11init; + +struct brcms_ucode { + struct d11init *d11lcn0bsinitvals24; + struct d11init *d11lcn0initvals24; + struct d11init *d11lcn1bsinitvals24; + struct d11init *d11lcn1initvals24; + struct d11init *d11lcn2bsinitvals24; + struct d11init *d11lcn2initvals24; + struct d11init *d11n0absinitvals16; + struct d11init *d11n0bsinitvals16; + struct d11init *d11n0initvals16; + __le32 *bcm43xx_16_mimo; + size_t bcm43xx_16_mimosz; + __le32 *bcm43xx_24_lcn; + size_t bcm43xx_24_lcnsz; + u32 *bcm43xx_bommajor; + u32 *bcm43xx_bomminor; +}; + +extern int +brcms_ucode_data_init(struct brcms_info *wl, struct brcms_ucode *ucode); + +extern void brcms_ucode_data_free(struct brcms_ucode *ucode); + +extern int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, + unsigned int idx); +extern int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, + unsigned int idx); +extern void brcms_ucode_free_buf(void *); +extern int brcms_check_firmwares(struct brcms_info *wl); + +#endif /* _BRCM_UCODE_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmutil/Makefile b/drivers/net/wireless/brcm80211/brcmutil/Makefile new file mode 100644 index 000000000000..6281c416289e --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmutil/Makefile @@ -0,0 +1,28 @@ +# +# Makefile fragment for Broadcom 802.11n Networking Device Driver Utilities +# +# Copyright (c) 2011 Broadcom Corporation +# +# 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. + +ccflags-y := \ + -Idrivers/net/wireless/brcm80211/brcmutil \ + -Idrivers/net/wireless/brcm80211/include + +BRCMUTIL_OFILES := \ + utils.o + +MODULEPFX := brcmutil + +obj-$(CONFIG_BRCMUTIL) += $(MODULEPFX).o +$(MODULEPFX)-objs = $(BRCMUTIL_OFILES) diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c new file mode 100644 index 000000000000..f27c48910827 --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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/netdevice.h> +#include <linux/module.h> +#include <brcmu_utils.h> + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver utilities."); +MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards"); +MODULE_LICENSE("Dual BSD/GPL"); + +struct sk_buff *brcmu_pkt_buf_get_skb(uint len) +{ + struct sk_buff *skb; + + skb = dev_alloc_skb(len); + if (skb) { + skb_put(skb, len); + skb->priority = 0; + } + + return skb; +} +EXPORT_SYMBOL(brcmu_pkt_buf_get_skb); + +/* Free the driver packet. Free the tag if present */ +void brcmu_pkt_buf_free_skb(struct sk_buff *skb) +{ + struct sk_buff *nskb; + int nest = 0; + + /* perversion: we use skb->next to chain multi-skb packets */ + while (skb) { + nskb = skb->next; + skb->next = NULL; + + if (skb->destructor) + /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if + * destructor exists + */ + dev_kfree_skb_any(skb); + else + /* can free immediately (even in_irq()) if destructor + * does not exist + */ + dev_kfree_skb(skb); + + nest++; + skb = nskb; + } +} +EXPORT_SYMBOL(brcmu_pkt_buf_free_skb); + + +/* copy a buffer into a pkt buffer chain */ +uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len, + unsigned char *buf) +{ + uint n, ret = 0; + + /* skip 'offset' bytes */ + for (; p && offset; p = p->next) { + if (offset < (uint) (p->len)) + break; + offset -= p->len; + } + + if (!p) + return 0; + + /* copy the data */ + for (; p && len; p = p->next) { + n = min((uint) (p->len) - offset, (uint) len); + memcpy(p->data + offset, buf, n); + buf += n; + len -= n; + ret += n; + offset = 0; + } + + return ret; +} +EXPORT_SYMBOL(brcmu_pktfrombuf); + +/* return total length of buffer chain */ +uint brcmu_pkttotlen(struct sk_buff *p) +{ + uint total; + + total = 0; + for (; p; p = p->next) + total += p->len; + return total; +} +EXPORT_SYMBOL(brcmu_pkttotlen); + +/* + * osl multiple-precedence packet queue + * hi_prec is always >= the number of the highest non-empty precedence + */ +struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec, + struct sk_buff *p) +{ + struct pktq_prec *q; + + if (pktq_full(pq) || pktq_pfull(pq, prec)) + return NULL; + + q = &pq->q[prec]; + + if (q->head) + q->tail->prev = p; + else + q->head = p; + + q->tail = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (u8) prec; + + return p; +} +EXPORT_SYMBOL(brcmu_pktq_penq); + +struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec, + struct sk_buff *p) +{ + struct pktq_prec *q; + + if (pktq_full(pq) || pktq_pfull(pq, prec)) + return NULL; + + q = &pq->q[prec]; + + if (q->head == NULL) + q->tail = p; + + p->prev = q->head; + q->head = p; + q->len++; + + pq->len++; + + if (pq->hi_prec < prec) + pq->hi_prec = (u8) prec; + + return p; +} +EXPORT_SYMBOL(brcmu_pktq_penq_head); + +struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + struct sk_buff *p; + + q = &pq->q[prec]; + + p = q->head; + if (p == NULL) + return NULL; + + q->head = p->prev; + if (q->head == NULL) + q->tail = NULL; + + q->len--; + + pq->len--; + + p->prev = NULL; + + return p; +} +EXPORT_SYMBOL(brcmu_pktq_pdeq); + +struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec) +{ + struct pktq_prec *q; + struct sk_buff *p, *prev; + + q = &pq->q[prec]; + + p = q->head; + if (p == NULL) + return NULL; + + for (prev = NULL; p != q->tail; p = p->prev) + prev = p; + + if (prev) + prev->prev = NULL; + else + q->head = NULL; + + q->tail = prev; + q->len--; + + pq->len--; + + return p; +} +EXPORT_SYMBOL(brcmu_pktq_pdeq_tail); + +void +brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir, + bool (*fn)(struct sk_buff *, void *), void *arg) +{ + struct pktq_prec *q; + struct sk_buff *p, *prev = NULL; + + q = &pq->q[prec]; + p = q->head; + while (p) { + if (fn == NULL || (*fn) (p, arg)) { + bool head = (p == q->head); + if (head) + q->head = p->prev; + else + prev->prev = p->prev; + p->prev = NULL; + brcmu_pkt_buf_free_skb(p); + q->len--; + pq->len--; + p = (head ? q->head : prev->prev); + } else { + prev = p; + p = p->prev; + } + } + + if (q->head == NULL) + q->tail = NULL; +} +EXPORT_SYMBOL(brcmu_pktq_pflush); + +void brcmu_pktq_flush(struct pktq *pq, bool dir, + bool (*fn)(struct sk_buff *, void *), void *arg) +{ + int prec; + for (prec = 0; prec < pq->num_prec; prec++) + brcmu_pktq_pflush(pq, prec, dir, fn, arg); +} +EXPORT_SYMBOL(brcmu_pktq_flush); + +void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len) +{ + int prec; + + /* pq is variable size; only zero out what's requested */ + memset(pq, 0, + offsetof(struct pktq, q) + (sizeof(struct pktq_prec) * num_prec)); + + pq->num_prec = (u16) num_prec; + + pq->max = (u16) max_len; + + for (prec = 0; prec < num_prec; prec++) + pq->q[prec].max = pq->max; +} +EXPORT_SYMBOL(brcmu_pktq_init); + +struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out) +{ + int prec; + + if (pq->len == 0) + return NULL; + + for (prec = 0; prec < pq->hi_prec; prec++) + if (pq->q[prec].head) + break; + + if (prec_out) + *prec_out = prec; + + return pq->q[prec].tail; +} +EXPORT_SYMBOL(brcmu_pktq_peek_tail); + +/* Return sum of lengths of a specific set of precedences */ +int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp) +{ + int prec, len; + + len = 0; + + for (prec = 0; prec <= pq->hi_prec; prec++) + if (prec_bmp & (1 << prec)) + len += pq->q[prec].len; + + return len; +} +EXPORT_SYMBOL(brcmu_pktq_mlen); + +/* Priority dequeue from a specific set of precedences */ +struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, + int *prec_out) +{ + struct pktq_prec *q; + struct sk_buff *p; + int prec; + + if (pq->len == 0) + return NULL; + + while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL) + pq->hi_prec--; + + while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL) + if (prec-- == 0) + return NULL; + + q = &pq->q[prec]; + + p = q->head; + if (p == NULL) + return NULL; + + q->head = p->prev; + if (q->head == NULL) + q->tail = NULL; + + q->len--; + + if (prec_out) + *prec_out = prec; + + pq->len--; + + p->prev = NULL; + + return p; +} +EXPORT_SYMBOL(brcmu_pktq_mdeq); + +#if defined(BCMDBG) +/* pretty hex print a pkt buffer chain */ +void brcmu_prpkt(const char *msg, struct sk_buff *p0) +{ + struct sk_buff *p; + + if (msg && (msg[0] != '\0')) + printk(KERN_DEBUG "%s:\n", msg); + + for (p = p0; p; p = p->next) + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, p->data, p->len); +} +EXPORT_SYMBOL(brcmu_prpkt); +#endif /* defined(BCMDBG) */ + +#if defined(BCMDBG) +/* + * print bytes formatted as hex to a string. return the resulting + * string length + */ +int brcmu_format_hex(char *str, const void *bytes, int len) +{ + int i; + char *p = str; + const u8 *src = (const u8 *)bytes; + + for (i = 0; i < len; i++) { + p += snprintf(p, 3, "%02X", *src); + src++; + } + return (int)(p - str); +} +EXPORT_SYMBOL(brcmu_format_hex); +#endif /* defined(BCMDBG) */ diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h new file mode 100644 index 000000000000..5fb17d53c9b2 --- /dev/null +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_HW_IDS_H_ +#define _BRCM_HW_IDS_H_ + +#define BCM4325_D11DUAL_ID 0x431b +#define BCM4325_D11G_ID 0x431c +#define BCM4325_D11A_ID 0x431d + +#define BCM4329_D11N2G_ID 0x432f /* 4329 802.11n 2.4G device */ +#define BCM4329_D11N5G_ID 0x4330 /* 4329 802.11n 5G device */ +#define BCM4329_D11NDUAL_ID 0x432e + +#define BCM4319_D11N_ID 0x4337 /* 4319 802.11n dualband device */ +#define BCM4319_D11N2G_ID 0x4338 /* 4319 802.11n 2.4G device */ +#define BCM4319_D11N5G_ID 0x4339 /* 4319 802.11n 5G device */ + +#define BCM43224_D11N_ID 0x4353 /* 43224 802.11n dualband device */ +#define BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db */ + +#define BCM43225_D11N2G_ID 0x4357 /* 43225 802.11n 2.4GHz device */ + +#define BCM43236_D11N_ID 0x4346 /* 43236 802.11n dualband device */ +#define BCM43236_D11N2G_ID 0x4347 /* 43236 802.11n 2.4GHz device */ + +#define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ + +/* Chip IDs */ +#define BCM4313_CHIP_ID 0x4313 /* 4313 chip id */ +#define BCM4319_CHIP_ID 0x4319 /* 4319 chip id */ + +#define BCM43224_CHIP_ID 43224 /* 43224 chipcommon chipid */ +#define BCM43225_CHIP_ID 43225 /* 43225 chipcommon chipid */ +#define BCM43421_CHIP_ID 43421 /* 43421 chipcommon chipid */ +#define BCM43235_CHIP_ID 43235 /* 43235 chipcommon chipid */ +#define BCM43236_CHIP_ID 43236 /* 43236 chipcommon chipid */ +#define BCM43238_CHIP_ID 43238 /* 43238 chipcommon chipid */ +#define BCM4329_CHIP_ID 0x4329 /* 4329 chipcommon chipid */ +#define BCM4325_CHIP_ID 0x4325 /* 4325 chipcommon chipid */ +#define BCM4331_CHIP_ID 0x4331 /* 4331 chipcommon chipid */ +#define BCM4336_CHIP_ID 0x4336 /* 4336 chipcommon chipid */ +#define BCM4330_CHIP_ID 0x4330 /* 4330 chipcommon chipid */ +#define BCM6362_CHIP_ID 0x6362 /* 6362 chipcommon chipid */ + +#endif /* _BRCM_HW_IDS_H_ */ diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h new file mode 100644 index 000000000000..7d0f46e0eb95 --- /dev/null +++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCMU_UTILS_H_ +#define _BRCMU_UTILS_H_ + +#include <linux/skbuff.h> + +/* + * Spin at most 'us' microseconds while 'exp' is true. + * Caller should explicitly test 'exp' when this completes + * and take appropriate error action if 'exp' is still true. + */ +#define SPINWAIT(exp, us) { \ + uint countdown = (us) + 9; \ + while ((exp) && (countdown >= 10)) {\ + udelay(10); \ + countdown -= 10; \ + } \ +} + +/* osl multi-precedence packet queue */ +#define PKTQ_LEN_DEFAULT 128 /* Max 128 packets */ +#define PKTQ_MAX_PREC 16 /* Maximum precedence levels */ + +#define BCME_STRLEN 64 /* Max string length for BCM errors */ + +/* the largest reasonable packet buffer driver uses for ethernet MTU in bytes */ +#define PKTBUFSZ 2048 + +#ifndef setbit +#ifndef NBBY /* the BSD family defines NBBY */ +#define NBBY 8 /* 8 bits per byte */ +#endif /* #ifndef NBBY */ +#define setbit(a, i) (((u8 *)a)[(i)/NBBY] |= 1<<((i)%NBBY)) +#define clrbit(a, i) (((u8 *)a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) +#define isset(a, i) (((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) +#define isclr(a, i) ((((const u8 *)a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) +#endif /* setbit */ + +#define NBITS(type) (sizeof(type) * 8) +#define NBITVAL(nbits) (1 << (nbits)) +#define MAXBITVAL(nbits) ((1 << (nbits)) - 1) +#define NBITMASK(nbits) MAXBITVAL(nbits) +#define MAXNBVAL(nbyte) MAXBITVAL((nbyte) * 8) + +/* crc defines */ +#define CRC16_INIT_VALUE 0xffff /* Initial CRC16 checksum value */ +#define CRC16_GOOD_VALUE 0xf0b8 /* Good final CRC16 checksum value */ + +/* 18-bytes of Ethernet address buffer length */ +#define ETHER_ADDR_STR_LEN 18 + +struct pktq_prec { + struct sk_buff *head; /* first packet to dequeue */ + struct sk_buff *tail; /* last packet to dequeue */ + u16 len; /* number of queued packets */ + u16 max; /* maximum number of queued packets */ +}; + +/* multi-priority pkt queue */ +struct pktq { + u16 num_prec; /* number of precedences in use */ + u16 hi_prec; /* rapid dequeue hint (>= highest non-empty prec) */ + u16 max; /* total max packets */ + u16 len; /* total number of packets */ + /* + * q array must be last since # of elements can be either + * PKTQ_MAX_PREC or 1 + */ + struct pktq_prec q[PKTQ_MAX_PREC]; +}; + +/* operations on a specific precedence in packet queue */ + +static inline int pktq_plen(struct pktq *pq, int prec) +{ + return pq->q[prec].len; +} + +static inline int pktq_pavail(struct pktq *pq, int prec) +{ + return pq->q[prec].max - pq->q[prec].len; +} + +static inline bool pktq_pfull(struct pktq *pq, int prec) +{ + return pq->q[prec].len >= pq->q[prec].max; +} + +static inline bool pktq_pempty(struct pktq *pq, int prec) +{ + return pq->q[prec].len == 0; +} + +static inline struct sk_buff *pktq_ppeek(struct pktq *pq, int prec) +{ + return pq->q[prec].head; +} + +static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec) +{ + return pq->q[prec].tail; +} + +extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec, + struct sk_buff *p); +extern struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec, + struct sk_buff *p); +extern struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec); +extern struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec); + +/* packet primitives */ +extern struct sk_buff *brcmu_pkt_buf_get_skb(uint len); +extern void brcmu_pkt_buf_free_skb(struct sk_buff *skb); + +/* Empty the queue at particular precedence level */ +/* callback function fn(pkt, arg) returns true if pkt belongs to if */ +extern void brcmu_pktq_pflush(struct pktq *pq, int prec, + bool dir, bool (*fn)(struct sk_buff *, void *), void *arg); + +/* operations on a set of precedences in packet queue */ + +extern int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp); +extern struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp, + int *prec_out); + +/* operations on packet queue as a whole */ + +static inline int pktq_len(struct pktq *pq) +{ + return (int)pq->len; +} + +static inline int pktq_max(struct pktq *pq) +{ + return (int)pq->max; +} + +static inline int pktq_avail(struct pktq *pq) +{ + return (int)(pq->max - pq->len); +} + +static inline bool pktq_full(struct pktq *pq) +{ + return pq->len >= pq->max; +} + +static inline bool pktq_empty(struct pktq *pq) +{ + return pq->len == 0; +} + +extern void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len); +/* prec_out may be NULL if caller is not interested in return value */ +extern struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out); +extern void brcmu_pktq_flush(struct pktq *pq, bool dir, + bool (*fn)(struct sk_buff *, void *), void *arg); + +/* externs */ +/* packet */ +extern uint brcmu_pktfrombuf(struct sk_buff *p, + uint offset, int len, unsigned char *buf); +extern uint brcmu_pkttotlen(struct sk_buff *p); + +/* ip address */ +struct ipv4_addr; + +#ifdef BCMDBG +extern void brcmu_prpkt(const char *msg, struct sk_buff *p0); +#else +#define brcmu_prpkt(a, b) +#endif /* BCMDBG */ + +/* externs */ +/* format/print */ +#if defined(BCMDBG) +extern int brcmu_format_hex(char *str, const void *bytes, int len); +#endif + +#endif /* _BRCMU_UTILS_H_ */ diff --git a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h new file mode 100644 index 000000000000..f10d30274c23 --- /dev/null +++ b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCMU_WIFI_H_ +#define _BRCMU_WIFI_H_ + +#include <linux/if_ether.h> /* for ETH_ALEN */ +#include <linux/ieee80211.h> /* for WLAN_PMKID_LEN */ + +/* + * A chanspec (u16) holds the channel number, band, bandwidth and control + * sideband + */ + +/* channel defines */ +#define CH_UPPER_SB 0x01 +#define CH_LOWER_SB 0x02 +#define CH_EWA_VALID 0x04 +#define CH_20MHZ_APART 4 +#define CH_10MHZ_APART 2 +#define CH_5MHZ_APART 1 /* 2G band channels are 5 Mhz apart */ +#define CH_MAX_2G_CHANNEL 14 /* Max channel in 2G band */ +#define BRCM_MAX_2G_CHANNEL CH_MAX_2G_CHANNEL /* legacy define */ + +/* bandstate array indices */ +#define BAND_2G_INDEX 0 /* wlc->bandstate[x] index */ +#define BAND_5G_INDEX 1 /* wlc->bandstate[x] index */ + +/* + * max # supported channels. The max channel no is 216, this is that + 1 + * rounded up to a multiple of NBBY (8). DO NOT MAKE it > 255: channels are + * u8's all over +*/ +#define MAXCHANNEL 224 + +#define WL_CHANSPEC_CHAN_MASK 0x00ff +#define WL_CHANSPEC_CHAN_SHIFT 0 + +#define WL_CHANSPEC_CTL_SB_MASK 0x0300 +#define WL_CHANSPEC_CTL_SB_SHIFT 8 +#define WL_CHANSPEC_CTL_SB_LOWER 0x0100 +#define WL_CHANSPEC_CTL_SB_UPPER 0x0200 +#define WL_CHANSPEC_CTL_SB_NONE 0x0300 + +#define WL_CHANSPEC_BW_MASK 0x0C00 +#define WL_CHANSPEC_BW_SHIFT 10 +#define WL_CHANSPEC_BW_10 0x0400 +#define WL_CHANSPEC_BW_20 0x0800 +#define WL_CHANSPEC_BW_40 0x0C00 + +#define WL_CHANSPEC_BAND_MASK 0xf000 +#define WL_CHANSPEC_BAND_SHIFT 12 +#define WL_CHANSPEC_BAND_5G 0x1000 +#define WL_CHANSPEC_BAND_2G 0x2000 +#define INVCHANSPEC 255 + +/* used to calculate the chan_freq = chan_factor * 500Mhz + 5 * chan_number */ +#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */ +#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */ +#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */ + +#define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK)) +#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK) + +#define CHSPEC_CTL_SB(chspec) ((chspec) & WL_CHANSPEC_CTL_SB_MASK) +#define CHSPEC_BW(chspec) ((chspec) & WL_CHANSPEC_BW_MASK) + +#define CHSPEC_IS10(chspec) \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_10) + +#define CHSPEC_IS20(chspec) \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_20) + +#ifndef CHSPEC_IS40 +#define CHSPEC_IS40(chspec) \ + (((chspec) & WL_CHANSPEC_BW_MASK) == WL_CHANSPEC_BW_40) +#endif + +#define CHSPEC_IS5G(chspec) \ + (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_5G) + +#define CHSPEC_IS2G(chspec) \ + (((chspec) & WL_CHANSPEC_BAND_MASK) == WL_CHANSPEC_BAND_2G) + +#define CHSPEC_SB_NONE(chspec) \ + (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_NONE) + +#define CHSPEC_SB_UPPER(chspec) \ + (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_UPPER) + +#define CHSPEC_SB_LOWER(chspec) \ + (((chspec) & WL_CHANSPEC_CTL_SB_MASK) == WL_CHANSPEC_CTL_SB_LOWER) + +#define CHSPEC_CTL_CHAN(chspec) \ + ((CHSPEC_SB_LOWER(chspec)) ? \ + (lower_20_sb(((chspec) & WL_CHANSPEC_CHAN_MASK))) : \ + (upper_20_sb(((chspec) & WL_CHANSPEC_CHAN_MASK)))) + +#define CHSPEC2BAND(chspec) (CHSPEC_IS5G(chspec) ? BRCM_BAND_5G : BRCM_BAND_2G) + +#define CHANSPEC_STR_LEN 8 + +static inline int lower_20_sb(int channel) +{ + return channel > CH_10MHZ_APART ? (channel - CH_10MHZ_APART) : 0; +} + +static inline int upper_20_sb(int channel) +{ + return (channel < (MAXCHANNEL - CH_10MHZ_APART)) ? + channel + CH_10MHZ_APART : 0; +} + +static inline int chspec_bandunit(u16 chspec) +{ + return CHSPEC_IS5G(chspec) ? BAND_5G_INDEX : BAND_2G_INDEX; +} + +static inline u16 ch20mhz_chspec(int channel) +{ + u16 rc = channel <= CH_MAX_2G_CHANNEL ? + WL_CHANSPEC_BAND_2G : WL_CHANSPEC_BAND_5G; + + return (u16)((u16)channel | WL_CHANSPEC_BW_20 | + WL_CHANSPEC_CTL_SB_NONE | rc); +} + +static inline int next_20mhz_chan(int channel) +{ + return channel < (MAXCHANNEL - CH_20MHZ_APART) ? + channel + CH_20MHZ_APART : 0; +} + +/* defined rate in 500kbps */ +#define BRCM_MAXRATE 108 /* in 500kbps units */ +#define BRCM_RATE_1M 2 /* in 500kbps units */ +#define BRCM_RATE_2M 4 /* in 500kbps units */ +#define BRCM_RATE_5M5 11 /* in 500kbps units */ +#define BRCM_RATE_11M 22 /* in 500kbps units */ +#define BRCM_RATE_6M 12 /* in 500kbps units */ +#define BRCM_RATE_9M 18 /* in 500kbps units */ +#define BRCM_RATE_12M 24 /* in 500kbps units */ +#define BRCM_RATE_18M 36 /* in 500kbps units */ +#define BRCM_RATE_24M 48 /* in 500kbps units */ +#define BRCM_RATE_36M 72 /* in 500kbps units */ +#define BRCM_RATE_48M 96 /* in 500kbps units */ +#define BRCM_RATE_54M 108 /* in 500kbps units */ + +#define BRCM_2G_25MHZ_OFFSET 5 /* 2.4GHz band channel offset */ + +#define MCSSET_LEN 16 + +static inline bool ac_bitmap_tst(u8 bitmap, int prec) +{ + return (bitmap & (1 << (prec))) != 0; +} + +/* Enumerate crypto algorithms */ +#define CRYPTO_ALGO_OFF 0 +#define CRYPTO_ALGO_WEP1 1 +#define CRYPTO_ALGO_TKIP 2 +#define CRYPTO_ALGO_WEP128 3 +#define CRYPTO_ALGO_AES_CCM 4 +#define CRYPTO_ALGO_AES_RESERVED1 5 +#define CRYPTO_ALGO_AES_RESERVED2 6 +#define CRYPTO_ALGO_NALG 7 + +/* wireless security bitvec */ + +#define WEP_ENABLED 0x0001 +#define TKIP_ENABLED 0x0002 +#define AES_ENABLED 0x0004 +#define WSEC_SWFLAG 0x0008 +/* to go into transition mode without setting wep */ +#define SES_OW_ENABLED 0x0040 + +/* WPA authentication mode bitvec */ +#define WPA_AUTH_DISABLED 0x0000 /* Legacy (i.e., non-WPA) */ +#define WPA_AUTH_NONE 0x0001 /* none (IBSS) */ +#define WPA_AUTH_UNSPECIFIED 0x0002 /* over 802.1x */ +#define WPA_AUTH_PSK 0x0004 /* Pre-shared key */ +#define WPA_AUTH_RESERVED1 0x0008 +#define WPA_AUTH_RESERVED2 0x0010 + +#define WPA2_AUTH_RESERVED1 0x0020 +#define WPA2_AUTH_UNSPECIFIED 0x0040 /* over 802.1x */ +#define WPA2_AUTH_PSK 0x0080 /* Pre-shared key */ +#define WPA2_AUTH_RESERVED3 0x0200 +#define WPA2_AUTH_RESERVED4 0x0400 +#define WPA2_AUTH_RESERVED5 0x0800 + +/* pmkid */ +#define MAXPMKID 16 + +#define DOT11_DEFAULT_RTS_LEN 2347 +#define DOT11_DEFAULT_FRAG_LEN 2346 + +#define DOT11_ICV_AES_LEN 8 +#define DOT11_QOS_LEN 2 +#define DOT11_IV_MAX_LEN 8 +#define DOT11_A4_HDR_LEN 30 + +#define HT_CAP_RX_STBC_NO 0x0 +#define HT_CAP_RX_STBC_ONE_STREAM 0x1 + +struct pmkid { + u8 BSSID[ETH_ALEN]; + u8 PMKID[WLAN_PMKID_LEN]; +}; + +struct pmkid_list { + __le32 npmkid; + struct pmkid pmkid[1]; +}; + +struct pmkid_cand { + u8 BSSID[ETH_ALEN]; + u8 preauth; +}; + +struct pmkid_cand_list { + u32 npmkid_cand; + struct pmkid_cand pmkid_cand[1]; +}; + +#endif /* _BRCMU_WIFI_H_ */ diff --git a/drivers/net/wireless/brcm80211/include/chipcommon.h b/drivers/net/wireless/brcm80211/include/chipcommon.h new file mode 100644 index 000000000000..fefabc39e646 --- /dev/null +++ b/drivers/net/wireless/brcm80211/include/chipcommon.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _SBCHIPC_H +#define _SBCHIPC_H + +#include "defs.h" /* for PAD macro */ + +struct chipcregs { + u32 chipid; /* 0x0 */ + u32 capabilities; + u32 corecontrol; /* corerev >= 1 */ + u32 bist; + + /* OTP */ + u32 otpstatus; /* 0x10, corerev >= 10 */ + u32 otpcontrol; + u32 otpprog; + u32 otplayout; /* corerev >= 23 */ + + /* Interrupt control */ + u32 intstatus; /* 0x20 */ + u32 intmask; + + /* Chip specific regs */ + u32 chipcontrol; /* 0x28, rev >= 11 */ + u32 chipstatus; /* 0x2c, rev >= 11 */ + + /* Jtag Master */ + u32 jtagcmd; /* 0x30, rev >= 10 */ + u32 jtagir; + u32 jtagdr; + u32 jtagctrl; + + /* serial flash interface registers */ + u32 flashcontrol; /* 0x40 */ + u32 flashaddress; + u32 flashdata; + u32 PAD[1]; + + /* Silicon backplane configuration broadcast control */ + u32 broadcastaddress; /* 0x50 */ + u32 broadcastdata; + + /* gpio - cleared only by power-on-reset */ + u32 gpiopullup; /* 0x58, corerev >= 20 */ + u32 gpiopulldown; /* 0x5c, corerev >= 20 */ + u32 gpioin; /* 0x60 */ + u32 gpioout; /* 0x64 */ + u32 gpioouten; /* 0x68 */ + u32 gpiocontrol; /* 0x6C */ + u32 gpiointpolarity; /* 0x70 */ + u32 gpiointmask; /* 0x74 */ + + /* GPIO events corerev >= 11 */ + u32 gpioevent; + u32 gpioeventintmask; + + /* Watchdog timer */ + u32 watchdog; /* 0x80 */ + + /* GPIO events corerev >= 11 */ + u32 gpioeventintpolarity; + + /* GPIO based LED powersave registers corerev >= 16 */ + u32 gpiotimerval; /* 0x88 */ + u32 gpiotimeroutmask; + + /* clock control */ + u32 clockcontrol_n; /* 0x90 */ + u32 clockcontrol_sb; /* aka m0 */ + u32 clockcontrol_pci; /* aka m1 */ + u32 clockcontrol_m2; /* mii/uart/mipsref */ + u32 clockcontrol_m3; /* cpu */ + u32 clkdiv; /* corerev >= 3 */ + u32 gpiodebugsel; /* corerev >= 28 */ + u32 capabilities_ext; /* 0xac */ + + /* pll delay registers (corerev >= 4) */ + u32 pll_on_delay; /* 0xb0 */ + u32 fref_sel_delay; + u32 slow_clk_ctl; /* 5 < corerev < 10 */ + u32 PAD; + + /* Instaclock registers (corerev >= 10) */ + u32 system_clk_ctl; /* 0xc0 */ + u32 clkstatestretch; + u32 PAD[2]; + + /* Indirect backplane access (corerev >= 22) */ + u32 bp_addrlow; /* 0xd0 */ + u32 bp_addrhigh; + u32 bp_data; + u32 PAD; + u32 bp_indaccess; + u32 PAD[3]; + + /* More clock dividers (corerev >= 32) */ + u32 clkdiv2; + u32 PAD[2]; + + /* In AI chips, pointer to erom */ + u32 eromptr; /* 0xfc */ + + /* ExtBus control registers (corerev >= 3) */ + u32 pcmcia_config; /* 0x100 */ + u32 pcmcia_memwait; + u32 pcmcia_attrwait; + u32 pcmcia_iowait; + u32 ide_config; + u32 ide_memwait; + u32 ide_attrwait; + u32 ide_iowait; + u32 prog_config; + u32 prog_waitcount; + u32 flash_config; + u32 flash_waitcount; + u32 SECI_config; /* 0x130 SECI configuration */ + u32 PAD[3]; + + /* Enhanced Coexistence Interface (ECI) registers (corerev >= 21) */ + u32 eci_output; /* 0x140 */ + u32 eci_control; + u32 eci_inputlo; + u32 eci_inputmi; + u32 eci_inputhi; + u32 eci_inputintpolaritylo; + u32 eci_inputintpolaritymi; + u32 eci_inputintpolarityhi; + u32 eci_intmasklo; + u32 eci_intmaskmi; + u32 eci_intmaskhi; + u32 eci_eventlo; + u32 eci_eventmi; + u32 eci_eventhi; + u32 eci_eventmasklo; + u32 eci_eventmaskmi; + u32 eci_eventmaskhi; + u32 PAD[3]; + + /* SROM interface (corerev >= 32) */ + u32 sromcontrol; /* 0x190 */ + u32 sromaddress; + u32 sromdata; + u32 PAD[17]; + + /* Clock control and hardware workarounds (corerev >= 20) */ + u32 clk_ctl_st; /* 0x1e0 */ + u32 hw_war; + u32 PAD[70]; + + /* UARTs */ + u8 uart0data; /* 0x300 */ + u8 uart0imr; + u8 uart0fcr; + u8 uart0lcr; + u8 uart0mcr; + u8 uart0lsr; + u8 uart0msr; + u8 uart0scratch; + u8 PAD[248]; /* corerev >= 1 */ + + u8 uart1data; /* 0x400 */ + u8 uart1imr; + u8 uart1fcr; + u8 uart1lcr; + u8 uart1mcr; + u8 uart1lsr; + u8 uart1msr; + u8 uart1scratch; + u32 PAD[126]; + + /* PMU registers (corerev >= 20) */ + u32 pmucontrol; /* 0x600 */ + u32 pmucapabilities; + u32 pmustatus; + u32 res_state; + u32 res_pending; + u32 pmutimer; + u32 min_res_mask; + u32 max_res_mask; + u32 res_table_sel; + u32 res_dep_mask; + u32 res_updn_timer; + u32 res_timer; + u32 clkstretch; + u32 pmuwatchdog; + u32 gpiosel; /* 0x638, rev >= 1 */ + u32 gpioenable; /* 0x63c, rev >= 1 */ + u32 res_req_timer_sel; + u32 res_req_timer; + u32 res_req_mask; + u32 PAD; + u32 chipcontrol_addr; /* 0x650 */ + u32 chipcontrol_data; /* 0x654 */ + u32 regcontrol_addr; + u32 regcontrol_data; + u32 pllcontrol_addr; + u32 pllcontrol_data; + u32 pmustrapopt; /* 0x668, corerev >= 28 */ + u32 pmu_xtalfreq; /* 0x66C, pmurev >= 10 */ + u32 PAD[100]; + u16 sromotp[768]; +}; + +/* chipid */ +#define CID_ID_MASK 0x0000ffff /* Chip Id mask */ +#define CID_REV_MASK 0x000f0000 /* Chip Revision mask */ +#define CID_REV_SHIFT 16 /* Chip Revision shift */ +#define CID_PKG_MASK 0x00f00000 /* Package Option mask */ +#define CID_PKG_SHIFT 20 /* Package Option shift */ +#define CID_CC_MASK 0x0f000000 /* CoreCount (corerev >= 4) */ +#define CID_CC_SHIFT 24 +#define CID_TYPE_MASK 0xf0000000 /* Chip Type */ +#define CID_TYPE_SHIFT 28 + +/* capabilities */ +#define CC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */ +#define CC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */ +#define CC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */ +/* UARTs are driven by internal divided clock */ +#define CC_CAP_UINTCLK 0x00000008 +#define CC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */ +#define CC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */ +#define CC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */ +#define CC_CAP_EXTBUS_FULL 0x00000040 /* ExtBus: PCMCIA, IDE & Prog */ +#define CC_CAP_EXTBUS_PROG 0x00000080 /* ExtBus: ProgIf only */ +#define CC_CAP_FLASH_MASK 0x00000700 /* Type of flash */ +#define CC_CAP_PLL_MASK 0x00038000 /* Type of PLL */ +#define CC_CAP_PWR_CTL 0x00040000 /* Power control */ +#define CC_CAP_OTPSIZE 0x00380000 /* OTP Size (0 = none) */ +#define CC_CAP_OTPSIZE_SHIFT 19 /* OTP Size shift */ +#define CC_CAP_OTPSIZE_BASE 5 /* OTP Size base */ +#define CC_CAP_JTAGP 0x00400000 /* JTAG Master Present */ +#define CC_CAP_ROM 0x00800000 /* Internal boot rom active */ +#define CC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */ +#define CC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */ +#define CC_CAP_SROM 0x40000000 /* Srom Present, rev >= 32 */ +/* Nand flash present, rev >= 35 */ +#define CC_CAP_NFLASH 0x80000000 + +#define CC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ +/* GSIO (spi/i2c) present, rev >= 37 */ +#define CC_CAP2_GSIO 0x00000002 + +/* pmucapabilities */ +#define PCAP_REV_MASK 0x000000ff +#define PCAP_RC_MASK 0x00001f00 +#define PCAP_RC_SHIFT 8 +#define PCAP_TC_MASK 0x0001e000 +#define PCAP_TC_SHIFT 13 +#define PCAP_PC_MASK 0x001e0000 +#define PCAP_PC_SHIFT 17 +#define PCAP_VC_MASK 0x01e00000 +#define PCAP_VC_SHIFT 21 +#define PCAP_CC_MASK 0x1e000000 +#define PCAP_CC_SHIFT 25 +#define PCAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */ +#define PCAP5_PC_SHIFT 17 +#define PCAP5_VC_MASK 0x07c00000 +#define PCAP5_VC_SHIFT 22 +#define PCAP5_CC_MASK 0xf8000000 +#define PCAP5_CC_SHIFT 27 + +/* +* Maximum delay for the PMU state transition in us. +* This is an upper bound intended for spinwaits etc. +*/ +#define PMU_MAX_TRANSITION_DLY 15000 + +#endif /* _SBCHIPC_H */ diff --git a/drivers/net/wireless/brcm80211/include/defs.h b/drivers/net/wireless/brcm80211/include/defs.h new file mode 100644 index 000000000000..1e5f310af1e7 --- /dev/null +++ b/drivers/net/wireless/brcm80211/include/defs.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_DEFS_H_ +#define _BRCM_DEFS_H_ + +#include <linux/types.h> + +#define SI_BUS 0 +#define PCI_BUS 1 +#define PCMCIA_BUS 2 +#define SDIO_BUS 3 +#define JTAG_BUS 4 +#define USB_BUS 5 +#define SPI_BUS 6 + +#define OFF 0 +#define ON 1 /* ON = 1 */ +#define AUTO (-1) /* Auto = -1 */ + +/* + * Priority definitions according 802.1D + */ +#define PRIO_8021D_NONE 2 +#define PRIO_8021D_BK 1 +#define PRIO_8021D_BE 0 +#define PRIO_8021D_EE 3 +#define PRIO_8021D_CL 4 +#define PRIO_8021D_VI 5 +#define PRIO_8021D_VO 6 +#define PRIO_8021D_NC 7 + +#define MAXPRIO 7 +#define NUMPRIO (MAXPRIO + 1) + +#define WL_NUMRATES 16 /* max # of rates in a rateset */ + +#define BRCM_CNTRY_BUF_SZ 4 /* Country string is 3 bytes + NUL */ + +#define BRCM_SET_CHANNEL 30 +#define BRCM_SET_SRL 32 +#define BRCM_SET_LRL 34 +#define BRCM_SET_BCNPRD 76 + +#define BRCM_GET_CURR_RATESET 114 /* current rateset */ +#define BRCM_GET_PHYLIST 180 + +/* Bit masks for radio disabled status - returned by WL_GET_RADIO */ + +#define WL_RADIO_SW_DISABLE (1<<0) +#define WL_RADIO_HW_DISABLE (1<<1) +#define WL_RADIO_MPC_DISABLE (1<<2) +/* some countries don't support any channel */ +#define WL_RADIO_COUNTRY_DISABLE (1<<3) + +/* Override bit for SET_TXPWR. if set, ignore other level limits */ +#define WL_TXPWR_OVERRIDE (1U<<31) + +/* band types */ +#define BRCM_BAND_AUTO 0 /* auto-select */ +#define BRCM_BAND_5G 1 /* 5 Ghz */ +#define BRCM_BAND_2G 2 /* 2.4 Ghz */ +#define BRCM_BAND_ALL 3 /* all bands */ + +/* Values for PM */ +#define PM_OFF 0 +#define PM_MAX 1 + +/* Message levels */ +#define LOG_ERROR_VAL 0x00000001 +#define LOG_TRACE_VAL 0x00000002 + +#define PM_OFF 0 +#define PM_MAX 1 +#define PM_FAST 2 + +/* + * Sonics Configuration Space Registers. + */ + +/* core sbconfig regs are top 256bytes of regs */ +#define SBCONFIGOFF 0xf00 + +/* cpp contortions to concatenate w/arg prescan */ +#ifndef PAD +#define _PADLINE(line) pad ## line +#define _XSTR(line) _PADLINE(line) +#define PAD _XSTR(__LINE__) +#endif + +#endif /* _BRCM_DEFS_H_ */ diff --git a/drivers/net/wireless/brcm80211/include/soc.h b/drivers/net/wireless/brcm80211/include/soc.h new file mode 100644 index 000000000000..4fcb956ad9e0 --- /dev/null +++ b/drivers/net/wireless/brcm80211/include/soc.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010 Broadcom Corporation + * + * 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 _BRCM_SOC_H +#define _BRCM_SOC_H + +#define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ + +/* core codes */ +#define NODEV_CORE_ID 0x700 /* Invalid coreid */ +#define CC_CORE_ID 0x800 /* chipcommon core */ +#define ILINE20_CORE_ID 0x801 /* iline20 core */ +#define SRAM_CORE_ID 0x802 /* sram core */ +#define SDRAM_CORE_ID 0x803 /* sdram core */ +#define PCI_CORE_ID 0x804 /* pci core */ +#define MIPS_CORE_ID 0x805 /* mips core */ +#define ENET_CORE_ID 0x806 /* enet mac core */ +#define CODEC_CORE_ID 0x807 /* v90 codec core */ +#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ +#define ADSL_CORE_ID 0x809 /* ADSL core */ +#define ILINE100_CORE_ID 0x80a /* iline100 core */ +#define IPSEC_CORE_ID 0x80b /* ipsec core */ +#define UTOPIA_CORE_ID 0x80c /* utopia core */ +#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ +#define SOCRAM_CORE_ID 0x80e /* internal memory core */ +#define MEMC_CORE_ID 0x80f /* memc sdram core */ +#define OFDM_CORE_ID 0x810 /* OFDM phy core */ +#define EXTIF_CORE_ID 0x811 /* external interface core */ +#define D11_CORE_ID 0x812 /* 802.11 MAC core */ +#define APHY_CORE_ID 0x813 /* 802.11a phy core */ +#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ +#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ +#define MIPS33_CORE_ID 0x816 /* mips3302 core */ +#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ +#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ +#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ +#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ +#define SDIOH_CORE_ID 0x81b /* sdio host core */ +#define ROBO_CORE_ID 0x81c /* roboswitch core */ +#define ATA100_CORE_ID 0x81d /* parallel ATA core */ +#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ +#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ +#define PCIE_CORE_ID 0x820 /* pci express core */ +#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ +#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ +#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ +#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ +#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ +#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ +#define PMU_CORE_ID 0x827 /* PMU core */ +#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ +#define SDIOD_CORE_ID 0x829 /* SDIO device core */ +#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ +#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ +#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ +#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ +#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ +#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ +#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ +#define SC_CORE_ID 0x831 /* shared common core */ +#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ +#define SPIH_CORE_ID 0x833 /* SPI host core */ +#define I2S_CORE_ID 0x834 /* I2S core */ +#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ +#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ +#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ +/* Default component, in ai chips it maps all unused address ranges */ +#define DEF_AI_COMP 0xfff + +/* Common core control flags */ +#define SICF_BIST_EN 0x8000 +#define SICF_PME_EN 0x4000 +#define SICF_CORE_BITS 0x3ffc +#define SICF_FGC 0x0002 +#define SICF_CLOCK_EN 0x0001 + +#endif /* _BRCM_SOC_H */ diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 89a116fba1de..bfa0d54221e8 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -816,7 +816,7 @@ static const struct net_device_ops hostap_netdev_ops = { .ndo_stop = prism2_close, .ndo_do_ioctl = hostap_ioctl, .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_multicast_list = hostap_set_multicast_list, + .ndo_set_rx_mode = hostap_set_multicast_list, .ndo_change_mtu = prism2_change_mtu, .ndo_tx_timeout = prism2_tx_timeout, .ndo_validate_addr = eth_validate_addr, @@ -829,7 +829,7 @@ static const struct net_device_ops hostap_mgmt_netdev_ops = { .ndo_stop = prism2_close, .ndo_do_ioctl = hostap_ioctl, .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_multicast_list = hostap_set_multicast_list, + .ndo_set_rx_mode = hostap_set_multicast_list, .ndo_change_mtu = prism2_change_mtu, .ndo_tx_timeout = prism2_tx_timeout, .ndo_validate_addr = eth_validate_addr, @@ -842,7 +842,7 @@ static const struct net_device_ops hostap_master_ops = { .ndo_stop = prism2_close, .ndo_do_ioctl = hostap_ioctl, .ndo_set_mac_address = prism2_set_mac_address, - .ndo_set_multicast_list = hostap_set_multicast_list, + .ndo_set_rx_mode = hostap_set_multicast_list, .ndo_change_mtu = prism2_change_mtu, .ndo_tx_timeout = prism2_tx_timeout, .ndo_validate_addr = eth_validate_addr, diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c index 4ffebede5e03..99a710dfe771 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -32,6 +32,7 @@ #include <linux/sched.h> #include <linux/slab.h> +#include <net/cfg80211-wext.h> #include "ipw2200.h" @@ -11704,7 +11705,7 @@ static const struct net_device_ops ipw_netdev_ops = { .ndo_init = ipw_net_init, .ndo_open = ipw_net_open, .ndo_stop = ipw_net_stop, - .ndo_set_multicast_list = ipw_net_set_multicast_list, + .ndo_set_rx_mode = ipw_net_set_multicast_list, .ndo_set_mac_address = ipw_net_set_mac_address, .ndo_start_xmit = libipw_xmit, .ndo_change_mtu = libipw_change_mtu, diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-led.c b/drivers/net/wireless/iwlegacy/iwl-3945-led.c index abd923558d48..7a7f0f38c8ab 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-3945-led.c @@ -32,7 +32,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> diff --git a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c index 164bcae821f8..8faeaf2dddec 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-3945-rs.c @@ -28,7 +28,6 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <linux/slab.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/netdevice.h> diff --git a/drivers/net/wireless/iwlegacy/iwl-3945.c b/drivers/net/wireless/iwlegacy/iwl-3945.c index 73fe3cdf796b..f7c0a7438476 100644 --- a/drivers/net/wireless/iwlegacy/iwl-3945.c +++ b/drivers/net/wireless/iwlegacy/iwl-3945.c @@ -34,7 +34,6 @@ #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <linux/firmware.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-led.c b/drivers/net/wireless/iwlegacy/iwl-4965-led.c index 26d324e30692..6862fdcaee62 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-led.c @@ -32,7 +32,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c index 9b65153bdd01..57ebe214e68c 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c @@ -27,7 +27,6 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <linux/slab.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/netdevice.h> diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c index ac4f64de1363..7f12e3638bae 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965-tx.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965-tx.c @@ -335,7 +335,7 @@ int iwl4965_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) sta_priv = (void *)sta->drv_priv; if (sta_priv && sta_priv->asleep && - (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) { + (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { /* * This sends an asynchronous command to the device, * but we can rely on it being processed before the diff --git a/drivers/net/wireless/iwlegacy/iwl-4965.c b/drivers/net/wireless/iwlegacy/iwl-4965.c index ecdc6e557428..86f4fce193e4 100644 --- a/drivers/net/wireless/iwlegacy/iwl-4965.c +++ b/drivers/net/wireless/iwlegacy/iwl-4965.c @@ -33,7 +33,6 @@ #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c index e5971fe9d169..2bd5659310d7 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.c +++ b/drivers/net/wireless/iwlegacy/iwl-core.c @@ -1250,7 +1250,8 @@ void iwl_legacy_clear_isr_stats(struct iwl_priv *priv) memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); } -int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; @@ -2220,7 +2221,8 @@ out: } EXPORT_SYMBOL(iwl_legacy_mac_config); -void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw) +void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; unsigned long flags; diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h index 84da79376ef8..d1271fe07d4b 100644 --- a/drivers/net/wireless/iwlegacy/iwl-core.h +++ b/drivers/net/wireless/iwlegacy/iwl-core.h @@ -286,7 +286,8 @@ struct iwl_cfg { ***************************/ struct ieee80211_hw *iwl_legacy_alloc_all(struct iwl_cfg *cfg); -int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwl_legacy_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); int iwl_legacy_mac_tx_last_beacon(struct ieee80211_hw *hw); void iwl_legacy_set_rxon_hwcrypto(struct iwl_priv *priv, @@ -620,7 +621,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode( /* mac80211 handlers */ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed); -void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw); +void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, diff --git a/drivers/net/wireless/iwlegacy/iwl-led.c b/drivers/net/wireless/iwlegacy/iwl-led.c index bda0d61b2c0d..dc568a474c5d 100644 --- a/drivers/net/wireless/iwlegacy/iwl-led.c +++ b/drivers/net/wireless/iwlegacy/iwl-led.c @@ -33,7 +33,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index 66ee15629a76..b282d869a546 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -40,7 +40,6 @@ #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <linux/firmware.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c index aa0c2539761e..d2fba9eae153 100644 --- a/drivers/net/wireless/iwlegacy/iwl4965-base.c +++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c @@ -40,7 +40,6 @@ #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <linux/firmware.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index ad3bdba6beed..57703d5209d7 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -1,5 +1,5 @@ -config IWLAGN - tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlagn) " +config IWLWIFI + tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) " depends on PCI && MAC80211 select FW_LOADER select NEW_LEDS @@ -39,14 +39,14 @@ config IWLAGN If you want to compile the driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read <file:Documentation/kbuild/modules.txt>. The - module will be called iwlagn. + module will be called iwlwifi. menu "Debugging Options" - depends on IWLAGN + depends on IWLWIFI config IWLWIFI_DEBUG - bool "Enable full debugging output in the iwlagn driver" - depends on IWLAGN + bool "Enable full debugging output in the iwlwifi driver" + depends on IWLWIFI ---help--- This option will enable debug tracing output for the iwlwifi drivers @@ -54,13 +54,13 @@ config IWLWIFI_DEBUG control which debug output is sent to the kernel log by setting the value in - /sys/class/net/wlan0/device/debug_level + /sys/module/iwlwifi/parameters/debug This entry will only exist if this option is enabled. To set a value, simply echo an 8-byte hex value to the same file: - % echo 0x43fff > /sys/class/net/wlan0/device/debug_level + % echo 0x43fff > /sys/module/iwlwifi/parameters/debug You can find the list of debug mask values in: drivers/net/wireless/iwlwifi/iwl-debug.h @@ -70,8 +70,8 @@ config IWLWIFI_DEBUG any problems you may encounter. config IWLWIFI_DEBUGFS - bool "iwlagn debugfs support" - depends on IWLAGN && MAC80211_DEBUGFS + bool "iwlwifi debugfs support" + depends on IWLWIFI && MAC80211_DEBUGFS ---help--- Enable creation of debugfs files for the iwlwifi drivers. This is a low-impact option that allows getting insight into the @@ -79,13 +79,13 @@ config IWLWIFI_DEBUGFS config IWLWIFI_DEBUG_EXPERIMENTAL_UCODE bool "Experimental uCode support" - depends on IWLAGN && IWLWIFI_DEBUG + depends on IWLWIFI && IWLWIFI_DEBUG ---help--- Enable use of experimental ucode for testing and debugging. config IWLWIFI_DEVICE_TRACING bool "iwlwifi device access tracing" - depends on IWLAGN + depends on IWLWIFI depends on EVENT_TRACING help Say Y here to trace all commands, including TX frames and IO @@ -104,27 +104,10 @@ endmenu config IWLWIFI_DEVICE_SVTOOL bool "iwlwifi device svtool support" - depends on IWLAGN + depends on IWLWIFI select NL80211_TESTMODE help This option enables the svtool support for iwlwifi device through NL80211_TESTMODE. svtool is a software validation tool that runs in the user space and interacts with the device in the kernel space through the generic netlink message via NL80211_TESTMODE channel. - -config IWL_P2P - bool "iwlwifi experimental P2P support" - depends on IWLAGN - help - This option enables experimental P2P support for some devices - based on microcode support. Since P2P support is still under - development, this option may even enable it for some devices - now that turn out to not support it in the future due to - microcode restrictions. - - To determine if your microcode supports the experimental P2P - offered by this option, check if the driver advertises AP - support when it is loaded. - - Say Y only if you want to experiment with P2P. - diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 48ab9142af38..c73e5ed8db5e 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -1,24 +1,24 @@ -# AGN -obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o -iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o -iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o -iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o +# WIFI +obj-$(CONFIG_IWLWIFI) += iwlwifi.o +iwlwifi-objs := iwl-agn.o iwl-agn-rs.o +iwlwifi-objs += iwl-agn-ucode.o iwl-agn-tx.o +iwlwifi-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o +iwlwifi-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o -iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-power.o -iwlagn-objs += iwl-rx.o iwl-sta.o -iwlagn-objs += iwl-scan.o iwl-led.o -iwlagn-objs += iwl-agn-rxon.o -iwlagn-objs += iwl-5000.o -iwlagn-objs += iwl-6000.o -iwlagn-objs += iwl-1000.o -iwlagn-objs += iwl-2000.o -iwlagn-objs += iwl-pci.o -iwlagn-objs += iwl-trans.o iwl-trans-rx-pcie.o iwl-trans-tx-pcie.o +iwlwifi-objs += iwl-core.o iwl-eeprom.o iwl-power.o +iwlwifi-objs += iwl-scan.o iwl-led.o +iwlwifi-objs += iwl-agn-rxon.o +iwlwifi-objs += iwl-5000.o +iwlwifi-objs += iwl-6000.o +iwlwifi-objs += iwl-1000.o +iwlwifi-objs += iwl-2000.o +iwlwifi-objs += iwl-pci.o +iwlwifi-objs += iwl-trans.o +iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o -iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o -iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o -iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o +iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o +iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o +iwlwifi-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o CFLAGS_iwl-devtrace.o := -I$(src) diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 01b49eb8c8ec..e12b48c2cff6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -30,7 +30,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> @@ -40,14 +39,18 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-sta.h" #include "iwl-agn.h" -#include "iwl-helpers.h" #include "iwl-agn-hw.h" +#include "iwl-shared.h" +#include "iwl-cfg.h" /* Highest firmware API version supported */ -#define IWL1000_UCODE_API_MAX 5 -#define IWL100_UCODE_API_MAX 5 +#define IWL1000_UCODE_API_MAX 6 +#define IWL100_UCODE_API_MAX 6 + +/* Oldest version we won't warn about */ +#define IWL1000_UCODE_API_OK 5 +#define IWL100_UCODE_API_OK 5 /* Lowest firmware API version supported */ #define IWL1000_UCODE_API_MIN 1 @@ -73,21 +76,21 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv) { /* want Celsius */ - priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; - priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; + hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; + hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; } /* NIC configuration for 1000 series */ static void iwl1000_nic_config(struct iwl_priv *priv) { /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* Setting digital SVR for 1000 card to 1.32V */ /* locking is acquired in iwl_set_bits_mask_prph() function */ - iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG, + iwl_set_bits_mask_prph(bus(priv), APMG_DIGITAL_SVR_REG, APMG_SVR_DIGITAL_VOLTAGE_1_32, ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); } @@ -124,44 +127,36 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv) priv->cfg->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; - priv->hw_params.scd_bc_tbls_size = - priv->cfg->base_params->num_of_queues * - sizeof(struct iwlagn_scd_bc_tbl); - priv->hw_params.tfd_size = sizeof(struct iwl_tfd); - priv->hw_params.max_stations = IWLAGN_STATION_COUNT; + hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; + hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; + hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | - BIT(IEEE80211_BAND_5GHZ); + hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); if (priv->cfg->rx_with_siso_diversity) - priv->hw_params.rx_chains_num = 1; + hw_params(priv).rx_chains_num = 1; else - priv->hw_params.rx_chains_num = + hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; - priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; + hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; iwl1000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ - priv->hw_params.sens = &iwl1000_sensitivity; - priv->hw_params.calib_init_cfg = + hw_params(priv).sens = &iwl1000_sensitivity; + hw_params(priv).calib_init_cfg = BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_TX_IQ_PERD) | BIT(IWL_CALIB_BASE_BAND); if (priv->cfg->need_dc_calib) - priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC); - - priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; + hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC); return 0; } @@ -191,7 +186,6 @@ static struct iwl_base_params iwl1000_base_params = { .max_ll_items = OTP_MAX_LL_ITEMS_1000, .shadow_ram_support = false, .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, @@ -201,12 +195,13 @@ static struct iwl_base_params iwl1000_base_params = { static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, .use_rts_for_aggregation = true, /* use rts/cts protection */ - .smps_mode = IEEE80211_SMPS_STATIC, + .smps_mode = IEEE80211_SMPS_DYNAMIC, }; #define IWL_DEVICE_1000 \ .fw_name_pre = IWL1000_FW_PRE, \ .ucode_api_max = IWL1000_UCODE_API_MAX, \ + .ucode_api_ok = IWL1000_UCODE_API_OK, \ .ucode_api_min = IWL1000_UCODE_API_MIN, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ @@ -228,6 +223,7 @@ struct iwl_cfg iwl1000_bg_cfg = { #define IWL_DEVICE_100 \ .fw_name_pre = IWL100_FW_PRE, \ .ucode_api_max = IWL100_UCODE_API_MAX, \ + .ucode_api_ok = IWL100_UCODE_API_OK, \ .ucode_api_min = IWL100_UCODE_API_MIN, \ .eeprom_ver = EEPROM_1000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index 0e13f0bb2e17..79431977a968 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -30,7 +30,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> @@ -40,17 +39,22 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-sta.h" #include "iwl-agn.h" -#include "iwl-helpers.h" #include "iwl-agn-hw.h" -#include "iwl-6000-hw.h" +#include "iwl-shared.h" +#include "iwl-cfg.h" /* Highest firmware API version supported */ -#define IWL2030_UCODE_API_MAX 5 -#define IWL2000_UCODE_API_MAX 5 -#define IWL105_UCODE_API_MAX 5 -#define IWL135_UCODE_API_MAX 5 +#define IWL2030_UCODE_API_MAX 6 +#define IWL2000_UCODE_API_MAX 6 +#define IWL105_UCODE_API_MAX 6 +#define IWL135_UCODE_API_MAX 6 + +/* Oldest version we won't warn about */ +#define IWL2030_UCODE_API_OK 5 +#define IWL2000_UCODE_API_OK 5 +#define IWL105_UCODE_API_OK 5 +#define IWL135_UCODE_API_OK 5 /* Lowest firmware API version supported */ #define IWL2030_UCODE_API_MIN 5 @@ -68,13 +72,13 @@ #define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode" #define IWL135_FW_PRE "iwlwifi-135-" -#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE #api ".ucode" +#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode" static void iwl2000_set_ct_threshold(struct iwl_priv *priv) { /* want Celsius */ - priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; - priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; + hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD; + hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; } /* NIC configuration for 2000 series */ @@ -83,7 +87,7 @@ static void iwl2000_nic_config(struct iwl_priv *priv) iwl_rf_config(priv); if (priv->cfg->iq_invert) - iwl_set_bit(priv, CSR_GP_DRIVER_REG, + iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); } @@ -119,45 +123,37 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv) priv->cfg->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; - priv->hw_params.scd_bc_tbls_size = - priv->cfg->base_params->num_of_queues * - sizeof(struct iwlagn_scd_bc_tbl); - priv->hw_params.tfd_size = sizeof(struct iwl_tfd); - priv->hw_params.max_stations = IWLAGN_STATION_COUNT; + hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; + hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; + hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | - BIT(IEEE80211_BAND_5GHZ); + hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ); - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); if (priv->cfg->rx_with_siso_diversity) - priv->hw_params.rx_chains_num = 1; + hw_params(priv).rx_chains_num = 1; else - priv->hw_params.rx_chains_num = + hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; - priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; + hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; iwl2000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ - priv->hw_params.sens = &iwl2000_sensitivity; - priv->hw_params.calib_init_cfg = + hw_params(priv).sens = &iwl2000_sensitivity; + hw_params(priv).calib_init_cfg = BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_BASE_BAND); if (priv->cfg->need_dc_calib) - priv->hw_params.calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX; + hw_params(priv).calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX; if (priv->cfg->need_temp_offset_calib) - priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); - - priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; + hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); return 0; } @@ -175,7 +171,7 @@ static struct iwl_lib_ops iwl2000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REGULATORY_BAND_NO_HT40, }, - .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + .update_enhanced_txpower = iwl_eeprom_enhanced_txpower, }, .temperature = iwlagn_temperature, }; @@ -196,7 +192,7 @@ static struct iwl_lib_ops iwl2030_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REGULATORY_BAND_NO_HT40, }, - .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + .update_enhanced_txpower = iwl_eeprom_enhanced_txpower, }, .temperature = iwlagn_temperature, }; @@ -209,7 +205,6 @@ static struct iwl_base_params iwl2000_base_params = { .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, @@ -217,6 +212,7 @@ static struct iwl_base_params iwl2000_base_params = { .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 512, .shadow_reg_enable = true, + .hd_v2 = true, }; @@ -228,7 +224,6 @@ static struct iwl_base_params iwl2030_base_params = { .max_ll_items = OTP_MAX_LL_ITEMS_2x00, .shadow_ram_support = true, .led_compensation = 57, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, @@ -236,6 +231,7 @@ static struct iwl_base_params iwl2030_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .shadow_reg_enable = true, + .hd_v2 = true, }; static struct iwl_ht_params iwl2000_ht_params = { @@ -256,6 +252,7 @@ static struct iwl_bt_params iwl2030_bt_params = { #define IWL_DEVICE_2000 \ .fw_name_pre = IWL2000_FW_PRE, \ .ucode_api_max = IWL2000_UCODE_API_MAX, \ + .ucode_api_ok = IWL2000_UCODE_API_OK, \ .ucode_api_min = IWL2000_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ @@ -263,6 +260,7 @@ static struct iwl_bt_params iwl2030_bt_params = { .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ + .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ .iq_invert = true \ @@ -277,9 +275,16 @@ struct iwl_cfg iwl2000_2bg_cfg = { IWL_DEVICE_2000, }; +struct iwl_cfg iwl2000_2bgn_d_cfg = { + .name = "2000D Series 2x2 BGN", + IWL_DEVICE_2000, + .ht_params = &iwl2000_ht_params, +}; + #define IWL_DEVICE_2030 \ .fw_name_pre = IWL2030_FW_PRE, \ .ucode_api_max = IWL2030_UCODE_API_MAX, \ + .ucode_api_ok = IWL2030_UCODE_API_OK, \ .ucode_api_min = IWL2030_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ @@ -288,6 +293,7 @@ struct iwl_cfg iwl2000_2bg_cfg = { .bt_params = &iwl2030_bt_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ + .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ .adv_pm = true, \ .iq_invert = true \ @@ -306,6 +312,7 @@ struct iwl_cfg iwl2030_2bg_cfg = { #define IWL_DEVICE_105 \ .fw_name_pre = IWL105_FW_PRE, \ .ucode_api_max = IWL105_UCODE_API_MAX, \ + .ucode_api_ok = IWL105_UCODE_API_OK, \ .ucode_api_min = IWL105_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ @@ -313,6 +320,7 @@ struct iwl_cfg iwl2030_2bg_cfg = { .base_params = &iwl2000_base_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ + .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ .adv_pm = true, \ .rx_with_siso_diversity = true, \ @@ -329,9 +337,16 @@ struct iwl_cfg iwl105_bgn_cfg = { .ht_params = &iwl2000_ht_params, }; +struct iwl_cfg iwl105_bgn_d_cfg = { + .name = "105D Series 1x1 BGN", + IWL_DEVICE_105, + .ht_params = &iwl2000_ht_params, +}; + #define IWL_DEVICE_135 \ .fw_name_pre = IWL135_FW_PRE, \ .ucode_api_max = IWL135_UCODE_API_MAX, \ + .ucode_api_ok = IWL135_UCODE_API_OK, \ .ucode_api_min = IWL135_UCODE_API_MIN, \ .eeprom_ver = EEPROM_2000_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \ @@ -340,6 +355,7 @@ struct iwl_cfg iwl105_bgn_cfg = { .bt_params = &iwl2030_bt_params, \ .need_dc_calib = true, \ .need_temp_offset_calib = true, \ + .temp_offset_v2 = true, \ .led_mode = IWL_LED_RF_STATE, \ .adv_pm = true, \ .rx_with_siso_diversity = true, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c95cefd529dc..c511c98a89a8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -31,7 +31,6 @@ #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> @@ -41,12 +40,11 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-sta.h" -#include "iwl-helpers.h" #include "iwl-agn.h" #include "iwl-agn-hw.h" -#include "iwl-5000-hw.h" #include "iwl-trans.h" +#include "iwl-shared.h" +#include "iwl-cfg.h" /* Highest firmware API version supported */ #define IWL5000_UCODE_API_MAX 5 @@ -69,27 +67,27 @@ static void iwl5000_nic_config(struct iwl_priv *priv) iwl_rf_config(priv); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->shrd->lock, flags); /* W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), * causing ME FW to lose ownership and not being able to obtain it back. */ - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, + iwl_set_bits_mask_prph(bus(priv), APMG_PS_CTRL_REG, APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); } static struct iwl_sensitivity_ranges iwl5000_sensitivity = { - .min_nrg_cck = 95, + .min_nrg_cck = 100, .max_nrg_cck = 0, /* not used, set to 0 */ .auto_corr_min_ofdm = 90, .auto_corr_min_ofdm_mrc = 170, - .auto_corr_min_ofdm_x1 = 120, - .auto_corr_min_ofdm_mrc_x1 = 240, + .auto_corr_min_ofdm_x1 = 105, + .auto_corr_min_ofdm_mrc_x1 = 220, .auto_corr_max_ofdm = 120, .auto_corr_max_ofdm_mrc = 210, @@ -98,10 +96,10 @@ static struct iwl_sensitivity_ranges iwl5000_sensitivity = { .auto_corr_min_cck = 125, .auto_corr_max_cck = 200, - .auto_corr_min_cck_mrc = 170, + .auto_corr_min_cck_mrc = 200, .auto_corr_max_cck_mrc = 400, - .nrg_th_cck = 95, - .nrg_th_ofdm = 95, + .nrg_th_cck = 100, + .nrg_th_ofdm = 100, .barker_corr_th_min = 190, .barker_corr_th_min_mrc = 390, @@ -134,19 +132,34 @@ static struct iwl_sensitivity_ranges iwl5150_sensitivity = { .nrg_th_cca = 62, }; +#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) + +static s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) +{ + u16 temperature, voltage; + __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv, + EEPROM_KELVIN_TEMPERATURE); + + temperature = le16_to_cpu(temp_calib[0]); + voltage = le16_to_cpu(temp_calib[1]); + + /* offset = temp - volt / coeff */ + return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); +} + static void iwl5150_set_ct_threshold(struct iwl_priv *priv) { const s32 volt2temp_coef = IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF; s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD_LEGACY) - iwl_temp_calib_to_offset(priv); - priv->hw_params.ct_kill_threshold = threshold * volt2temp_coef; + hw_params(priv).ct_kill_threshold = threshold * volt2temp_coef; } static void iwl5000_set_ct_threshold(struct iwl_priv *priv) { /* want Celsius */ - priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; + hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD_LEGACY; } static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) @@ -156,39 +169,32 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) priv->cfg->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; - priv->hw_params.scd_bc_tbls_size = - priv->cfg->base_params->num_of_queues * - sizeof(struct iwlagn_scd_bc_tbl); - priv->hw_params.tfd_size = sizeof(struct iwl_tfd); - priv->hw_params.max_stations = IWLAGN_STATION_COUNT; + hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; + hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; + hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; - priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); + hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; + hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; iwl5000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ - priv->hw_params.sens = &iwl5000_sensitivity; - priv->hw_params.calib_init_cfg = + hw_params(priv).sens = &iwl5000_sensitivity; + hw_params(priv).calib_init_cfg = BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_TX_IQ_PERD) | BIT(IWL_CALIB_BASE_BAND); - priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; - return 0; } @@ -199,38 +205,31 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv) priv->cfg->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; - priv->hw_params.scd_bc_tbls_size = - priv->cfg->base_params->num_of_queues * - sizeof(struct iwlagn_scd_bc_tbl); - priv->hw_params.tfd_size = sizeof(struct iwl_tfd); - priv->hw_params.max_stations = IWLAGN_STATION_COUNT; + hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWLAGN_RTC_INST_SIZE; + hw_params(priv).max_data_size = IWLAGN_RTC_DATA_SIZE; + hw_params(priv).max_inst_size = IWLAGN_RTC_INST_SIZE; - priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); - priv->hw_params.rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; - priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); + hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; + hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; iwl5150_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ - priv->hw_params.sens = &iwl5150_sensitivity; - priv->hw_params.calib_init_cfg = + hw_params(priv).sens = &iwl5150_sensitivity; + hw_params(priv).calib_init_cfg = BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_BASE_BAND); if (priv->cfg->need_dc_calib) - priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_DC); - - priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; + hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC); return 0; } @@ -252,7 +251,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, { /* * MULTI-FIXME - * See iwl_mac_channel_switch. + * See iwlagn_mac_channel_switch. */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl5000_channel_switch_cmd cmd; @@ -315,7 +314,7 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv, return -EFAULT; } - return trans_send_cmd(&priv->trans, &hcmd); + return iwl_trans_send_cmd(trans(priv), &hcmd); } static struct iwl_lib_ops iwl5000_lib = { @@ -360,7 +359,6 @@ static struct iwl_base_params iwl5000_base_params = { .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES, .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL, .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF, .chain_noise_scale = 1000, .wd_timeout = IWL_LONG_WD_TIMEOUT, diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h deleted file mode 100644 index b27986e57c92..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h +++ /dev/null @@ -1,81 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - *****************************************************************************/ -/* - * Please use this file (iwl-6000-hw.h) only for hardware-related definitions. - * Use iwl-commands.h for uCode API definitions. - */ - -#ifndef __iwl_6000_hw_h__ -#define __iwl_6000_hw_h__ - -#define IWL60_RTC_INST_LOWER_BOUND (0x000000) -#define IWL60_RTC_INST_UPPER_BOUND (0x040000) -#define IWL60_RTC_DATA_LOWER_BOUND (0x800000) -#define IWL60_RTC_DATA_UPPER_BOUND (0x814000) -#define IWL60_RTC_INST_SIZE \ - (IWL60_RTC_INST_UPPER_BOUND - IWL60_RTC_INST_LOWER_BOUND) -#define IWL60_RTC_DATA_SIZE \ - (IWL60_RTC_DATA_UPPER_BOUND - IWL60_RTC_DATA_LOWER_BOUND) - -#endif /* __iwl_6000_hw_h__ */ - diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 973d1972e8cc..c840c78278db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -30,7 +30,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> @@ -40,17 +39,19 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-sta.h" #include "iwl-agn.h" -#include "iwl-helpers.h" #include "iwl-agn-hw.h" -#include "iwl-6000-hw.h" #include "iwl-trans.h" +#include "iwl-shared.h" +#include "iwl-cfg.h" /* Highest firmware API version supported */ #define IWL6000_UCODE_API_MAX 4 #define IWL6050_UCODE_API_MAX 5 -#define IWL6000G2_UCODE_API_MAX 5 +#define IWL6000G2_UCODE_API_MAX 6 + +/* Oldest version we won't warn about */ +#define IWL6000G2_UCODE_API_OK 5 /* Lowest firmware API version supported */ #define IWL6000_UCODE_API_MIN 4 @@ -72,15 +73,15 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv) { /* want Celsius */ - priv->hw_params.ct_kill_threshold = CT_KILL_THRESHOLD; - priv->hw_params.ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; + hw_params(priv).ct_kill_threshold = CT_KILL_THRESHOLD; + hw_params(priv).ct_kill_exit_threshold = CT_KILL_EXIT_THRESHOLD; } static void iwl6050_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ if (iwlagn_eeprom_calib_version(priv) >= 6) - iwl_set_bit(priv, CSR_GP_DRIVER_REG, + iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); } @@ -88,9 +89,9 @@ static void iwl6150_additional_nic_config(struct iwl_priv *priv) { /* Indicate calibration version to uCode. */ if (iwlagn_eeprom_calib_version(priv) >= 6) - iwl_set_bit(priv, CSR_GP_DRIVER_REG, + iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); - iwl_set_bit(priv, CSR_GP_DRIVER_REG, + iwl_set_bit(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_6050_1x2); } @@ -102,7 +103,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv) /* no locking required for register write */ if (priv->cfg->pa_type == IWL_PA_INTERNAL) { /* 2x2 IPA phy type */ - iwl_write32(priv, CSR_GP_DRIVER_REG, + iwl_write32(bus(priv), CSR_GP_DRIVER_REG, CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); } /* do additional nic configuration if needed */ @@ -111,7 +112,7 @@ static void iwl6000_nic_config(struct iwl_priv *priv) } static struct iwl_sensitivity_ranges iwl6000_sensitivity = { - .min_nrg_cck = 97, + .min_nrg_cck = 110, .max_nrg_cck = 0, /* not used, set to 0 */ .auto_corr_min_ofdm = 80, .auto_corr_min_ofdm_mrc = 128, @@ -127,11 +128,11 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = { .auto_corr_max_cck = 175, .auto_corr_min_cck_mrc = 160, .auto_corr_max_cck_mrc = 310, - .nrg_th_cck = 97, - .nrg_th_ofdm = 100, + .nrg_th_cck = 110, + .nrg_th_ofdm = 110, .barker_corr_th_min = 190, - .barker_corr_th_min_mrc = 390, + .barker_corr_th_min_mrc = 336, .nrg_th_cca = 62, }; @@ -142,45 +143,38 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv) priv->cfg->base_params->num_of_queues = iwlagn_mod_params.num_of_queues; - priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues; - priv->hw_params.scd_bc_tbls_size = - priv->cfg->base_params->num_of_queues * - sizeof(struct iwlagn_scd_bc_tbl); - priv->hw_params.tfd_size = sizeof(struct iwl_tfd); - priv->hw_params.max_stations = IWLAGN_STATION_COUNT; + hw_params(priv).max_txq_num = priv->cfg->base_params->num_of_queues; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; - priv->hw_params.max_data_size = IWL60_RTC_DATA_SIZE; - priv->hw_params.max_inst_size = IWL60_RTC_INST_SIZE; + hw_params(priv).max_data_size = IWL60_RTC_DATA_SIZE; + hw_params(priv).max_inst_size = IWL60_RTC_INST_SIZE; - priv->hw_params.ht40_channel = BIT(IEEE80211_BAND_2GHZ) | + hw_params(priv).ht40_channel = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ); - priv->hw_params.tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); + hw_params(priv).tx_chains_num = num_of_ant(priv->cfg->valid_tx_ant); if (priv->cfg->rx_with_siso_diversity) - priv->hw_params.rx_chains_num = 1; + hw_params(priv).rx_chains_num = 1; else - priv->hw_params.rx_chains_num = + hw_params(priv).rx_chains_num = num_of_ant(priv->cfg->valid_rx_ant); - priv->hw_params.valid_tx_ant = priv->cfg->valid_tx_ant; - priv->hw_params.valid_rx_ant = priv->cfg->valid_rx_ant; + hw_params(priv).valid_tx_ant = priv->cfg->valid_tx_ant; + hw_params(priv).valid_rx_ant = priv->cfg->valid_rx_ant; iwl6000_set_ct_threshold(priv); /* Set initial sensitivity parameters */ /* Set initial calibration set */ - priv->hw_params.sens = &iwl6000_sensitivity; - priv->hw_params.calib_init_cfg = + hw_params(priv).sens = &iwl6000_sensitivity; + hw_params(priv).calib_init_cfg = BIT(IWL_CALIB_XTAL) | BIT(IWL_CALIB_LO) | BIT(IWL_CALIB_TX_IQ) | BIT(IWL_CALIB_BASE_BAND); if (priv->cfg->need_dc_calib) - priv->hw_params.calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX; + hw_params(priv).calib_rt_cfg |= IWL_CALIB_CFG_DC_IDX; if (priv->cfg->need_temp_offset_calib) - priv->hw_params.calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); - - priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS; + hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET); return 0; } @@ -190,7 +184,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, { /* * MULTI-FIXME - * See iwl_mac_channel_switch. + * See iwlagn_mac_channel_switch. */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl6000_channel_switch_cmd cmd; @@ -253,7 +247,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv, return -EFAULT; } - return trans_send_cmd(&priv->trans, &hcmd); + return iwl_trans_send_cmd(trans(priv), &hcmd); } static struct iwl_lib_ops iwl6000_lib = { @@ -270,7 +264,7 @@ static struct iwl_lib_ops iwl6000_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + .update_enhanced_txpower = iwl_eeprom_enhanced_txpower, }, .temperature = iwlagn_temperature, }; @@ -292,7 +286,7 @@ static struct iwl_lib_ops iwl6030_lib = { EEPROM_6000_REG_BAND_24_HT40_CHANNELS, EEPROM_REG_BAND_52_HT40_CHANNELS }, - .update_enhanced_txpower = iwlcore_eeprom_enhanced_txpower, + .update_enhanced_txpower = iwl_eeprom_enhanced_txpower, }, .temperature = iwlagn_temperature, }; @@ -305,7 +299,6 @@ static struct iwl_base_params iwl6000_base_params = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, @@ -323,7 +316,6 @@ static struct iwl_base_params iwl6050_base_params = { .max_ll_items = OTP_MAX_LL_ITEMS_6x50, .shadow_ram_support = true, .led_compensation = 51, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, @@ -340,7 +332,6 @@ static struct iwl_base_params iwl6000_g2_base_params = { .max_ll_items = OTP_MAX_LL_ITEMS_6x00, .shadow_ram_support = true, .led_compensation = 57, - .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS, .adv_thermal_throttle = true, .support_ct_kill_exit = true, .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF, @@ -365,8 +356,9 @@ static struct iwl_bt_params iwl6000_bt_params = { }; #define IWL_DEVICE_6005 \ - .fw_name_pre = IWL6005_FW_PRE, \ + .fw_name_pre = IWL6005_FW_PRE, \ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ + .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ .eeprom_ver = EEPROM_6005_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \ @@ -392,9 +384,22 @@ struct iwl_cfg iwl6005_2bg_cfg = { IWL_DEVICE_6005, }; +struct iwl_cfg iwl6005_2agn_sff_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6205S AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + +struct iwl_cfg iwl6005_2agn_d_cfg = { + .name = "Intel(R) Centrino(R) Advanced-N 6205D AGN", + IWL_DEVICE_6005, + .ht_params = &iwl6000_ht_params, +}; + #define IWL_DEVICE_6030 \ - .fw_name_pre = IWL6030_FW_PRE, \ + .fw_name_pre = IWL6030_FW_PRE, \ .ucode_api_max = IWL6000G2_UCODE_API_MAX, \ + .ucode_api_ok = IWL6000G2_UCODE_API_OK, \ .ucode_api_min = IWL6000G2_UCODE_API_MIN, \ .eeprom_ver = EEPROM_6030_EEPROM_VERSION, \ .eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c index 72d6297602b8..03bac48558b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c @@ -93,12 +93,12 @@ int iwl_send_calib_results(struct iwl_priv *priv) }; for (i = 0; i < IWL_CALIB_MAX; i++) { - if ((BIT(i) & priv->hw_params.calib_init_cfg) && + if ((BIT(i) & hw_params(priv).calib_init_cfg) && priv->calib_results[i].buf) { hcmd.len[0] = priv->calib_results[i].buf_len; hcmd.data[0] = priv->calib_results[i].buf; hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; - ret = trans_send_cmd(&priv->trans, &hcmd); + ret = iwl_trans_send_cmd(trans(priv), &hcmd); if (ret) { IWL_ERR(priv, "Error %d iteration %d\n", ret, i); @@ -174,7 +174,7 @@ static int iwl_sens_energy_cck(struct iwl_priv *priv, u32 max_false_alarms = MAX_FA_CCK * rx_enable_time; u32 min_false_alarms = MIN_FA_CCK * rx_enable_time; struct iwl_sensitivity_data *data = NULL; - const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens; data = &(priv->sensitivity_data); @@ -357,7 +357,7 @@ static int iwl_sens_auto_corr_ofdm(struct iwl_priv *priv, u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time; u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time; struct iwl_sensitivity_data *data = NULL; - const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens; data = &(priv->sensitivity_data); @@ -484,7 +484,7 @@ static int iwl_sensitivity_write(struct iwl_priv *priv) memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]), sizeof(u16)*HD_TABLE_SIZE); - return trans_send_cmd(&priv->trans, &cmd_out); + return iwl_trans_send_cmd(trans(priv), &cmd_out); } /* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */ @@ -505,28 +505,53 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv) iwl_prepare_legacy_sensitivity_tbl(priv, data, &cmd.enhance_table[0]); - cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = - HD_INA_NON_SQUARE_DET_OFDM_DATA; - cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = - HD_INA_NON_SQUARE_DET_CCK_DATA; - cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] = - HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA; - cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] = - HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA; - cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = - HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA; - cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] = - HD_OFDM_NON_SQUARE_DET_SLOPE_DATA; - cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] = - HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA; - cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] = - HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA; - cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = - HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA; - cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] = - HD_CCK_NON_SQUARE_DET_SLOPE_DATA; - cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] = - HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA; + if (priv->cfg->base_params->hd_v2) { + cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = + HD_INA_NON_SQUARE_DET_OFDM_DATA_V2; + cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = + HD_INA_NON_SQUARE_DET_CCK_DATA_V2; + cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] = + HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2; + cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] = + HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2; + cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = + HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2; + cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] = + HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2; + cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] = + HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2; + cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] = + HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2; + cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = + HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2; + cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] = + HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2; + cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] = + HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2; + } else { + cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX] = + HD_INA_NON_SQUARE_DET_OFDM_DATA_V1; + cmd.enhance_table[HD_INA_NON_SQUARE_DET_CCK_INDEX] = + HD_INA_NON_SQUARE_DET_CCK_DATA_V1; + cmd.enhance_table[HD_CORR_11_INSTEAD_OF_CORR_9_EN_INDEX] = + HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1; + cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_INDEX] = + HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1; + cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = + HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1; + cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_SLOPE_INDEX] = + HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1; + cmd.enhance_table[HD_OFDM_NON_SQUARE_DET_INTERCEPT_INDEX] = + HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1; + cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_MRC_INDEX] = + HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1; + cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_INDEX] = + HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1; + cmd.enhance_table[HD_CCK_NON_SQUARE_DET_SLOPE_INDEX] = + HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1; + cmd.enhance_table[HD_CCK_NON_SQUARE_DET_INTERCEPT_INDEX] = + HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1; + } /* Update uCode's "work" table, and copy it to DSP */ cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE; @@ -548,7 +573,7 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv) &(cmd.enhance_table[HD_INA_NON_SQUARE_DET_OFDM_INDEX]), sizeof(u16)*ENHANCE_HD_TABLE_ENTRIES); - return trans_send_cmd(&priv->trans, &cmd_out); + return iwl_trans_send_cmd(trans(priv), &cmd_out); } void iwl_init_sensitivity(struct iwl_priv *priv) @@ -556,7 +581,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv) int ret = 0; int i; struct iwl_sensitivity_data *data = NULL; - const struct iwl_sensitivity_ranges *ranges = priv->hw_params.sens; + const struct iwl_sensitivity_ranges *ranges = hw_params(priv).sens; if (priv->disable_sens_cal) return; @@ -633,13 +658,13 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv) return; } - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->shrd->lock, flags); rx_info = &priv->statistics.rx_non_phy; ofdm = &priv->statistics.rx_ofdm; cck = &priv->statistics.rx_cck; if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { IWL_DEBUG_CALIB(priv, "<< invalid data.\n"); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); return; } @@ -663,7 +688,7 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv) statis.beacon_energy_c = le32_to_cpu(rx_info->beacon_energy_c); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); IWL_DEBUG_CALIB(priv, "rx_enable_time = %u usecs\n", rx_enable_time); @@ -741,12 +766,9 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, u8 first_chain; u16 i = 0; - average_sig[0] = data->chain_signal_a / - priv->cfg->base_params->chain_noise_num_beacons; - average_sig[1] = data->chain_signal_b / - priv->cfg->base_params->chain_noise_num_beacons; - average_sig[2] = data->chain_signal_c / - priv->cfg->base_params->chain_noise_num_beacons; + average_sig[0] = data->chain_signal_a / IWL_CAL_NUM_BEACONS; + average_sig[1] = data->chain_signal_b / IWL_CAL_NUM_BEACONS; + average_sig[2] = data->chain_signal_c / IWL_CAL_NUM_BEACONS; if (average_sig[0] >= average_sig[1]) { max_average_sig = average_sig[0]; @@ -796,21 +818,21 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, * To be safe, simply mask out any chains that we know * are not on the device. */ - active_chains &= priv->hw_params.valid_rx_ant; + active_chains &= hw_params(priv).valid_rx_ant; num_tx_chains = 0; for (i = 0; i < NUM_RX_CHAINS; i++) { /* loops on all the bits of * priv->hw_setting.valid_tx_ant */ u8 ant_msk = (1 << i); - if (!(priv->hw_params.valid_tx_ant & ant_msk)) + if (!(hw_params(priv).valid_tx_ant & ant_msk)) continue; num_tx_chains++; if (data->disconn_array[i] == 0) /* there is a Tx antenna connected */ break; - if (num_tx_chains == priv->hw_params.tx_chains_num && + if (num_tx_chains == hw_params(priv).tx_chains_num && data->disconn_array[i]) { /* * If all chains are disconnected @@ -827,12 +849,13 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig, } } - if (active_chains != priv->hw_params.valid_rx_ant && + if (active_chains != hw_params(priv).valid_rx_ant && active_chains != priv->chain_noise_data.active_chains) IWL_DEBUG_CALIB(priv, "Detected that not all antennas are connected! " "Connected: %#x, valid: %#x.\n", - active_chains, priv->hw_params.valid_rx_ant); + active_chains, + hw_params(priv).valid_rx_ant); /* Save for use within RXON, TX, SCAN commands, etc. */ data->active_chains = active_chains; @@ -892,7 +915,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv, priv->phy_calib_chain_noise_gain_cmd); cmd.delta_gain_1 = data->delta_gain_code[1]; cmd.delta_gain_2 = data->delta_gain_code[2]; - trans_send_cmd_pdu(&priv->trans, REPLY_PHY_CALIBRATION_CMD, + iwl_trans_send_cmd_pdu(trans(priv), REPLY_PHY_CALIBRATION_CMD, CMD_ASYNC, sizeof(cmd), &cmd); data->radio_write = 1; @@ -950,13 +973,13 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) return; } - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->shrd->lock, flags); rx_info = &priv->statistics.rx_non_phy; if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) { IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n"); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); return; } @@ -971,7 +994,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) if ((rxon_chnum != stat_chnum) || (rxon_band24 != stat_band24)) { IWL_DEBUG_CALIB(priv, "Stats not from chan=%d, band24=%d\n", rxon_chnum, rxon_band24); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); return; } @@ -990,7 +1013,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER; chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); data->beacon_count++; @@ -1012,8 +1035,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) /* If this is the "chain_noise_num_beacons", determine: * 1) Disconnected antennas (using signal strengths) * 2) Differential gain (using silence noise) to balance receivers */ - if (data->beacon_count != - priv->cfg->base_params->chain_noise_num_beacons) + if (data->beacon_count != IWL_CAL_NUM_BEACONS) return; /* Analyze signal for disconnected antenna */ @@ -1021,7 +1043,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) priv->cfg->bt_params->advanced_bt_coexist) { /* Disable disconnected antenna algorithm for advanced bt coex, assuming valid antennas are connected */ - data->active_chains = priv->hw_params.valid_rx_ant; + data->active_chains = hw_params(priv).valid_rx_ant; for (i = 0; i < NUM_RX_CHAINS; i++) if (!(data->active_chains & (1<<i))) data->disconn_array[i] = 1; @@ -1029,12 +1051,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv) iwl_find_disconn_antenna(priv, average_sig, data); /* Analyze noise for rx balance */ - average_noise[0] = data->chain_noise_a / - priv->cfg->base_params->chain_noise_num_beacons; - average_noise[1] = data->chain_noise_b / - priv->cfg->base_params->chain_noise_num_beacons; - average_noise[2] = data->chain_noise_c / - priv->cfg->base_params->chain_noise_num_beacons; + average_noise[0] = data->chain_noise_a / IWL_CAL_NUM_BEACONS; + average_noise[1] = data->chain_noise_b / IWL_CAL_NUM_BEACONS; + average_noise[2] = data->chain_noise_c / IWL_CAL_NUM_BEACONS; for (i = 0; i < NUM_RX_CHAINS; i++) { if (!(data->disconn_array[i]) && diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c deleted file mode 100644 index b8347db850e7..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c +++ /dev/null @@ -1,299 +0,0 @@ -/****************************************************************************** - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - * BSD LICENSE - * - * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> - -#include <net/mac80211.h> - -#include "iwl-commands.h" -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-debug.h" -#include "iwl-agn.h" -#include "iwl-io.h" - -/****************************************************************************** - * - * EEPROM related functions - * -******************************************************************************/ - -int iwl_eeprom_check_version(struct iwl_priv *priv) -{ - u16 eeprom_ver; - u16 calib_ver; - - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - calib_ver = iwlagn_eeprom_calib_version(priv); - - if (eeprom_ver < priv->cfg->eeprom_ver || - calib_ver < priv->cfg->eeprom_calib_ver) - goto err; - - IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n", - eeprom_ver, calib_ver); - - return 0; -err: - IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x " - "CALIB=0x%x < 0x%x\n", - eeprom_ver, priv->cfg->eeprom_ver, - calib_ver, priv->cfg->eeprom_calib_ver); - return -EINVAL; - -} - -int iwl_eeprom_check_sku(struct iwl_priv *priv) -{ - u16 radio_cfg; - - if (!priv->cfg->sku) { - /* not using sku overwrite */ - priv->cfg->sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP); - if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE && - !priv->cfg->ht_params) { - IWL_ERR(priv, "Invalid 11n configuration\n"); - return -EINVAL; - } - } - if (!priv->cfg->sku) { - IWL_ERR(priv, "Invalid device sku\n"); - return -EINVAL; - } - - IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku); - - if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) { - /* not using .cfg overwrite */ - radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); - priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg); - priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg); - if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) { - IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n", - priv->cfg->valid_tx_ant, - priv->cfg->valid_rx_ant); - return -EINVAL; - } - IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n", - priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant); - } - /* - * for some special cases, - * EEPROM did not reflect the correct antenna setting - * so overwrite the valid tx/rx antenna from .cfg - */ - return 0; -} - -void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) -{ - const u8 *addr = iwl_eeprom_query_addr(priv, - EEPROM_MAC_ADDRESS); - memcpy(mac, addr, ETH_ALEN); -} - -/** - * iwl_get_max_txpower_avg - get the highest tx power from all chains. - * find the highest tx power from all chains for the channel - */ -static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, - struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, - int element, s8 *max_txpower_in_half_dbm) -{ - s8 max_txpower_avg = 0; /* (dBm) */ - - /* Take the highest tx power from any valid chains */ - if ((priv->cfg->valid_tx_ant & ANT_A) && - (enhanced_txpower[element].chain_a_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].chain_a_max; - if ((priv->cfg->valid_tx_ant & ANT_B) && - (enhanced_txpower[element].chain_b_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].chain_b_max; - if ((priv->cfg->valid_tx_ant & ANT_C) && - (enhanced_txpower[element].chain_c_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].chain_c_max; - if (((priv->cfg->valid_tx_ant == ANT_AB) | - (priv->cfg->valid_tx_ant == ANT_BC) | - (priv->cfg->valid_tx_ant == ANT_AC)) && - (enhanced_txpower[element].mimo2_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].mimo2_max; - if ((priv->cfg->valid_tx_ant == ANT_ABC) && - (enhanced_txpower[element].mimo3_max > max_txpower_avg)) - max_txpower_avg = enhanced_txpower[element].mimo3_max; - - /* - * max. tx power in EEPROM is in 1/2 dBm format - * convert from 1/2 dBm to dBm (round-up convert) - * but we also do not want to loss 1/2 dBm resolution which - * will impact performance - */ - *max_txpower_in_half_dbm = max_txpower_avg; - return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1); -} - -static void -iwlcore_eeprom_enh_txp_read_element(struct iwl_priv *priv, - struct iwl_eeprom_enhanced_txpwr *txp, - s8 max_txpower_avg) -{ - int ch_idx; - bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ; - enum ieee80211_band band; - - band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ? - IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; - - for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) { - struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx]; - - /* update matching channel or from common data only */ - if (txp->channel != 0 && ch_info->channel != txp->channel) - continue; - - /* update matching band only */ - if (band != ch_info->band) - continue; - - if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) { - ch_info->max_power_avg = max_txpower_avg; - ch_info->curr_txpow = max_txpower_avg; - ch_info->scan_power = max_txpower_avg; - } - - if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg) - ch_info->ht40_max_power_avg = max_txpower_avg; - } -} - -#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT) -#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr) -#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE) - -#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \ - ? # x " " : "") - -void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv) -{ - struct iwl_eeprom_enhanced_txpwr *txp_array, *txp; - int idx, entries; - __le16 *txp_len; - s8 max_txp_avg, max_txp_avg_halfdbm; - - BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8); - - /* the length is in 16-bit words, but we want entries */ - txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS); - entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN; - - txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS); - - for (idx = 0; idx < entries; idx++) { - txp = &txp_array[idx]; - /* skip invalid entries */ - if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID)) - continue; - - IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n", - (txp->channel && (txp->flags & - IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ? - "Common " : (txp->channel) ? - "Channel" : "Common", - (txp->channel), - TXP_CHECK_AND_PRINT(VALID), - TXP_CHECK_AND_PRINT(BAND_52G), - TXP_CHECK_AND_PRINT(OFDM), - TXP_CHECK_AND_PRINT(40MHZ), - TXP_CHECK_AND_PRINT(HT_AP), - TXP_CHECK_AND_PRINT(RES1), - TXP_CHECK_AND_PRINT(RES2), - TXP_CHECK_AND_PRINT(COMMON_TYPE), - txp->flags); - IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x " - "chain_B: 0X%02x chain_C: 0X%02x\n", - txp->chain_a_max, txp->chain_b_max, - txp->chain_c_max); - IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x " - "MIMO3: 0x%02x High 20_on_40: 0x%02x " - "Low 20_on_40: 0x%02x\n", - txp->mimo2_max, txp->mimo3_max, - ((txp->delta_20_in_40 & 0xf0) >> 4), - (txp->delta_20_in_40 & 0x0f)); - - max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx, - &max_txp_avg_halfdbm); - - /* - * Update the user limit values values to the highest - * power supported by any channel - */ - if (max_txp_avg > priv->tx_power_user_lmt) - priv->tx_power_user_lmt = max_txp_avg; - if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm) - priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm; - - iwlcore_eeprom_enh_txp_read_element(priv, txp, max_txp_avg); - } -} diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index 0e5b842529c4..123ef5e129d5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -78,10 +78,23 @@ #define IWLAGN_RTC_DATA_SIZE (IWLAGN_RTC_DATA_UPPER_BOUND - \ IWLAGN_RTC_DATA_LOWER_BOUND) +#define IWL60_RTC_INST_LOWER_BOUND (0x000000) +#define IWL60_RTC_INST_UPPER_BOUND (0x040000) +#define IWL60_RTC_DATA_LOWER_BOUND (0x800000) +#define IWL60_RTC_DATA_UPPER_BOUND (0x814000) +#define IWL60_RTC_INST_SIZE \ + (IWL60_RTC_INST_UPPER_BOUND - IWL60_RTC_INST_LOWER_BOUND) +#define IWL60_RTC_DATA_SIZE \ + (IWL60_RTC_DATA_UPPER_BOUND - IWL60_RTC_DATA_LOWER_BOUND) + /* RSSI to dBm */ #define IWLAGN_RSSI_OFFSET 44 -#define IWLAGN_DEFAULT_TX_RETRY 15 +#define IWLAGN_DEFAULT_TX_RETRY 15 +#define IWLAGN_MGMT_DFAULT_RETRY_LIMIT 3 +#define IWLAGN_RTS_DFAULT_RETRY_LIMIT 60 +#define IWLAGN_BAR_DFAULT_RETRY_LIMIT 60 +#define IWLAGN_LOW_RETRY_LIMIT 7 /* Limit range of txpower output target to be between these values */ #define IWLAGN_TX_POWER_TARGET_POWER_MIN (0) /* 0 dBm: 1 milliwatt */ @@ -92,20 +105,7 @@ #define IWLAGN_CMD_FIFO_NUM 7 #define IWLAGN_NUM_QUEUES 20 -#define IWLAGN_NUM_AMPDU_QUEUES 10 -#define IWLAGN_FIRST_AMPDU_QUEUE 10 - -/* Fixed (non-configurable) rx data from phy */ - -/** - * struct iwlagn_schedq_bc_tbl scheduler byte count table - * base physical address provided by SCD_DRAM_BASE_ADDR - * @tfd_offset 0-12 - tx command byte count - * 12-16 - station index - */ -struct iwlagn_scd_bc_tbl { - __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; -} __packed; - +#define IWLAGN_NUM_AMPDU_QUEUES 9 +#define IWLAGN_FIRST_AMPDU_QUEUE 11 #endif /* __iwl_agn_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3bee0f119bcd..1a52ed29f2d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -35,454 +35,10 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-agn.h" -#include "iwl-sta.h" #include "iwl-trans.h" - -static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp) -{ - return le32_to_cpup((__le32 *)&tx_resp->status + - tx_resp->frame_count) & MAX_SN; -} - -static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status) -{ - status &= TX_STATUS_MSK; - - switch (status) { - case TX_STATUS_POSTPONE_DELAY: - priv->reply_tx_stats.pp_delay++; - break; - case TX_STATUS_POSTPONE_FEW_BYTES: - priv->reply_tx_stats.pp_few_bytes++; - break; - case TX_STATUS_POSTPONE_BT_PRIO: - priv->reply_tx_stats.pp_bt_prio++; - break; - case TX_STATUS_POSTPONE_QUIET_PERIOD: - priv->reply_tx_stats.pp_quiet_period++; - break; - case TX_STATUS_POSTPONE_CALC_TTAK: - priv->reply_tx_stats.pp_calc_ttak++; - break; - case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY: - priv->reply_tx_stats.int_crossed_retry++; - break; - case TX_STATUS_FAIL_SHORT_LIMIT: - priv->reply_tx_stats.short_limit++; - break; - case TX_STATUS_FAIL_LONG_LIMIT: - priv->reply_tx_stats.long_limit++; - break; - case TX_STATUS_FAIL_FIFO_UNDERRUN: - priv->reply_tx_stats.fifo_underrun++; - break; - case TX_STATUS_FAIL_DRAIN_FLOW: - priv->reply_tx_stats.drain_flow++; - break; - case TX_STATUS_FAIL_RFKILL_FLUSH: - priv->reply_tx_stats.rfkill_flush++; - break; - case TX_STATUS_FAIL_LIFE_EXPIRE: - priv->reply_tx_stats.life_expire++; - break; - case TX_STATUS_FAIL_DEST_PS: - priv->reply_tx_stats.dest_ps++; - break; - case TX_STATUS_FAIL_HOST_ABORTED: - priv->reply_tx_stats.host_abort++; - break; - case TX_STATUS_FAIL_BT_RETRY: - priv->reply_tx_stats.bt_retry++; - break; - case TX_STATUS_FAIL_STA_INVALID: - priv->reply_tx_stats.sta_invalid++; - break; - case TX_STATUS_FAIL_FRAG_DROPPED: - priv->reply_tx_stats.frag_drop++; - break; - case TX_STATUS_FAIL_TID_DISABLE: - priv->reply_tx_stats.tid_disable++; - break; - case TX_STATUS_FAIL_FIFO_FLUSHED: - priv->reply_tx_stats.fifo_flush++; - break; - case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL: - priv->reply_tx_stats.insuff_cf_poll++; - break; - case TX_STATUS_FAIL_PASSIVE_NO_RX: - priv->reply_tx_stats.fail_hw_drop++; - break; - case TX_STATUS_FAIL_NO_BEACON_ON_RADAR: - priv->reply_tx_stats.sta_color_mismatch++; - break; - default: - priv->reply_tx_stats.unknown++; - break; - } -} - -static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status) -{ - status &= AGG_TX_STATUS_MSK; - - switch (status) { - case AGG_TX_STATE_UNDERRUN_MSK: - priv->reply_agg_tx_stats.underrun++; - break; - case AGG_TX_STATE_BT_PRIO_MSK: - priv->reply_agg_tx_stats.bt_prio++; - break; - case AGG_TX_STATE_FEW_BYTES_MSK: - priv->reply_agg_tx_stats.few_bytes++; - break; - case AGG_TX_STATE_ABORT_MSK: - priv->reply_agg_tx_stats.abort++; - break; - case AGG_TX_STATE_LAST_SENT_TTL_MSK: - priv->reply_agg_tx_stats.last_sent_ttl++; - break; - case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK: - priv->reply_agg_tx_stats.last_sent_try++; - break; - case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK: - priv->reply_agg_tx_stats.last_sent_bt_kill++; - break; - case AGG_TX_STATE_SCD_QUERY_MSK: - priv->reply_agg_tx_stats.scd_query++; - break; - case AGG_TX_STATE_TEST_BAD_CRC32_MSK: - priv->reply_agg_tx_stats.bad_crc32++; - break; - case AGG_TX_STATE_RESPONSE_MSK: - priv->reply_agg_tx_stats.response++; - break; - case AGG_TX_STATE_DUMP_TX_MSK: - priv->reply_agg_tx_stats.dump_tx++; - break; - case AGG_TX_STATE_DELAY_TX_MSK: - priv->reply_agg_tx_stats.delay_tx++; - break; - default: - priv->reply_agg_tx_stats.unknown++; - break; - } -} - -static void iwlagn_set_tx_status(struct iwl_priv *priv, - struct ieee80211_tx_info *info, - struct iwl_rxon_context *ctx, - struct iwlagn_tx_resp *tx_resp, - int txq_id, bool is_agg) -{ - u16 status = le16_to_cpu(tx_resp->status.status); - - info->status.rates[0].count = tx_resp->failure_frame + 1; - if (is_agg) - info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_tx_status_to_mac80211(status); - iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), - info); - if (!iwl_is_tx_success(status)) - iwlagn_count_tx_err_status(priv, status); - - if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && - iwl_is_associated_ctx(ctx) && ctx->vif && - ctx->vif->type == NL80211_IFTYPE_STATION) { - ctx->last_tx_rejected = true; - iwl_stop_queue(priv, &priv->txq[txq_id]); - } - - IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags " - "0x%x retries %d\n", - txq_id, - iwl_get_tx_fail_reason(status), status, - le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); -} - -#ifdef CONFIG_IWLWIFI_DEBUG -#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x - -const char *iwl_get_agg_tx_fail_reason(u16 status) -{ - status &= AGG_TX_STATUS_MSK; - switch (status) { - case AGG_TX_STATE_TRANSMITTED: - return "SUCCESS"; - AGG_TX_STATE_FAIL(UNDERRUN_MSK); - AGG_TX_STATE_FAIL(BT_PRIO_MSK); - AGG_TX_STATE_FAIL(FEW_BYTES_MSK); - AGG_TX_STATE_FAIL(ABORT_MSK); - AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK); - AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK); - AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK); - AGG_TX_STATE_FAIL(SCD_QUERY_MSK); - AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK); - AGG_TX_STATE_FAIL(RESPONSE_MSK); - AGG_TX_STATE_FAIL(DUMP_TX_MSK); - AGG_TX_STATE_FAIL(DELAY_TX_MSK); - } - - return "UNKNOWN"; -} -#endif /* CONFIG_IWLWIFI_DEBUG */ - -static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv, - struct iwl_ht_agg *agg, - struct iwlagn_tx_resp *tx_resp, - int txq_id, u16 start_idx) -{ - u16 status; - struct agg_tx_status *frame_status = &tx_resp->status; - struct ieee80211_hdr *hdr = NULL; - int i, sh, idx; - u16 seq; - - if (agg->wait_for_ba) - IWL_DEBUG_TX_REPLY(priv, "got tx response w/o block-ack\n"); - - agg->frame_count = tx_resp->frame_count; - agg->start_idx = start_idx; - agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); - agg->bitmap = 0; - - /* # frames attempted by Tx command */ - if (agg->frame_count == 1) { - struct iwl_tx_info *txb; - - /* Only one frame was attempted; no block-ack will arrive */ - idx = start_idx; - - IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n", - agg->frame_count, agg->start_idx, idx); - txb = &priv->txq[txq_id].txb[idx]; - iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb), - txb->ctx, tx_resp, txq_id, true); - agg->wait_for_ba = 0; - } else { - /* Two or more frames were attempted; expect block-ack */ - u64 bitmap = 0; - - /* - * Start is the lowest frame sent. It may not be the first - * frame in the batch; we figure this out dynamically during - * the following loop. - */ - int start = agg->start_idx; - - /* Construct bit-map of pending frames within Tx window */ - for (i = 0; i < agg->frame_count; i++) { - u16 sc; - status = le16_to_cpu(frame_status[i].status); - seq = le16_to_cpu(frame_status[i].sequence); - idx = SEQ_TO_INDEX(seq); - txq_id = SEQ_TO_QUEUE(seq); - - if (status & AGG_TX_STATUS_MSK) - iwlagn_count_agg_tx_err_status(priv, status); - - if (status & (AGG_TX_STATE_FEW_BYTES_MSK | - AGG_TX_STATE_ABORT_MSK)) - continue; - - IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, txq_id=%d idx=%d\n", - agg->frame_count, txq_id, idx); - IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), " - "try-count (0x%08x)\n", - iwl_get_agg_tx_fail_reason(status), - status & AGG_TX_STATUS_MSK, - status & AGG_TX_TRY_MSK); - - hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx); - if (!hdr) { - IWL_ERR(priv, - "BUG_ON idx doesn't point to valid skb" - " idx=%d, txq_id=%d\n", idx, txq_id); - return -1; - } - - sc = le16_to_cpu(hdr->seq_ctrl); - if (idx != (SEQ_TO_SN(sc) & 0xff)) { - IWL_ERR(priv, - "BUG_ON idx doesn't match seq control" - " idx=%d, seq_idx=%d, seq=%d\n", - idx, SEQ_TO_SN(sc), - hdr->seq_ctrl); - return -1; - } - - IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n", - i, idx, SEQ_TO_SN(sc)); - - /* - * sh -> how many frames ahead of the starting frame is - * the current one? - * - * Note that all frames sent in the batch must be in a - * 64-frame window, so this number should be in [0,63]. - * If outside of this window, then we've found a new - * "first" frame in the batch and need to change start. - */ - sh = idx - start; - - /* - * If >= 64, out of window. start must be at the front - * of the circular buffer, idx must be near the end of - * the buffer, and idx is the new "first" frame. Shift - * the indices around. - */ - if (sh >= 64) { - /* Shift bitmap by start - idx, wrapped */ - sh = 0x100 - idx + start; - bitmap = bitmap << sh; - /* Now idx is the new start so sh = 0 */ - sh = 0; - start = idx; - /* - * If <= -64 then wraps the 256-pkt circular buffer - * (e.g., start = 255 and idx = 0, sh should be 1) - */ - } else if (sh <= -64) { - sh = 0x100 - start + idx; - /* - * If < 0 but > -64, out of window. idx is before start - * but not wrapped. Shift the indices around. - */ - } else if (sh < 0) { - /* Shift by how far start is ahead of idx */ - sh = start - idx; - bitmap = bitmap << sh; - /* Now idx is the new start so sh = 0 */ - start = idx; - sh = 0; - } - /* Sequence number start + sh was sent in this batch */ - bitmap |= 1ULL << sh; - IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n", - start, (unsigned long long)bitmap); - } - - /* - * Store the bitmap and possibly the new start, if we wrapped - * the buffer above - */ - agg->bitmap = bitmap; - agg->start_idx = start; - IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n", - agg->frame_count, agg->start_idx, - (unsigned long long)agg->bitmap); - - if (bitmap) - agg->wait_for_ba = 1; - } - return 0; -} - -void iwl_check_abort_status(struct iwl_priv *priv, - u8 frame_count, u32 status) -{ - if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) { - IWL_ERR(priv, "Tx flush command to flush out all frames\n"); - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) - queue_work(priv->workqueue, &priv->tx_flush); - } -} - -void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - u16 sequence = le16_to_cpu(pkt->hdr.sequence); - int txq_id = SEQ_TO_QUEUE(sequence); - int index = SEQ_TO_INDEX(sequence); - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct ieee80211_tx_info *info; - struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; - struct ieee80211_hdr *hdr; - struct iwl_tx_info *txb; - u32 status = le16_to_cpu(tx_resp->status.status); - int tid; - int sta_id; - int freed; - unsigned long flags; - - if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { - IWL_ERR(priv, "%s: Read index for DMA queue txq_id (%d) " - "index %d is out of range [0-%d] %d %d\n", __func__, - txq_id, index, txq->q.n_bd, txq->q.write_ptr, - txq->q.read_ptr); - return; - } - - txq->time_stamp = jiffies; - txb = &txq->txb[txq->q.read_ptr]; - info = IEEE80211_SKB_CB(txb->skb); - memset(&info->status, 0, sizeof(info->status)); - - tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> - IWLAGN_TX_RES_TID_POS; - sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> - IWLAGN_TX_RES_RA_POS; - - spin_lock_irqsave(&priv->sta_lock, flags); - - hdr = (void *)txb->skb->data; - if (!ieee80211_is_data_qos(hdr->frame_control)) - priv->last_seq_ctl = tx_resp->seq_ctl; - - if (txq->sched_retry) { - const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp); - struct iwl_ht_agg *agg; - - agg = &priv->stations[sta_id].tid[tid].agg; - /* - * If the BT kill count is non-zero, we'll get this - * notification again. - */ - if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && - priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { - IWL_DEBUG_COEX(priv, "receive reply tx with bt_kill\n"); - } - iwlagn_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); - - /* check if BAR is needed */ - if ((tx_resp->frame_count == 1) && !iwl_is_tx_success(status)) - info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - - if (txq->q.read_ptr != (scd_ssn & 0xff)) { - index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd); - IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim " - "scd_ssn=%d idx=%d txq=%d swq=%d\n", - scd_ssn , index, txq_id, txq->swq_id); - - freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); - iwl_free_tfds_in_queue(priv, sta_id, tid, freed); - - if (priv->mac80211_registered && - (iwl_queue_space(&txq->q) > txq->q.low_mark) && - (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) - iwl_wake_queue(priv, txq); - } - } else { - iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp, - txq_id, false); - freed = iwlagn_tx_queue_reclaim(priv, txq_id, index); - iwl_free_tfds_in_queue(priv, sta_id, tid, freed); - - if (priv->mac80211_registered && - iwl_queue_space(&txq->q) > txq->q.low_mark && - status != TX_STATUS_FAIL_PASSIVE_NO_RX) - iwl_wake_queue(priv, txq); - } - - iwlagn_txq_check_empty(priv, sta_id, tid, txq_id); - - iwl_check_abort_status(priv, tx_resp->frame_count, status); - spin_unlock_irqrestore(&priv->sta_lock, flags); -} +#include "iwl-shared.h" int iwlagn_hw_valid_rtc_data_addr(u32 addr) { @@ -495,7 +51,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) struct iwlagn_tx_power_dbm_cmd tx_power_cmd; u8 tx_ant_cfg_cmd; - if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->status), + if (WARN_ONCE(test_bit(STATUS_SCAN_HW, &priv->shrd->status), "TX Power requested while scanning!\n")) return -EAGAIN; @@ -525,7 +81,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv) else tx_ant_cfg_cmd = REPLY_TX_POWER_DBM_CMD; - return trans_send_cmd_pdu(&priv->trans, tx_ant_cfg_cmd, CMD_SYNC, + return iwl_trans_send_cmd_pdu(trans(priv), tx_ant_cfg_cmd, CMD_SYNC, sizeof(tx_power_cmd), &tx_power_cmd); } @@ -538,11 +94,7 @@ void iwlagn_temperature(struct iwl_priv *priv) u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv) { - struct iwl_eeprom_calib_hdr { - u8 version; - u8 pa_type; - u16 voltage; - } *hdr; + struct iwl_eeprom_calib_hdr *hdr; hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, EEPROM_CALIB_ALL); @@ -609,6 +161,9 @@ struct iwl_mod_params iwlagn_mod_params = { .bt_coex_active = true, .no_sleep_autoadjust = true, .power_level = IWL_POWER_INDEX_1, + .bt_ch_announce = true, + .wanted_ucode_alternative = 1, + .auto_agg = true, /* the rest are 0 by default */ }; @@ -633,449 +188,6 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) return -1; } -static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, - struct ieee80211_vif *vif, - enum ieee80211_band band, - struct iwl_scan_channel *scan_ch) -{ - const struct ieee80211_supported_band *sband; - u16 passive_dwell = 0; - u16 active_dwell = 0; - int added = 0; - u16 channel = 0; - - sband = iwl_get_hw_mode(priv, band); - if (!sband) { - IWL_ERR(priv, "invalid band\n"); - return added; - } - - active_dwell = iwl_get_active_dwell_time(priv, band, 0); - passive_dwell = iwl_get_passive_dwell_time(priv, band, vif); - - if (passive_dwell <= active_dwell) - passive_dwell = active_dwell + 1; - - channel = iwl_get_single_channel_number(priv, band); - if (channel) { - scan_ch->channel = cpu_to_le16(channel); - scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - /* Set txpower levels to defaults */ - scan_ch->dsp_atten = 110; - if (band == IEEE80211_BAND_5GHZ) - scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; - else - scan_ch->tx_gain = ((1 << 5) | (5 << 3)); - added++; - } else - IWL_ERR(priv, "no valid channel found\n"); - return added; -} - -static int iwl_get_channels_for_scan(struct iwl_priv *priv, - struct ieee80211_vif *vif, - enum ieee80211_band band, - u8 is_active, u8 n_probes, - struct iwl_scan_channel *scan_ch) -{ - struct ieee80211_channel *chan; - const struct ieee80211_supported_band *sband; - const struct iwl_channel_info *ch_info; - u16 passive_dwell = 0; - u16 active_dwell = 0; - int added, i; - u16 channel; - - sband = iwl_get_hw_mode(priv, band); - if (!sband) - return 0; - - active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); - passive_dwell = iwl_get_passive_dwell_time(priv, band, vif); - - if (passive_dwell <= active_dwell) - passive_dwell = active_dwell + 1; - - for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { - chan = priv->scan_request->channels[i]; - - if (chan->band != band) - continue; - - channel = chan->hw_value; - scan_ch->channel = cpu_to_le16(channel); - - ch_info = iwl_get_channel_info(priv, band, channel); - if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN(priv, "Channel %d is INVALID for this band.\n", - channel); - continue; - } - - if (!is_active || is_channel_passive(ch_info) || - (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) - scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; - else - scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; - - if (n_probes) - scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); - - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); - - /* Set txpower levels to defaults */ - scan_ch->dsp_atten = 110; - - /* NOTE: if we were doing 6Mb OFDM for scans we'd use - * power level: - * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; - */ - if (band == IEEE80211_BAND_5GHZ) - scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; - else - scan_ch->tx_gain = ((1 << 5) | (5 << 3)); - - IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n", - channel, le32_to_cpu(scan_ch->type), - (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? - "ACTIVE" : "PASSIVE", - (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? - active_dwell : passive_dwell); - - scan_ch++; - added++; - } - - IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added); - return added; -} - -static int iwl_fill_offch_tx(struct iwl_priv *priv, void *data, size_t maxlen) -{ - struct sk_buff *skb = priv->offchan_tx_skb; - - if (skb->len < maxlen) - maxlen = skb->len; - - memcpy(data, skb->data, maxlen); - - return maxlen; -} - -int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) -{ - struct iwl_host_cmd cmd = { - .id = REPLY_SCAN_CMD, - .len = { sizeof(struct iwl_scan_cmd), }, - .flags = CMD_SYNC, - }; - struct iwl_scan_cmd *scan; - struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - u32 rate_flags = 0; - u16 cmd_len; - u16 rx_chain = 0; - enum ieee80211_band band; - u8 n_probes = 0; - u8 rx_ant = priv->hw_params.valid_rx_ant; - u8 rate; - bool is_active = false; - int chan_mod; - u8 active_chains; - u8 scan_tx_antennas = priv->hw_params.valid_tx_ant; - int ret; - - lockdep_assert_held(&priv->mutex); - - if (vif) - ctx = iwl_rxon_ctx_from_vif(vif); - - if (!priv->scan_cmd) { - priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) + - IWL_MAX_SCAN_SIZE, GFP_KERNEL); - if (!priv->scan_cmd) { - IWL_DEBUG_SCAN(priv, - "fail to allocate memory for scan\n"); - return -ENOMEM; - } - } - scan = priv->scan_cmd; - memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); - - scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; - scan->quiet_time = IWL_ACTIVE_QUIET_TIME; - - if (priv->scan_type != IWL_SCAN_OFFCH_TX && - iwl_is_any_associated(priv)) { - u16 interval = 0; - u32 extra; - u32 suspend_time = 100; - u32 scan_suspend_time = 100; - - IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); - switch (priv->scan_type) { - case IWL_SCAN_OFFCH_TX: - WARN_ON(1); - break; - case IWL_SCAN_RADIO_RESET: - interval = 0; - break; - case IWL_SCAN_NORMAL: - interval = vif->bss_conf.beacon_int; - break; - } - - scan->suspend_time = 0; - scan->max_out_time = cpu_to_le32(200 * 1024); - if (!interval) - interval = suspend_time; - - extra = (suspend_time / interval) << 22; - scan_suspend_time = (extra | - ((suspend_time % interval) * 1024)); - scan->suspend_time = cpu_to_le32(scan_suspend_time); - IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", - scan_suspend_time, interval); - } else if (priv->scan_type == IWL_SCAN_OFFCH_TX) { - scan->suspend_time = 0; - scan->max_out_time = - cpu_to_le32(1024 * priv->offchan_tx_timeout); - } - - switch (priv->scan_type) { - case IWL_SCAN_RADIO_RESET: - IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); - break; - case IWL_SCAN_NORMAL: - if (priv->scan_request->n_ssids) { - int i, p = 0; - IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); - for (i = 0; i < priv->scan_request->n_ssids; i++) { - /* always does wildcard anyway */ - if (!priv->scan_request->ssids[i].ssid_len) - continue; - scan->direct_scan[p].id = WLAN_EID_SSID; - scan->direct_scan[p].len = - priv->scan_request->ssids[i].ssid_len; - memcpy(scan->direct_scan[p].ssid, - priv->scan_request->ssids[i].ssid, - priv->scan_request->ssids[i].ssid_len); - n_probes++; - p++; - } - is_active = true; - } else - IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); - break; - case IWL_SCAN_OFFCH_TX: - IWL_DEBUG_SCAN(priv, "Start offchannel TX scan.\n"); - break; - } - - scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; - scan->tx_cmd.sta_id = ctx->bcast_sta_id; - scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; - - switch (priv->scan_band) { - case IEEE80211_BAND_2GHZ: - scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; - chan_mod = le32_to_cpu( - priv->contexts[IWL_RXON_CTX_BSS].active.flags & - RXON_FLG_CHANNEL_MODE_MSK) - >> RXON_FLG_CHANNEL_MODE_POS; - if (chan_mod == CHANNEL_MODE_PURE_40) { - rate = IWL_RATE_6M_PLCP; - } else { - rate = IWL_RATE_1M_PLCP; - rate_flags = RATE_MCS_CCK_MSK; - } - /* - * Internal scans are passive, so we can indiscriminately set - * the BT ignore flag on 2.4 GHz since it applies to TX only. - */ - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) - scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; - break; - case IEEE80211_BAND_5GHZ: - rate = IWL_RATE_6M_PLCP; - break; - default: - IWL_WARN(priv, "Invalid scan band\n"); - return -EIO; - } - - /* - * If active scanning is requested but a certain channel is - * marked passive, we can do active scanning if we detect - * transmissions. - * - * There is an issue with some firmware versions that triggers - * a sysassert on a "good CRC threshold" of zero (== disabled), - * on a radar channel even though this means that we should NOT - * send probes. - * - * The "good CRC threshold" is the number of frames that we - * need to receive during our dwell time on a channel before - * sending out probes -- setting this to a huge value will - * mean we never reach it, but at the same time work around - * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER - * here instead of IWL_GOOD_CRC_TH_DISABLED. - * - * This was fixed in later versions along with some other - * scan changes, and the threshold behaves as a flag in those - * versions. - */ - if (priv->new_scan_threshold_behaviour) - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_DISABLED; - else - scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_NEVER; - - band = priv->scan_band; - - if (priv->cfg->scan_rx_antennas[band]) - rx_ant = priv->cfg->scan_rx_antennas[band]; - - if (band == IEEE80211_BAND_2GHZ && - priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist) { - /* transmit 2.4 GHz probes only on first antenna */ - scan_tx_antennas = first_antenna(scan_tx_antennas); - } - - priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band], - scan_tx_antennas); - rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); - scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); - - /* In power save mode use one chain, otherwise use all chains */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - /* rx_ant has been set to all valid chains previously */ - active_chains = rx_ant & - ((u8)(priv->chain_noise_data.active_chains)); - if (!active_chains) - active_chains = rx_ant; - - IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n", - priv->chain_noise_data.active_chains); - - rx_ant = first_antenna(active_chains); - } - if (priv->cfg->bt_params && - priv->cfg->bt_params->advanced_bt_coexist && - priv->bt_full_concurrent) { - /* operated as 1x1 in full concurrency mode */ - rx_ant = first_antenna(rx_ant); - } - - /* MIMO is not used here, but value is required */ - rx_chain |= priv->hw_params.valid_rx_ant << RXON_RX_CHAIN_VALID_POS; - rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; - rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; - rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; - scan->rx_chain = cpu_to_le16(rx_chain); - switch (priv->scan_type) { - case IWL_SCAN_NORMAL: - cmd_len = iwl_fill_probe_req(priv, - (struct ieee80211_mgmt *)scan->data, - vif->addr, - priv->scan_request->ie, - priv->scan_request->ie_len, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); - break; - case IWL_SCAN_RADIO_RESET: - /* use bcast addr, will not be transmitted but must be valid */ - cmd_len = iwl_fill_probe_req(priv, - (struct ieee80211_mgmt *)scan->data, - iwl_bcast_addr, NULL, 0, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); - break; - case IWL_SCAN_OFFCH_TX: - cmd_len = iwl_fill_offch_tx(priv, scan->data, - IWL_MAX_SCAN_SIZE - - sizeof(*scan) - - sizeof(struct iwl_scan_channel)); - scan->scan_flags |= IWL_SCAN_FLAGS_ACTION_FRAME_TX; - break; - default: - BUG(); - } - scan->tx_cmd.len = cpu_to_le16(cmd_len); - - scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | - RXON_FILTER_BCON_AWARE_MSK); - - switch (priv->scan_type) { - case IWL_SCAN_RADIO_RESET: - scan->channel_count = - iwl_get_single_channel_for_scan(priv, vif, band, - (void *)&scan->data[cmd_len]); - break; - case IWL_SCAN_NORMAL: - scan->channel_count = - iwl_get_channels_for_scan(priv, vif, band, - is_active, n_probes, - (void *)&scan->data[cmd_len]); - break; - case IWL_SCAN_OFFCH_TX: { - struct iwl_scan_channel *scan_ch; - - scan->channel_count = 1; - - scan_ch = (void *)&scan->data[cmd_len]; - scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; - scan_ch->channel = - cpu_to_le16(priv->offchan_tx_chan->hw_value); - scan_ch->active_dwell = - cpu_to_le16(priv->offchan_tx_timeout); - scan_ch->passive_dwell = 0; - - /* Set txpower levels to defaults */ - scan_ch->dsp_atten = 110; - - /* NOTE: if we were doing 6Mb OFDM for scans we'd use - * power level: - * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; - */ - if (priv->offchan_tx_chan->band == IEEE80211_BAND_5GHZ) - scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; - else - scan_ch->tx_gain = ((1 << 5) | (5 << 3)); - } - break; - } - - if (scan->channel_count == 0) { - IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); - return -EIO; - } - - cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) + - scan->channel_count * sizeof(struct iwl_scan_channel); - cmd.data[0] = scan; - cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; - scan->len = cpu_to_le16(cmd.len[0]); - - /* set scan bit here for PAN params */ - set_bit(STATUS_SCAN_HW, &priv->status); - - ret = iwlagn_set_pan_params(priv); - if (ret) - return ret; - - ret = trans_send_cmd(&priv->trans, &cmd); - if (ret) { - clear_bit(STATUS_SCAN_HW, &priv->status); - iwlagn_set_pan_params(priv); - } - - return ret; -} - int iwlagn_manage_ibss_station(struct iwl_priv *priv, struct ieee80211_vif *vif, bool add) { @@ -1089,52 +201,6 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv, vif->bss_conf.bssid); } -void iwl_free_tfds_in_queue(struct iwl_priv *priv, - int sta_id, int tid, int freed) -{ - lockdep_assert_held(&priv->sta_lock); - - if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed) - priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - else { - IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n", - priv->stations[sta_id].tid[tid].tfds_in_queue, - freed); - priv->stations[sta_id].tid[tid].tfds_in_queue = 0; - } -} - -#define IWL_FLUSH_WAIT_MS 2000 - -int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv) -{ - struct iwl_tx_queue *txq; - struct iwl_queue *q; - int cnt; - unsigned long now = jiffies; - int ret = 0; - - /* waiting for all the tx frames complete might take a while */ - for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { - if (cnt == priv->cmd_queue) - continue; - txq = &priv->txq[cnt]; - q = &txq->q; - while (q->read_ptr != q->write_ptr && !time_after(jiffies, - now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) - msleep(1); - - if (q->read_ptr != q->write_ptr) { - IWL_ERR(priv, "fail to flush all tx fifo queues\n"); - ret = -ETIMEDOUT; - break; - } - } - return ret; -} - -#define IWL_TX_QUEUE_MSK 0xfffff - /** * iwlagn_txfifo_flush: send REPLY_TXFIFO_FLUSH command to uCode * @@ -1160,7 +226,7 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control) IWL_SCD_BE_MSK | IWL_SCD_BK_MSK | IWL_SCD_MGMT_MSK; if ((flush_control & BIT(IWL_RXON_CTX_PAN)) && - (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))) + (priv->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS))) flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK | IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK | IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK | @@ -1173,22 +239,22 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control) flush_cmd.fifo_control); flush_cmd.flush_control = cpu_to_le16(flush_control); - return trans_send_cmd(&priv->trans, &cmd); + return iwl_trans_send_cmd(trans(priv), &cmd); } void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control) { - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); ieee80211_stop_queues(priv->hw); if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) { IWL_ERR(priv, "flush request fail\n"); goto done; } IWL_DEBUG_INFO(priv, "wait transmit/flush all frames\n"); - iwlagn_wait_tx_queue_empty(priv); + iwl_trans_wait_tx_queue_empty(trans(priv)); done: ieee80211_wake_queues(priv->hw); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } /* @@ -1367,12 +433,12 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) if (priv->cfg->bt_params->bt_session_2) { memcpy(&bt_cmd_2000.basic, &basic, sizeof(basic)); - ret = trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG, CMD_SYNC, sizeof(bt_cmd_2000), &bt_cmd_2000); } else { memcpy(&bt_cmd_6000.basic, &basic, sizeof(basic)); - ret = trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG, CMD_SYNC, sizeof(bt_cmd_6000), &bt_cmd_6000); } if (ret) @@ -1385,7 +451,7 @@ void iwlagn_bt_adjust_rssi_monitor(struct iwl_priv *priv, bool rssi_ena) struct iwl_rxon_context *ctx, *found_ctx = NULL; bool found_ap = false; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); /* Check whether AP or GO mode is active. */ if (rssi_ena) { @@ -1498,7 +564,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) break; } - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); /* * We can not send command to firmware while scanning. When the scan @@ -1507,7 +573,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) * STATUS_SCANNING to avoid race when queue_work two times from * different notifications, but quit and not perform any work at all. */ - if (test_bit(STATUS_SCAN_HW, &priv->status)) + if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) goto out; iwl_update_chain_flags(priv); @@ -1526,7 +592,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work) */ iwlagn_bt_coex_rssi_monitor(priv); out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } /* @@ -1633,12 +699,13 @@ static void iwlagn_set_kill_msk(struct iwl_priv *priv, priv->kill_cts_mask = bt_kill_cts_msg[kill_msk]; /* schedule to send runtime bt_config */ - queue_work(priv->workqueue, &priv->bt_runtime_config); + queue_work(priv->shrd->workqueue, &priv->bt_runtime_config); } } -void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { unsigned long flags; struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -1647,7 +714,7 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) { /* bt coex disabled */ - return; + return 0; } IWL_DEBUG_COEX(priv, "BT Coex notification:\n"); @@ -1677,7 +744,7 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, IWL_BT_COEX_TRAFFIC_LOAD_NONE; } priv->bt_status = coex->bt_status; - queue_work(priv->workqueue, + queue_work(priv->shrd->workqueue, &priv->bt_traffic_change_work); } } @@ -1686,9 +753,10 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, /* FIXME: based on notification, adjust the prio_boost */ - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->shrd->lock, flags); priv->bt_ci_compliance = coex->bt_ci_compliance; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); + return 0; } void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv) @@ -1788,7 +856,7 @@ static u8 iwl_count_chain_bitmap(u32 chain_bitmap) void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { bool is_single = is_single_rx_stream(priv); - bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->status); + bool is_cam = !test_bit(STATUS_POWER_PMI, &priv->shrd->status); u8 idle_rx_cnt, active_rx_cnt, valid_rx_cnt; u32 active_chains; u16 rx_chain; @@ -1800,7 +868,7 @@ void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx) if (priv->chain_noise_data.active_chains) active_chains = priv->chain_noise_data.active_chains; else - active_chains = priv->hw_params.valid_rx_ant; + active_chains = hw_params(priv).valid_rx_ant; if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist && @@ -1865,136 +933,6 @@ u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid) return ant; } -static const char *get_csr_string(int cmd) -{ - switch (cmd) { - IWL_CMD(CSR_HW_IF_CONFIG_REG); - IWL_CMD(CSR_INT_COALESCING); - IWL_CMD(CSR_INT); - IWL_CMD(CSR_INT_MASK); - IWL_CMD(CSR_FH_INT_STATUS); - IWL_CMD(CSR_GPIO_IN); - IWL_CMD(CSR_RESET); - IWL_CMD(CSR_GP_CNTRL); - IWL_CMD(CSR_HW_REV); - IWL_CMD(CSR_EEPROM_REG); - IWL_CMD(CSR_EEPROM_GP); - IWL_CMD(CSR_OTP_GP_REG); - IWL_CMD(CSR_GIO_REG); - IWL_CMD(CSR_GP_UCODE_REG); - IWL_CMD(CSR_GP_DRIVER_REG); - IWL_CMD(CSR_UCODE_DRV_GP1); - IWL_CMD(CSR_UCODE_DRV_GP2); - IWL_CMD(CSR_LED_REG); - IWL_CMD(CSR_DRAM_INT_TBL_REG); - IWL_CMD(CSR_GIO_CHICKEN_BITS); - IWL_CMD(CSR_ANA_PLL_CFG); - IWL_CMD(CSR_HW_REV_WA_REG); - IWL_CMD(CSR_DBG_HPET_MEM_REG); - default: - return "UNKNOWN"; - } -} - -void iwl_dump_csr(struct iwl_priv *priv) -{ - int i; - static const u32 csr_tbl[] = { - CSR_HW_IF_CONFIG_REG, - CSR_INT_COALESCING, - CSR_INT, - CSR_INT_MASK, - CSR_FH_INT_STATUS, - CSR_GPIO_IN, - CSR_RESET, - CSR_GP_CNTRL, - CSR_HW_REV, - CSR_EEPROM_REG, - CSR_EEPROM_GP, - CSR_OTP_GP_REG, - CSR_GIO_REG, - CSR_GP_UCODE_REG, - CSR_GP_DRIVER_REG, - CSR_UCODE_DRV_GP1, - CSR_UCODE_DRV_GP2, - CSR_LED_REG, - CSR_DRAM_INT_TBL_REG, - CSR_GIO_CHICKEN_BITS, - CSR_ANA_PLL_CFG, - CSR_HW_REV_WA_REG, - CSR_DBG_HPET_MEM_REG - }; - IWL_ERR(priv, "CSR values:\n"); - IWL_ERR(priv, "(2nd byte of CSR_INT_COALESCING is " - "CSR_INT_PERIODIC_REG)\n"); - for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { - IWL_ERR(priv, " %25s: 0X%08x\n", - get_csr_string(csr_tbl[i]), - iwl_read32(priv, csr_tbl[i])); - } -} - -static const char *get_fh_string(int cmd) -{ - switch (cmd) { - IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); - IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); - IWL_CMD(FH_RSCSR_CHNL0_WPTR); - IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); - IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); - IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); - IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); - IWL_CMD(FH_TSSR_TX_STATUS_REG); - IWL_CMD(FH_TSSR_TX_ERROR_REG); - default: - return "UNKNOWN"; - } -} - -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display) -{ - int i; -#ifdef CONFIG_IWLWIFI_DEBUG - int pos = 0; - size_t bufsz = 0; -#endif - static const u32 fh_tbl[] = { - FH_RSCSR_CHNL0_STTS_WPTR_REG, - FH_RSCSR_CHNL0_RBDCB_BASE_REG, - FH_RSCSR_CHNL0_WPTR, - FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_MEM_RSSR_SHARED_CTRL_REG, - FH_MEM_RSSR_RX_STATUS_REG, - FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, - FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_ERROR_REG - }; -#ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - pos += scnprintf(*buf + pos, bufsz - pos, - "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { - pos += scnprintf(*buf + pos, bufsz - pos, - " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(priv, fh_tbl[i])); - } - return pos; - } -#endif - IWL_ERR(priv, "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { - IWL_ERR(priv, " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(priv, fh_tbl[i])); - } - return 0; -} - /* notification wait support */ void iwlagn_init_notification_wait(struct iwl_priv *priv, struct iwl_notification_wait *wait_entry, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index 3789ff4bf53b..66118cea2af3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -27,7 +27,6 @@ #include <linux/init.h> #include <linux/skbuff.h> #include <linux/slab.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/netdevice.h> @@ -37,7 +36,6 @@ #include <linux/workqueue.h> #include "iwl-dev.h" -#include "iwl-sta.h" #include "iwl-core.h" #include "iwl-agn.h" @@ -298,10 +296,10 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, u8 *qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; } else - return MAX_TID_COUNT; + return IWL_MAX_TID_COUNT; if (unlikely(tid >= TID_MAX_LOAD_COUNT)) - return MAX_TID_COUNT; + return IWL_MAX_TID_COUNT; tl = &lq_data->load[tid]; @@ -314,7 +312,7 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, tl->queue_count = 1; tl->head = 0; tl->packet_count[0] = 1; - return MAX_TID_COUNT; + return IWL_MAX_TID_COUNT; } time_diff = TIME_WRAP_AROUND(tl->time_stamp, curr_time); @@ -347,7 +345,7 @@ static void rs_program_fix_rate(struct iwl_priv *priv, { struct iwl_station_priv *sta_priv = container_of(lq_sta, struct iwl_station_priv, lq_sta); - struct iwl_rxon_context *ctx = sta_priv->common.ctx; + struct iwl_rxon_context *ctx = sta_priv->ctx; lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */ lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */ @@ -421,7 +419,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, load = rs_tl_get_load(lq_data, tid); - if (load > IWL_AGG_LOAD_THRESHOLD) { + if ((iwlagn_mod_params.auto_agg) || (load > IWL_AGG_LOAD_THRESHOLD)) { IWL_DEBUG_HT(priv, "Starting Tx agg: STA: %pM tid: %d\n", sta->addr, tid); ret = ieee80211_start_tx_ba_session(sta, tid, 5000); @@ -711,7 +709,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags, static bool rs_use_green(struct ieee80211_sta *sta) { struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - struct iwl_rxon_context *ctx = sta_priv->common.ctx; + struct iwl_rxon_context *ctx = sta_priv->ctx; return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && !(ctx->ht.non_gf_sta_present); @@ -820,7 +818,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta, if (num_of_ant(tbl->ant_type) > 1) tbl->ant_type = - first_antenna(priv->hw_params.valid_tx_ant); + first_antenna(hw_params(priv).valid_tx_ant); tbl->is_ht40 = 0; tbl->is_SGI = 0; @@ -878,12 +876,12 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, * Is there a need to switch between * full concurrency and 3-wire? */ - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->shrd->lock, flags); if (priv->bt_ci_compliance && priv->bt_ant_couple_ok) full_concurrent = true; else full_concurrent = false; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); } if ((priv->bt_traffic_load != priv->last_bt_traffic_load) || (priv->bt_full_concurrent != full_concurrent)) { @@ -894,7 +892,7 @@ static void rs_bt_update_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, rs_fill_link_cmd(priv, lq_sta, tbl->current_rate); iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false); - queue_work(priv->workqueue, &priv->bt_full_concurrency); + queue_work(priv->shrd->workqueue, &priv->bt_full_concurrency); } } @@ -918,7 +916,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - struct iwl_rxon_context *ctx = sta_priv->common.ctx; + struct iwl_rxon_context *ctx = sta_priv->ctx; IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n"); @@ -1284,7 +1282,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, s32 rate; s8 is_green = lq_sta->is_green; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - struct iwl_rxon_context *ctx = sta_priv->common.ctx; + struct iwl_rxon_context *ctx = sta_priv->ctx; if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) return -1; @@ -1294,7 +1292,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, return -1; /* Need both Tx chains/antennas to support MIMO */ - if (priv->hw_params.tx_chains_num < 2) + if (hw_params(priv).tx_chains_num < 2) return -1; IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO2\n"); @@ -1340,7 +1338,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, s32 rate; s8 is_green = lq_sta->is_green; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - struct iwl_rxon_context *ctx = sta_priv->common.ctx; + struct iwl_rxon_context *ctx = sta_priv->ctx; if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) return -1; @@ -1350,7 +1348,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv, return -1; /* Need both Tx chains/antennas to support MIMO */ - if (priv->hw_params.tx_chains_num < 3) + if (hw_params(priv).tx_chains_num < 3) return -1; IWL_DEBUG_RATE(priv, "LQ: try to switch to MIMO3\n"); @@ -1397,7 +1395,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, u8 is_green = lq_sta->is_green; s32 rate; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - struct iwl_rxon_context *ctx = sta_priv->common.ctx; + struct iwl_rxon_context *ctx = sta_priv->ctx; if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported) return -1; @@ -1449,8 +1447,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; - u8 valid_tx_ant = priv->hw_params.valid_tx_ant; - u8 tx_chains_num = priv->hw_params.tx_chains_num; + u8 valid_tx_ant = hw_params(priv).valid_tx_ant; + u8 tx_chains_num = hw_params(priv).tx_chains_num; int ret = 0; u8 update_search_tbl_counter = 0; @@ -1460,14 +1458,16 @@ static int rs_move_legacy_other(struct iwl_priv *priv, break; case IWL_BT_COEX_TRAFFIC_LOAD_LOW: /* avoid antenna B unless MIMO */ - valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant); + valid_tx_ant = + first_antenna(hw_params(priv).valid_tx_ant); if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2) tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; break; case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: /* avoid antenna B and MIMO */ - valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant); + valid_tx_ant = + first_antenna(hw_params(priv).valid_tx_ant); if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2 && tbl->action != IWL_LEGACY_SWITCH_SISO) tbl->action = IWL_LEGACY_SWITCH_SISO; @@ -1490,7 +1490,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv, tbl->action = IWL_LEGACY_SWITCH_ANTENNA1; else if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2) tbl->action = IWL_LEGACY_SWITCH_SISO; - valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant); + valid_tx_ant = + first_antenna(hw_params(priv).valid_tx_ant); } start_action = tbl->action; @@ -1624,8 +1625,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; - u8 valid_tx_ant = priv->hw_params.valid_tx_ant; - u8 tx_chains_num = priv->hw_params.tx_chains_num; + u8 valid_tx_ant = hw_params(priv).valid_tx_ant; + u8 tx_chains_num = hw_params(priv).tx_chains_num; u8 update_search_tbl_counter = 0; int ret; @@ -1635,14 +1636,16 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, break; case IWL_BT_COEX_TRAFFIC_LOAD_LOW: /* avoid antenna B unless MIMO */ - valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant); + valid_tx_ant = + first_antenna(hw_params(priv).valid_tx_ant); if (tbl->action == IWL_SISO_SWITCH_ANTENNA2) tbl->action = IWL_SISO_SWITCH_ANTENNA1; break; case IWL_BT_COEX_TRAFFIC_LOAD_HIGH: case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS: /* avoid antenna B and MIMO */ - valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant); + valid_tx_ant = + first_antenna(hw_params(priv).valid_tx_ant); if (tbl->action != IWL_SISO_SWITCH_ANTENNA1) tbl->action = IWL_SISO_SWITCH_ANTENNA1; break; @@ -1659,7 +1662,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv, /* configure as 1x1 if bt full concurrency */ if (priv->bt_full_concurrent) { - valid_tx_ant = first_antenna(priv->hw_params.valid_tx_ant); + valid_tx_ant = + first_antenna(hw_params(priv).valid_tx_ant); if (tbl->action >= IWL_LEGACY_SWITCH_ANTENNA2) tbl->action = IWL_SISO_SWITCH_ANTENNA1; } @@ -1795,8 +1799,8 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; - u8 valid_tx_ant = priv->hw_params.valid_tx_ant; - u8 tx_chains_num = priv->hw_params.tx_chains_num; + u8 valid_tx_ant = hw_params(priv).valid_tx_ant; + u8 tx_chains_num = hw_params(priv).tx_chains_num; u8 update_search_tbl_counter = 0; int ret; @@ -1965,8 +1969,8 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv, u32 sz = (sizeof(struct iwl_scale_tbl_info) - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); u8 start_action; - u8 valid_tx_ant = priv->hw_params.valid_tx_ant; - u8 tx_chains_num = priv->hw_params.tx_chains_num; + u8 valid_tx_ant = hw_params(priv).valid_tx_ant; + u8 tx_chains_num = hw_params(priv).tx_chains_num; int ret; u8 update_search_tbl_counter = 0; @@ -2209,7 +2213,6 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) /* * setup rate table in uCode - * return rate_n_flags as used in the table */ static void rs_update_rate_tbl(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -2256,10 +2259,10 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, u8 done_search = 0; u16 high_low; s32 sr; - u8 tid = MAX_TID_COUNT; + u8 tid = IWL_MAX_TID_COUNT; struct iwl_tid_data *tid_data; struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; - struct iwl_rxon_context *ctx = sta_priv->common.ctx; + struct iwl_rxon_context *ctx = sta_priv->ctx; IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n"); @@ -2269,14 +2272,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, info->flags & IEEE80211_TX_CTL_NO_ACK) return; - if (!sta || !lq_sta) - return; - lq_sta->supp_rates = sta->supp_rates[lq_sta->band]; tid = rs_tl_add_packet(lq_sta, hdr); - if ((tid != MAX_TID_COUNT) && (lq_sta->tx_agg_tid_en & (1 << tid))) { - tid_data = &priv->stations[lq_sta->lq.sta_id].tid[tid]; + if ((tid != IWL_MAX_TID_COUNT) && + (lq_sta->tx_agg_tid_en & (1 << tid))) { + tid_data = &priv->shrd->tid_data[lq_sta->lq.sta_id][tid]; if (tid_data->agg.state == IWL_AGG_OFF) lq_sta->is_agg = 0; else @@ -2646,9 +2647,10 @@ lq_update: iwl_ht_enabled(priv)) { if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) && (lq_sta->tx_agg_tid_en & (1 << tid)) && - (tid != MAX_TID_COUNT)) { + (tid != IWL_MAX_TID_COUNT)) { + u8 sta_id = lq_sta->lq.sta_id; tid_data = - &priv->stations[lq_sta->lq.sta_id].tid[tid]; + &priv->shrd->tid_data[sta_id][tid]; if (tid_data->agg.state == IWL_AGG_OFF) { IWL_DEBUG_RATE(priv, "try to aggregate tid %d\n", @@ -2663,8 +2665,7 @@ lq_update: out: tbl->current_rate = rate_n_flags_from_tbl(priv, tbl, index, is_green); - i = index; - lq_sta->last_txrate_idx = i; + lq_sta->last_txrate_idx = index; } /** @@ -2700,11 +2701,11 @@ static void rs_initialize_lq(struct iwl_priv *priv, return; sta_priv = (void *)sta->drv_priv; - ctx = sta_priv->common.ctx; + ctx = sta_priv->ctx; i = lq_sta->last_txrate_idx; - valid_tx_ant = priv->hw_params.valid_tx_ant; + valid_tx_ant = hw_params(priv).valid_tx_ant; if (!lq_sta->search_better_tbl) active_tbl = lq_sta->active_tbl; @@ -2887,15 +2888,15 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i /* These values will be overridden later */ lq_sta->lq.general_params.single_stream_ant_msk = - first_antenna(priv->hw_params.valid_tx_ant); + first_antenna(hw_params(priv).valid_tx_ant); lq_sta->lq.general_params.dual_stream_ant_msk = - priv->hw_params.valid_tx_ant & - ~first_antenna(priv->hw_params.valid_tx_ant); + hw_params(priv).valid_tx_ant & + ~first_antenna(hw_params(priv).valid_tx_ant); if (!lq_sta->lq.general_params.dual_stream_ant_msk) { lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; - } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { + } else if (num_of_ant(hw_params(priv).valid_tx_ant) == 2) { lq_sta->lq.general_params.dual_stream_ant_msk = - priv->hw_params.valid_tx_ant; + hw_params(priv).valid_tx_ant; } /* as default allow aggregation for all tids */ @@ -2941,7 +2942,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, if (priv && priv->bt_full_concurrent) { /* 1x1 only */ tbl_type.ant_type = - first_antenna(priv->hw_params.valid_tx_ant); + first_antenna(hw_params(priv).valid_tx_ant); } /* How many times should we repeat the initial rate? */ @@ -2973,7 +2974,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, if (priv->bt_full_concurrent) valid_tx_ant = ANT_A; else - valid_tx_ant = priv->hw_params.valid_tx_ant; + valid_tx_ant = hw_params(priv).valid_tx_ant; } /* Fill rest of rate table */ @@ -3007,7 +3008,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, if (priv && priv->bt_full_concurrent) { /* 1x1 only */ tbl_type.ant_type = - first_antenna(priv->hw_params.valid_tx_ant); + first_antenna(hw_params(priv).valid_tx_ant); } /* Indicate to uCode which entries might be MIMO. @@ -3098,7 +3099,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, u8 ant_sel_tx; priv = lq_sta->drv; - valid_tx_ant = priv->hw_params.valid_tx_ant; + valid_tx_ant = hw_params(priv).valid_tx_ant; if (lq_sta->dbg_fixed_rate) { ant_sel_tx = ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK) @@ -3169,9 +3170,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, desc += sprintf(buff+desc, "fixed rate 0x%X\n", lq_sta->dbg_fixed_rate); desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n", - (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "", - (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "", - (priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : ""); + (hw_params(priv).valid_tx_ant & ANT_A) ? "ANT_A," : "", + (hw_params(priv).valid_tx_ant & ANT_B) ? "ANT_B," : "", + (hw_params(priv).valid_tx_ant & ANT_C) ? "ANT_C" : ""); desc += sprintf(buff+desc, "lq type %s\n", (is_legacy(tbl->lq_type)) ? "legacy" : "HT"); if (is_Ht(tbl->lq_type)) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index bdae82e7fa90..f4f6deb829ae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -27,6 +27,10 @@ #ifndef __iwl_agn_rs_h__ #define __iwl_agn_rs_h__ +#include <net/mac80211.h> + +#include "iwl-commands.h" + struct iwl_rate_info { u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */ u8 plcp_siso; /* uCode API: IWL_RATE_SISO_6M_PLCP, etc. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c index 8e314003b63a..5af9e6258a16 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c @@ -3,7 +3,7 @@ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. + * as portionhelp of the ieee80211 subsystem header files. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -35,12 +35,93 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-sta.h" #include "iwl-io.h" -#include "iwl-helpers.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" +#include "iwl-shared.h" +const char *get_cmd_string(u8 cmd) +{ + switch (cmd) { + IWL_CMD(REPLY_ALIVE); + IWL_CMD(REPLY_ERROR); + IWL_CMD(REPLY_ECHO); + IWL_CMD(REPLY_RXON); + IWL_CMD(REPLY_RXON_ASSOC); + IWL_CMD(REPLY_QOS_PARAM); + IWL_CMD(REPLY_RXON_TIMING); + IWL_CMD(REPLY_ADD_STA); + IWL_CMD(REPLY_REMOVE_STA); + IWL_CMD(REPLY_REMOVE_ALL_STA); + IWL_CMD(REPLY_TXFIFO_FLUSH); + IWL_CMD(REPLY_WEPKEY); + IWL_CMD(REPLY_TX); + IWL_CMD(REPLY_LEDS_CMD); + IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); + IWL_CMD(COEX_PRIORITY_TABLE_CMD); + IWL_CMD(COEX_MEDIUM_NOTIFICATION); + IWL_CMD(COEX_EVENT_CMD); + IWL_CMD(REPLY_QUIET_CMD); + IWL_CMD(REPLY_CHANNEL_SWITCH); + IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); + IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); + IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); + IWL_CMD(POWER_TABLE_CMD); + IWL_CMD(PM_SLEEP_NOTIFICATION); + IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); + IWL_CMD(REPLY_SCAN_CMD); + IWL_CMD(REPLY_SCAN_ABORT_CMD); + IWL_CMD(SCAN_START_NOTIFICATION); + IWL_CMD(SCAN_RESULTS_NOTIFICATION); + IWL_CMD(SCAN_COMPLETE_NOTIFICATION); + IWL_CMD(BEACON_NOTIFICATION); + IWL_CMD(REPLY_TX_BEACON); + IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); + IWL_CMD(QUIET_NOTIFICATION); + IWL_CMD(REPLY_TX_PWR_TABLE_CMD); + IWL_CMD(MEASURE_ABORT_NOTIFICATION); + IWL_CMD(REPLY_BT_CONFIG); + IWL_CMD(REPLY_STATISTICS_CMD); + IWL_CMD(STATISTICS_NOTIFICATION); + IWL_CMD(REPLY_CARD_STATE_CMD); + IWL_CMD(CARD_STATE_NOTIFICATION); + IWL_CMD(MISSED_BEACONS_NOTIFICATION); + IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); + IWL_CMD(SENSITIVITY_CMD); + IWL_CMD(REPLY_PHY_CALIBRATION_CMD); + IWL_CMD(REPLY_RX_PHY_CMD); + IWL_CMD(REPLY_RX_MPDU_CMD); + IWL_CMD(REPLY_RX); + IWL_CMD(REPLY_COMPRESSED_BA); + IWL_CMD(CALIBRATION_CFG_CMD); + IWL_CMD(CALIBRATION_RES_NOTIFICATION); + IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); + IWL_CMD(REPLY_TX_POWER_DBM_CMD); + IWL_CMD(TEMPERATURE_NOTIFICATION); + IWL_CMD(TX_ANT_CONFIGURATION_CMD); + IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF); + IWL_CMD(REPLY_BT_COEX_PRIO_TABLE); + IWL_CMD(REPLY_BT_COEX_PROT_ENV); + IWL_CMD(REPLY_WIPAN_PARAMS); + IWL_CMD(REPLY_WIPAN_RXON); + IWL_CMD(REPLY_WIPAN_RXON_TIMING); + IWL_CMD(REPLY_WIPAN_RXON_ASSOC); + IWL_CMD(REPLY_WIPAN_QOS_PARAM); + IWL_CMD(REPLY_WIPAN_WEPKEY); + IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); + IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); + IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); + IWL_CMD(REPLY_WOWLAN_PATTERNS); + IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER); + IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS); + IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS); + IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL); + IWL_CMD(REPLY_WOWLAN_GET_STATUS); + default: + return "UNKNOWN"; + + } +} /****************************************************************************** * @@ -48,8 +129,9 @@ * ******************************************************************************/ -static void iwl_rx_reply_error(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_reply_error(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -60,21 +142,23 @@ static void iwl_rx_reply_error(struct iwl_priv *priv, pkt->u.err_resp.cmd_id, le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num), le32_to_cpu(pkt->u.err_resp.error_info)); + return 0; } -static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_csa_notification *csa = &(pkt->u.csa_notif); /* * MULTI-FIXME - * See iwl_mac_channel_switch. + * See iwlagn_mac_channel_switch. */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; struct iwl_rxon_cmd *rxon = (void *)&ctx->active; - if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) - return; + if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status)) + return 0; if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) { rxon->channel = csa->channel; @@ -87,11 +171,13 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) le16_to_cpu(csa->channel)); iwl_chswitch_done(priv, false); } + return 0; } -static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); @@ -99,15 +185,17 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, if (!report->state) { IWL_DEBUG_11H(priv, "Spectrum Measure Notification: Start\n"); - return; + return 0; } memcpy(&priv->measure_report, report, sizeof(*report)); priv->measurement_status |= MEASUREMENT_READY; + return 0; } -static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_pm_sleep_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -115,21 +203,26 @@ static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); #endif + return 0; } -static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_pm_debug_statistics_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + u32 __maybe_unused len = + le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled " "notification for %s:\n", len, get_cmd_string(pkt->hdr.cmd)); iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len); + return 0; } -static void iwl_rx_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw; @@ -148,8 +241,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, priv->ibss_manager = le32_to_cpu(beacon->ibss_mgr_status); - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) - queue_work(priv->workqueue, &priv->beacon_update); + return 0; } /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */ @@ -164,7 +256,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv, * the BA_TIMEOUT_MAX, reload firmware and bring system back to normal * operation state. */ -static bool iwl_good_ack_health(struct iwl_priv *priv, +static bool iwlagn_good_ack_health(struct iwl_priv *priv, struct statistics_tx *cur) { int actual_delta, expected_delta, ba_timeout_delta; @@ -189,8 +281,9 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, if ((actual_delta * 100 / expected_delta) < ACK_CNT_RATIO && ba_timeout_delta > BA_TIMEOUT_CNT) { - IWL_DEBUG_RADIO(priv, "deltas: actual %d expected %d ba_timeout %d\n", - actual_delta, expected_delta, ba_timeout_delta); + IWL_DEBUG_RADIO(priv, + "deltas: actual %d expected %d ba_timeout %d\n", + actual_delta, expected_delta, ba_timeout_delta); #ifdef CONFIG_IWLWIFI_DEBUGFS /* @@ -218,7 +311,7 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, * When the plcp error is exceeding the thresholds, reset the radio * to improve the throughput. */ -static bool iwl_good_plcp_health(struct iwl_priv *priv, +static bool iwlagn_good_plcp_health(struct iwl_priv *priv, struct statistics_rx_phy *cur_ofdm, struct statistics_rx_ht_phy *cur_ofdm_ht, unsigned int msecs) @@ -250,15 +343,15 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv, return true; } -static void iwl_recover_from_statistics(struct iwl_priv *priv, - struct statistics_rx_phy *cur_ofdm, - struct statistics_rx_ht_phy *cur_ofdm_ht, - struct statistics_tx *tx, - unsigned long stamp) +static void iwlagn_recover_from_statistics(struct iwl_priv *priv, + struct statistics_rx_phy *cur_ofdm, + struct statistics_rx_ht_phy *cur_ofdm_ht, + struct statistics_tx *tx, + unsigned long stamp) { unsigned int msecs; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies); @@ -271,21 +364,21 @@ static void iwl_recover_from_statistics(struct iwl_priv *priv, if (msecs < 99) return; - if (iwlagn_mod_params.ack_check && !iwl_good_ack_health(priv, tx)) { + if (iwlagn_mod_params.ack_check && !iwlagn_good_ack_health(priv, tx)) { IWL_ERR(priv, "low ack count detected, restart firmware\n"); if (!iwl_force_reset(priv, IWL_FW_RESET, false)) return; } if (iwlagn_mod_params.plcp_check && - !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) + !iwlagn_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs)) iwl_force_reset(priv, IWL_RF_RESET, false); } /* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know * exactly when to expect beacons, therefore only when we're associated. */ -static void iwl_rx_calc_noise(struct iwl_priv *priv) +static void iwlagn_rx_calc_noise(struct iwl_priv *priv) { struct statistics_rx_non_phy *rx_info; int num_active_rx = 0; @@ -351,7 +444,7 @@ static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta, } static void -iwl_accumulative_statistics(struct iwl_priv *priv, +iwlagn_accumulative_statistics(struct iwl_priv *priv, struct statistics_general_common *common, struct statistics_rx_non_phy *rx_non_phy, struct statistics_rx_phy *rx_ofdm, @@ -380,7 +473,7 @@ iwl_accumulative_statistics(struct iwl_priv *priv, } #else static inline void -iwl_accumulative_statistics(struct iwl_priv *priv, +iwlagn_accumulative_statistics(struct iwl_priv *priv, struct statistics_general_common *common, struct statistics_rx_non_phy *rx_non_phy, struct statistics_rx_phy *rx_ofdm, @@ -392,8 +485,9 @@ iwl_accumulative_statistics(struct iwl_priv *priv, } #endif -static void iwl_rx_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { unsigned long stamp = jiffies; const int reg_recalib_period = 60; @@ -447,17 +541,17 @@ static void iwl_rx_statistics(struct iwl_priv *priv, WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n", len, sizeof(struct iwl_bt_notif_statistics), sizeof(struct iwl_notif_statistics)); - return; + return 0; } change = common->temperature != priv->statistics.common.temperature || (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) != (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK); - iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm, + iwlagn_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm, rx_ofdm_ht, rx_cck, tx, bt_activity); - iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp); + iwlagn_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp); priv->statistics.flag = *flag; memcpy(&priv->statistics.common, common, sizeof(*common)); @@ -474,7 +568,7 @@ static void iwl_rx_statistics(struct iwl_priv *priv, priv->rx_statistics_jiffies = stamp; - set_bit(STATUS_STATISTICS, &priv->status); + set_bit(STATUS_STATISTICS, &priv->shrd->status); /* Reschedule the statistics timer to occur in * reg_recalib_period seconds to ensure we get a @@ -483,17 +577,19 @@ static void iwl_rx_statistics(struct iwl_priv *priv, mod_timer(&priv->statistics_periodic, jiffies + msecs_to_jiffies(reg_recalib_period * 1000)); - if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && + if (unlikely(!test_bit(STATUS_SCANNING, &priv->shrd->status)) && (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { - iwl_rx_calc_noise(priv); - queue_work(priv->workqueue, &priv->run_time_calib_work); + iwlagn_rx_calc_noise(priv); + queue_work(priv->shrd->workqueue, &priv->run_time_calib_work); } if (priv->cfg->lib->temperature && change) priv->cfg->lib->temperature(priv); + return 0; } -static void iwl_rx_reply_statistics(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_reply_statistics(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -508,17 +604,19 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv, #endif IWL_DEBUG_RX(priv, "Statistics have been cleared\n"); } - iwl_rx_statistics(priv, rxb); + iwlagn_rx_statistics(priv, rxb, cmd); + return 0; } /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static void iwl_rx_card_state_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_card_state_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags); - unsigned long status = priv->status; + unsigned long status = priv->shrd->status; IWL_DEBUG_RF_KILL(priv, "Card state received: HW:%s SW:%s CT:%s\n", (flags & HW_CARD_DISABLED) ? "Kill" : "On", @@ -529,16 +627,16 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | CT_CARD_DISABLED)) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(priv, HBUS_TARG_MBX_C, + iwl_write_direct32(bus(priv), HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); if (!(flags & RXON_CARD_DISABLED)) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(priv, HBUS_TARG_MBX_C, + iwl_write_direct32(bus(priv), HBUS_TARG_MBX_C, HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); } if (flags & CT_CARD_DISABLED) @@ -548,24 +646,26 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, iwl_tt_exit_ct_kill(priv); if (flags & HW_CARD_DISABLED) - set_bit(STATUS_RF_KILL_HW, &priv->status); + set_bit(STATUS_RF_KILL_HW, &priv->shrd->status); else - clear_bit(STATUS_RF_KILL_HW, &priv->status); + clear_bit(STATUS_RF_KILL_HW, &priv->shrd->status); if (!(flags & RXON_CARD_DISABLED)) iwl_scan_cancel(priv); if ((test_bit(STATUS_RF_KILL_HW, &status) != - test_bit(STATUS_RF_KILL_HW, &priv->status))) + test_bit(STATUS_RF_KILL_HW, &priv->shrd->status))) wiphy_rfkill_set_hw_state(priv->hw->wiphy, - test_bit(STATUS_RF_KILL_HW, &priv->status)); + test_bit(STATUS_RF_KILL_HW, &priv->shrd->status)); else - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->shrd->wait_command_queue); + return 0; } -static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_missed_beacon_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -580,27 +680,30 @@ static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, le32_to_cpu(missed_beacon->total_missed_becons), le32_to_cpu(missed_beacon->num_recvd_beacons), le32_to_cpu(missed_beacon->num_expected_beacons)); - if (!test_bit(STATUS_SCANNING, &priv->status)) + if (!test_bit(STATUS_SCANNING, &priv->shrd->status)) iwl_init_sensitivity(priv); } + return 0; } /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ -static void iwl_rx_reply_rx_phy(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); priv->last_phy_res_valid = true; memcpy(&priv->last_phy_res, pkt->u.raw, sizeof(struct iwl_rx_phy_res)); + return 0; } /* * returns non-zero if packet should be dropped */ -static int iwl_set_decrypted_flag(struct iwl_priv *priv, +static int iwlagn_set_decrypted_flag(struct iwl_priv *priv, struct ieee80211_hdr *hdr, u32 decrypt_res, struct ieee80211_rx_status *stats) @@ -649,7 +752,7 @@ static int iwl_set_decrypted_flag(struct iwl_priv *priv, return 0; } -static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, +static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, struct ieee80211_hdr *hdr, u16 len, u32 ampdu_status, @@ -669,7 +772,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, /* In case of HW accelerated crypto and bad decryption, drop */ if (!iwlagn_mod_params.sw_crypto && - iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) + iwlagn_set_decrypted_flag(priv, hdr, ampdu_status, stats)) return; skb = dev_alloc_skb(128); @@ -697,7 +800,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, ctx->active.bssid_addr)) continue; ctx->last_tx_rejected = false; - iwl_wake_any_queue(priv, ctx); + iwl_trans_wake_any_queue(trans(priv), ctx->ctxid); } } @@ -707,7 +810,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, rxb->page = NULL; } -static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) +static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) { u32 decrypt_out = 0; @@ -809,8 +912,9 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv, /* Called for REPLY_RX (legacy ABG frames), or * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ -static void iwl_rx_reply_rx(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwlagn_rx_reply_rx(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct ieee80211_hdr *header; struct ieee80211_rx_status rx_status; @@ -843,28 +947,28 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv, } else { if (!priv->last_phy_res_valid) { IWL_ERR(priv, "MPDU frame without cached PHY data\n"); - return; + return 0; } phy_res = &priv->last_phy_res; amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw; header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); len = le16_to_cpu(amsdu->byte_count); rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); - ampdu_status = iwl_translate_rx_status(priv, + ampdu_status = iwlagn_translate_rx_status(priv, le32_to_cpu(rx_pkt_status)); } if ((unlikely(phy_res->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", phy_res->cfg_phy_cnt); - return; + return 0; } if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", le32_to_cpu(rx_pkt_status)); - return; + return 0; } /* This will be used in several places later */ @@ -923,8 +1027,9 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv, if (rate_n_flags & RATE_MCS_SGI_MSK) rx_status.flag |= RX_FLAG_SHORT_GI; - iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, + iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status, rxb, &rx_status); + return 0; } /** @@ -935,36 +1040,42 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv, */ void iwl_setup_rx_handlers(struct iwl_priv *priv) { - void (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); + int (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); handlers = priv->rx_handlers; - handlers[REPLY_ERROR] = iwl_rx_reply_error; - handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; - handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif; - handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; - handlers[PM_DEBUG_STATISTIC_NOTIFIC] = iwl_rx_pm_debug_statistics_notif; - handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; + handlers[REPLY_ERROR] = iwlagn_rx_reply_error; + handlers[CHANNEL_SWITCH_NOTIFICATION] = iwlagn_rx_csa; + handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwlagn_rx_spectrum_measure_notif; + handlers[PM_SLEEP_NOTIFICATION] = iwlagn_rx_pm_sleep_notif; + handlers[PM_DEBUG_STATISTIC_NOTIFIC] = + iwlagn_rx_pm_debug_statistics_notif; + handlers[BEACON_NOTIFICATION] = iwlagn_rx_beacon_notif; + handlers[REPLY_ADD_STA] = iwl_add_sta_callback; /* * The same handler is used for both the REPLY to a discrete * statistics request from the host as well as for the periodic * statistics notifications (after received beacons) from the uCode. */ - handlers[REPLY_STATISTICS_CMD] = iwl_rx_reply_statistics; - handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; + handlers[REPLY_STATISTICS_CMD] = iwlagn_rx_reply_statistics; + handlers[STATISTICS_NOTIFICATION] = iwlagn_rx_statistics; iwl_setup_rx_scan_handlers(priv); - handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; - handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; + handlers[CARD_STATE_NOTIFICATION] = iwlagn_rx_card_state_notif; + handlers[MISSED_BEACONS_NOTIFICATION] = + iwlagn_rx_missed_beacon_notif; /* Rx handlers */ - handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; - handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; + handlers[REPLY_RX_PHY_CMD] = iwlagn_rx_reply_rx_phy; + handlers[REPLY_RX_MPDU_CMD] = iwlagn_rx_reply_rx; /* block ack */ - handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; + handlers[REPLY_COMPRESSED_BA] = + iwlagn_rx_reply_compressed_ba; /* init calibration handlers */ priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] = @@ -982,9 +1093,11 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv) } -void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); + int err = 0; /* * Do the notification wait before RX handlers so @@ -1018,12 +1131,13 @@ void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) * handle those that need handling via function in * rx_handlers table. See iwl_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { - priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; - priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); + priv->rx_handlers_stats[pkt->hdr.cmd]++; + err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd); } else { /* No handling needed */ IWL_DEBUG_RX(priv, "No handler needed for %s, 0x%02x\n", get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); } + return err; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index d42ef1763a71..58a381c01c89 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -26,11 +26,10 @@ #include "iwl-dev.h" #include "iwl-agn.h" -#include "iwl-sta.h" #include "iwl-core.h" #include "iwl-agn-calib.h" -#include "iwl-helpers.h" #include "iwl-trans.h" +#include "iwl-shared.h" static int iwlagn_disable_bss(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -40,7 +39,7 @@ static int iwlagn_disable_bss(struct iwl_priv *priv, int ret; send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd, + ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd, CMD_SYNC, sizeof(*send), send); send->filter_flags = old_filter; @@ -66,7 +65,7 @@ static int iwlagn_disable_pan(struct iwl_priv *priv, send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; send->dev_type = RXON_DEV_TYPE_P2P; - ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd, + ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd, CMD_SYNC, sizeof(*send), send); send->filter_flags = old_filter; @@ -92,7 +91,7 @@ static int iwlagn_disconn_pan(struct iwl_priv *priv, int ret; send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; - ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd, CMD_SYNC, + ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd, CMD_SYNC, sizeof(*send), send); send->filter_flags = old_filter; @@ -121,7 +120,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv, ctx->qos_data.qos_active, ctx->qos_data.def_qos_parm.qos_flags); - ret = trans_send_cmd_pdu(&priv->trans, ctx->qos_cmd, CMD_SYNC, + ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->qos_cmd, CMD_SYNC, sizeof(struct iwl_qosparam_cmd), &ctx->qos_data.def_qos_parm); if (ret) @@ -131,7 +130,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv, static int iwlagn_update_beacon(struct iwl_priv *priv, struct ieee80211_vif *vif) { - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = ieee80211_beacon_get(priv->hw, vif); @@ -180,7 +179,7 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv, ctx->staging.ofdm_ht_triple_stream_basic_rates; rxon_assoc.acquisition_data = ctx->staging.acquisition_data; - ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_assoc_cmd, + ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_assoc_cmd, CMD_ASYNC, sizeof(rxon_assoc), &rxon_assoc); return ret; } @@ -266,7 +265,7 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv, * Associated RXON doesn't clear the station table in uCode, * so we don't need to restore stations etc. after this. */ - ret = trans_send_cmd_pdu(&priv->trans, ctx->rxon_cmd, CMD_SYNC, + ret = iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_cmd, CMD_SYNC, sizeof(struct iwl_rxon_cmd), &ctx->staging); if (ret) { IWL_ERR(priv, "Error setting new RXON (%d)\n", ret); @@ -295,8 +294,8 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv, return ret; } - if ((ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) && - priv->cfg->ht_params->smps_mode) + if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION && + priv->cfg->ht_params && priv->cfg->ht_params->smps_mode) ieee80211_request_smps(ctx->vif, priv->cfg->ht_params->smps_mode); @@ -310,12 +309,12 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) int slot0 = 300, slot1 = 0; int ret; - if (priv->valid_contexts == BIT(IWL_RXON_CTX_BSS)) + if (priv->shrd->valid_contexts == BIT(IWL_RXON_CTX_BSS)) return 0; BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); ctx_bss = &priv->contexts[IWL_RXON_CTX_BSS]; ctx_pan = &priv->contexts[IWL_RXON_CTX_PAN]; @@ -337,10 +336,10 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) cmd.slots[0].type = 0; /* BSS */ cmd.slots[1].type = 1; /* PAN */ - if (priv->hw_roc_channel) { + if (priv->hw_roc_setup) { /* both contexts must be used for this to happen */ - slot1 = priv->hw_roc_duration; - slot0 = IWL_MIN_SLOT_TIME; + slot1 = IWL_MIN_SLOT_TIME; + slot0 = 3000; } else if (ctx_bss->vif && ctx_pan->vif) { int bcnint = ctx_pan->beacon_int; int dtim = ctx_pan->vif->bss_conf.dtim_period ?: 1; @@ -362,14 +361,14 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) slot0 = bcnint / 2; slot1 = bcnint - slot0; - if (test_bit(STATUS_SCAN_HW, &priv->status) || + if (test_bit(STATUS_SCAN_HW, &priv->shrd->status) || (!ctx_bss->vif->bss_conf.idle && !ctx_bss->vif->bss_conf.assoc)) { slot0 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; slot1 = IWL_MIN_SLOT_TIME; } else if (!ctx_pan->vif->bss_conf.idle && !ctx_pan->vif->bss_conf.assoc) { - slot1 = bcnint * 3 - IWL_MIN_SLOT_TIME; + slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME; slot0 = IWL_MIN_SLOT_TIME; } } else if (ctx_pan->vif) { @@ -378,7 +377,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) ctx_pan->beacon_int; slot1 = max_t(int, DEFAULT_BEACON_INTERVAL, slot1); - if (test_bit(STATUS_SCAN_HW, &priv->status)) { + if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) { slot0 = slot1 * 3 - IWL_MIN_SLOT_TIME; slot1 = IWL_MIN_SLOT_TIME; } @@ -387,7 +386,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv) cmd.slots[0].width = cpu_to_le16(slot0); cmd.slots[1].width = cpu_to_le16(slot1); - ret = trans_send_cmd_pdu(&priv->trans, REPLY_WIPAN_PARAMS, CMD_SYNC, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WIPAN_PARAMS, CMD_SYNC, sizeof(cmd), &cmd); if (ret) IWL_ERR(priv, "Error setting PAN parameters (%d)\n", ret); @@ -420,12 +419,12 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK); int ret; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return -EINVAL; - if (!iwl_is_alive(priv)) + if (!iwl_is_alive(priv->shrd)) return -EBUSY; /* This function hardcodes a bunch of dual-mode assumptions */ @@ -434,26 +433,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) if (!ctx->is_active) return 0; + /* override BSSID if necessary due to preauth */ + if (ctx->preauth_bssid) + memcpy(ctx->staging.bssid_addr, ctx->bssid, ETH_ALEN); + /* always get timestamp with Rx frame */ ctx->staging.flags |= RXON_FLG_TSF2HOST_MSK; - if (ctx->ctxid == IWL_RXON_CTX_PAN && priv->hw_roc_channel) { - struct ieee80211_channel *chan = priv->hw_roc_channel; - - iwl_set_rxon_channel(priv, chan, ctx); - iwl_set_flags_for_band(priv, ctx, chan->band, NULL); - ctx->staging.filter_flags |= - RXON_FILTER_ASSOC_MSK | - RXON_FILTER_PROMISC_MSK | - RXON_FILTER_CTL2HOST_MSK; - ctx->staging.dev_type = RXON_DEV_TYPE_P2P; - new_assoc = true; - - if (memcmp(&ctx->staging, &ctx->active, - sizeof(ctx->staging)) == 0) - return 0; - } - /* * force CTS-to-self frames protection if RTS-CTS is not preferred * one aggregation protection method @@ -468,7 +454,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) else ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK; - iwl_print_rx_config_cmd(priv, ctx); + iwl_print_rx_config_cmd(priv, ctx->ctxid); ret = iwl_check_rxon_cmd(priv, ctx); if (ret) { IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n"); @@ -479,7 +465,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) * receive commit_rxon request * abort any previous channel switch if still in process */ - if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) && + if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status) && (priv->switch_channel != ctx->staging.channel)) { IWL_DEBUG_11H(priv, "abort channel switch on %d\n", le16_to_cpu(priv->switch_channel)); @@ -551,16 +537,16 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) const struct iwl_channel_info *ch_info; int ret = 0; - IWL_DEBUG_MAC80211(priv, "changed %#x", changed); + IWL_DEBUG_MAC80211(priv, "enter: changed %#x", changed); - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); - if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { + if (unlikely(test_bit(STATUS_SCANNING, &priv->shrd->status))) { IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); goto out; } - if (!iwl_is_ready(priv)) { + if (!iwl_is_ready(priv->shrd)) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); goto out; } @@ -592,7 +578,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) goto out; } - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->shrd->lock, flags); for_each_context(priv, ctx) { /* Configure HT40 channels */ @@ -636,7 +622,7 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) ctx->vif); } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); iwl_update_bcast_stations(priv); @@ -668,7 +654,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) iwlagn_commit_rxon(priv, ctx); } out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + return ret; } @@ -683,7 +671,7 @@ static void iwlagn_check_needed_chains(struct iwl_priv *priv, struct ieee80211_sta_ht_cap *ht_cap; bool need_multiple; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); switch (vif->type) { case NL80211_IFTYPE_STATION: @@ -787,7 +775,7 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv) memset(&cmd, 0, sizeof(cmd)); iwl_set_calib_hdr(&cmd.hdr, priv->phy_calib_chain_noise_reset_cmd); - ret = trans_send_cmd_pdu(&priv->trans, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_PHY_CALIBRATION_CMD, CMD_SYNC, sizeof(cmd), &cmd); if (ret) @@ -808,17 +796,17 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, int ret; bool force = false; - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); - if (unlikely(!iwl_is_ready(priv))) { + if (unlikely(!iwl_is_ready(priv->shrd))) { IWL_DEBUG_MAC80211(priv, "leave - not ready\n"); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); return; } if (unlikely(!ctx->vif)) { IWL_DEBUG_MAC80211(priv, "leave - vif is NULL\n"); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); return; } @@ -851,7 +839,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, */ if (ctx->last_tx_rejected) { ctx->last_tx_rejected = false; - iwl_wake_any_queue(priv, ctx); + iwl_trans_wake_any_queue(trans(priv), + ctx->ctxid); } ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; @@ -912,6 +901,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (!priv->disable_chain_noise_cal) iwlagn_chain_noise_reset(priv); priv->start_calib = 1; + WARN_ON(ctx->preauth_bssid); } if (changes & BSS_CHANGED_IBSS) { @@ -929,7 +919,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, IWL_ERR(priv, "Error sending IBSS beacon\n"); } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } void iwlagn_post_scan(struct iwl_priv *priv) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index 37e624095e40..ed6283623932 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -31,25 +31,833 @@ #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-sta.h" #include "iwl-agn.h" #include "iwl-trans.h" -static struct iwl_link_quality_cmd * -iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id) +/* priv->shrd->sta_lock must be held */ +static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) +{ + + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) + IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u " + "addr %pM\n", + sta_id, priv->stations[sta_id].sta.sta.addr); + + if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) { + IWL_DEBUG_ASSOC(priv, + "STA id %u addr %pM already present in uCode " + "(according to driver)\n", + sta_id, priv->stations[sta_id].sta.sta.addr); + } else { + priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; + IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n", + sta_id, priv->stations[sta_id].sta.sta.addr); + } +} + +static int iwl_process_add_sta_resp(struct iwl_priv *priv, + struct iwl_addsta_cmd *addsta, + struct iwl_rx_packet *pkt) +{ + u8 sta_id = addsta->sta.sta_id; + unsigned long flags; + int ret = -EIO; + + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", + pkt->hdr.flags); + return ret; + } + + IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", + sta_id); + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + + switch (pkt->u.add_sta.status) { + case ADD_STA_SUCCESS_MSK: + IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); + iwl_sta_ucode_activate(priv, sta_id); + ret = 0; + break; + case ADD_STA_NO_ROOM_IN_TABLE: + IWL_ERR(priv, "Adding station %d failed, no room in table.\n", + sta_id); + break; + case ADD_STA_NO_BLOCK_ACK_RESOURCE: + IWL_ERR(priv, "Adding station %d failed, no block ack " + "resource.\n", sta_id); + break; + case ADD_STA_MODIFY_NON_EXIST_STA: + IWL_ERR(priv, "Attempting to modify non-existing station %d\n", + sta_id); + break; + default: + IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", + pkt->u.add_sta.status); + break; + } + + IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n", + priv->stations[sta_id].sta.mode == + STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", + sta_id, priv->stations[sta_id].sta.sta.addr); + + /* + * XXX: The MAC address in the command buffer is often changed from + * the original sent to the device. That is, the MAC address + * written to the command buffer often is not the same MAC address + * read from the command buffer when the command returns. This + * issue has not yet been resolved and this debugging is left to + * observe the problem. + */ + IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n", + priv->stations[sta_id].sta.mode == + STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", + addsta->sta.addr); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + + return ret; +} + +int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_addsta_cmd *addsta = + (struct iwl_addsta_cmd *) cmd->payload; + + return iwl_process_add_sta_resp(priv, addsta, pkt); +} + +static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) +{ + u16 size = (u16)sizeof(struct iwl_addsta_cmd); + struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data; + memcpy(addsta, cmd, size); + /* resrved in 5000 */ + addsta->rate_n_flags = cpu_to_le16(0); + return size; +} + +int iwl_send_add_sta(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags) +{ + int ret = 0; + u8 data[sizeof(*sta)]; + struct iwl_host_cmd cmd = { + .id = REPLY_ADD_STA, + .flags = flags, + .data = { data, }, + }; + u8 sta_id __maybe_unused = sta->sta.sta_id; + + IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", + sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); + + if (!(flags & CMD_ASYNC)) { + cmd.flags |= CMD_WANT_SKB; + might_sleep(); + } + + cmd.len[0] = iwlagn_build_addsta_hcmd(sta, data); + ret = iwl_trans_send_cmd(trans(priv), &cmd); + + if (ret || (flags & CMD_ASYNC)) + return ret; + /*else the command was successfully sent in SYNC mode, need to free + * the reply page */ + + iwl_free_pages(priv->shrd, cmd.reply_page); + + if (cmd.handler_status) + IWL_ERR(priv, "%s - error in the CMD response %d", __func__, + cmd.handler_status); + + return cmd.handler_status; +} + +static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, + struct ieee80211_sta *sta, + struct iwl_rxon_context *ctx) +{ + struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; + __le32 sta_flags; + u8 mimo_ps_mode; + + if (!sta || !sta_ht_inf->ht_supported) + goto done; + + mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; + IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save mode: %s\n", + (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? + "static" : + (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? + "dynamic" : "disabled"); + + sta_flags = priv->stations[index].sta.station_flags; + + sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); + + switch (mimo_ps_mode) { + case WLAN_HT_CAP_SM_PS_STATIC: + sta_flags |= STA_FLG_MIMO_DIS_MSK; + break; + case WLAN_HT_CAP_SM_PS_DYNAMIC: + sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; + break; + case WLAN_HT_CAP_SM_PS_DISABLED: + break; + default: + IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode); + break; + } + + sta_flags |= cpu_to_le32( + (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); + + sta_flags |= cpu_to_le32( + (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); + + if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) + sta_flags |= STA_FLG_HT40_EN_MSK; + else + sta_flags &= ~STA_FLG_HT40_EN_MSK; + + priv->stations[index].sta.station_flags = sta_flags; + done: + return; +} + +/** + * iwl_prep_station - Prepare station information for addition + * + * should be called with sta_lock held + */ +u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + const u8 *addr, bool is_ap, struct ieee80211_sta *sta) +{ + struct iwl_station_entry *station; + int i; + u8 sta_id = IWL_INVALID_STATION; + + if (is_ap) + sta_id = ctx->ap_sta_id; + else if (is_broadcast_ether_addr(addr)) + sta_id = ctx->bcast_sta_id; + else + for (i = IWL_STA_ID; i < IWLAGN_STATION_COUNT; i++) { + if (!compare_ether_addr(priv->stations[i].sta.sta.addr, + addr)) { + sta_id = i; + break; + } + + if (!priv->stations[i].used && + sta_id == IWL_INVALID_STATION) + sta_id = i; + } + + /* + * These two conditions have the same outcome, but keep them + * separate + */ + if (unlikely(sta_id == IWL_INVALID_STATION)) + return sta_id; + + /* + * uCode is not able to deal with multiple requests to add a + * station. Keep track if one is in progress so that we do not send + * another. + */ + if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { + IWL_DEBUG_INFO(priv, "STA %d already in process of being " + "added.\n", sta_id); + return sta_id; + } + + if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && + (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) && + !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { + IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not " + "adding again.\n", sta_id, addr); + return sta_id; + } + + station = &priv->stations[sta_id]; + station->used = IWL_STA_DRIVER_ACTIVE; + IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n", + sta_id, addr); + priv->num_stations++; + + /* Set up the REPLY_ADD_STA command to send to device */ + memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); + memcpy(station->sta.sta.addr, addr, ETH_ALEN); + station->sta.mode = 0; + station->sta.sta.sta_id = sta_id; + station->sta.station_flags = ctx->station_flags; + station->ctxid = ctx->ctxid; + + if (sta) { + struct iwl_station_priv *sta_priv; + + sta_priv = (void *)sta->drv_priv; + sta_priv->ctx = ctx; + } + + /* + * OK to call unconditionally, since local stations (IBSS BSSID + * STA and broadcast STA) pass in a NULL sta, and mac80211 + * doesn't allow HT IBSS. + */ + iwl_set_ht_add_station(priv, sta_id, sta, ctx); + + return sta_id; + +} + +#define STA_WAIT_TIMEOUT (HZ/2) + +/** + * iwl_add_station_common - + */ +int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + const u8 *addr, bool is_ap, + struct ieee80211_sta *sta, u8 *sta_id_r) +{ + unsigned long flags_spin; + int ret = 0; + u8 sta_id; + struct iwl_addsta_cmd sta_cmd; + + *sta_id_r = 0; + spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); + sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta); + if (sta_id == IWL_INVALID_STATION) { + IWL_ERR(priv, "Unable to prepare station %pM for addition\n", + addr); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + return -EINVAL; + } + + /* + * uCode is not able to deal with multiple requests to add a + * station. Keep track if one is in progress so that we do not send + * another. + */ + if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { + IWL_DEBUG_INFO(priv, "STA %d already in process of being " + "added.\n", sta_id); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + return -EEXIST; + } + + if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && + (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { + IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not " + "adding again.\n", sta_id, addr); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + return -EEXIST; + } + + priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS; + memcpy(&sta_cmd, &priv->stations[sta_id].sta, + sizeof(struct iwl_addsta_cmd)); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + + /* Add station to device's station table */ + ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); + if (ret) { + spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); + IWL_ERR(priv, "Adding station %pM failed.\n", + priv->stations[sta_id].sta.sta.addr); + priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; + priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + } + *sta_id_r = sta_id; + return ret; +} + +/** + * iwl_sta_ucode_deactivate - deactivate ucode status for a station + * + * priv->shrd->sta_lock must be held + */ +static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) +{ + /* Ucode must be active and driver must be non active */ + if ((priv->stations[sta_id].used & + (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) != + IWL_STA_UCODE_ACTIVE) + IWL_ERR(priv, "removed non active STA %u\n", sta_id); + + priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; + + memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); + IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id); +} + +static int iwl_send_remove_station(struct iwl_priv *priv, + const u8 *addr, int sta_id, + bool temporary) +{ + struct iwl_rx_packet *pkt; + int ret; + + unsigned long flags_spin; + struct iwl_rem_sta_cmd rm_sta_cmd; + + struct iwl_host_cmd cmd = { + .id = REPLY_REMOVE_STA, + .len = { sizeof(struct iwl_rem_sta_cmd), }, + .flags = CMD_SYNC, + .data = { &rm_sta_cmd, }, + }; + + memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); + rm_sta_cmd.num_sta = 1; + memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN); + + cmd.flags |= CMD_WANT_SKB; + + ret = iwl_trans_send_cmd(trans(priv), &cmd); + + if (ret) + return ret; + + pkt = (struct iwl_rx_packet *)cmd.reply_page; + if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", + pkt->hdr.flags); + ret = -EIO; + } + + if (!ret) { + switch (pkt->u.rem_sta.status) { + case REM_STA_SUCCESS_MSK: + if (!temporary) { + spin_lock_irqsave(&priv->shrd->sta_lock, + flags_spin); + iwl_sta_ucode_deactivate(priv, sta_id); + spin_unlock_irqrestore(&priv->shrd->sta_lock, + flags_spin); + } + IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); + break; + default: + ret = -EIO; + IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); + break; + } + } + iwl_free_pages(priv->shrd, cmd.reply_page); + + return ret; +} + +/** + * iwl_remove_station - Remove driver's knowledge of station. + */ +int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, + const u8 *addr) +{ + unsigned long flags; + + if (!iwl_is_ready(priv->shrd)) { + IWL_DEBUG_INFO(priv, + "Unable to remove station %pM, device not ready.\n", + addr); + /* + * It is typical for stations to be removed when we are + * going down. Return success since device will be down + * soon anyway + */ + return 0; + } + + IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n", + sta_id, addr); + + if (WARN_ON(sta_id == IWL_INVALID_STATION)) + return -EINVAL; + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { + IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n", + addr); + goto out_err; + } + + if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { + IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n", + addr); + goto out_err; + } + + if (priv->stations[sta_id].used & IWL_STA_LOCAL) { + kfree(priv->stations[sta_id].lq); + priv->stations[sta_id].lq = NULL; + } + + priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; + + priv->num_stations--; + + if (WARN_ON(priv->num_stations < 0)) + priv->num_stations = 0; + + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + + return iwl_send_remove_station(priv, addr, sta_id, false); +out_err: + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return -EINVAL; +} + +/** + * iwl_clear_ucode_stations - clear ucode station table bits + * + * This function clears all the bits in the driver indicating + * which stations are active in the ucode. Call when something + * other than explicit station management would cause this in + * the ucode, e.g. unassociated RXON. + */ +void iwl_clear_ucode_stations(struct iwl_priv *priv, + struct iwl_rxon_context *ctx) +{ + int i; + unsigned long flags_spin; + bool cleared = false; + + IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n"); + + spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); + for (i = 0; i < IWLAGN_STATION_COUNT; i++) { + if (ctx && ctx->ctxid != priv->stations[i].ctxid) + continue; + + if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { + IWL_DEBUG_INFO(priv, + "Clearing ucode active for station %d\n", i); + priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; + cleared = true; + } + } + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + + if (!cleared) + IWL_DEBUG_INFO(priv, + "No active stations found to be cleared\n"); +} + +/** + * iwl_restore_stations() - Restore driver known stations to device + * + * All stations considered active by driver, but not present in ucode, is + * restored. + * + * Function sleeps. + */ +void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + struct iwl_addsta_cmd sta_cmd; + struct iwl_link_quality_cmd lq; + unsigned long flags_spin; + int i; + bool found = false; + int ret; + bool send_lq; + + if (!iwl_is_ready(priv->shrd)) { + IWL_DEBUG_INFO(priv, + "Not ready yet, not restoring any stations.\n"); + return; + } + + IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n"); + spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); + for (i = 0; i < IWLAGN_STATION_COUNT; i++) { + if (ctx->ctxid != priv->stations[i].ctxid) + continue; + if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) && + !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) { + IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n", + priv->stations[i].sta.sta.addr); + priv->stations[i].sta.mode = 0; + priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS; + found = true; + } + } + + for (i = 0; i < IWLAGN_STATION_COUNT; i++) { + if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) { + memcpy(&sta_cmd, &priv->stations[i].sta, + sizeof(struct iwl_addsta_cmd)); + send_lq = false; + if (priv->stations[i].lq) { + if (priv->shrd->wowlan) + iwl_sta_fill_lq(priv, ctx, i, &lq); + else + memcpy(&lq, priv->stations[i].lq, + sizeof(struct iwl_link_quality_cmd)); + send_lq = true; + } + spin_unlock_irqrestore(&priv->shrd->sta_lock, + flags_spin); + ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); + if (ret) { + spin_lock_irqsave(&priv->shrd->sta_lock, + flags_spin); + IWL_ERR(priv, "Adding station %pM failed.\n", + priv->stations[i].sta.sta.addr); + priv->stations[i].used &= + ~IWL_STA_DRIVER_ACTIVE; + priv->stations[i].used &= + ~IWL_STA_UCODE_INPROGRESS; + spin_unlock_irqrestore(&priv->shrd->sta_lock, + flags_spin); + } + /* + * Rate scaling has already been initialized, send + * current LQ command + */ + if (send_lq) + iwl_send_lq_cmd(priv, ctx, &lq, + CMD_SYNC, true); + spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); + priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; + } + } + + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + if (!found) + IWL_DEBUG_INFO(priv, "Restoring all known stations .... " + "no stations to be restored.\n"); + else + IWL_DEBUG_INFO(priv, "Restoring all known stations .... " + "complete.\n"); +} + +void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) +{ + unsigned long flags; + int sta_id = ctx->ap_sta_id; + int ret; + struct iwl_addsta_cmd sta_cmd; + struct iwl_link_quality_cmd lq; + bool active; + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return; + } + + memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); + sta_cmd.mode = 0; + memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq)); + + active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE; + priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + + if (active) { + ret = iwl_send_remove_station( + priv, priv->stations[sta_id].sta.sta.addr, + sta_id, true); + if (ret) + IWL_ERR(priv, "failed to remove STA %pM (%d)\n", + priv->stations[sta_id].sta.sta.addr, ret); + } + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + + ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); + if (ret) + IWL_ERR(priv, "failed to re-add STA %pM (%d)\n", + priv->stations[sta_id].sta.sta.addr, ret); + iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true); +} + +int iwl_get_free_ucode_key_offset(struct iwl_priv *priv) +{ + int i; + + for (i = 0; i < priv->sta_key_max_num; i++) + if (!test_and_set_bit(i, &priv->ucode_key_table)) + return i; + + return WEP_INVALID_OFFSET; +} + +void iwl_dealloc_bcast_stations(struct iwl_priv *priv) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + for (i = 0; i < IWLAGN_STATION_COUNT; i++) { + if (!(priv->stations[i].used & IWL_STA_BCAST)) + continue; + + priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; + priv->num_stations--; + if (WARN_ON(priv->num_stations < 0)) + priv->num_stations = 0; + kfree(priv->stations[i].lq); + priv->stations[i].lq = NULL; + } + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); +} + +#ifdef CONFIG_IWLWIFI_DEBUG +static void iwl_dump_lq_cmd(struct iwl_priv *priv, + struct iwl_link_quality_cmd *lq) +{ + int i; + IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id); + IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n", + lq->general_params.single_stream_ant_msk, + lq->general_params.dual_stream_ant_msk); + + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) + IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n", + i, lq->rs_table[i].rate_n_flags); +} +#else +static inline void iwl_dump_lq_cmd(struct iwl_priv *priv, + struct iwl_link_quality_cmd *lq) +{ +} +#endif + +/** + * is_lq_table_valid() - Test one aspect of LQ cmd for validity + * + * It sometimes happens when a HT rate has been in use and we + * loose connectivity with AP then mac80211 will first tell us that the + * current channel is not HT anymore before removing the station. In such a + * scenario the RXON flags will be updated to indicate we are not + * communicating HT anymore, but the LQ command may still contain HT rates. + * Test for this to prevent driver from sending LQ command between the time + * RXON flags are updated and when LQ command is updated. + */ +static bool is_lq_table_valid(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, + struct iwl_link_quality_cmd *lq) +{ + int i; + + if (ctx->ht.enabled) + return true; + + IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n", + ctx->active.channel); + for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { + if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & + RATE_MCS_HT_MSK) { + IWL_DEBUG_INFO(priv, + "index %d of LQ expects HT channel\n", + i); + return false; + } + } + return true; +} + +/** + * iwl_send_lq_cmd() - Send link quality command + * @init: This command is sent as part of station initialization right + * after station has been added. + * + * The link quality command is sent as the last step of station creation. + * This is the special case in which init is set and we call a callback in + * this case to clear the state indicating that station creation is in + * progress. + */ +int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + struct iwl_link_quality_cmd *lq, u8 flags, bool init) +{ + int ret = 0; + unsigned long flags_spin; + + struct iwl_host_cmd cmd = { + .id = REPLY_TX_LINK_QUALITY_CMD, + .len = { sizeof(struct iwl_link_quality_cmd), }, + .flags = flags, + .data = { lq, }, + }; + + if (WARN_ON(lq->sta_id == IWL_INVALID_STATION)) + return -EINVAL; + + + spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); + if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) { + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + return -EINVAL; + } + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + + iwl_dump_lq_cmd(priv, lq); + if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) + return -EINVAL; + + if (is_lq_table_valid(priv, ctx, lq)) + ret = iwl_trans_send_cmd(trans(priv), &cmd); + else + ret = -EINVAL; + + if (cmd.flags & CMD_ASYNC) + return ret; + + if (init) { + IWL_DEBUG_INFO(priv, "init LQ command complete, " + "clearing sta addition status for sta %d\n", + lq->sta_id); + spin_lock_irqsave(&priv->shrd->sta_lock, flags_spin); + priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags_spin); + } + return ret; +} + +int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; + int ret; + + IWL_DEBUG_MAC80211(priv, "enter: received request to remove " + "station %pM\n", sta->addr); + mutex_lock(&priv->shrd->mutex); + IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", + sta->addr); + ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr); + if (ret) + IWL_ERR(priv, "Error removing station %pM\n", + sta->addr); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return ret; +} + +void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + u8 sta_id, struct iwl_link_quality_cmd *link_cmd) { int i, r; - struct iwl_link_quality_cmd *link_cmd; u32 rate_flags = 0; __le32 rate_n_flags; - link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL); - if (!link_cmd) { - IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); - return NULL; - } + lockdep_assert_held(&priv->shrd->mutex); - lockdep_assert_held(&priv->mutex); + memset(link_cmd, 0, sizeof(*link_cmd)); /* Set up the rate scaling to start at selected rate, fall back * all the way down to 1M in IEEE order, and then spin on 1M */ @@ -63,30 +871,46 @@ iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id) if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) rate_flags |= RATE_MCS_CCK_MSK; - rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << + rate_flags |= first_antenna(hw_params(priv).valid_tx_ant) << RATE_MCS_ANT_POS; rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) link_cmd->rs_table[i].rate_n_flags = rate_n_flags; link_cmd->general_params.single_stream_ant_msk = - first_antenna(priv->hw_params.valid_tx_ant); + first_antenna(hw_params(priv).valid_tx_ant); link_cmd->general_params.dual_stream_ant_msk = - priv->hw_params.valid_tx_ant & - ~first_antenna(priv->hw_params.valid_tx_ant); + hw_params(priv).valid_tx_ant & + ~first_antenna(hw_params(priv).valid_tx_ant); if (!link_cmd->general_params.dual_stream_ant_msk) { link_cmd->general_params.dual_stream_ant_msk = ANT_AB; - } else if (num_of_ant(priv->hw_params.valid_tx_ant) == 2) { + } else if (num_of_ant(hw_params(priv).valid_tx_ant) == 2) { link_cmd->general_params.dual_stream_ant_msk = - priv->hw_params.valid_tx_ant; + hw_params(priv).valid_tx_ant; } - link_cmd->agg_params.agg_dis_start_th = LINK_QUAL_AGG_DISABLE_START_DEF; + link_cmd->agg_params.agg_dis_start_th = + LINK_QUAL_AGG_DISABLE_START_DEF; link_cmd->agg_params.agg_time_limit = cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF); link_cmd->sta_id = sta_id; +} + +static struct iwl_link_quality_cmd * +iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + u8 sta_id) +{ + struct iwl_link_quality_cmd *link_cmd; + + link_cmd = kzalloc(sizeof(struct iwl_link_quality_cmd), GFP_KERNEL); + if (!link_cmd) { + IWL_ERR(priv, "Unable to allocate memory for LQ cmd.\n"); + return NULL; + } + + iwl_sta_fill_lq(priv, ctx, sta_id, link_cmd); return link_cmd; } @@ -96,7 +920,8 @@ iwl_sta_alloc_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, u8 sta_id) * * Function sleeps. */ -int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, +int iwlagn_add_bssid_station(struct iwl_priv *priv, + struct iwl_rxon_context *ctx, const u8 *addr, u8 *sta_id_r) { int ret; @@ -116,14 +941,15 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx if (sta_id_r) *sta_id_r = sta_id; - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); priv->stations[sta_id].used |= IWL_STA_LOCAL; - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); /* Set up default rate scaling table in device's station table */ link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); if (!link_cmd) { - IWL_ERR(priv, "Unable to initialize rate scaling for station %pM.\n", + IWL_ERR(priv, + "Unable to initialize rate scaling for station %pM.\n", addr); return -ENOMEM; } @@ -132,9 +958,9 @@ int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx if (ret) IWL_ERR(priv, "Link quality command failed (%d)\n", ret); - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); priv->stations[sta_id].lq = link_cmd; - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return 0; } @@ -189,7 +1015,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, cmd.len[0] = cmd_size; if (not_empty || send_if_empty) - return trans_send_cmd(&priv->trans, &cmd); + return iwl_trans_send_cmd(trans(priv), &cmd); else return 0; } @@ -197,7 +1023,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, int iwl_restore_default_wep_keys(struct iwl_priv *priv, struct iwl_rxon_context *ctx) { - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); return iwl_send_static_wepkey_cmd(priv, ctx, false); } @@ -208,14 +1034,15 @@ int iwl_remove_default_wep_key(struct iwl_priv *priv, { int ret; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); IWL_DEBUG_WEP(priv, "Removing default WEP key: idx=%d\n", keyconf->keyidx); memset(&ctx->wep_keys[keyconf->keyidx], 0, sizeof(ctx->wep_keys[0])); - if (iwl_is_rfkill(priv)) { - IWL_DEBUG_WEP(priv, "Not sending REPLY_WEPKEY command due to RFKILL.\n"); + if (iwl_is_rfkill(priv->shrd)) { + IWL_DEBUG_WEP(priv, + "Not sending REPLY_WEPKEY command due to RFKILL.\n"); /* but keys in device are clear anyway so return success */ return 0; } @@ -232,11 +1059,12 @@ int iwl_set_default_wep_key(struct iwl_priv *priv, { int ret; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); if (keyconf->keylen != WEP_KEY_LEN_128 && keyconf->keylen != WEP_KEY_LEN_64) { - IWL_DEBUG_WEP(priv, "Bad WEP key length %d\n", keyconf->keylen); + IWL_DEBUG_WEP(priv, + "Bad WEP key length %d\n", keyconf->keylen); return -EINVAL; } @@ -311,9 +1139,9 @@ static int iwlagn_send_sta_key(struct iwl_priv *priv, struct iwl_addsta_cmd sta_cmd; int i; - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); key_flags = cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); key_flags |= STA_KEY_FLG_MAP_KEY_MSK; @@ -388,16 +1216,16 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv, if (sta_id == IWL_INVALID_STATION) return -ENOENT; - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) sta_id = IWL_INVALID_STATION; - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); if (sta_id == IWL_INVALID_STATION) return 0; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); ctx->key_mapping_keys--; @@ -430,7 +1258,7 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, if (sta_id == IWL_INVALID_STATION) return -EINVAL; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); keyconf->hw_key_idx = iwl_get_free_ucode_key_offset(priv); if (keyconf->hw_key_idx == WEP_INVALID_OFFSET) @@ -493,18 +1321,18 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv, unsigned long flags; u8 sta_id; - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); sta_id = iwl_prep_station(priv, ctx, iwl_bcast_addr, false, NULL); if (sta_id == IWL_INVALID_STATION) { IWL_ERR(priv, "Unable to prepare broadcast station\n"); - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return -EINVAL; } priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; priv->stations[sta_id].used |= IWL_STA_BCAST; - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); link_cmd = iwl_sta_alloc_lq(priv, ctx, sta_id); if (!link_cmd) { @@ -513,9 +1341,9 @@ int iwlagn_alloc_bcast_station(struct iwl_priv *priv, return -ENOMEM; } - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); priv->stations[sta_id].lq = link_cmd; - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return 0; } @@ -539,13 +1367,13 @@ int iwl_update_bcast_station(struct iwl_priv *priv, return -ENOMEM; } - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); if (priv->stations[sta_id].lq) kfree(priv->stations[sta_id].lq); else IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n"); priv->stations[sta_id].lq = link_cmd; - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return 0; } @@ -572,15 +1400,15 @@ int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) unsigned long flags; struct iwl_addsta_cmd sta_cmd; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); /* Remove "disable" flag, to enable Tx for this TID */ - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX; priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid)); priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); } @@ -592,20 +1420,20 @@ int iwl_sta_rx_agg_start(struct iwl_priv *priv, struct ieee80211_sta *sta, int sta_id; struct iwl_addsta_cmd sta_cmd; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); sta_id = iwl_sta_id(sta); if (sta_id == IWL_INVALID_STATION) return -ENXIO; - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); priv->stations[sta_id].sta.station_flags_msk = 0; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); } @@ -617,7 +1445,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, int sta_id; struct iwl_addsta_cmd sta_cmd; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); sta_id = iwl_sta_id(sta); if (sta_id == IWL_INVALID_STATION) { @@ -625,13 +1453,13 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta, return -ENXIO; } - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); priv->stations[sta_id].sta.station_flags_msk = 0; priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); } @@ -640,14 +1468,14 @@ static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) { unsigned long flags; - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.sta.modify_mask = 0; priv->stations[sta_id].sta.sleep_tx_count = 0; priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); } @@ -655,7 +1483,7 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) { unsigned long flags; - spin_lock_irqsave(&priv->sta_lock, flags); + spin_lock_irqsave(&priv->shrd->sta_lock, flags); priv->stations[sta_id].sta.station_flags |= STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; priv->stations[sta_id].sta.sta.modify_mask = @@ -663,7 +1491,7 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt) priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt); priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); } @@ -676,6 +1504,8 @@ void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; int sta_id; + IWL_DEBUG_MAC80211(priv, "enter\n"); + switch (cmd) { case STA_NOTIFY_SLEEP: WARN_ON(!sta_priv->client); @@ -695,4 +1525,5 @@ void iwlagn_mac_sta_notify(struct ieee80211_hw *hw, default: break; } + IWL_DEBUG_MAC80211(priv, "leave\n"); } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c index f501d742984c..c27180a73351 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c @@ -114,9 +114,6 @@ static bool iwl_within_ct_kill_margin(struct iwl_priv *priv) s32 temp = priv->temperature; /* degrees CELSIUS except specified */ bool within_margin = false; - if (priv->cfg->base_params->temperature_kelvin) - temp = KELVIN_TO_CELSIUS(priv->temperature); - if (!priv->thermal_throttle.advanced_tt) within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >= CT_KILL_THRESHOLD_LEGACY) ? true : false; @@ -176,24 +173,24 @@ static void iwl_tt_check_exit_ct_kill(unsigned long data) struct iwl_tt_mgmt *tt = &priv->thermal_throttle; unsigned long flags; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; if (tt->state == IWL_TI_CT_KILL) { if (priv->thermal_throttle.ct_kill_toggle) { - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = false; } else { - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = true; } - iwl_read32(priv, CSR_UCODE_DRV_GP1); - spin_lock_irqsave(&priv->reg_lock, flags); - if (!iwl_grab_nic_access(priv)) - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); + iwl_read32(bus(priv), CSR_UCODE_DRV_GP1); + spin_lock_irqsave(&bus(priv)->reg_lock, flags); + if (!iwl_grab_nic_access(bus(priv))) + iwl_release_nic_access(bus(priv)); + spin_unlock_irqrestore(&bus(priv)->reg_lock, flags); /* Reschedule the ct_kill timer to occur in * CT_KILL_EXIT_DURATION seconds to ensure we get a @@ -227,7 +224,7 @@ static void iwl_tt_ready_for_ct_kill(unsigned long data) struct iwl_priv *priv = (struct iwl_priv *)data; struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; /* temperature timer expired, ready to go into CT_KILL state */ @@ -235,7 +232,7 @@ static void iwl_tt_ready_for_ct_kill(unsigned long data) IWL_DEBUG_TEMP(priv, "entering CT_KILL state when " "temperature timer expired\n"); tt->state = IWL_TI_CT_KILL; - set_bit(STATUS_CT_KILL, &priv->status); + set_bit(STATUS_CT_KILL, &priv->shrd->status); iwl_perform_ct_kill_task(priv, true); } } @@ -313,23 +310,24 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force) tt->tt_power_mode = IWL_POWER_INDEX_5; break; } - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); if (old_state == IWL_TI_CT_KILL) - clear_bit(STATUS_CT_KILL, &priv->status); + clear_bit(STATUS_CT_KILL, &priv->shrd->status); if (tt->state != IWL_TI_CT_KILL && iwl_power_update_mode(priv, true)) { /* TT state not updated * try again during next temperature read */ if (old_state == IWL_TI_CT_KILL) - set_bit(STATUS_CT_KILL, &priv->status); + set_bit(STATUS_CT_KILL, &priv->shrd->status); tt->state = old_state; IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); } else { if (tt->state == IWL_TI_CT_KILL) { if (force) { - set_bit(STATUS_CT_KILL, &priv->status); + set_bit(STATUS_CT_KILL, + &priv->shrd->status); iwl_perform_ct_kill_task(priv, true); } else { iwl_prepare_ct_kill_task(priv); @@ -343,7 +341,7 @@ static void iwl_legacy_tt_handler(struct iwl_priv *priv, s32 temp, bool force) IWL_DEBUG_TEMP(priv, "Power Index change to %u\n", tt->tt_power_mode); } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } } @@ -453,9 +451,9 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force) * in case get disabled before */ iwl_set_rxon_ht(priv, &priv->current_ht_config); } - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); if (old_state == IWL_TI_CT_KILL) - clear_bit(STATUS_CT_KILL, &priv->status); + clear_bit(STATUS_CT_KILL, &priv->shrd->status); if (tt->state != IWL_TI_CT_KILL && iwl_power_update_mode(priv, true)) { /* TT state not updated @@ -464,7 +462,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force) IWL_ERR(priv, "Cannot update power mode, " "TT state not updated\n"); if (old_state == IWL_TI_CT_KILL) - set_bit(STATUS_CT_KILL, &priv->status); + set_bit(STATUS_CT_KILL, &priv->shrd->status); tt->state = old_state; } else { IWL_DEBUG_TEMP(priv, @@ -475,7 +473,8 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force) if (force) { IWL_DEBUG_TEMP(priv, "Enter IWL_TI_CT_KILL\n"); - set_bit(STATUS_CT_KILL, &priv->status); + set_bit(STATUS_CT_KILL, + &priv->shrd->status); iwl_perform_ct_kill_task(priv, true); } else { iwl_prepare_ct_kill_task(priv); @@ -487,7 +486,7 @@ static void iwl_advance_tt_handler(struct iwl_priv *priv, s32 temp, bool force) iwl_perform_ct_kill_task(priv, false); } } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } } @@ -506,10 +505,10 @@ static void iwl_bg_ct_enter(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_enter); struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; - if (!iwl_is_ready(priv)) + if (!iwl_is_ready(priv->shrd)) return; if (tt->state != IWL_TI_CT_KILL) { @@ -535,10 +534,10 @@ static void iwl_bg_ct_exit(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, ct_exit); struct iwl_tt_mgmt *tt = &priv->thermal_throttle; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; - if (!iwl_is_ready(priv)) + if (!iwl_is_ready(priv->shrd)) return; /* stop ct_kill_exit_tm timer */ @@ -565,20 +564,20 @@ static void iwl_bg_ct_exit(struct work_struct *work) void iwl_tt_enter_ct_kill(struct iwl_priv *priv) { - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; IWL_DEBUG_TEMP(priv, "Queueing critical temperature enter.\n"); - queue_work(priv->workqueue, &priv->ct_enter); + queue_work(priv->shrd->workqueue, &priv->ct_enter); } void iwl_tt_exit_ct_kill(struct iwl_priv *priv) { - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; IWL_DEBUG_TEMP(priv, "Queueing critical temperature exit.\n"); - queue_work(priv->workqueue, &priv->ct_exit); + queue_work(priv->shrd->workqueue, &priv->ct_exit); } static void iwl_bg_tt_work(struct work_struct *work) @@ -586,12 +585,9 @@ static void iwl_bg_tt_work(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, tt_work); s32 temp = priv->temperature; /* degrees CELSIUS except specified */ - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; - if (priv->cfg->base_params->temperature_kelvin) - temp = KELVIN_TO_CELSIUS(priv->temperature); - if (!priv->thermal_throttle.advanced_tt) iwl_legacy_tt_handler(priv, temp, false); else @@ -600,11 +596,11 @@ static void iwl_bg_tt_work(struct work_struct *work) void iwl_tt_handler(struct iwl_priv *priv) { - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; IWL_DEBUG_TEMP(priv, "Queueing thermal throttling work.\n"); - queue_work(priv->workqueue, &priv->tt_work); + queue_work(priv->shrd->workqueue, &priv->tt_work); } /* Thermal throttling initialization @@ -639,11 +635,13 @@ void iwl_tt_initialize(struct iwl_priv *priv) if (priv->cfg->base_params->adv_thermal_throttle) { IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n"); - tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) * - IWL_TI_STATE_MAX, GFP_KERNEL); - tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) * - IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1), - GFP_KERNEL); + tt->restriction = kcalloc(IWL_TI_STATE_MAX, + sizeof(struct iwl_tt_restriction), + GFP_KERNEL); + tt->transaction = kcalloc(IWL_TI_STATE_MAX * + (IWL_TI_STATE_MAX - 1), + sizeof(struct iwl_tt_trans), + GFP_KERNEL); if (!tt->restriction || !tt->transaction) { IWL_ERR(priv, "Fallback to Legacy Throttling\n"); priv->thermal_throttle.advanced_tt = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h index d118ed29bf3f..7282a23e8f1c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h @@ -117,7 +117,6 @@ struct iwl_tt_mgmt { u8 iwl_tt_current_power_mode(struct iwl_priv *priv); bool iwl_tt_is_low_power_state(struct iwl_priv *priv); bool iwl_ht_enabled(struct iwl_priv *priv); -bool iwl_check_for_ct_kill(struct iwl_priv *priv); enum iwl_antenna_ok iwl_tx_ant_restriction(struct iwl_priv *priv); enum iwl_antenna_ok iwl_rx_ant_restriction(struct iwl_priv *priv); void iwl_tt_enter_ct_kill(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 53bb59ee719d..35a6b71f358c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -31,89 +31,15 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/ieee80211.h> #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-sta.h" #include "iwl-io.h" -#include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-agn.h" #include "iwl-trans.h" -/* - * mac80211 queues, ACs, hardware queues, FIFOs. - * - * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues - * - * Mac80211 uses the following numbers, which we get as from it - * by way of skb_get_queue_mapping(skb): - * - * VO 0 - * VI 1 - * BE 2 - * BK 3 - * - * - * Regular (not A-MPDU) frames are put into hardware queues corresponding - * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their - * own queue per aggregation session (RA/TID combination), such queues are - * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In - * order to map frames to the right queue, we also need an AC->hw queue - * mapping. This is implemented here. - * - * Due to the way hw queues are set up (by the hw specific modules like - * iwl-4965.c, iwl-5000.c etc.), the AC->hw queue mapping is the identity - * mapping. - */ - -static const u8 tid_to_ac[] = { - IEEE80211_AC_BE, - IEEE80211_AC_BK, - IEEE80211_AC_BK, - IEEE80211_AC_BE, - IEEE80211_AC_VI, - IEEE80211_AC_VI, - IEEE80211_AC_VO, - IEEE80211_AC_VO -}; - -static inline int get_ac_from_tid(u16 tid) -{ - if (likely(tid < ARRAY_SIZE(tid_to_ac))) - return tid_to_ac[tid]; - - /* no support for TIDs 8-15 yet */ - return -EINVAL; -} - -static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid) -{ - if (likely(tid < ARRAY_SIZE(tid_to_ac))) - return ctx->ac_to_fifo[tid_to_ac[tid]]; - - /* no support for TIDs 8-15 yet */ - return -EINVAL; -} - -static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, - int tid) -{ - if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || - (IWLAGN_FIRST_AMPDU_QUEUE + - priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { - IWL_WARN(priv, - "queue number out of range: %d, must be %d to %d\n", - txq_id, IWLAGN_FIRST_AMPDU_QUEUE, - IWLAGN_FIRST_AMPDU_QUEUE + - priv->cfg->base_params->num_of_ampdu_queues - 1); - return -EINVAL; - } - - /* Modify device's station table to Tx this TID */ - return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); -} - static void iwlagn_tx_cmd_protection(struct iwl_priv *priv, struct ieee80211_tx_info *info, __le16 fc, __le32 *tx_flags) @@ -128,11 +54,10 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv, * handle build REPLY_TX command notification. */ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, - struct sk_buff *skb, - struct iwl_tx_cmd *tx_cmd, - struct ieee80211_tx_info *info, - struct ieee80211_hdr *hdr, - u8 std_id) + struct sk_buff *skb, + struct iwl_tx_cmd *tx_cmd, + struct ieee80211_tx_info *info, + struct ieee80211_hdr *hdr, u8 sta_id) { __le16 fc = hdr->frame_control; __le32 tx_flags = tx_cmd->tx_flags; @@ -157,7 +82,7 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, tx_flags |= TX_CMD_FLG_IGNORE_BT; - tx_cmd->sta_id = std_id; + tx_cmd->sta_id = sta_id; if (ieee80211_has_morefrags(fc)) tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK; @@ -186,12 +111,10 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, tx_cmd->next_frame_len = 0; } -#define RTS_DFAULT_RETRY_LIMIT 60 - static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, - struct iwl_tx_cmd *tx_cmd, - struct ieee80211_tx_info *info, - __le16 fc) + struct iwl_tx_cmd *tx_cmd, + struct ieee80211_tx_info *info, + __le16 fc) { u32 rate_flags; int rate_idx; @@ -199,17 +122,25 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, u8 data_retry_limit; u8 rate_plcp; - /* Set retry limit on DATA packets and Probe Responses*/ - if (ieee80211_is_probe_resp(fc)) - data_retry_limit = 3; - else - data_retry_limit = IWLAGN_DEFAULT_TX_RETRY; - tx_cmd->data_retry_limit = data_retry_limit; + if (priv->shrd->wowlan) { + rts_retry_limit = IWLAGN_LOW_RETRY_LIMIT; + data_retry_limit = IWLAGN_LOW_RETRY_LIMIT; + } else { + /* Set retry limit on RTS packets */ + rts_retry_limit = IWLAGN_RTS_DFAULT_RETRY_LIMIT; + + /* Set retry limit on DATA packets and Probe Responses*/ + if (ieee80211_is_probe_resp(fc)) { + data_retry_limit = IWLAGN_MGMT_DFAULT_RETRY_LIMIT; + rts_retry_limit = + min(data_retry_limit, rts_retry_limit); + } else if (ieee80211_is_back_req(fc)) + data_retry_limit = IWLAGN_BAR_DFAULT_RETRY_LIMIT; + else + data_retry_limit = IWLAGN_DEFAULT_TX_RETRY; + } - /* Set retry limit on RTS packets */ - rts_retry_limit = RTS_DFAULT_RETRY_LIMIT; - if (data_retry_limit < rts_retry_limit) - rts_retry_limit = data_retry_limit; + tx_cmd->data_retry_limit = data_retry_limit; tx_cmd->rts_retry_limit = rts_retry_limit; /* DATA packets will use the uCode station table for rate/antenna @@ -261,10 +192,10 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, priv->bt_full_concurrent) { /* operated as 1x1 in full concurrency mode */ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, - first_antenna(priv->hw_params.valid_tx_ant)); + first_antenna(hw_params(priv).valid_tx_ant)); } else priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, - priv->hw_params.valid_tx_ant); + hw_params(priv).valid_tx_ant); rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); /* Set the rate in the TX cmd */ @@ -322,30 +253,21 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_station_priv *sta_priv = NULL; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + struct iwl_device_cmd *dev_cmd = NULL; struct iwl_tx_cmd *tx_cmd; - int txq_id; - u16 seq_number = 0; __le16 fc; u8 hdr_len; u16 len; u8 sta_id; - u8 tid = 0; unsigned long flags; bool is_agg = false; - /* - * If the frame needs to go out off-channel, then - * we'll have put the PAN context to that channel, - * so make the frame go out there. - */ - if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) - ctx = &priv->contexts[IWL_RXON_CTX_PAN]; - else if (info->control.vif) + if (info->control.vif) ctx = iwl_rxon_ctx_from_vif(info->control.vif); - spin_lock_irqsave(&priv->lock, flags); - if (iwl_is_rfkill(priv)) { + spin_lock_irqsave(&priv->shrd->lock, flags); + if (iwl_is_rfkill(priv->shrd)) { IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n"); goto drop_unlock_priv; } @@ -382,7 +304,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) sta_priv = (void *)info->control.sta->drv_priv; if (sta_priv && sta_priv->asleep && - (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) { + (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE)) { /* * This sends an asynchronous command to the device, * but we can rely on it being processed before the @@ -395,52 +317,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); } - /* - * Send this frame after DTIM -- there's a special queue - * reserved for this for contexts that support AP mode. - */ - if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { - txq_id = ctx->mcast_queue; - /* - * The microcode will clear the more data - * bit in the last frame it transmits. - */ - hdr->frame_control |= - cpu_to_le16(IEEE80211_FCTL_MOREDATA); - } else - txq_id = ctx->ac_to_queue[skb_get_queue_mapping(skb)]; + if (info->flags & IEEE80211_TX_CTL_AMPDU) + is_agg = true; - /* irqs already disabled/saved above when locking priv->lock */ - spin_lock(&priv->sta_lock); + /* irqs already disabled/saved above when locking priv->shrd->lock */ + spin_lock(&priv->shrd->sta_lock); - if (ieee80211_is_data_qos(fc)) { - u8 *qc = NULL; - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; - - if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) - goto drop_unlock_sta; - - seq_number = priv->stations[sta_id].tid[tid].seq_number; - seq_number &= IEEE80211_SCTL_SEQ; - hdr->seq_ctrl = hdr->seq_ctrl & - cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(seq_number); - seq_number += 0x10; - /* aggregation is on for this <sta,tid> */ - if (info->flags & IEEE80211_TX_CTL_AMPDU && - priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) { - txq_id = priv->stations[sta_id].tid[tid].agg.txq_id; - is_agg = true; - } - } + dev_cmd = kmem_cache_alloc(priv->tx_cmd_pool, GFP_ATOMIC); - tx_cmd = trans_get_tx_cmd(&priv->trans, txq_id); - if (unlikely(!tx_cmd)) + if (unlikely(!dev_cmd)) goto drop_unlock_sta; - /* Copy MAC header from skb into command buffer */ - memcpy(tx_cmd->hdr, hdr, hdr_len); + memset(dev_cmd, 0, sizeof(*dev_cmd)); + tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; /* Total # bytes to be transmitted */ len = (u16)skb->len; @@ -457,17 +346,16 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_update_stats(priv, true, fc, len); - if (trans_tx(&priv->trans, skb, tx_cmd, txq_id, fc, is_agg, ctx)) - goto drop_unlock_sta; + memset(&info->status, 0, sizeof(info->status)); - if (ieee80211_is_data_qos(fc)) { - priv->stations[sta_id].tid[tid].tfds_in_queue++; - if (!ieee80211_has_morefrags(fc)) - priv->stations[sta_id].tid[tid].seq_number = seq_number; - } + info->driver_data[0] = ctx; + info->driver_data[1] = dev_cmd; + + if (iwl_trans_tx(trans(priv), skb, dev_cmd, ctx->ctxid, sta_id)) + goto drop_unlock_sta; - spin_unlock(&priv->sta_lock); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock(&priv->shrd->sta_lock); + spin_unlock_irqrestore(&priv->shrd->lock, flags); /* * Avoid atomic ops if it isn't an associated client. @@ -482,41 +370,20 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) return 0; drop_unlock_sta: - spin_unlock(&priv->sta_lock); + if (dev_cmd) + kmem_cache_free(priv->tx_cmd_pool, dev_cmd); + spin_unlock(&priv->shrd->sta_lock); drop_unlock_priv: - spin_unlock_irqrestore(&priv->lock, flags); - return -1; -} - -/* - * Find first available (lowest unused) Tx Queue, mark it "active". - * Called only when finding queue for aggregation. - * Should never return anything < 7, because they should already - * be in use as EDCA AC (0-3), Command (4), reserved (5, 6) - */ -static int iwlagn_txq_ctx_activate_free(struct iwl_priv *priv) -{ - int txq_id; - - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk)) - return txq_id; + spin_unlock_irqrestore(&priv->shrd->lock, flags); return -1; } int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; int sta_id; - int tx_fifo; - int txq_id; int ret; - unsigned long flags; - struct iwl_tid_data *tid_data; - - tx_fifo = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid); - if (unlikely(tx_fifo < 0)) - return tx_fifo; IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n", sta->addr, tid); @@ -526,58 +393,29 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, IWL_ERR(priv, "Start AGG on invalid station\n"); return -ENXIO; } - if (unlikely(tid >= MAX_TID_COUNT)) + if (unlikely(tid >= IWL_MAX_TID_COUNT)) return -EINVAL; - if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_OFF) { + if (priv->shrd->tid_data[sta_id][tid].agg.state != IWL_AGG_OFF) { IWL_ERR(priv, "Start AGG when state is not IWL_AGG_OFF !\n"); return -ENXIO; } - txq_id = iwlagn_txq_ctx_activate_free(priv); - if (txq_id == -1) { - IWL_ERR(priv, "No free aggregation queue available\n"); - return -ENXIO; - } - - spin_lock_irqsave(&priv->sta_lock, flags); - tid_data = &priv->stations[sta_id].tid[tid]; - *ssn = SEQ_TO_SN(tid_data->seq_number); - tid_data->agg.txq_id = txq_id; - tid_data->agg.tx_fifo = tx_fifo; - iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid); + ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); if (ret) return ret; - spin_lock_irqsave(&priv->sta_lock, flags); - tid_data = &priv->stations[sta_id].tid[tid]; - if (tid_data->tfds_in_queue == 0) { - IWL_DEBUG_HT(priv, "HW queue is empty\n"); - tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); - } else { - IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n", - tid_data->tfds_in_queue); - tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; - } - spin_unlock_irqrestore(&priv->sta_lock, flags); + ret = iwl_trans_tx_agg_alloc(trans(priv), vif_priv->ctx->ctxid, sta_id, + tid, ssn); + return ret; } int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid) { - int tx_fifo_id, txq_id, sta_id, ssn; - struct iwl_tid_data *tid_data; - int write_ptr, read_ptr; - unsigned long flags; - - tx_fifo_id = get_fifo_from_tid(iwl_rxon_ctx_from_vif(vif), tid); - if (unlikely(tx_fifo_id < 0)) - return tx_fifo_id; + int sta_id; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; sta_id = iwl_sta_id(sta); @@ -586,101 +424,8 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, return -ENXIO; } - spin_lock_irqsave(&priv->sta_lock, flags); - - tid_data = &priv->stations[sta_id].tid[tid]; - ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4; - txq_id = tid_data->agg.txq_id; - - switch (priv->stations[sta_id].tid[tid].agg.state) { - case IWL_EMPTYING_HW_QUEUE_ADDBA: - /* - * This can happen if the peer stops aggregation - * again before we've had a chance to drain the - * queue we selected previously, i.e. before the - * session was really started completely. - */ - IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); - goto turn_off; - case IWL_AGG_ON: - break; - default: - IWL_WARN(priv, "Stopping AGG while state not ON or starting\n"); - } - - write_ptr = priv->txq[txq_id].q.write_ptr; - read_ptr = priv->txq[txq_id].q.read_ptr; - - /* The queue is not empty */ - if (write_ptr != read_ptr) { - IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n"); - priv->stations[sta_id].tid[tid].agg.state = - IWL_EMPTYING_HW_QUEUE_DELBA; - spin_unlock_irqrestore(&priv->sta_lock, flags); - return 0; - } - - IWL_DEBUG_HT(priv, "HW queue is empty\n"); - turn_off: - priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; - - /* do not restore/save irqs */ - spin_unlock(&priv->sta_lock); - spin_lock(&priv->lock); - - /* - * the only reason this call can fail is queue number out of range, - * which can happen if uCode is reloaded and all the station - * information are lost. if it is outside the range, there is no need - * to deactivate the uCode queue, just return "success" to allow - * mac80211 to clean up it own data. - */ - trans_txq_agg_disable(&priv->trans, txq_id, ssn, tx_fifo_id); - spin_unlock_irqrestore(&priv->lock, flags); - - ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); - - return 0; -} - -int iwlagn_txq_check_empty(struct iwl_priv *priv, - int sta_id, u8 tid, int txq_id) -{ - struct iwl_queue *q = &priv->txq[txq_id].q; - u8 *addr = priv->stations[sta_id].sta.sta.addr; - struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; - struct iwl_rxon_context *ctx; - - ctx = &priv->contexts[priv->stations[sta_id].ctxid]; - - lockdep_assert_held(&priv->sta_lock); - - switch (priv->stations[sta_id].tid[tid].agg.state) { - case IWL_EMPTYING_HW_QUEUE_DELBA: - /* We are reclaiming the last packet of the */ - /* aggregated HW queue */ - if ((txq_id == tid_data->agg.txq_id) && - (q->read_ptr == q->write_ptr)) { - u16 ssn = SEQ_TO_SN(tid_data->seq_number); - int tx_fifo = get_fifo_from_tid(ctx, tid); - IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); - trans_txq_agg_disable(&priv->trans, txq_id, - ssn, tx_fifo); - tid_data->agg.state = IWL_AGG_OFF; - ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); - } - break; - case IWL_EMPTYING_HW_QUEUE_ADDBA: - /* We are reclaiming the last packet of the queue */ - if (tid_data->tfds_in_queue == 0) { - IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n"); - tid_data->agg.state = IWL_AGG_ON; - ieee80211_start_tx_ba_cb_irqsafe(ctx->vif, addr, tid); - } - break; - } - - return 0; + return iwl_trans_tx_agg_disable(trans(priv), vif_priv->ctx->ctxid, + sta_id, tid); } static void iwlagn_non_agg_tx_status(struct iwl_priv *priv, @@ -702,147 +447,394 @@ static void iwlagn_non_agg_tx_status(struct iwl_priv *priv, rcu_read_unlock(); } -static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info, - bool is_agg) +/** + * translate ucode response to mac80211 tx status control values + */ +static void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, + struct ieee80211_tx_info *info) +{ + struct ieee80211_tx_rate *r = &info->control.rates[0]; + + info->antenna_sel_tx = + ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); + if (rate_n_flags & RATE_MCS_HT_MSK) + r->flags |= IEEE80211_TX_RC_MCS; + if (rate_n_flags & RATE_MCS_GF_MSK) + r->flags |= IEEE80211_TX_RC_GREEN_FIELD; + if (rate_n_flags & RATE_MCS_HT40_MSK) + r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (rate_n_flags & RATE_MCS_DUP_MSK) + r->flags |= IEEE80211_TX_RC_DUP_DATA; + if (rate_n_flags & RATE_MCS_SGI_MSK) + r->flags |= IEEE80211_TX_RC_SHORT_GI; + r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band); +} + +#ifdef CONFIG_IWLWIFI_DEBUG +const char *iwl_get_tx_fail_reason(u32 status) { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data; +#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x +#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x + + switch (status & TX_STATUS_MSK) { + case TX_STATUS_SUCCESS: + return "SUCCESS"; + TX_STATUS_POSTPONE(DELAY); + TX_STATUS_POSTPONE(FEW_BYTES); + TX_STATUS_POSTPONE(BT_PRIO); + TX_STATUS_POSTPONE(QUIET_PERIOD); + TX_STATUS_POSTPONE(CALC_TTAK); + TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); + TX_STATUS_FAIL(SHORT_LIMIT); + TX_STATUS_FAIL(LONG_LIMIT); + TX_STATUS_FAIL(FIFO_UNDERRUN); + TX_STATUS_FAIL(DRAIN_FLOW); + TX_STATUS_FAIL(RFKILL_FLUSH); + TX_STATUS_FAIL(LIFE_EXPIRE); + TX_STATUS_FAIL(DEST_PS); + TX_STATUS_FAIL(HOST_ABORTED); + TX_STATUS_FAIL(BT_RETRY); + TX_STATUS_FAIL(STA_INVALID); + TX_STATUS_FAIL(FRAG_DROPPED); + TX_STATUS_FAIL(TID_DISABLE); + TX_STATUS_FAIL(FIFO_FLUSHED); + TX_STATUS_FAIL(INSUFFICIENT_CF_POLL); + TX_STATUS_FAIL(PASSIVE_NO_RX); + TX_STATUS_FAIL(NO_BEACON_ON_RADAR); + } - if (!is_agg) - iwlagn_non_agg_tx_status(priv, tx_info->ctx, hdr->addr1); + return "UNKNOWN"; - ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb); +#undef TX_STATUS_FAIL +#undef TX_STATUS_POSTPONE } +#endif /* CONFIG_IWLWIFI_DEBUG */ -int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status) { - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; - struct iwl_tx_info *tx_info; - int nfreed = 0; - struct ieee80211_hdr *hdr; + status &= AGG_TX_STATUS_MSK; - if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { - IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), " - "index %d is out of range [0-%d] %d %d.\n", __func__, - txq_id, index, q->n_bd, q->write_ptr, q->read_ptr); - return 0; + switch (status) { + case AGG_TX_STATE_UNDERRUN_MSK: + priv->reply_agg_tx_stats.underrun++; + break; + case AGG_TX_STATE_BT_PRIO_MSK: + priv->reply_agg_tx_stats.bt_prio++; + break; + case AGG_TX_STATE_FEW_BYTES_MSK: + priv->reply_agg_tx_stats.few_bytes++; + break; + case AGG_TX_STATE_ABORT_MSK: + priv->reply_agg_tx_stats.abort++; + break; + case AGG_TX_STATE_LAST_SENT_TTL_MSK: + priv->reply_agg_tx_stats.last_sent_ttl++; + break; + case AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK: + priv->reply_agg_tx_stats.last_sent_try++; + break; + case AGG_TX_STATE_LAST_SENT_BT_KILL_MSK: + priv->reply_agg_tx_stats.last_sent_bt_kill++; + break; + case AGG_TX_STATE_SCD_QUERY_MSK: + priv->reply_agg_tx_stats.scd_query++; + break; + case AGG_TX_STATE_TEST_BAD_CRC32_MSK: + priv->reply_agg_tx_stats.bad_crc32++; + break; + case AGG_TX_STATE_RESPONSE_MSK: + priv->reply_agg_tx_stats.response++; + break; + case AGG_TX_STATE_DUMP_TX_MSK: + priv->reply_agg_tx_stats.dump_tx++; + break; + case AGG_TX_STATE_DELAY_TX_MSK: + priv->reply_agg_tx_stats.delay_tx++; + break; + default: + priv->reply_agg_tx_stats.unknown++; + break; } +} + +static void iwl_rx_reply_tx_agg(struct iwl_priv *priv, + struct iwlagn_tx_resp *tx_resp) +{ + struct agg_tx_status *frame_status = &tx_resp->status; + int tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> + IWLAGN_TX_RES_TID_POS; + int sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> + IWLAGN_TX_RES_RA_POS; + struct iwl_ht_agg *agg = &priv->shrd->tid_data[sta_id][tid].agg; + u32 status = le16_to_cpu(tx_resp->status.status); + int i; + + if (agg->wait_for_ba) + IWL_DEBUG_TX_REPLY(priv, + "got tx response w/o block-ack\n"); - for (index = iwl_queue_inc_wrap(index, q->n_bd); - q->read_ptr != index; - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags); + agg->wait_for_ba = (tx_resp->frame_count > 1); - tx_info = &txq->txb[txq->q.read_ptr]; + /* + * If the BT kill count is non-zero, we'll get this + * notification again. + */ + if (tx_resp->bt_kill_count && tx_resp->frame_count == 1 && + priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { + IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n"); + } - if (WARN_ON_ONCE(tx_info->skb == NULL)) - continue; + if (tx_resp->frame_count == 1) + return; - hdr = (struct ieee80211_hdr *)tx_info->skb->data; - if (ieee80211_is_data_qos(hdr->frame_control)) - nfreed++; + /* Construct bit-map of pending frames within Tx window */ + for (i = 0; i < tx_resp->frame_count; i++) { + u16 fstatus = le16_to_cpu(frame_status[i].status); - iwlagn_tx_status(priv, tx_info, - txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); - tx_info->skb = NULL; + if (status & AGG_TX_STATUS_MSK) + iwlagn_count_agg_tx_err_status(priv, fstatus); - iwlagn_txq_inval_byte_cnt_tbl(priv, txq); + if (status & (AGG_TX_STATE_FEW_BYTES_MSK | + AGG_TX_STATE_ABORT_MSK)) + continue; - iwlagn_txq_free_tfd(priv, txq, txq->q.read_ptr); + IWL_DEBUG_TX_REPLY(priv, "status %s (0x%08x), " + "try-count (0x%08x)\n", + iwl_get_agg_tx_fail_reason(fstatus), + fstatus & AGG_TX_STATUS_MSK, + fstatus & AGG_TX_TRY_MSK); } - return nfreed; } -/** - * iwlagn_tx_status_reply_compressed_ba - Update tx status from block-ack - * - * Go through block-ack's bitmap of ACK'd frames, update driver's record of - * ACK vs. not. This gets sent to mac80211, then to rate scaling algo. - */ -static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_ht_agg *agg, - struct iwl_compressed_ba_resp *ba_resp) +#ifdef CONFIG_IWLWIFI_DEBUG +#define AGG_TX_STATE_FAIL(x) case AGG_TX_STATE_ ## x: return #x +const char *iwl_get_agg_tx_fail_reason(u16 status) { - int sh; - u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); - u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); - struct ieee80211_tx_info *info; - u64 bitmap, sent_bitmap; - - if (unlikely(!agg->wait_for_ba)) { - if (unlikely(ba_resp->bitmap)) - IWL_ERR(priv, "Received BA when not expected\n"); - return -EINVAL; + status &= AGG_TX_STATUS_MSK; + switch (status) { + case AGG_TX_STATE_TRANSMITTED: + return "SUCCESS"; + AGG_TX_STATE_FAIL(UNDERRUN_MSK); + AGG_TX_STATE_FAIL(BT_PRIO_MSK); + AGG_TX_STATE_FAIL(FEW_BYTES_MSK); + AGG_TX_STATE_FAIL(ABORT_MSK); + AGG_TX_STATE_FAIL(LAST_SENT_TTL_MSK); + AGG_TX_STATE_FAIL(LAST_SENT_TRY_CNT_MSK); + AGG_TX_STATE_FAIL(LAST_SENT_BT_KILL_MSK); + AGG_TX_STATE_FAIL(SCD_QUERY_MSK); + AGG_TX_STATE_FAIL(TEST_BAD_CRC32_MSK); + AGG_TX_STATE_FAIL(RESPONSE_MSK); + AGG_TX_STATE_FAIL(DUMP_TX_MSK); + AGG_TX_STATE_FAIL(DELAY_TX_MSK); } - /* Mark that the expected block-ack response arrived */ - agg->wait_for_ba = 0; - IWL_DEBUG_TX_REPLY(priv, "BA %d %d\n", agg->start_idx, ba_resp->seq_ctl); - - /* Calculate shift to align block-ack bits with our Tx window bits */ - sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); - if (sh < 0) - sh += 0x100; + return "UNKNOWN"; +} +#endif /* CONFIG_IWLWIFI_DEBUG */ - /* - * Check for success or failure according to the - * transmitted bitmap and block-ack bitmap - */ - bitmap = le64_to_cpu(ba_resp->bitmap) >> sh; - sent_bitmap = bitmap & agg->bitmap; +static inline u32 iwlagn_get_scd_ssn(struct iwlagn_tx_resp *tx_resp) +{ + return le32_to_cpup((__le32 *)&tx_resp->status + + tx_resp->frame_count) & MAX_SN; +} - /* Sanity check values reported by uCode */ - if (ba_resp->txed_2_done > ba_resp->txed) { - IWL_DEBUG_TX_REPLY(priv, - "bogus sent(%d) and ack(%d) count\n", - ba_resp->txed, ba_resp->txed_2_done); - /* - * set txed_2_done = txed, - * so it won't impact rate scale - */ - ba_resp->txed = ba_resp->txed_2_done; - } - IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", - ba_resp->txed, ba_resp->txed_2_done); +static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status) +{ + status &= TX_STATUS_MSK; - /* Find the first ACKed frame to store the TX status */ - while (sent_bitmap && !(sent_bitmap & 1)) { - agg->start_idx = (agg->start_idx + 1) & 0xff; - sent_bitmap >>= 1; + switch (status) { + case TX_STATUS_POSTPONE_DELAY: + priv->reply_tx_stats.pp_delay++; + break; + case TX_STATUS_POSTPONE_FEW_BYTES: + priv->reply_tx_stats.pp_few_bytes++; + break; + case TX_STATUS_POSTPONE_BT_PRIO: + priv->reply_tx_stats.pp_bt_prio++; + break; + case TX_STATUS_POSTPONE_QUIET_PERIOD: + priv->reply_tx_stats.pp_quiet_period++; + break; + case TX_STATUS_POSTPONE_CALC_TTAK: + priv->reply_tx_stats.pp_calc_ttak++; + break; + case TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY: + priv->reply_tx_stats.int_crossed_retry++; + break; + case TX_STATUS_FAIL_SHORT_LIMIT: + priv->reply_tx_stats.short_limit++; + break; + case TX_STATUS_FAIL_LONG_LIMIT: + priv->reply_tx_stats.long_limit++; + break; + case TX_STATUS_FAIL_FIFO_UNDERRUN: + priv->reply_tx_stats.fifo_underrun++; + break; + case TX_STATUS_FAIL_DRAIN_FLOW: + priv->reply_tx_stats.drain_flow++; + break; + case TX_STATUS_FAIL_RFKILL_FLUSH: + priv->reply_tx_stats.rfkill_flush++; + break; + case TX_STATUS_FAIL_LIFE_EXPIRE: + priv->reply_tx_stats.life_expire++; + break; + case TX_STATUS_FAIL_DEST_PS: + priv->reply_tx_stats.dest_ps++; + break; + case TX_STATUS_FAIL_HOST_ABORTED: + priv->reply_tx_stats.host_abort++; + break; + case TX_STATUS_FAIL_BT_RETRY: + priv->reply_tx_stats.bt_retry++; + break; + case TX_STATUS_FAIL_STA_INVALID: + priv->reply_tx_stats.sta_invalid++; + break; + case TX_STATUS_FAIL_FRAG_DROPPED: + priv->reply_tx_stats.frag_drop++; + break; + case TX_STATUS_FAIL_TID_DISABLE: + priv->reply_tx_stats.tid_disable++; + break; + case TX_STATUS_FAIL_FIFO_FLUSHED: + priv->reply_tx_stats.fifo_flush++; + break; + case TX_STATUS_FAIL_INSUFFICIENT_CF_POLL: + priv->reply_tx_stats.insuff_cf_poll++; + break; + case TX_STATUS_FAIL_PASSIVE_NO_RX: + priv->reply_tx_stats.fail_hw_drop++; + break; + case TX_STATUS_FAIL_NO_BEACON_ON_RADAR: + priv->reply_tx_stats.sta_color_mismatch++; + break; + default: + priv->reply_tx_stats.unknown++; + break; } +} - info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); - memset(&info->status, 0, sizeof(info->status)); - info->flags |= IEEE80211_TX_STAT_ACK; - info->flags |= IEEE80211_TX_STAT_AMPDU; - info->status.ampdu_ack_len = ba_resp->txed_2_done; - info->status.ampdu_len = ba_resp->txed; - iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); +static void iwlagn_set_tx_status(struct iwl_priv *priv, + struct ieee80211_tx_info *info, + struct iwlagn_tx_resp *tx_resp, + bool is_agg) +{ + u16 status = le16_to_cpu(tx_resp->status.status); + + info->status.rates[0].count = tx_resp->failure_frame + 1; + if (is_agg) + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + info->flags |= iwl_tx_status_to_mac80211(status); + iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), + info); + if (!iwl_is_tx_success(status)) + iwlagn_count_tx_err_status(priv, status); +} - return 0; +static void iwl_check_abort_status(struct iwl_priv *priv, + u8 frame_count, u32 status) +{ + if (frame_count == 1 && status == TX_STATUS_FAIL_RFKILL_FLUSH) { + IWL_ERR(priv, "Tx flush command to flush out all frames\n"); + if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) + queue_work(priv->shrd->workqueue, &priv->tx_flush); + } } -/** - * translate ucode response to mac80211 tx status control values - */ -void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_info *info) +int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { - struct ieee80211_tx_rate *r = &info->control.rates[0]; + struct iwl_rx_packet *pkt = rxb_addr(rxb); + u16 sequence = le16_to_cpu(pkt->hdr.sequence); + int txq_id = SEQ_TO_QUEUE(sequence); + int cmd_index __maybe_unused = SEQ_TO_INDEX(sequence); + struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; + struct ieee80211_hdr *hdr; + u32 status = le16_to_cpu(tx_resp->status.status); + u32 ssn = iwlagn_get_scd_ssn(tx_resp); + int tid; + int sta_id; + int freed; + struct ieee80211_tx_info *info; + unsigned long flags; + struct sk_buff_head skbs; + struct sk_buff *skb; + struct iwl_rxon_context *ctx; + bool is_agg = (txq_id >= IWLAGN_FIRST_AMPDU_QUEUE); + + tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >> + IWLAGN_TX_RES_TID_POS; + sta_id = (tx_resp->ra_tid & IWLAGN_TX_RES_RA_MSK) >> + IWLAGN_TX_RES_RA_POS; + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + + if (is_agg) + iwl_rx_reply_tx_agg(priv, tx_resp); + + if (tx_resp->frame_count == 1) { + __skb_queue_head_init(&skbs); + /*we can free until ssn % q.n_bd not inclusive */ + iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id, + ssn, status, &skbs); + freed = 0; + while (!skb_queue_empty(&skbs)) { + skb = __skb_dequeue(&skbs); + hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_is_data_qos(hdr->frame_control)) + priv->last_seq_ctl = tx_resp->seq_ctl; + + info = IEEE80211_SKB_CB(skb); + ctx = info->driver_data[0]; + kmem_cache_free(priv->tx_cmd_pool, + (info->driver_data[1])); + + memset(&info->status, 0, sizeof(info->status)); + + if (status == TX_STATUS_FAIL_PASSIVE_NO_RX && + iwl_is_associated_ctx(ctx) && ctx->vif && + ctx->vif->type == NL80211_IFTYPE_STATION) { + ctx->last_tx_rejected = true; + iwl_trans_stop_queue(trans(priv), txq_id); + + IWL_DEBUG_TX_REPLY(priv, + "TXQ %d status %s (0x%08x) " + "rate_n_flags 0x%x retries %d\n", + txq_id, + iwl_get_tx_fail_reason(status), + status, + le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); + + IWL_DEBUG_TX_REPLY(priv, + "FrameCnt = %d, idx=%d\n", + tx_resp->frame_count, cmd_index); + } + + /* check if BAR is needed */ + if (is_agg && !iwl_is_tx_success(status)) + info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb), + tx_resp, is_agg); + if (!is_agg) + iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1); + + ieee80211_tx_status_irqsafe(priv->hw, skb); + + freed++; + } - info->antenna_sel_tx = - ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); - if (rate_n_flags & RATE_MCS_HT_MSK) - r->flags |= IEEE80211_TX_RC_MCS; - if (rate_n_flags & RATE_MCS_GF_MSK) - r->flags |= IEEE80211_TX_RC_GREEN_FIELD; - if (rate_n_flags & RATE_MCS_HT40_MSK) - r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - if (rate_n_flags & RATE_MCS_DUP_MSK) - r->flags |= IEEE80211_TX_RC_DUP_DATA; - if (rate_n_flags & RATE_MCS_SGI_MSK) - r->flags |= IEEE80211_TX_RC_SHORT_GI; - r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band); + WARN_ON(!is_agg && freed != 1); + } + + iwl_check_abort_status(priv, tx_resp->frame_count, status); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return 0; } /** @@ -851,17 +843,21 @@ void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, * Handles block-acknowledge notification from device, which reports success * of frames sent via aggregation. */ -void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; - struct iwl_tx_queue *txq = NULL; struct iwl_ht_agg *agg; - int index; + struct sk_buff_head reclaimed_skbs; + struct ieee80211_tx_info *info; + struct ieee80211_hdr *hdr; + struct sk_buff *skb; + unsigned long flags; int sta_id; int tid; - unsigned long flags; + int freed; /* "flow" corresponds to Tx queue */ u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); @@ -870,16 +866,18 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, * (in Tx queue's circular buffer) of first TFD/frame in window */ u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn); - if (scd_flow >= priv->hw_params.max_txq_num) { + if (scd_flow >= hw_params(priv).max_txq_num) { IWL_ERR(priv, "BUG_ON scd_flow is bigger than number of queues\n"); - return; + return 0; } - txq = &priv->txq[scd_flow]; sta_id = ba_resp->sta_id; tid = ba_resp->tid; - agg = &priv->stations[sta_id].tid[tid].agg; + agg = &priv->shrd->tid_data[sta_id][tid].agg; + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + if (unlikely(agg->txq_id != scd_flow)) { /* * FIXME: this is a uCode bug which need to be addressed, @@ -890,88 +888,84 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, IWL_DEBUG_TX_REPLY(priv, "BA scd_flow %d does not match txq_id %d\n", scd_flow, agg->txq_id); - return; + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return 0; } - /* Find index just before block-ack window */ - index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); - - spin_lock_irqsave(&priv->sta_lock, flags); + if (unlikely(!agg->wait_for_ba)) { + if (unlikely(ba_resp->bitmap)) + IWL_ERR(priv, "Received BA when not expected\n"); + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return 0; + } IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, " "sta_id = %d\n", agg->wait_for_ba, (u8 *) &ba_resp->sta_addr_lo32, ba_resp->sta_id); - IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " - "%d, scd_ssn = %d\n", + IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, " + "scd_flow = %d, scd_ssn = %d\n", ba_resp->tid, ba_resp->seq_ctl, (unsigned long long)le64_to_cpu(ba_resp->bitmap), ba_resp->scd_flow, ba_resp->scd_ssn); - IWL_DEBUG_TX_REPLY(priv, "DAT start_idx = %d, bitmap = 0x%llx\n", - agg->start_idx, - (unsigned long long)agg->bitmap); - /* Update driver's record of ACK vs. not for each frame in window */ - iwlagn_tx_status_reply_compressed_ba(priv, agg, ba_resp); + /* Mark that the expected block-ack response arrived */ + agg->wait_for_ba = false; + + /* Sanity check values reported by uCode */ + if (ba_resp->txed_2_done > ba_resp->txed) { + IWL_DEBUG_TX_REPLY(priv, + "bogus sent(%d) and ack(%d) count\n", + ba_resp->txed, ba_resp->txed_2_done); + /* + * set txed_2_done = txed, + * so it won't impact rate scale + */ + ba_resp->txed = ba_resp->txed_2_done; + } + IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", + ba_resp->txed, ba_resp->txed_2_done); + + __skb_queue_head_init(&reclaimed_skbs); /* Release all TFDs before the SSN, i.e. all TFDs in front of * block-ack window (we assume that they've been successfully * transmitted ... if not, it's too late anyway). */ - if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { - /* calculate mac80211 ampdu sw queue to wake */ - int freed = iwlagn_tx_queue_reclaim(priv, scd_flow, index); - iwl_free_tfds_in_queue(priv, sta_id, tid, freed); - - if ((iwl_queue_space(&txq->q) > txq->q.low_mark) && - priv->mac80211_registered && - (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) - iwl_wake_queue(priv, txq); - - iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); - } + iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow, ba_resp_scd_ssn, + 0, &reclaimed_skbs); + freed = 0; + while (!skb_queue_empty(&reclaimed_skbs)) { - spin_unlock_irqrestore(&priv->sta_lock, flags); -} + skb = __skb_dequeue(&reclaimed_skbs); + hdr = (struct ieee80211_hdr *)skb->data; -#ifdef CONFIG_IWLWIFI_DEBUG -const char *iwl_get_tx_fail_reason(u32 status) -{ -#define TX_STATUS_FAIL(x) case TX_STATUS_FAIL_ ## x: return #x -#define TX_STATUS_POSTPONE(x) case TX_STATUS_POSTPONE_ ## x: return #x + if (ieee80211_is_data_qos(hdr->frame_control)) + freed++; + else + WARN_ON_ONCE(1); + + info = IEEE80211_SKB_CB(skb); + kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1])); + + if (freed == 1) { + /* this is the first skb we deliver in this batch */ + /* put the rate scaling data there */ + info = IEEE80211_SKB_CB(skb); + memset(&info->status, 0, sizeof(info->status)); + info->flags |= IEEE80211_TX_STAT_ACK; + info->flags |= IEEE80211_TX_STAT_AMPDU; + info->status.ampdu_ack_len = ba_resp->txed_2_done; + info->status.ampdu_len = ba_resp->txed; + iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, + info); + } - switch (status & TX_STATUS_MSK) { - case TX_STATUS_SUCCESS: - return "SUCCESS"; - TX_STATUS_POSTPONE(DELAY); - TX_STATUS_POSTPONE(FEW_BYTES); - TX_STATUS_POSTPONE(BT_PRIO); - TX_STATUS_POSTPONE(QUIET_PERIOD); - TX_STATUS_POSTPONE(CALC_TTAK); - TX_STATUS_FAIL(INTERNAL_CROSSED_RETRY); - TX_STATUS_FAIL(SHORT_LIMIT); - TX_STATUS_FAIL(LONG_LIMIT); - TX_STATUS_FAIL(FIFO_UNDERRUN); - TX_STATUS_FAIL(DRAIN_FLOW); - TX_STATUS_FAIL(RFKILL_FLUSH); - TX_STATUS_FAIL(LIFE_EXPIRE); - TX_STATUS_FAIL(DEST_PS); - TX_STATUS_FAIL(HOST_ABORTED); - TX_STATUS_FAIL(BT_RETRY); - TX_STATUS_FAIL(STA_INVALID); - TX_STATUS_FAIL(FRAG_DROPPED); - TX_STATUS_FAIL(TID_DISABLE); - TX_STATUS_FAIL(FIFO_FLUSHED); - TX_STATUS_FAIL(INSUFFICIENT_CF_POLL); - TX_STATUS_FAIL(PASSIVE_NO_RX); - TX_STATUS_FAIL(NO_BEACON_ON_RADAR); + ieee80211_tx_status_irqsafe(priv->hw, skb); } - return "UNKNOWN"; - -#undef TX_STATUS_FAIL -#undef TX_STATUS_POSTPONE + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); + return 0; } -#endif /* CONFIG_IWLWIFI_DEBUG */ diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 56211006a182..8ba0dd54e37d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -35,11 +35,11 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-helpers.h" #include "iwl-agn-hw.h" #include "iwl-agn.h" #include "iwl-agn-calib.h" #include "iwl-trans.h" +#include "iwl-fh.h" static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = { {COEX_CU_UNASSOC_IDLE_RP, COEX_CU_UNASSOC_IDLE_WP, @@ -84,42 +84,37 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, priv->ucode_write_complete = 0; - iwl_write_direct32(priv, + iwl_write_direct32(bus(priv), FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); - iwl_write_direct32(priv, + iwl_write_direct32(bus(priv), FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr); - iwl_write_direct32(priv, + iwl_write_direct32(bus(priv), FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); - iwl_write_direct32(priv, + iwl_write_direct32(bus(priv), FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), (iwl_get_dma_hi_addr(phy_addr) << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); - iwl_write_direct32(priv, + iwl_write_direct32(bus(priv), FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM | 1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX | FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); - iwl_write_direct32(priv, + iwl_write_direct32(bus(priv), FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); IWL_DEBUG_FW(priv, "%s uCode section being loaded...\n", name); - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - priv->ucode_write_complete, 5 * HZ); - if (ret == -ERESTARTSYS) { - IWL_ERR(priv, "Could not load the %s uCode section due " - "to interrupt\n", name); - return ret; - } + ret = wait_event_timeout(priv->shrd->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); if (!ret) { IWL_ERR(priv, "Could not load the %s uCode section\n", name); @@ -163,7 +158,7 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv) { struct iwl_calib_temperature_offset_cmd cmd; __le16 *offset_calib = - (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_TEMPERATURE); + (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE); memset(&cmd, 0, sizeof(cmd)); iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); @@ -177,6 +172,42 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv) (u8 *)&cmd, sizeof(cmd)); } +static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv) +{ + struct iwl_calib_temperature_offset_v2_cmd cmd; + __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv, + EEPROM_KELVIN_TEMPERATURE); + __le16 *offset_calib_low = + (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE); + struct iwl_eeprom_calib_hdr *hdr; + + memset(&cmd, 0, sizeof(cmd)); + iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD); + hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, + EEPROM_CALIB_ALL); + memcpy(&cmd.radio_sensor_offset_high, offset_calib_high, + sizeof(*offset_calib_high)); + memcpy(&cmd.radio_sensor_offset_low, offset_calib_low, + sizeof(*offset_calib_low)); + if (!(cmd.radio_sensor_offset_low)) { + IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n"); + cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET; + cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET; + } + memcpy(&cmd.burntVoltageRef, &hdr->voltage, + sizeof(hdr->voltage)); + + IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n", + le16_to_cpu(cmd.radio_sensor_offset_high)); + IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n", + le16_to_cpu(cmd.radio_sensor_offset_low)); + IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n", + le16_to_cpu(cmd.burntVoltageRef)); + + return iwl_calib_set(&priv->calib_results[IWL_CALIB_TEMP_OFFSET], + (u8 *)&cmd, sizeof(cmd)); +} + static int iwlagn_send_calib_cfg(struct iwl_priv *priv) { struct iwl_calib_cfg_cmd calib_cfg_cmd; @@ -193,11 +224,12 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv) calib_cfg_cmd.ucd_calib_cfg.flags = IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK; - return trans_send_cmd(&priv->trans, &cmd); + return iwl_trans_send_cmd(trans(priv), &cmd); } -void iwlagn_rx_calib_result(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +int iwlagn_rx_calib_result(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; @@ -230,9 +262,10 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv, default: IWL_ERR(priv, "Unknown calibration notification %d\n", hdr->op_code); - return; + return -1; } iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len); + return 0; } int iwlagn_init_alive_start(struct iwl_priv *priv) @@ -262,8 +295,12 @@ int iwlagn_init_alive_start(struct iwl_priv *priv) * temperature offset calibration is only needed for runtime ucode, * so prepare the value now. */ - if (priv->cfg->need_temp_offset_calib) - return iwlagn_set_temperature_offset_calib(priv); + if (priv->cfg->need_temp_offset_calib) { + if (priv->cfg->temp_offset_v2) + return iwlagn_set_temperature_offset_calib_v2(priv); + else + return iwlagn_set_temperature_offset_calib(priv); + } return 0; } @@ -291,7 +328,7 @@ static int iwlagn_send_wimax_coex(struct iwl_priv *priv) /* coexistence is disabled */ memset(&coex_cmd, 0, sizeof(coex_cmd)); } - return trans_send_cmd_pdu(&priv->trans, + return iwl_trans_send_cmd_pdu(trans(priv), COEX_PRIORITY_TABLE_CMD, CMD_SYNC, sizeof(coex_cmd), &coex_cmd); } @@ -324,7 +361,7 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv) memcpy(prio_tbl_cmd.prio_tbl, iwlagn_bt_prio_tbl, sizeof(iwlagn_bt_prio_tbl)); - if (trans_send_cmd_pdu(&priv->trans, + if (iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_COEX_PRIO_TABLE, CMD_SYNC, sizeof(prio_tbl_cmd), &prio_tbl_cmd)) IWL_ERR(priv, "failed to send BT prio tbl command\n"); @@ -337,7 +374,7 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) env_cmd.action = action; env_cmd.type = type; - ret = trans_send_cmd_pdu(&priv->trans, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_COEX_PROT_ENV, CMD_SYNC, sizeof(env_cmd), &env_cmd); if (ret) @@ -348,9 +385,21 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) static int iwlagn_alive_notify(struct iwl_priv *priv) { + struct iwl_rxon_context *ctx; int ret; - trans_tx_start(&priv->trans); + if (!priv->tx_cmd_pool) + priv->tx_cmd_pool = + kmem_cache_create("iwlagn_dev_cmd", + sizeof(struct iwl_device_cmd), + sizeof(void *), 0, NULL); + + if (!priv->tx_cmd_pool) + return -ENOMEM; + + iwl_trans_tx_start(trans(priv)); + for_each_context(priv, ctx) + ctx->last_tx_rejected = false; ret = iwlagn_send_wimax_coex(priv); if (ret) @@ -369,7 +418,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv) * using sample data 100 bytes apart. If these sample points are good, * it's a pretty good bet that everything between them is good, too. */ -static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, +static int iwl_verify_inst_sparse(struct iwl_priv *priv, struct fw_desc *fw_desc) { __le32 *image = (__le32 *)fw_desc->v_addr; @@ -383,9 +432,9 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, /* read data comes through single port, auto-incr addr */ /* NOTE: Use the debugless read so we don't flood kernel log * if IWL_DL_IO is set */ - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, + iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR, i + IWLAGN_RTC_INST_LOWER_BOUND); - val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) return -EIO; } @@ -404,14 +453,14 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len); - iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, + iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR, IWLAGN_RTC_INST_LOWER_BOUND); for (offs = 0; offs < len && errors < 20; offs += sizeof(u32), image++) { /* read data comes through single port, auto-incr addr */ - val = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); if (val != le32_to_cpu(*image)) { IWL_ERR(priv, "uCode INST section at " "offset 0x%x, is 0x%x, s/b 0x%x\n", @@ -427,7 +476,7 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv, */ static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img) { - if (!iwlcore_verify_inst_sparse(priv, &img->code)) { + if (!iwl_verify_inst_sparse(priv, &img->code)) { IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n"); return 0; } @@ -478,7 +527,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, int ret; enum iwlagn_ucode_type old_type; - ret = trans_start_device(&priv->trans); + ret = iwl_trans_start_device(trans(priv)); if (ret) return ret; @@ -495,7 +544,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, return ret; } - trans_kick_nic(&priv->trans); + iwl_trans_kick_nic(trans(priv)); /* * Some things may run in the background now, but we @@ -545,7 +594,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) struct iwl_notification_wait calib_wait; int ret; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); /* No init ucode required? Curious, but maybe ok */ if (!priv->ucode_init.code.len) @@ -580,6 +629,6 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv) iwlagn_remove_notification(priv, &calib_wait); out: /* Whatever happened, stop the device */ - trans_stop_device(&priv->trans); + iwl_trans_stop_device(trans(priv)); return ret; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f9c3cd95d614..ccba69b7f8a7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -35,7 +35,6 @@ #include <linux/sched.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <linux/firmware.h> #include <linux/etherdevice.h> #include <linux/if_arp.h> @@ -48,10 +47,9 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-helpers.h" -#include "iwl-sta.h" #include "iwl-agn-calib.h" #include "iwl-agn.h" +#include "iwl-shared.h" #include "iwl-bus.h" #include "iwl-trans.h" @@ -79,9 +77,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); - -static int iwlagn_ant_coupling; -static bool iwlagn_bt_ch_announce = 1; +MODULE_ALIAS("iwlagn"); void iwl_update_chain_flags(struct iwl_priv *priv) { @@ -138,7 +134,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) * beacon contents. */ - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); if (!priv->beacon_ctx) { IWL_ERR(priv, "trying to build beacon w/o beacon context!\n"); @@ -183,7 +179,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) rate = info->control.rates[0].idx; priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, - priv->hw_params.valid_tx_ant); + hw_params(priv).valid_tx_ant); rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant); /* In mac80211, rates for 5 GHz start at 0 */ @@ -203,7 +199,7 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv) cmd.data[1] = priv->beacon_skb->data; cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY; - return trans_send_cmd(&priv->trans, &cmd); + return iwl_trans_send_cmd(trans(priv), &cmd); } static void iwl_bg_beacon_update(struct work_struct *work) @@ -212,7 +208,7 @@ static void iwl_bg_beacon_update(struct work_struct *work) container_of(work, struct iwl_priv, beacon_update); struct sk_buff *beacon; - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); if (!priv->beacon_ctx) { IWL_ERR(priv, "updating beacon w/o beacon context!\n"); goto out; @@ -242,7 +238,7 @@ static void iwl_bg_beacon_update(struct work_struct *work) iwlagn_send_beacon_cmd(priv); out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } static void iwl_bg_bt_runtime_config(struct work_struct *work) @@ -250,11 +246,11 @@ static void iwl_bg_bt_runtime_config(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, bt_runtime_config); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; /* dont send host command if rf-kill is on */ - if (!iwl_is_ready_rf(priv)) + if (!iwl_is_ready_rf(priv->shrd)) return; iwlagn_send_advance_bt_config(priv); } @@ -265,13 +261,13 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) container_of(work, struct iwl_priv, bt_full_concurrency); struct iwl_rxon_context *ctx; - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) goto out; /* dont send host command if rf-kill is on */ - if (!iwl_is_ready_rf(priv)) + if (!iwl_is_ready_rf(priv->shrd)) goto out; IWL_DEBUG_INFO(priv, "BT coex in %s mode\n", @@ -289,7 +285,7 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work) iwlagn_send_advance_bt_config(priv); out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } /** @@ -306,11 +302,11 @@ static void iwl_bg_statistics_periodic(unsigned long data) { struct iwl_priv *priv = (struct iwl_priv *)data; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; /* dont send host command if rf-kill is on */ - if (!iwl_is_ready_rf(priv)) + if (!iwl_is_ready_rf(priv->shrd)) return; iwl_send_statistics_request(priv, CMD_ASYNC, false); @@ -332,14 +328,14 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, ptr = base + (4 * sizeof(u32)) + (start_idx * 3 * sizeof(u32)); /* Make sure device is powered up for SRAM reads */ - spin_lock_irqsave(&priv->reg_lock, reg_flags); - if (iwl_grab_nic_access(priv)) { - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + spin_lock_irqsave(&bus(priv)->reg_lock, reg_flags); + if (iwl_grab_nic_access(bus(priv))) { + spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags); return; } /* Set starting address; reads will auto-increment */ - iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); + iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, ptr); rmb(); /* @@ -347,20 +343,20 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); - time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + ev = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); + time = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); if (mode == 0) { trace_iwlwifi_dev_ucode_cont_event(priv, 0, time, ev); } else { - data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + data = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); trace_iwlwifi_dev_ucode_cont_event(priv, time, data, ev); } } /* Allow device to power down */ - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); + iwl_release_nic_access(bus(priv)); + spin_unlock_irqrestore(&bus(priv)->reg_lock, reg_flags); } static void iwl_continuous_event_trace(struct iwl_priv *priv) @@ -373,10 +369,12 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv) base = priv->device_pointers.error_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { - capacity = iwl_read_targ_mem(priv, base); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); + capacity = iwl_read_targ_mem(bus(priv), base); + num_wraps = iwl_read_targ_mem(bus(priv), + base + (2 * sizeof(u32))); + mode = iwl_read_targ_mem(bus(priv), base + (1 * sizeof(u32))); + next_entry = iwl_read_targ_mem(bus(priv), + base + (3 * sizeof(u32))); } else return; @@ -427,7 +425,7 @@ static void iwl_bg_ucode_trace(unsigned long data) { struct iwl_priv *priv = (struct iwl_priv *)data; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; if (priv->event_log.ucode_trace) { @@ -443,131 +441,17 @@ static void iwl_bg_tx_flush(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, tx_flush); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; /* do nothing if rf-kill is on */ - if (!iwl_is_ready_rf(priv)) + if (!iwl_is_ready_rf(priv->shrd)) return; IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n"); iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); } -/***************************************************************************** - * - * sysfs attributes - * - *****************************************************************************/ - -#ifdef CONFIG_IWLWIFI_DEBUG - -/* - * The following adds a new attribute to the sysfs representation - * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/) - * used for controlling the debug level. - * - * See the level definitions in iwl for details. - * - * The debug_level being managed using sysfs below is a per device debug - * level that is used instead of the global debug level if it (the per - * device debug level) is set. - */ -static ssize_t show_debug_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); -} -static ssize_t store_debug_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - unsigned long val; - int ret; - - ret = strict_strtoul(buf, 0, &val); - if (ret) - IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); - else { - priv->debug_level = val; - if (iwl_alloc_traffic_mem(priv)) - IWL_ERR(priv, - "Not enough memory to generate traffic log\n"); - } - return strnlen(buf, count); -} - -static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, - show_debug_level, store_debug_level); - - -#endif /* CONFIG_IWLWIFI_DEBUG */ - - -static ssize_t show_temperature(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - if (!iwl_is_alive(priv)) - return -EAGAIN; - - return sprintf(buf, "%d\n", priv->temperature); -} - -static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); - -static ssize_t show_tx_power(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - - if (!iwl_is_ready_rf(priv)) - return sprintf(buf, "off\n"); - else - return sprintf(buf, "%d\n", priv->tx_power_user_lmt); -} - -static ssize_t store_tx_power(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - unsigned long val; - int ret; - - ret = strict_strtoul(buf, 10, &val); - if (ret) - IWL_INFO(priv, "%s is not in decimal form.\n", buf); - else { - ret = iwl_set_tx_power(priv, val, false); - if (ret) - IWL_ERR(priv, "failed setting tx power (0x%d).\n", - ret); - else - ret = count; - } - return ret; -} - -static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); - -static struct attribute *iwl_sysfs_entries[] = { - &dev_attr_temperature.attr, - &dev_attr_tx_power.attr, -#ifdef CONFIG_IWLWIFI_DEBUG - &dev_attr_debug_level.attr, -#endif - NULL -}; - -static struct attribute_group iwl_attribute_group = { - .name = NULL, /* put in device directory */ - .attrs = iwl_sysfs_entries, -}; - /****************************************************************************** * * uCode download functions @@ -577,7 +461,7 @@ static struct attribute_group iwl_attribute_group = { static void iwl_free_fw_desc(struct iwl_priv *priv, struct fw_desc *desc) { if (desc->v_addr) - dma_free_coherent(priv->bus->dev, desc->len, + dma_free_coherent(bus(priv)->dev, desc->len, desc->v_addr, desc->p_addr); desc->v_addr = NULL; desc->len = 0; @@ -604,7 +488,7 @@ static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc, return -EINVAL; } - desc->v_addr = dma_alloc_coherent(priv->bus->dev, len, + desc->v_addr = dma_alloc_coherent(bus(priv)->dev, len, &desc->p_addr, GFP_KERNEL); if (!desc->v_addr) return -ENOMEM; @@ -614,6 +498,64 @@ static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc, return 0; } +static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) +{ + int i; + + /* + * The default context is always valid, + * the PAN context depends on uCode. + */ + priv->shrd->valid_contexts = BIT(IWL_RXON_CTX_BSS); + if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) + priv->shrd->valid_contexts |= BIT(IWL_RXON_CTX_PAN); + + for (i = 0; i < NUM_IWL_RXON_CTX; i++) + priv->contexts[i].ctxid = i; + + priv->contexts[IWL_RXON_CTX_BSS].always_active = true; + priv->contexts[IWL_RXON_CTX_BSS].is_active = true; + priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON; + priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING; + priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC; + priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM; + priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID; + priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY; + priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes = + BIT(NL80211_IFTYPE_ADHOC); + priv->contexts[IWL_RXON_CTX_BSS].interface_modes = + BIT(NL80211_IFTYPE_STATION); + priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP; + priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; + priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; + priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; + + priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON; + priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd = + REPLY_WIPAN_RXON_TIMING; + priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd = + REPLY_WIPAN_RXON_ASSOC; + priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM; + priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN; + priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY; + priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID; + priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION; + priv->contexts[IWL_RXON_CTX_PAN].interface_modes = + BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); + + if (ucode_flags & IWL_UCODE_TLV_FLAGS_P2P) + priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + + priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; + priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; + priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; + + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); +} + + struct iwlagn_ucode_capabilities { u32 max_probe_length; u32 standard_phy_calibration_size; @@ -621,7 +563,7 @@ struct iwlagn_ucode_capabilities { }; static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context); -static int iwl_mac_setup_register(struct iwl_priv *priv, +static int iwlagn_mac_setup_register(struct iwl_priv *priv, struct iwlagn_ucode_capabilities *capa); #define UCODE_EXPERIMENTAL_INDEX 100 @@ -658,7 +600,7 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first) priv->firmware_name); return request_firmware_nowait(THIS_MODULE, 1, priv->firmware_name, - priv->bus->dev, + bus(priv)->dev, GFP_KERNEL, priv, iwl_ucode_callback); } @@ -738,8 +680,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv, return 0; } -static int iwlagn_wanted_ucode_alternative = 1; - static int iwlagn_load_firmware(struct iwl_priv *priv, const struct firmware *ucode_raw, struct iwlagn_firmware_pieces *pieces, @@ -749,7 +689,8 @@ static int iwlagn_load_firmware(struct iwl_priv *priv, struct iwl_ucode_tlv *tlv; size_t len = ucode_raw->size; const u8 *data; - int wanted_alternative = iwlagn_wanted_ucode_alternative, tmp; + int wanted_alternative = iwlagn_mod_params.wanted_ucode_alternative; + int tmp; u64 alternatives; u32 tlv_len; enum iwl_ucode_tlv_type tlv_type; @@ -952,6 +893,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) int err; struct iwlagn_firmware_pieces pieces; const unsigned int api_max = priv->cfg->ucode_api_max; + unsigned int api_ok = priv->cfg->ucode_api_ok; const unsigned int api_min = priv->cfg->ucode_api_min; u32 api_ver; char buildstr[25]; @@ -962,10 +904,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) IWL_DEFAULT_STANDARD_PHY_CALIBRATE_TBL_SIZE, }; + if (!api_ok) + api_ok = api_max; + memset(&pieces, 0, sizeof(pieces)); if (!ucode_raw) { - if (priv->fw_index <= priv->cfg->ucode_api_max) + if (priv->fw_index <= api_ok) IWL_ERR(priv, "request for firmware file '%s' failed.\n", priv->firmware_name); @@ -1011,12 +956,18 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) goto try_again; } - if (api_ver != api_max) - IWL_ERR(priv, - "Firmware has old API version. Expected v%u, " - "got v%u. New firmware can be obtained " - "from http://www.intellinuxwireless.org.\n", - api_max, api_ver); + if (api_ver < api_ok) { + if (api_ok != api_max) + IWL_ERR(priv, "Firmware has old API version, " + "expected v%u through v%u, got v%u.\n", + api_ok, api_max, api_ver); + else + IWL_ERR(priv, "Firmware has old API version, " + "expected v%u, got v%u.\n", + api_max, api_ver); + IWL_ERR(priv, "New firmware can be obtained from " + "http://www.intellinuxwireless.org/.\n"); + } } if (build) @@ -1060,25 +1011,25 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) pieces.init_data_size); /* Verify that uCode images will fit in card's SRAM */ - if (pieces.inst_size > priv->hw_params.max_inst_size) { + if (pieces.inst_size > hw_params(priv).max_inst_size) { IWL_ERR(priv, "uCode instr len %Zd too large to fit in\n", pieces.inst_size); goto try_again; } - if (pieces.data_size > priv->hw_params.max_data_size) { + if (pieces.data_size > hw_params(priv).max_data_size) { IWL_ERR(priv, "uCode data len %Zd too large to fit in\n", pieces.data_size); goto try_again; } - if (pieces.init_size > priv->hw_params.max_inst_size) { + if (pieces.init_size > hw_params(priv).max_inst_size) { IWL_ERR(priv, "uCode init instr len %Zd too large to fit in\n", pieces.init_size); goto try_again; } - if (pieces.init_data_size > priv->hw_params.max_data_size) { + if (pieces.init_data_size > hw_params(priv).max_data_size) { IWL_ERR(priv, "uCode init data len %Zd too large to fit in\n", pieces.init_data_size); goto try_again; @@ -1143,17 +1094,23 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->new_scan_threshold_behaviour = !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN); - if ((priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE) && - (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) { - priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN); + if (!(priv->cfg->sku & EEPROM_SKU_CAP_IPAN_ENABLE)) + ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_PAN; + + /* + * if not PAN, then don't support P2P -- might be a uCode + * packaging bug or due to the eeprom check above + */ + if (!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN)) + ucode_capa.flags &= ~IWL_UCODE_TLV_FLAGS_P2P; + + if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; - } else + priv->shrd->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; + } else { priv->sta_key_max_num = STA_KEY_MAX_NUM; - - if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) - priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; - else - priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + priv->shrd->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; + } /* * figure out the offset of chain noise reset and gain commands @@ -1169,12 +1126,15 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) priv->phy_calib_chain_noise_gain_cmd = ucode_capa.standard_phy_calibration_size + 1; + /* initialize all valid contexts */ + iwl_init_context(priv, ucode_capa.flags); + /************************************************** * This is still part of probe() in a sense... * * 9. Setup and register with mac80211 and debugfs **************************************************/ - err = iwl_mac_setup_register(priv, &ucode_capa); + err = iwlagn_mac_setup_register(priv, &ucode_capa); if (err) goto out_unbind; @@ -1182,13 +1142,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) if (err) IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); - err = sysfs_create_group(&(priv->bus->dev->kobj), - &iwl_attribute_group); - if (err) { - IWL_ERR(priv, "failed to create sysfs device attributes\n"); - goto out_unbind; - } - /* We have our copies now, allow OS release its copies */ release_firmware(ucode_raw); complete(&priv->firmware_loading_complete); @@ -1206,368 +1159,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) iwl_dealloc_ucode(priv); out_unbind: complete(&priv->firmware_loading_complete); - device_release_driver(priv->bus->dev); + device_release_driver(bus(priv)->dev); release_firmware(ucode_raw); } -static const char * const desc_lookup_text[] = { - "OK", - "FAIL", - "BAD_PARAM", - "BAD_CHECKSUM", - "NMI_INTERRUPT_WDG", - "SYSASSERT", - "FATAL_ERROR", - "BAD_COMMAND", - "HW_ERROR_TUNE_LOCK", - "HW_ERROR_TEMPERATURE", - "ILLEGAL_CHAN_FREQ", - "VCC_NOT_STABLE", - "FH_ERROR", - "NMI_INTERRUPT_HOST", - "NMI_INTERRUPT_ACTION_PT", - "NMI_INTERRUPT_UNKNOWN", - "UCODE_VERSION_MISMATCH", - "HW_ERROR_ABS_LOCK", - "HW_ERROR_CAL_LOCK_FAIL", - "NMI_INTERRUPT_INST_ACTION_PT", - "NMI_INTERRUPT_DATA_ACTION_PT", - "NMI_TRM_HW_ER", - "NMI_INTERRUPT_TRM", - "NMI_INTERRUPT_BREAK_POINT", - "DEBUG_0", - "DEBUG_1", - "DEBUG_2", - "DEBUG_3", -}; - -static struct { char *name; u8 num; } advanced_lookup[] = { - { "NMI_INTERRUPT_WDG", 0x34 }, - { "SYSASSERT", 0x35 }, - { "UCODE_VERSION_MISMATCH", 0x37 }, - { "BAD_COMMAND", 0x38 }, - { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, - { "FATAL_ERROR", 0x3D }, - { "NMI_TRM_HW_ERR", 0x46 }, - { "NMI_INTERRUPT_TRM", 0x4C }, - { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, - { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, - { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, - { "NMI_INTERRUPT_HOST", 0x66 }, - { "NMI_INTERRUPT_ACTION_PT", 0x7C }, - { "NMI_INTERRUPT_UNKNOWN", 0x84 }, - { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, - { "ADVANCED_SYSASSERT", 0 }, -}; - -static const char *desc_lookup(u32 num) -{ - int i; - int max = ARRAY_SIZE(desc_lookup_text); - - if (num < max) - return desc_lookup_text[num]; - - max = ARRAY_SIZE(advanced_lookup) - 1; - for (i = 0; i < max; i++) { - if (advanced_lookup[i].num == num) - break; - } - return advanced_lookup[i].name; -} - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -void iwl_dump_nic_error_log(struct iwl_priv *priv) -{ - u32 base; - struct iwl_error_event_table table; - - base = priv->device_pointers.error_event_table; - if (priv->ucode_type == IWL_UCODE_INIT) { - if (!base) - base = priv->init_errlog_ptr; - } else { - if (!base) - base = priv->inst_errlog_ptr; - } - - if (!iwlagn_hw_valid_rtc_data_addr(base)) { - IWL_ERR(priv, - "Not valid error log pointer 0x%08X for %s uCode\n", - base, - (priv->ucode_type == IWL_UCODE_INIT) - ? "Init" : "RT"); - return; - } - - iwl_read_targ_mem_words(priv, base, &table, sizeof(table)); - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(priv, "Start IWL Error Log Dump:\n"); - IWL_ERR(priv, "Status: 0x%08lX, count: %d\n", - priv->status, table.valid); - } - - priv->isr_stats.err_code = table.error_id; - - trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, - table.data1, table.data2, table.line, - table.blink1, table.blink2, table.ilink1, - table.ilink2, table.bcon_time, table.gp1, - table.gp2, table.gp3, table.ucode_ver, - table.hw_ver, table.brd_ver); - IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id, - desc_lookup(table.error_id)); - IWL_ERR(priv, "0x%08X | uPc\n", table.pc); - IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1); - IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2); - IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1); - IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2); - IWL_ERR(priv, "0x%08X | data1\n", table.data1); - IWL_ERR(priv, "0x%08X | data2\n", table.data2); - IWL_ERR(priv, "0x%08X | line\n", table.line); - IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time); - IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low); - IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi); - IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1); - IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2); - IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3); - IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver); - IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver); - IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver); - IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd); -} - -#define EVENT_START_OFFSET (4 * sizeof(u32)) - -/** - * iwl_print_event_log - Dump error event log to syslog - * - */ -static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, - u32 num_events, u32 mode, - int pos, char **buf, size_t bufsz) -{ - u32 i; - u32 base; /* SRAM byte address of event log header */ - u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ - u32 ptr; /* SRAM byte address of log data */ - u32 ev, time, data; /* event log data */ - unsigned long reg_flags; - - if (num_events == 0) - return pos; - - base = priv->device_pointers.log_event_table; - if (priv->ucode_type == IWL_UCODE_INIT) { - if (!base) - base = priv->init_evtlog_ptr; - } else { - if (!base) - base = priv->inst_evtlog_ptr; - } - - if (mode == 0) - event_size = 2 * sizeof(u32); - else - event_size = 3 * sizeof(u32); - - ptr = base + EVENT_START_OFFSET + (start_idx * event_size); - - /* Make sure device is powered up for SRAM reads */ - spin_lock_irqsave(&priv->reg_lock, reg_flags); - iwl_grab_nic_access(priv); - - /* Set starting address; reads will auto-increment */ - iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr); - rmb(); - - /* "time" is actually "data" for mode 0 (no timestamp). - * place event id # at far right for easier visual parsing. */ - for (i = 0; i < num_events; i++) { - ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT); - time = iwl_read32(priv, HBUS_TARG_MEM_RDAT); - if (mode == 0) { - /* data, ev */ - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "EVT_LOG:0x%08x:%04u\n", - time, ev); - } else { - trace_iwlwifi_dev_ucode_event(priv, 0, - time, ev); - IWL_ERR(priv, "EVT_LOG:0x%08x:%04u\n", - time, ev); - } - } else { - data = iwl_read32(priv, HBUS_TARG_MEM_RDAT); - if (bufsz) { - pos += scnprintf(*buf + pos, bufsz - pos, - "EVT_LOGT:%010u:0x%08x:%04u\n", - time, data, ev); - } else { - IWL_ERR(priv, "EVT_LOGT:%010u:0x%08x:%04u\n", - time, data, ev); - trace_iwlwifi_dev_ucode_event(priv, time, - data, ev); - } - } - } - - /* Allow device to power down */ - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, reg_flags); - return pos; -} - -/** - * iwl_print_last_event_logs - Dump the newest # of event log to syslog - */ -static int iwl_print_last_event_logs(struct iwl_priv *priv, u32 capacity, - u32 num_wraps, u32 next_entry, - u32 size, u32 mode, - int pos, char **buf, size_t bufsz) -{ - /* - * display the newest DEFAULT_LOG_ENTRIES entries - * i.e the entries just before the next ont that uCode would fill. - */ - if (num_wraps) { - if (next_entry < size) { - pos = iwl_print_event_log(priv, - capacity - (size - next_entry), - size - next_entry, mode, - pos, buf, bufsz); - pos = iwl_print_event_log(priv, 0, - next_entry, mode, - pos, buf, bufsz); - } else - pos = iwl_print_event_log(priv, next_entry - size, - size, mode, pos, buf, bufsz); - } else { - if (next_entry < size) { - pos = iwl_print_event_log(priv, 0, next_entry, - mode, pos, buf, bufsz); - } else { - pos = iwl_print_event_log(priv, next_entry - size, - size, mode, pos, buf, bufsz); - } - } - return pos; -} - -#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) - -int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log, - char **buf, bool display) -{ - u32 base; /* SRAM byte address of event log header */ - u32 capacity; /* event log capacity in # entries */ - u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ - u32 num_wraps; /* # times uCode wrapped to top of log */ - u32 next_entry; /* index of next entry to be written by uCode */ - u32 size; /* # entries that we'll print */ - u32 logsize; - int pos = 0; - size_t bufsz = 0; - - base = priv->device_pointers.log_event_table; - if (priv->ucode_type == IWL_UCODE_INIT) { - logsize = priv->init_evtlog_size; - if (!base) - base = priv->init_evtlog_ptr; - } else { - logsize = priv->inst_evtlog_size; - if (!base) - base = priv->inst_evtlog_ptr; - } - - if (!iwlagn_hw_valid_rtc_data_addr(base)) { - IWL_ERR(priv, - "Invalid event log pointer 0x%08X for %s uCode\n", - base, - (priv->ucode_type == IWL_UCODE_INIT) - ? "Init" : "RT"); - return -EINVAL; - } - - /* event log header */ - capacity = iwl_read_targ_mem(priv, base); - mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32))); - num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32))); - next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32))); - - if (capacity > logsize) { - IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n", - capacity, logsize); - capacity = logsize; - } - - if (next_entry > logsize) { - IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n", - next_entry, logsize); - next_entry = logsize; - } - - size = num_wraps ? capacity : next_entry; - - /* bail out if nothing in log */ - if (size == 0) { - IWL_ERR(priv, "Start IWL Event Log Dump: nothing in log\n"); - return pos; - } - - /* enable/disable bt channel inhibition */ - priv->bt_ch_announce = iwlagn_bt_ch_announce; - -#ifdef CONFIG_IWLWIFI_DEBUG - if (!(iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) && !full_log) - size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) - ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; -#else - size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) - ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; -#endif - IWL_ERR(priv, "Start IWL Event Log Dump: display last %u entries\n", - size); - -#ifdef CONFIG_IWLWIFI_DEBUG - if (display) { - if (full_log) - bufsz = capacity * 48; - else - bufsz = size * 48; - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - } - if ((iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) || full_log) { - /* - * if uCode has wrapped back to top of log, - * start at the oldest entry, - * i.e the next one that uCode would fill. - */ - if (num_wraps) - pos = iwl_print_event_log(priv, next_entry, - capacity - next_entry, mode, - pos, buf, bufsz); - /* (then/else) start at top of log */ - pos = iwl_print_event_log(priv, 0, - next_entry, mode, pos, buf, bufsz); - } else - pos = iwl_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); -#else - pos = iwl_print_last_event_logs(priv, capacity, num_wraps, - next_entry, size, mode, - pos, buf, bufsz); -#endif - return pos; -} - static void iwl_rf_kill_ct_config(struct iwl_priv *priv) { struct iwl_ct_kill_config cmd; @@ -1575,44 +1170,43 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) unsigned long flags; int ret = 0; - spin_lock_irqsave(&priv->lock, flags); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + spin_lock_irqsave(&priv->shrd->lock, flags); + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); priv->thermal_throttle.ct_kill_toggle = false; if (priv->cfg->base_params->support_ct_kill_exit) { adv_cmd.critical_temperature_enter = - cpu_to_le32(priv->hw_params.ct_kill_threshold); + cpu_to_le32(hw_params(priv).ct_kill_threshold); adv_cmd.critical_temperature_exit = - cpu_to_le32(priv->hw_params.ct_kill_exit_threshold); + cpu_to_le32(hw_params(priv).ct_kill_exit_threshold); - ret = trans_send_cmd_pdu(&priv->trans, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_CT_KILL_CONFIG_CMD, CMD_SYNC, sizeof(adv_cmd), &adv_cmd); if (ret) IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); else IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " - "succeeded, " - "critical temperature enter is %d," - "exit is %d\n", - priv->hw_params.ct_kill_threshold, - priv->hw_params.ct_kill_exit_threshold); + "succeeded, critical temperature enter is %d," + "exit is %d\n", + hw_params(priv).ct_kill_threshold, + hw_params(priv).ct_kill_exit_threshold); } else { cmd.critical_temperature_R = - cpu_to_le32(priv->hw_params.ct_kill_threshold); + cpu_to_le32(hw_params(priv).ct_kill_threshold); - ret = trans_send_cmd_pdu(&priv->trans, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_CT_KILL_CONFIG_CMD, CMD_SYNC, sizeof(cmd), &cmd); if (ret) IWL_ERR(priv, "REPLY_CT_KILL_CONFIG_CMD failed\n"); else IWL_DEBUG_INFO(priv, "REPLY_CT_KILL_CONFIG_CMD " - "succeeded, " - "critical temperature is %d\n", - priv->hw_params.ct_kill_threshold); + "succeeded, " + "critical temperature is %d\n", + hw_params(priv).ct_kill_threshold); } } @@ -1626,10 +1220,10 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg) }; memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd)); - calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_INIT_CFG_ALL; + calib_cfg_cmd.ucd_calib_cfg.once.is_enable = IWL_CALIB_RT_CFG_ALL; calib_cfg_cmd.ucd_calib_cfg.once.start = cpu_to_le32(cfg); - return trans_send_cmd(&priv->trans, &cmd); + return iwl_trans_send_cmd(trans(priv), &cmd); } @@ -1641,7 +1235,7 @@ static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant) if (IWL_UCODE_API(priv->ucode_ver) > 1) { IWL_DEBUG_HC(priv, "select valid tx ant: %u\n", valid_tx_ant); - return trans_send_cmd_pdu(&priv->trans, + return iwl_trans_send_cmd_pdu(trans(priv), TX_ANT_CONFIGURATION_CMD, CMD_SYNC, sizeof(struct iwl_tx_ant_config_cmd), @@ -1663,17 +1257,17 @@ int iwl_alive_start(struct iwl_priv *priv) struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; /*TODO: this should go to the transport layer */ - iwl_reset_ict(priv); + iwl_reset_ict(trans(priv)); IWL_DEBUG_INFO(priv, "Runtime Alive received.\n"); /* After the ALIVE response, we can send host commands to the uCode */ - set_bit(STATUS_ALIVE, &priv->status); + set_bit(STATUS_ALIVE, &priv->shrd->status); /* Enable watchdog to monitor the driver tx queues */ iwl_setup_watchdog(priv); - if (iwl_is_rfkill(priv)) + if (iwl_is_rfkill(priv->shrd)) return -ERFKILL; /* download priority table before any calibration request */ @@ -1710,8 +1304,9 @@ int iwl_alive_start(struct iwl_priv *priv) iwl_send_bt_config(priv); } - if (priv->hw_params.calib_rt_cfg) - iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg); + if (hw_params(priv).calib_rt_cfg) + iwlagn_send_calib_cfg_rt(priv, + hw_params(priv).calib_rt_cfg); ieee80211_wake_queues(priv->hw); @@ -1720,7 +1315,7 @@ int iwl_alive_start(struct iwl_priv *priv) /* Configure Tx antenna selection based on H/W config */ iwlagn_send_tx_ant_config(priv, priv->cfg->valid_tx_ant); - if (iwl_is_associated_ctx(ctx) && !priv->wowlan) { + if (iwl_is_associated_ctx(ctx) && !priv->shrd->wowlan) { struct iwl_rxon_cmd *active_rxon = (struct iwl_rxon_cmd *)&ctx->active; /* apply any changes in staging */ @@ -1735,12 +1330,12 @@ int iwl_alive_start(struct iwl_priv *priv) iwlagn_set_rxon_chain(priv, ctx); } - if (!priv->wowlan) { + if (!priv->shrd->wowlan) { /* WoWLAN ucode will not reply in the same way, skip it */ iwl_reset_run_time_calib(priv); } - set_bit(STATUS_READY, &priv->status); + set_bit(STATUS_READY, &priv->shrd->status); /* Configure the adapter for unassociated operation */ ret = iwlagn_commit_rxon(priv, ctx); @@ -1765,7 +1360,15 @@ static void __iwl_down(struct iwl_priv *priv) iwl_scan_cancel_timeout(priv, 200); - exit_pending = test_and_set_bit(STATUS_EXIT_PENDING, &priv->status); + /* + * If active, scanning won't cancel it, so say it expired. + * No race since we hold the mutex here and a new one + * can't come in at this time. + */ + ieee80211_remain_on_channel_expired(priv->hw); + + exit_pending = + test_and_set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); /* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set * to prevent rearm timer */ @@ -1790,32 +1393,33 @@ static void __iwl_down(struct iwl_priv *priv) /* Wipe out the EXIT_PENDING status bit if we are not actually * exiting the module */ if (!exit_pending) - clear_bit(STATUS_EXIT_PENDING, &priv->status); + clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); + iwl_trans_stop_device(trans(priv)); + /* Clear out all status bits but a few that are stable across reset */ - priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) << + priv->shrd->status &= + test_bit(STATUS_RF_KILL_HW, &priv->shrd->status) << STATUS_RF_KILL_HW | - test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status) << STATUS_GEO_CONFIGURED | - test_bit(STATUS_FW_ERROR, &priv->status) << + test_bit(STATUS_FW_ERROR, &priv->shrd->status) << STATUS_FW_ERROR | - test_bit(STATUS_EXIT_PENDING, &priv->status) << + test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) << STATUS_EXIT_PENDING; - trans_stop_device(&priv->trans); - dev_kfree_skb(priv->beacon_skb); priv->beacon_skb = NULL; } static void iwl_down(struct iwl_priv *priv) { - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); __iwl_down(priv); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); iwl_cancel_deferred_work(priv); } @@ -1827,9 +1431,9 @@ static int __iwl_up(struct iwl_priv *priv) struct iwl_rxon_context *ctx; int ret; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) { IWL_WARN(priv, "Exit pending; will not bring the NIC up\n"); return -EIO; } @@ -1862,9 +1466,9 @@ static int __iwl_up(struct iwl_priv *priv) return 0; error: - set_bit(STATUS_EXIT_PENDING, &priv->status); + set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); __iwl_down(priv); - clear_bit(STATUS_EXIT_PENDING, &priv->status); + clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status); IWL_ERR(priv, "Unable to initialize device.\n"); return ret; @@ -1882,11 +1486,11 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) struct iwl_priv *priv = container_of(work, struct iwl_priv, run_time_calib_work); - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - test_bit(STATUS_SCANNING, &priv->status)) { - mutex_unlock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) || + test_bit(STATUS_SCANNING, &priv->shrd->status)) { + mutex_unlock(&priv->shrd->mutex); return; } @@ -1895,7 +1499,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) iwl_sensitivity_calibration(priv); } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } static void iwlagn_prepare_restart(struct iwl_priv *priv) @@ -1907,7 +1511,7 @@ static void iwlagn_prepare_restart(struct iwl_priv *priv) u8 bt_status; bool bt_is_sco; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); for_each_context(priv, ctx) ctx->vif = NULL; @@ -1941,13 +1545,13 @@ static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; - if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) { - mutex_lock(&priv->mutex); + if (test_and_clear_bit(STATUS_FW_ERROR, &priv->shrd->status)) { + mutex_lock(&priv->shrd->mutex); iwlagn_prepare_restart(priv); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); iwl_cancel_deferred_work(priv); ieee80211_restart_hw(priv->hw); } else { @@ -1955,94 +1559,6 @@ static void iwl_bg_restart(struct work_struct *data) } } -static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type, - unsigned int wait) -{ - struct iwl_priv *priv = hw->priv; - int ret; - - /* Not supported if we don't have PAN */ - if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) { - ret = -EOPNOTSUPP; - goto free; - } - - /* Not supported on pre-P2P firmware */ - if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & - BIT(NL80211_IFTYPE_P2P_CLIENT))) { - ret = -EOPNOTSUPP; - goto free; - } - - mutex_lock(&priv->mutex); - - if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) { - /* - * If the PAN context is free, use the normal - * way of doing remain-on-channel offload + TX. - */ - ret = 1; - goto out; - } - - /* TODO: queue up if scanning? */ - if (test_bit(STATUS_SCANNING, &priv->status) || - priv->offchan_tx_skb) { - ret = -EBUSY; - goto out; - } - - /* - * max_scan_ie_len doesn't include the blank SSID or the header, - * so need to add that again here. - */ - if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) { - ret = -ENOBUFS; - goto out; - } - - priv->offchan_tx_skb = skb; - priv->offchan_tx_timeout = wait; - priv->offchan_tx_chan = chan; - - ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif, - IWL_SCAN_OFFCH_TX, chan->band); - if (ret) - priv->offchan_tx_skb = NULL; - out: - mutex_unlock(&priv->mutex); - free: - if (ret < 0) - kfree_skb(skb); - - return ret; -} - -static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw) -{ - struct iwl_priv *priv = hw->priv; - int ret; - - mutex_lock(&priv->mutex); - - if (!priv->offchan_tx_skb) { - ret = -EINVAL; - goto unlock; - } - - priv->offchan_tx_skb = NULL; - - ret = iwl_scan_cancel_timeout(priv, 200); - if (ret) - ret = -EIO; -unlock: - mutex_unlock(&priv->mutex); - - return ret; -} - /***************************************************************************** * * mac80211 entry point functions @@ -2124,7 +1640,7 @@ iwlagn_iface_combinations_p2p[] = { * Not a mac80211 entry point function, but it fits in with all the * other mac80211 functions grouped here. */ -static int iwl_mac_setup_register(struct iwl_priv *priv, +static int iwlagn_mac_setup_register(struct iwl_priv *priv, struct iwlagn_ucode_capabilities *capa) { int ret; @@ -2183,7 +1699,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv, WIPHY_FLAG_DISABLE_BEACON_HINTS | WIPHY_FLAG_IBSS_RSN; - if (priv->ucode_wowlan.code.len && device_can_wakeup(priv->bus->dev)) { + if (priv->ucode_wowlan.code.len && device_can_wakeup(bus(priv)->dev)) { hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | @@ -2242,16 +1758,16 @@ static int iwlagn_mac_start(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211(priv, "enter\n"); /* we should be verifying the device is ready to be opened */ - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); ret = __iwl_up(priv); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); if (ret) return ret; IWL_DEBUG_INFO(priv, "Start UP work done.\n"); /* Now we should be done, and the READY bit should be set. */ - if (WARN_ON(!test_bit(STATUS_READY, &priv->status))) + if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status))) ret = -EIO; iwlagn_led_enable(priv); @@ -2274,17 +1790,17 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) iwl_down(priv); - flush_workqueue(priv->workqueue); + flush_workqueue(priv->shrd->workqueue); /* User space software may expect getting rfkill changes * even if interface is down */ - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); + iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF); iwl_enable_rfkill_int(priv); IWL_DEBUG_MAC80211(priv, "leave\n"); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int iwlagn_send_patterns(struct iwl_priv *priv, struct cfg80211_wowlan *wowlan) { @@ -2322,7 +1838,7 @@ static int iwlagn_send_patterns(struct iwl_priv *priv, } cmd.data[0] = pattern_cmd; - err = trans_send_cmd(&priv->trans, &cmd); + err = iwl_trans_send_cmd(trans(priv), &cmd); kfree(pattern_cmd); return err; } @@ -2337,7 +1853,8 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, if (iwlagn_mod_params.sw_crypto) return; - mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif) goto out; @@ -2348,7 +1865,8 @@ static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw, priv->have_rekey_data = true; out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); } struct wowlan_key_data { @@ -2359,7 +1877,7 @@ struct wowlan_key_data { bool error, use_rsc_tsc, use_tkip; }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static void iwlagn_convert_p1k(u16 *p1k, __le16 *out) { int i; @@ -2386,7 +1904,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, u16 p1k[IWLAGN_P1K_SIZE]; int ret, i; - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 || key->cipher == WLAN_CIPHER_SUITE_WEP104) && @@ -2491,7 +2009,7 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw, break; } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } static int iwlagn_mac_suspend(struct ieee80211_hw *hw, @@ -2516,7 +2034,8 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, if (WARN_ON(!wowlan)) return -EINVAL; - mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); /* Don't attempt WoWLAN when not associated, tear down instead. */ if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION || @@ -2545,7 +2064,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, * since the uCode will add 0x10 before using the value. */ for (i = 0; i < 8; i++) { - seq = priv->stations[IWL_AP_ID].tid[i].seq_number; + seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number; seq -= 0x10; wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq); } @@ -2577,9 +2096,9 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, memcpy(&rxon, &ctx->active, sizeof(rxon)); - trans_stop_device(&priv->trans); + iwl_trans_stop_device(trans(priv)); - priv->wowlan = true; + priv->shrd->wowlan = true; ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_wowlan, IWL_UCODE_WOWLAN); @@ -2610,11 +2129,11 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, * constraints. Since we're in the suspend path * that isn't really a problem though. */ - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); ieee80211_iter_keys(priv->hw, ctx->vif, iwlagn_wowlan_program_keys, &key_data); - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); if (key_data.error) { ret = -EIO; goto error; @@ -2629,13 +2148,13 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, .len[0] = sizeof(*key_data.rsc_tsc), }; - ret = trans_send_cmd(&priv->trans, &rsc_tsc_cmd); + ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd); if (ret) goto error; } if (key_data.use_tkip) { - ret = trans_send_cmd_pdu(&priv->trans, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_TKIP_PARAMS, CMD_SYNC, sizeof(tkip_cmd), &tkip_cmd); @@ -2651,7 +2170,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN); kek_kck_cmd.replay_ctr = priv->replay_ctr; - ret = trans_send_cmd_pdu(&priv->trans, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_KEK_KCK_MATERIAL, CMD_SYNC, sizeof(kek_kck_cmd), &kek_kck_cmd); @@ -2660,7 +2179,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, } } - ret = trans_send_cmd_pdu(&priv->trans, REPLY_WOWLAN_WAKEUP_FILTER, + ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER, CMD_SYNC, sizeof(wakeup_filter_cmd), &wakeup_filter_cmd); if (ret) @@ -2670,21 +2189,23 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, if (ret) goto error; - device_set_wakeup_enable(priv->bus->dev, true); + device_set_wakeup_enable(bus(priv)->dev, true); /* Now let the ucode operate on its own */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_SET, + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); goto out; error: - priv->wowlan = false; + priv->shrd->wowlan = false; iwlagn_prepare_restart(priv); ieee80211_restart_hw(priv->hw); out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); kfree(key_data.rsc_tsc); + IWL_DEBUG_MAC80211(priv, "leave\n"); + return ret; } @@ -2697,21 +2218,22 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) u32 base, status = 0xffffffff; int ret = -EIO; - mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, + iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); base = priv->device_pointers.error_event_table; if (iwlagn_hw_valid_rtc_data_addr(base)) { - spin_lock_irqsave(&priv->reg_lock, flags); - ret = iwl_grab_nic_access_silent(priv); + spin_lock_irqsave(&bus(priv)->reg_lock, flags); + ret = iwl_grab_nic_access_silent(bus(priv)); if (ret == 0) { - iwl_write32(priv, HBUS_TARG_MEM_RADDR, base); - status = iwl_read32(priv, HBUS_TARG_MEM_RDAT); - iwl_release_nic_access(priv); + iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base); + status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT); + iwl_release_nic_access(bus(priv)); } - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_unlock_irqrestore(&bus(priv)->reg_lock, flags); #ifdef CONFIG_IWLWIFI_DEBUGFS if (ret == 0) { @@ -2722,7 +2244,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) if (priv->wowlan_sram) _iwl_read_targ_mem_words( - priv, 0x800000, priv->wowlan_sram, + bus(priv), 0x800000, priv->wowlan_sram, priv->ucode_wowlan.data.len / 4); } #endif @@ -2731,9 +2253,9 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) /* we'll clear ctx->vif during iwlagn_prepare_restart() */ vif = ctx->vif; - priv->wowlan = false; + priv->shrd->wowlan = false; - device_set_wakeup_enable(priv->bus->dev, false); + device_set_wakeup_enable(bus(priv)->dev, false); iwlagn_prepare_restart(priv); @@ -2741,7 +2263,8 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) iwl_connection_init_rx_config(priv, ctx); iwlagn_set_rxon_chain(priv, ctx); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); ieee80211_resume_disconnect(vif); @@ -2810,7 +2333,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET) return 0; - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); iwl_scan_cancel_timeout(priv, 100); BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT); @@ -2861,7 +2384,7 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ret = -EINVAL; } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); return ret; @@ -2876,6 +2399,7 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, struct iwl_priv *priv = hw->priv; int ret = -EINVAL; struct iwl_station_priv *sta_priv = (void *) sta->drv_priv; + struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n", sta->addr, tid); @@ -2883,7 +2407,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)) return -EACCES; - mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); switch (action) { case IEEE80211_AMPDU_RX_START: @@ -2893,17 +2418,12 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: IWL_DEBUG_HT(priv, "stop Rx\n"); ret = iwl_sta_rx_agg_stop(priv, sta, tid); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) ret = 0; break; case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT(priv, "start Tx\n"); ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); - if (ret == 0) { - priv->agg_tids_count++; - IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", - priv->agg_tids_count); - } break; case IEEE80211_AMPDU_TX_STOP: IWL_DEBUG_HT(priv, "stop Tx\n"); @@ -2913,9 +2433,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", priv->agg_tids_count); } - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) ret = 0; - if (priv->cfg->ht_params && + if (!priv->agg_tids_count && priv->cfg->ht_params && priv->cfg->ht_params->use_rts_for_aggregation) { /* * switch off RTS/CTS if it was previously enabled @@ -2929,8 +2449,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_TX_OPERATIONAL: buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF); - trans_txq_agg_setup(&priv->trans, iwl_sta_id(sta), tid, - buf_size); + iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta), + tid, buf_size); /* * If the limit is 0, then it wasn't initialised yet, @@ -2962,6 +2482,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, sta_priv->lq_sta.lq.general_params.flags |= LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK; } + priv->agg_tids_count++; + IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n", + priv->agg_tids_count); sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit = sta_priv->max_agg_bufsize; @@ -2974,8 +2497,8 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw, ret = 0; break; } - mutex_unlock(&priv->mutex); - + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); return ret; } @@ -2987,15 +2510,15 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, struct iwl_station_priv *sta_priv = (void *)sta->drv_priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; bool is_ap = vif->type == NL80211_IFTYPE_STATION; - int ret; + int ret = 0; u8 sta_id; - IWL_DEBUG_INFO(priv, "received request to add station %pM\n", + IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n", sta->addr); - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n", sta->addr); - sta_priv->common.sta_id = IWL_INVALID_STATION; + sta_priv->sta_id = IWL_INVALID_STATION; atomic_set(&sta_priv->pending_frames, 0); if (vif->type == NL80211_IFTYPE_AP) @@ -3007,19 +2530,20 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, IWL_ERR(priv, "Unable to add station %pM (%d)\n", sta->addr, ret); /* Should we return success if return code is EEXIST ? */ - mutex_unlock(&priv->mutex); - return ret; + goto out; } - sta_priv->common.sta_id = sta_id; + sta_priv->sta_id = sta_id; /* Initialize rate scaling */ IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n", sta->addr); iwl_rs_rate_init(priv, sta, sta_id); - mutex_unlock(&priv->mutex); + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); - return 0; + return ret; } static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, @@ -3043,14 +2567,14 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); - if (iwl_is_rfkill(priv)) + if (iwl_is_rfkill(priv->shrd)) goto out; - if (test_bit(STATUS_EXIT_PENDING, &priv->status) || - test_bit(STATUS_SCANNING, &priv->status) || - test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) || + test_bit(STATUS_SCANNING, &priv->shrd->status) || + test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status)) goto out; if (!iwl_is_associated_ctx(ctx)) @@ -3069,7 +2593,7 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, goto out; } - spin_lock_irq(&priv->lock); + spin_lock_irq(&priv->shrd->lock); priv->current_ht_config.smps = conf->smps_mode; @@ -3099,23 +2623,23 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, iwl_set_rxon_ht(priv, ht_conf); iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif); - spin_unlock_irq(&priv->lock); + spin_unlock_irq(&priv->shrd->lock); iwl_set_rate(priv); /* * at this point, staging_rxon has the * configuration for channel switch */ - set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); + set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status); priv->switch_channel = cpu_to_le16(ch); if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) { - clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status); + clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status); priv->switch_channel = 0; ieee80211_chswitch_done(ctx->vif, false); } out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); } @@ -3145,7 +2669,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, #undef CHK - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); for_each_context(priv, ctx) { ctx->staging.filter_flags &= ~filter_nand; @@ -3157,7 +2681,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw, */ } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); /* * Receiving all multicast frames is always enabled by the @@ -3173,14 +2697,14 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) { struct iwl_priv *priv = hw->priv; - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); IWL_DEBUG_MAC80211(priv, "enter\n"); - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) { IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n"); goto done; } - if (iwl_is_rfkill(priv)) { + if (iwl_is_rfkill(priv->shrd)) { IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n"); goto done; } @@ -3197,101 +2721,198 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop) } } IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n"); - iwlagn_wait_tx_queue_empty(priv); + iwl_trans_wait_tx_queue_empty(trans(priv)); done: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); } -static void iwlagn_disable_roc(struct iwl_priv *priv) +void iwlagn_disable_roc(struct iwl_priv *priv) { struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; - struct ieee80211_channel *chan = ACCESS_ONCE(priv->hw->conf.channel); - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); - if (!ctx->is_active) + if (!priv->hw_roc_setup) return; - ctx->staging.dev_type = RXON_DEV_TYPE_2STA; + ctx->staging.dev_type = RXON_DEV_TYPE_P2P; ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl_set_rxon_channel(priv, chan, ctx); - iwl_set_flags_for_band(priv, ctx, chan->band, NULL); priv->hw_roc_channel = NULL; + memset(ctx->staging.node_addr, 0, ETH_ALEN); + iwlagn_commit_rxon(priv, ctx); ctx->is_active = false; + priv->hw_roc_setup = false; } -static void iwlagn_bg_roc_done(struct work_struct *work) +static void iwlagn_disable_roc_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, - hw_roc_work.work); + hw_roc_disable_work.work); - mutex_lock(&priv->mutex); - ieee80211_remain_on_channel_expired(priv->hw); + mutex_lock(&priv->shrd->mutex); iwlagn_disable_roc(priv); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } -static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw, +static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type, int duration) { struct iwl_priv *priv = hw->priv; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN]; int err = 0; - if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) return -EOPNOTSUPP; - if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes & - BIT(NL80211_IFTYPE_P2P_CLIENT))) + if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT))) return -EOPNOTSUPP; - mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); - if (priv->contexts[IWL_RXON_CTX_PAN].is_active || - test_bit(STATUS_SCAN_HW, &priv->status)) { + if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) { err = -EBUSY; goto out; } - priv->contexts[IWL_RXON_CTX_PAN].is_active = true; priv->hw_roc_channel = channel; priv->hw_roc_chantype = channel_type; - priv->hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024); - iwlagn_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]); - queue_delayed_work(priv->workqueue, &priv->hw_roc_work, - msecs_to_jiffies(duration + 20)); + priv->hw_roc_duration = duration; + priv->hw_roc_start_notified = false; + cancel_delayed_work(&priv->hw_roc_disable_work); + + if (!ctx->is_active) { + ctx->is_active = true; + ctx->staging.dev_type = RXON_DEV_TYPE_P2P; + memcpy(ctx->staging.node_addr, + priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, + ETH_ALEN); + memcpy(ctx->staging.bssid_addr, + priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr, + ETH_ALEN); + err = iwlagn_commit_rxon(priv, ctx); + if (err) + goto out; + ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK | + RXON_FILTER_PROMISC_MSK | + RXON_FILTER_CTL2HOST_MSK; + + err = iwlagn_commit_rxon(priv, ctx); + if (err) { + iwlagn_disable_roc(priv); + goto out; + } + priv->hw_roc_setup = true; + } - msleep(IWL_MIN_SLOT_TIME); /* TU is almost ms */ - ieee80211_ready_on_channel(priv->hw); + err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band); + if (err) + iwlagn_disable_roc(priv); out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); return err; } -static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) +static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; - if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) + if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN))) return -EOPNOTSUPP; - cancel_delayed_work_sync(&priv->hw_roc_work); - - mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + iwl_scan_cancel_timeout(priv, priv->hw_roc_duration); iwlagn_disable_roc(priv); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; } +static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *bssid, + enum ieee80211_tx_sync_type type) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_rxon_context *ctx = vif_priv->ctx; + int ret; + u8 sta_id; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + if (iwl_is_associated_ctx(ctx)) { + ret = 0; + goto out; + } + + if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) { + ret = -EBUSY; + goto out; + } + + ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id); + if (ret) + goto out; + + if (WARN_ON(sta_id != ctx->ap_sta_id)) { + ret = -EIO; + goto out_remove_sta; + } + + memcpy(ctx->bssid, bssid, ETH_ALEN); + ctx->preauth_bssid = true; + + ret = iwlagn_commit_rxon(priv, ctx); + + if (ret == 0) + goto out; + + out_remove_sta: + iwl_remove_station(priv, sta_id, bssid); + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + + return ret; +} + +static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const u8 *bssid, + enum ieee80211_tx_sync_type type) +{ + struct iwl_priv *priv = hw->priv; + struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; + struct iwl_rxon_context *ctx = vif_priv->ctx; + + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); + + if (iwl_is_associated_ctx(ctx)) + goto out; + + iwl_remove_station(priv, ctx->ap_sta_id, bssid); + ctx->preauth_bssid = false; + /* no need to commit */ + out: + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + /***************************************************************************** * * driver setup and teardown @@ -3300,9 +2921,9 @@ static int iwl_mac_cancel_remain_on_channel(struct ieee80211_hw *hw) static void iwl_setup_deferred_work(struct iwl_priv *priv) { - priv->workqueue = create_singlethread_workqueue(DRV_NAME); + priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME); - init_waitqueue_head(&priv->wait_command_queue); + init_waitqueue_head(&priv->shrd->wait_command_queue); INIT_WORK(&priv->restart, iwl_bg_restart); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); @@ -3310,7 +2931,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush); INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency); INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config); - INIT_DELAYED_WORK(&priv->hw_roc_work, iwlagn_bg_roc_done); + INIT_DELAYED_WORK(&priv->hw_roc_disable_work, + iwlagn_disable_roc_work); iwl_setup_scan_deferred_work(priv); @@ -3342,6 +2964,7 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->bt_full_concurrency); cancel_work_sync(&priv->bt_runtime_config); + cancel_delayed_work_sync(&priv->hw_roc_disable_work); del_timer_sync(&priv->statistics_periodic); del_timer_sync(&priv->ucode_trace); @@ -3372,10 +2995,9 @@ static int iwl_init_drv(struct iwl_priv *priv) { int ret; - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); + spin_lock_init(&priv->shrd->sta_lock); - mutex_init(&priv->mutex); + mutex_init(&priv->shrd->mutex); priv->ieee_channels = NULL; priv->ieee_rates = NULL; @@ -3416,7 +3038,7 @@ static int iwl_init_drv(struct iwl_priv *priv) goto err; } - ret = iwlcore_init_geos(priv); + ret = iwl_init_geos(priv); if (ret) { IWL_ERR(priv, "initializing geos failed: %d\n", ret); goto err_free_channel_map; @@ -3434,8 +3056,10 @@ err: static void iwl_uninit_drv(struct iwl_priv *priv) { iwl_calib_free_results(priv); - iwlcore_free_geos(priv); + iwl_free_geos(priv); iwl_free_channel_map(priv); + if (priv->tx_cmd_pool) + kmem_cache_destroy(priv->tx_cmd_pool); kfree(priv->scan_cmd); kfree(priv->beacon_cmd); #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -3443,12 +3067,13 @@ static void iwl_uninit_drv(struct iwl_priv *priv) #endif } -static void iwl_mac_rssi_callback(struct ieee80211_hw *hw, +static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw, enum ieee80211_rssi_event rssi_event) { struct iwl_priv *priv = hw->priv; - mutex_lock(&priv->mutex); + IWL_DEBUG_MAC80211(priv, "enter\n"); + mutex_lock(&priv->shrd->mutex); if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist) { @@ -3463,89 +3088,88 @@ static void iwl_mac_rssi_callback(struct ieee80211_hw *hw, "ignoring RSSI callback\n"); } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); +} + +static int iwlagn_mac_set_tim(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, bool set) +{ + struct iwl_priv *priv = hw->priv; + + queue_work(priv->shrd->workqueue, &priv->beacon_update); + + return 0; } struct ieee80211_ops iwlagn_hw_ops = { .tx = iwlagn_mac_tx, .start = iwlagn_mac_start, .stop = iwlagn_mac_stop, -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP .suspend = iwlagn_mac_suspend, .resume = iwlagn_mac_resume, #endif - .add_interface = iwl_mac_add_interface, - .remove_interface = iwl_mac_remove_interface, - .change_interface = iwl_mac_change_interface, + .add_interface = iwlagn_mac_add_interface, + .remove_interface = iwlagn_mac_remove_interface, + .change_interface = iwlagn_mac_change_interface, .config = iwlagn_mac_config, .configure_filter = iwlagn_configure_filter, .set_key = iwlagn_mac_set_key, .update_tkip_key = iwlagn_mac_update_tkip_key, .set_rekey_data = iwlagn_mac_set_rekey_data, - .conf_tx = iwl_mac_conf_tx, + .conf_tx = iwlagn_mac_conf_tx, .bss_info_changed = iwlagn_bss_info_changed, .ampdu_action = iwlagn_mac_ampdu_action, - .hw_scan = iwl_mac_hw_scan, + .hw_scan = iwlagn_mac_hw_scan, .sta_notify = iwlagn_mac_sta_notify, .sta_add = iwlagn_mac_sta_add, - .sta_remove = iwl_mac_sta_remove, + .sta_remove = iwlagn_mac_sta_remove, .channel_switch = iwlagn_mac_channel_switch, .flush = iwlagn_mac_flush, - .tx_last_beacon = iwl_mac_tx_last_beacon, - .remain_on_channel = iwl_mac_remain_on_channel, - .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, - .offchannel_tx = iwl_mac_offchannel_tx, - .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait, - .rssi_callback = iwl_mac_rssi_callback, - CFG80211_TESTMODE_CMD(iwl_testmode_cmd) - CFG80211_TESTMODE_DUMP(iwl_testmode_dump) + .tx_last_beacon = iwlagn_mac_tx_last_beacon, + .remain_on_channel = iwlagn_mac_remain_on_channel, + .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel, + .rssi_callback = iwlagn_mac_rssi_callback, + CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd) + CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump) + .tx_sync = iwlagn_mac_tx_sync, + .finish_tx_sync = iwlagn_mac_finish_tx_sync, + .set_tim = iwlagn_mac_set_tim, }; static u32 iwl_hw_detect(struct iwl_priv *priv) { - return iwl_read32(priv, CSR_HW_REV); + return iwl_read32(bus(priv), CSR_HW_REV); } +/* Size of one Rx buffer in host DRAM */ +#define IWL_RX_BUF_SIZE_4K (4 * 1024) +#define IWL_RX_BUF_SIZE_8K (8 * 1024) + static int iwl_set_hw_params(struct iwl_priv *priv) { - priv->hw_params.max_rxq_size = RX_QUEUE_SIZE; - priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG; if (iwlagn_mod_params.amsdu_size_8K) - priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K); + hw_params(priv).rx_page_order = + get_order(IWL_RX_BUF_SIZE_8K); else - priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K); - - priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL; + hw_params(priv).rx_page_order = + get_order(IWL_RX_BUF_SIZE_4K); if (iwlagn_mod_params.disable_11n) priv->cfg->sku &= ~EEPROM_SKU_CAP_11N_ENABLE; + hw_params(priv).num_ampdu_queues = + priv->cfg->base_params->num_of_ampdu_queues; + hw_params(priv).shadow_reg_enable = + priv->cfg->base_params->shadow_reg_enable; + hw_params(priv).sku = priv->cfg->sku; + hw_params(priv).wd_timeout = priv->cfg->base_params->wd_timeout; + /* Device-specific setup */ return priv->cfg->lib->set_hw_params(priv); } -static const u8 iwlagn_bss_ac_to_fifo[] = { - IWL_TX_FIFO_VO, - IWL_TX_FIFO_VI, - IWL_TX_FIFO_BE, - IWL_TX_FIFO_BK, -}; - -static const u8 iwlagn_bss_ac_to_queue[] = { - 0, 1, 2, 3, -}; - -static const u8 iwlagn_pan_ac_to_fifo[] = { - IWL_TX_FIFO_VO_IPAN, - IWL_TX_FIFO_VI_IPAN, - IWL_TX_FIFO_BE_IPAN, - IWL_TX_FIFO_BK_IPAN, -}; - -static const u8 iwlagn_pan_ac_to_queue[] = { - 7, 6, 5, 4, -}; - /* This function both allocates and initializes hw and priv. */ static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg) { @@ -3568,66 +3192,8 @@ out: return hw; } -static void iwl_init_context(struct iwl_priv *priv) -{ - int i; - - /* - * The default context is always valid, - * more may be discovered when firmware - * is loaded. - */ - priv->valid_contexts = BIT(IWL_RXON_CTX_BSS); - - for (i = 0; i < NUM_IWL_RXON_CTX; i++) - priv->contexts[i].ctxid = i; - - priv->contexts[IWL_RXON_CTX_BSS].always_active = true; - priv->contexts[IWL_RXON_CTX_BSS].is_active = true; - priv->contexts[IWL_RXON_CTX_BSS].rxon_cmd = REPLY_RXON; - priv->contexts[IWL_RXON_CTX_BSS].rxon_timing_cmd = REPLY_RXON_TIMING; - priv->contexts[IWL_RXON_CTX_BSS].rxon_assoc_cmd = REPLY_RXON_ASSOC; - priv->contexts[IWL_RXON_CTX_BSS].qos_cmd = REPLY_QOS_PARAM; - priv->contexts[IWL_RXON_CTX_BSS].ap_sta_id = IWL_AP_ID; - priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY; - priv->contexts[IWL_RXON_CTX_BSS].ac_to_fifo = iwlagn_bss_ac_to_fifo; - priv->contexts[IWL_RXON_CTX_BSS].ac_to_queue = iwlagn_bss_ac_to_queue; - priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes = - BIT(NL80211_IFTYPE_ADHOC); - priv->contexts[IWL_RXON_CTX_BSS].interface_modes = - BIT(NL80211_IFTYPE_STATION); - priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP; - priv->contexts[IWL_RXON_CTX_BSS].ibss_devtype = RXON_DEV_TYPE_IBSS; - priv->contexts[IWL_RXON_CTX_BSS].station_devtype = RXON_DEV_TYPE_ESS; - priv->contexts[IWL_RXON_CTX_BSS].unused_devtype = RXON_DEV_TYPE_ESS; - - priv->contexts[IWL_RXON_CTX_PAN].rxon_cmd = REPLY_WIPAN_RXON; - priv->contexts[IWL_RXON_CTX_PAN].rxon_timing_cmd = - REPLY_WIPAN_RXON_TIMING; - priv->contexts[IWL_RXON_CTX_PAN].rxon_assoc_cmd = - REPLY_WIPAN_RXON_ASSOC; - priv->contexts[IWL_RXON_CTX_PAN].qos_cmd = REPLY_WIPAN_QOS_PARAM; - priv->contexts[IWL_RXON_CTX_PAN].ap_sta_id = IWL_AP_ID_PAN; - priv->contexts[IWL_RXON_CTX_PAN].wep_key_cmd = REPLY_WIPAN_WEPKEY; - priv->contexts[IWL_RXON_CTX_PAN].bcast_sta_id = IWLAGN_PAN_BCAST_ID; - priv->contexts[IWL_RXON_CTX_PAN].station_flags = STA_FLG_PAN_STATION; - priv->contexts[IWL_RXON_CTX_PAN].ac_to_fifo = iwlagn_pan_ac_to_fifo; - priv->contexts[IWL_RXON_CTX_PAN].ac_to_queue = iwlagn_pan_ac_to_queue; - priv->contexts[IWL_RXON_CTX_PAN].mcast_queue = IWL_IPAN_MCAST_QUEUE; - priv->contexts[IWL_RXON_CTX_PAN].interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP); -#ifdef CONFIG_IWL_P2P - priv->contexts[IWL_RXON_CTX_PAN].interface_modes |= - BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); -#endif - priv->contexts[IWL_RXON_CTX_PAN].ap_devtype = RXON_DEV_TYPE_CP; - priv->contexts[IWL_RXON_CTX_PAN].station_devtype = RXON_DEV_TYPE_2STA; - priv->contexts[IWL_RXON_CTX_PAN].unused_devtype = RXON_DEV_TYPE_P2P; - - BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); -} - -int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) +int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, + struct iwl_cfg *cfg) { int err = 0; struct iwl_priv *priv; @@ -3645,24 +3211,32 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) } priv = hw->priv; - priv->bus = bus; - bus_set_drv_data(priv->bus, priv); + priv->shrd = &priv->_shrd; + bus->shrd = priv->shrd; + priv->shrd->bus = bus; + priv->shrd->priv = priv; + + priv->shrd->trans = trans_ops->alloc(priv->shrd); + if (priv->shrd->trans == NULL) { + err = -ENOMEM; + goto out_free_traffic_mem; + } /* At this point both hw and priv are allocated. */ - SET_IEEE80211_DEV(hw, priv->bus->dev); + SET_IEEE80211_DEV(hw, bus(priv)->dev); IWL_DEBUG_INFO(priv, "*** LOAD DRIVER ***\n"); priv->cfg = cfg; - priv->inta_mask = CSR_INI_SET_MASK; /* is antenna coupling more than 35dB ? */ priv->bt_ant_couple_ok = - (iwlagn_ant_coupling > IWL_BT_ANTENNA_COUPLING_THRESHOLD) ? - true : false; + (iwlagn_mod_params.ant_coupling > + IWL_BT_ANTENNA_COUPLING_THRESHOLD) ? + true : false; /* enable/disable bt channel inhibition */ - priv->bt_ch_announce = iwlagn_bt_ch_announce; + priv->bt_ch_announce = iwlagn_mod_params.bt_ch_announce; IWL_DEBUG_INFO(priv, "BT channel inhibition is %s\n", (priv->bt_ch_announce) ? "On" : "Off"); @@ -3672,15 +3246,15 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) /* these spin locks will be used in apm_ops.init and EEPROM access * we should init now */ - spin_lock_init(&priv->reg_lock); - spin_lock_init(&priv->lock); + spin_lock_init(&bus(priv)->reg_lock); + spin_lock_init(&priv->shrd->lock); /* * stop and reset the on-board processor just in case it is in a * strange state ... like being left stranded by a primary kernel * and this is now the kdump kernel trying to start up */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + iwl_write32(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); /*********************** * 3. Read REV register @@ -3689,11 +3263,11 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) IWL_INFO(priv, "Detected %s, REV=0x%X\n", priv->cfg->name, hw_rev); - err = iwl_trans_register(&priv->trans, priv); + err = iwl_trans_request_irq(trans(priv)); if (err) - goto out_free_traffic_mem; + goto out_free_trans; - if (trans_prepare_card_hw(&priv->trans)) { + if (iwl_trans_prepare_card_hw(trans(priv))) { err = -EIO; IWL_WARN(priv, "Failed, HW not ready\n"); goto out_free_trans; @@ -3729,9 +3303,6 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) priv->hw->wiphy->n_addresses++; } - /* initialize all valid contexts */ - iwl_init_context(priv); - /************************ * 5. Setup HW constants ************************/ @@ -3764,13 +3335,14 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) iwl_enable_rfkill_int(priv); /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); + if (iwl_read32(bus(priv), + CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &priv->shrd->status); else - set_bit(STATUS_RF_KILL_HW, &priv->status); + set_bit(STATUS_RF_KILL_HW, &priv->shrd->status); wiphy_rfkill_set_hw_state(priv->hw->wiphy, - test_bit(STATUS_RF_KILL_HW, &priv->status)); + test_bit(STATUS_RF_KILL_HW, &priv->shrd->status)); iwl_power_initialize(priv); iwl_tt_initialize(priv); @@ -3784,13 +3356,13 @@ int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg) return 0; out_destroy_workqueue: - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; + destroy_workqueue(priv->shrd->workqueue); + priv->shrd->workqueue = NULL; iwl_uninit_drv(priv); out_free_eeprom: iwl_eeprom_free(priv); out_free_trans: - trans_free(&priv->trans); + iwl_trans_free(trans(priv)); out_free_traffic_mem: iwl_free_traffic_mem(priv); ieee80211_free_hw(priv->hw); @@ -3800,21 +3372,17 @@ out: void __devexit iwl_remove(struct iwl_priv * priv) { - unsigned long flags; - wait_for_completion(&priv->firmware_loading_complete); IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n"); iwl_dbgfs_unregister(priv); - sysfs_remove_group(&priv->bus->dev->kobj, - &iwl_attribute_group); - /* ieee80211_unregister_hw call wil cause iwl_mac_stop to + /* ieee80211_unregister_hw call wil cause iwlagn_mac_stop to * to be called and iwl_down since we are removing the device * we need to set STATUS_EXIT_PENDING bit. */ - set_bit(STATUS_EXIT_PENDING, &priv->status); + set_bit(STATUS_EXIT_PENDING, &priv->shrd->status); iwl_testmode_cleanup(priv); iwl_leds_exit(priv); @@ -3824,40 +3392,26 @@ void __devexit iwl_remove(struct iwl_priv * priv) priv->mac80211_registered = 0; } - /* Reset to low power before unloading driver. */ - iwl_apm_stop(priv); - iwl_tt_exit(priv); - /* make sure we flush any pending irq or - * tasklet for the driver - */ - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - trans_sync_irq(&priv->trans); + /*This will stop the queues, move the device to low power state */ + iwl_trans_stop_device(trans(priv)); iwl_dealloc_ucode(priv); - trans_rx_free(&priv->trans); - trans_tx_free(&priv->trans); - iwl_eeprom_free(priv); /*netif_stop_queue(dev); */ - flush_workqueue(priv->workqueue); + flush_workqueue(priv->shrd->workqueue); - /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes - * priv->workqueue... so we can't take down the workqueue + /* ieee80211_unregister_hw calls iwlagn_mac_stop, which flushes + * priv->shrd->workqueue... so we can't take down the workqueue * until now... */ - destroy_workqueue(priv->workqueue); - priv->workqueue = NULL; + destroy_workqueue(priv->shrd->workqueue); + priv->shrd->workqueue = NULL; iwl_free_traffic_mem(priv); - trans_free(&priv->trans); - - bus_set_drv_data(priv->bus, NULL); + iwl_trans_free(trans(priv)); iwl_uninit_drv(priv); @@ -3906,7 +3460,8 @@ module_exit(iwl_exit); module_init(iwl_init); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR); +module_param_named(debug, iwlagn_mod_params.debug_level, uint, + S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "debug output mask"); #endif @@ -3922,18 +3477,21 @@ MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size"); module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); -module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int, - S_IRUGO); +module_param_named(ucode_alternative, + iwlagn_mod_params.wanted_ucode_alternative, + int, S_IRUGO); MODULE_PARM_DESC(ucode_alternative, "specify ucode alternative to use from ucode file"); -module_param_named(antenna_coupling, iwlagn_ant_coupling, int, S_IRUGO); +module_param_named(antenna_coupling, iwlagn_mod_params.ant_coupling, + int, S_IRUGO); MODULE_PARM_DESC(antenna_coupling, "specify antenna coupling in dB (defualt: 0 dB)"); -module_param_named(bt_ch_inhibition, iwlagn_bt_ch_announce, bool, S_IRUGO); +module_param_named(bt_ch_inhibition, iwlagn_mod_params.bt_ch_announce, + bool, S_IRUGO); MODULE_PARM_DESC(bt_ch_inhibition, - "Disable BT channel inhibition (default: enable)"); + "Enable BT channel inhibition (default: enable)"); module_param_named(plcp_check, iwlagn_mod_params.plcp_check, bool, S_IRUGO); MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); @@ -3979,6 +3537,11 @@ module_param_named(power_level, iwlagn_mod_params.power_level, MODULE_PARM_DESC(power_level, "default power save level (range from 1 - 5, default: 1)"); +module_param_named(auto_agg, iwlagn_mod_params.auto_agg, + bool, S_IRUGO); +MODULE_PARM_DESC(auto_agg, + "enable agg w/o check traffic load (default: enable)"); + /* * For now, keep using power level 1 instead of automatically * adjusting ... diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index d941c4c98e4b..5b936ec1a541 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -65,54 +65,9 @@ #include "iwl-dev.h" -/* configuration for the _agn devices */ -extern struct iwl_cfg iwl5300_agn_cfg; -extern struct iwl_cfg iwl5100_agn_cfg; -extern struct iwl_cfg iwl5350_agn_cfg; -extern struct iwl_cfg iwl5100_bgn_cfg; -extern struct iwl_cfg iwl5100_abg_cfg; -extern struct iwl_cfg iwl5150_agn_cfg; -extern struct iwl_cfg iwl5150_abg_cfg; -extern struct iwl_cfg iwl6005_2agn_cfg; -extern struct iwl_cfg iwl6005_2abg_cfg; -extern struct iwl_cfg iwl6005_2bg_cfg; -extern struct iwl_cfg iwl1030_bgn_cfg; -extern struct iwl_cfg iwl1030_bg_cfg; -extern struct iwl_cfg iwl6030_2agn_cfg; -extern struct iwl_cfg iwl6030_2abg_cfg; -extern struct iwl_cfg iwl6030_2bgn_cfg; -extern struct iwl_cfg iwl6030_2bg_cfg; -extern struct iwl_cfg iwl6000i_2agn_cfg; -extern struct iwl_cfg iwl6000i_2abg_cfg; -extern struct iwl_cfg iwl6000i_2bg_cfg; -extern struct iwl_cfg iwl6000_3agn_cfg; -extern struct iwl_cfg iwl6050_2agn_cfg; -extern struct iwl_cfg iwl6050_2abg_cfg; -extern struct iwl_cfg iwl6150_bgn_cfg; -extern struct iwl_cfg iwl6150_bg_cfg; -extern struct iwl_cfg iwl1000_bgn_cfg; -extern struct iwl_cfg iwl1000_bg_cfg; -extern struct iwl_cfg iwl100_bgn_cfg; -extern struct iwl_cfg iwl100_bg_cfg; -extern struct iwl_cfg iwl130_bgn_cfg; -extern struct iwl_cfg iwl130_bg_cfg; -extern struct iwl_cfg iwl2000_2bgn_cfg; -extern struct iwl_cfg iwl2000_2bg_cfg; -extern struct iwl_cfg iwl2030_2bgn_cfg; -extern struct iwl_cfg iwl2030_2bg_cfg; -extern struct iwl_cfg iwl6035_2agn_cfg; -extern struct iwl_cfg iwl6035_2abg_cfg; -extern struct iwl_cfg iwl6035_2bg_cfg; -extern struct iwl_cfg iwl105_bg_cfg; -extern struct iwl_cfg iwl105_bgn_cfg; -extern struct iwl_cfg iwl135_bg_cfg; -extern struct iwl_cfg iwl135_bgn_cfg; - -extern struct iwl_mod_params iwlagn_mod_params; - extern struct ieee80211_ops iwlagn_hw_ops; -int iwl_reset_ict(struct iwl_priv *priv); +int iwl_reset_ict(struct iwl_trans *trans); static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) { @@ -122,10 +77,6 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd) hdr->data_valid = 1; } -/* tx queue */ -void iwl_free_tfds_in_queue(struct iwl_priv *priv, - int sta_id, int tid, int freed); - /* RXON */ int iwlagn_set_pan_params(struct iwl_priv *priv); int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -137,8 +88,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, u32 changes); /* uCode */ -void iwlagn_rx_calib_result(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); +int iwlagn_rx_calib_result(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type); void iwlagn_send_prio_tbl(struct iwl_priv *priv); int iwlagn_run_init_ucode(struct iwl_priv *priv); @@ -147,13 +99,9 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv, enum iwlagn_ucode_type ucode_type); /* lib */ -void iwl_check_abort_status(struct iwl_priv *priv, - u8 frame_count, u32 status); -int iwlagn_hw_valid_rtc_data_addr(u32 addr); int iwlagn_send_tx_power(struct iwl_priv *priv); void iwlagn_temperature(struct iwl_priv *priv); u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv); -int iwlagn_wait_tx_queue_empty(struct iwl_priv *priv); int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control); void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control); int iwlagn_send_beacon_cmd(struct iwl_priv *priv); @@ -161,25 +109,19 @@ int iwlagn_send_beacon_cmd(struct iwl_priv *priv); /* rx */ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); void iwl_setup_rx_handlers(struct iwl_priv *priv); -void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); /* tx */ -void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int index); -void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_info *info); int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn); int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid); -int iwlagn_txq_check_empty(struct iwl_priv *priv, - int sta_id, u8 tid, int txq_id); -void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); -void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); +int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); +int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); static inline u32 iwl_tx_status_to_mac80211(u32 status) { @@ -207,17 +149,14 @@ static inline bool iwl_is_tx_success(u32 status) u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid); /* scan */ -int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif); void iwlagn_post_scan(struct iwl_priv *priv); - -/* station mgmt */ -int iwlagn_manage_ibss_station(struct iwl_priv *priv, - struct ieee80211_vif *vif, bool add); +void iwlagn_disable_roc(struct iwl_priv *priv); /* bt coex */ void iwlagn_send_advance_bt_config(struct iwl_priv *priv); -void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); +int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv); void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv); void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv); @@ -232,7 +171,120 @@ static inline const char *iwl_get_tx_fail_reason(u32 status) { return ""; } static inline const char *iwl_get_agg_tx_fail_reason(u16 status) { return ""; } #endif + /* station management */ +int iwlagn_manage_ibss_station(struct iwl_priv *priv, + struct ieee80211_vif *vif, bool add); +#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ +#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ +#define IWL_STA_UCODE_INPROGRESS BIT(2) /* ucode entry is in process of + being activated */ +#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211; + (this is for the IBSS BSSID stations) */ +#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */ + + +void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx); +void iwl_clear_ucode_stations(struct iwl_priv *priv, + struct iwl_rxon_context *ctx); +void iwl_dealloc_bcast_stations(struct iwl_priv *priv); +int iwl_get_free_ucode_key_offset(struct iwl_priv *priv); +int iwl_send_add_sta(struct iwl_priv *priv, + struct iwl_addsta_cmd *sta, u8 flags); +int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + const u8 *addr, bool is_ap, + struct ieee80211_sta *sta, u8 *sta_id_r); +int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, + const u8 *addr); +int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + +u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + const u8 *addr, bool is_ap, struct ieee80211_sta *sta); + +void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + u8 sta_id, struct iwl_link_quality_cmd *link_cmd); +int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, + struct iwl_link_quality_cmd *lq, u8 flags, bool init); +void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx); +int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); + + +/** + * iwl_clear_driver_stations - clear knowledge of all stations from driver + * @priv: iwl priv struct + * + * This is called during iwl_down() to make sure that in the case + * we're coming there from a hardware restart mac80211 will be + * able to reconfigure stations -- if we're getting there in the + * normal down flow then the stations will already be cleared. + */ +static inline void iwl_clear_driver_stations(struct iwl_priv *priv) +{ + unsigned long flags; + struct iwl_rxon_context *ctx; + + spin_lock_irqsave(&priv->shrd->sta_lock, flags); + memset(priv->stations, 0, sizeof(priv->stations)); + priv->num_stations = 0; + + priv->ucode_key_table = 0; + + for_each_context(priv, ctx) { + /* + * Remove all key information that is not stored as part + * of station information since mac80211 may not have had + * a chance to remove all the keys. When device is + * reconfigured by mac80211 after an error all keys will + * be reconfigured. + */ + memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys)); + ctx->key_mapping_keys = 0; + } + + spin_unlock_irqrestore(&priv->shrd->sta_lock, flags); +} + +static inline int iwl_sta_id(struct ieee80211_sta *sta) +{ + if (WARN_ON(!sta)) + return IWL_INVALID_STATION; + + return ((struct iwl_station_priv *)sta->drv_priv)->sta_id; +} + +/** + * iwl_sta_id_or_broadcast - return sta_id or broadcast sta + * @priv: iwl priv + * @context: the current context + * @sta: mac80211 station + * + * In certain circumstances mac80211 passes a station pointer + * that may be %NULL, for example during TX or key setup. In + * that case, we need to use the broadcast station, so this + * inline wraps that pattern. + */ +static inline int iwl_sta_id_or_broadcast(struct iwl_priv *priv, + struct iwl_rxon_context *context, + struct ieee80211_sta *sta) +{ + int sta_id; + + if (!sta) + return context->bcast_sta_id; + + sta_id = iwl_sta_id(sta); + + /* + * mac80211 should not be passing a partially + * initialised station! + */ + WARN_ON(sta_id == IWL_INVALID_STATION); + + return sta_id; +} + int iwlagn_alloc_bcast_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx); int iwlagn_add_bssid_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, @@ -286,7 +338,7 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags) } /* eeprom */ -void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv); +void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv); void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac); /* notification wait support */ @@ -309,20 +361,22 @@ extern int iwlagn_init_alive_start(struct iwl_priv *priv); extern int iwl_alive_start(struct iwl_priv *priv); /* svtool */ #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL -extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len); -extern int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, - struct netlink_callback *cb, - void *data, int len); +extern int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, + int len); +extern int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct netlink_callback *cb, + void *data, int len); extern void iwl_testmode_init(struct iwl_priv *priv); extern void iwl_testmode_cleanup(struct iwl_priv *priv); #else static inline -int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) { return -ENOSYS; } static inline -int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, +int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, struct netlink_callback *cb, void *data, int len) { diff --git a/drivers/net/wireless/iwlwifi/iwl-bus.h b/drivers/net/wireless/iwlwifi/iwl-bus.h index f3ee1c0c004c..08b97594e305 100644 --- a/drivers/net/wireless/iwlwifi/iwl-bus.h +++ b/drivers/net/wireless/iwlwifi/iwl-bus.h @@ -60,16 +60,68 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ -#ifndef __iwl_pci_h__ -#define __iwl_pci_h__ +#ifndef __iwl_bus_h__ +#define __iwl_bus_h__ +#include <linux/types.h> +#include <linux/spinlock.h> + +/** + * DOC: Bus layer - role and goal + * + * iwl-bus.h defines the API to the bus layer of the iwlwifi driver. + * The bus layer is responsible for doing very basic bus operations that are + * listed in the iwl_bus_ops structure. + * The bus layer registers to the bus driver, advertises the supported HW and + * gets notifications about enumeration, suspend, resume. + * For the moment, the bus layer is not a linux kernel module as itself, and + * the module_init function of the driver must call the bus specific + * registration functions. These functions are listed at the end of this file. + * For the moment, there is only one implementation of this interface: PCI-e. + * This implementation is iwl-pci.c + */ + +/** + * DOC: encapsulation and type safety + * + * The iwl_bus describes the data that is shared amongst all the bus layer + * implementations. This data is visible to other layers. Data in the bus + * specific area is not visible outside the bus specific implementation. + * iwl_bus holds a pointer to iwl_shared which holds pointer to all the other + * layers of the driver (iwl_priv, iwl_trans). In fact, this is the way to go + * when the transport layer needs to call a function of another layer. + * + * In order to achieve encapsulation, iwl_priv cannot be dereferenced from the + * bus layer. Type safety is still kept since functions that gets iwl_priv gets + * a typed pointer (as opposed to void *). + */ + +/** + * DOC: probe flow + * + * The module_init calls the bus specific registration function. The + * registration to the bus layer will trigger an enumeration of the bus which + * will call the bus specific probe function. + * The first thing this function must do is to allocate the memory needed by + * iwl_bus + the bus_specific data. + * Once the bus specific probe function has configured the hardware, it + * chooses the appropriate transport layer and calls iwl_probe that will run + * the bus independent probe flow. + * + * Note: The bus specific code must set the following data in iwl_bus before it + * calls iwl_probe: + * * bus->dev + * * bus->irq + * * bus->ops + */ + +struct iwl_shared; struct iwl_bus; /** * struct iwl_bus_ops - bus specific operations * @get_pm_support: must returns true if the bus can go to sleep - * @apm_config: will be called during the config of the APM configuration - * @set_drv_data: set the drv_data pointer to the bus layer + * @apm_config: will be called during the config of the APM * @get_hw_id: prints the hw_id in the provided buffer * @write8: write a byte to register at offset ofs * @write32: write a dword to register at offset ofs @@ -78,20 +130,32 @@ struct iwl_bus; struct iwl_bus_ops { bool (*get_pm_support)(struct iwl_bus *bus); void (*apm_config)(struct iwl_bus *bus); - void (*set_drv_data)(struct iwl_bus *bus, void *drv_data); void (*get_hw_id)(struct iwl_bus *bus, char buf[], int buf_len); void (*write8)(struct iwl_bus *bus, u32 ofs, u8 val); void (*write32)(struct iwl_bus *bus, u32 ofs, u32 val); u32 (*read32)(struct iwl_bus *bus, u32 ofs); }; +/** + * struct iwl_bus - bus common data + * + * This data is common to all bus layer implementations. + * + * @dev - pointer to struct device * that represents the device + * @ops - pointer to iwl_bus_ops + * @shrd - pointer to iwl_shared which holds shared data from the upper layer + * NB: for the time being this needs to be set by the upper layer since + * it allocates the shared data + * @irq - the irq number for the device + * @reg_lock - protect hw register access + */ struct iwl_bus { - /* Common data to all buses */ - void *drv_data; /* driver's context */ struct device *dev; - struct iwl_bus_ops *ops; + const struct iwl_bus_ops *ops; + struct iwl_shared *shrd; unsigned int irq; + spinlock_t reg_lock; /* pointer to bus specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ @@ -108,11 +172,6 @@ static inline void bus_apm_config(struct iwl_bus *bus) bus->ops->apm_config(bus); } -static inline void bus_set_drv_data(struct iwl_bus *bus, void *drv_data) -{ - bus->ops->set_drv_data(bus, drv_data); -} - static inline void bus_get_hw_id(struct iwl_bus *bus, char buf[], int buf_len) { bus->ops->get_hw_id(bus, buf, buf_len); @@ -133,7 +192,10 @@ static inline u32 bus_read32(struct iwl_bus *bus, u32 ofs) return bus->ops->read32(bus, ofs); } +/***************************************************** +* Bus layer registration functions +******************************************************/ int __must_check iwl_pci_register_driver(void); void iwl_pci_unregister_driver(void); -#endif +#endif /* __iwl_bus_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-cfg.h index f9630a3c79fe..2a2dc4597ba1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-cfg.h @@ -60,29 +60,58 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ -/* - * Please use this file (iwl-5000-hw.h) only for hardware-related definitions. - * Use iwl-commands.h for uCode API definitions. - */ - -#ifndef __iwl_5000_hw_h__ -#define __iwl_5000_hw_h__ - -/* 5150 only */ -#define IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF (-5) +#ifndef __iwl_pci_h__ +#define __iwl_pci_h__ -static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv) -{ - u16 temperature, voltage; - __le16 *temp_calib = - (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_TEMPERATURE); - temperature = le16_to_cpu(temp_calib[0]); - voltage = le16_to_cpu(temp_calib[1]); - - /* offset = temp - volt / coeff */ - return (s32)(temperature - voltage / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF); -} +/* + * This file declares the config structures for all devices. + */ -#endif /* __iwl_5000_hw_h__ */ +extern struct iwl_cfg iwl5300_agn_cfg; +extern struct iwl_cfg iwl5100_agn_cfg; +extern struct iwl_cfg iwl5350_agn_cfg; +extern struct iwl_cfg iwl5100_bgn_cfg; +extern struct iwl_cfg iwl5100_abg_cfg; +extern struct iwl_cfg iwl5150_agn_cfg; +extern struct iwl_cfg iwl5150_abg_cfg; +extern struct iwl_cfg iwl6005_2agn_cfg; +extern struct iwl_cfg iwl6005_2abg_cfg; +extern struct iwl_cfg iwl6005_2bg_cfg; +extern struct iwl_cfg iwl6005_2agn_sff_cfg; +extern struct iwl_cfg iwl6005_2agn_d_cfg; +extern struct iwl_cfg iwl1030_bgn_cfg; +extern struct iwl_cfg iwl1030_bg_cfg; +extern struct iwl_cfg iwl6030_2agn_cfg; +extern struct iwl_cfg iwl6030_2abg_cfg; +extern struct iwl_cfg iwl6030_2bgn_cfg; +extern struct iwl_cfg iwl6030_2bg_cfg; +extern struct iwl_cfg iwl6000i_2agn_cfg; +extern struct iwl_cfg iwl6000i_2abg_cfg; +extern struct iwl_cfg iwl6000i_2bg_cfg; +extern struct iwl_cfg iwl6000_3agn_cfg; +extern struct iwl_cfg iwl6050_2agn_cfg; +extern struct iwl_cfg iwl6050_2abg_cfg; +extern struct iwl_cfg iwl6150_bgn_cfg; +extern struct iwl_cfg iwl6150_bg_cfg; +extern struct iwl_cfg iwl1000_bgn_cfg; +extern struct iwl_cfg iwl1000_bg_cfg; +extern struct iwl_cfg iwl100_bgn_cfg; +extern struct iwl_cfg iwl100_bg_cfg; +extern struct iwl_cfg iwl130_bgn_cfg; +extern struct iwl_cfg iwl130_bg_cfg; +extern struct iwl_cfg iwl2000_2bgn_cfg; +extern struct iwl_cfg iwl2000_2bg_cfg; +extern struct iwl_cfg iwl2000_2bgn_d_cfg; +extern struct iwl_cfg iwl2030_2bgn_cfg; +extern struct iwl_cfg iwl2030_2bg_cfg; +extern struct iwl_cfg iwl6035_2agn_cfg; +extern struct iwl_cfg iwl6035_2abg_cfg; +extern struct iwl_cfg iwl6035_2bg_cfg; +extern struct iwl_cfg iwl105_bg_cfg; +extern struct iwl_cfg iwl105_bgn_cfg; +extern struct iwl_cfg iwl105_bgn_d_cfg; +extern struct iwl_cfg iwl135_bg_cfg; +extern struct iwl_cfg iwl135_bgn_cfg; +#endif /* __iwl_pci_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index e9e9d1d1778d..69d5f85d11e2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -69,6 +69,9 @@ #ifndef __iwl_commands_h__ #define __iwl_commands_h__ +#include <linux/etherdevice.h> +#include <linux/ieee80211.h> + struct iwl_priv; /* uCode version contains 4 values: Major/Minor/API/Serial */ @@ -86,6 +89,7 @@ struct iwl_priv; enum { REPLY_ALIVE = 0x1, REPLY_ERROR = 0x2, + REPLY_ECHO = 0x3, /* test command */ /* RXON and QOS commands */ REPLY_RXON = 0x10, @@ -670,7 +674,6 @@ struct iwl_rxon_assoc_cmd { #define IWL_CONN_MAX_LISTEN_INTERVAL 10 #define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */ -#define IWL39_MAX_UCODE_BEACON_INTERVAL 1 /* 1024 */ /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) @@ -806,6 +809,7 @@ struct iwl_qosparam_cmd { #define IWLAGN_STATION_COUNT 16 #define IWL_INVALID_STATION 255 +#define IWL_MAX_TID_COUNT 9 #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) #define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8) @@ -3067,17 +3071,29 @@ struct iwl_missed_beacon_notif { /* number of additional entries for enhanced tbl */ #define ENHANCE_HD_TABLE_ENTRIES (ENHANCE_HD_TABLE_SIZE - HD_TABLE_SIZE) -#define HD_INA_NON_SQUARE_DET_OFDM_DATA cpu_to_le16(0) -#define HD_INA_NON_SQUARE_DET_CCK_DATA cpu_to_le16(0) -#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA cpu_to_le16(0) -#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(668) -#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4) -#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(486) -#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(37) -#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA cpu_to_le16(853) -#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA cpu_to_le16(4) -#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA cpu_to_le16(476) -#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA cpu_to_le16(99) +#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V1 cpu_to_le16(0) +#define HD_INA_NON_SQUARE_DET_CCK_DATA_V1 cpu_to_le16(0) +#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V1 cpu_to_le16(0) +#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V1 cpu_to_le16(668) +#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1 cpu_to_le16(4) +#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V1 cpu_to_le16(486) +#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V1 cpu_to_le16(37) +#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V1 cpu_to_le16(853) +#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V1 cpu_to_le16(4) +#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V1 cpu_to_le16(476) +#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V1 cpu_to_le16(99) + +#define HD_INA_NON_SQUARE_DET_OFDM_DATA_V2 cpu_to_le16(1) +#define HD_INA_NON_SQUARE_DET_CCK_DATA_V2 cpu_to_le16(1) +#define HD_CORR_11_INSTEAD_OF_CORR_9_EN_DATA_V2 cpu_to_le16(1) +#define HD_OFDM_NON_SQUARE_DET_SLOPE_MRC_DATA_V2 cpu_to_le16(600) +#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2 cpu_to_le16(40) +#define HD_OFDM_NON_SQUARE_DET_SLOPE_DATA_V2 cpu_to_le16(486) +#define HD_OFDM_NON_SQUARE_DET_INTERCEPT_DATA_V2 cpu_to_le16(45) +#define HD_CCK_NON_SQUARE_DET_SLOPE_MRC_DATA_V2 cpu_to_le16(853) +#define HD_CCK_NON_SQUARE_DET_INTERCEPT_MRC_DATA_V2 cpu_to_le16(60) +#define HD_CCK_NON_SQUARE_DET_SLOPE_DATA_V2 cpu_to_le16(476) +#define HD_CCK_NON_SQUARE_DET_INTERCEPT_DATA_V2 cpu_to_le16(99) /* Control field in struct iwl_sensitivity_cmd */ @@ -3198,12 +3214,17 @@ enum iwl_ucode_calib_cfg { IWL_CALIB_CFG_LO_IDX | \ IWL_CALIB_CFG_TX_IQ_IDX | \ IWL_CALIB_CFG_RX_IQ_IDX | \ - IWL_CALIB_CFG_NOISE_IDX | \ - IWL_CALIB_CFG_CRYSTAL_IDX | \ + IWL_CALIB_CFG_CRYSTAL_IDX) + +#define IWL_CALIB_RT_CFG_ALL cpu_to_le32(IWL_CALIB_CFG_RX_BB_IDX | \ + IWL_CALIB_CFG_DC_IDX | \ + IWL_CALIB_CFG_LO_IDX | \ + IWL_CALIB_CFG_TX_IQ_IDX | \ + IWL_CALIB_CFG_RX_IQ_IDX | \ IWL_CALIB_CFG_TEMPERATURE_IDX | \ IWL_CALIB_CFG_PAPD_IDX | \ - IWL_CALIB_CFG_SENSITIVITY_IDX | \ - IWL_CALIB_CFG_TX_PWR_IDX) + IWL_CALIB_CFG_TX_PWR_IDX | \ + IWL_CALIB_CFG_CRYSTAL_IDX) #define IWL_CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_MSK cpu_to_le32(BIT(0)) @@ -3253,6 +3274,14 @@ struct iwl_calib_temperature_offset_cmd { __le16 reserved; } __packed; +struct iwl_calib_temperature_offset_v2_cmd { + struct iwl_calib_hdr hdr; + __le16 radio_sensor_offset_high; + __le16 radio_sensor_offset_low; + __le16 burntVoltageRef; + __le16 reserved; +} __packed; + /* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ struct iwl_calib_chain_noise_reset_cmd { struct iwl_calib_hdr hdr; @@ -3897,6 +3926,7 @@ struct iwlagn_wowlan_kek_kck_material_cmd { * Union of all expected notifications/responses: * *****************************************************************************/ +#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ struct iwl_rx_packet { /* diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index cf376f62b2f6..b247a56d5135 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -34,29 +34,26 @@ #include <net/mac80211.h> #include "iwl-eeprom.h" -#include "iwl-dev.h" /* FIXME: remove */ #include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-power.h" -#include "iwl-sta.h" -#include "iwl-helpers.h" +#include "iwl-agn.h" +#include "iwl-shared.h" #include "iwl-agn.h" #include "iwl-trans.h" -u32 iwl_debug_level; - const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; #define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ #define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ -static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, +static void iwl_init_ht_hw_capab(const struct iwl_priv *priv, struct ieee80211_sta_ht_cap *ht_info, enum ieee80211_band band) { u16 max_bit_rate = 0; - u8 rx_chains_num = priv->hw_params.rx_chains_num; - u8 tx_chains_num = priv->hw_params.tx_chains_num; + u8 rx_chains_num = hw_params(priv).rx_chains_num; + u8 tx_chains_num = hw_params(priv).tx_chains_num; ht_info->cap = 0; memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); @@ -68,7 +65,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; ht_info->cap |= IEEE80211_HT_CAP_SGI_20; max_bit_rate = MAX_BIT_RATE_20_MHZ; - if (priv->hw_params.ht40_channel & BIT(band)) { + if (hw_params(priv).ht40_channel & BIT(band)) { ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; ht_info->cap |= IEEE80211_HT_CAP_SGI_40; ht_info->mcs.rx_mask[4] = 0x01; @@ -106,9 +103,9 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, } /** - * iwlcore_init_geos - Initialize mac80211's geo/channel info based from eeprom + * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom */ -int iwlcore_init_geos(struct iwl_priv *priv) +int iwl_init_geos(struct iwl_priv *priv) { struct iwl_channel_info *ch; struct ieee80211_supported_band *sband; @@ -121,16 +118,16 @@ int iwlcore_init_geos(struct iwl_priv *priv) if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { IWL_DEBUG_INFO(priv, "Geography modes already initialized.\n"); - set_bit(STATUS_GEO_CONFIGURED, &priv->status); + set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status); return 0; } - channels = kzalloc(sizeof(struct ieee80211_channel) * - priv->channel_count, GFP_KERNEL); + channels = kcalloc(priv->channel_count, + sizeof(struct ieee80211_channel), GFP_KERNEL); if (!channels) return -ENOMEM; - rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY), + rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate), GFP_KERNEL); if (!rates) { kfree(channels); @@ -145,7 +142,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) sband->n_bitrates = IWL_RATE_COUNT_LEGACY - IWL_FIRST_OFDM_RATE; if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) - iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, + iwl_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_5GHZ); sband = &priv->bands[IEEE80211_BAND_2GHZ]; @@ -155,7 +152,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) sband->n_bitrates = IWL_RATE_COUNT_LEGACY; if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE) - iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, + iwl_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_2GHZ); priv->ieee_channels = channels; @@ -211,7 +208,7 @@ int iwlcore_init_geos(struct iwl_priv *priv) if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->cfg->sku & EEPROM_SKU_CAP_BAND_52GHZ) { char buf[32]; - bus_get_hw_id(priv->bus, buf, sizeof(buf)); + bus_get_hw_id(bus(priv), buf, sizeof(buf)); IWL_INFO(priv, "Incorrectly detected BG card as ABG. " "Please send your %s to maintainer.\n", buf); priv->cfg->sku &= ~EEPROM_SKU_CAP_BAND_52GHZ; @@ -221,19 +218,19 @@ int iwlcore_init_geos(struct iwl_priv *priv) priv->bands[IEEE80211_BAND_2GHZ].n_channels, priv->bands[IEEE80211_BAND_5GHZ].n_channels); - set_bit(STATUS_GEO_CONFIGURED, &priv->status); + set_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status); return 0; } /* - * iwlcore_free_geos - undo allocations in iwlcore_init_geos + * iwl_free_geos - undo allocations in iwl_init_geos */ -void iwlcore_free_geos(struct iwl_priv *priv) +void iwl_free_geos(struct iwl_priv *priv) { kfree(priv->ieee_channels); kfree(priv->ieee_rates); - clear_bit(STATUS_GEO_CONFIGURED, &priv->status); + clear_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status); } static bool iwl_is_channel_extension(struct iwl_priv *priv, @@ -323,9 +320,9 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx) u16 beacon_int; struct ieee80211_vif *vif = ctx->vif; - conf = ieee80211_get_hw_conf(priv->hw); + conf = &priv->hw->conf; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); memset(&ctx->timing, 0, sizeof(struct iwl_rxon_time_cmd)); @@ -359,7 +356,7 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx) beacon_int = le16_to_cpu(ctx->timing.beacon_interval); } else { beacon_int = iwl_adjust_beacon_interval(beacon_int, - priv->hw_params.max_beacon_itrvl * TIME_UNIT); + IWL_MAX_UCODE_BEACON_INTERVAL * TIME_UNIT); ctx->timing.beacon_interval = cpu_to_le16(beacon_int); } @@ -378,7 +375,7 @@ int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx) le32_to_cpu(ctx->timing.beacon_init_val), le16_to_cpu(ctx->timing.atim_window)); - return trans_send_cmd_pdu(&priv->trans, ctx->rxon_timing_cmd, + return iwl_trans_send_cmd_pdu(trans(priv), ctx->rxon_timing_cmd, CMD_SYNC, sizeof(ctx->timing), &ctx->timing); } @@ -804,21 +801,23 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success) { /* * MULTI-FIXME - * See iwl_mac_channel_switch. + * See iwlagn_mac_channel_switch. */ struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; - if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) + if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, + &priv->shrd->status)) ieee80211_chswitch_done(ctx->vif, is_success); } #ifdef CONFIG_IWLWIFI_DEBUG void iwl_print_rx_config_cmd(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) + enum iwl_rxon_context_id ctxid) { + struct iwl_rxon_context *ctx = &priv->contexts[ctxid]; struct iwl_rxon_cmd *rxon = &ctx->staging; IWL_DEBUG_RADIO(priv, "RX CONFIG:\n"); @@ -856,18 +855,18 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) unsigned long reload_jiffies; /* Set the FW error flag -- cleared on iwl_down */ - set_bit(STATUS_FW_ERROR, &priv->status); + set_bit(STATUS_FW_ERROR, &priv->shrd->status); /* Cancel currently queued command. */ - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); + clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status); iwlagn_abort_notification_waits(priv); /* Keep the restart process from trying to send host * commands by clearing the ready bit */ - clear_bit(STATUS_READY, &priv->status); + clear_bit(STATUS_READY, &priv->shrd->status); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->shrd->wait_command_queue); if (!ondemand) { /* @@ -890,63 +889,26 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) priv->reload_count = 0; } - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) { + if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) { if (iwlagn_mod_params.restart_fw) { - IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + IWL_DEBUG_FW_ERRORS(priv, "Restarting adapter due to uCode error.\n"); - queue_work(priv->workqueue, &priv->restart); + queue_work(priv->shrd->workqueue, &priv->restart); } else - IWL_DEBUG(priv, IWL_DL_FW_ERRORS, + IWL_DEBUG_FW_ERRORS(priv, "Detected FW error, but not restarting\n"); } } -/** - * iwl_irq_handle_error - called for HW or SW error interrupt from card - */ -void iwl_irq_handle_error(struct iwl_priv *priv) -{ - /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ - if (priv->cfg->internal_wimax_coex && - (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & - APMS_CLK_VAL_MRB_FUNC_MODE) || - (iwl_read_prph(priv, APMG_PS_CTRL_REG) & - APMG_PS_CTRL_VAL_RESET_REQ))) { - /* - * Keep the restart process from trying to send host - * commands by clearing the ready bit. - */ - clear_bit(STATUS_READY, &priv->status); - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); - IWL_ERR(priv, "RF is used by WiMAX\n"); - return; - } - - IWL_ERR(priv, "Loaded firmware version: %s\n", - priv->hw->wiphy->fw_version); - - iwl_dump_nic_error_log(priv); - iwl_dump_csr(priv); - iwl_dump_fh(priv, NULL, false); - iwl_dump_nic_event_log(priv, false, NULL, false); -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS) - iwl_print_rx_config_cmd(priv, - &priv->contexts[IWL_RXON_CTX_BSS]); -#endif - - iwlagn_fw_error(priv, false); -} - static int iwl_apm_stop_master(struct iwl_priv *priv) { int ret = 0; /* stop device's busmaster DMA activity */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + iwl_set_bit(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, + ret = iwl_poll_bit(bus(priv), CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (ret) IWL_WARN(priv, "Master Disable Timed Out, 100 usec\n"); @@ -960,13 +922,13 @@ void iwl_apm_stop(struct iwl_priv *priv) { IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n"); - clear_bit(STATUS_DEVICE_ENABLED, &priv->status); + clear_bit(STATUS_DEVICE_ENABLED, &priv->shrd->status); /* Stop device's DMA activity */ iwl_apm_stop_master(priv); /* Reset the entire device */ - iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_set_bit(bus(priv), CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); udelay(10); @@ -974,7 +936,7 @@ void iwl_apm_stop(struct iwl_priv *priv) * Clear "initialization complete" bit to move adapter from * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_clear_bit(bus(priv), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } @@ -994,45 +956,45 @@ int iwl_apm_init(struct iwl_priv *priv) */ /* Disable L0S exit timer (platform NMI Work/Around) */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + iwl_set_bit(bus(priv), CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); /* * Disable L0s without affecting L1; * don't wait for ICH L0s (ICH bug W/A) */ - iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, + iwl_set_bit(bus(priv), CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); /* Set FH wait threshold to maximum (HW error during stress W/A) */ - iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + iwl_set_bit(bus(priv), CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A); - bus_apm_config(priv->bus); + bus_apm_config(bus(priv)); /* Configure analog phase-lock-loop before activating to D0A */ if (priv->cfg->base_params->pll_cfg_val) - iwl_set_bit(priv, CSR_ANA_PLL_CFG, + iwl_set_bit(bus(priv), CSR_ANA_PLL_CFG, priv->cfg->base_params->pll_cfg_val); /* * Set "initialization complete" bit to move adapter from * D0U* --> D0A* (powered-up active) state. */ - iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_set_bit(bus(priv), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* * Wait for clock stabilization; once stabilized, access to * device-internal resources is supported, e.g. iwl_write_prph() * and accesses to uCode SRAM. */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { @@ -1047,14 +1009,14 @@ int iwl_apm_init(struct iwl_priv *priv) * do not disable clocks. This preserves any hardware bits already * set by default in "CLK_CTRL_REG" after reset. */ - iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); + iwl_write_prph(bus(priv), APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT); udelay(20); /* Disable L1-Active */ - iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG, + iwl_set_bits_prph(bus(priv), APMG_PCIDEV_STT_REG, APMG_PCIDEV_STT_VAL_L1_ACT_DIS); - set_bit(STATUS_DEVICE_ENABLED, &priv->status); + set_bit(STATUS_DEVICE_ENABLED, &priv->shrd->status); out: return ret; @@ -1068,7 +1030,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) bool defer; struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); if (priv->tx_power_user_lmt == tx_power && !force) return 0; @@ -1088,7 +1050,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) return -EINVAL; } - if (!iwl_is_ready_rf(priv)) + if (!iwl_is_ready_rf(priv->shrd)) return -EIO; /* scan complete and commit_rxon use tx_power_next value, @@ -1096,7 +1058,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force) priv->tx_power_next = tx_power; /* do not set tx power when scanning or channel changing */ - defer = test_bit(STATUS_SCANNING, &priv->status) || + defer = test_bit(STATUS_SCANNING, &priv->shrd->status) || memcmp(&ctx->active, &ctx->staging, sizeof(ctx->staging)); if (defer && !force) { IWL_DEBUG_INFO(priv, "Deferring tx power set\n"); @@ -1134,7 +1096,7 @@ void iwl_send_bt_config(struct iwl_priv *priv) IWL_DEBUG_INFO(priv, "BT coex %s\n", (bt_cmd.flags == BT_COEX_DISABLE) ? "disable" : "active"); - if (trans_send_cmd_pdu(&priv->trans, REPLY_BT_CONFIG, + if (iwl_trans_send_cmd_pdu(trans(priv), REPLY_BT_CONFIG, CMD_SYNC, sizeof(struct iwl_bt_cmd), &bt_cmd)) IWL_ERR(priv, "failed to send BT Coex Config\n"); } @@ -1147,24 +1109,20 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear) }; if (flags & CMD_ASYNC) - return trans_send_cmd_pdu(&priv->trans, REPLY_STATISTICS_CMD, + return iwl_trans_send_cmd_pdu(trans(priv), REPLY_STATISTICS_CMD, CMD_ASYNC, sizeof(struct iwl_statistics_cmd), &statistics_cmd); else - return trans_send_cmd_pdu(&priv->trans, REPLY_STATISTICS_CMD, + return iwl_trans_send_cmd_pdu(trans(priv), REPLY_STATISTICS_CMD, CMD_SYNC, sizeof(struct iwl_statistics_cmd), &statistics_cmd); } -void iwl_clear_isr_stats(struct iwl_priv *priv) -{ - memset(&priv->isr_stats, 0, sizeof(priv->isr_stats)); -} - -int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, - const struct ieee80211_tx_queue_params *params) +int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, + const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx; @@ -1173,7 +1131,7 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, IWL_DEBUG_MAC80211(priv, "enter\n"); - if (!iwl_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv->shrd)) { IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n"); return -EIO; } @@ -1185,7 +1143,7 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, q = AC_NUM - 1 - queue; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->shrd->lock, flags); /* * MULTI-FIXME @@ -1203,13 +1161,13 @@ int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0; } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&priv->shrd->lock, flags); IWL_DEBUG_MAC80211(priv, "leave\n"); return 0; } -int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw) +int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -1231,7 +1189,7 @@ static int iwl_setup_interface(struct iwl_priv *priv, struct ieee80211_vif *vif = ctx->vif; int err; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); /* * This variable will be correct only when there's just @@ -1262,7 +1220,8 @@ static int iwl_setup_interface(struct iwl_priv *priv, return 0; } -int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +int iwlagn_mac_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; @@ -1273,9 +1232,13 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n", viftype, vif->addr); - mutex_lock(&priv->mutex); + cancel_delayed_work_sync(&priv->hw_roc_disable_work); + + mutex_lock(&priv->shrd->mutex); + + iwlagn_disable_roc(priv); - if (!iwl_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv->shrd)) { IWL_WARN(priv, "Try to add interface when device not ready\n"); err = -EINVAL; goto out; @@ -1318,7 +1281,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) ctx->vif = NULL; priv->iw_mode = NL80211_IFTYPE_STATION; out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); return err; @@ -1330,7 +1293,7 @@ static void iwl_teardown_interface(struct iwl_priv *priv, { struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); if (priv->scan_vif == vif) { iwl_scan_cancel_timeout(priv, 200); @@ -1354,7 +1317,7 @@ static void iwl_teardown_interface(struct iwl_priv *priv, priv->bt_traffic_load = priv->last_bt_traffic_load; } -void iwl_mac_remove_interface(struct ieee80211_hw *hw, +void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct iwl_priv *priv = hw->priv; @@ -1362,14 +1325,20 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "enter\n"); - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); - WARN_ON(ctx->vif != vif); + if (WARN_ON(ctx->vif != vif)) { + struct iwl_rxon_context *tmp; + IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif); + for_each_context(priv, tmp) + IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n", + tmp->ctxid, tmp, tmp->vif); + } ctx->vif = NULL; iwl_teardown_interface(priv, vif, false); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); IWL_DEBUG_MAC80211(priv, "leave\n"); @@ -1393,7 +1362,7 @@ int iwl_alloc_traffic_mem(struct iwl_priv *priv) { u32 traffic_size = IWL_TRAFFIC_DUMP_SIZE; - if (iwl_debug_level & IWL_DL_TX) { + if (iwl_get_debug_level(priv->shrd) & IWL_DL_TX) { if (!priv->tx_traffic) { priv->tx_traffic = kzalloc(traffic_size, GFP_KERNEL); @@ -1401,7 +1370,7 @@ int iwl_alloc_traffic_mem(struct iwl_priv *priv) return -ENOMEM; } } - if (iwl_debug_level & IWL_DL_RX) { + if (iwl_get_debug_level(priv->shrd) & IWL_DL_RX) { if (!priv->rx_traffic) { priv->rx_traffic = kzalloc(traffic_size, GFP_KERNEL); @@ -1428,7 +1397,7 @@ void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, __le16 fc; u16 len; - if (likely(!(iwl_debug_level & IWL_DL_TX))) + if (likely(!(iwl_get_debug_level(priv->shrd) & IWL_DL_TX))) return; if (!priv->tx_traffic) @@ -1452,7 +1421,7 @@ void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, __le16 fc; u16 len; - if (likely(!(iwl_debug_level & IWL_DL_RX))) + if (likely(!(iwl_get_debug_level(priv->shrd) & IWL_DL_RX))) return; if (!priv->rx_traffic) @@ -1609,7 +1578,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len) static void iwl_force_rf_reset(struct iwl_priv *priv) { - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return; if (!iwl_is_any_associated(priv)) { @@ -1634,7 +1603,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) { struct iwl_force_reset *force_reset; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return -EINVAL; if (mode >= IWL_MAX_FORCE_RESET) { @@ -1680,8 +1649,9 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external) return 0; } -int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum nl80211_iftype newtype, bool newp2p) +int iwlagn_mac_change_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + enum nl80211_iftype newtype, bool newp2p) { struct iwl_priv *priv = hw->priv; struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif); @@ -1691,11 +1661,13 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 interface_modes; int err; + IWL_DEBUG_MAC80211(priv, "enter\n"); + newtype = ieee80211_iftype_p2p(newtype, newp2p); - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); - if (!ctx->vif || !iwl_is_ready_rf(priv)) { + if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) { /* * Huh? But wait ... this can maybe happen when * we're in the middle of a firmware restart! @@ -1757,36 +1729,45 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, err = 0; out: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); + IWL_DEBUG_MAC80211(priv, "leave\n"); + return err; } -/* - * On every watchdog tick we check (latest) time stamp. If it does not - * change during timeout period and queue is not empty we reset firmware. - */ -static int iwl_check_stuck_queue(struct iwl_priv *priv, int cnt) +int iwl_cmd_echo_test(struct iwl_priv *priv) { - struct iwl_tx_queue *txq = &priv->txq[cnt]; - struct iwl_queue *q = &txq->q; - unsigned long timeout; int ret; + struct iwl_host_cmd cmd = { + .id = REPLY_ECHO, + .flags = CMD_SYNC, + }; - if (q->read_ptr == q->write_ptr) { - txq->time_stamp = jiffies; - return 0; - } - - timeout = txq->time_stamp + - msecs_to_jiffies(priv->cfg->base_params->wd_timeout); + ret = iwl_trans_send_cmd(trans(priv), &cmd); + if (ret) + IWL_ERR(priv, "echo testing fail: 0X%x\n", ret); + else + IWL_DEBUG_INFO(priv, "echo testing pass\n"); + return ret; +} - if (time_after(jiffies, timeout)) { - IWL_ERR(priv, "Queue %d stuck for %u ms.\n", - q->id, priv->cfg->base_params->wd_timeout); +static inline int iwl_check_stuck_queue(struct iwl_priv *priv, int txq) +{ + if (iwl_trans_check_stuck_queue(trans(priv), txq)) { + int ret; + if (txq == priv->shrd->cmd_queue) { + /* + * validate command queue still working + * by sending "ECHO" command + */ + if (!iwl_cmd_echo_test(priv)) + return 0; + else + IWL_DEBUG_HC(priv, "echo testing fail\n"); + } ret = iwl_force_reset(priv, IWL_FW_RESET, false); return (ret == -EAGAIN) ? 0 : 1; } - return 0; } @@ -1806,7 +1787,10 @@ void iwl_bg_watchdog(unsigned long data) int cnt; unsigned long timeout; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) + return; + + if (iwl_is_rfkill(priv->shrd)) return; timeout = priv->cfg->base_params->wd_timeout; @@ -1814,14 +1798,14 @@ void iwl_bg_watchdog(unsigned long data) return; /* monitor and check for stuck cmd queue */ - if (iwl_check_stuck_queue(priv, priv->cmd_queue)) + if (iwl_check_stuck_queue(priv, priv->shrd->cmd_queue)) return; /* monitor and check for other stuck queues */ if (iwl_is_any_associated(priv)) { - for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { + for (cnt = 0; cnt < hw_params(priv).max_txq_num; cnt++) { /* skip as we already checked the command queue */ - if (cnt == priv->cmd_queue) + if (cnt == priv->shrd->cmd_queue) continue; if (iwl_check_stuck_queue(priv, cnt)) return; @@ -1843,6 +1827,28 @@ void iwl_setup_watchdog(struct iwl_priv *priv) del_timer(&priv->watchdog); } +/** + * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time + * @priv -- pointer to iwl_priv data structure + * @tsf_bits -- number of bits need to shift for masking) + */ +static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv, + u16 tsf_bits) +{ + return (1 << tsf_bits) - 1; +} + +/** + * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time + * @priv -- pointer to iwl_priv data structure + * @tsf_bits -- number of bits need to shift for masking) + */ +static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv, + u16 tsf_bits) +{ + return ((1 << (32 - tsf_bits)) - 1) << tsf_bits; +} + /* * extended beacon time format * time in usec will be changed into a 32-bit value in extended:internal format @@ -1859,13 +1865,12 @@ u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval) return 0; quot = (usec / interval) & - (iwl_beacon_time_mask_high(priv, - priv->hw_params.beacon_time_tsf_bits) >> - priv->hw_params.beacon_time_tsf_bits); + (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >> + IWLAGN_EXT_BEACON_TIME_POS); rem = (usec % interval) & iwl_beacon_time_mask_low(priv, - priv->hw_params.beacon_time_tsf_bits); + IWLAGN_EXT_BEACON_TIME_POS); - return (quot << priv->hw_params.beacon_time_tsf_bits) + rem; + return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem; } /* base is usually what we get from ucode with each received frame, @@ -1875,64 +1880,80 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, u32 addon, u32 beacon_interval) { u32 base_low = base & iwl_beacon_time_mask_low(priv, - priv->hw_params.beacon_time_tsf_bits); + IWLAGN_EXT_BEACON_TIME_POS); u32 addon_low = addon & iwl_beacon_time_mask_low(priv, - priv->hw_params.beacon_time_tsf_bits); + IWLAGN_EXT_BEACON_TIME_POS); u32 interval = beacon_interval * TIME_UNIT; u32 res = (base & iwl_beacon_time_mask_high(priv, - priv->hw_params.beacon_time_tsf_bits)) + + IWLAGN_EXT_BEACON_TIME_POS)) + (addon & iwl_beacon_time_mask_high(priv, - priv->hw_params.beacon_time_tsf_bits)); + IWLAGN_EXT_BEACON_TIME_POS)); if (base_low > addon_low) res += base_low - addon_low; else if (base_low < addon_low) { res += interval + base_low - addon_low; - res += (1 << priv->hw_params.beacon_time_tsf_bits); + res += (1 << IWLAGN_EXT_BEACON_TIME_POS); } else - res += (1 << priv->hw_params.beacon_time_tsf_bits); + res += (1 << IWLAGN_EXT_BEACON_TIME_POS); return cpu_to_le32(res); } -#ifdef CONFIG_PM +void iwl_start_tx_ba_trans_ready(struct iwl_priv *priv, + enum iwl_rxon_context_id ctx, + u8 sta_id, u8 tid) +{ + struct ieee80211_vif *vif; + u8 *addr = priv->stations[sta_id].sta.sta.addr; -int iwl_suspend(struct iwl_priv *priv) + if (ctx == NUM_IWL_RXON_CTX) + ctx = priv->stations[sta_id].ctxid; + vif = priv->contexts[ctx].vif; + + ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); +} + +void iwl_stop_tx_ba_trans_ready(struct iwl_priv *priv, + enum iwl_rxon_context_id ctx, + u8 sta_id, u8 tid) { - /* - * This function is called when system goes into suspend state - * mac80211 will call iwl_mac_stop() from the mac80211 suspend function - * first but since iwl_mac_stop() has no knowledge of who the caller is, - * it will not call apm_ops.stop() to stop the DMA operation. - * Calling apm_ops.stop here to make sure we stop the DMA. - * - * But of course ... if we have configured WoWLAN then we did other - * things already :-) - */ - if (!priv->wowlan) - iwl_apm_stop(priv); + struct ieee80211_vif *vif; + u8 *addr = priv->stations[sta_id].sta.sta.addr; - return 0; + if (ctx == NUM_IWL_RXON_CTX) + ctx = priv->stations[sta_id].ctxid; + vif = priv->contexts[ctx].vif; + + ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid); } -int iwl_resume(struct iwl_priv *priv) +void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state) { - bool hw_rfkill = false; + wiphy_rfkill_set_hw_state(priv->hw->wiphy, state); +} - iwl_enable_interrupts(priv); +void iwl_nic_config(struct iwl_priv *priv) +{ + priv->cfg->lib->nic_config(priv); - if (!(iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rfkill = true; +} - if (hw_rfkill) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); +void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb) +{ + struct ieee80211_tx_info *info; - wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rfkill); + info = IEEE80211_SKB_CB(skb); + kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1])); + dev_kfree_skb_any(skb); +} - return 0; +void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac) +{ + ieee80211_stop_queue(priv->hw, ac); } -#endif /* CONFIG_PM */ +void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac) +{ + ieee80211_wake_queue(priv->hw, ac); +} diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 02817a438550..137da3380704 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -64,6 +64,7 @@ #define __iwl_core_h__ #include "iwl-dev.h" +#include "iwl-io.h" /************************ * forward declarations * @@ -71,15 +72,8 @@ struct iwl_host_cmd; struct iwl_cmd; - -#define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" -#define DRV_AUTHOR "<ilw@linux.intel.com>" - #define TIME_UNIT 1024 -#define IWL_CMD(x) case x: return #x - struct iwl_lib_ops { /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); @@ -101,23 +95,6 @@ struct iwl_lib_ops { void (*temperature)(struct iwl_priv *priv); }; -struct iwl_mod_params { - int sw_crypto; /* def: 0 = using hardware encryption */ - int num_of_queues; /* def: HW dependent */ - int disable_11n; /* def: 0 = 11n capabilities enabled */ - int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ - int antenna; /* def: 0 = both antennas (use diversity) */ - int restart_fw; /* def: 1 = restart firmware */ - bool plcp_check; /* def: true = enable plcp health check */ - bool ack_check; /* def: false = disable ack health check */ - bool wd_disable; /* def: false = enable stuck queue check */ - bool bt_coex_active; /* def: true = enable bt coex */ - int led_mode; /* def: 0 = system default */ - bool no_sleep_autoadjust; /* def: true = disable autoadjust */ - bool power_save; /* def: false = disable power save */ - int power_level; /* def: 1 = power level */ -}; - /* * @max_ll_items: max number of OTP blocks * @shadow_ram_support: shadow support for OTP memory @@ -132,10 +109,10 @@ struct iwl_mod_params { * radio tuning when there is a high receiving plcp error rate * @chain_noise_scale: default chain noise scale used for gain computation * @wd_timeout: TX queues watchdog timeout - * @temperature_kelvin: temperature report by uCode in kelvin * @max_event_log_size: size of event log buffer size for ucode event logging * @shadow_reg_enable: HW shadhow register bit * @no_idle_support: do not support idle mode + * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up */ struct iwl_base_params { int eeprom_size; @@ -147,17 +124,16 @@ struct iwl_base_params { const u16 max_ll_items; const bool shadow_ram_support; u16 led_compensation; - int chain_noise_num_beacons; bool adv_thermal_throttle; bool support_ct_kill_exit; const bool support_wimax_coexist; u8 plcp_delta_threshold; s32 chain_noise_scale; unsigned int wd_timeout; - bool temperature_kelvin; u32 max_event_log_size; const bool shadow_reg_enable; const bool no_idle_support; + const bool hd_v2; }; /* * @advanced_bt_coexist: support advanced bt coexist @@ -194,6 +170,8 @@ struct iwl_ht_params { * (.ucode) will be added to filename before loading from disk. The * filename is constructed as fw_name_pre<api>.ucode. * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_ok: oldest version of the uCode API that is OK to load + * without a warning, for use in transitions * @ucode_api_min: Lowest version of uCode API supported by driver. * @valid_tx_ant: valid transmit antenna * @valid_rx_ant: valid receive antenna @@ -214,20 +192,12 @@ struct iwl_ht_params { * @rx_with_siso_diversity: 1x1 device with rx antenna diversity * @internal_wimax_coex: internal wifi/wimax combo device * @iq_invert: I/Q inversion + * @temp_offset_v2: support v2 of temperature offset calibration * * We enable the driver to be backward compatible wrt API version. The * driver specifies which APIs it supports (with @ucode_api_max being the * highest and @ucode_api_min the lowest). Firmware will only be loaded if - * it has a supported API version. The firmware's API version will be - * stored in @iwl_priv, enabling the driver to make runtime changes based - * on firmware version used. - * - * For example, - * if (IWL_UCODE_API(priv->ucode_ver) >= 2) { - * Driver interacts with Firmware API version >= 2. - * } else { - * Driver interacts with Firmware API version 1. - * } + * it has a supported API version. * * The ideal usage of this infrastructure is to treat a new ucode API * release as a new hardware revision. @@ -237,6 +207,7 @@ struct iwl_cfg { const char *name; const char *fw_name_pre; const unsigned int ucode_api_max; + const unsigned int ucode_api_ok; const unsigned int ucode_api_min; u8 valid_tx_ant; u8 valid_rx_ant; @@ -259,15 +230,17 @@ struct iwl_cfg { const bool rx_with_siso_diversity; const bool internal_wimax_coex; const bool iq_invert; + const bool temp_offset_v2; }; /*************************** * L i b * ***************************/ -int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int iwlagn_mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); -int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw); +int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw); void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx, int hw_decrypt); int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -287,18 +260,17 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv, void iwl_connection_init_rx_config(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void iwl_set_rate(struct iwl_priv *priv); -void iwl_irq_handle_error(struct iwl_priv *priv); -int iwl_mac_add_interface(struct ieee80211_hw *hw, +int iwlagn_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void iwl_mac_remove_interface(struct ieee80211_hw *hw, +void iwlagn_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int iwl_mac_change_interface(struct ieee80211_hw *hw, +int iwlagn_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum nl80211_iftype newtype, bool newp2p); +int iwl_cmd_echo_test(struct iwl_priv *priv); #ifdef CONFIG_IWLWIFI_DEBUGFS int iwl_alloc_traffic_mem(struct iwl_priv *priv); void iwl_free_traffic_mem(struct iwl_priv *priv); -void iwl_reset_traffic_log(struct iwl_priv *priv); void iwl_dbg_log_tx_data_frame(struct iwl_priv *priv, u16 length, struct ieee80211_hdr *header); void iwl_dbg_log_rx_data_frame(struct iwl_priv *priv, @@ -349,9 +321,9 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); ******************************************************************************/ void iwl_init_scan_params(struct iwl_priv *priv); int iwl_scan_cancel(struct iwl_priv *priv); -int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); +void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms); void iwl_force_scan_end(struct iwl_priv *priv); -int iwl_mac_hw_scan(struct ieee80211_hw *hw, +int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req); void iwl_internal_short_hw_scan(struct iwl_priv *priv); @@ -359,12 +331,6 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external); u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame, const u8 *ta, const u8 *ie, int ie_len, int left); void iwl_setup_rx_scan_handlers(struct iwl_priv *priv); -u16 iwl_get_active_dwell_time(struct iwl_priv *priv, - enum ieee80211_band band, - u8 n_probes); -u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, - enum ieee80211_band band, - struct ieee80211_vif *vif); void iwl_setup_scan_deferred_work(struct iwl_priv *priv); void iwl_cancel_scan_deferred_work(struct iwl_priv *priv); int __must_check iwl_scan_initiate(struct iwl_priv *priv, @@ -387,117 +353,21 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, * S e n d i n g H o s t C o m m a n d s * *****************************************************/ -const char *get_cmd_string(u8 cmd); void iwl_bg_watchdog(unsigned long data); u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval); __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base, u32 addon, u32 beacon_interval); -#ifdef CONFIG_PM -int iwl_suspend(struct iwl_priv *priv); -int iwl_resume(struct iwl_priv *priv); -#endif /* !CONFIG_PM */ - -int iwl_probe(struct iwl_bus *bus, struct iwl_cfg *cfg); -void __devexit iwl_remove(struct iwl_priv * priv); - -/***************************************************** -* Error Handling Debugging -******************************************************/ -void iwl_dump_nic_error_log(struct iwl_priv *priv); -int iwl_dump_nic_event_log(struct iwl_priv *priv, - bool full_log, char **buf, bool display); -void iwl_dump_csr(struct iwl_priv *priv); -int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display); -#ifdef CONFIG_IWLWIFI_DEBUG -void iwl_print_rx_config_cmd(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); -#else -static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ -} -#endif - -void iwl_clear_isr_stats(struct iwl_priv *priv); /***************************************************** * GEOS ******************************************************/ -int iwlcore_init_geos(struct iwl_priv *priv); -void iwlcore_free_geos(struct iwl_priv *priv); - -/*************** DRIVER STATUS FUNCTIONS *****/ - -#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ -/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */ -#define STATUS_INT_ENABLED 2 -#define STATUS_RF_KILL_HW 3 -#define STATUS_CT_KILL 4 -#define STATUS_INIT 5 -#define STATUS_ALIVE 6 -#define STATUS_READY 7 -#define STATUS_TEMPERATURE 8 -#define STATUS_GEO_CONFIGURED 9 -#define STATUS_EXIT_PENDING 10 -#define STATUS_STATISTICS 12 -#define STATUS_SCANNING 13 -#define STATUS_SCAN_ABORTING 14 -#define STATUS_SCAN_HW 15 -#define STATUS_POWER_PMI 16 -#define STATUS_FW_ERROR 17 -#define STATUS_DEVICE_ENABLED 18 -#define STATUS_CHANNEL_SWITCH_PENDING 19 - - -static inline int iwl_is_ready(struct iwl_priv *priv) -{ - /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are - * set but EXIT_PENDING is not */ - return test_bit(STATUS_READY, &priv->status) && - test_bit(STATUS_GEO_CONFIGURED, &priv->status) && - !test_bit(STATUS_EXIT_PENDING, &priv->status); -} - -static inline int iwl_is_alive(struct iwl_priv *priv) -{ - return test_bit(STATUS_ALIVE, &priv->status); -} - -static inline int iwl_is_init(struct iwl_priv *priv) -{ - return test_bit(STATUS_INIT, &priv->status); -} - -static inline int iwl_is_rfkill_hw(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_HW, &priv->status); -} - -static inline int iwl_is_rfkill(struct iwl_priv *priv) -{ - return iwl_is_rfkill_hw(priv); -} - -static inline int iwl_is_ctkill(struct iwl_priv *priv) -{ - return test_bit(STATUS_CT_KILL, &priv->status); -} - -static inline int iwl_is_ready_rf(struct iwl_priv *priv) -{ - - if (iwl_is_rfkill(priv)) - return 0; - - return iwl_is_ready(priv); -} +int iwl_init_geos(struct iwl_priv *priv); +void iwl_free_geos(struct iwl_priv *priv); extern void iwl_send_bt_config(struct iwl_priv *priv); extern int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear); -void iwl_apm_stop(struct iwl_priv *priv); -int iwl_apm_init(struct iwl_priv *priv); int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx); @@ -513,9 +383,12 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv) priv->cfg->bt_params->advanced_bt_coexist; } -extern bool bt_siso_mode; - +static inline void iwl_enable_rfkill_int(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n"); + iwl_write32(bus(priv), CSR_INT_MASK, CSR_INT_BIT_RF_KILL); +} -void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); +extern bool bt_siso_mode; #endif /* __iwl_core_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index d6dbb0423045..b9f3267e720c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -439,4 +439,22 @@ */ #define HBUS_TARG_WRPTR (HBUS_BASE+0x060) +/********************************************************** + * CSR values + **********************************************************/ + /* + * host interrupt timeout value + * used with setting interrupt coalescing timer + * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit + * + * default interrupt coalescing timer is 64 x 32 = 2048 usecs + * default interrupt coalescing calibration timer is 16 x 32 = 512 usecs + */ +#define IWL_HOST_INT_TIMEOUT_MAX (0xFF) +#define IWL_HOST_INT_TIMEOUT_DEF (0x40) +#define IWL_HOST_INT_TIMEOUT_MIN (0x0) +#define IWL_HOST_INT_CALIB_TIMEOUT_MAX (0xFF) +#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10) +#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0) + #endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index f9a407e40aff..69a77e24d229 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -29,50 +29,51 @@ #ifndef __iwl_debug_h__ #define __iwl_debug_h__ +#include "iwl-bus.h" +#include "iwl-shared.h" + struct iwl_priv; -extern u32 iwl_debug_level; -#define IWL_ERR(p, f, a...) dev_err(p->bus->dev, f, ## a) -#define IWL_WARN(p, f, a...) dev_warn(p->bus->dev, f, ## a) -#define IWL_INFO(p, f, a...) dev_info(p->bus->dev, f, ## a) -#define IWL_CRIT(p, f, a...) dev_crit(p->bus->dev, f, ## a) +/*No matter what is m (priv, bus, trans), this will work */ +#define IWL_ERR(m, f, a...) dev_err(bus(m)->dev, f, ## a) +#define IWL_WARN(m, f, a...) dev_warn(bus(m)->dev, f, ## a) +#define IWL_INFO(m, f, a...) dev_info(bus(m)->dev, f, ## a) +#define IWL_CRIT(m, f, a...) dev_crit(bus(m)->dev, f, ## a) -#define iwl_print_hex_error(priv, p, len) \ +#define iwl_print_hex_error(m, p, len) \ do { \ print_hex_dump(KERN_ERR, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) #ifdef CONFIG_IWLWIFI_DEBUG -#define IWL_DEBUG(__priv, level, fmt, args...) \ +#define IWL_DEBUG(m, level, fmt, args...) \ do { \ - if (iwl_get_debug_level(__priv) & (level)) \ - dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ + if (iwl_get_debug_level((m)->shrd) & (level)) \ + dev_printk(KERN_ERR, bus(m)->dev, \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ } while (0) -#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) \ +#define IWL_DEBUG_LIMIT(m, level, fmt, args...) \ do { \ - if ((iwl_get_debug_level(__priv) & (level)) && net_ratelimit()) \ - dev_printk(KERN_ERR, &(__priv->hw->wiphy->dev), \ + if (iwl_get_debug_level((m)->shrd) & (level) && net_ratelimit())\ + dev_printk(KERN_ERR, bus(m)->dev, \ "%c %s " fmt, in_interrupt() ? 'I' : 'U', \ __func__ , ## args); \ } while (0) -#define iwl_print_hex_dump(priv, level, p, len) \ +#define iwl_print_hex_dump(m, level, p, len) \ do { \ - if (iwl_get_debug_level(priv) & level) \ + if (iwl_get_debug_level((m)->shrd) & level) \ print_hex_dump(KERN_DEBUG, "iwl data: ", \ DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ } while (0) #else -#define IWL_DEBUG(__priv, level, fmt, args...) -#define IWL_DEBUG_LIMIT(__priv, level, fmt, args...) -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - const void *p, u32 len) -{} +#define IWL_DEBUG(m, level, fmt, args...) +#define IWL_DEBUG_LIMIT(m, level, fmt, args...) +#define iwl_print_hex_dump(m, level, p, len) #endif /* CONFIG_IWLWIFI_DEBUG */ #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -104,10 +105,12 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) * * The active debug levels can be accessed via files * - * /sys/module/iwlagn/parameters/debug{50} - * /sys/class/net/wlan0/device/debug_level - * + * /sys/module/iwlwifi/parameters/debug * when CONFIG_IWLWIFI_DEBUG=y. + * + * /sys/kernel/debug/phy0/iwlwifi/debug/debug_level + * when CONFIG_IWLWIFI_DEBUGFS=y. + * */ /* 0x0000000F - 0x00000001 */ @@ -166,6 +169,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #define IWL_DEBUG_CALIB(p, f, a...) IWL_DEBUG(p, IWL_DL_CALIB, f, ## a) #define IWL_DEBUG_FW(p, f, a...) IWL_DEBUG(p, IWL_DL_FW, f, ## a) #define IWL_DEBUG_RF_KILL(p, f, a...) IWL_DEBUG(p, IWL_DL_RF_KILL, f, ## a) +#define IWL_DEBUG_FW_ERRORS(p, f, a...) IWL_DEBUG(p, IWL_DL_FW_ERRORS, f, ## a) #define IWL_DEBUG_DROP(p, f, a...) IWL_DEBUG(p, IWL_DL_DROP, f, ## a) #define IWL_DEBUG_DROP_LIMIT(p, f, a...) \ IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index ec1485b2d3fe..a1670e3f8bfa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -64,6 +64,14 @@ goto err; \ } while (0) +#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do { \ + struct dentry *__tmp; \ + __tmp = debugfs_create_u32(#name, mode, \ + parent, ptr); \ + if (IS_ERR(__tmp) || !__tmp) \ + goto err; \ +} while (0) + /* file operation */ #define DEBUGFS_READ_FUNC(name) \ static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ @@ -254,7 +262,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, sram = priv->dbgfs_sram_offset & ~0x3; /* read the first u32 from sram */ - val = iwl_read_targ_mem(priv, sram); + val = iwl_read_targ_mem(bus(priv), sram); for (; len; len--) { /* put the address at the start of every line */ @@ -273,7 +281,7 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, if (++offset == 4) { sram += 4; offset = 0; - val = iwl_read_targ_mem(priv, sram); + val = iwl_read_targ_mem(bus(priv), sram); } /* put in extra spaces and split lines for human readability */ @@ -340,7 +348,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, { struct iwl_priv *priv = file->private_data; struct iwl_station_entry *station; - int max_sta = priv->hw_params.max_stations; + struct iwl_tid_data *tid_data; char *buf; int i, j, pos = 0; ssize_t ret; @@ -354,7 +362,7 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, pos += scnprintf(buf + pos, bufsz - pos, "num of stations: %d\n\n", priv->num_stations); - for (i = 0; i < max_sta; i++) { + for (i = 0; i < IWLAGN_STATION_COUNT; i++) { station = &priv->stations[i]; if (!station->used) continue; @@ -363,22 +371,18 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, i, station->sta.sta.addr, station->sta.station_flags_msk); pos += scnprintf(buf + pos, bufsz - pos, - "TID\tseq_num\ttxq_id\tframes\ttfds\t"); - pos += scnprintf(buf + pos, bufsz - pos, - "start_idx\tbitmap\t\t\trate_n_flags\n"); + "TID\tseq_num\ttxq_id\ttfds\trate_n_flags\n"); - for (j = 0; j < MAX_TID_COUNT; j++) { + for (j = 0; j < IWL_MAX_TID_COUNT; j++) { + tid_data = &priv->shrd->tid_data[i][j]; pos += scnprintf(buf + pos, bufsz - pos, - "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x", - j, station->tid[j].seq_number, - station->tid[j].agg.txq_id, - station->tid[j].agg.frame_count, - station->tid[j].tfds_in_queue, - station->tid[j].agg.start_idx, - station->tid[j].agg.bitmap, - station->tid[j].agg.rate_n_flags); - - if (station->tid[j].agg.wait_for_ba) + "%d:\t%#x\t%#x\t%u\t%#x", + j, tid_data->seq_number, + tid_data->agg.txq_id, + tid_data->tfds_in_queue, + tid_data->agg.rate_n_flags); + + if (tid_data->agg.wait_for_ba) pos += scnprintf(buf + pos, bufsz - pos, " - waitforba"); pos += scnprintf(buf + pos, bufsz - pos, "\n"); @@ -442,46 +446,6 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file, return ret; } -static ssize_t iwl_dbgfs_log_event_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char *buf; - int pos = 0; - ssize_t ret = -ENOMEM; - - ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - } - return ret; -} - -static ssize_t iwl_dbgfs_log_event_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - u32 event_log_flag; - char buf[8]; - int buf_size; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &event_log_flag) != 1) - return -EFAULT; - if (event_log_flag == 1) - iwl_dump_nic_event_log(priv, true, NULL, false); - - return count; -} - - - static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -492,7 +456,7 @@ static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, char *buf; ssize_t ret; - if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) + if (!test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status)) return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); @@ -562,45 +526,46 @@ static ssize_t iwl_dbgfs_status_read(struct file *file, const size_t bufsz = sizeof(buf); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_HCMD_ACTIVE:\t %d\n", - test_bit(STATUS_HCMD_ACTIVE, &priv->status)); + test_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INT_ENABLED:\t %d\n", - test_bit(STATUS_INT_ENABLED, &priv->status)); + test_bit(STATUS_INT_ENABLED, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_RF_KILL_HW:\t %d\n", - test_bit(STATUS_RF_KILL_HW, &priv->status)); + test_bit(STATUS_RF_KILL_HW, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_CT_KILL:\t\t %d\n", - test_bit(STATUS_CT_KILL, &priv->status)); + test_bit(STATUS_CT_KILL, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_INIT:\t\t %d\n", - test_bit(STATUS_INIT, &priv->status)); + test_bit(STATUS_INIT, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_ALIVE:\t\t %d\n", - test_bit(STATUS_ALIVE, &priv->status)); + test_bit(STATUS_ALIVE, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_READY:\t\t %d\n", - test_bit(STATUS_READY, &priv->status)); + test_bit(STATUS_READY, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_TEMPERATURE:\t %d\n", - test_bit(STATUS_TEMPERATURE, &priv->status)); + test_bit(STATUS_TEMPERATURE, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_GEO_CONFIGURED:\t %d\n", - test_bit(STATUS_GEO_CONFIGURED, &priv->status)); + test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_EXIT_PENDING:\t %d\n", - test_bit(STATUS_EXIT_PENDING, &priv->status)); + test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_STATISTICS:\t %d\n", - test_bit(STATUS_STATISTICS, &priv->status)); + test_bit(STATUS_STATISTICS, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCANNING:\t %d\n", - test_bit(STATUS_SCANNING, &priv->status)); + test_bit(STATUS_SCANNING, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_ABORTING:\t %d\n", - test_bit(STATUS_SCAN_ABORTING, &priv->status)); + test_bit(STATUS_SCAN_ABORTING, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_SCAN_HW:\t\t %d\n", - test_bit(STATUS_SCAN_HW, &priv->status)); + test_bit(STATUS_SCAN_HW, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_POWER_PMI:\t %d\n", - test_bit(STATUS_POWER_PMI, &priv->status)); + test_bit(STATUS_POWER_PMI, &priv->shrd->status)); pos += scnprintf(buf + pos, bufsz - pos, "STATUS_FW_ERROR:\t %d\n", - test_bit(STATUS_FW_ERROR, &priv->status)); + test_bit(STATUS_FW_ERROR, &priv->shrd->status)); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } -static ssize_t iwl_dbgfs_interrupt_read(struct file *file, +static ssize_t iwl_dbgfs_rx_handlers_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; + int pos = 0; int cnt = 0; char *buf; @@ -613,61 +578,25 @@ static ssize_t iwl_dbgfs_interrupt_read(struct file *file, return -ENOMEM; } - pos += scnprintf(buf + pos, bufsz - pos, - "Interrupt Statistics Report:\n"); - - pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n", - priv->isr_stats.hw); - pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n", - priv->isr_stats.sw); - if (priv->isr_stats.sw || priv->isr_stats.hw) { - pos += scnprintf(buf + pos, bufsz - pos, - "\tLast Restarting Code: 0x%X\n", - priv->isr_stats.err_code); - } -#ifdef CONFIG_IWLWIFI_DEBUG - pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n", - priv->isr_stats.sch); - pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n", - priv->isr_stats.alive); -#endif - pos += scnprintf(buf + pos, bufsz - pos, - "HW RF KILL switch toggled:\t %u\n", - priv->isr_stats.rfkill); - - pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n", - priv->isr_stats.ctkill); - - pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n", - priv->isr_stats.wakeup); - - pos += scnprintf(buf + pos, bufsz - pos, - "Rx command responses:\t\t %u\n", - priv->isr_stats.rx); for (cnt = 0; cnt < REPLY_MAX; cnt++) { - if (priv->isr_stats.rx_handlers[cnt] > 0) + if (priv->rx_handlers_stats[cnt] > 0) pos += scnprintf(buf + pos, bufsz - pos, "\tRx handler[%36s]:\t\t %u\n", get_cmd_string(cnt), - priv->isr_stats.rx_handlers[cnt]); + priv->rx_handlers_stats[cnt]); } - pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n", - priv->isr_stats.tx); - - pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n", - priv->isr_stats.unhandled); - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); kfree(buf); return ret; } -static ssize_t iwl_dbgfs_interrupt_write(struct file *file, +static ssize_t iwl_dbgfs_rx_handlers_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_priv *priv = file->private_data; + char buf[8]; int buf_size; u32 reset_flag; @@ -679,7 +608,8 @@ static ssize_t iwl_dbgfs_interrupt_write(struct file *file, if (sscanf(buf, "%x", &reset_flag) != 1) return -EFAULT; if (reset_flag == 0) - iwl_clear_isr_stats(priv); + memset(&priv->rx_handlers_stats[0], 0, + sizeof(priv->rx_handlers_stats)); return count; } @@ -784,6 +714,20 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } +static ssize_t iwl_dbgfs_temperature_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int pos = 0; + const size_t bufsz = sizeof(buf); + + pos += scnprintf(buf + pos, bufsz - pos, "%d\n", priv->temperature); + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + + static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) @@ -814,14 +758,14 @@ static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file, if (value != -1 && (value < 0 || value >= IWL_POWER_NUM)) return -EINVAL; - if (!iwl_is_ready_rf(priv)) + if (!iwl_is_ready_rf(priv->shrd)) return -EAGAIN; priv->power_data.debug_sleep_level_override = value; - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); iwl_power_update_mode(priv, true); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); return count; } @@ -870,15 +814,15 @@ static ssize_t iwl_dbgfs_current_sleep_command_read(struct file *file, DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_READ_FILE_OPS(wowlan_sram); -DEBUGFS_READ_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(nvm); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(channels); DEBUGFS_READ_FILE_OPS(status); -DEBUGFS_READ_WRITE_FILE_OPS(interrupt); +DEBUGFS_READ_WRITE_FILE_OPS(rx_handlers); DEBUGFS_READ_FILE_OPS(qos); DEBUGFS_READ_FILE_OPS(thermal_throttling); DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40); +DEBUGFS_READ_FILE_OPS(temperature); DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override); DEBUGFS_READ_FILE_OPS(current_sleep_command); @@ -889,36 +833,23 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, struct iwl_priv *priv = file->private_data; int pos = 0, ofs = 0; int cnt = 0, entry; - struct iwl_tx_queue *txq; - struct iwl_queue *q; - struct iwl_rx_queue *rxq = &priv->rxq; + char *buf; int bufsz = ((IWL_TRAFFIC_ENTRIES * IWL_TRAFFIC_ENTRY_SIZE * 64) * 2) + - (priv->cfg->base_params->num_of_queues * 32 * 8) + 400; + (hw_params(priv).max_txq_num * 32 * 8) + 400; const u8 *ptr; ssize_t ret; - if (!priv->txq) { - IWL_ERR(priv, "txq not ready\n"); - return -EAGAIN; - } buf = kzalloc(bufsz, GFP_KERNEL); if (!buf) { IWL_ERR(priv, "Can not allocate buffer\n"); return -ENOMEM; } - pos += scnprintf(buf + pos, bufsz - pos, "Tx Queue\n"); - for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { - txq = &priv->txq[cnt]; - q = &txq->q; - pos += scnprintf(buf + pos, bufsz - pos, - "q[%d]: read_ptr: %u, write_ptr: %u\n", - cnt, q->read_ptr, q->write_ptr); - } - if (priv->tx_traffic && (iwl_debug_level & IWL_DL_TX)) { + if (priv->tx_traffic && + (iwl_get_debug_level(priv->shrd) & IWL_DL_TX)) { ptr = priv->tx_traffic; pos += scnprintf(buf + pos, bufsz - pos, - "Tx Traffic idx: %u\n", priv->tx_traffic_idx); + "Tx Traffic idx: %u\n", priv->tx_traffic_idx); for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; entry++, ofs += 16) { @@ -933,15 +864,11 @@ static ssize_t iwl_dbgfs_traffic_log_read(struct file *file, } } - pos += scnprintf(buf + pos, bufsz - pos, "Rx Queue\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "read: %u, write: %u\n", - rxq->read, rxq->write); - - if (priv->rx_traffic && (iwl_debug_level & IWL_DL_RX)) { + if (priv->rx_traffic && + (iwl_get_debug_level(priv->shrd) & IWL_DL_RX)) { ptr = priv->rx_traffic; pos += scnprintf(buf + pos, bufsz - pos, - "Rx Traffic idx: %u\n", priv->rx_traffic_idx); + "Rx Traffic idx: %u\n", priv->rx_traffic_idx); for (cnt = 0, ofs = 0; cnt < IWL_TRAFFIC_ENTRIES; cnt++) { for (entry = 0; entry < IWL_TRAFFIC_ENTRY_SIZE / 16; entry++, ofs += 16) { @@ -982,76 +909,6 @@ static ssize_t iwl_dbgfs_traffic_log_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = file->private_data; - struct iwl_tx_queue *txq; - struct iwl_queue *q; - char *buf; - int pos = 0; - int cnt; - int ret; - const size_t bufsz = sizeof(char) * 64 * - priv->cfg->base_params->num_of_queues; - - if (!priv->txq) { - IWL_ERR(priv, "txq not ready\n"); - return -EAGAIN; - } - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - for (cnt = 0; cnt < priv->hw_params.max_txq_num; cnt++) { - txq = &priv->txq[cnt]; - q = &txq->q; - pos += scnprintf(buf + pos, bufsz - pos, - "hwq %.2d: read=%u write=%u stop=%d" - " swq_id=%#.2x (ac %d/hwq %d)\n", - cnt, q->read_ptr, q->write_ptr, - !!test_bit(cnt, priv->queue_stopped), - txq->swq_id, txq->swq_id & 3, - (txq->swq_id >> 2) & 0x1f); - if (cnt >= 4) - continue; - /* for the ACs, display the stop count too */ - pos += scnprintf(buf + pos, bufsz - pos, - " stop-count: %d\n", - atomic_read(&priv->queue_stop_count[cnt])); - } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return ret; -} - -static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) { - - struct iwl_priv *priv = file->private_data; - struct iwl_rx_queue *rxq = &priv->rxq; - char buf[256]; - int pos = 0; - const size_t bufsz = sizeof(buf); - - pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", - rxq->read); - pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", - rxq->write); - pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", - rxq->free_count); - if (rxq->rb_stts) { - pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n", - le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF); - } else { - pos += scnprintf(buf + pos, bufsz - pos, - "closed_rb_num: Not Allocated\n"); - } - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - static const char *fmt_value = " %-30s %10u\n"; static const char *fmt_hex = " %-30s 0x%02X\n"; static const char *fmt_table = " %-30s %10u %10u %10u %10u\n"; @@ -1096,7 +953,7 @@ static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file, struct statistics_rx_non_phy *delta_general, *max_general; struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht; - if (!iwl_is_alive(priv)) + if (!iwl_is_alive(priv->shrd)) return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); @@ -1522,7 +1379,7 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file, ssize_t ret; struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx; - if (!iwl_is_alive(priv)) + if (!iwl_is_alive(priv->shrd)) return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); @@ -1716,7 +1573,7 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file, struct statistics_dbg *dbg, *accum_dbg, *delta_dbg, *max_dbg; struct statistics_div *div, *accum_div, *delta_div, *max_div; - if (!iwl_is_alive(priv)) + if (!iwl_is_alive(priv->shrd)) return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); @@ -1829,16 +1686,16 @@ static ssize_t iwl_dbgfs_ucode_bt_stats_read(struct file *file, ssize_t ret; struct statistics_bt_activity *bt, *accum_bt; - if (!iwl_is_alive(priv)) + if (!iwl_is_alive(priv->shrd)) return -EAGAIN; if (!priv->bt_enable_flag) return -EINVAL; /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); ret = iwl_send_statistics_request(priv, CMD_SYNC, false); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); if (ret) { IWL_ERR(priv, @@ -1917,7 +1774,7 @@ static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file, (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200; ssize_t ret; - if (!iwl_is_alive(priv)) + if (!iwl_is_alive(priv->shrd)) return -EAGAIN; buf = kzalloc(bufsz, GFP_KERNEL); @@ -2199,7 +2056,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, const size_t bufsz = sizeof(buf); u32 pwrsave_status; - pwrsave_status = iwl_read32(priv, CSR_GP_CNTRL) & + pwrsave_status = iwl_read32(bus(priv), CSR_GP_CNTRL) & CSR_GP_REG_POWER_SAVE_STATUS_MSK; pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: "); @@ -2229,30 +2086,9 @@ static ssize_t iwl_dbgfs_clear_ucode_statistics_write(struct file *file, return -EFAULT; /* make request to uCode to retrieve statistics information */ - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); iwl_send_statistics_request(priv, CMD_SYNC, true); - mutex_unlock(&priv->mutex); - - return count; -} - -static ssize_t iwl_dbgfs_csr_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char buf[8]; - int buf_size; - int csr; - - memset(buf, 0, sizeof(buf)); - buf_size = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - if (sscanf(buf, "%d", &csr) != 1) - return -EFAULT; - - iwl_dump_csr(priv); + mutex_unlock(&priv->shrd->mutex); return count; } @@ -2333,25 +2169,6 @@ static ssize_t iwl_dbgfs_rxon_filter_flags_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_priv *priv = file->private_data; - char *buf; - int pos = 0; - ssize_t ret = -EFAULT; - - ret = pos = iwl_dump_fh(priv, &buf, true); - if (buf) { - ret = simple_read_from_buffer(user_buf, - count, ppos, buf, pos); - kfree(buf); - } - - return ret; -} - static ssize_t iwl_dbgfs_missed_beacon_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -2434,8 +2251,8 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file, static ssize_t iwl_dbgfs_force_reset_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) { - + size_t count, loff_t *ppos) +{ struct iwl_priv *priv = file->private_data; int i, pos = 0; char buf[300]; @@ -2504,7 +2321,7 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, if (sscanf(buf, "%d", &flush) != 1) return -EINVAL; - if (iwl_is_rfkill(priv)) + if (iwl_is_rfkill(priv->shrd)) return -EFAULT; iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL); @@ -2514,8 +2331,8 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file, static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) { - + size_t count, loff_t *ppos) +{ struct iwl_priv *priv = file->private_data; char buf[8]; int buf_size; @@ -2626,11 +2443,26 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file, return count; } +static ssize_t iwl_dbgfs_echo_test_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + iwl_cmd_echo_test(priv); + return count; +} + DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); DEBUGFS_READ_WRITE_FILE_OPS(traffic_log); -DEBUGFS_READ_FILE_OPS(rx_queue); -DEBUGFS_READ_FILE_OPS(tx_queue); DEBUGFS_READ_FILE_OPS(ucode_rx_stats); DEBUGFS_READ_FILE_OPS(ucode_tx_stats); DEBUGFS_READ_FILE_OPS(ucode_general_stats); @@ -2639,9 +2471,7 @@ DEBUGFS_READ_FILE_OPS(chain_noise); DEBUGFS_READ_FILE_OPS(power_save_status); DEBUGFS_WRITE_FILE_OPS(clear_ucode_statistics); DEBUGFS_WRITE_FILE_OPS(clear_traffic_statistics); -DEBUGFS_WRITE_FILE_OPS(csr); DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing); -DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon); DEBUGFS_READ_WRITE_FILE_OPS(plcp_delta); DEBUGFS_READ_WRITE_FILE_OPS(force_reset); @@ -2653,6 +2483,53 @@ DEBUGFS_WRITE_FILE_OPS(wd_timeout); DEBUGFS_READ_FILE_OPS(bt_traffic); DEBUGFS_READ_WRITE_FILE_OPS(protection_mode); DEBUGFS_READ_FILE_OPS(reply_tx_error); +DEBUGFS_WRITE_FILE_OPS(echo_test); + +#ifdef CONFIG_IWLWIFI_DEBUG +static ssize_t iwl_dbgfs_debug_level_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + struct iwl_shared *shrd = priv->shrd; + char buf[11]; + int len; + + len = scnprintf(buf, sizeof(buf), "0x%.8x", + iwl_get_debug_level(shrd)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t iwl_dbgfs_debug_level_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = file->private_data; + struct iwl_shared *shrd = priv->shrd; + char buf[11]; + unsigned long val; + int ret; + + if (count > sizeof(buf)) + return -EINVAL; + + memset(buf, 0, sizeof(buf)); + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + + ret = strict_strtoul(buf, 0, &val); + if (ret) + return ret; + + shrd->dbg_level_dev = val; + if (iwl_alloc_traffic_mem(priv)) + IWL_ERR(priv, "Not enough memory to generate traffic log\n"); + + return count; +} +DEBUGFS_READ_WRITE_FILE_OPS(debug_level); +#endif /* CONFIG_IWLWIFI_DEBUG */ /* * Create the debugfs files and directories @@ -2682,26 +2559,23 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(log_event, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_handlers, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR); + DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(clear_traffic_statistics, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(csr, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR); DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR); @@ -2710,7 +2584,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); @@ -2719,12 +2592,20 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR); if (iwl_advanced_bt_coexist(priv)) DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); +#ifdef CONFIG_IWLWIFI_DEBUG + DEBUGFS_ADD_FILE(debug_level, dir_debug, S_IRUSR | S_IWUSR); +#endif + DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf, &priv->disable_chain_noise_cal); + + if (iwl_trans_dbgfs_register(trans(priv), dir_debug)) + goto err; return 0; err: @@ -2745,6 +2626,3 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) debugfs_remove_recursive(priv->debugfs_dir); priv->debugfs_dir = NULL; } - - - diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 6c9790cac8d0..6c00a447963d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -32,16 +32,15 @@ #define __iwl_dev_h__ #include <linux/interrupt.h> -#include <linux/pci.h> /* for struct pci_device_id */ #include <linux/kernel.h> #include <linux/wait.h> #include <linux/leds.h> +#include <linux/slab.h> #include <net/ieee80211_radiotap.h> #include "iwl-eeprom.h" #include "iwl-csr.h" #include "iwl-prph.h" -#include "iwl-fh.h" #include "iwl-debug.h" #include "iwl-agn-hw.h" #include "iwl-led.h" @@ -50,8 +49,7 @@ #include "iwl-agn-tt.h" #include "iwl-bus.h" #include "iwl-trans.h" - -#define DRV_NAME "iwlagn" +#include "iwl-shared.h" struct iwl_tx_queue; @@ -90,109 +88,6 @@ struct iwl_tx_queue; #define DEFAULT_SHORT_RETRY_LIMIT 7U #define DEFAULT_LONG_RETRY_LIMIT 4U -struct iwl_rx_mem_buffer { - dma_addr_t page_dma; - struct page *page; - struct list_head list; -}; - -#define rxb_addr(r) page_address(r->page) - -/* defined below */ -struct iwl_device_cmd; - -struct iwl_cmd_meta { - /* only for SYNC commands, iff the reply skb is wanted */ - struct iwl_host_cmd *source; - /* - * only for ASYNC commands - * (which is somewhat stupid -- look at iwl-sta.c for instance - * which duplicates a bunch of code because the callback isn't - * invoked for SYNC commands, if it were and its result passed - * through it would be simpler...) - */ - void (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct iwl_rx_packet *pkt); - - u32 flags; - - DEFINE_DMA_UNMAP_ADDR(mapping); - DEFINE_DMA_UNMAP_LEN(len); -}; - -/* - * Generic queue structure - * - * Contains common data for Rx and Tx queues. - * - * Note the difference between n_bd and n_window: the hardware - * always assumes 256 descriptors, so n_bd is always 256 (unless - * there might be HW changes in the future). For the normal TX - * queues, n_window, which is the size of the software queue data - * is also 256; however, for the command queue, n_window is only - * 32 since we don't need so many commands pending. Since the HW - * still uses 256 BDs for DMA though, n_bd stays 256. As a result, - * the software buffers (in the variables @meta, @txb in struct - * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds - * in the same struct) have 256. - * This means that we end up with the following: - * HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 | - * SW entries: | 0 | ... | 31 | - * where N is a number between 0 and 7. This means that the SW - * data is a window overlayed over the HW queue. - */ -struct iwl_queue { - int n_bd; /* number of BDs in this queue */ - int write_ptr; /* 1-st empty entry (index) host_w*/ - int read_ptr; /* last used entry (index) host_r*/ - /* use for monitoring and recovering the stuck queue */ - dma_addr_t dma_addr; /* physical addr for BD's */ - int n_window; /* safe queue window */ - u32 id; - int low_mark; /* low watermark, resume queue if free - * space more than this */ - int high_mark; /* high watermark, stop queue if free - * space less than this */ -}; - -/* One for each TFD */ -struct iwl_tx_info { - struct sk_buff *skb; - struct iwl_rxon_context *ctx; -}; - -/** - * struct iwl_tx_queue - Tx Queue for DMA - * @q: generic Rx/Tx queue descriptor - * @bd: base of circular buffer of TFDs - * @cmd: array of command/TX buffer pointers - * @meta: array of meta data for each command/tx buffer - * @dma_addr_cmd: physical address of cmd/tx buffer array - * @txb: array of per-TFD driver data - * @time_stamp: time (in jiffies) of last read_ptr change - * @need_update: indicates need to update read/write index - * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled - * - * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame - * descriptors) and required locking structures. - */ -#define TFD_TX_CMD_SLOTS 256 -#define TFD_CMD_SLOTS 32 - -struct iwl_tx_queue { - struct iwl_queue q; - struct iwl_tfd *tfds; - struct iwl_device_cmd **cmd; - struct iwl_cmd_meta *meta; - struct iwl_tx_info *txb; - unsigned long time_stamp; - u8 need_update; - u8 sched_retry; - u8 active; - u8 swq_id; -}; - #define IWL_NUM_SCAN_RATES (2) /* @@ -222,20 +117,16 @@ struct iwl_channel_info { u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */ }; -#define IWL_TX_FIFO_BK 0 /* shared */ -#define IWL_TX_FIFO_BE 1 -#define IWL_TX_FIFO_VI 2 /* shared */ -#define IWL_TX_FIFO_VO 3 -#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK -#define IWL_TX_FIFO_BE_IPAN 4 -#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI -#define IWL_TX_FIFO_VO_IPAN 5 -#define IWL_TX_FIFO_UNUSED -1 - -/* Minimum number of queues. MAX_NUM is defined in hw specific files. - * Set the minimum to accommodate the 4 standard TX queues, 1 command - * queue, 2 (unused) HCCA queues, and 4 HT queues (one for each AC) */ -#define IWL_MIN_NUM_QUEUES 10 +/* + * Minimum number of queues. MAX_NUM is defined in hw specific files. + * Set the minimum to accommodate + * - 4 standard TX queues + * - the command queue + * - 4 PAN TX queues + * - the PAN multicast queue, and + * - the AUX (TX during scan dwell) queue. + */ +#define IWL_MIN_NUM_QUEUES 11 /* * Command queue depends on iPAN support. @@ -243,161 +134,20 @@ struct iwl_channel_info { #define IWL_DEFAULT_CMD_QUEUE_NUM 4 #define IWL_IPAN_CMD_QUEUE_NUM 9 -/* - * This queue number is required for proper operation - * because the ucode will stop/start the scheduler as - * required. - */ -#define IWL_IPAN_MCAST_QUEUE 8 - #define IEEE80211_DATA_LEN 2304 #define IEEE80211_4ADDR_LEN 30 #define IEEE80211_HLEN (IEEE80211_4ADDR_LEN) #define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) - -#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) -#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) -#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) - -enum { - CMD_SYNC = 0, - CMD_ASYNC = BIT(0), - CMD_WANT_SKB = BIT(1), - CMD_ON_DEMAND = BIT(2), -}; - -#define DEF_CMD_PAYLOAD_SIZE 320 - -/** - * struct iwl_device_cmd - * - * For allocation of the command and tx queues, this establishes the overall - * size of the largest command we send to uCode, except for commands that - * aren't fully copied and use other TFD space. - */ -struct iwl_device_cmd { - struct iwl_cmd_header hdr; /* uCode API */ - union { - u32 flags; - u8 val8; - u16 val16; - u32 val32; - struct iwl_tx_cmd tx; - struct iwl6000_channel_switch_cmd chswitch; - u8 payload[DEF_CMD_PAYLOAD_SIZE]; - } __packed cmd; -} __packed; - -#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) - -#define IWL_MAX_CMD_TFDS 2 - -enum iwl_hcmd_dataflag { - IWL_HCMD_DFL_NOCOPY = BIT(0), -}; - -/** - * struct iwl_host_cmd - Host command to the uCode - * @data: array of chunks that composes the data of the host command - * @reply_page: pointer to the page that holds the response to the host command - * @callback: - * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC - * @len: array of the lenths of the chunks in data - * @dataflags: - * @id: id of the host command - */ -struct iwl_host_cmd { - const void *data[IWL_MAX_CMD_TFDS]; - unsigned long reply_page; - void (*callback)(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct iwl_rx_packet *pkt); - u32 flags; - u16 len[IWL_MAX_CMD_TFDS]; - u8 dataflags[IWL_MAX_CMD_TFDS]; - u8 id; -}; - #define SUP_RATE_11A_MAX_NUM_CHANNELS 8 #define SUP_RATE_11B_MAX_NUM_CHANNELS 4 #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 -/** - * struct iwl_rx_queue - Rx queue - * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) - * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) - * @read: Shared index to newest available Rx buffer - * @write: Shared index to oldest written Rx packet - * @free_count: Number of pre-allocated buffers in rx_free - * @rx_free: list of free SKBs for use - * @rx_used: List of Rx buffers with no SKB - * @need_update: flag to indicate we need to update read/write index - * @rb_stts: driver's pointer to receive buffer status - * @rb_stts_dma: bus address of receive buffer status - * - * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers - */ -struct iwl_rx_queue { - __le32 *bd; - dma_addr_t bd_dma; - struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; - struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; - u32 read; - u32 write; - u32 free_count; - u32 write_actual; - struct list_head rx_free; - struct list_head rx_used; - int need_update; - struct iwl_rb_status *rb_stts; - dma_addr_t rb_stts_dma; - spinlock_t lock; -}; - #define IWL_SUPPORTED_RATES_IE_LEN 8 -#define MAX_TID_COUNT 9 - #define IWL_INVALID_RATE 0xFF #define IWL_INVALID_VALUE -1 -/** - * struct iwl_ht_agg -- aggregation status while waiting for block-ack - * @txq_id: Tx queue used for Tx attempt - * @frame_count: # frames attempted by Tx command - * @wait_for_ba: Expect block-ack before next Tx reply - * @start_idx: Index of 1st Transmit Frame Descriptor (TFD) in Tx window - * @bitmap0: Low order bitmap, one bit for each frame pending ACK in Tx window - * @bitmap1: High order, one bit for each frame pending ACK in Tx window - * @rate_n_flags: Rate at which Tx was attempted - * - * If REPLY_TX indicates that aggregation was attempted, driver must wait - * for block ack (REPLY_COMPRESSED_BA). This struct stores tx reply info - * until block ack arrives. - */ -struct iwl_ht_agg { - u16 txq_id; - u16 frame_count; - u16 wait_for_ba; - u16 start_idx; - u64 bitmap; - u32 rate_n_flags; -#define IWL_AGG_OFF 0 -#define IWL_AGG_ON 1 -#define IWL_EMPTYING_HW_QUEUE_ADDBA 2 -#define IWL_EMPTYING_HW_QUEUE_DELBA 3 - u8 state; - u8 tx_fifo; -}; - - -struct iwl_tid_data { - u16 seq_number; /* agn only */ - u16 tfds_in_queue; - struct iwl_ht_agg agg; -}; - union iwl_ht_rate_supp { u16 rates; struct { @@ -448,16 +198,10 @@ struct iwl_qos_info { */ struct iwl_station_entry { struct iwl_addsta_cmd sta; - struct iwl_tid_data tid[MAX_TID_COUNT]; u8 used, ctxid; struct iwl_link_quality_cmd *lq; }; -struct iwl_station_priv_common { - struct iwl_rxon_context *ctx; - u8 sta_id; -}; - /* * iwl_station_priv: Driver's private station information * @@ -466,12 +210,13 @@ struct iwl_station_priv_common { * space. */ struct iwl_station_priv { - struct iwl_station_priv_common common; + struct iwl_rxon_context *ctx; struct iwl_lq_sta lq_sta; atomic_t pending_frames; bool client; bool asleep; u8 max_agg_bufsize; + u8 sta_id; }; /** @@ -564,11 +309,13 @@ enum iwl_ucode_tlv_type { * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID, * treats good CRC threshold as a boolean * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w). + * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. */ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_PAN = BIT(0), IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1), IWL_UCODE_TLV_FLAGS_MFP = BIT(2), + IWL_UCODE_TLV_FLAGS_P2P = BIT(3), }; struct iwl_ucode_tlv { @@ -634,54 +381,6 @@ struct iwl_sensitivity_ranges { #define CELSIUS_TO_KELVIN(x) ((x)+273) -/** - * struct iwl_hw_params - * @max_txq_num: Max # Tx queues supported - * @scd_bc_tbls_size: size of scheduler byte count tables - * @tfd_size: TFD size - * @tx/rx_chains_num: Number of TX/RX chains - * @valid_tx/rx_ant: usable antennas - * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) - * @max_rxq_log: Log-base-2 of max_rxq_size - * @rx_page_order: Rx buffer page order - * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR - * @max_stations: - * @ht40_channel: is 40MHz width possible in band 2.4 - * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ) - * @sw_crypto: 0 for hw, 1 for sw - * @max_xxx_size: for ucode uses - * @ct_kill_threshold: temperature threshold - * @beacon_time_tsf_bits: number of valid tsf bits for beacon time - * @calib_init_cfg: setup initial calibrations for the hw - * @calib_rt_cfg: setup runtime calibrations for the hw - * @struct iwl_sensitivity_ranges: range of sensitivity values - */ -struct iwl_hw_params { - u8 max_txq_num; - u16 scd_bc_tbls_size; - u32 tfd_size; - u8 tx_chains_num; - u8 rx_chains_num; - u8 valid_tx_ant; - u8 valid_rx_ant; - u16 max_rxq_size; - u16 max_rxq_log; - u32 rx_page_order; - u8 max_stations; - u8 ht40_channel; - u8 max_beacon_itrvl; /* in 1024 ms */ - u32 max_inst_size; - u32 max_data_size; - u32 ct_kill_threshold; /* value in hw-dependent units */ - u32 ct_kill_exit_threshold; /* value in hw-dependent units */ - /* for 1000, 6000 series and up */ - u16 beacon_time_tsf_bits; - u32 calib_init_cfg; - u32 calib_rt_cfg; - const struct iwl_sensitivity_ranges *sens; -}; - - /****************************************************************************** * * Functions implemented in core module which are forward declared here @@ -697,35 +396,12 @@ struct iwl_hw_params { ****************************************************************************/ extern void iwl_update_chain_flags(struct iwl_priv *priv); extern const u8 iwl_bcast_addr[ETH_ALEN]; -extern int iwl_queue_space(const struct iwl_queue *q); -static inline int iwl_queue_used(const struct iwl_queue *q, int i) -{ - return q->write_ptr >= q->read_ptr ? - (i >= q->read_ptr && i < q->write_ptr) : - !(i < q->read_ptr && i >= q->write_ptr); -} - - -static inline u8 get_cmd_index(struct iwl_queue *q, u32 index) -{ - return index & (q->n_window - 1); -} - - -struct iwl_dma_ptr { - dma_addr_t dma; - void *addr; - size_t size; -}; #define IWL_OPERATION_MODE_AUTO 0 #define IWL_OPERATION_MODE_HT_ONLY 1 #define IWL_OPERATION_MODE_MIXED 2 #define IWL_OPERATION_MODE_20MHZ 3 -#define IWL_TX_CRC_SIZE 4 -#define IWL_TX_DELIMITER_SIZE 4 - #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 /* Sensitivity and chain noise calibration */ @@ -849,9 +525,6 @@ struct iwl_chain_noise_data { #define EEPROM_SEM_TIMEOUT 10 /* milliseconds */ #define EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ -#define IWL_TRAFFIC_ENTRIES (256) -#define IWL_TRAFFIC_ENTRY_SIZE (64) - enum { MEASUREMENT_READY = (1 << 0), MEASUREMENT_ACTIVE = (1 << 1), @@ -884,22 +557,6 @@ enum iwl_pa_type { IWL_PA_INTERNAL = 1, }; -/* interrupt statistics */ -struct isr_statistics { - u32 hw; - u32 sw; - u32 err_code; - u32 sch; - u32 alive; - u32 rfkill; - u32 ctkill; - u32 wakeup; - u32 rx; - u32 rx_handlers[REPLY_MAX]; - u32 tx; - u32 unhandled; -}; - /* reply_tx_statistics (for _agn devices) */ struct reply_tx_error_statistics { u32 pp_delay; @@ -1009,21 +666,6 @@ struct iwl_event_log { }; /* - * host interrupt timeout value - * used with setting interrupt coalescing timer - * the CSR_INT_COALESCING is an 8 bit register in 32-usec unit - * - * default interrupt coalescing timer is 64 x 32 = 2048 usecs - * default interrupt coalescing calibration timer is 16 x 32 = 512 usecs - */ -#define IWL_HOST_INT_TIMEOUT_MAX (0xFF) -#define IWL_HOST_INT_TIMEOUT_DEF (0x40) -#define IWL_HOST_INT_TIMEOUT_MIN (0x0) -#define IWL_HOST_INT_CALIB_TIMEOUT_MAX (0xFF) -#define IWL_HOST_INT_CALIB_TIMEOUT_DEF (0x10) -#define IWL_HOST_INT_CALIB_TIMEOUT_MIN (0x0) - -/* * This is the threshold value of plcp error rate per 100mSecs. It is * used to set and check for the validity of plcp_delta. */ @@ -1101,20 +743,9 @@ struct iwl_notification_wait { bool triggered, aborted; }; -enum iwl_rxon_context_id { - IWL_RXON_CTX_BSS, - IWL_RXON_CTX_PAN, - - NUM_IWL_RXON_CTX -}; - struct iwl_rxon_context { struct ieee80211_vif *vif; - const u8 *ac_to_fifo; - const u8 *ac_to_queue; - u8 mcast_queue; - /* * We could use the vif to indicate active, but we * also need it to be active during disabling when @@ -1162,13 +793,16 @@ struct iwl_rxon_context { u8 extension_chan_offset; } ht; + u8 bssid[ETH_ALEN]; + bool preauth_bssid; + bool last_tx_rejected; }; enum iwl_scan_type { IWL_SCAN_NORMAL, IWL_SCAN_RADIO_RESET, - IWL_SCAN_OFFCH_TX, + IWL_SCAN_ROC, }; enum iwlagn_ucode_type { @@ -1190,24 +824,26 @@ struct iwl_testmode_trace { }; #endif -/* uCode ownership */ -#define IWL_OWNERSHIP_DRIVER 0 -#define IWL_OWNERSHIP_TM 1 - struct iwl_priv { + /*data shared among all the driver's layers */ + struct iwl_shared _shrd; + struct iwl_shared *shrd; + /* ieee device used by generic ieee processing code */ struct ieee80211_hw *hw; struct ieee80211_channel *ieee_channels; struct ieee80211_rate *ieee_rates; + struct kmem_cache *tx_cmd_pool; struct iwl_cfg *cfg; enum ieee80211_band band; void (*pre_rx_handler)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); - void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb); + int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; @@ -1225,6 +861,9 @@ struct iwl_priv { /* jiffies when last recovery from statistics was performed */ unsigned long rx_statistics_jiffies; + /*counters */ + u32 rx_handlers_stats[REPLY_MAX]; + /* force reset */ struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET]; @@ -1238,7 +877,7 @@ struct iwl_priv { u8 channel_count; /* # of channels */ /* thermal calibration */ - s32 temperature; /* degrees Kelvin */ + s32 temperature; /* Celsius */ s32 last_temperature; /* init calibration results */ @@ -1255,21 +894,6 @@ struct iwl_priv { u8 scan_tx_ant[IEEE80211_NUM_BANDS]; u8 mgmt_tx_ant; - /* spinlock */ - spinlock_t lock; /* protect general shared data */ - spinlock_t hcmd_lock; /* protect hcmd */ - spinlock_t reg_lock; /* protect hw register access */ - struct mutex mutex; - - struct iwl_bus *bus; /* bus specific data */ - struct iwl_trans trans; - - /* microcode/device supports multiple contexts */ - u8 valid_contexts; - - /* command queue number */ - u8 cmd_queue; - /* max number of station keys */ u8 sta_key_max_num; @@ -1283,9 +907,6 @@ struct iwl_priv { u32 ucode_ver; /* version of ucode, copy of iwl_ucode.ver */ - /* uCode owner: default: IWL_OWNERSHIP_DRIVER */ - u8 ucode_owner; - struct fw_img ucode_rt; struct fw_img ucode_init; struct fw_img ucode_wowlan; @@ -1317,52 +938,25 @@ struct iwl_priv { /* Rate scaling data */ u8 retry_rate; - wait_queue_head_t wait_command_queue; - int activity_timer_active; - /* Rx and Tx DMA processing queues */ - struct iwl_rx_queue rxq; - struct iwl_tx_queue *txq; - unsigned long txq_ctx_active_msk; - struct iwl_dma_ptr kw; /* keep warm address */ - struct iwl_dma_ptr scd_bc_tbls; - - u32 scd_base_addr; /* scheduler sram base address */ - - unsigned long status; - /* counts mgmt, ctl, and data packets */ struct traffic_stats tx_stats; struct traffic_stats rx_stats; - /* counts interrupts */ - struct isr_statistics isr_stats; - struct iwl_power_mgr power_data; struct iwl_tt_mgmt thermal_throttle; /* station table variables */ - - /* Note: if lock and sta_lock are needed, lock must be acquired first */ - spinlock_t sta_lock; int num_stations; struct iwl_station_entry stations[IWLAGN_STATION_COUNT]; unsigned long ucode_key_table; - /* queue refcounts */ -#define IWL_MAX_HW_QUEUES 32 - unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; - /* for each AC */ - atomic_t queue_stop_count[4]; + u8 mac80211_registered; /* Indication if ieee80211_ops->open has been called */ u8 is_open; - u8 mac80211_registered; - - bool wowlan; - /* eeprom -- this is in the card's little endian byte order */ u8 *eeprom; int nvm_device_type; @@ -1398,14 +992,6 @@ struct iwl_priv { } accum_stats, delta_stats, max_delta_stats; #endif - /* INT ICT Table */ - __le32 *ict_tbl; - void *ict_tbl_vir; - dma_addr_t ict_tbl_dma; - dma_addr_t aligned_ict_tbl_dma; - int ict_index; - u32 inta; - bool use_ict; /* * reporting the number of tids has AGG on. 0 means * no AGGREGATION @@ -1438,14 +1024,10 @@ struct iwl_priv { /* remain-on-channel offload support */ struct ieee80211_channel *hw_roc_channel; - struct delayed_work hw_roc_work; + struct delayed_work hw_roc_disable_work; enum nl80211_channel_type hw_roc_chantype; int hw_roc_duration; - bool hw_roc_setup; - - struct sk_buff *offchan_tx_skb; - int offchan_tx_timeout; - struct ieee80211_channel *offchan_tx_chan; + bool hw_roc_setup, hw_roc_start_notified; /* bt coex */ u8 bt_enable_flag; @@ -1466,15 +1048,8 @@ struct iwl_priv { struct iwl_rxon_context *cur_rssi_ctx; bool bt_is_sco; - struct iwl_hw_params hw_params; - - u32 inta_mask; - - struct workqueue_struct *workqueue; - struct work_struct restart; struct work_struct scan_completed; - struct work_struct rx_replenish; struct work_struct abort_scan; struct work_struct beacon_update; @@ -1490,8 +1065,6 @@ struct iwl_priv { struct work_struct bt_full_concurrency; struct work_struct bt_runtime_config; - struct tasklet_struct irq_tasklet; - struct delayed_work scan_check; /* TX Power */ @@ -1500,12 +1073,6 @@ struct iwl_priv { s8 tx_power_lmt_in_half_dbm; /* max tx power in half-dBm format */ s8 tx_power_next; - -#ifdef CONFIG_IWLWIFI_DEBUG - /* debugging info */ - u32 debug_level; /* per device debugging will override global - iwl_debug_level if set */ -#endif /* CONFIG_IWLWIFI_DEBUG */ #ifdef CONFIG_IWLWIFI_DEBUGFS /* debugfs */ u16 tx_traffic_idx; @@ -1543,47 +1110,7 @@ struct iwl_priv { bool have_rekey_data; }; /*iwl_priv */ -static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id) -{ - set_bit(txq_id, &priv->txq_ctx_active_msk); -} - -static inline void iwl_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id) -{ - clear_bit(txq_id, &priv->txq_ctx_active_msk); -} - -#ifdef CONFIG_IWLWIFI_DEBUG -/* - * iwl_get_debug_level: Return active debug level for device - * - * Using sysfs it is possible to set per device debug level. This debug - * level will be used if set, otherwise the global debug level which can be - * set via module parameter is used. - */ -static inline u32 iwl_get_debug_level(struct iwl_priv *priv) -{ - if (priv->debug_level) - return priv->debug_level; - else - return iwl_debug_level; -} -#else -static inline u32 iwl_get_debug_level(struct iwl_priv *priv) -{ - return iwl_debug_level; -} -#endif - - -static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv, - int txq_id, int idx) -{ - if (priv->txq[txq_id].txb[idx].skb) - return (struct ieee80211_hdr *)priv->txq[txq_id]. - txb[idx].skb->data; - return NULL; -} +extern struct iwl_mod_params iwlagn_mod_params; static inline struct iwl_rxon_context * iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif) @@ -1596,7 +1123,7 @@ iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif) #define for_each_context(priv, ctx) \ for (ctx = &priv->contexts[IWL_RXON_CTX_BSS]; \ ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++) \ - if (priv->valid_contexts & BIT(ctx->ctxid)) + if (priv->shrd->valid_contexts & BIT(ctx->ctxid)) static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx) { @@ -1650,13 +1177,4 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } -static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page) -{ - __free_pages(page, priv->hw_params.rx_page_order); -} - -static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page) -{ - free_pages(page, priv->hw_params.rx_page_order); -} #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 2c84ba95afca..8a51c5ccda1e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -29,6 +29,8 @@ #include <linux/tracepoint.h> +struct iwl_priv; + #if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__) #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) \ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 19d31a5e32e5..a4e43bd4a547 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -72,6 +72,7 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-debug.h" +#include "iwl-agn.h" #include "iwl-eeprom.h" #include "iwl-io.h" @@ -138,7 +139,7 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ /****************************************************************************** * - * EEPROM related functions + * generic NVM functions * ******************************************************************************/ @@ -155,11 +156,11 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) { /* Request semaphore */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, + ret = iwl_poll_bit(bus(priv), CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, EEPROM_SEM_TIMEOUT); @@ -176,14 +177,14 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv) static void iwl_eeprom_release_semaphore(struct iwl_priv *priv) { - iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl_clear_bit(bus(priv), CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); } static int iwl_eeprom_verify_signature(struct iwl_priv *priv) { - u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; + u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; int ret = 0; IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp); @@ -214,19 +215,106 @@ static int iwl_eeprom_verify_signature(struct iwl_priv *priv) return ret; } +u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) +{ + if (!priv->eeprom) + return 0; + return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); +} + +int iwl_eeprom_check_version(struct iwl_priv *priv) +{ + u16 eeprom_ver; + u16 calib_ver; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + calib_ver = iwlagn_eeprom_calib_version(priv); + + if (eeprom_ver < priv->cfg->eeprom_ver || + calib_ver < priv->cfg->eeprom_calib_ver) + goto err; + + IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n", + eeprom_ver, calib_ver); + + return 0; +err: + IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x " + "CALIB=0x%x < 0x%x\n", + eeprom_ver, priv->cfg->eeprom_ver, + calib_ver, priv->cfg->eeprom_calib_ver); + return -EINVAL; + +} + +int iwl_eeprom_check_sku(struct iwl_priv *priv) +{ + u16 radio_cfg; + + if (!priv->cfg->sku) { + /* not using sku overwrite */ + priv->cfg->sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP); + if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE && + !priv->cfg->ht_params) { + IWL_ERR(priv, "Invalid 11n configuration\n"); + return -EINVAL; + } + } + if (!priv->cfg->sku) { + IWL_ERR(priv, "Invalid device sku\n"); + return -EINVAL; + } + + IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku); + + if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) { + /* not using .cfg overwrite */ + radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG); + priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg); + priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg); + if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) { + IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n", + priv->cfg->valid_tx_ant, + priv->cfg->valid_rx_ant); + return -EINVAL; + } + IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n", + priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant); + } + /* + * for some special cases, + * EEPROM did not reflect the correct antenna setting + * so overwrite the valid tx/rx antenna from .cfg + */ + return 0; +} + +void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac) +{ + const u8 *addr = iwl_eeprom_query_addr(priv, + EEPROM_MAC_ADDRESS); + memcpy(mac, addr, ETH_ALEN); +} + +/****************************************************************************** + * + * OTP related functions + * +******************************************************************************/ + static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode) { - iwl_read32(priv, CSR_OTP_GP_REG); + iwl_read32(bus(priv), CSR_OTP_GP_REG); if (mode == IWL_OTP_ACCESS_ABSOLUTE) - iwl_clear_bit(priv, CSR_OTP_GP_REG, + iwl_clear_bit(bus(priv), CSR_OTP_GP_REG, CSR_OTP_GP_REG_OTP_ACCESS_MODE); else - iwl_set_bit(priv, CSR_OTP_GP_REG, + iwl_set_bit(bus(priv), CSR_OTP_GP_REG, CSR_OTP_GP_REG_OTP_ACCESS_MODE); } -static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) +static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) { u32 otpgp; int nvm_type; @@ -243,7 +331,7 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev) nvm_type = NVM_DEVICE_TYPE_EEPROM; break; default: - otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) nvm_type = NVM_DEVICE_TYPE_OTP; else @@ -258,22 +346,22 @@ static int iwl_init_otp_access(struct iwl_priv *priv) int ret; /* Enable 40MHz radio clock */ - iwl_write32(priv, CSR_GP_CNTRL, - iwl_read32(priv, CSR_GP_CNTRL) | + iwl_write32(bus(priv), CSR_GP_CNTRL, + iwl_read32(bus(priv), CSR_GP_CNTRL) | CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock to be ready */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) IWL_ERR(priv, "Time out access OTP\n"); else { - iwl_set_bits_prph(priv, APMG_PS_CTRL_REG, + iwl_set_bits_prph(bus(priv), APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_prph(priv, APMG_PS_CTRL_REG, + iwl_clear_bits_prph(bus(priv), APMG_PS_CTRL_REG, APMG_PS_CTRL_VAL_RESET_REQ); /* @@ -281,7 +369,7 @@ static int iwl_init_otp_access(struct iwl_priv *priv) * this is only applicable for HW with OTP shadow RAM */ if (priv->cfg->base_params->shadow_ram_support) - iwl_set_bit(priv, CSR_DBG_LINK_PWR_MGMT_REG, + iwl_set_bit(bus(priv), CSR_DBG_LINK_PWR_MGMT_REG, CSR_RESET_LINK_PWR_MGMT_DISABLED); } return ret; @@ -293,9 +381,9 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat u32 r; u32 otpgp; - iwl_write32(priv, CSR_EEPROM_REG, + iwl_write32(bus(priv), CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(priv, CSR_EEPROM_REG, + ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); @@ -303,13 +391,13 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat IWL_ERR(priv, "Time out reading OTP[%d]\n", addr); return ret; } - r = iwl_read32(priv, CSR_EEPROM_REG); + r = iwl_read32(bus(priv), CSR_EEPROM_REG); /* check for ECC errors: */ - otpgp = iwl_read32(priv, CSR_OTP_GP_REG); + otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { /* stop in this case */ /* set the uncorrectable OTP ECC bit for acknowledgement */ - iwl_set_bit(priv, CSR_OTP_GP_REG, + iwl_set_bit(bus(priv), CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n"); return -EINVAL; @@ -317,7 +405,7 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { /* continue in this case */ /* set the correctable OTP ECC bit for acknowledgement */ - iwl_set_bit(priv, CSR_OTP_GP_REG, + iwl_set_bit(bus(priv), CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); IWL_ERR(priv, "Correctable OTP ECC error, continue read\n"); } @@ -407,11 +495,152 @@ static int iwl_find_otp_image(struct iwl_priv *priv, return -EINVAL; } -u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) +/****************************************************************************** + * + * Tx Power related functions + * +******************************************************************************/ +/** + * iwl_get_max_txpower_avg - get the highest tx power from all chains. + * find the highest tx power from all chains for the channel + */ +static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *enhanced_txpower, + int element, s8 *max_txpower_in_half_dbm) { - if (!priv->eeprom) - return 0; - return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8); + s8 max_txpower_avg = 0; /* (dBm) */ + + /* Take the highest tx power from any valid chains */ + if ((priv->cfg->valid_tx_ant & ANT_A) && + (enhanced_txpower[element].chain_a_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_a_max; + if ((priv->cfg->valid_tx_ant & ANT_B) && + (enhanced_txpower[element].chain_b_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_b_max; + if ((priv->cfg->valid_tx_ant & ANT_C) && + (enhanced_txpower[element].chain_c_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].chain_c_max; + if (((priv->cfg->valid_tx_ant == ANT_AB) | + (priv->cfg->valid_tx_ant == ANT_BC) | + (priv->cfg->valid_tx_ant == ANT_AC)) && + (enhanced_txpower[element].mimo2_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo2_max; + if ((priv->cfg->valid_tx_ant == ANT_ABC) && + (enhanced_txpower[element].mimo3_max > max_txpower_avg)) + max_txpower_avg = enhanced_txpower[element].mimo3_max; + + /* + * max. tx power in EEPROM is in 1/2 dBm format + * convert from 1/2 dBm to dBm (round-up convert) + * but we also do not want to loss 1/2 dBm resolution which + * will impact performance + */ + *max_txpower_in_half_dbm = max_txpower_avg; + return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1); +} + +static void +iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv, + struct iwl_eeprom_enhanced_txpwr *txp, + s8 max_txpower_avg) +{ + int ch_idx; + bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ; + enum ieee80211_band band; + + band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ? + IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ; + + for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) { + struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx]; + + /* update matching channel or from common data only */ + if (txp->channel != 0 && ch_info->channel != txp->channel) + continue; + + /* update matching band only */ + if (band != ch_info->band) + continue; + + if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) { + ch_info->max_power_avg = max_txpower_avg; + ch_info->curr_txpow = max_txpower_avg; + ch_info->scan_power = max_txpower_avg; + } + + if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg) + ch_info->ht40_max_power_avg = max_txpower_avg; + } +} + +#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT) +#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr) +#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE) + +#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \ + ? # x " " : "") + +void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv) +{ + struct iwl_eeprom_enhanced_txpwr *txp_array, *txp; + int idx, entries; + __le16 *txp_len; + s8 max_txp_avg, max_txp_avg_halfdbm; + + BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8); + + /* the length is in 16-bit words, but we want entries */ + txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS); + entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN; + + txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS); + + for (idx = 0; idx < entries; idx++) { + txp = &txp_array[idx]; + /* skip invalid entries */ + if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID)) + continue; + + IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n", + (txp->channel && (txp->flags & + IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ? + "Common " : (txp->channel) ? + "Channel" : "Common", + (txp->channel), + TXP_CHECK_AND_PRINT(VALID), + TXP_CHECK_AND_PRINT(BAND_52G), + TXP_CHECK_AND_PRINT(OFDM), + TXP_CHECK_AND_PRINT(40MHZ), + TXP_CHECK_AND_PRINT(HT_AP), + TXP_CHECK_AND_PRINT(RES1), + TXP_CHECK_AND_PRINT(RES2), + TXP_CHECK_AND_PRINT(COMMON_TYPE), + txp->flags); + IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x " + "chain_B: 0X%02x chain_C: 0X%02x\n", + txp->chain_a_max, txp->chain_b_max, + txp->chain_c_max); + IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x " + "MIMO3: 0x%02x High 20_on_40: 0x%02x " + "Low 20_on_40: 0x%02x\n", + txp->mimo2_max, txp->mimo3_max, + ((txp->delta_20_in_40 & 0xf0) >> 4), + (txp->delta_20_in_40 & 0x0f)); + + max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx, + &max_txp_avg_halfdbm); + + /* + * Update the user limit values values to the highest + * power supported by any channel + */ + if (max_txp_avg > priv->tx_power_user_lmt) + priv->tx_power_user_lmt = max_txp_avg; + if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm) + priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm; + + iwl_eeprom_enh_txp_read_element(priv, txp, max_txp_avg); + } } /** @@ -424,14 +653,14 @@ u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset) int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) { __le16 *e; - u32 gp = iwl_read32(priv, CSR_EEPROM_GP); + u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP); int sz; int ret; u16 addr; u16 validblockaddr = 0; u16 cache_addr = 0; - priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev); + priv->nvm_device_type = iwl_get_nvm_type(priv, hw_rev); if (priv->nvm_device_type == -ENOENT) return -ENOENT; /* allocate eeprom */ @@ -469,11 +698,11 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) ret = -ENOENT; goto done; } - iwl_write32(priv, CSR_EEPROM_GP, - iwl_read32(priv, CSR_EEPROM_GP) & + iwl_write32(bus(priv), CSR_EEPROM_GP, + iwl_read32(bus(priv), CSR_EEPROM_GP) & ~CSR_EEPROM_GP_IF_OWNER_MSK); - iwl_set_bit(priv, CSR_OTP_GP_REG, + iwl_set_bit(bus(priv), CSR_OTP_GP_REG, CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); /* traversing the linked list if no shadow ram supported */ @@ -498,10 +727,10 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - iwl_write32(priv, CSR_EEPROM_REG, + iwl_write32(bus(priv), CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(priv, CSR_EEPROM_REG, + ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG, CSR_EEPROM_REG_READ_VALID_MSK, CSR_EEPROM_REG_READ_VALID_MSK, IWL_EEPROM_ACCESS_TIMEOUT); @@ -509,7 +738,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev) IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr); goto done; } - r = iwl_read32(priv, CSR_EEPROM_REG); + r = iwl_read32(bus(priv), CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } @@ -670,8 +899,9 @@ int iwl_init_channel_map(struct iwl_priv *priv) IWL_DEBUG_EEPROM(priv, "Parsing data for %d channels.\n", priv->channel_count); - priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) * - priv->channel_count, GFP_KERNEL); + priv->channel_info = kcalloc(priv->channel_count, + sizeof(struct iwl_channel_info), + GFP_KERNEL); if (!priv->channel_info) { IWL_ERR(priv, "Could not allocate channel_info\n"); priv->channel_count = 0; @@ -838,7 +1068,7 @@ void iwl_rf_config(struct iwl_priv *priv) /* write radio config values to register */ if (EEPROM_RF_CFG_TYPE_MSK(radio_cfg) <= EEPROM_RF_CONFIG_TYPE_MAX) { - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, EEPROM_RF_CFG_TYPE_MSK(radio_cfg) | EEPROM_RF_CFG_STEP_MSK(radio_cfg) | EEPROM_RF_CFG_DASH_MSK(radio_cfg)); @@ -850,7 +1080,7 @@ void iwl_rf_config(struct iwl_priv *priv) WARN_ON(1); /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, + iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG, CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); } diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index e4bf8ac5e64e..c94747e7299e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -163,11 +163,19 @@ struct iwl_eeprom_enhanced_txpwr { } __packed; /* calibration */ +struct iwl_eeprom_calib_hdr { + u8 version; + u8 pa_type; + __le16 voltage; +} __packed; + #define EEPROM_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) #define EEPROM_XTAL ((2*0x128) | EEPROM_CALIB_ALL) /* temperature */ -#define EEPROM_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL) +#define EEPROM_KELVIN_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL) +#define EEPROM_RAW_TEMPERATURE ((2*0x12B) | EEPROM_CALIB_ALL) + /* agn links */ #define EEPROM_LINK_HOST (2*0x64) @@ -301,7 +309,6 @@ void iwl_eeprom_free(struct iwl_priv *priv); int iwl_eeprom_check_version(struct iwl_priv *priv); int iwl_eeprom_check_sku(struct iwl_priv *priv); const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset); -int iwlcore_eeprom_verify_signature(struct iwl_priv *priv); u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset); int iwl_init_channel_map(struct iwl_priv *priv); void iwl_free_channel_map(struct iwl_priv *priv); diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 0ad60b3c04db..5bede9d7f955 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -63,6 +63,8 @@ #ifndef __iwl_fh_h__ #define __iwl_fh_h__ +#include <linux/types.h> + /****************************/ /* Flow Handler Definitions */ /****************************/ @@ -266,8 +268,6 @@ #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) -#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ - /** * Rx Shared Status Registers (RSSR) * @@ -422,10 +422,6 @@ #define RX_FREE_BUFFERS 64 #define RX_LOW_WATERMARK 8 -/* Size of one Rx buffer in host DRAM */ -#define IWL_RX_BUF_SIZE_4K (4 * 1024) -#define IWL_RX_BUF_SIZE_8K (8 * 1024) - /** * struct iwl_rb_status - reseve buffer status * host memory mapped FH registers @@ -508,4 +504,16 @@ struct iwl_tfd { /* Keep Warm Size */ #define IWL_KW_SIZE 0x1000 /* 4k */ +/* Fixed (non-configurable) rx data from phy */ + +/** + * struct iwlagn_schedq_bc_tbl scheduler byte count table + * base physical address provided by SCD_DRAM_BASE_ADDR + * @tfd_offset 0-12 - tx command byte count + * 12-16 - station index + */ +struct iwlagn_scd_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; +} __packed; + #endif /* !__iwl_fh_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h deleted file mode 100644 index 9d91552d13c1..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ /dev/null @@ -1,184 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#ifndef __iwl_helpers_h__ -#define __iwl_helpers_h__ - -#include <linux/ctype.h> -#include <net/mac80211.h> - -#include "iwl-io.h" - -#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) - - -static inline struct ieee80211_conf *ieee80211_get_hw_conf( - struct ieee80211_hw *hw) -{ - return &hw->conf; -} - -/** - * iwl_queue_inc_wrap - increment queue index, wrap back to beginning - * @index -- current index - * @n_bd -- total number of entries in queue (must be power of 2) - */ -static inline int iwl_queue_inc_wrap(int index, int n_bd) -{ - return ++index & (n_bd - 1); -} - -/** - * iwl_queue_dec_wrap - decrement queue index, wrap back to end - * @index -- current index - * @n_bd -- total number of entries in queue (must be power of 2) - */ -static inline int iwl_queue_dec_wrap(int index, int n_bd) -{ - return --index & (n_bd - 1); -} - -/* - * we have 8 bits used like this: - * - * 7 6 5 4 3 2 1 0 - * | | | | | | | | - * | | | | | | +-+-------- AC queue (0-3) - * | | | | | | - * | +-+-+-+-+------------ HW queue ID - * | - * +---------------------- unused - */ -static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq) -{ - BUG_ON(ac > 3); /* only have 2 bits */ - BUG_ON(hwq > 31); /* only use 5 bits */ - - txq->swq_id = (hwq << 2) | ac; -} - -static inline void iwl_wake_queue(struct iwl_priv *priv, - struct iwl_tx_queue *txq) -{ - u8 queue = txq->swq_id; - u8 ac = queue & 3; - u8 hwq = (queue >> 2) & 0x1f; - - if (test_and_clear_bit(hwq, priv->queue_stopped)) - if (atomic_dec_return(&priv->queue_stop_count[ac]) <= 0) - ieee80211_wake_queue(priv->hw, ac); -} - -static inline void iwl_stop_queue(struct iwl_priv *priv, - struct iwl_tx_queue *txq) -{ - u8 queue = txq->swq_id; - u8 ac = queue & 3; - u8 hwq = (queue >> 2) & 0x1f; - - if (!test_and_set_bit(hwq, priv->queue_stopped)) - if (atomic_inc_return(&priv->queue_stop_count[ac]) > 0) - ieee80211_stop_queue(priv->hw, ac); -} - -static inline void iwl_wake_any_queue(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - u8 ac; - - for (ac = 0; ac < AC_NUM; ac++) { - IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n", - ac, (atomic_read(&priv->queue_stop_count[ac]) > 0) - ? "stopped" : "awake"); - iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]); - } -} - -#ifdef ieee80211_stop_queue -#undef ieee80211_stop_queue -#endif - -#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue - -#ifdef ieee80211_wake_queue -#undef ieee80211_wake_queue -#endif - -#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue - -static inline void iwl_disable_interrupts(struct iwl_priv *priv) -{ - clear_bit(STATUS_INT_ENABLED, &priv->status); - - /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* acknowledge/clear/reset any interrupts still pending - * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(priv, CSR_INT, 0xffffffff); - iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); - IWL_DEBUG_ISR(priv, "Disabled interrupts\n"); -} - -static inline void iwl_enable_rfkill_int(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n"); - iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); -} - -static inline void iwl_enable_interrupts(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR(priv, "Enabling interrupts\n"); - set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, priv->inta_mask); -} - -/** - * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time - * @priv -- pointer to iwl_priv data structure - * @tsf_bits -- number of bits need to shift for masking) - */ -static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv, - u16 tsf_bits) -{ - return (1 << tsf_bits) - 1; -} - -/** - * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time - * @priv -- pointer to iwl_priv data structure - * @tsf_bits -- number of bits need to shift for masking) - */ -static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv, - u16 tsf_bits) -{ - return ((1 << (32 - tsf_bits)) - 1) << tsf_bits; -} - -#endif /* __iwl_helpers_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index aa4a90674452..3ffa8e62b856 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -25,46 +25,50 @@ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ +#include <linux/delay.h> +#include <linux/device.h> #include "iwl-io.h" +#include"iwl-csr.h" +#include "iwl-debug.h" #define IWL_POLL_INTERVAL 10 /* microseconds */ -static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +static inline void __iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask) { - iwl_write32(priv, reg, iwl_read32(priv, reg) | mask); + iwl_write32(bus, reg, iwl_read32(bus, reg) | mask); } -static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +static inline void __iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask) { - iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask); + iwl_write32(bus, reg, iwl_read32(bus, reg) & ~mask); } -void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask) +void iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask) { unsigned long flags; - spin_lock_irqsave(&priv->reg_lock, flags); - __iwl_set_bit(priv, reg, mask); - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_lock_irqsave(&bus->reg_lock, flags); + __iwl_set_bit(bus, reg, mask); + spin_unlock_irqrestore(&bus->reg_lock, flags); } -void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask) +void iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask) { unsigned long flags; - spin_lock_irqsave(&priv->reg_lock, flags); - __iwl_clear_bit(priv, reg, mask); - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_lock_irqsave(&bus->reg_lock, flags); + __iwl_clear_bit(bus, reg, mask); + spin_unlock_irqrestore(&bus->reg_lock, flags); } -int iwl_poll_bit(struct iwl_priv *priv, u32 addr, +int iwl_poll_bit(struct iwl_bus *bus, u32 addr, u32 bits, u32 mask, int timeout) { int t = 0; do { - if ((iwl_read32(priv, addr) & mask) == (bits & mask)) + if ((iwl_read32(bus, addr) & mask) == (bits & mask)) return t; udelay(IWL_POLL_INTERVAL); t += IWL_POLL_INTERVAL; @@ -73,14 +77,14 @@ int iwl_poll_bit(struct iwl_priv *priv, u32 addr, return -ETIMEDOUT; } -int iwl_grab_nic_access_silent(struct iwl_priv *priv) +int iwl_grab_nic_access_silent(struct iwl_bus *bus) { int ret; - lockdep_assert_held(&priv->reg_lock); + lockdep_assert_held(&bus->reg_lock); /* this bit wakes up the NIC */ - __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + __iwl_set_bit(bus, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* * These bits say the device is running, and should keep running for @@ -101,70 +105,70 @@ int iwl_grab_nic_access_silent(struct iwl_priv *priv) * 5000 series and later (including 1000 series) have non-volatile SRAM, * and do not save/restore SRAM when power cycling. */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, + ret = iwl_poll_bit(bus, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000); if (ret < 0) { - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); + iwl_write32(bus, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI); return -EIO; } return 0; } -int iwl_grab_nic_access(struct iwl_priv *priv) +int iwl_grab_nic_access(struct iwl_bus *bus) { - int ret = iwl_grab_nic_access_silent(priv); + int ret = iwl_grab_nic_access_silent(bus); if (ret) { - u32 val = iwl_read32(priv, CSR_GP_CNTRL); - IWL_ERR(priv, + u32 val = iwl_read32(bus, CSR_GP_CNTRL); + IWL_ERR(bus, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val); } return ret; } -void iwl_release_nic_access(struct iwl_priv *priv) +void iwl_release_nic_access(struct iwl_bus *bus) { - lockdep_assert_held(&priv->reg_lock); - __iwl_clear_bit(priv, CSR_GP_CNTRL, + lockdep_assert_held(&bus->reg_lock); + __iwl_clear_bit(bus, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); } -u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg) +u32 iwl_read_direct32(struct iwl_bus *bus, u32 reg) { u32 value; unsigned long flags; - spin_lock_irqsave(&priv->reg_lock, flags); - iwl_grab_nic_access(priv); - value = iwl_read32(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_lock_irqsave(&bus->reg_lock, flags); + iwl_grab_nic_access(bus); + value = iwl_read32(bus(bus), reg); + iwl_release_nic_access(bus); + spin_unlock_irqrestore(&bus->reg_lock, flags); return value; } -void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value) +void iwl_write_direct32(struct iwl_bus *bus, u32 reg, u32 value) { unsigned long flags; - spin_lock_irqsave(&priv->reg_lock, flags); - if (!iwl_grab_nic_access(priv)) { - iwl_write32(priv, reg, value); - iwl_release_nic_access(priv); + spin_lock_irqsave(&bus->reg_lock, flags); + if (!iwl_grab_nic_access(bus)) { + iwl_write32(bus, reg, value); + iwl_release_nic_access(bus); } - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_unlock_irqrestore(&bus->reg_lock, flags); } -int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, +int iwl_poll_direct_bit(struct iwl_bus *bus, u32 addr, u32 mask, int timeout) { int t = 0; do { - if ((iwl_read_direct32(priv, addr) & mask) == mask) + if ((iwl_read_direct32(bus, addr) & mask) == mask) return t; udelay(IWL_POLL_INTERVAL); t += IWL_POLL_INTERVAL; @@ -173,122 +177,122 @@ int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, return -ETIMEDOUT; } -static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg) +static inline u32 __iwl_read_prph(struct iwl_bus *bus, u32 reg) { - iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + iwl_write32(bus, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); rmb(); - return iwl_read32(priv, HBUS_TARG_PRPH_RDAT); + return iwl_read32(bus, HBUS_TARG_PRPH_RDAT); } -static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +static inline void __iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val) { - iwl_write32(priv, HBUS_TARG_PRPH_WADDR, + iwl_write32(bus, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24))); wmb(); - iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val); + iwl_write32(bus, HBUS_TARG_PRPH_WDAT, val); } -u32 iwl_read_prph(struct iwl_priv *priv, u32 reg) +u32 iwl_read_prph(struct iwl_bus *bus, u32 reg) { unsigned long flags; u32 val; - spin_lock_irqsave(&priv->reg_lock, flags); - iwl_grab_nic_access(priv); - val = __iwl_read_prph(priv, reg); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_lock_irqsave(&bus->reg_lock, flags); + iwl_grab_nic_access(bus); + val = __iwl_read_prph(bus, reg); + iwl_release_nic_access(bus); + spin_unlock_irqrestore(&bus->reg_lock, flags); return val; } -void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val) +void iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val) { unsigned long flags; - spin_lock_irqsave(&priv->reg_lock, flags); - if (!iwl_grab_nic_access(priv)) { - __iwl_write_prph(priv, addr, val); - iwl_release_nic_access(priv); + spin_lock_irqsave(&bus->reg_lock, flags); + if (!iwl_grab_nic_access(bus)) { + __iwl_write_prph(bus, addr, val); + iwl_release_nic_access(bus); } - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_unlock_irqrestore(&bus->reg_lock, flags); } -void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +void iwl_set_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask) { unsigned long flags; - spin_lock_irqsave(&priv->reg_lock, flags); - iwl_grab_nic_access(priv); - __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_lock_irqsave(&bus->reg_lock, flags); + iwl_grab_nic_access(bus); + __iwl_write_prph(bus, reg, __iwl_read_prph(bus, reg) | mask); + iwl_release_nic_access(bus); + spin_unlock_irqrestore(&bus->reg_lock, flags); } -void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, +void iwl_set_bits_mask_prph(struct iwl_bus *bus, u32 reg, u32 bits, u32 mask) { unsigned long flags; - spin_lock_irqsave(&priv->reg_lock, flags); - iwl_grab_nic_access(priv); - __iwl_write_prph(priv, reg, - (__iwl_read_prph(priv, reg) & mask) | bits); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_lock_irqsave(&bus->reg_lock, flags); + iwl_grab_nic_access(bus); + __iwl_write_prph(bus, reg, + (__iwl_read_prph(bus, reg) & mask) | bits); + iwl_release_nic_access(bus); + spin_unlock_irqrestore(&bus->reg_lock, flags); } -void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask) +void iwl_clear_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask) { unsigned long flags; u32 val; - spin_lock_irqsave(&priv->reg_lock, flags); - iwl_grab_nic_access(priv); - val = __iwl_read_prph(priv, reg); - __iwl_write_prph(priv, reg, (val & ~mask)); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_lock_irqsave(&bus->reg_lock, flags); + iwl_grab_nic_access(bus); + val = __iwl_read_prph(bus, reg); + __iwl_write_prph(bus, reg, (val & ~mask)); + iwl_release_nic_access(bus); + spin_unlock_irqrestore(&bus->reg_lock, flags); } -void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, +void _iwl_read_targ_mem_words(struct iwl_bus *bus, u32 addr, void *buf, int words) { unsigned long flags; int offs; u32 *vals = buf; - spin_lock_irqsave(&priv->reg_lock, flags); - iwl_grab_nic_access(priv); + spin_lock_irqsave(&bus->reg_lock, flags); + iwl_grab_nic_access(bus); - iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr); + iwl_write32(bus, HBUS_TARG_MEM_RADDR, addr); rmb(); for (offs = 0; offs < words; offs++) - vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT); + vals[offs] = iwl_read32(bus, HBUS_TARG_MEM_RDAT); - iwl_release_nic_access(priv); - spin_unlock_irqrestore(&priv->reg_lock, flags); + iwl_release_nic_access(bus); + spin_unlock_irqrestore(&bus->reg_lock, flags); } -u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) +u32 iwl_read_targ_mem(struct iwl_bus *bus, u32 addr) { u32 value; - _iwl_read_targ_mem_words(priv, addr, &value, 1); + _iwl_read_targ_mem_words(bus, addr, &value, 1); return value; } -void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) +void iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val) { unsigned long flags; - spin_lock_irqsave(&priv->reg_lock, flags); - if (!iwl_grab_nic_access(priv)) { - iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr); + spin_lock_irqsave(&bus->reg_lock, flags); + if (!iwl_grab_nic_access(bus)) { + iwl_write32(bus, HBUS_TARG_MEM_WADDR, addr); wmb(); - iwl_write32(priv, HBUS_TARG_MEM_WDAT, val); - iwl_release_nic_access(priv); + iwl_write32(bus, HBUS_TARG_MEM_WDAT, val); + iwl_release_nic_access(bus); } - spin_unlock_irqrestore(&priv->reg_lock, flags); + spin_unlock_irqrestore(&bus->reg_lock, flags); } diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 19a093101122..ced2cbeb6eae 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -29,65 +29,62 @@ #ifndef __iwl_io_h__ #define __iwl_io_h__ -#include <linux/io.h> - -#include "iwl-dev.h" -#include "iwl-debug.h" #include "iwl-devtrace.h" +#include "iwl-shared.h" #include "iwl-bus.h" -static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val) +static inline void iwl_write8(struct iwl_bus *bus, u32 ofs, u8 val) { - trace_iwlwifi_dev_iowrite8(priv, ofs, val); - bus_write8(priv->bus, ofs, val); + trace_iwlwifi_dev_iowrite8(priv(bus), ofs, val); + bus_write8(bus, ofs, val); } -static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val) +static inline void iwl_write32(struct iwl_bus *bus, u32 ofs, u32 val) { - trace_iwlwifi_dev_iowrite32(priv, ofs, val); - bus_write32(priv->bus, ofs, val); + trace_iwlwifi_dev_iowrite32(priv(bus), ofs, val); + bus_write32(bus, ofs, val); } -static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs) +static inline u32 iwl_read32(struct iwl_bus *bus, u32 ofs) { - u32 val = bus_read32(priv->bus, ofs); - trace_iwlwifi_dev_ioread32(priv, ofs, val); + u32 val = bus_read32(bus, ofs); + trace_iwlwifi_dev_ioread32(priv(bus), ofs, val); return val; } -void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask); -void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_set_bit(struct iwl_bus *bus, u32 reg, u32 mask); +void iwl_clear_bit(struct iwl_bus *bus, u32 reg, u32 mask); -int iwl_poll_bit(struct iwl_priv *priv, u32 addr, +int iwl_poll_bit(struct iwl_bus *bus, u32 addr, u32 bits, u32 mask, int timeout); -int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask, +int iwl_poll_direct_bit(struct iwl_bus *bus, u32 addr, u32 mask, int timeout); -int iwl_grab_nic_access_silent(struct iwl_priv *priv); -int iwl_grab_nic_access(struct iwl_priv *priv); -void iwl_release_nic_access(struct iwl_priv *priv); +int iwl_grab_nic_access_silent(struct iwl_bus *bus); +int iwl_grab_nic_access(struct iwl_bus *bus); +void iwl_release_nic_access(struct iwl_bus *bus); -u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg); -void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value); +u32 iwl_read_direct32(struct iwl_bus *bus, u32 reg); +void iwl_write_direct32(struct iwl_bus *bus, u32 reg, u32 value); -u32 iwl_read_prph(struct iwl_priv *priv, u32 reg); -void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val); -void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); -void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg, +u32 iwl_read_prph(struct iwl_bus *bus, u32 reg); +void iwl_write_prph(struct iwl_bus *bus, u32 addr, u32 val); +void iwl_set_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask); +void iwl_set_bits_mask_prph(struct iwl_bus *bus, u32 reg, u32 bits, u32 mask); -void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask); +void iwl_clear_bits_prph(struct iwl_bus *bus, u32 reg, u32 mask); -void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr, +void _iwl_read_targ_mem_words(struct iwl_bus *bus, u32 addr, void *buf, int words); -#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \ +#define iwl_read_targ_mem_words(bus, addr, buf, bufsize) \ do { \ BUILD_BUG_ON((bufsize) % sizeof(u32)); \ - _iwl_read_targ_mem_words(priv, addr, buf, \ + _iwl_read_targ_mem_words(bus, addr, buf, \ (bufsize) / sizeof(u32));\ } while (0) -u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr); -void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val); +u32 iwl_read_targ_mem(struct iwl_bus *bus, u32 addr); +void iwl_write_targ_mem(struct iwl_bus *bus, u32 addr, u32 val); #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index a67ae56d5464..eb541735296c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -31,7 +31,6 @@ #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/netdevice.h> -#include <linux/wireless.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <asm/unaligned.h> @@ -41,6 +40,7 @@ #include "iwl-agn.h" #include "iwl-io.h" #include "iwl-trans.h" +#include "iwl-shared.h" /* Throughput OFF time(ms) ON time (ms) * >300 25 25 @@ -71,7 +71,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { /* Set led register off */ void iwlagn_led_enable(struct iwl_priv *priv) { - iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON); + iwl_write32(bus(priv), CSR_LED_REG, CSR_LED_REG_TRUN_ON); } /* @@ -104,15 +104,14 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) .len = { sizeof(struct iwl_led_cmd), }, .data = { led_cmd, }, .flags = CMD_ASYNC, - .callback = NULL, }; u32 reg; - reg = iwl_read32(priv, CSR_LED_REG); + reg = iwl_read32(bus(priv), CSR_LED_REG); if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); + iwl_write32(bus(priv), CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK); - return trans_send_cmd(&priv->trans, &cmd); + return iwl_trans_send_cmd(trans(priv), &cmd); } /* Set led pattern command */ @@ -126,7 +125,7 @@ static int iwl_led_cmd(struct iwl_priv *priv, }; int ret; - if (!test_bit(STATUS_READY, &priv->status)) + if (!test_bit(STATUS_READY, &priv->shrd->status)) return -EBUSY; if (priv->blink_on == on && priv->blink_off == off) @@ -203,8 +202,7 @@ void iwl_leds_init(struct iwl_priv *priv) break; } - ret = led_classdev_register(priv->bus->dev, - &priv->led); + ret = led_classdev_register(bus(priv)->dev, &priv->led); if (ret) { kfree(priv->led.name); return; diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index 2fdbffa079c1..3b6cc66365e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -64,9 +64,11 @@ #include <linux/pci-aspm.h> #include "iwl-bus.h" -#include "iwl-agn.h" -#include "iwl-core.h" #include "iwl-io.h" +#include "iwl-shared.h" +#include "iwl-trans.h" +#include "iwl-csr.h" +#include "iwl-cfg.h" /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 @@ -91,6 +93,7 @@ static u16 iwl_pciexp_link_ctrl(struct iwl_bus *bus) { int pos; u16 pci_lnk_ctl; + struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); pos = pci_pcie_cap(pci_dev); @@ -120,23 +123,17 @@ static void iwl_pci_apm_config(struct iwl_bus *bus) if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) { /* L1-ASPM enabled; disable(!) L0S */ - iwl_set_bit(bus->drv_data, CSR_GIO_REG, + iwl_set_bit(bus, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); dev_printk(KERN_INFO, bus->dev, "L1 Enabled; Disabling L0S\n"); } else { /* L1-ASPM disabled; enable(!) L0S */ - iwl_clear_bit(bus->drv_data, CSR_GIO_REG, + iwl_clear_bit(bus, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); dev_printk(KERN_INFO, bus->dev, "L1 Disabled; Enabling L0S\n"); } } -static void iwl_pci_set_drv_data(struct iwl_bus *bus, void *drv_data) -{ - bus->drv_data = drv_data; - pci_set_drvdata(IWL_BUS_GET_PCI_DEV(bus), drv_data); -} - static void iwl_pci_get_hw_id(struct iwl_bus *bus, char buf[], int buf_len) { @@ -162,10 +159,9 @@ static u32 iwl_pci_read32(struct iwl_bus *bus, u32 ofs) return val; } -static struct iwl_bus_ops pci_ops = { +static const struct iwl_bus_ops bus_ops_pci = { .get_pm_support = iwl_pci_is_pm_supported, .apm_config = iwl_pci_apm_config, - .set_drv_data = iwl_pci_set_drv_data, .get_hw_id = iwl_pci_get_hw_id, .write8 = iwl_pci_write8, .write32 = iwl_pci_write32, @@ -256,6 +252,9 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6005_2abg_cfg)}, {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)}, {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)}, + {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)}, + {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)}, + {IWL_PCI_DEVICE(0x0082, 0x1341, iwl6005_2agn_d_cfg)}, /* 6x30 Series */ {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)}, @@ -328,6 +327,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)}, {IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)}, {IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)}, + {IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)}, /* 2x30 Series */ {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)}, @@ -355,6 +355,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)}, {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)}, {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)}, + {IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)}, /* 135 Series */ {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)}, @@ -387,6 +388,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_bus = IWL_BUS_GET_PCI_BUS(bus); pci_bus->pci_dev = pdev; + pci_set_drvdata(pdev, bus); + /* W/A - seems to solve weird behavior. We need to remove this if we * don't want to stay in L1 all the time. This wastes a lot of power */ pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | @@ -457,9 +460,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) bus->dev = &pdev->dev; bus->irq = pdev->irq; - bus->ops = &pci_ops; + bus->ops = &bus_ops_pci; - err = iwl_probe(bus, cfg); + err = iwl_probe(bus, &trans_ops_pcie, cfg); if (err) goto out_disable_msi; return 0; @@ -480,12 +483,12 @@ out_no_pci: static void __devexit iwl_pci_remove(struct pci_dev *pdev) { - struct iwl_priv *priv = pci_get_drvdata(pdev); - struct iwl_bus *bus = priv->bus; + struct iwl_bus *bus = pci_get_drvdata(pdev); struct iwl_pci_bus *pci_bus = IWL_BUS_GET_PCI_BUS(bus); struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus); + struct iwl_shared *shrd = bus->shrd; - iwl_remove(priv); + iwl_remove(shrd->priv); pci_disable_msi(pci_dev); pci_iounmap(pci_dev, pci_bus->hw_base); @@ -496,25 +499,27 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev) kfree(bus); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int iwl_pci_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_priv *priv = pci_get_drvdata(pdev); + struct iwl_bus *bus = pci_get_drvdata(pdev); + struct iwl_shared *shrd = bus->shrd; /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if * WoWLAN is enabled - don't kill the NIC, someone may need it in Sx. */ - return iwl_suspend(priv); + return iwl_trans_suspend(shrd->trans); } static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); - struct iwl_priv *priv = pci_get_drvdata(pdev); + struct iwl_bus *bus = pci_get_drvdata(pdev); + struct iwl_shared *shrd = bus->shrd; /* Before you put code here, think about WoWLAN. You cannot check here * whether WoWLAN is enabled or not, and your code will run even if @@ -527,7 +532,7 @@ static int iwl_pci_resume(struct device *device) */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); - return iwl_resume(priv); + return iwl_trans_resume(shrd->trans); } static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume); diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index cd64df05f9ed..4eaab204322d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -43,6 +43,7 @@ #include "iwl-debug.h" #include "iwl-power.h" #include "iwl-trans.h" +#include "iwl-shared.h" /* * Setting power level allows the card to go to sleep when not busy. @@ -214,7 +215,7 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, else cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK; - if (priv->cfg->base_params->shadow_reg_enable) + if (hw_params(priv).shadow_reg_enable) cmd->flags |= IWL_POWER_SHADOW_REG_ENA; else cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; @@ -300,7 +301,7 @@ static void iwl_power_fill_sleep_cmd(struct iwl_priv *priv, if (priv->power_data.bus_pm) cmd->flags |= IWL_POWER_PCI_PM_MSK; - if (priv->cfg->base_params->shadow_reg_enable) + if (hw_params(priv).shadow_reg_enable) cmd->flags |= IWL_POWER_SHADOW_REG_ENA; else cmd->flags &= ~IWL_POWER_SHADOW_REG_ENA; @@ -335,7 +336,7 @@ static int iwl_set_power(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd) le32_to_cpu(cmd->sleep_interval[3]), le32_to_cpu(cmd->sleep_interval[4])); - return trans_send_cmd_pdu(&priv->trans, POWER_TABLE_CMD, CMD_SYNC, + return iwl_trans_send_cmd_pdu(trans(priv), POWER_TABLE_CMD, CMD_SYNC, sizeof(struct iwl_powertable_cmd), cmd); } @@ -347,7 +348,7 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, dtimper = priv->hw->conf.ps_dtim_period ?: 1; - if (priv->wowlan) + if (priv->shrd->wowlan) iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, dtimper); else if (!priv->cfg->base_params->no_idle_support && priv->hw->conf.flags & IEEE80211_CONF_IDLE) @@ -382,7 +383,7 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, int ret; bool update_chains; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); /* Don't update the RX chain when chain noise calibration is running */ update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || @@ -391,23 +392,23 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, if (!memcmp(&priv->power_data.sleep_cmd, cmd, sizeof(*cmd)) && !force) return 0; - if (!iwl_is_ready_rf(priv)) + if (!iwl_is_ready_rf(priv->shrd)) return -EIO; /* scan complete use sleep_power_next, need to be updated */ memcpy(&priv->power_data.sleep_cmd_next, cmd, sizeof(*cmd)); - if (test_bit(STATUS_SCANNING, &priv->status) && !force) { + if (test_bit(STATUS_SCANNING, &priv->shrd->status) && !force) { IWL_DEBUG_INFO(priv, "Defer power set mode while scanning\n"); return 0; } if (cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK) - set_bit(STATUS_POWER_PMI, &priv->status); + set_bit(STATUS_POWER_PMI, &priv->shrd->status); ret = iwl_set_power(priv, cmd); if (!ret) { if (!(cmd->flags & IWL_POWER_DRIVER_ALLOW_SLEEP_MSK)) - clear_bit(STATUS_POWER_PMI, &priv->status); + clear_bit(STATUS_POWER_PMI, &priv->shrd->status); if (update_chains) iwl_update_chain_flags(priv); @@ -435,7 +436,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { - priv->power_data.bus_pm = bus_get_pm_support(priv->bus); + priv->power_data.bus_pm = bus_get_pm_support(bus(priv)); priv->power_data.debug_sleep_level_override = -1; diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index 2f267b8aabbb..bebdd828f324 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -217,8 +217,8 @@ ((SCD_TRANS_TBL_MEM_LOWER_BOUND + ((x) * 2)) & 0xfffc) #define SCD_QUEUECHAIN_SEL_ALL(priv) \ - (((1<<(priv)->hw_params.max_txq_num) - 1) &\ - (~(1<<(priv)->cmd_queue))) + (((1<<hw_params(priv).max_txq_num) - 1) &\ + (~(1<<(priv)->shrd->cmd_queue))) #define SCD_BASE (PRPH_BASE + 0xa02c00) diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index 77e528f5db88..e5d727f537d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -33,9 +33,7 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-sta.h" #include "iwl-io.h" -#include "iwl-helpers.h" #include "iwl-agn.h" #include "iwl-trans.h" @@ -68,14 +66,14 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) /* Exit instantly with error when device is not ready * to receive scan abort command or it does not perform * hardware scan currently */ - if (!test_bit(STATUS_READY, &priv->status) || - !test_bit(STATUS_GEO_CONFIGURED, &priv->status) || - !test_bit(STATUS_SCAN_HW, &priv->status) || - test_bit(STATUS_FW_ERROR, &priv->status) || - test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (!test_bit(STATUS_READY, &priv->shrd->status) || + !test_bit(STATUS_GEO_CONFIGURED, &priv->shrd->status) || + !test_bit(STATUS_SCAN_HW, &priv->shrd->status) || + test_bit(STATUS_FW_ERROR, &priv->shrd->status) || + test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) return -EIO; - ret = trans_send_cmd(&priv->trans, &cmd); + ret = iwl_trans_send_cmd(trans(priv), &cmd); if (ret) return ret; @@ -91,7 +89,7 @@ static int iwl_send_scan_abort(struct iwl_priv *priv) ret = -EIO; } - iwl_free_pages(priv, cmd.reply_page); + iwl_free_pages(priv->shrd, cmd.reply_page); return ret; } @@ -103,24 +101,90 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted) ieee80211_scan_completed(priv->hw, aborted); } + if (priv->scan_type == IWL_SCAN_ROC) { + ieee80211_remain_on_channel_expired(priv->hw); + priv->hw_roc_channel = NULL; + schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); + } + priv->scan_type = IWL_SCAN_NORMAL; priv->scan_vif = NULL; priv->scan_request = NULL; } +static void iwl_process_scan_complete(struct iwl_priv *priv) +{ + bool aborted; + + lockdep_assert_held(&priv->shrd->mutex); + + if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status)) + return; + + IWL_DEBUG_SCAN(priv, "Completed scan.\n"); + + cancel_delayed_work(&priv->scan_check); + + aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status); + if (aborted) + IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n"); + + if (!test_and_clear_bit(STATUS_SCANNING, &priv->shrd->status)) { + IWL_DEBUG_SCAN(priv, "Scan already completed.\n"); + goto out_settings; + } + + if (priv->scan_type == IWL_SCAN_ROC) { + ieee80211_remain_on_channel_expired(priv->hw); + priv->hw_roc_channel = NULL; + schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ); + } + + if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { + int err; + + /* Check if mac80211 requested scan during our internal scan */ + if (priv->scan_request == NULL) + goto out_complete; + + /* If so request a new scan */ + err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, + priv->scan_request->channels[0]->band); + if (err) { + IWL_DEBUG_SCAN(priv, + "failed to initiate pending scan: %d\n", err); + aborted = true; + goto out_complete; + } + + return; + } + +out_complete: + iwl_complete_scan(priv, aborted); + +out_settings: + /* Can we still talk to firmware ? */ + if (!iwl_is_ready_rf(priv->shrd)) + return; + + iwlagn_post_scan(priv); +} + void iwl_force_scan_end(struct iwl_priv *priv) { - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); - if (!test_bit(STATUS_SCANNING, &priv->status)) { + if (!test_bit(STATUS_SCANNING, &priv->shrd->status)) { IWL_DEBUG_SCAN(priv, "Forcing scan end while not scanning\n"); return; } IWL_DEBUG_SCAN(priv, "Forcing scan end\n"); - clear_bit(STATUS_SCANNING, &priv->status); - clear_bit(STATUS_SCAN_HW, &priv->status); - clear_bit(STATUS_SCAN_ABORTING, &priv->status); + clear_bit(STATUS_SCANNING, &priv->shrd->status); + clear_bit(STATUS_SCAN_HW, &priv->shrd->status); + clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status); + clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status); iwl_complete_scan(priv, true); } @@ -128,14 +192,14 @@ static void iwl_do_scan_abort(struct iwl_priv *priv) { int ret; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); - if (!test_bit(STATUS_SCANNING, &priv->status)) { + if (!test_bit(STATUS_SCANNING, &priv->shrd->status)) { IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n"); return; } - if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) { + if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->shrd->status)) { IWL_DEBUG_SCAN(priv, "Scan abort in progress\n"); return; } @@ -154,7 +218,7 @@ static void iwl_do_scan_abort(struct iwl_priv *priv) int iwl_scan_cancel(struct iwl_priv *priv) { IWL_DEBUG_SCAN(priv, "Queuing abort scan\n"); - queue_work(priv->workqueue, &priv->abort_scan); + queue_work(priv->shrd->workqueue, &priv->abort_scan); return 0; } @@ -163,28 +227,42 @@ int iwl_scan_cancel(struct iwl_priv *priv) * @ms: amount of time to wait (in milliseconds) for scan to abort * */ -int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) +void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) { unsigned long timeout = jiffies + msecs_to_jiffies(ms); - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n"); iwl_do_scan_abort(priv); while (time_before_eq(jiffies, timeout)) { - if (!test_bit(STATUS_SCAN_HW, &priv->status)) - break; + if (!test_bit(STATUS_SCAN_HW, &priv->shrd->status)) + goto finished; msleep(20); } - return test_bit(STATUS_SCAN_HW, &priv->status); + return; + + finished: + /* + * Now STATUS_SCAN_HW is clear. This means that the + * device finished, but the background work is going + * to execute at best as soon as we release the mutex. + * Since we need to be able to issue a new scan right + * after this function returns, run the complete here. + * The STATUS_SCAN_COMPLETE bit will then be cleared + * and prevent the background work from "completing" + * a possible new scan. + */ + iwl_process_scan_complete(priv); } /* Service response to REPLY_SCAN_CMD (0x80) */ -static void iwl_rx_reply_scan(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwl_rx_reply_scan(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -193,11 +271,13 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv, IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status); #endif + return 0; } /* Service SCAN_START_NOTIFICATION (0x82) */ -static void iwl_rx_scan_start_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwl_rx_scan_start_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scanstart_notification *notif = @@ -211,11 +291,20 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv, le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), notif->status, notif->beacon_timer); + + if (priv->scan_type == IWL_SCAN_ROC && + !priv->hw_roc_start_notified) { + ieee80211_ready_on_channel(priv->hw); + priv->hw_roc_start_notified = true; + } + + return 0; } /* Service SCAN_RESULTS_NOTIFICATION (0x83) */ -static void iwl_rx_scan_results_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwl_rx_scan_results_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -224,20 +313,24 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv, IWL_DEBUG_SCAN(priv, "Scan ch.res: " "%d [802.11%s] " + "probe status: %u:%u " "(TSF: 0x%08X:%08X) - %d " "elapsed=%lu usec\n", notif->channel, notif->band ? "bg" : "a", + notif->probe_status, notif->num_probe_not_sent, le32_to_cpu(notif->tsf_high), le32_to_cpu(notif->tsf_low), le32_to_cpu(notif->statistics[0]), le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf); #endif + return 0; } /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ -static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) +static int iwl_rx_scan_complete_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; @@ -247,14 +340,21 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, scan_notif->tsf_low, scan_notif->tsf_high, scan_notif->status); - /* The HW is no longer scanning */ - clear_bit(STATUS_SCAN_HW, &priv->status); - IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n", (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2", jiffies_to_msecs(jiffies - priv->scan_start)); - queue_work(priv->workqueue, &priv->scan_completed); + /* + * When aborting, we run the scan completed background work inline + * and the background work must then do nothing. The SCAN_COMPLETE + * bit helps implement that logic and thus needs to be set before + * queueing the work. Also, since the scan abort waits for SCAN_HW + * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW + * to avoid a race there. + */ + set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status); + clear_bit(STATUS_SCAN_HW, &priv->shrd->status); + queue_work(priv->shrd->workqueue, &priv->scan_completed); if (priv->iw_mode != NL80211_IFTYPE_ADHOC && iwl_advanced_bt_coexist(priv) && @@ -274,8 +374,10 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, IWL_BT_COEX_TRAFFIC_LOAD_NONE; } priv->bt_status = scan_notif->bt_status; - queue_work(priv->workqueue, &priv->bt_traffic_change_work); + queue_work(priv->shrd->workqueue, + &priv->bt_traffic_change_work); } + return 0; } void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) @@ -289,9 +391,8 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv) iwl_rx_scan_complete_notif; } -inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, - enum ieee80211_band band, - u8 n_probes) +static u16 iwl_get_active_dwell_time(struct iwl_priv *priv, + enum ieee80211_band band, u8 n_probes) { if (band == IEEE80211_BAND_5GHZ) return IWL_ACTIVE_DWELL_TIME_52 + @@ -301,40 +402,486 @@ inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1); } -u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, - enum ieee80211_band band, - struct ieee80211_vif *vif) +static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) { struct iwl_rxon_context *ctx; + + /* + * If we're associated, we clamp the dwell time 98% + * of the smallest beacon interval (minus 2 * channel + * tune time) + */ + for_each_context(priv, ctx) { + u16 value; + + if (!iwl_is_associated_ctx(ctx)) + continue; + value = ctx->beacon_int; + if (!value) + value = IWL_PASSIVE_DWELL_BASE; + value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; + dwell_time = min(value, dwell_time); + } + + return dwell_time; +} + +static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, + enum ieee80211_band band) +{ u16 passive = (band == IEEE80211_BAND_2GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; - if (iwl_is_any_associated(priv)) { + return iwl_limit_dwell(priv, passive); +} + +static int iwl_get_single_channel_for_scan(struct iwl_priv *priv, + struct ieee80211_vif *vif, + enum ieee80211_band band, + struct iwl_scan_channel *scan_ch) +{ + const struct ieee80211_supported_band *sband; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int added = 0; + u16 channel = 0; + + sband = iwl_get_hw_mode(priv, band); + if (!sband) { + IWL_ERR(priv, "invalid band\n"); + return added; + } + + active_dwell = iwl_get_active_dwell_time(priv, band, 0); + passive_dwell = iwl_get_passive_dwell_time(priv, band); + + if (passive_dwell <= active_dwell) + passive_dwell = active_dwell + 1; + + channel = iwl_get_single_channel_number(priv, band); + if (channel) { + scan_ch->channel = cpu_to_le16(channel); + scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* Set txpower levels to defaults */ + scan_ch->dsp_atten = 110; + if (band == IEEE80211_BAND_5GHZ) + scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; + else + scan_ch->tx_gain = ((1 << 5) | (5 << 3)); + added++; + } else + IWL_ERR(priv, "no valid channel found\n"); + return added; +} + +static int iwl_get_channels_for_scan(struct iwl_priv *priv, + struct ieee80211_vif *vif, + enum ieee80211_band band, + u8 is_active, u8 n_probes, + struct iwl_scan_channel *scan_ch) +{ + struct ieee80211_channel *chan; + const struct ieee80211_supported_band *sband; + const struct iwl_channel_info *ch_info; + u16 passive_dwell = 0; + u16 active_dwell = 0; + int added, i; + u16 channel; + + sband = iwl_get_hw_mode(priv, band); + if (!sband) + return 0; + + active_dwell = iwl_get_active_dwell_time(priv, band, n_probes); + passive_dwell = iwl_get_passive_dwell_time(priv, band); + + if (passive_dwell <= active_dwell) + passive_dwell = active_dwell + 1; + + for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + + if (chan->band != band) + continue; + + channel = chan->hw_value; + scan_ch->channel = cpu_to_le16(channel); + + ch_info = iwl_get_channel_info(priv, band, channel); + if (!is_channel_valid(ch_info)) { + IWL_DEBUG_SCAN(priv, + "Channel %d is INVALID for this band.\n", + channel); + continue; + } + + if (!is_active || is_channel_passive(ch_info) || + (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)) + scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; + else + scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE; + + if (n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); + + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + + /* Set txpower levels to defaults */ + scan_ch->dsp_atten = 110; + + /* NOTE: if we were doing 6Mb OFDM for scans we'd use + * power level: + * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; + */ + if (band == IEEE80211_BAND_5GHZ) + scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; + else + scan_ch->tx_gain = ((1 << 5) | (5 << 3)); + + IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n", + channel, le32_to_cpu(scan_ch->type), + (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? + "ACTIVE" : "PASSIVE", + (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ? + active_dwell : passive_dwell); + + scan_ch++; + added++; + } + + IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added); + return added; +} + +static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) +{ + struct iwl_host_cmd cmd = { + .id = REPLY_SCAN_CMD, + .len = { sizeof(struct iwl_scan_cmd), }, + .flags = CMD_SYNC, + }; + struct iwl_scan_cmd *scan; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + u32 rate_flags = 0; + u16 cmd_len; + u16 rx_chain = 0; + enum ieee80211_band band; + u8 n_probes = 0; + u8 rx_ant = hw_params(priv).valid_rx_ant; + u8 rate; + bool is_active = false; + int chan_mod; + u8 active_chains; + u8 scan_tx_antennas = hw_params(priv).valid_tx_ant; + int ret; + + lockdep_assert_held(&priv->shrd->mutex); + + if (vif) + ctx = iwl_rxon_ctx_from_vif(vif); + + if (!priv->scan_cmd) { + priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) + + IWL_MAX_SCAN_SIZE, GFP_KERNEL); + if (!priv->scan_cmd) { + IWL_DEBUG_SCAN(priv, + "fail to allocate memory for scan\n"); + return -ENOMEM; + } + } + scan = priv->scan_cmd; + memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + + scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; + scan->quiet_time = IWL_ACTIVE_QUIET_TIME; + + if (priv->scan_type != IWL_SCAN_ROC && + iwl_is_any_associated(priv)) { + u16 interval = 0; + u32 extra; + u32 suspend_time = 100; + u32 scan_suspend_time = 100; + + IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); + switch (priv->scan_type) { + case IWL_SCAN_ROC: + WARN_ON(1); + break; + case IWL_SCAN_RADIO_RESET: + interval = 0; + break; + case IWL_SCAN_NORMAL: + interval = vif->bss_conf.beacon_int; + break; + } + + scan->suspend_time = 0; + scan->max_out_time = cpu_to_le32(200 * 1024); + if (!interval) + interval = suspend_time; + + extra = (suspend_time / interval) << 22; + scan_suspend_time = (extra | + ((suspend_time % interval) * 1024)); + scan->suspend_time = cpu_to_le32(scan_suspend_time); + IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", + scan_suspend_time, interval); + } else if (priv->scan_type == IWL_SCAN_ROC) { + scan->suspend_time = 0; + scan->max_out_time = 0; + scan->quiet_time = 0; + scan->quiet_plcp_th = 0; + } + + switch (priv->scan_type) { + case IWL_SCAN_RADIO_RESET: + IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); + break; + case IWL_SCAN_NORMAL: + if (priv->scan_request->n_ssids) { + int i, p = 0; + IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); + for (i = 0; i < priv->scan_request->n_ssids; i++) { + /* always does wildcard anyway */ + if (!priv->scan_request->ssids[i].ssid_len) + continue; + scan->direct_scan[p].id = WLAN_EID_SSID; + scan->direct_scan[p].len = + priv->scan_request->ssids[i].ssid_len; + memcpy(scan->direct_scan[p].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + n_probes++; + p++; + } + is_active = true; + } else + IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); + break; + case IWL_SCAN_ROC: + IWL_DEBUG_SCAN(priv, "Start ROC scan.\n"); + break; + } + + scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; + scan->tx_cmd.sta_id = ctx->bcast_sta_id; + scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; + + switch (priv->scan_band) { + case IEEE80211_BAND_2GHZ: + scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; + chan_mod = le32_to_cpu( + priv->contexts[IWL_RXON_CTX_BSS].active.flags & + RXON_FLG_CHANNEL_MODE_MSK) + >> RXON_FLG_CHANNEL_MODE_POS; + if (chan_mod == CHANNEL_MODE_PURE_40) { + rate = IWL_RATE_6M_PLCP; + } else { + rate = IWL_RATE_1M_PLCP; + rate_flags = RATE_MCS_CCK_MSK; + } /* - * If we're associated, we clamp the maximum passive - * dwell time to be 98% of the smallest beacon interval - * (minus 2 * channel tune time) + * Internal scans are passive, so we can indiscriminately set + * the BT ignore flag on 2.4 GHz since it applies to TX only. */ - for_each_context(priv, ctx) { - u16 value; - - if (!iwl_is_associated_ctx(ctx)) - continue; - value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0; - if ((value > IWL_PASSIVE_DWELL_BASE) || !value) - value = IWL_PASSIVE_DWELL_BASE; - value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; - passive = min(value, passive); + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) + scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT; + break; + case IEEE80211_BAND_5GHZ: + rate = IWL_RATE_6M_PLCP; + break; + default: + IWL_WARN(priv, "Invalid scan band\n"); + return -EIO; + } + + /* + * If active scanning is requested but a certain channel is + * marked passive, we can do active scanning if we detect + * transmissions. + * + * There is an issue with some firmware versions that triggers + * a sysassert on a "good CRC threshold" of zero (== disabled), + * on a radar channel even though this means that we should NOT + * send probes. + * + * The "good CRC threshold" is the number of frames that we + * need to receive during our dwell time on a channel before + * sending out probes -- setting this to a huge value will + * mean we never reach it, but at the same time work around + * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER + * here instead of IWL_GOOD_CRC_TH_DISABLED. + * + * This was fixed in later versions along with some other + * scan changes, and the threshold behaves as a flag in those + * versions. + */ + if (priv->new_scan_threshold_behaviour) + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_DISABLED; + else + scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : + IWL_GOOD_CRC_TH_NEVER; + + band = priv->scan_band; + + if (priv->cfg->scan_rx_antennas[band]) + rx_ant = priv->cfg->scan_rx_antennas[band]; + + if (band == IEEE80211_BAND_2GHZ && + priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist) { + /* transmit 2.4 GHz probes only on first antenna */ + scan_tx_antennas = first_antenna(scan_tx_antennas); + } + + priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, + priv->scan_tx_ant[band], + scan_tx_antennas); + rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); + scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); + + /* In power save mode use one chain, otherwise use all chains */ + if (test_bit(STATUS_POWER_PMI, &priv->shrd->status)) { + /* rx_ant has been set to all valid chains previously */ + active_chains = rx_ant & + ((u8)(priv->chain_noise_data.active_chains)); + if (!active_chains) + active_chains = rx_ant; + + IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n", + priv->chain_noise_data.active_chains); + + rx_ant = first_antenna(active_chains); + } + if (priv->cfg->bt_params && + priv->cfg->bt_params->advanced_bt_coexist && + priv->bt_full_concurrent) { + /* operated as 1x1 in full concurrency mode */ + rx_ant = first_antenna(rx_ant); + } + + /* MIMO is not used here, but value is required */ + rx_chain |= + hw_params(priv).valid_rx_ant << RXON_RX_CHAIN_VALID_POS; + rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS; + rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; + rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; + scan->rx_chain = cpu_to_le16(rx_chain); + switch (priv->scan_type) { + case IWL_SCAN_NORMAL: + cmd_len = iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + vif->addr, + priv->scan_request->ie, + priv->scan_request->ie_len, + IWL_MAX_SCAN_SIZE - sizeof(*scan)); + break; + case IWL_SCAN_RADIO_RESET: + case IWL_SCAN_ROC: + /* use bcast addr, will not be transmitted but must be valid */ + cmd_len = iwl_fill_probe_req(priv, + (struct ieee80211_mgmt *)scan->data, + iwl_bcast_addr, NULL, 0, + IWL_MAX_SCAN_SIZE - sizeof(*scan)); + break; + default: + BUG(); + } + scan->tx_cmd.len = cpu_to_le16(cmd_len); + + scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | + RXON_FILTER_BCON_AWARE_MSK); + + switch (priv->scan_type) { + case IWL_SCAN_RADIO_RESET: + scan->channel_count = + iwl_get_single_channel_for_scan(priv, vif, band, + (void *)&scan->data[cmd_len]); + break; + case IWL_SCAN_NORMAL: + scan->channel_count = + iwl_get_channels_for_scan(priv, vif, band, + is_active, n_probes, + (void *)&scan->data[cmd_len]); + break; + case IWL_SCAN_ROC: { + struct iwl_scan_channel *scan_ch; + int n_chan, i; + u16 dwell; + + dwell = iwl_limit_dwell(priv, priv->hw_roc_duration); + n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell); + + scan->channel_count = n_chan; + + scan_ch = (void *)&scan->data[cmd_len]; + + for (i = 0; i < n_chan; i++) { + scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE; + scan_ch->channel = + cpu_to_le16(priv->hw_roc_channel->hw_value); + + if (i == n_chan - 1) + dwell = priv->hw_roc_duration - i * dwell; + + scan_ch->active_dwell = + scan_ch->passive_dwell = cpu_to_le16(dwell); + + /* Set txpower levels to defaults */ + scan_ch->dsp_atten = 110; + + /* NOTE: if we were doing 6Mb OFDM for scans we'd use + * power level: + * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; + */ + if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ) + scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; + else + scan_ch->tx_gain = ((1 << 5) | (5 << 3)); + + scan_ch++; } + } + + break; + } + + if (scan->channel_count == 0) { + IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); + return -EIO; + } + + cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) + + scan->channel_count * sizeof(struct iwl_scan_channel); + cmd.data[0] = scan; + cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; + scan->len = cpu_to_le16(cmd.len[0]); + + /* set scan bit here for PAN params */ + set_bit(STATUS_SCAN_HW, &priv->shrd->status); + + ret = iwlagn_set_pan_params(priv); + if (ret) + return ret; + + ret = iwl_trans_send_cmd(trans(priv), &cmd); + if (ret) { + clear_bit(STATUS_SCAN_HW, &priv->shrd->status); + iwlagn_set_pan_params(priv); } - return passive; + return ret; } void iwl_init_scan_params(struct iwl_priv *priv) { - u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1; + u8 ant_idx = fls(hw_params(priv).valid_tx_ant) - 1; if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) @@ -348,50 +895,50 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv, { int ret; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&priv->shrd->mutex); cancel_delayed_work(&priv->scan_check); - if (!iwl_is_ready_rf(priv)) { + if (!iwl_is_ready_rf(priv->shrd)) { IWL_WARN(priv, "Request scan called when driver not ready.\n"); return -EIO; } - if (test_bit(STATUS_SCAN_HW, &priv->status)) { + if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) { IWL_DEBUG_SCAN(priv, "Multiple concurrent scan requests in parallel.\n"); return -EBUSY; } - if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { + if (test_bit(STATUS_SCAN_ABORTING, &priv->shrd->status)) { IWL_DEBUG_SCAN(priv, "Scan request while abort pending.\n"); return -EBUSY; } IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", scan_type == IWL_SCAN_NORMAL ? "" : - scan_type == IWL_SCAN_OFFCH_TX ? "offchan TX " : + scan_type == IWL_SCAN_ROC ? "remain-on-channel " : "internal short "); - set_bit(STATUS_SCANNING, &priv->status); + set_bit(STATUS_SCANNING, &priv->shrd->status); priv->scan_type = scan_type; priv->scan_start = jiffies; priv->scan_band = band; ret = iwlagn_request_scan(priv, vif); if (ret) { - clear_bit(STATUS_SCANNING, &priv->status); + clear_bit(STATUS_SCANNING, &priv->shrd->status); priv->scan_type = IWL_SCAN_NORMAL; return ret; } - queue_delayed_work(priv->workqueue, &priv->scan_check, + queue_delayed_work(priv->shrd->workqueue, &priv->scan_check, IWL_SCAN_CHECK_WATCHDOG); return 0; } -int iwl_mac_hw_scan(struct ieee80211_hw *hw, +int iwlagn_mac_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct cfg80211_scan_request *req) { @@ -403,7 +950,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, if (req->n_channels == 0) return -EINVAL; - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); /* * If an internal scan is in progress, just set @@ -432,7 +979,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, IWL_DEBUG_MAC80211(priv, "leave\n"); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); return ret; } @@ -443,7 +990,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw, */ void iwl_internal_short_hw_scan(struct iwl_priv *priv) { - queue_work(priv->workqueue, &priv->start_internal_scan); + queue_work(priv->shrd->workqueue, &priv->start_internal_scan); } static void iwl_bg_start_internal_scan(struct work_struct *work) @@ -453,14 +1000,14 @@ static void iwl_bg_start_internal_scan(struct work_struct *work) IWL_DEBUG_SCAN(priv, "Start internal scan\n"); - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); if (priv->scan_type == IWL_SCAN_RADIO_RESET) { IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); goto unlock; } - if (test_bit(STATUS_SCANNING, &priv->status)) { + if (test_bit(STATUS_SCANNING, &priv->shrd->status)) { IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); goto unlock; } @@ -468,7 +1015,7 @@ static void iwl_bg_start_internal_scan(struct work_struct *work) if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band)) IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n"); unlock: - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } static void iwl_bg_scan_check(struct work_struct *data) @@ -481,9 +1028,9 @@ static void iwl_bg_scan_check(struct work_struct *data) /* Since we are here firmware does not finish scan and * most likely is in bad shape, so we don't bother to * send abort command, just force scan complete to mac80211 */ - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); iwl_force_scan_end(priv); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } /** @@ -541,70 +1088,19 @@ static void iwl_bg_abort_scan(struct work_struct *work) /* We keep scan_check work queued in case when firmware will not * report back scan completed notification */ - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); iwl_scan_cancel_timeout(priv, 200); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } static void iwl_bg_scan_completed(struct work_struct *work) { struct iwl_priv *priv = - container_of(work, struct iwl_priv, scan_completed); - bool aborted; - - IWL_DEBUG_SCAN(priv, "Completed scan.\n"); - - cancel_delayed_work(&priv->scan_check); - - mutex_lock(&priv->mutex); - - aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status); - if (aborted) - IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n"); - - if (!test_and_clear_bit(STATUS_SCANNING, &priv->status)) { - IWL_DEBUG_SCAN(priv, "Scan already completed.\n"); - goto out_settings; - } - - if (priv->scan_type == IWL_SCAN_OFFCH_TX && priv->offchan_tx_skb) { - ieee80211_tx_status_irqsafe(priv->hw, - priv->offchan_tx_skb); - priv->offchan_tx_skb = NULL; - } - - if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) { - int err; - - /* Check if mac80211 requested scan during our internal scan */ - if (priv->scan_request == NULL) - goto out_complete; - - /* If so request a new scan */ - err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL, - priv->scan_request->channels[0]->band); - if (err) { - IWL_DEBUG_SCAN(priv, - "failed to initiate pending scan: %d\n", err); - aborted = true; - goto out_complete; - } - - goto out; - } - -out_complete: - iwl_complete_scan(priv, aborted); - -out_settings: - /* Can we still talk to firmware ? */ - if (!iwl_is_ready_rf(priv)) - goto out; - - iwlagn_post_scan(priv); + container_of(work, struct iwl_priv, scan_completed); -out: - mutex_unlock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); + iwl_process_scan_complete(priv); + mutex_unlock(&priv->shrd->mutex); } void iwl_setup_scan_deferred_work(struct iwl_priv *priv) @@ -622,8 +1118,8 @@ void iwl_cancel_scan_deferred_work(struct iwl_priv *priv) cancel_work_sync(&priv->scan_completed); if (cancel_delayed_work_sync(&priv->scan_check)) { - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); iwl_force_scan_end(priv); - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); } } diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h new file mode 100644 index 000000000000..1f7a93c67c45 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -0,0 +1,534 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#ifndef __iwl_shared_h__ +#define __iwl_shared_h__ + +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/mutex.h> +#include <linux/gfp.h> +#include <linux/mm.h> /* for page_address */ +#include <net/mac80211.h> + +#include "iwl-commands.h" + +/** + * DOC: shared area - role and goal + * + * The shared area contains all the data exported by the upper layer to the + * other layers. Since the bus and transport layer shouldn't dereference + * iwl_priv, all the data needed by the upper layer and the transport / bus + * layer must be here. + * The shared area also holds pointer to all the other layers. This allows a + * layer to call a function from another layer. + * + * NOTE: All the layers hold a pointer to the shared area which must be shrd. + * A few macros assume that (_m)->shrd points to the shared area no matter + * what _m is. + * + * gets notifications about enumeration, suspend, resume. + * For the moment, the bus layer is not a linux kernel module as itself, and + * the module_init function of the driver must call the bus specific + * registration functions. These functions are listed at the end of this file. + * For the moment, there is only one implementation of this interface: PCI-e. + * This implementation is iwl-pci.c + */ + +struct iwl_cfg; +struct iwl_bus; +struct iwl_priv; +struct iwl_sensitivity_ranges; +struct iwl_trans_ops; + +#define DRV_NAME "iwlwifi" +#define IWLWIFI_VERSION "in-tree:" +#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation" +#define DRV_AUTHOR "<ilw@linux.intel.com>" + +extern struct iwl_mod_params iwlagn_mod_params; + +/** + * struct iwl_mod_params + * + * Holds the module parameters + * + * @sw_crypto: using hardware encryption, default = 0 + * @num_of_queues: number of tx queue, HW dependent + * @disable_11n: 11n capabilities enabled, default = 0 + * @amsdu_size_8K: enable 8K amsdu size, default = 1 + * @antenna: both antennas (use diversity), default = 0 + * @restart_fw: restart firmware, default = 1 + * @plcp_check: enable plcp health check, default = true + * @ack_check: disable ack health check, default = false + * @wd_disable: enable stuck queue check, default = false + * @bt_coex_active: enable bt coex, default = true + * @led_mode: system default, default = 0 + * @no_sleep_autoadjust: disable autoadjust, default = true + * @power_save: disable power save, default = false + * @power_level: power level, default = 1 + * @debug_level: levels are IWL_DL_* + * @ant_coupling: antenna coupling in dB, default = 0 + * @bt_ch_announce: BT channel inhibition, default = enable + * @wanted_ucode_alternative: ucode alternative to use, default = 1 + * @auto_agg: enable agg. without check, default = true + */ +struct iwl_mod_params { + int sw_crypto; + int num_of_queues; + int disable_11n; + int amsdu_size_8K; + int antenna; + int restart_fw; + bool plcp_check; + bool ack_check; + bool wd_disable; + bool bt_coex_active; + int led_mode; + bool no_sleep_autoadjust; + bool power_save; + int power_level; + u32 debug_level; + int ant_coupling; + bool bt_ch_announce; + int wanted_ucode_alternative; + bool auto_agg; +}; + +/** + * struct iwl_hw_params + * + * Holds the module parameters + * + * @max_txq_num: Max # Tx queues supported + * @num_ampdu_queues: num of ampdu queues + * @tx_chains_num: Number of TX chains + * @rx_chains_num: Number of RX chains + * @valid_tx_ant: usable antennas for TX + * @valid_rx_ant: usable antennas for RX + * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX) + * @sku: sku read from EEPROM + * @rx_page_order: Rx buffer page order + * @max_inst_size: for ucode use + * @max_data_size: for ucode use + * @ct_kill_threshold: temperature threshold - in hw dependent unit + * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit + * relevant for 1000, 6000 and up + * @wd_timeout: TX queues watchdog timeout + * @calib_init_cfg: setup initial calibrations for the hw + * @calib_rt_cfg: setup runtime calibrations for the hw + * @struct iwl_sensitivity_ranges: range of sensitivity values + */ +struct iwl_hw_params { + u8 max_txq_num; + u8 num_ampdu_queues; + u8 tx_chains_num; + u8 rx_chains_num; + u8 valid_tx_ant; + u8 valid_rx_ant; + u8 ht40_channel; + bool shadow_reg_enable; + u16 sku; + u32 rx_page_order; + u32 max_inst_size; + u32 max_data_size; + u32 ct_kill_threshold; + u32 ct_kill_exit_threshold; + unsigned int wd_timeout; + + u32 calib_init_cfg; + u32 calib_rt_cfg; + const struct iwl_sensitivity_ranges *sens; +}; + +/** + * enum iwl_agg_state + * + * The state machine of the BA agreement establishment / tear down. + * These states relate to a specific RA / TID. + * + * @IWL_AGG_OFF: aggregation is not used + * @IWL_AGG_ON: aggregation session is up + * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the + * HW queue to be empty from packets for this RA /TID. + * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the + * HW queue to be empty from packets for this RA /TID. + */ +enum iwl_agg_state { + IWL_AGG_OFF = 0, + IWL_AGG_ON, + IWL_EMPTYING_HW_QUEUE_ADDBA, + IWL_EMPTYING_HW_QUEUE_DELBA, +}; + +/** + * struct iwl_ht_agg - aggregation state machine + + * This structs holds the states for the BA agreement establishment and tear + * down. It also holds the state during the BA session itself. This struct is + * duplicated for each RA / TID. + + * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the + * Tx response (REPLY_TX), and the block ack notification + * (REPLY_COMPRESSED_BA). + * @state: state of the BA agreement establishment / tear down. + * @txq_id: Tx queue used by the BA session - used by the transport layer. + * Needed by the upper layer for debugfs only. + * @wait_for_ba: Expect block-ack before next Tx reply + */ +struct iwl_ht_agg { + u32 rate_n_flags; + enum iwl_agg_state state; + u16 txq_id; + bool wait_for_ba; +}; + +/** + * struct iwl_tid_data - one for each RA / TID + + * This structs holds the states for each RA / TID. + + * @seq_number: the next WiFi sequence number to use + * @tfds_in_queue: number of packets sent to the HW queues. + * Exported for debugfs only + * @agg: aggregation state machine + */ +struct iwl_tid_data { + u16 seq_number; + u16 tfds_in_queue; + struct iwl_ht_agg agg; +}; + +/** + * struct iwl_shared - shared fields for all the layers of the driver + * + * @dbg_level_dev: dbg level set per device. Prevails on + * iwlagn_mod_params.debug_level if set (!= 0) + * @ucode_owner: IWL_OWNERSHIP_* + * @cmd_queue: command queue number + * @status: STATUS_* + * @valid_contexts: microcode/device supports multiple contexts + * @bus: pointer to the bus layer data + * @priv: pointer to the upper layer data + * @hw_params: see struct iwl_hw_params + * @workqueue: the workqueue used by all the layers of the driver + * @lock: protect general shared data + * @sta_lock: protects the station table. + * If lock and sta_lock are needed, lock must be acquired first. + * @mutex: + */ +struct iwl_shared { +#ifdef CONFIG_IWLWIFI_DEBUG + u32 dbg_level_dev; +#endif /* CONFIG_IWLWIFI_DEBUG */ + +#define IWL_OWNERSHIP_DRIVER 0 +#define IWL_OWNERSHIP_TM 1 + u8 ucode_owner; + u8 cmd_queue; + unsigned long status; + bool wowlan; + u8 valid_contexts; + + struct iwl_bus *bus; + struct iwl_priv *priv; + struct iwl_trans *trans; + struct iwl_hw_params hw_params; + + struct workqueue_struct *workqueue; + spinlock_t lock; + spinlock_t sta_lock; + struct mutex mutex; + + struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT]; + + wait_queue_head_t wait_command_queue; +}; + +/*Whatever _m is (iwl_trans, iwl_priv, iwl_bus, these macros will work */ +#define priv(_m) ((_m)->shrd->priv) +#define bus(_m) ((_m)->shrd->bus) +#define trans(_m) ((_m)->shrd->trans) +#define hw_params(_m) ((_m)->shrd->hw_params) + +#ifdef CONFIG_IWLWIFI_DEBUG +/* + * iwl_get_debug_level: Return active debug level for device + * + * Using sysfs it is possible to set per device debug level. This debug + * level will be used if set, otherwise the global debug level which can be + * set via module parameter is used. + */ +static inline u32 iwl_get_debug_level(struct iwl_shared *shrd) +{ + if (shrd->dbg_level_dev) + return shrd->dbg_level_dev; + else + return iwlagn_mod_params.debug_level; +} +#else +static inline u32 iwl_get_debug_level(struct iwl_shared *shrd) +{ + return iwlagn_mod_params.debug_level; +} +#endif + +static inline void iwl_free_pages(struct iwl_shared *shrd, unsigned long page) +{ + free_pages(page, shrd->hw_params.rx_page_order); +} + +/** + * iwl_queue_inc_wrap - increment queue index, wrap back to beginning + * @index -- current index + * @n_bd -- total number of entries in queue (must be power of 2) + */ +static inline int iwl_queue_inc_wrap(int index, int n_bd) +{ + return ++index & (n_bd - 1); +} + +/** + * iwl_queue_dec_wrap - decrement queue index, wrap back to end + * @index -- current index + * @n_bd -- total number of entries in queue (must be power of 2) + */ +static inline int iwl_queue_dec_wrap(int index, int n_bd) +{ + return --index & (n_bd - 1); +} + +struct iwl_rx_mem_buffer { + dma_addr_t page_dma; + struct page *page; + struct list_head list; +}; + +#define rxb_addr(r) page_address(r->page) + +/* + * mac80211 queues, ACs, hardware queues, FIFOs. + * + * Cf. http://wireless.kernel.org/en/developers/Documentation/mac80211/queues + * + * Mac80211 uses the following numbers, which we get as from it + * by way of skb_get_queue_mapping(skb): + * + * VO 0 + * VI 1 + * BE 2 + * BK 3 + * + * + * Regular (not A-MPDU) frames are put into hardware queues corresponding + * to the FIFOs, see comments in iwl-prph.h. Aggregated frames get their + * own queue per aggregation session (RA/TID combination), such queues are + * set up to map into FIFOs too, for which we need an AC->FIFO mapping. In + * order to map frames to the right queue, we also need an AC->hw queue + * mapping. This is implemented here. + * + * Due to the way hw queues are set up (by the hw specific modules like + * iwl-4965.c, iwl-5000.c etc.), the AC->hw queue mapping is the identity + * mapping. + */ + +static const u8 tid_to_ac[] = { + IEEE80211_AC_BE, + IEEE80211_AC_BK, + IEEE80211_AC_BK, + IEEE80211_AC_BE, + IEEE80211_AC_VI, + IEEE80211_AC_VI, + IEEE80211_AC_VO, + IEEE80211_AC_VO +}; + +static inline int get_ac_from_tid(u16 tid) +{ + if (likely(tid < ARRAY_SIZE(tid_to_ac))) + return tid_to_ac[tid]; + + /* no support for TIDs 8-15 yet */ + return -EINVAL; +} + +enum iwl_rxon_context_id { + IWL_RXON_CTX_BSS, + IWL_RXON_CTX_PAN, + + NUM_IWL_RXON_CTX +}; + +int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops, + struct iwl_cfg *cfg); +void __devexit iwl_remove(struct iwl_priv * priv); +struct iwl_device_cmd; +int __must_check iwl_rx_dispatch(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb, + struct iwl_device_cmd *cmd); + +int iwlagn_hw_valid_rtc_data_addr(u32 addr); +void iwl_start_tx_ba_trans_ready(struct iwl_priv *priv, + enum iwl_rxon_context_id ctx, + u8 sta_id, u8 tid); +void iwl_stop_tx_ba_trans_ready(struct iwl_priv *priv, + enum iwl_rxon_context_id ctx, + u8 sta_id, u8 tid); +void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state); +void iwl_nic_config(struct iwl_priv *priv); +void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb); +void iwl_apm_stop(struct iwl_priv *priv); +int iwl_apm_init(struct iwl_priv *priv); +void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand); +const char *get_cmd_string(u8 cmd); +bool iwl_check_for_ct_kill(struct iwl_priv *priv); + +void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac); +void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac); + +#ifdef CONFIG_IWLWIFI_DEBUGFS +void iwl_reset_traffic_log(struct iwl_priv *priv); +#endif /* CONFIG_IWLWIFI_DEBUGFS */ + +#ifdef CONFIG_IWLWIFI_DEBUG +void iwl_print_rx_config_cmd(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid); +#else +static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv, + enum iwl_rxon_context_id ctxid) +{ +} +#endif + +#define IWL_CMD(x) case x: return #x +#define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) + +#define IWL_TRAFFIC_ENTRIES (256) +#define IWL_TRAFFIC_ENTRY_SIZE (64) + +/***************************************************** +* DRIVER STATUS FUNCTIONS +******************************************************/ +#define STATUS_HCMD_ACTIVE 0 /* host command in progress */ +/* 1 is unused (used to be STATUS_HCMD_SYNC_ACTIVE) */ +#define STATUS_INT_ENABLED 2 +#define STATUS_RF_KILL_HW 3 +#define STATUS_CT_KILL 4 +#define STATUS_INIT 5 +#define STATUS_ALIVE 6 +#define STATUS_READY 7 +#define STATUS_TEMPERATURE 8 +#define STATUS_GEO_CONFIGURED 9 +#define STATUS_EXIT_PENDING 10 +#define STATUS_STATISTICS 12 +#define STATUS_SCANNING 13 +#define STATUS_SCAN_ABORTING 14 +#define STATUS_SCAN_HW 15 +#define STATUS_POWER_PMI 16 +#define STATUS_FW_ERROR 17 +#define STATUS_DEVICE_ENABLED 18 +#define STATUS_CHANNEL_SWITCH_PENDING 19 +#define STATUS_SCAN_COMPLETE 20 + +static inline int iwl_is_ready(struct iwl_shared *shrd) +{ + /* The adapter is 'ready' if READY and GEO_CONFIGURED bits are + * set but EXIT_PENDING is not */ + return test_bit(STATUS_READY, &shrd->status) && + test_bit(STATUS_GEO_CONFIGURED, &shrd->status) && + !test_bit(STATUS_EXIT_PENDING, &shrd->status); +} + +static inline int iwl_is_alive(struct iwl_shared *shrd) +{ + return test_bit(STATUS_ALIVE, &shrd->status); +} + +static inline int iwl_is_init(struct iwl_shared *shrd) +{ + return test_bit(STATUS_INIT, &shrd->status); +} + +static inline int iwl_is_rfkill_hw(struct iwl_shared *shrd) +{ + return test_bit(STATUS_RF_KILL_HW, &shrd->status); +} + +static inline int iwl_is_rfkill(struct iwl_shared *shrd) +{ + return iwl_is_rfkill_hw(shrd); +} + +static inline int iwl_is_ctkill(struct iwl_shared *shrd) +{ + return test_bit(STATUS_CT_KILL, &shrd->status); +} + +static inline int iwl_is_ready_rf(struct iwl_shared *shrd) +{ + if (iwl_is_rfkill(shrd)) + return 0; + + return iwl_is_ready(shrd); +} + +#endif /* #__iwl_shared_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c deleted file mode 100644 index 1ef3b7106ad5..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ /dev/null @@ -1,832 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ - -#include <net/mac80211.h> -#include <linux/etherdevice.h> -#include <linux/sched.h> -#include <linux/lockdep.h> - -#include "iwl-dev.h" -#include "iwl-core.h" -#include "iwl-sta.h" -#include "iwl-trans.h" -#include "iwl-agn.h" - -/* priv->sta_lock must be held */ -static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) -{ - - if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) - IWL_ERR(priv, "ACTIVATE a non DRIVER active station id %u addr %pM\n", - sta_id, priv->stations[sta_id].sta.sta.addr); - - if (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) { - IWL_DEBUG_ASSOC(priv, - "STA id %u addr %pM already present in uCode (according to driver)\n", - sta_id, priv->stations[sta_id].sta.sta.addr); - } else { - priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; - IWL_DEBUG_ASSOC(priv, "Added STA id %u addr %pM to uCode\n", - sta_id, priv->stations[sta_id].sta.sta.addr); - } -} - -static int iwl_process_add_sta_resp(struct iwl_priv *priv, - struct iwl_addsta_cmd *addsta, - struct iwl_rx_packet *pkt, - bool sync) -{ - u8 sta_id = addsta->sta.sta_id; - unsigned long flags; - int ret = -EIO; - - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n", - pkt->hdr.flags); - return ret; - } - - IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n", - sta_id); - - spin_lock_irqsave(&priv->sta_lock, flags); - - switch (pkt->u.add_sta.status) { - case ADD_STA_SUCCESS_MSK: - IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n"); - iwl_sta_ucode_activate(priv, sta_id); - ret = 0; - break; - case ADD_STA_NO_ROOM_IN_TABLE: - IWL_ERR(priv, "Adding station %d failed, no room in table.\n", - sta_id); - break; - case ADD_STA_NO_BLOCK_ACK_RESOURCE: - IWL_ERR(priv, "Adding station %d failed, no block ack resource.\n", - sta_id); - break; - case ADD_STA_MODIFY_NON_EXIST_STA: - IWL_ERR(priv, "Attempting to modify non-existing station %d\n", - sta_id); - break; - default: - IWL_DEBUG_ASSOC(priv, "Received REPLY_ADD_STA:(0x%08X)\n", - pkt->u.add_sta.status); - break; - } - - IWL_DEBUG_INFO(priv, "%s station id %u addr %pM\n", - priv->stations[sta_id].sta.mode == - STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", - sta_id, priv->stations[sta_id].sta.sta.addr); - - /* - * XXX: The MAC address in the command buffer is often changed from - * the original sent to the device. That is, the MAC address - * written to the command buffer often is not the same MAC address - * read from the command buffer when the command returns. This - * issue has not yet been resolved and this debugging is left to - * observe the problem. - */ - IWL_DEBUG_INFO(priv, "%s station according to cmd buffer %pM\n", - priv->stations[sta_id].sta.mode == - STA_CONTROL_MODIFY_MSK ? "Modified" : "Added", - addsta->sta.addr); - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return ret; -} - -static void iwl_add_sta_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct iwl_rx_packet *pkt) -{ - struct iwl_addsta_cmd *addsta = - (struct iwl_addsta_cmd *)cmd->cmd.payload; - - iwl_process_add_sta_resp(priv, addsta, pkt, false); - -} - -static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) -{ - u16 size = (u16)sizeof(struct iwl_addsta_cmd); - struct iwl_addsta_cmd *addsta = (struct iwl_addsta_cmd *)data; - memcpy(addsta, cmd, size); - /* resrved in 5000 */ - addsta->rate_n_flags = cpu_to_le16(0); - return size; -} - -int iwl_send_add_sta(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags) -{ - struct iwl_rx_packet *pkt = NULL; - int ret = 0; - u8 data[sizeof(*sta)]; - struct iwl_host_cmd cmd = { - .id = REPLY_ADD_STA, - .flags = flags, - .data = { data, }, - }; - u8 sta_id __maybe_unused = sta->sta.sta_id; - - IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n", - sta_id, sta->sta.addr, flags & CMD_ASYNC ? "a" : ""); - - if (flags & CMD_ASYNC) - cmd.callback = iwl_add_sta_callback; - else { - cmd.flags |= CMD_WANT_SKB; - might_sleep(); - } - - cmd.len[0] = iwlagn_build_addsta_hcmd(sta, data); - ret = trans_send_cmd(&priv->trans, &cmd); - - if (ret || (flags & CMD_ASYNC)) - return ret; - - if (ret == 0) { - pkt = (struct iwl_rx_packet *)cmd.reply_page; - ret = iwl_process_add_sta_resp(priv, sta, pkt, true); - } - iwl_free_pages(priv, cmd.reply_page); - - return ret; -} - -static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_sta *sta, - struct iwl_rxon_context *ctx) -{ - struct ieee80211_sta_ht_cap *sta_ht_inf = &sta->ht_cap; - __le32 sta_flags; - u8 mimo_ps_mode; - - if (!sta || !sta_ht_inf->ht_supported) - goto done; - - mimo_ps_mode = (sta_ht_inf->cap & IEEE80211_HT_CAP_SM_PS) >> 2; - IWL_DEBUG_ASSOC(priv, "spatial multiplexing power save mode: %s\n", - (mimo_ps_mode == WLAN_HT_CAP_SM_PS_STATIC) ? - "static" : - (mimo_ps_mode == WLAN_HT_CAP_SM_PS_DYNAMIC) ? - "dynamic" : "disabled"); - - sta_flags = priv->stations[index].sta.station_flags; - - sta_flags &= ~(STA_FLG_RTS_MIMO_PROT_MSK | STA_FLG_MIMO_DIS_MSK); - - switch (mimo_ps_mode) { - case WLAN_HT_CAP_SM_PS_STATIC: - sta_flags |= STA_FLG_MIMO_DIS_MSK; - break; - case WLAN_HT_CAP_SM_PS_DYNAMIC: - sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK; - break; - case WLAN_HT_CAP_SM_PS_DISABLED: - break; - default: - IWL_WARN(priv, "Invalid MIMO PS mode %d\n", mimo_ps_mode); - break; - } - - sta_flags |= cpu_to_le32( - (u32)sta_ht_inf->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS); - - sta_flags |= cpu_to_le32( - (u32)sta_ht_inf->ampdu_density << STA_FLG_AGG_MPDU_DENSITY_POS); - - if (iwl_is_ht40_tx_allowed(priv, ctx, &sta->ht_cap)) - sta_flags |= STA_FLG_HT40_EN_MSK; - else - sta_flags &= ~STA_FLG_HT40_EN_MSK; - - priv->stations[index].sta.station_flags = sta_flags; - done: - return; -} - -/** - * iwl_prep_station - Prepare station information for addition - * - * should be called with sta_lock held - */ -u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - const u8 *addr, bool is_ap, struct ieee80211_sta *sta) -{ - struct iwl_station_entry *station; - int i; - u8 sta_id = IWL_INVALID_STATION; - - if (is_ap) - sta_id = ctx->ap_sta_id; - else if (is_broadcast_ether_addr(addr)) - sta_id = ctx->bcast_sta_id; - else - for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) { - if (!compare_ether_addr(priv->stations[i].sta.sta.addr, - addr)) { - sta_id = i; - break; - } - - if (!priv->stations[i].used && - sta_id == IWL_INVALID_STATION) - sta_id = i; - } - - /* - * These two conditions have the same outcome, but keep them - * separate - */ - if (unlikely(sta_id == IWL_INVALID_STATION)) - return sta_id; - - /* - * uCode is not able to deal with multiple requests to add a - * station. Keep track if one is in progress so that we do not send - * another. - */ - if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { - IWL_DEBUG_INFO(priv, "STA %d already in process of being added.\n", - sta_id); - return sta_id; - } - - if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && - (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE) && - !compare_ether_addr(priv->stations[sta_id].sta.sta.addr, addr)) { - IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n", - sta_id, addr); - return sta_id; - } - - station = &priv->stations[sta_id]; - station->used = IWL_STA_DRIVER_ACTIVE; - IWL_DEBUG_ASSOC(priv, "Add STA to driver ID %d: %pM\n", - sta_id, addr); - priv->num_stations++; - - /* Set up the REPLY_ADD_STA command to send to device */ - memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd)); - memcpy(station->sta.sta.addr, addr, ETH_ALEN); - station->sta.mode = 0; - station->sta.sta.sta_id = sta_id; - station->sta.station_flags = ctx->station_flags; - station->ctxid = ctx->ctxid; - - if (sta) { - struct iwl_station_priv_common *sta_priv; - - sta_priv = (void *)sta->drv_priv; - sta_priv->ctx = ctx; - } - - /* - * OK to call unconditionally, since local stations (IBSS BSSID - * STA and broadcast STA) pass in a NULL sta, and mac80211 - * doesn't allow HT IBSS. - */ - iwl_set_ht_add_station(priv, sta_id, sta, ctx); - - return sta_id; - -} - -#define STA_WAIT_TIMEOUT (HZ/2) - -/** - * iwl_add_station_common - - */ -int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - const u8 *addr, bool is_ap, - struct ieee80211_sta *sta, u8 *sta_id_r) -{ - unsigned long flags_spin; - int ret = 0; - u8 sta_id; - struct iwl_addsta_cmd sta_cmd; - - *sta_id_r = 0; - spin_lock_irqsave(&priv->sta_lock, flags_spin); - sta_id = iwl_prep_station(priv, ctx, addr, is_ap, sta); - if (sta_id == IWL_INVALID_STATION) { - IWL_ERR(priv, "Unable to prepare station %pM for addition\n", - addr); - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return -EINVAL; - } - - /* - * uCode is not able to deal with multiple requests to add a - * station. Keep track if one is in progress so that we do not send - * another. - */ - if (priv->stations[sta_id].used & IWL_STA_UCODE_INPROGRESS) { - IWL_DEBUG_INFO(priv, "STA %d already in process of being added.\n", - sta_id); - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return -EEXIST; - } - - if ((priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE) && - (priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { - IWL_DEBUG_ASSOC(priv, "STA %d (%pM) already added, not adding again.\n", - sta_id, addr); - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return -EEXIST; - } - - priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS; - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd)); - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - /* Add station to device's station table */ - ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); - if (ret) { - spin_lock_irqsave(&priv->sta_lock, flags_spin); - IWL_ERR(priv, "Adding station %pM failed.\n", - priv->stations[sta_id].sta.sta.addr); - priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; - priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - } - *sta_id_r = sta_id; - return ret; -} - -/** - * iwl_sta_ucode_deactivate - deactivate ucode status for a station - * - * priv->sta_lock must be held - */ -static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id) -{ - /* Ucode must be active and driver must be non active */ - if ((priv->stations[sta_id].used & - (IWL_STA_UCODE_ACTIVE | IWL_STA_DRIVER_ACTIVE)) != IWL_STA_UCODE_ACTIVE) - IWL_ERR(priv, "removed non active STA %u\n", sta_id); - - priv->stations[sta_id].used &= ~IWL_STA_UCODE_ACTIVE; - - memset(&priv->stations[sta_id], 0, sizeof(struct iwl_station_entry)); - IWL_DEBUG_ASSOC(priv, "Removed STA %u\n", sta_id); -} - -static int iwl_send_remove_station(struct iwl_priv *priv, - const u8 *addr, int sta_id, - bool temporary) -{ - struct iwl_rx_packet *pkt; - int ret; - - unsigned long flags_spin; - struct iwl_rem_sta_cmd rm_sta_cmd; - - struct iwl_host_cmd cmd = { - .id = REPLY_REMOVE_STA, - .len = { sizeof(struct iwl_rem_sta_cmd), }, - .flags = CMD_SYNC, - .data = { &rm_sta_cmd, }, - }; - - memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd)); - rm_sta_cmd.num_sta = 1; - memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN); - - cmd.flags |= CMD_WANT_SKB; - - ret = trans_send_cmd(&priv->trans, &cmd); - - if (ret) - return ret; - - pkt = (struct iwl_rx_packet *)cmd.reply_page; - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from REPLY_REMOVE_STA (0x%08X)\n", - pkt->hdr.flags); - ret = -EIO; - } - - if (!ret) { - switch (pkt->u.rem_sta.status) { - case REM_STA_SUCCESS_MSK: - if (!temporary) { - spin_lock_irqsave(&priv->sta_lock, flags_spin); - iwl_sta_ucode_deactivate(priv, sta_id); - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - } - IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n"); - break; - default: - ret = -EIO; - IWL_ERR(priv, "REPLY_REMOVE_STA failed\n"); - break; - } - } - iwl_free_pages(priv, cmd.reply_page); - - return ret; -} - -/** - * iwl_remove_station - Remove driver's knowledge of station. - */ -int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, - const u8 *addr) -{ - unsigned long flags; - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_INFO(priv, - "Unable to remove station %pM, device not ready.\n", - addr); - /* - * It is typical for stations to be removed when we are - * going down. Return success since device will be down - * soon anyway - */ - return 0; - } - - IWL_DEBUG_ASSOC(priv, "Removing STA from driver:%d %pM\n", - sta_id, addr); - - if (WARN_ON(sta_id == IWL_INVALID_STATION)) - return -EINVAL; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { - IWL_DEBUG_INFO(priv, "Removing %pM but non DRIVER active\n", - addr); - goto out_err; - } - - if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { - IWL_DEBUG_INFO(priv, "Removing %pM but non UCODE active\n", - addr); - goto out_err; - } - - if (priv->stations[sta_id].used & IWL_STA_LOCAL) { - kfree(priv->stations[sta_id].lq); - priv->stations[sta_id].lq = NULL; - } - - priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; - - priv->num_stations--; - - if (WARN_ON(priv->num_stations < 0)) - priv->num_stations = 0; - - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_remove_station(priv, addr, sta_id, false); -out_err: - spin_unlock_irqrestore(&priv->sta_lock, flags); - return -EINVAL; -} - -/** - * iwl_clear_ucode_stations - clear ucode station table bits - * - * This function clears all the bits in the driver indicating - * which stations are active in the ucode. Call when something - * other than explicit station management would cause this in - * the ucode, e.g. unassociated RXON. - */ -void iwl_clear_ucode_stations(struct iwl_priv *priv, - struct iwl_rxon_context *ctx) -{ - int i; - unsigned long flags_spin; - bool cleared = false; - - IWL_DEBUG_INFO(priv, "Clearing ucode stations in driver\n"); - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - for (i = 0; i < priv->hw_params.max_stations; i++) { - if (ctx && ctx->ctxid != priv->stations[i].ctxid) - continue; - - if (priv->stations[i].used & IWL_STA_UCODE_ACTIVE) { - IWL_DEBUG_INFO(priv, "Clearing ucode active for station %d\n", i); - priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; - cleared = true; - } - } - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - if (!cleared) - IWL_DEBUG_INFO(priv, "No active stations found to be cleared\n"); -} - -/** - * iwl_restore_stations() - Restore driver known stations to device - * - * All stations considered active by driver, but not present in ucode, is - * restored. - * - * Function sleeps. - */ -void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - struct iwl_addsta_cmd sta_cmd; - struct iwl_link_quality_cmd lq; - unsigned long flags_spin; - int i; - bool found = false; - int ret; - bool send_lq; - - if (!iwl_is_ready(priv)) { - IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n"); - return; - } - - IWL_DEBUG_ASSOC(priv, "Restoring all known stations ... start.\n"); - spin_lock_irqsave(&priv->sta_lock, flags_spin); - for (i = 0; i < priv->hw_params.max_stations; i++) { - if (ctx->ctxid != priv->stations[i].ctxid) - continue; - if ((priv->stations[i].used & IWL_STA_DRIVER_ACTIVE) && - !(priv->stations[i].used & IWL_STA_UCODE_ACTIVE)) { - IWL_DEBUG_ASSOC(priv, "Restoring sta %pM\n", - priv->stations[i].sta.sta.addr); - priv->stations[i].sta.mode = 0; - priv->stations[i].used |= IWL_STA_UCODE_INPROGRESS; - found = true; - } - } - - for (i = 0; i < priv->hw_params.max_stations; i++) { - if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) { - memcpy(&sta_cmd, &priv->stations[i].sta, - sizeof(struct iwl_addsta_cmd)); - send_lq = false; - if (priv->stations[i].lq) { - memcpy(&lq, priv->stations[i].lq, - sizeof(struct iwl_link_quality_cmd)); - send_lq = true; - } - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); - if (ret) { - spin_lock_irqsave(&priv->sta_lock, flags_spin); - IWL_ERR(priv, "Adding station %pM failed.\n", - priv->stations[i].sta.sta.addr); - priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE; - priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - } - /* - * Rate scaling has already been initialized, send - * current LQ command - */ - if (send_lq) - iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true); - spin_lock_irqsave(&priv->sta_lock, flags_spin); - priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS; - } - } - - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - if (!found) - IWL_DEBUG_INFO(priv, "Restoring all known stations .... no stations to be restored.\n"); - else - IWL_DEBUG_INFO(priv, "Restoring all known stations .... complete.\n"); -} - -void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx) -{ - unsigned long flags; - int sta_id = ctx->ap_sta_id; - int ret; - struct iwl_addsta_cmd sta_cmd; - struct iwl_link_quality_cmd lq; - bool active; - - spin_lock_irqsave(&priv->sta_lock, flags); - if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { - spin_unlock_irqrestore(&priv->sta_lock, flags); - return; - } - - memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd)); - sta_cmd.mode = 0; - memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq)); - - active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE; - priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - if (active) { - ret = iwl_send_remove_station( - priv, priv->stations[sta_id].sta.sta.addr, - sta_id, true); - if (ret) - IWL_ERR(priv, "failed to remove STA %pM (%d)\n", - priv->stations[sta_id].sta.sta.addr, ret); - } - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].used |= IWL_STA_DRIVER_ACTIVE; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC); - if (ret) - IWL_ERR(priv, "failed to re-add STA %pM (%d)\n", - priv->stations[sta_id].sta.sta.addr, ret); - iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true); -} - -int iwl_get_free_ucode_key_offset(struct iwl_priv *priv) -{ - int i; - - for (i = 0; i < priv->sta_key_max_num; i++) - if (!test_and_set_bit(i, &priv->ucode_key_table)) - return i; - - return WEP_INVALID_OFFSET; -} - -void iwl_dealloc_bcast_stations(struct iwl_priv *priv) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&priv->sta_lock, flags); - for (i = 0; i < priv->hw_params.max_stations; i++) { - if (!(priv->stations[i].used & IWL_STA_BCAST)) - continue; - - priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE; - priv->num_stations--; - if (WARN_ON(priv->num_stations < 0)) - priv->num_stations = 0; - kfree(priv->stations[i].lq); - priv->stations[i].lq = NULL; - } - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -#ifdef CONFIG_IWLWIFI_DEBUG -static void iwl_dump_lq_cmd(struct iwl_priv *priv, - struct iwl_link_quality_cmd *lq) -{ - int i; - IWL_DEBUG_RATE(priv, "lq station id 0x%x\n", lq->sta_id); - IWL_DEBUG_RATE(priv, "lq ant 0x%X 0x%X\n", - lq->general_params.single_stream_ant_msk, - lq->general_params.dual_stream_ant_msk); - - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) - IWL_DEBUG_RATE(priv, "lq index %d 0x%X\n", - i, lq->rs_table[i].rate_n_flags); -} -#else -static inline void iwl_dump_lq_cmd(struct iwl_priv *priv, - struct iwl_link_quality_cmd *lq) -{ -} -#endif - -/** - * is_lq_table_valid() - Test one aspect of LQ cmd for validity - * - * It sometimes happens when a HT rate has been in use and we - * loose connectivity with AP then mac80211 will first tell us that the - * current channel is not HT anymore before removing the station. In such a - * scenario the RXON flags will be updated to indicate we are not - * communicating HT anymore, but the LQ command may still contain HT rates. - * Test for this to prevent driver from sending LQ command between the time - * RXON flags are updated and when LQ command is updated. - */ -static bool is_lq_table_valid(struct iwl_priv *priv, - struct iwl_rxon_context *ctx, - struct iwl_link_quality_cmd *lq) -{ - int i; - - if (ctx->ht.enabled) - return true; - - IWL_DEBUG_INFO(priv, "Channel %u is not an HT channel\n", - ctx->active.channel); - for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) { - if (le32_to_cpu(lq->rs_table[i].rate_n_flags) & RATE_MCS_HT_MSK) { - IWL_DEBUG_INFO(priv, - "index %d of LQ expects HT channel\n", - i); - return false; - } - } - return true; -} - -/** - * iwl_send_lq_cmd() - Send link quality command - * @init: This command is sent as part of station initialization right - * after station has been added. - * - * The link quality command is sent as the last step of station creation. - * This is the special case in which init is set and we call a callback in - * this case to clear the state indicating that station creation is in - * progress. - */ -int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - struct iwl_link_quality_cmd *lq, u8 flags, bool init) -{ - int ret = 0; - unsigned long flags_spin; - - struct iwl_host_cmd cmd = { - .id = REPLY_TX_LINK_QUALITY_CMD, - .len = { sizeof(struct iwl_link_quality_cmd), }, - .flags = flags, - .data = { lq, }, - }; - - if (WARN_ON(lq->sta_id == IWL_INVALID_STATION)) - return -EINVAL; - - - spin_lock_irqsave(&priv->sta_lock, flags_spin); - if (!(priv->stations[lq->sta_id].used & IWL_STA_DRIVER_ACTIVE)) { - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - return -EINVAL; - } - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - - iwl_dump_lq_cmd(priv, lq); - if (WARN_ON(init && (cmd.flags & CMD_ASYNC))) - return -EINVAL; - - if (is_lq_table_valid(priv, ctx, lq)) - ret = trans_send_cmd(&priv->trans, &cmd); - else - ret = -EINVAL; - - if (cmd.flags & CMD_ASYNC) - return ret; - - if (init) { - IWL_DEBUG_INFO(priv, "init LQ command complete, clearing sta addition status for sta %d\n", - lq->sta_id); - spin_lock_irqsave(&priv->sta_lock, flags_spin); - priv->stations[lq->sta_id].used &= ~IWL_STA_UCODE_INPROGRESS; - spin_unlock_irqrestore(&priv->sta_lock, flags_spin); - } - return ret; -} - -int iwl_mac_sta_remove(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct iwl_priv *priv = hw->priv; - struct iwl_station_priv_common *sta_common = (void *)sta->drv_priv; - int ret; - - IWL_DEBUG_INFO(priv, "received request to remove station %pM\n", - sta->addr); - mutex_lock(&priv->mutex); - IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n", - sta->addr); - ret = iwl_remove_station(priv, sta_common->sta_id, sta->addr); - if (ret) - IWL_ERR(priv, "Error removing station %pM\n", - sta->addr); - mutex_unlock(&priv->mutex); - return ret; -} diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h deleted file mode 100644 index 9a6768d66851..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ /dev/null @@ -1,138 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ -#ifndef __iwl_sta_h__ -#define __iwl_sta_h__ - -#include "iwl-dev.h" - -#define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ -#define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ -#define IWL_STA_UCODE_INPROGRESS BIT(2) /* ucode entry is in process of - being activated */ -#define IWL_STA_LOCAL BIT(3) /* station state not directed by mac80211; - (this is for the IBSS BSSID stations) */ -#define IWL_STA_BCAST BIT(4) /* this station is the special bcast station */ - - -void iwl_restore_stations(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -void iwl_clear_ucode_stations(struct iwl_priv *priv, - struct iwl_rxon_context *ctx); -void iwl_dealloc_bcast_stations(struct iwl_priv *priv); -int iwl_get_free_ucode_key_offset(struct iwl_priv *priv); -int iwl_send_add_sta(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags); -int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - const u8 *addr, bool is_ap, - struct ieee80211_sta *sta, u8 *sta_id_r); -int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id, - const u8 *addr); -int iwl_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); - -u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - const u8 *addr, bool is_ap, struct ieee80211_sta *sta); - -int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx, - struct iwl_link_quality_cmd *lq, u8 flags, bool init); -void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx); - -/** - * iwl_clear_driver_stations - clear knowledge of all stations from driver - * @priv: iwl priv struct - * - * This is called during iwl_down() to make sure that in the case - * we're coming there from a hardware restart mac80211 will be - * able to reconfigure stations -- if we're getting there in the - * normal down flow then the stations will already be cleared. - */ -static inline void iwl_clear_driver_stations(struct iwl_priv *priv) -{ - unsigned long flags; - struct iwl_rxon_context *ctx; - - spin_lock_irqsave(&priv->sta_lock, flags); - memset(priv->stations, 0, sizeof(priv->stations)); - priv->num_stations = 0; - - priv->ucode_key_table = 0; - - for_each_context(priv, ctx) { - /* - * Remove all key information that is not stored as part - * of station information since mac80211 may not have had - * a chance to remove all the keys. When device is - * reconfigured by mac80211 after an error all keys will - * be reconfigured. - */ - memset(ctx->wep_keys, 0, sizeof(ctx->wep_keys)); - ctx->key_mapping_keys = 0; - } - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} - -static inline int iwl_sta_id(struct ieee80211_sta *sta) -{ - if (WARN_ON(!sta)) - return IWL_INVALID_STATION; - - return ((struct iwl_station_priv_common *)sta->drv_priv)->sta_id; -} - -/** - * iwl_sta_id_or_broadcast - return sta_id or broadcast sta - * @priv: iwl priv - * @context: the current context - * @sta: mac80211 station - * - * In certain circumstances mac80211 passes a station pointer - * that may be %NULL, for example during TX or key setup. In - * that case, we need to use the broadcast station, so this - * inline wraps that pattern. - */ -static inline int iwl_sta_id_or_broadcast(struct iwl_priv *priv, - struct iwl_rxon_context *context, - struct ieee80211_sta *sta) -{ - int sta_id; - - if (!sta) - return context->bcast_sta_id; - - sta_id = iwl_sta_id(sta); - - /* - * mac80211 should not be passing a partially - * initialised station! - */ - WARN_ON(sta_id == IWL_INVALID_STATION); - - return sta_id; -} -#endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c index b11f60de4f1e..5e50d88f302b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sv-open.c +++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c @@ -63,6 +63,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/dma-mapping.h> #include <net/net_namespace.h> #include <linux/netdevice.h> #include <net/cfg80211.h> @@ -72,7 +73,6 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-debug.h" -#include "iwl-fh.h" #include "iwl-io.h" #include "iwl-agn.h" #include "iwl-testmode.h" @@ -184,7 +184,7 @@ static void iwl_trace_cleanup(struct iwl_priv *priv) if (priv->testmode_trace.trace_enabled) { if (priv->testmode_trace.cpu_addr && priv->testmode_trace.dma_addr) - dma_free_coherent(priv->bus->dev, + dma_free_coherent(bus(priv)->dev, priv->testmode_trace.total_size, priv->testmode_trace.cpu_addr, priv->testmode_trace.dma_addr); @@ -239,7 +239,7 @@ static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb) IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x," " len %d\n", cmd.id, cmd.flags, cmd.len[0]); /* ok, let's submit the command to ucode */ - return trans_send_cmd(&priv->trans, &cmd); + return iwl_trans_send_cmd(trans(priv), &cmd); } @@ -277,7 +277,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_REG_READ32: - val32 = iwl_read32(priv, ofs); + val32 = iwl_read32(bus(priv), ofs); IWL_INFO(priv, "32bit value to read 0x%x\n", val32); skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20); @@ -299,7 +299,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) } else { val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]); IWL_INFO(priv, "32bit value to write 0x%x\n", val32); - iwl_write32(priv, ofs, val32); + iwl_write32(bus(priv), ofs, val32); } break; case IWL_TM_CMD_APP2DEV_REG_WRITE8: @@ -309,7 +309,7 @@ static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb) } else { val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]); IWL_INFO(priv, "8bit value to write 0x%x\n", val8); - iwl_write8(priv, ofs, val8); + iwl_write8(bus(priv), ofs, val8); } break; default: @@ -405,7 +405,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb) case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB: iwl_testmode_cfg_init_calib(priv); - trans_stop_device(&priv->trans); + iwl_trans_stop_device(trans(priv)); break; case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW: @@ -484,7 +484,7 @@ static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb) struct iwl_priv *priv = hw->priv; struct sk_buff *skb; int status = 0; - struct device *dev = priv->bus->dev; + struct device *dev = bus(priv)->dev; switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_BEGIN_TRACE: @@ -613,7 +613,7 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) owner = nla_get_u8(tb[IWL_TM_ATTR_UCODE_OWNER]); if ((owner == IWL_OWNERSHIP_DRIVER) || (owner == IWL_OWNERSHIP_TM)) - priv->ucode_owner = owner; + priv->shrd->ucode_owner = owner; else { IWL_DEBUG_INFO(priv, "Invalid owner\n"); return -EINVAL; @@ -641,7 +641,7 @@ static int iwl_testmode_ownership(struct ieee80211_hw *hw, struct nlattr **tb) * @data: pointer to user space message * @len: length in byte of @data */ -int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) +int iwlagn_mac_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) { struct nlattr *tb[IWL_TM_ATTR_MAX]; struct iwl_priv *priv = hw->priv; @@ -661,7 +661,7 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) return -ENOMSG; } /* in case multiple accesses to the device happens */ - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) { case IWL_TM_CMD_APP2DEV_UCODE: @@ -702,11 +702,11 @@ int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len) break; } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); return result; } -int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, +int iwlagn_mac_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, struct netlink_callback *cb, void *data, int len) { @@ -738,7 +738,7 @@ int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, } /* in case multiple accesses to the device happens */ - mutex_lock(&priv->mutex); + mutex_lock(&priv->shrd->mutex); switch (cmd) { case IWL_TM_CMD_APP2DEV_READ_TRACE: IWL_DEBUG_INFO(priv, "uCode trace cmd to driver\n"); @@ -749,6 +749,6 @@ int iwl_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, break; } - mutex_unlock(&priv->mutex); + mutex_unlock(&priv->shrd->mutex); return result; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h b/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h deleted file mode 100644 index b79330d84185..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h +++ /dev/null @@ -1,82 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ -#ifndef __iwl_trans_int_pcie_h__ -#define __iwl_trans_int_pcie_h__ - -/*This file includes the declaration that are internal to the - * trans_pcie layer */ - -/***************************************************** -* RX -******************************************************/ -void iwl_bg_rx_replenish(struct work_struct *data); -void iwl_irq_tasklet(struct iwl_priv *priv); -void iwlagn_rx_replenish(struct iwl_priv *priv); -void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl_rx_queue *q); - -/***************************************************** -* ICT -******************************************************/ -int iwl_reset_ict(struct iwl_priv *priv); -void iwl_disable_ict(struct iwl_priv *priv); -int iwl_alloc_isr_ict(struct iwl_priv *priv); -void iwl_free_isr_ict(struct iwl_priv *priv); -irqreturn_t iwl_isr_ict(int irq, void *data); - - -/***************************************************** -* TX / HCMD -******************************************************/ -void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); -void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int index); -int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - dma_addr_t addr, u16 len, u8 reset); -int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, - int count, int slots_num, u32 id); -int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); -int __must_check iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, - u16 len, const void *data); -void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); -void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - u16 byte_cnt); -int iwl_trans_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo); -void iwl_trans_set_wr_ptrs(struct iwl_priv *priv, - int txq_id, u32 index); -void iwl_trans_tx_queue_set_status(struct iwl_priv *priv, - struct iwl_tx_queue *txq, - int tx_fifo_id, int scd_retry); -void iwl_trans_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid, - int frame_limit); - -#endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h new file mode 100644 index 000000000000..2b6756e8b8f9 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h @@ -0,0 +1,436 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#ifndef __iwl_trans_int_pcie_h__ +#define __iwl_trans_int_pcie_h__ + +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/skbuff.h> +#include <linux/pci.h> + +#include "iwl-fh.h" +#include "iwl-csr.h" +#include "iwl-shared.h" +#include "iwl-trans.h" +#include "iwl-debug.h" +#include "iwl-io.h" + +struct iwl_tx_queue; +struct iwl_queue; +struct iwl_host_cmd; + +/*This file includes the declaration that are internal to the + * trans_pcie layer */ + +/** + * struct isr_statistics - interrupt statistics + * + */ +struct isr_statistics { + u32 hw; + u32 sw; + u32 err_code; + u32 sch; + u32 alive; + u32 rfkill; + u32 ctkill; + u32 wakeup; + u32 rx; + u32 tx; + u32 unhandled; +}; + +/** + * struct iwl_rx_queue - Rx queue + * @bd: driver's pointer to buffer of receive buffer descriptors (rbd) + * @bd_dma: bus address of buffer of receive buffer descriptors (rbd) + * @pool: + * @queue: + * @read: Shared index to newest available Rx buffer + * @write: Shared index to oldest written Rx packet + * @free_count: Number of pre-allocated buffers in rx_free + * @write_actual: + * @rx_free: list of free SKBs for use + * @rx_used: List of Rx buffers with no SKB + * @need_update: flag to indicate we need to update read/write index + * @rb_stts: driver's pointer to receive buffer status + * @rb_stts_dma: bus address of receive buffer status + * @lock: + * + * NOTE: rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers + */ +struct iwl_rx_queue { + __le32 *bd; + dma_addr_t bd_dma; + struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; + struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; + u32 read; + u32 write; + u32 free_count; + u32 write_actual; + struct list_head rx_free; + struct list_head rx_used; + int need_update; + struct iwl_rb_status *rb_stts; + dma_addr_t rb_stts_dma; + spinlock_t lock; +}; + +struct iwl_dma_ptr { + dma_addr_t dma; + void *addr; + size_t size; +}; + +/* + * This queue number is required for proper operation + * because the ucode will stop/start the scheduler as + * required. + */ +#define IWL_IPAN_MCAST_QUEUE 8 + +struct iwl_cmd_meta { + /* only for SYNC commands, iff the reply skb is wanted */ + struct iwl_host_cmd *source; + + u32 flags; + + DEFINE_DMA_UNMAP_ADDR(mapping); + DEFINE_DMA_UNMAP_LEN(len); +}; + +/* + * Generic queue structure + * + * Contains common data for Rx and Tx queues. + * + * Note the difference between n_bd and n_window: the hardware + * always assumes 256 descriptors, so n_bd is always 256 (unless + * there might be HW changes in the future). For the normal TX + * queues, n_window, which is the size of the software queue data + * is also 256; however, for the command queue, n_window is only + * 32 since we don't need so many commands pending. Since the HW + * still uses 256 BDs for DMA though, n_bd stays 256. As a result, + * the software buffers (in the variables @meta, @txb in struct + * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds + * in the same struct) have 256. + * This means that we end up with the following: + * HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 | + * SW entries: | 0 | ... | 31 | + * where N is a number between 0 and 7. This means that the SW + * data is a window overlayed over the HW queue. + */ +struct iwl_queue { + int n_bd; /* number of BDs in this queue */ + int write_ptr; /* 1-st empty entry (index) host_w*/ + int read_ptr; /* last used entry (index) host_r*/ + /* use for monitoring and recovering the stuck queue */ + dma_addr_t dma_addr; /* physical addr for BD's */ + int n_window; /* safe queue window */ + u32 id; + int low_mark; /* low watermark, resume queue if free + * space more than this */ + int high_mark; /* high watermark, stop queue if free + * space less than this */ +}; + +/** + * struct iwl_tx_queue - Tx Queue for DMA + * @q: generic Rx/Tx queue descriptor + * @bd: base of circular buffer of TFDs + * @cmd: array of command/TX buffer pointers + * @meta: array of meta data for each command/tx buffer + * @dma_addr_cmd: physical address of cmd/tx buffer array + * @txb: array of per-TFD driver data + * @time_stamp: time (in jiffies) of last read_ptr change + * @need_update: indicates need to update read/write index + * @sched_retry: indicates queue is high-throughput aggregation (HT AGG) enabled + * @sta_id: valid if sched_retry is set + * @tid: valid if sched_retry is set + * + * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame + * descriptors) and required locking structures. + */ +#define TFD_TX_CMD_SLOTS 256 +#define TFD_CMD_SLOTS 32 + +struct iwl_tx_queue { + struct iwl_queue q; + struct iwl_tfd *tfds; + struct iwl_device_cmd **cmd; + struct iwl_cmd_meta *meta; + struct sk_buff **skbs; + unsigned long time_stamp; + u8 need_update; + u8 sched_retry; + u8 active; + u8 swq_id; + + u16 sta_id; + u16 tid; +}; + +/** + * struct iwl_trans_pcie - PCIe transport specific data + * @rxq: all the RX queue data + * @rx_replenish: work that will be called when buffers need to be allocated + * @trans: pointer to the generic transport area + * @scd_base_addr: scheduler sram base address in SRAM + * @scd_bc_tbls: pointer to the byte count table of the scheduler + * @kw: keep warm address + * @ac_to_fifo: to what fifo is a specifc AC mapped ? + * @ac_to_queue: to what tx queue is a specifc AC mapped ? + * @mcast_queue: + * @txq: Tx DMA processing queues + * @txq_ctx_active_msk: what queue is active + * queue_stopped: tracks what queue is stopped + * queue_stop_count: tracks what SW queue is stopped + */ +struct iwl_trans_pcie { + struct iwl_rx_queue rxq; + struct work_struct rx_replenish; + struct iwl_trans *trans; + + /* INT ICT Table */ + __le32 *ict_tbl; + void *ict_tbl_vir; + dma_addr_t ict_tbl_dma; + dma_addr_t aligned_ict_tbl_dma; + int ict_index; + u32 inta; + bool use_ict; + struct tasklet_struct irq_tasklet; + struct isr_statistics isr_stats; + + u32 inta_mask; + u32 scd_base_addr; + struct iwl_dma_ptr scd_bc_tbls; + struct iwl_dma_ptr kw; + + const u8 *ac_to_fifo[NUM_IWL_RXON_CTX]; + const u8 *ac_to_queue[NUM_IWL_RXON_CTX]; + u8 mcast_queue[NUM_IWL_RXON_CTX]; + + struct iwl_tx_queue *txq; + unsigned long txq_ctx_active_msk; +#define IWL_MAX_HW_QUEUES 32 + unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)]; + atomic_t queue_stop_count[4]; +}; + +#define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ + ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific)) + +/***************************************************** +* RX +******************************************************/ +void iwl_bg_rx_replenish(struct work_struct *data); +void iwl_irq_tasklet(struct iwl_trans *trans); +void iwlagn_rx_replenish(struct iwl_trans *trans); +void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, + struct iwl_rx_queue *q); + +/***************************************************** +* ICT +******************************************************/ +int iwl_reset_ict(struct iwl_trans *trans); +void iwl_disable_ict(struct iwl_trans *trans); +int iwl_alloc_isr_ict(struct iwl_trans *trans); +void iwl_free_isr_ict(struct iwl_trans *trans); +irqreturn_t iwl_isr_ict(int irq, void *data); + +/***************************************************** +* TX / HCMD +******************************************************/ +void iwl_txq_update_write_ptr(struct iwl_trans *trans, + struct iwl_tx_queue *txq); +int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans, + struct iwl_tx_queue *txq, + dma_addr_t addr, u16 len, u8 reset); +int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id); +int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); +void iwl_tx_cmd_complete(struct iwl_trans *trans, + struct iwl_rx_mem_buffer *rxb, int handler_status); +void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, + struct iwl_tx_queue *txq, + u16 byte_cnt); +void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id); +int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, int sta_id, + int tid); +void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index); +void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, + struct iwl_tx_queue *txq, + int tx_fifo_id, int scd_retry); +int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, int sta_id, + int tid, u16 *ssn); +void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, + int sta_id, int tid, int frame_limit); +void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, + int index, enum dma_data_direction dma_dir); +int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, + struct sk_buff_head *skbs); +int iwl_queue_space(const struct iwl_queue *q); + +/***************************************************** +* Error handling +******************************************************/ +int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, + char **buf, bool display); +int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display); +void iwl_dump_csr(struct iwl_trans *trans); + +/***************************************************** +* Helpers +******************************************************/ +static inline void iwl_disable_interrupts(struct iwl_trans *trans) +{ + clear_bit(STATUS_INT_ENABLED, &trans->shrd->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(bus(trans), CSR_INT, 0xffffffff); + iwl_write32(bus(trans), CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); +} + +static inline void iwl_enable_interrupts(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + IWL_DEBUG_ISR(trans, "Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &trans->shrd->status); + iwl_write32(bus(trans), CSR_INT_MASK, trans_pcie->inta_mask); +} + +/* + * we have 8 bits used like this: + * + * 7 6 5 4 3 2 1 0 + * | | | | | | | | + * | | | | | | +-+-------- AC queue (0-3) + * | | | | | | + * | +-+-+-+-+------------ HW queue ID + * | + * +---------------------- unused + */ +static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq) +{ + BUG_ON(ac > 3); /* only have 2 bits */ + BUG_ON(hwq > 31); /* only use 5 bits */ + + txq->swq_id = (hwq << 2) | ac; +} + +static inline void iwl_wake_queue(struct iwl_trans *trans, + struct iwl_tx_queue *txq) +{ + u8 queue = txq->swq_id; + u8 ac = queue & 3; + u8 hwq = (queue >> 2) & 0x1f; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) + if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) + iwl_wake_sw_queue(priv(trans), ac); +} + +static inline void iwl_stop_queue(struct iwl_trans *trans, + struct iwl_tx_queue *txq) +{ + u8 queue = txq->swq_id; + u8 ac = queue & 3; + u8 hwq = (queue >> 2) & 0x1f; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) + if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) + iwl_stop_sw_queue(priv(trans), ac); +} + +#ifdef ieee80211_stop_queue +#undef ieee80211_stop_queue +#endif + +#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue + +#ifdef ieee80211_wake_queue +#undef ieee80211_wake_queue +#endif + +#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue + +static inline void iwl_txq_ctx_activate(struct iwl_trans_pcie *trans_pcie, + int txq_id) +{ + set_bit(txq_id, &trans_pcie->txq_ctx_active_msk); +} + +static inline void iwl_txq_ctx_deactivate(struct iwl_trans_pcie *trans_pcie, + int txq_id) +{ + clear_bit(txq_id, &trans_pcie->txq_ctx_active_msk); +} + +static inline int iwl_queue_used(const struct iwl_queue *q, int i) +{ + return q->write_ptr >= q->read_ptr ? + (i >= q->read_ptr && i < q->write_ptr) : + !(i < q->read_ptr && i >= q->write_ptr); +} + +static inline u8 get_cmd_index(struct iwl_queue *q, u32 index) +{ + return index & (q->n_window - 1); +} + +#define IWL_TX_FIFO_BK 0 /* shared */ +#define IWL_TX_FIFO_BE 1 +#define IWL_TX_FIFO_VI 2 /* shared */ +#define IWL_TX_FIFO_VO 3 +#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK +#define IWL_TX_FIFO_BE_IPAN 4 +#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI +#define IWL_TX_FIFO_VO_IPAN 5 +/* re-uses the VO FIFO, uCode will properly flush/schedule */ +#define IWL_TX_FIFO_AUX 5 +#define IWL_TX_FIFO_UNUSED -1 + +/* AUX (TX during scan dwell) queue */ +#define IWL_AUX_QUEUE 10 + +#endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c new file mode 100644 index 000000000000..374c68cc1d70 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c @@ -0,0 +1,1435 @@ +/****************************************************************************** + * + * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. + * + * Portions of this file are derived from the ipw3945 project, as well + * as portions of the ieee80211 subsystem header files. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/gfp.h> + +/*TODO: Remove include to iwl-core.h*/ +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-trans-pcie-int.h" + +/****************************************************************************** + * + * RX path functions + * + ******************************************************************************/ + +/* + * Rx theory of operation + * + * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), + * each of which point to Receive Buffers to be filled by the NIC. These get + * used not only for Rx frames, but for any command response or notification + * from the NIC. The driver and NIC manage the Rx buffers by means + * of indexes into the circular buffer. + * + * Rx Queue Indexes + * The host/firmware share two index registers for managing the Rx buffers. + * + * The READ index maps to the first position that the firmware may be writing + * to -- the driver can read up to (but not including) this position and get + * good data. + * The READ index is managed by the firmware once the card is enabled. + * + * The WRITE index maps to the last position the driver has read from -- the + * position preceding WRITE is the last slot the firmware can place a packet. + * + * The queue is empty (no good data) if WRITE = READ - 1, and is full if + * WRITE = READ. + * + * During initialization, the host sets up the READ queue position to the first + * INDEX position, and WRITE to the last (READ - 1 wrapped) + * + * When the firmware places a packet in a buffer, it will advance the READ index + * and fire the RX interrupt. The driver can then query the READ index and + * process as many packets as possible, moving the WRITE index forward as it + * resets the Rx queue buffers with new memory. + * + * The management in the driver is as follows: + * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When + * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled + * to replenish the iwl->rxq->rx_free. + * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the + * iwl->rxq is replenished and the READ INDEX is updated (updating the + * 'processed' and 'read' driver indexes as well) + * + A received packet is processed and handed to the kernel network stack, + * detached from the iwl->rxq. The driver 'processed' index is updated. + * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free + * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ + * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there + * were enough free buffers and RX_STALLED is set it is cleared. + * + * + * Driver sequence: + * + * iwl_rx_queue_alloc() Allocates rx_free + * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls + * iwl_rx_queue_restock + * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx + * queue, updates firmware pointers, and updates + * the WRITE index. If insufficient rx_free buffers + * are available, schedules iwl_rx_replenish + * + * -- enable interrupts -- + * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the + * READ INDEX, detaching the SKB from the pool. + * Moves the packet buffer from queue to rx_used. + * Calls iwl_rx_queue_restock to refill any empty + * slots. + * ... + * + */ + +/** + * iwl_rx_queue_space - Return number of free slots available in queue. + */ +static int iwl_rx_queue_space(const struct iwl_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +/** + * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue + */ +void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans, + struct iwl_rx_queue *q) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&q->lock, flags); + + if (q->need_update == 0) + goto exit_unlock; + + if (hw_params(trans).shadow_reg_enable) { + /* shadow register enabled */ + /* Device expects a multiple of 8 */ + q->write_actual = (q->write & ~0x7); + iwl_write32(bus(trans), FH_RSCSR_CHNL0_WPTR, q->write_actual); + } else { + /* If power-saving is in use, make sure device is awake */ + if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) { + reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1); + + if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { + IWL_DEBUG_INFO(trans, + "Rx queue requesting wakeup," + " GP1 = 0x%x\n", reg); + iwl_set_bit(bus(trans), CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + goto exit_unlock; + } + + q->write_actual = (q->write & ~0x7); + iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, + q->write_actual); + + /* Else device is assumed to be awake */ + } else { + /* Device expects a multiple of 8 */ + q->write_actual = (q->write & ~0x7); + iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_WPTR, + q->write_actual); + } + } + q->need_update = 0; + + exit_unlock: + spin_unlock_irqrestore(&q->lock, flags); +} + +/** + * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr + */ +static inline __le32 iwlagn_dma_addr2rbd_ptr(dma_addr_t dma_addr) +{ + return cpu_to_le32((u32)(dma_addr >> 8)); +} + +/** + * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool + * + * If there are slots in the RX queue that need to be restocked, + * and we have free pre-allocated buffers, fill the ranks as much + * as we can, pulling from rx_free. + * + * This moves the 'write' index forward to catch up with 'processed', and + * also updates the memory address in the firmware to reference the new + * target buffer. + */ +static void iwlagn_rx_queue_restock(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + struct iwl_rx_queue *rxq = &trans_pcie->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + unsigned long flags; + + spin_lock_irqsave(&rxq->lock, flags); + while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { + /* The overwritten rxb must be a used one */ + rxb = rxq->queue[rxq->write]; + BUG_ON(rxb && rxb->page); + + /* Get next free Rx buffer, remove from free list */ + element = rxq->rx_free.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + + /* Point to Rx buffer via next RBD in circular buffer */ + rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(rxb->page_dma); + rxq->queue[rxq->write] = rxb; + rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; + rxq->free_count--; + } + spin_unlock_irqrestore(&rxq->lock, flags); + /* If the pre-allocated buffer pool is dropping low, schedule to + * refill it */ + if (rxq->free_count <= RX_LOW_WATERMARK) + queue_work(trans->shrd->workqueue, &trans_pcie->rx_replenish); + + + /* If we've added more space for the firmware to place data, tell it. + * Increment device's write pointer in multiples of 8. */ + if (rxq->write_actual != (rxq->write & ~0x7)) { + spin_lock_irqsave(&rxq->lock, flags); + rxq->need_update = 1; + spin_unlock_irqrestore(&rxq->lock, flags); + iwl_rx_queue_update_write_ptr(trans, rxq); + } +} + +/** + * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free + * + * When moving to rx_free an SKB is allocated for the slot. + * + * Also restock the Rx queue via iwl_rx_queue_restock. + * This is called as a scheduled work item (except for during initialization) + */ +static void iwlagn_rx_allocate(struct iwl_trans *trans, gfp_t priority) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + struct iwl_rx_queue *rxq = &trans_pcie->rxq; + struct list_head *element; + struct iwl_rx_mem_buffer *rxb; + struct page *page; + unsigned long flags; + gfp_t gfp_mask = priority; + + while (1) { + spin_lock_irqsave(&rxq->lock, flags); + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + return; + } + spin_unlock_irqrestore(&rxq->lock, flags); + + if (rxq->free_count > RX_LOW_WATERMARK) + gfp_mask |= __GFP_NOWARN; + + if (hw_params(trans).rx_page_order > 0) + gfp_mask |= __GFP_COMP; + + /* Alloc a new receive buffer */ + page = alloc_pages(gfp_mask, + hw_params(trans).rx_page_order); + if (!page) { + if (net_ratelimit()) + IWL_DEBUG_INFO(trans, "alloc_pages failed, " + "order: %d\n", + hw_params(trans).rx_page_order); + + if ((rxq->free_count <= RX_LOW_WATERMARK) && + net_ratelimit()) + IWL_CRIT(trans, "Failed to alloc_pages with %s." + "Only %u free buffers remaining.\n", + priority == GFP_ATOMIC ? + "GFP_ATOMIC" : "GFP_KERNEL", + rxq->free_count); + /* We don't reschedule replenish work here -- we will + * call the restock method and if it still needs + * more buffers it will schedule replenish */ + return; + } + + spin_lock_irqsave(&rxq->lock, flags); + + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + __free_pages(page, hw_params(trans).rx_page_order); + return; + } + element = rxq->rx_used.next; + rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + + spin_unlock_irqrestore(&rxq->lock, flags); + + BUG_ON(rxb->page); + rxb->page = page; + /* Get physical address of the RB */ + rxb->page_dma = dma_map_page(bus(trans)->dev, page, 0, + PAGE_SIZE << hw_params(trans).rx_page_order, + DMA_FROM_DEVICE); + /* dma address must be no more than 36 bits */ + BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); + /* and also 256 byte aligned! */ + BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); + + spin_lock_irqsave(&rxq->lock, flags); + + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + + spin_unlock_irqrestore(&rxq->lock, flags); + } +} + +void iwlagn_rx_replenish(struct iwl_trans *trans) +{ + unsigned long flags; + + iwlagn_rx_allocate(trans, GFP_KERNEL); + + spin_lock_irqsave(&trans->shrd->lock, flags); + iwlagn_rx_queue_restock(trans); + spin_unlock_irqrestore(&trans->shrd->lock, flags); +} + +static void iwlagn_rx_replenish_now(struct iwl_trans *trans) +{ + iwlagn_rx_allocate(trans, GFP_ATOMIC); + + iwlagn_rx_queue_restock(trans); +} + +void iwl_bg_rx_replenish(struct work_struct *data) +{ + struct iwl_trans_pcie *trans_pcie = + container_of(data, struct iwl_trans_pcie, rx_replenish); + struct iwl_trans *trans = trans_pcie->trans; + + if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) + return; + + mutex_lock(&trans->shrd->mutex); + iwlagn_rx_replenish(trans); + mutex_unlock(&trans->shrd->mutex); +} + +/** + * iwl_rx_handle - Main entry function for receiving responses from uCode + * + * Uses the priv->rx_handlers callback function array to invoke + * the appropriate handlers, including command responses, + * frame-received notifications, and other notifications. + */ +static void iwl_rx_handle(struct iwl_trans *trans) +{ + struct iwl_rx_mem_buffer *rxb; + struct iwl_rx_packet *pkt; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rx_queue *rxq = &trans_pcie->rxq; + struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue]; + struct iwl_device_cmd *cmd; + u32 r, i; + int reclaim; + unsigned long flags; + u8 fill_rx = 0; + u32 count = 8; + int total_empty; + int index, cmd_index; + + /* uCode's read index (stored in shared DRAM) indicates the last Rx + * buffer that the driver may process (last buffer filled by ucode). */ + r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; + i = rxq->read; + + /* Rx interrupt, but nothing sent from uCode */ + if (i == r) + IWL_DEBUG_RX(trans, "r = %d, i = %d\n", r, i); + + /* calculate total frames need to be restock after handling RX */ + total_empty = r - rxq->write_actual; + if (total_empty < 0) + total_empty += RX_QUEUE_SIZE; + + if (total_empty > (RX_QUEUE_SIZE / 2)) + fill_rx = 1; + + while (i != r) { + int len, err; + u16 sequence; + + rxb = rxq->queue[i]; + + /* If an RXB doesn't have a Rx queue slot associated with it, + * then a bug has been introduced in the queue refilling + * routines -- catch it here */ + if (WARN_ON(rxb == NULL)) { + i = (i + 1) & RX_QUEUE_MASK; + continue; + } + + rxq->queue[i] = NULL; + + dma_unmap_page(bus(trans)->dev, rxb->page_dma, + PAGE_SIZE << hw_params(trans).rx_page_order, + DMA_FROM_DEVICE); + pkt = rxb_addr(rxb); + + IWL_DEBUG_RX(trans, "r = %d, i = %d, %s, 0x%02x\n", r, + i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); + + len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; + len += sizeof(u32); /* account for status word */ + trace_iwlwifi_dev_rx(priv(trans), pkt, len); + + /* Reclaim a command buffer only if this packet is a response + * to a (driver-originated) command. + * If the packet (e.g. Rx frame) originated from uCode, + * there is no command buffer to reclaim. + * Ucode should set SEQ_RX_FRAME bit if ucode-originated, + * but apparently a few don't get set; catch them here. */ + reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && + (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && + (pkt->hdr.cmd != REPLY_RX) && + (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && + (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && + (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && + (pkt->hdr.cmd != REPLY_TX); + + sequence = le16_to_cpu(pkt->hdr.sequence); + index = SEQ_TO_INDEX(sequence); + cmd_index = get_cmd_index(&txq->q, index); + + if (reclaim) + cmd = txq->cmd[cmd_index]; + else + cmd = NULL; + + /* warn if this is cmd response / notification and the uCode + * didn't set the SEQ_RX_FRAME for a frame that is + * uCode-originated + * If you saw this code after the second half of 2012, then + * please remove it + */ + WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false && + (!(pkt->hdr.sequence & SEQ_RX_FRAME)), + "reclaim is false, SEQ_RX_FRAME unset: %s\n", + get_cmd_string(pkt->hdr.cmd)); + + err = iwl_rx_dispatch(priv(trans), rxb, cmd); + + /* + * XXX: After here, we should always check rxb->page + * against NULL before touching it or its virtual + * memory (pkt). Because some rx_handler might have + * already taken or freed the pages. + */ + + if (reclaim) { + /* Invoke any callbacks, transfer the buffer to caller, + * and fire off the (possibly) blocking + * iwl_trans_send_cmd() + * as we reclaim the driver command queue */ + if (rxb->page) + iwl_tx_cmd_complete(trans, rxb, err); + else + IWL_WARN(trans, "Claim null rxb?\n"); + } + + /* Reuse the page if possible. For notification packets and + * SKBs that fail to Rx correctly, add them back into the + * rx_free list for reuse later. */ + spin_lock_irqsave(&rxq->lock, flags); + if (rxb->page != NULL) { + rxb->page_dma = dma_map_page(bus(trans)->dev, rxb->page, + 0, PAGE_SIZE << + hw_params(trans).rx_page_order, + DMA_FROM_DEVICE); + list_add_tail(&rxb->list, &rxq->rx_free); + rxq->free_count++; + } else + list_add_tail(&rxb->list, &rxq->rx_used); + + spin_unlock_irqrestore(&rxq->lock, flags); + + i = (i + 1) & RX_QUEUE_MASK; + /* If there are a lot of unused frames, + * restock the Rx queue so ucode wont assert. */ + if (fill_rx) { + count++; + if (count >= 8) { + rxq->read = i; + iwlagn_rx_replenish_now(trans); + count = 0; + } + } + } + + /* Backtrack one entry */ + rxq->read = i; + if (fill_rx) + iwlagn_rx_replenish_now(trans); + else + iwlagn_rx_queue_restock(trans); +} + +static const char * const desc_lookup_text[] = { + "OK", + "FAIL", + "BAD_PARAM", + "BAD_CHECKSUM", + "NMI_INTERRUPT_WDG", + "SYSASSERT", + "FATAL_ERROR", + "BAD_COMMAND", + "HW_ERROR_TUNE_LOCK", + "HW_ERROR_TEMPERATURE", + "ILLEGAL_CHAN_FREQ", + "VCC_NOT_STABLE", + "FH_ERROR", + "NMI_INTERRUPT_HOST", + "NMI_INTERRUPT_ACTION_PT", + "NMI_INTERRUPT_UNKNOWN", + "UCODE_VERSION_MISMATCH", + "HW_ERROR_ABS_LOCK", + "HW_ERROR_CAL_LOCK_FAIL", + "NMI_INTERRUPT_INST_ACTION_PT", + "NMI_INTERRUPT_DATA_ACTION_PT", + "NMI_TRM_HW_ER", + "NMI_INTERRUPT_TRM", + "NMI_INTERRUPT_BREAK_POINT", + "DEBUG_0", + "DEBUG_1", + "DEBUG_2", + "DEBUG_3", +}; + +static struct { char *name; u8 num; } advanced_lookup[] = { + { "NMI_INTERRUPT_WDG", 0x34 }, + { "SYSASSERT", 0x35 }, + { "UCODE_VERSION_MISMATCH", 0x37 }, + { "BAD_COMMAND", 0x38 }, + { "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C }, + { "FATAL_ERROR", 0x3D }, + { "NMI_TRM_HW_ERR", 0x46 }, + { "NMI_INTERRUPT_TRM", 0x4C }, + { "NMI_INTERRUPT_BREAK_POINT", 0x54 }, + { "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C }, + { "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 }, + { "NMI_INTERRUPT_HOST", 0x66 }, + { "NMI_INTERRUPT_ACTION_PT", 0x7C }, + { "NMI_INTERRUPT_UNKNOWN", 0x84 }, + { "NMI_INTERRUPT_INST_ACTION_PT", 0x86 }, + { "ADVANCED_SYSASSERT", 0 }, +}; + +static const char *desc_lookup(u32 num) +{ + int i; + int max = ARRAY_SIZE(desc_lookup_text); + + if (num < max) + return desc_lookup_text[num]; + + max = ARRAY_SIZE(advanced_lookup) - 1; + for (i = 0; i < max; i++) { + if (advanced_lookup[i].num == num) + break; + } + return advanced_lookup[i].name; +} + +#define ERROR_START_OFFSET (1 * sizeof(u32)) +#define ERROR_ELEM_SIZE (7 * sizeof(u32)) + +static void iwl_dump_nic_error_log(struct iwl_trans *trans) +{ + u32 base; + struct iwl_error_event_table table; + struct iwl_priv *priv = priv(trans); + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + base = priv->device_pointers.error_event_table; + if (priv->ucode_type == IWL_UCODE_INIT) { + if (!base) + base = priv->init_errlog_ptr; + } else { + if (!base) + base = priv->inst_errlog_ptr; + } + + if (!iwlagn_hw_valid_rtc_data_addr(base)) { + IWL_ERR(trans, + "Not valid error log pointer 0x%08X for %s uCode\n", + base, + (priv->ucode_type == IWL_UCODE_INIT) + ? "Init" : "RT"); + return; + } + + iwl_read_targ_mem_words(bus(priv), base, &table, sizeof(table)); + + if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { + IWL_ERR(trans, "Start IWL Error Log Dump:\n"); + IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", + trans->shrd->status, table.valid); + } + + trans_pcie->isr_stats.err_code = table.error_id; + + trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low, + table.data1, table.data2, table.line, + table.blink1, table.blink2, table.ilink1, + table.ilink2, table.bcon_time, table.gp1, + table.gp2, table.gp3, table.ucode_ver, + table.hw_ver, table.brd_ver); + IWL_ERR(trans, "0x%08X | %-28s\n", table.error_id, + desc_lookup(table.error_id)); + IWL_ERR(trans, "0x%08X | uPc\n", table.pc); + IWL_ERR(trans, "0x%08X | branchlink1\n", table.blink1); + IWL_ERR(trans, "0x%08X | branchlink2\n", table.blink2); + IWL_ERR(trans, "0x%08X | interruptlink1\n", table.ilink1); + IWL_ERR(trans, "0x%08X | interruptlink2\n", table.ilink2); + IWL_ERR(trans, "0x%08X | data1\n", table.data1); + IWL_ERR(trans, "0x%08X | data2\n", table.data2); + IWL_ERR(trans, "0x%08X | line\n", table.line); + IWL_ERR(trans, "0x%08X | beacon time\n", table.bcon_time); + IWL_ERR(trans, "0x%08X | tsf low\n", table.tsf_low); + IWL_ERR(trans, "0x%08X | tsf hi\n", table.tsf_hi); + IWL_ERR(trans, "0x%08X | time gp1\n", table.gp1); + IWL_ERR(trans, "0x%08X | time gp2\n", table.gp2); + IWL_ERR(trans, "0x%08X | time gp3\n", table.gp3); + IWL_ERR(trans, "0x%08X | uCode version\n", table.ucode_ver); + IWL_ERR(trans, "0x%08X | hw version\n", table.hw_ver); + IWL_ERR(trans, "0x%08X | board version\n", table.brd_ver); + IWL_ERR(trans, "0x%08X | hcmd\n", table.hcmd); +} + +/** + * iwl_irq_handle_error - called for HW or SW error interrupt from card + */ +static void iwl_irq_handle_error(struct iwl_trans *trans) +{ + struct iwl_priv *priv = priv(trans); + /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ + if (priv->cfg->internal_wimax_coex && + (!(iwl_read_prph(bus(trans), APMG_CLK_CTRL_REG) & + APMS_CLK_VAL_MRB_FUNC_MODE) || + (iwl_read_prph(bus(trans), APMG_PS_CTRL_REG) & + APMG_PS_CTRL_VAL_RESET_REQ))) { + /* + * Keep the restart process from trying to send host + * commands by clearing the ready bit. + */ + clear_bit(STATUS_READY, &trans->shrd->status); + clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); + wake_up(&priv->shrd->wait_command_queue); + IWL_ERR(trans, "RF is used by WiMAX\n"); + return; + } + + IWL_ERR(trans, "Loaded firmware version: %s\n", + priv->hw->wiphy->fw_version); + + iwl_dump_nic_error_log(trans); + iwl_dump_csr(trans); + iwl_dump_fh(trans, NULL, false); + iwl_dump_nic_event_log(trans, false, NULL, false); +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) + iwl_print_rx_config_cmd(priv(trans), IWL_RXON_CTX_BSS); +#endif + + iwlagn_fw_error(priv, false); +} + +#define EVENT_START_OFFSET (4 * sizeof(u32)) + +/** + * iwl_print_event_log - Dump error event log to syslog + * + */ +static int iwl_print_event_log(struct iwl_trans *trans, u32 start_idx, + u32 num_events, u32 mode, + int pos, char **buf, size_t bufsz) +{ + u32 i; + u32 base; /* SRAM byte address of event log header */ + u32 event_size; /* 2 u32s, or 3 u32s if timestamp recorded */ + u32 ptr; /* SRAM byte address of log data */ + u32 ev, time, data; /* event log data */ + unsigned long reg_flags; + struct iwl_priv *priv = priv(trans); + + if (num_events == 0) + return pos; + + base = priv->device_pointers.log_event_table; + if (priv->ucode_type == IWL_UCODE_INIT) { + if (!base) + base = priv->init_evtlog_ptr; + } else { + if (!base) + base = priv->inst_evtlog_ptr; + } + + if (mode == 0) + event_size = 2 * sizeof(u32); + else + event_size = 3 * sizeof(u32); + + ptr = base + EVENT_START_OFFSET + (start_idx * event_size); + + /* Make sure device is powered up for SRAM reads */ + spin_lock_irqsave(&bus(trans)->reg_lock, reg_flags); + iwl_grab_nic_access(bus(trans)); + + /* Set starting address; reads will auto-increment */ + iwl_write32(bus(trans), HBUS_TARG_MEM_RADDR, ptr); + rmb(); + + /* "time" is actually "data" for mode 0 (no timestamp). + * place event id # at far right for easier visual parsing. */ + for (i = 0; i < num_events; i++) { + ev = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); + time = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); + if (mode == 0) { + /* data, ev */ + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "EVT_LOG:0x%08x:%04u\n", + time, ev); + } else { + trace_iwlwifi_dev_ucode_event(priv, 0, + time, ev); + IWL_ERR(trans, "EVT_LOG:0x%08x:%04u\n", + time, ev); + } + } else { + data = iwl_read32(bus(trans), HBUS_TARG_MEM_RDAT); + if (bufsz) { + pos += scnprintf(*buf + pos, bufsz - pos, + "EVT_LOGT:%010u:0x%08x:%04u\n", + time, data, ev); + } else { + IWL_ERR(trans, "EVT_LOGT:%010u:0x%08x:%04u\n", + time, data, ev); + trace_iwlwifi_dev_ucode_event(priv, time, + data, ev); + } + } + } + + /* Allow device to power down */ + iwl_release_nic_access(bus(trans)); + spin_unlock_irqrestore(&bus(trans)->reg_lock, reg_flags); + return pos; +} + +/** + * iwl_print_last_event_logs - Dump the newest # of event log to syslog + */ +static int iwl_print_last_event_logs(struct iwl_trans *trans, u32 capacity, + u32 num_wraps, u32 next_entry, + u32 size, u32 mode, + int pos, char **buf, size_t bufsz) +{ + /* + * display the newest DEFAULT_LOG_ENTRIES entries + * i.e the entries just before the next ont that uCode would fill. + */ + if (num_wraps) { + if (next_entry < size) { + pos = iwl_print_event_log(trans, + capacity - (size - next_entry), + size - next_entry, mode, + pos, buf, bufsz); + pos = iwl_print_event_log(trans, 0, + next_entry, mode, + pos, buf, bufsz); + } else + pos = iwl_print_event_log(trans, next_entry - size, + size, mode, pos, buf, bufsz); + } else { + if (next_entry < size) { + pos = iwl_print_event_log(trans, 0, next_entry, + mode, pos, buf, bufsz); + } else { + pos = iwl_print_event_log(trans, next_entry - size, + size, mode, pos, buf, bufsz); + } + } + return pos; +} + +#define DEFAULT_DUMP_EVENT_LOG_ENTRIES (20) + +int iwl_dump_nic_event_log(struct iwl_trans *trans, bool full_log, + char **buf, bool display) +{ + u32 base; /* SRAM byte address of event log header */ + u32 capacity; /* event log capacity in # entries */ + u32 mode; /* 0 - no timestamp, 1 - timestamp recorded */ + u32 num_wraps; /* # times uCode wrapped to top of log */ + u32 next_entry; /* index of next entry to be written by uCode */ + u32 size; /* # entries that we'll print */ + u32 logsize; + int pos = 0; + size_t bufsz = 0; + struct iwl_priv *priv = priv(trans); + + base = priv->device_pointers.log_event_table; + if (priv->ucode_type == IWL_UCODE_INIT) { + logsize = priv->init_evtlog_size; + if (!base) + base = priv->init_evtlog_ptr; + } else { + logsize = priv->inst_evtlog_size; + if (!base) + base = priv->inst_evtlog_ptr; + } + + if (!iwlagn_hw_valid_rtc_data_addr(base)) { + IWL_ERR(trans, + "Invalid event log pointer 0x%08X for %s uCode\n", + base, + (priv->ucode_type == IWL_UCODE_INIT) + ? "Init" : "RT"); + return -EINVAL; + } + + /* event log header */ + capacity = iwl_read_targ_mem(bus(trans), base); + mode = iwl_read_targ_mem(bus(trans), base + (1 * sizeof(u32))); + num_wraps = iwl_read_targ_mem(bus(trans), base + (2 * sizeof(u32))); + next_entry = iwl_read_targ_mem(bus(trans), base + (3 * sizeof(u32))); + + if (capacity > logsize) { + IWL_ERR(trans, "Log capacity %d is bogus, limit to %d " + "entries\n", capacity, logsize); + capacity = logsize; + } + + if (next_entry > logsize) { + IWL_ERR(trans, "Log write index %d is bogus, limit to %d\n", + next_entry, logsize); + next_entry = logsize; + } + + size = num_wraps ? capacity : next_entry; + + /* bail out if nothing in log */ + if (size == 0) { + IWL_ERR(trans, "Start IWL Event Log Dump: nothing in log\n"); + return pos; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (!(iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) && !full_log) + size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; +#else + size = (size > DEFAULT_DUMP_EVENT_LOG_ENTRIES) + ? DEFAULT_DUMP_EVENT_LOG_ENTRIES : size; +#endif + IWL_ERR(trans, "Start IWL Event Log Dump: display last %u entries\n", + size); + +#ifdef CONFIG_IWLWIFI_DEBUG + if (display) { + if (full_log) + bufsz = capacity * 48; + else + bufsz = size * 48; + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return -ENOMEM; + } + if ((iwl_get_debug_level(trans->shrd) & IWL_DL_FW_ERRORS) || full_log) { + /* + * if uCode has wrapped back to top of log, + * start at the oldest entry, + * i.e the next one that uCode would fill. + */ + if (num_wraps) + pos = iwl_print_event_log(trans, next_entry, + capacity - next_entry, mode, + pos, buf, bufsz); + /* (then/else) start at top of log */ + pos = iwl_print_event_log(trans, 0, + next_entry, mode, pos, buf, bufsz); + } else + pos = iwl_print_last_event_logs(trans, capacity, num_wraps, + next_entry, size, mode, + pos, buf, bufsz); +#else + pos = iwl_print_last_event_logs(trans, capacity, num_wraps, + next_entry, size, mode, + pos, buf, bufsz); +#endif + return pos; +} + +/* tasklet for iwlagn interrupt */ +void iwl_irq_tasklet(struct iwl_trans *trans) +{ + u32 inta = 0; + u32 handled = 0; + unsigned long flags; + u32 i; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_mask; +#endif + + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct isr_statistics *isr_stats = &trans_pcie->isr_stats; + + + spin_lock_irqsave(&trans->shrd->lock, flags); + + /* Ack/clear/reset pending uCode interrupts. + * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, + */ + /* There is a hardware bug in the interrupt mask function that some + * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if + * they are disabled in the CSR_INT_MASK register. Furthermore the + * ICT interrupt handling mechanism has another bug that might cause + * these unmasked interrupts fail to be detected. We workaround the + * hardware bugs here by ACKing all the possible interrupts so that + * interrupt coalescing can still be achieved. + */ + iwl_write32(bus(trans), CSR_INT, + trans_pcie->inta | ~trans_pcie->inta_mask); + + inta = trans_pcie->inta; + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(trans->shrd) & IWL_DL_ISR) { + /* just for debug */ + inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); + IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n ", + inta, inta_mask); + } +#endif + + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + /* saved interrupt in inta variable now we can reset trans_pcie->inta */ + trans_pcie->inta = 0; + + /* Now service all interrupt bits discovered above. */ + if (inta & CSR_INT_BIT_HW_ERR) { + IWL_ERR(trans, "Hardware error detected. Restarting.\n"); + + /* Tell the device to stop sending interrupts */ + iwl_disable_interrupts(trans); + + isr_stats->hw++; + iwl_irq_handle_error(trans); + + handled |= CSR_INT_BIT_HW_ERR; + + return; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { + /* NIC fires this, but we don't use it, redundant with WAKEUP */ + if (inta & CSR_INT_BIT_SCD) { + IWL_DEBUG_ISR(trans, "Scheduler finished to transmit " + "the frame/frames.\n"); + isr_stats->sch++; + } + + /* Alive notification via Rx interrupt will do the real work */ + if (inta & CSR_INT_BIT_ALIVE) { + IWL_DEBUG_ISR(trans, "Alive interrupt\n"); + isr_stats->alive++; + } + } +#endif + /* Safely ignore these bits for debug checks below */ + inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); + + /* HW RF KILL switch toggled */ + if (inta & CSR_INT_BIT_RF_KILL) { + int hw_rf_kill = 0; + if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rf_kill = 1; + + IWL_WARN(trans, "RF_KILL bit toggled to %s.\n", + hw_rf_kill ? "disable radio" : "enable radio"); + + isr_stats->rfkill++; + + /* driver only loads ucode once setting the interface up. + * the driver allows loading the ucode even if the radio + * is killed. Hence update the killswitch state here. The + * rfkill handler will care about restarting if needed. + */ + if (!test_bit(STATUS_ALIVE, &trans->shrd->status)) { + if (hw_rf_kill) + set_bit(STATUS_RF_KILL_HW, + &trans->shrd->status); + else + clear_bit(STATUS_RF_KILL_HW, + &trans->shrd->status); + iwl_set_hw_rfkill_state(priv(trans), hw_rf_kill); + } + + handled |= CSR_INT_BIT_RF_KILL; + } + + /* Chip got too hot and stopped itself */ + if (inta & CSR_INT_BIT_CT_KILL) { + IWL_ERR(trans, "Microcode CT kill error detected.\n"); + isr_stats->ctkill++; + handled |= CSR_INT_BIT_CT_KILL; + } + + /* Error detected by uCode */ + if (inta & CSR_INT_BIT_SW_ERR) { + IWL_ERR(trans, "Microcode SW error detected. " + " Restarting 0x%X.\n", inta); + isr_stats->sw++; + iwl_irq_handle_error(trans); + handled |= CSR_INT_BIT_SW_ERR; + } + + /* uCode wakes up after power-down sleep */ + if (inta & CSR_INT_BIT_WAKEUP) { + IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); + iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq); + for (i = 0; i < hw_params(trans).max_txq_num; i++) + iwl_txq_update_write_ptr(trans, + &trans_pcie->txq[i]); + + isr_stats->wakeup++; + + handled |= CSR_INT_BIT_WAKEUP; + } + + /* All uCode command responses, including Tx command responses, + * Rx "responses" (frame-received notification), and other + * notifications from uCode come through here*/ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | + CSR_INT_BIT_RX_PERIODIC)) { + IWL_DEBUG_ISR(trans, "Rx interrupt\n"); + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { + handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); + iwl_write32(bus(trans), CSR_FH_INT_STATUS, + CSR_FH_INT_RX_MASK); + } + if (inta & CSR_INT_BIT_RX_PERIODIC) { + handled |= CSR_INT_BIT_RX_PERIODIC; + iwl_write32(bus(trans), + CSR_INT, CSR_INT_BIT_RX_PERIODIC); + } + /* Sending RX interrupt require many steps to be done in the + * the device: + * 1- write interrupt to current index in ICT table. + * 2- dma RX frame. + * 3- update RX shared data to indicate last write index. + * 4- send interrupt. + * This could lead to RX race, driver could receive RX interrupt + * but the shared data changes does not reflect this; + * periodic interrupt will detect any dangling Rx activity. + */ + + /* Disable periodic interrupt; we use it as just a one-shot. */ + iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, + CSR_INT_PERIODIC_DIS); + iwl_rx_handle(trans); + + /* + * Enable periodic interrupt in 8 msec only if we received + * real RX interrupt (instead of just periodic int), to catch + * any dangling Rx interrupt. If it was just the periodic + * interrupt, there was no dangling Rx activity, and no need + * to extend the periodic interrupt; one-shot is enough. + */ + if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) + iwl_write8(bus(trans), CSR_INT_PERIODIC_REG, + CSR_INT_PERIODIC_ENA); + + isr_stats->rx++; + } + + /* This "Tx" DMA channel is used only for loading uCode */ + if (inta & CSR_INT_BIT_FH_TX) { + iwl_write32(bus(trans), CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); + IWL_DEBUG_ISR(trans, "uCode load interrupt\n"); + isr_stats->tx++; + handled |= CSR_INT_BIT_FH_TX; + /* Wake up uCode load routine, now that load is complete */ + priv(trans)->ucode_write_complete = 1; + wake_up(&trans->shrd->wait_command_queue); + } + + if (inta & ~handled) { + IWL_ERR(trans, "Unhandled INTA bits 0x%08x\n", inta & ~handled); + isr_stats->unhandled++; + } + + if (inta & ~(trans_pcie->inta_mask)) { + IWL_WARN(trans, "Disabled INTA bits 0x%08x were pending\n", + inta & ~trans_pcie->inta_mask); + } + + /* Re-enable all interrupts */ + /* only Re-enable if disabled by irq */ + if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status)) + iwl_enable_interrupts(trans); + /* Re-enable RF_KILL if it occurred */ + else if (handled & CSR_INT_BIT_RF_KILL) + iwl_enable_rfkill_int(priv(trans)); +} + +/****************************************************************************** + * + * ICT functions + * + ******************************************************************************/ +#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) + +/* Free dram table */ +void iwl_free_isr_ict(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + if (trans_pcie->ict_tbl_vir) { + dma_free_coherent(bus(trans)->dev, + (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, + trans_pcie->ict_tbl_vir, + trans_pcie->ict_tbl_dma); + trans_pcie->ict_tbl_vir = NULL; + memset(&trans_pcie->ict_tbl_dma, 0, + sizeof(trans_pcie->ict_tbl_dma)); + memset(&trans_pcie->aligned_ict_tbl_dma, 0, + sizeof(trans_pcie->aligned_ict_tbl_dma)); + } +} + + +/* allocate dram shared table it is a PAGE_SIZE aligned + * also reset all data related to ICT table interrupt. + */ +int iwl_alloc_isr_ict(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + /* allocate shrared data table */ + trans_pcie->ict_tbl_vir = + dma_alloc_coherent(bus(trans)->dev, + (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, + &trans_pcie->ict_tbl_dma, GFP_KERNEL); + if (!trans_pcie->ict_tbl_vir) + return -ENOMEM; + + /* align table to PAGE_SIZE boundary */ + trans_pcie->aligned_ict_tbl_dma = + ALIGN(trans_pcie->ict_tbl_dma, PAGE_SIZE); + + IWL_DEBUG_ISR(trans, "ict dma addr %Lx dma aligned %Lx diff %d\n", + (unsigned long long)trans_pcie->ict_tbl_dma, + (unsigned long long)trans_pcie->aligned_ict_tbl_dma, + (int)(trans_pcie->aligned_ict_tbl_dma - + trans_pcie->ict_tbl_dma)); + + trans_pcie->ict_tbl = trans_pcie->ict_tbl_vir + + (trans_pcie->aligned_ict_tbl_dma - + trans_pcie->ict_tbl_dma); + + IWL_DEBUG_ISR(trans, "ict vir addr %p vir aligned %p diff %d\n", + trans_pcie->ict_tbl, trans_pcie->ict_tbl_vir, + (int)(trans_pcie->aligned_ict_tbl_dma - + trans_pcie->ict_tbl_dma)); + + /* reset table and index to all 0 */ + memset(trans_pcie->ict_tbl_vir, 0, + (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); + trans_pcie->ict_index = 0; + + /* add periodic RX interrupt */ + trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC; + return 0; +} + +/* Device is going up inform it about using ICT interrupt table, + * also we need to tell the driver to start using ICT interrupt. + */ +int iwl_reset_ict(struct iwl_trans *trans) +{ + u32 val; + unsigned long flags; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + if (!trans_pcie->ict_tbl_vir) + return 0; + + spin_lock_irqsave(&trans->shrd->lock, flags); + iwl_disable_interrupts(trans); + + memset(&trans_pcie->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); + + val = trans_pcie->aligned_ict_tbl_dma >> PAGE_SHIFT; + + val |= CSR_DRAM_INT_TBL_ENABLE; + val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; + + IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%X " + "aligned dma address %Lx\n", + val, + (unsigned long long)trans_pcie->aligned_ict_tbl_dma); + + iwl_write32(bus(trans), CSR_DRAM_INT_TBL_REG, val); + trans_pcie->use_ict = true; + trans_pcie->ict_index = 0; + iwl_write32(bus(trans), CSR_INT, trans_pcie->inta_mask); + iwl_enable_interrupts(trans); + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + return 0; +} + +/* Device is going down disable ict interrupt usage */ +void iwl_disable_ict(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + unsigned long flags; + + spin_lock_irqsave(&trans->shrd->lock, flags); + trans_pcie->use_ict = false; + spin_unlock_irqrestore(&trans->shrd->lock, flags); +} + +static irqreturn_t iwl_isr(int irq, void *data) +{ + struct iwl_trans *trans = data; + struct iwl_trans_pcie *trans_pcie; + u32 inta, inta_mask; + unsigned long flags; +#ifdef CONFIG_IWLWIFI_DEBUG + u32 inta_fh; +#endif + if (!trans) + return IRQ_NONE; + + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + spin_lock_irqsave(&trans->shrd->lock, flags); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. */ + inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */ + iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(bus(trans), CSR_INT); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!inta) { + IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); + goto none; + } + + if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* Hardware disappeared. It might have already raised + * an interrupt */ + IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta); + goto unplugged; + } + +#ifdef CONFIG_IWLWIFI_DEBUG + if (iwl_get_debug_level(trans->shrd) & (IWL_DL_ISR)) { + inta_fh = iwl_read32(bus(trans), CSR_FH_INT_STATUS); + IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x, " + "fh 0x%08x\n", inta, inta_mask, inta_fh); + } +#endif + + trans_pcie->inta |= inta; + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + if (likely(inta)) + tasklet_schedule(&trans_pcie->irq_tasklet); + else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && + !trans_pcie->inta) + iwl_enable_interrupts(trans); + + unplugged: + spin_unlock_irqrestore(&trans->shrd->lock, flags); + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. */ + /* only Re-enable if disabled by irq and no schedules tasklet. */ + if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && + !trans_pcie->inta) + iwl_enable_interrupts(trans); + + spin_unlock_irqrestore(&trans->shrd->lock, flags); + return IRQ_NONE; +} + +/* interrupt handler using ict table, with this interrupt driver will + * stop using INTA register to get device's interrupt, reading this register + * is expensive, device will write interrupts in ICT dram table, increment + * index then will fire interrupt to driver, driver will OR all ICT table + * entries from current index up to table entry with 0 value. the result is + * the interrupt we need to service, driver will set the entries back to 0 and + * set index. + */ +irqreturn_t iwl_isr_ict(int irq, void *data) +{ + struct iwl_trans *trans = data; + struct iwl_trans_pcie *trans_pcie; + u32 inta, inta_mask; + u32 val = 0; + unsigned long flags; + + if (!trans) + return IRQ_NONE; + + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + /* dram interrupt table not set yet, + * use legacy interrupt. + */ + if (!trans_pcie->use_ict) + return iwl_isr(irq, data); + + spin_lock_irqsave(&trans->shrd->lock, flags); + + /* Disable (but don't clear!) interrupts here to avoid + * back-to-back ISRs and sporadic interrupts from our NIC. + * If we have something to service, the tasklet will re-enable ints. + * If we *don't* have something, we'll re-enable before leaving here. + */ + inta_mask = iwl_read32(bus(trans), CSR_INT_MASK); /* just for debug */ + iwl_write32(bus(trans), CSR_INT_MASK, 0x00000000); + + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + if (!trans_pcie->ict_tbl[trans_pcie->ict_index]) { + IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); + goto none; + } + + /* read all entries that not 0 start with ict_index */ + while (trans_pcie->ict_tbl[trans_pcie->ict_index]) { + + val |= le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); + IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n", + trans_pcie->ict_index, + le32_to_cpu( + trans_pcie->ict_tbl[trans_pcie->ict_index])); + trans_pcie->ict_tbl[trans_pcie->ict_index] = 0; + trans_pcie->ict_index = + iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT); + + } + + /* We should not get this value, just ignore it. */ + if (val == 0xffffffff) + val = 0; + + /* + * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit + * (bit 15 before shifting it to 31) to clear when using interrupt + * coalescing. fortunately, bits 18 and 19 stay set when this happens + * so we use them to decide on the real state of the Rx bit. + * In order words, bit 15 is set if bit 18 or bit 19 are set. + */ + if (val & 0xC0000) + val |= 0x8000; + + inta = (0xff & val) | ((0xff00 & val) << 16); + IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", + inta, inta_mask, val); + + inta &= trans_pcie->inta_mask; + trans_pcie->inta |= inta; + + /* iwl_irq_tasklet() will service interrupts and re-enable them */ + if (likely(inta)) + tasklet_schedule(&trans_pcie->irq_tasklet); + else if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && + !trans_pcie->inta) { + /* Allow interrupt if was disabled by this handler and + * no tasklet was schedules, We should not enable interrupt, + * tasklet will enable it. + */ + iwl_enable_interrupts(trans); + } + + spin_unlock_irqrestore(&trans->shrd->lock, flags); + return IRQ_HANDLED; + + none: + /* re-enable interrupts here since we don't have anything to service. + * only Re-enable if disabled by irq. + */ + if (test_bit(STATUS_INT_ENABLED, &trans->shrd->status) && + !trans_pcie->inta) + iwl_enable_interrupts(trans); + + spin_unlock_irqrestore(&trans->shrd->lock, flags); + return IRQ_NONE; +} diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c index 222d410c586e..4a0c95302a7e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c @@ -29,34 +29,42 @@ #include <linux/etherdevice.h> #include <linux/slab.h> #include <linux/sched.h> -#include <net/mac80211.h> -#include "iwl-agn.h" -#include "iwl-dev.h" -#include "iwl-core.h" +#include "iwl-debug.h" +#include "iwl-csr.h" +#include "iwl-prph.h" #include "iwl-io.h" -#include "iwl-helpers.h" -#include "iwl-trans-int-pcie.h" +#include "iwl-agn-hw.h" +#include "iwl-trans-pcie-int.h" + +#define IWL_TX_CRC_SIZE 4 +#define IWL_TX_DELIMITER_SIZE 4 /** * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ -void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_priv *priv, +void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans, struct iwl_tx_queue *txq, u16 byte_cnt) { - struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; + struct iwlagn_scd_bc_tbl *scd_bc_tbl; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); int write_ptr = txq->q.write_ptr; int txq_id = txq->q.id; u8 sec_ctl = 0; u8 sta_id = 0; u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; __le16 bc_ent; + struct iwl_tx_cmd *tx_cmd = + (struct iwl_tx_cmd *) txq->cmd[txq->q.write_ptr]->payload; + + scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); - sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; - sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; + sta_id = tx_cmd->sta_id; + sec_ctl = tx_cmd->sec_ctl; switch (sec_ctl & TX_CMD_SEC_MSK) { case TX_CMD_SEC_CCM: @@ -82,7 +90,7 @@ void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_priv *priv, /** * iwl_txq_update_write_ptr - Send new write index to hardware */ -void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) +void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq) { u32 reg = 0; int txq_id = txq->q.id; @@ -90,28 +98,28 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) if (txq->need_update == 0) return; - if (priv->cfg->base_params->shadow_reg_enable) { + if (hw_params(trans).shadow_reg_enable) { /* shadow register enabled */ - iwl_write32(priv, HBUS_TARG_WRPTR, + iwl_write32(bus(trans), HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); } else { /* if we're trying to save power */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { + if (test_bit(STATUS_POWER_PMI, &trans->shrd->status)) { /* wake up nic if it's powered down ... * uCode will wake up, and interrupt us again, so next * time we'll skip this part. */ - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); + reg = iwl_read32(bus(trans), CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(priv, + IWL_DEBUG_INFO(trans, "Tx queue %d requesting wakeup," " GP1 = 0x%x\n", txq_id, reg); - iwl_set_bit(priv, CSR_GP_CNTRL, + iwl_set_bit(bus(trans), CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); return; } - iwl_write_direct32(priv, HBUS_TARG_WRPTR, + iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); /* @@ -120,7 +128,7 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq) * trying to tx (during RFKILL, we're not trying to tx). */ } else - iwl_write32(priv, HBUS_TARG_WRPTR, + iwl_write32(bus(trans), HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8)); } txq->need_update = 0; @@ -165,7 +173,7 @@ static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) return tfd->num_tbs & 0x1f; } -static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta, +static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta, struct iwl_tfd *tfd, enum dma_data_direction dma_dir) { int i; @@ -175,56 +183,59 @@ static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta, num_tbs = iwl_tfd_get_num_tbs(tfd); if (num_tbs >= IWL_NUM_OF_TBS) { - IWL_ERR(priv, "Too many chunks: %i\n", num_tbs); + IWL_ERR(trans, "Too many chunks: %i\n", num_tbs); /* @todo issue fatal error, it is quite serious situation */ return; } /* Unmap tx_cmd */ if (num_tbs) - dma_unmap_single(priv->bus->dev, + dma_unmap_single(bus(trans)->dev, dma_unmap_addr(meta, mapping), dma_unmap_len(meta, len), DMA_BIDIRECTIONAL); /* Unmap chunks, if any. */ for (i = 1; i < num_tbs; i++) - dma_unmap_single(priv->bus->dev, iwl_tfd_tb_get_addr(tfd, i), + dma_unmap_single(bus(trans)->dev, iwl_tfd_tb_get_addr(tfd, i), iwl_tfd_tb_get_len(tfd, i), dma_dir); } /** * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] - * @priv - driver private data + * @trans - transport private data * @txq - tx queue * @index - the index of the TFD to be freed + *@dma_dir - the direction of the DMA mapping * * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int index) +void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, + int index, enum dma_data_direction dma_dir) { struct iwl_tfd *tfd_tmp = txq->tfds; - iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index], - DMA_TO_DEVICE); + iwlagn_unmap_tfd(trans, &txq->meta[index], &tfd_tmp[index], dma_dir); /* free SKB */ - if (txq->txb) { + if (txq->skbs) { struct sk_buff *skb; - skb = txq->txb[index].skb; + skb = txq->skbs[index]; - /* can be called from irqs-disabled context */ + /* Can be called from irqs-disabled context + * If skb is not NULL, it means that the whole queue is being + * freed and that the queue is not empty - free the skb + */ if (skb) { - dev_kfree_skb_any(skb); - txq->txb[index].skb = NULL; + iwl_free_skb(priv(trans), skb); + txq->skbs[index] = NULL; } } } -int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv, +int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq, dma_addr_t addr, u16 len, u8 reset) @@ -244,7 +255,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv, /* Each TFD can point to a maximum 20 Tx buffers */ if (num_tbs >= IWL_NUM_OF_TBS) { - IWL_ERR(priv, "Error can not send more than %d chunks\n", + IWL_ERR(trans, "Error can not send more than %d chunks\n", IWL_NUM_OF_TBS); return -EINVAL; } @@ -253,7 +264,7 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv, return -EINVAL; if (unlikely(addr & ~IWL_TX_DMA_MASK)) - IWL_ERR(priv, "Unaligned address = %llx\n", + IWL_ERR(trans, "Unaligned address = %llx\n", (unsigned long long)addr); iwl_tfd_set_tb(tfd, num_tbs, addr, len); @@ -302,8 +313,7 @@ int iwl_queue_space(const struct iwl_queue *q) /** * iwl_queue_init - Initialize queue's high/low-water and read/write indexes */ -int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, - int count, int slots_num, u32 id) +int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id) { q->n_bd = count; q->n_window = slots_num; @@ -332,25 +342,23 @@ int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, return 0; } -/*TODO: this functions should NOT be exported from trans module - export it - * until the reclaim flow will be brought to the transport module too. - * Add a declaration to make sparse happy */ -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq); - -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, +static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans, struct iwl_tx_queue *txq) { - struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr; int txq_id = txq->q.id; int read_ptr = txq->q.read_ptr; u8 sta_id = 0; __le16 bc_ent; + struct iwl_tx_cmd *tx_cmd = + (struct iwl_tx_cmd *) txq->cmd[txq->q.read_ptr]->payload; WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); - if (txq_id != priv->cmd_queue) - sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; + if (txq_id != trans->shrd->cmd_queue) + sta_id = tx_cmd->sta_id; bc_ent = cpu_to_le16(1 | (sta_id << 12)); scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; @@ -360,56 +368,61 @@ void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; } -static int iwlagn_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, +static int iwlagn_tx_queue_set_q2ratid(struct iwl_trans *trans, u16 ra_tid, u16 txq_id) { u32 tbl_dw_addr; u32 tbl_dw; u16 scd_q2ratid; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK; - tbl_dw_addr = priv->scd_base_addr + + tbl_dw_addr = trans_pcie->scd_base_addr + SCD_TRANS_TBL_OFFSET_QUEUE(txq_id); - tbl_dw = iwl_read_targ_mem(priv, tbl_dw_addr); + tbl_dw = iwl_read_targ_mem(bus(trans), tbl_dw_addr); if (txq_id & 0x1) tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF); else tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000); - iwl_write_targ_mem(priv, tbl_dw_addr, tbl_dw); + iwl_write_targ_mem(bus(trans), tbl_dw_addr, tbl_dw); return 0; } -static void iwlagn_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id) +static void iwlagn_tx_queue_stop_scheduler(struct iwl_trans *trans, u16 txq_id) { /* Simply stop the queue, but don't change any configuration; * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */ - iwl_write_prph(priv, + iwl_write_prph(bus(trans), SCD_QUEUE_STATUS_BITS(txq_id), (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); } -void iwl_trans_set_wr_ptrs(struct iwl_priv *priv, +void iwl_trans_set_wr_ptrs(struct iwl_trans *trans, int txq_id, u32 index) { - iwl_write_direct32(priv, HBUS_TARG_WRPTR, + iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, (index & 0xff) | (txq_id << 8)); - iwl_write_prph(priv, SCD_QUEUE_RDPTR(txq_id), index); + iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(txq_id), index); } -void iwl_trans_tx_queue_set_status(struct iwl_priv *priv, +void iwl_trans_tx_queue_set_status(struct iwl_trans *trans, struct iwl_tx_queue *txq, int tx_fifo_id, int scd_retry) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int txq_id = txq->q.id; - int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; + int active = + test_bit(txq_id, &trans_pcie->txq_ctx_active_msk) ? 1 : 0; - iwl_write_prph(priv, SCD_QUEUE_STATUS_BITS(txq_id), + iwl_write_prph(bus(trans), SCD_QUEUE_STATUS_BITS(txq_id), (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) | (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) | (1 << SCD_QUEUE_STTS_REG_POS_WSL) | @@ -417,55 +430,75 @@ void iwl_trans_tx_queue_set_status(struct iwl_priv *priv, txq->sched_retry = scd_retry; - IWL_DEBUG_INFO(priv, "%s %s Queue %d on FIFO %d\n", + IWL_DEBUG_INFO(trans, "%s %s Queue %d on FIFO %d\n", active ? "Activate" : "Deactivate", scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); } -void iwl_trans_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid, - int frame_limit) +static inline int get_fifo_from_tid(struct iwl_trans_pcie *trans_pcie, + u8 ctx, u16 tid) +{ + const u8 *ac_to_fifo = trans_pcie->ac_to_fifo[ctx]; + if (likely(tid < ARRAY_SIZE(tid_to_ac))) + return ac_to_fifo[tid_to_ac[tid]]; + + /* no support for TIDs 8-15 yet */ + return -EINVAL; +} + +void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, int sta_id, + int tid, int frame_limit) { int tx_fifo, txq_id, ssn_idx; u16 ra_tid; unsigned long flags; struct iwl_tid_data *tid_data; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + if (WARN_ON(sta_id == IWL_INVALID_STATION)) return; - if (WARN_ON(tid >= MAX_TID_COUNT)) + if (WARN_ON(tid >= IWL_MAX_TID_COUNT)) return; - spin_lock_irqsave(&priv->sta_lock, flags); - tid_data = &priv->stations[sta_id].tid[tid]; + tx_fifo = get_fifo_from_tid(trans_pcie, ctx, tid); + if (WARN_ON(tx_fifo < 0)) { + IWL_ERR(trans, "txq_agg_setup, bad fifo: %d\n", tx_fifo); + return; + } + + spin_lock_irqsave(&trans->shrd->sta_lock, flags); + tid_data = &trans->shrd->tid_data[sta_id][tid]; ssn_idx = SEQ_TO_SN(tid_data->seq_number); txq_id = tid_data->agg.txq_id; - tx_fifo = tid_data->agg.tx_fifo; - spin_unlock_irqrestore(&priv->sta_lock, flags); + spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); ra_tid = BUILD_RAxTID(sta_id, tid); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&trans->shrd->lock, flags); /* Stop this Tx queue before configuring it */ - iwlagn_tx_queue_stop_scheduler(priv, txq_id); + iwlagn_tx_queue_stop_scheduler(trans, txq_id); /* Map receiver-address / traffic-ID to this queue */ - iwlagn_tx_queue_set_q2ratid(priv, ra_tid, txq_id); + iwlagn_tx_queue_set_q2ratid(trans, ra_tid, txq_id); /* Set this queue as a chain-building queue */ - iwl_set_bits_prph(priv, SCD_QUEUECHAIN_SEL, (1<<txq_id)); + iwl_set_bits_prph(bus(trans), SCD_QUEUECHAIN_SEL, (1<<txq_id)); /* enable aggregations for the queue */ - iwl_set_bits_prph(priv, SCD_AGGR_SEL, (1<<txq_id)); + iwl_set_bits_prph(bus(trans), SCD_AGGR_SEL, (1<<txq_id)); /* Place first TFD at index corresponding to start sequence number. * Assumes that ssn_idx is valid (!= 0xFFF) */ - priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); - priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); - iwl_trans_set_wr_ptrs(priv, txq_id, ssn_idx); + trans_pcie->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); + trans_pcie->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); + iwl_trans_set_wr_ptrs(trans, txq_id, ssn_idx); /* Set up Tx window size and frame limit for this queue */ - iwl_write_targ_mem(priv, priv->scd_base_addr + + iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32), ((frame_limit << @@ -475,40 +508,161 @@ void iwl_trans_txq_agg_setup(struct iwl_priv *priv, int sta_id, int tid, SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); - iwl_set_bits_prph(priv, SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl_set_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id)); /* Set up Status area in SRAM, map to Tx DMA/FIFO, activate the queue */ - iwl_trans_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); + iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], + tx_fifo, 1); + + trans_pcie->txq[txq_id].sta_id = sta_id; + trans_pcie->txq[txq_id].tid = tid; + + spin_unlock_irqrestore(&trans->shrd->lock, flags); +} - spin_unlock_irqrestore(&priv->lock, flags); +/* + * Find first available (lowest unused) Tx Queue, mark it "active". + * Called only when finding queue for aggregation. + * Should never return anything < 7, because they should already + * be in use as EDCA AC (0-3), Command (4), reserved (5, 6) + */ +static int iwlagn_txq_ctx_activate_free(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int txq_id; + + for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) + if (!test_and_set_bit(txq_id, + &trans_pcie->txq_ctx_active_msk)) + return txq_id; + return -1; } -int iwl_trans_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) +int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, int sta_id, + int tid, u16 *ssn) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tid_data *tid_data; + unsigned long flags; + int txq_id; + + txq_id = iwlagn_txq_ctx_activate_free(trans); + if (txq_id == -1) { + IWL_ERR(trans, "No free aggregation queue available\n"); + return -ENXIO; + } + + spin_lock_irqsave(&trans->shrd->sta_lock, flags); + tid_data = &trans->shrd->tid_data[sta_id][tid]; + *ssn = SEQ_TO_SN(tid_data->seq_number); + tid_data->agg.txq_id = txq_id; + iwl_set_swq_id(&trans_pcie->txq[txq_id], get_ac_from_tid(tid), txq_id); + + tid_data = &trans->shrd->tid_data[sta_id][tid]; + if (tid_data->tfds_in_queue == 0) { + IWL_DEBUG_HT(trans, "HW queue is empty\n"); + tid_data->agg.state = IWL_AGG_ON; + iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid); + } else { + IWL_DEBUG_HT(trans, "HW queue is NOT empty: %d packets in HW" + "queue\n", tid_data->tfds_in_queue); + tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; + } + spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); + + return 0; +} + +void iwl_trans_pcie_txq_agg_disable(struct iwl_trans *trans, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + iwlagn_tx_queue_stop_scheduler(trans, txq_id); + + iwl_clear_bits_prph(bus(trans), SCD_AGGR_SEL, (1 << txq_id)); + + trans_pcie->txq[txq_id].q.read_ptr = 0; + trans_pcie->txq[txq_id].q.write_ptr = 0; + /* supposes that ssn_idx is valid (!= 0xFFF) */ + iwl_trans_set_wr_ptrs(trans, txq_id, 0); + + iwl_clear_bits_prph(bus(trans), SCD_INTERRUPT_MASK, (1 << txq_id)); + iwl_txq_ctx_deactivate(trans_pcie, txq_id); + iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[txq_id], 0, 0); +} + +int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, int sta_id, + int tid) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long flags; + int read_ptr, write_ptr; + struct iwl_tid_data *tid_data; + int txq_id; + + spin_lock_irqsave(&trans->shrd->sta_lock, flags); + + tid_data = &trans->shrd->tid_data[sta_id][tid]; + txq_id = tid_data->agg.txq_id; + if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || (IWLAGN_FIRST_AMPDU_QUEUE + - priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { - IWL_ERR(priv, + hw_params(trans).num_ampdu_queues <= txq_id)) { + IWL_ERR(trans, "queue number out of range: %d, must be %d to %d\n", txq_id, IWLAGN_FIRST_AMPDU_QUEUE, IWLAGN_FIRST_AMPDU_QUEUE + - priv->cfg->base_params->num_of_ampdu_queues - 1); + hw_params(trans).num_ampdu_queues - 1); + spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); return -EINVAL; } - iwlagn_tx_queue_stop_scheduler(priv, txq_id); + switch (trans->shrd->tid_data[sta_id][tid].agg.state) { + case IWL_EMPTYING_HW_QUEUE_ADDBA: + /* + * This can happen if the peer stops aggregation + * again before we've had a chance to drain the + * queue we selected previously, i.e. before the + * session was really started completely. + */ + IWL_DEBUG_HT(trans, "AGG stop before setup done\n"); + goto turn_off; + case IWL_AGG_ON: + break; + default: + IWL_WARN(trans, "Stopping AGG while state not ON " + "or starting for %d on %d (%d)\n", sta_id, tid, + trans->shrd->tid_data[sta_id][tid].agg.state); + spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); + return 0; + } - iwl_clear_bits_prph(priv, SCD_AGGR_SEL, (1 << txq_id)); + write_ptr = trans_pcie->txq[txq_id].q.write_ptr; + read_ptr = trans_pcie->txq[txq_id].q.read_ptr; - priv->txq[txq_id].q.read_ptr = (ssn_idx & 0xff); - priv->txq[txq_id].q.write_ptr = (ssn_idx & 0xff); - /* supposes that ssn_idx is valid (!= 0xFFF) */ - iwl_trans_set_wr_ptrs(priv, txq_id, ssn_idx); + /* The queue is not empty */ + if (write_ptr != read_ptr) { + IWL_DEBUG_HT(trans, "Stopping a non empty AGG HW QUEUE\n"); + trans->shrd->tid_data[sta_id][tid].agg.state = + IWL_EMPTYING_HW_QUEUE_DELBA; + spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); + return 0; + } + + IWL_DEBUG_HT(trans, "HW queue is empty\n"); +turn_off: + trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; + + /* do not restore/save irqs */ + spin_unlock(&trans->shrd->sta_lock); + spin_lock(&trans->shrd->lock); - iwl_clear_bits_prph(priv, SCD_INTERRUPT_MASK, (1 << txq_id)); - iwl_txq_ctx_deactivate(priv, txq_id); - iwl_trans_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0); + iwl_trans_pcie_txq_agg_disable(trans, txq_id); + + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + iwl_stop_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid); return 0; } @@ -524,9 +678,10 @@ int iwl_trans_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, * failed. On success, it turns the index (> 0) of command in the * command queue. */ -static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { - struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue]; struct iwl_queue *q = &txq->q; struct iwl_device_cmd *out_cmd; struct iwl_cmd_meta *out_meta; @@ -544,14 +699,14 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) int trace_idx; #endif - if (test_bit(STATUS_FW_ERROR, &priv->status)) { - IWL_WARN(priv, "fw recovery, no hcmd send\n"); + if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) { + IWL_WARN(trans, "fw recovery, no hcmd send\n"); return -EIO; } - if ((priv->ucode_owner == IWL_OWNERSHIP_TM) && + if ((trans->shrd->ucode_owner == IWL_OWNERSHIP_TM) && !(cmd->flags & CMD_ON_DEMAND)) { - IWL_DEBUG_HC(priv, "tm own the uCode, no regular hcmd send\n"); + IWL_DEBUG_HC(trans, "tm own the uCode, no regular hcmd send\n"); return -EIO; } @@ -584,22 +739,22 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE)) return -EINVAL; - if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) { - IWL_WARN(priv, "Not sending command - %s KILL\n", - iwl_is_rfkill(priv) ? "RF" : "CT"); + if (iwl_is_rfkill(trans->shrd) || iwl_is_ctkill(trans->shrd)) { + IWL_WARN(trans, "Not sending command - %s KILL\n", + iwl_is_rfkill(trans->shrd) ? "RF" : "CT"); return -EIO; } - spin_lock_irqsave(&priv->hcmd_lock, flags); + spin_lock_irqsave(&trans->hcmd_lock, flags); if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { - spin_unlock_irqrestore(&priv->hcmd_lock, flags); + spin_unlock_irqrestore(&trans->hcmd_lock, flags); - IWL_ERR(priv, "No space in command queue\n"); - is_ct_kill = iwl_check_for_ct_kill(priv); + IWL_ERR(trans, "No space in command queue\n"); + is_ct_kill = iwl_check_for_ct_kill(priv(trans)); if (!is_ct_kill) { - IWL_ERR(priv, "Restarting adapter due to queue full\n"); - iwlagn_fw_error(priv, false); + IWL_ERR(trans, "Restarting adapter queue is full\n"); + iwlagn_fw_error(priv(trans), false); } return -ENOSPC; } @@ -611,19 +766,18 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */ if (cmd->flags & CMD_WANT_SKB) out_meta->source = cmd; - if (cmd->flags & CMD_ASYNC) - out_meta->callback = cmd->callback; /* set up the header */ out_cmd->hdr.cmd = cmd->id; out_cmd->hdr.flags = 0; - out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) | - INDEX_TO_SEQ(q->write_ptr)); + out_cmd->hdr.sequence = + cpu_to_le16(QUEUE_TO_SEQ(trans->shrd->cmd_queue) | + INDEX_TO_SEQ(q->write_ptr)); /* and copy the data that needs to be copied */ - cmd_dest = &out_cmd->cmd.payload[0]; + cmd_dest = out_cmd->payload; for (i = 0; i < IWL_MAX_CMD_TFDS; i++) { if (!cmd->len[i]) continue; @@ -633,16 +787,16 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) cmd_dest += cmd->len[i]; } - IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, " + IWL_DEBUG_HC(trans, "Sending command %s (#%x), seq: 0x%04X, " "%d bytes at %d[%d]:%d\n", get_cmd_string(out_cmd->hdr.cmd), out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence), cmd_size, - q->write_ptr, idx, priv->cmd_queue); + q->write_ptr, idx, trans->shrd->cmd_queue); - phys_addr = dma_map_single(priv->bus->dev, &out_cmd->hdr, copy_size, + phys_addr = dma_map_single(bus(trans)->dev, &out_cmd->hdr, copy_size, DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(priv->bus->dev, phys_addr))) { + if (unlikely(dma_mapping_error(bus(trans)->dev, phys_addr))) { idx = -ENOMEM; goto out; } @@ -650,7 +804,8 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) dma_unmap_addr_set(out_meta, mapping, phys_addr); dma_unmap_len_set(out_meta, len, copy_size); - iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, copy_size, 1); + iwlagn_txq_attach_buf_to_tfd(trans, txq, + phys_addr, copy_size, 1); #ifdef CONFIG_IWLWIFI_DEVICE_TRACING trace_bufs[0] = &out_cmd->hdr; trace_lens[0] = copy_size; @@ -662,17 +817,18 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) continue; if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)) continue; - phys_addr = dma_map_single(priv->bus->dev, (void *)cmd->data[i], + phys_addr = dma_map_single(bus(trans)->dev, + (void *)cmd->data[i], cmd->len[i], DMA_BIDIRECTIONAL); - if (dma_mapping_error(priv->bus->dev, phys_addr)) { - iwlagn_unmap_tfd(priv, out_meta, + if (dma_mapping_error(bus(trans)->dev, phys_addr)) { + iwlagn_unmap_tfd(trans, out_meta, &txq->tfds[q->write_ptr], DMA_BIDIRECTIONAL); idx = -ENOMEM; goto out; } - iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, + iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, cmd->len[i], 0); #ifdef CONFIG_IWLWIFI_DEVICE_TRACING trace_bufs[trace_idx] = cmd->data[i]; @@ -688,7 +844,7 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) /* check that tracing gets all possible blocks */ BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3); #ifdef CONFIG_IWLWIFI_DEVICE_TRACING - trace_iwlwifi_dev_hcmd(priv, cmd->flags, + trace_iwlwifi_dev_hcmd(priv(trans), cmd->flags, trace_bufs[0], trace_lens[0], trace_bufs[1], trace_lens[1], trace_bufs[2], trace_lens[2]); @@ -696,10 +852,10 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_txq_update_write_ptr(priv, txq); + iwl_txq_update_write_ptr(trans, txq); out: - spin_unlock_irqrestore(&priv->hcmd_lock, flags); + spin_unlock_irqrestore(&trans->hcmd_lock, flags); return idx; } @@ -710,14 +866,16 @@ static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) * need to be reclaimed. As result, some free space forms. If there is * enough free space (> low mark), wake the stack that feeds us. */ -static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx) +static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id, + int idx) { - struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; struct iwl_queue *q = &txq->q; int nfreed = 0; if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) { - IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), " + IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), " "index %d is out of range [0-%d] %d %d.\n", __func__, txq_id, idx, q->n_bd, q->write_ptr, q->read_ptr); return; @@ -727,9 +885,9 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx) q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { if (nfreed++ > 0) { - IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, + IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); - iwlagn_fw_error(priv, false); + iwlagn_fw_error(priv(trans), false); } } @@ -738,12 +896,15 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx) /** * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them * @rxb: Rx buffer to reclaim + * @handler_status: return value of the handler of the command + * (put in setup_rx_handlers) * * If an Rx buffer has an async callback associated with it the callback * will be executed. The attached skb (if present) will only be freed * if the callback returns 1 */ -void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb, + int handler_status) { struct iwl_rx_packet *pkt = rxb_addr(rxb); u16 sequence = le16_to_cpu(pkt->hdr.sequence); @@ -752,18 +913,19 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) int cmd_index; struct iwl_device_cmd *cmd; struct iwl_cmd_meta *meta; - struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue]; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue]; unsigned long flags; /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced * in the queue management code. */ - if (WARN(txq_id != priv->cmd_queue, + if (WARN(txq_id != trans->shrd->cmd_queue, "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n", - txq_id, priv->cmd_queue, sequence, - priv->txq[priv->cmd_queue].q.read_ptr, - priv->txq[priv->cmd_queue].q.write_ptr)) { - iwl_print_hex_error(priv, pkt, 32); + txq_id, trans->shrd->cmd_queue, sequence, + trans_pcie->txq[trans->shrd->cmd_queue].q.read_ptr, + trans_pcie->txq[trans->shrd->cmd_queue].q.write_ptr)) { + iwl_print_hex_error(trans, pkt, 32); return; } @@ -773,140 +935,40 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) txq->time_stamp = jiffies; - iwlagn_unmap_tfd(priv, meta, &txq->tfds[index], DMA_BIDIRECTIONAL); + iwlagn_unmap_tfd(trans, meta, &txq->tfds[index], + DMA_BIDIRECTIONAL); /* Input error checking is done when commands are added to queue. */ if (meta->flags & CMD_WANT_SKB) { meta->source->reply_page = (unsigned long)rxb_addr(rxb); + meta->source->handler_status = handler_status; rxb->page = NULL; - } else if (meta->callback) - meta->callback(priv, cmd, pkt); + } - spin_lock_irqsave(&priv->hcmd_lock, flags); + spin_lock_irqsave(&trans->hcmd_lock, flags); - iwl_hcmd_queue_reclaim(priv, txq_id, index); + iwl_hcmd_queue_reclaim(trans, txq_id, index); if (!(meta->flags & CMD_ASYNC)) { - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n", + if (!test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) { + IWL_WARN(trans, + "HCMD_ACTIVE already clear for command %s\n", + get_cmd_string(cmd->hdr.cmd)); + } + clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); + IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n", get_cmd_string(cmd->hdr.cmd)); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&trans->shrd->wait_command_queue); } meta->flags = 0; - spin_unlock_irqrestore(&priv->hcmd_lock, flags); -} - -const char *get_cmd_string(u8 cmd) -{ - switch (cmd) { - IWL_CMD(REPLY_ALIVE); - IWL_CMD(REPLY_ERROR); - IWL_CMD(REPLY_RXON); - IWL_CMD(REPLY_RXON_ASSOC); - IWL_CMD(REPLY_QOS_PARAM); - IWL_CMD(REPLY_RXON_TIMING); - IWL_CMD(REPLY_ADD_STA); - IWL_CMD(REPLY_REMOVE_STA); - IWL_CMD(REPLY_REMOVE_ALL_STA); - IWL_CMD(REPLY_TXFIFO_FLUSH); - IWL_CMD(REPLY_WEPKEY); - IWL_CMD(REPLY_TX); - IWL_CMD(REPLY_LEDS_CMD); - IWL_CMD(REPLY_TX_LINK_QUALITY_CMD); - IWL_CMD(COEX_PRIORITY_TABLE_CMD); - IWL_CMD(COEX_MEDIUM_NOTIFICATION); - IWL_CMD(COEX_EVENT_CMD); - IWL_CMD(REPLY_QUIET_CMD); - IWL_CMD(REPLY_CHANNEL_SWITCH); - IWL_CMD(CHANNEL_SWITCH_NOTIFICATION); - IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD); - IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION); - IWL_CMD(POWER_TABLE_CMD); - IWL_CMD(PM_SLEEP_NOTIFICATION); - IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC); - IWL_CMD(REPLY_SCAN_CMD); - IWL_CMD(REPLY_SCAN_ABORT_CMD); - IWL_CMD(SCAN_START_NOTIFICATION); - IWL_CMD(SCAN_RESULTS_NOTIFICATION); - IWL_CMD(SCAN_COMPLETE_NOTIFICATION); - IWL_CMD(BEACON_NOTIFICATION); - IWL_CMD(REPLY_TX_BEACON); - IWL_CMD(WHO_IS_AWAKE_NOTIFICATION); - IWL_CMD(QUIET_NOTIFICATION); - IWL_CMD(REPLY_TX_PWR_TABLE_CMD); - IWL_CMD(MEASURE_ABORT_NOTIFICATION); - IWL_CMD(REPLY_BT_CONFIG); - IWL_CMD(REPLY_STATISTICS_CMD); - IWL_CMD(STATISTICS_NOTIFICATION); - IWL_CMD(REPLY_CARD_STATE_CMD); - IWL_CMD(CARD_STATE_NOTIFICATION); - IWL_CMD(MISSED_BEACONS_NOTIFICATION); - IWL_CMD(REPLY_CT_KILL_CONFIG_CMD); - IWL_CMD(SENSITIVITY_CMD); - IWL_CMD(REPLY_PHY_CALIBRATION_CMD); - IWL_CMD(REPLY_RX_PHY_CMD); - IWL_CMD(REPLY_RX_MPDU_CMD); - IWL_CMD(REPLY_RX); - IWL_CMD(REPLY_COMPRESSED_BA); - IWL_CMD(CALIBRATION_CFG_CMD); - IWL_CMD(CALIBRATION_RES_NOTIFICATION); - IWL_CMD(CALIBRATION_COMPLETE_NOTIFICATION); - IWL_CMD(REPLY_TX_POWER_DBM_CMD); - IWL_CMD(TEMPERATURE_NOTIFICATION); - IWL_CMD(TX_ANT_CONFIGURATION_CMD); - IWL_CMD(REPLY_BT_COEX_PROFILE_NOTIF); - IWL_CMD(REPLY_BT_COEX_PRIO_TABLE); - IWL_CMD(REPLY_BT_COEX_PROT_ENV); - IWL_CMD(REPLY_WIPAN_PARAMS); - IWL_CMD(REPLY_WIPAN_RXON); - IWL_CMD(REPLY_WIPAN_RXON_TIMING); - IWL_CMD(REPLY_WIPAN_RXON_ASSOC); - IWL_CMD(REPLY_WIPAN_QOS_PARAM); - IWL_CMD(REPLY_WIPAN_WEPKEY); - IWL_CMD(REPLY_WIPAN_P2P_CHANNEL_SWITCH); - IWL_CMD(REPLY_WIPAN_NOA_NOTIFICATION); - IWL_CMD(REPLY_WIPAN_DEACTIVATION_COMPLETE); - IWL_CMD(REPLY_WOWLAN_PATTERNS); - IWL_CMD(REPLY_WOWLAN_WAKEUP_FILTER); - IWL_CMD(REPLY_WOWLAN_TSC_RSC_PARAMS); - IWL_CMD(REPLY_WOWLAN_TKIP_PARAMS); - IWL_CMD(REPLY_WOWLAN_KEK_KCK_MATERIAL); - IWL_CMD(REPLY_WOWLAN_GET_STATUS); - default: - return "UNKNOWN"; - - } + spin_unlock_irqrestore(&trans->hcmd_lock, flags); } #define HOST_COMPLETE_TIMEOUT (2 * HZ) -static void iwl_generic_cmd_callback(struct iwl_priv *priv, - struct iwl_device_cmd *cmd, - struct iwl_rx_packet *pkt) -{ - if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERR(priv, "Bad return from %s (0x%08X)\n", - get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); - return; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - switch (cmd->hdr.cmd) { - case REPLY_TX_LINK_QUALITY_CMD: - case SENSITIVITY_CMD: - IWL_DEBUG_HC_DUMP(priv, "back from %s (0x%08X)\n", - get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); - break; - default: - IWL_DEBUG_HC(priv, "back from %s (0x%08X)\n", - get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags); - } -#endif -} - -static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { int ret; @@ -914,81 +976,83 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd) if (WARN_ON(cmd->flags & CMD_WANT_SKB)) return -EINVAL; - /* Assign a generic callback if one is not provided */ - if (!cmd->callback) - cmd->callback = iwl_generic_cmd_callback; - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status)) return -EBUSY; - ret = iwl_enqueue_hcmd(priv, cmd); + ret = iwl_enqueue_hcmd(trans, cmd); if (ret < 0) { - IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", + IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } return 0; } -static int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int cmd_idx; int ret; - lockdep_assert_held(&priv->mutex); + lockdep_assert_held(&trans->shrd->mutex); - /* A synchronous command can not have a callback set. */ - if (WARN_ON(cmd->callback)) - return -EINVAL; - - IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n", + IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", get_cmd_string(cmd->id)); - set_bit(STATUS_HCMD_ACTIVE, &priv->status); - IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n", + set_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); + IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n", get_cmd_string(cmd->id)); - cmd_idx = iwl_enqueue_hcmd(priv, cmd); + cmd_idx = iwl_enqueue_hcmd(trans, cmd); if (cmd_idx < 0) { ret = cmd_idx; - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n", + clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); + IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n", get_cmd_string(cmd->id), ret); return ret; } - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - !test_bit(STATUS_HCMD_ACTIVE, &priv->status), + ret = wait_event_timeout(trans->shrd->wait_command_queue, + !test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status), HOST_COMPLETE_TIMEOUT); if (!ret) { - if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) { - IWL_ERR(priv, + if (test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status)) { + struct iwl_tx_queue *txq = + &trans_pcie->txq[trans->shrd->cmd_queue]; + struct iwl_queue *q = &txq->q; + + IWL_ERR(trans, "Error sending %s: time out after %dms.\n", get_cmd_string(cmd->id), jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); - clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command" + IWL_ERR(trans, + "Current CMD queue read_ptr %d write_ptr %d\n", + q->read_ptr, q->write_ptr); + + clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status); + IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command" "%s\n", get_cmd_string(cmd->id)); ret = -ETIMEDOUT; goto cancel; } } - if (test_bit(STATUS_RF_KILL_HW, &priv->status)) { - IWL_ERR(priv, "Command %s aborted: RF KILL Switch\n", + if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) { + IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n", get_cmd_string(cmd->id)); ret = -ECANCELED; goto fail; } - if (test_bit(STATUS_FW_ERROR, &priv->status)) { - IWL_ERR(priv, "Command %s failed: FW Error\n", + if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) { + IWL_ERR(trans, "Command %s failed: FW Error\n", get_cmd_string(cmd->id)); ret = -EIO; goto fail; } if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) { - IWL_ERR(priv, "Error: Response NULL in '%s'\n", + IWL_ERR(trans, "Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); ret = -EIO; goto cancel; @@ -1004,35 +1068,74 @@ cancel: * in later, it will possibly set an invalid * address (cmd->meta.source). */ - priv->txq[priv->cmd_queue].meta[cmd_idx].flags &= + trans_pcie->txq[trans->shrd->cmd_queue].meta[cmd_idx].flags &= ~CMD_WANT_SKB; } fail: if (cmd->reply_page) { - iwl_free_pages(priv, cmd->reply_page); + iwl_free_pages(trans->shrd, cmd->reply_page); cmd->reply_page = 0; } return ret; } -int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) +int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { if (cmd->flags & CMD_ASYNC) - return iwl_send_cmd_async(priv, cmd); + return iwl_send_cmd_async(trans, cmd); - return iwl_send_cmd_sync(priv, cmd); + return iwl_send_cmd_sync(trans, cmd); } -int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u32 flags, u16 len, - const void *data) +/* Frees buffers until index _not_ inclusive */ +int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index, + struct sk_buff_head *skbs) { - struct iwl_host_cmd cmd = { - .id = id, - .len = { len, }, - .data = { data, }, - .flags = flags, - }; - - return iwl_send_cmd(priv, &cmd); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; + struct iwl_queue *q = &txq->q; + int last_to_free; + int freed = 0; + + /* This function is not meant to release cmd queue*/ + if (WARN_ON(txq_id == trans->shrd->cmd_queue)) + return 0; + + /*Since we free until index _not_ inclusive, the one before index is + * the last we will free. This one must be used */ + last_to_free = iwl_queue_dec_wrap(index, q->n_bd); + + if ((index >= q->n_bd) || + (iwl_queue_used(q, last_to_free) == 0)) { + IWL_ERR(trans, "%s: Read index for DMA queue txq id (%d), " + "last_to_free %d is out of range [0-%d] %d %d.\n", + __func__, txq_id, last_to_free, q->n_bd, + q->write_ptr, q->read_ptr); + return 0; + } + + IWL_DEBUG_TX_REPLY(trans, "reclaim: [%d, %d, %d]\n", txq_id, + q->read_ptr, index); + + if (WARN_ON(!skb_queue_empty(skbs))) + return 0; + + for (; + q->read_ptr != index; + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { + + if (WARN_ON_ONCE(txq->skbs[txq->q.read_ptr] == NULL)) + continue; + + __skb_queue_tail(skbs, txq->skbs[txq->q.read_ptr]); + + txq->skbs[txq->q.read_ptr] = NULL; + + iwlagn_txq_inval_byte_cnt_tbl(trans, txq); + + iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE); + freed++; + } + return freed; } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c new file mode 100644 index 000000000000..8e8c75c997ee --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -0,0 +1,1998 @@ +/****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, + * USA + * + * The full GNU General Public License is included in this distribution + * in the file called LICENSE.GPL. + * + * Contact Information: + * Intel Linux Wireless <ilw@linux.intel.com> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + * BSD LICENSE + * + * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ +#include <linux/interrupt.h> +#include <linux/debugfs.h> +#include <linux/bitops.h> +#include <linux/gfp.h> + +#include "iwl-trans.h" +#include "iwl-trans-pcie-int.h" +#include "iwl-csr.h" +#include "iwl-prph.h" +#include "iwl-shared.h" +#include "iwl-eeprom.h" +#include "iwl-agn-hw.h" + +static int iwl_trans_rx_alloc(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rx_queue *rxq = &trans_pcie->rxq; + struct device *dev = bus(trans)->dev; + + memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq)); + + spin_lock_init(&rxq->lock); + + if (WARN_ON(rxq->bd || rxq->rb_stts)) + return -EINVAL; + + /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */ + rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + &rxq->bd_dma, GFP_KERNEL); + if (!rxq->bd) + goto err_bd; + memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE); + + /*Allocate the driver's pointer to receive buffer status */ + rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts), + &rxq->rb_stts_dma, GFP_KERNEL); + if (!rxq->rb_stts) + goto err_rb_stts; + memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); + + return 0; + +err_rb_stts: + dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, + rxq->bd, rxq->bd_dma); + memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); + rxq->bd = NULL; +err_bd: + return -ENOMEM; +} + +static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rx_queue *rxq = &trans_pcie->rxq; + int i; + + /* Fill the rx_used queue with _all_ of the Rx buffers */ + for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { + /* In the reset function, these buffers may have been allocated + * to an SKB, so we need to unmap and free potential storage */ + if (rxq->pool[i].page != NULL) { + dma_unmap_page(bus(trans)->dev, rxq->pool[i].page_dma, + PAGE_SIZE << hw_params(trans).rx_page_order, + DMA_FROM_DEVICE); + __free_pages(rxq->pool[i].page, + hw_params(trans).rx_page_order); + rxq->pool[i].page = NULL; + } + list_add_tail(&rxq->pool[i].list, &rxq->rx_used); + } +} + +static void iwl_trans_rx_hw_init(struct iwl_trans *trans, + struct iwl_rx_queue *rxq) +{ + u32 rb_size; + const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ + u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */ + + if (iwlagn_mod_params.amsdu_size_8K) + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; + else + rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; + + /* Stop Rx DMA */ + iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + + /* Reset driver's Rx queue write index */ + iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + + /* Tell device where to find RBD circular buffer in DRAM */ + iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_BASE_REG, + (u32)(rxq->bd_dma >> 8)); + + /* Tell device where in DRAM to update its Rx status */ + iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_STTS_WPTR_REG, + rxq->rb_stts_dma >> 4); + + /* Enable Rx DMA + * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in + * the credit mechanism in 5000 HW RX FIFO + * Direct rx interrupts to hosts + * Rx buffer size 4 or 8k + * RB timeout 0x10 + * 256 RBDs + */ + iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | + FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | + rb_size| + (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| + (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); + + /* Set interrupt coalescing timer to default (2048 usecs) */ + iwl_write8(bus(trans), CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); +} + +static int iwl_rx_init(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rx_queue *rxq = &trans_pcie->rxq; + + int i, err; + unsigned long flags; + + if (!rxq->bd) { + err = iwl_trans_rx_alloc(trans); + if (err) + return err; + } + + spin_lock_irqsave(&rxq->lock, flags); + INIT_LIST_HEAD(&rxq->rx_free); + INIT_LIST_HEAD(&rxq->rx_used); + + iwl_trans_rxq_free_rx_bufs(trans); + + for (i = 0; i < RX_QUEUE_SIZE; i++) + rxq->queue[i] = NULL; + + /* Set us so that we have processed and used all buffers, but have + * not restocked the Rx queue with fresh buffers */ + rxq->read = rxq->write = 0; + rxq->write_actual = 0; + rxq->free_count = 0; + spin_unlock_irqrestore(&rxq->lock, flags); + + iwlagn_rx_replenish(trans); + + iwl_trans_rx_hw_init(trans, rxq); + + spin_lock_irqsave(&trans->shrd->lock, flags); + rxq->need_update = 1; + iwl_rx_queue_update_write_ptr(trans, rxq); + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + return 0; +} + +static void iwl_trans_pcie_rx_free(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rx_queue *rxq = &trans_pcie->rxq; + + unsigned long flags; + + /*if rxq->bd is NULL, it means that nothing has been allocated, + * exit now */ + if (!rxq->bd) { + IWL_DEBUG_INFO(trans, "Free NULL rx context\n"); + return; + } + + spin_lock_irqsave(&rxq->lock, flags); + iwl_trans_rxq_free_rx_bufs(trans); + spin_unlock_irqrestore(&rxq->lock, flags); + + dma_free_coherent(bus(trans)->dev, sizeof(__le32) * RX_QUEUE_SIZE, + rxq->bd, rxq->bd_dma); + memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); + rxq->bd = NULL; + + if (rxq->rb_stts) + dma_free_coherent(bus(trans)->dev, + sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); + else + IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n"); + memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma)); + rxq->rb_stts = NULL; +} + +static int iwl_trans_rx_stop(struct iwl_trans *trans) +{ + + /* stop Rx DMA */ + iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + return iwl_poll_direct_bit(bus(trans), FH_MEM_RSSR_RX_STATUS_REG, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); +} + +static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans, + struct iwl_dma_ptr *ptr, size_t size) +{ + if (WARN_ON(ptr->addr)) + return -EINVAL; + + ptr->addr = dma_alloc_coherent(bus(trans)->dev, size, + &ptr->dma, GFP_KERNEL); + if (!ptr->addr) + return -ENOMEM; + ptr->size = size; + return 0; +} + +static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans, + struct iwl_dma_ptr *ptr) +{ + if (unlikely(!ptr->addr)) + return; + + dma_free_coherent(bus(trans)->dev, ptr->size, ptr->addr, ptr->dma); + memset(ptr, 0, sizeof(*ptr)); +} + +static int iwl_trans_txq_alloc(struct iwl_trans *trans, + struct iwl_tx_queue *txq, int slots_num, + u32 txq_id) +{ + size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX; + int i; + + if (WARN_ON(txq->meta || txq->cmd || txq->skbs || txq->tfds)) + return -EINVAL; + + txq->q.n_window = slots_num; + + txq->meta = kcalloc(slots_num, sizeof(txq->meta[0]), GFP_KERNEL); + txq->cmd = kcalloc(slots_num, sizeof(txq->cmd[0]), GFP_KERNEL); + + if (!txq->meta || !txq->cmd) + goto error; + + if (txq_id == trans->shrd->cmd_queue) + for (i = 0; i < slots_num; i++) { + txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd), + GFP_KERNEL); + if (!txq->cmd[i]) + goto error; + } + + /* Alloc driver data array and TFD circular buffer */ + /* Driver private data, only for Tx (not command) queues, + * not shared with device. */ + if (txq_id != trans->shrd->cmd_queue) { + txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(txq->skbs[0]), + GFP_KERNEL); + if (!txq->skbs) { + IWL_ERR(trans, "kmalloc for auxiliary BD " + "structures failed\n"); + goto error; + } + } else { + txq->skbs = NULL; + } + + /* Circular buffer of transmit frame descriptors (TFDs), + * shared with device */ + txq->tfds = dma_alloc_coherent(bus(trans)->dev, tfd_sz, + &txq->q.dma_addr, GFP_KERNEL); + if (!txq->tfds) { + IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz); + goto error; + } + txq->q.id = txq_id; + + return 0; +error: + kfree(txq->skbs); + txq->skbs = NULL; + /* since txq->cmd has been zeroed, + * all non allocated cmd[i] will be NULL */ + if (txq->cmd && txq_id == trans->shrd->cmd_queue) + for (i = 0; i < slots_num; i++) + kfree(txq->cmd[i]); + kfree(txq->meta); + kfree(txq->cmd); + txq->meta = NULL; + txq->cmd = NULL; + + return -ENOMEM; + +} + +static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq, + int slots_num, u32 txq_id) +{ + int ret; + + txq->need_update = 0; + memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num); + + /* + * For the default queues 0-3, set up the swq_id + * already -- all others need to get one later + * (if they need one at all). + */ + if (txq_id < 4) + iwl_set_swq_id(txq, txq_id, txq_id); + + /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise + * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ + BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); + + /* Initialize queue's high/low-water marks, and head/tail indexes */ + ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num, + txq_id); + if (ret) + return ret; + + /* + * Tell nic where to find circular buffer of Tx Frame Descriptors for + * given Tx queue, and enable the DMA channel used for that queue. + * Circular buffer (TFD queue in DRAM) physical base address */ + iwl_write_direct32(bus(trans), FH_MEM_CBBC_QUEUE(txq_id), + txq->q.dma_addr >> 8); + + return 0; +} + +/** + * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's + */ +static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; + struct iwl_queue *q = &txq->q; + enum dma_data_direction dma_dir; + unsigned long flags; + + if (!q->n_bd) + return; + + /* In the command queue, all the TBs are mapped as BIDI + * so unmap them as such. + */ + if (txq_id == trans->shrd->cmd_queue) + dma_dir = DMA_BIDIRECTIONAL; + else + dma_dir = DMA_TO_DEVICE; + + spin_lock_irqsave(&trans->shrd->sta_lock, flags); + while (q->write_ptr != q->read_ptr) { + /* The read_ptr needs to bound by q->n_window */ + iwlagn_txq_free_tfd(trans, txq, get_cmd_index(q, q->read_ptr), + dma_dir); + q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); + } + spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); +} + +/** + * iwl_tx_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; + struct device *dev = bus(trans)->dev; + int i; + if (WARN_ON(!txq)) + return; + + iwl_tx_queue_unmap(trans, txq_id); + + /* De-alloc array of command/tx buffers */ + + if (txq_id == trans->shrd->cmd_queue) + for (i = 0; i < txq->q.n_window; i++) + kfree(txq->cmd[i]); + + /* De-alloc circular buffer of TFDs */ + if (txq->q.n_bd) { + dma_free_coherent(dev, sizeof(struct iwl_tfd) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); + memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr)); + } + + /* De-alloc array of per-TFD driver data */ + kfree(txq->skbs); + txq->skbs = NULL; + + /* deallocate arrays */ + kfree(txq->cmd); + kfree(txq->meta); + txq->cmd = NULL; + txq->meta = NULL; + + /* 0-fill queue descriptor structure */ + memset(txq, 0, sizeof(*txq)); +} + +/** + * iwl_trans_tx_free - Free TXQ Context + * + * Destroy all TX DMA queues and structures + */ +static void iwl_trans_pcie_tx_free(struct iwl_trans *trans) +{ + int txq_id; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + /* Tx queues */ + if (trans_pcie->txq) { + for (txq_id = 0; + txq_id < hw_params(trans).max_txq_num; txq_id++) + iwl_tx_queue_free(trans, txq_id); + } + + kfree(trans_pcie->txq); + trans_pcie->txq = NULL; + + iwlagn_free_dma_ptr(trans, &trans_pcie->kw); + + iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls); +} + +/** + * iwl_trans_tx_alloc - allocate TX context + * Allocate all Tx DMA structures and initialize them + * + * @param priv + * @return error code + */ +static int iwl_trans_tx_alloc(struct iwl_trans *trans) +{ + int ret; + int txq_id, slots_num; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + u16 scd_bc_tbls_size = hw_params(trans).max_txq_num * + sizeof(struct iwlagn_scd_bc_tbl); + + /*It is not allowed to alloc twice, so warn when this happens. + * We cannot rely on the previous allocation, so free and fail */ + if (WARN_ON(trans_pcie->txq)) { + ret = -EINVAL; + goto error; + } + + ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls, + scd_bc_tbls_size); + if (ret) { + IWL_ERR(trans, "Scheduler BC Table allocation failed\n"); + goto error; + } + + /* Alloc keep-warm buffer */ + ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE); + if (ret) { + IWL_ERR(trans, "Keep Warm allocation failed\n"); + goto error; + } + + trans_pcie->txq = kcalloc(hw_params(trans).max_txq_num, + sizeof(struct iwl_tx_queue), GFP_KERNEL); + if (!trans_pcie->txq) { + IWL_ERR(trans, "Not enough memory for txq\n"); + ret = ENOMEM; + goto error; + } + + /* Alloc and init all Tx queues, including the command queue (#4/#9) */ + for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) { + slots_num = (txq_id == trans->shrd->cmd_queue) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id], + slots_num, txq_id); + if (ret) { + IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id); + goto error; + } + } + + return 0; + +error: + iwl_trans_pcie_tx_free(trans); + + return ret; +} +static int iwl_tx_init(struct iwl_trans *trans) +{ + int ret; + int txq_id, slots_num; + unsigned long flags; + bool alloc = false; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + if (!trans_pcie->txq) { + ret = iwl_trans_tx_alloc(trans); + if (ret) + goto error; + alloc = true; + } + + spin_lock_irqsave(&trans->shrd->lock, flags); + + /* Turn off all Tx DMA fifos */ + iwl_write_prph(bus(trans), SCD_TXFACT, 0); + + /* Tell NIC where to find the "keep warm" buffer */ + iwl_write_direct32(bus(trans), FH_KW_MEM_ADDR_REG, + trans_pcie->kw.dma >> 4); + + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + /* Alloc and init all Tx queues, including the command queue (#4/#9) */ + for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) { + slots_num = (txq_id == trans->shrd->cmd_queue) ? + TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; + ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id], + slots_num, txq_id); + if (ret) { + IWL_ERR(trans, "Tx %d queue init failed\n", txq_id); + goto error; + } + } + + return 0; +error: + /*Upon error, free only if we allocated something */ + if (alloc) + iwl_trans_pcie_tx_free(trans); + return ret; +} + +static void iwl_set_pwr_vmain(struct iwl_trans *trans) +{ +/* + * (for documentation purposes) + * to set power to V_AUX, do: + + if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) + iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); + */ + + iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); +} + +static int iwl_nic_init(struct iwl_trans *trans) +{ + unsigned long flags; + + /* nic_init */ + spin_lock_irqsave(&trans->shrd->lock, flags); + iwl_apm_init(priv(trans)); + + /* Set interrupt coalescing calibration timer to default (512 usecs) */ + iwl_write8(bus(trans), CSR_INT_COALESCING, + IWL_HOST_INT_CALIB_TIMEOUT_DEF); + + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + iwl_set_pwr_vmain(trans); + + iwl_nic_config(priv(trans)); + + /* Allocate the RX queue, or reset if it is already allocated */ + iwl_rx_init(trans); + + /* Allocate or reset and init all Tx and Command queues */ + if (iwl_tx_init(trans)) + return -ENOMEM; + + if (hw_params(trans).shadow_reg_enable) { + /* enable shadow regs in HW */ + iwl_set_bit(bus(trans), CSR_MAC_SHADOW_REG_CTRL, + 0x800FFFFF); + } + + set_bit(STATUS_INIT, &trans->shrd->status); + + return 0; +} + +#define HW_READY_TIMEOUT (50) + +/* Note: returns poll_bit return value, which is >= 0 if success */ +static int iwl_set_hw_ready(struct iwl_trans *trans) +{ + int ret; + + iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); + + /* See if we got it */ + ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, + CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, + HW_READY_TIMEOUT); + + IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : ""); + return ret; +} + +/* Note: returns standard 0/-ERROR code */ +static int iwl_trans_pcie_prepare_card_hw(struct iwl_trans *trans) +{ + int ret; + + IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n"); + + ret = iwl_set_hw_ready(trans); + if (ret >= 0) + return 0; + + /* If HW is not ready, prepare the conditions to check again */ + iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PREPARE); + + ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG, + ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, + CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); + + if (ret < 0) + return ret; + + /* HW should be ready by now, check again. */ + ret = iwl_set_hw_ready(trans); + if (ret >= 0) + return 0; + return ret; +} + +#define IWL_AC_UNSET -1 + +struct queue_to_fifo_ac { + s8 fifo, ac; +}; + +static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = { + { IWL_TX_FIFO_VO, IEEE80211_AC_VO, }, + { IWL_TX_FIFO_VI, IEEE80211_AC_VI, }, + { IWL_TX_FIFO_BE, IEEE80211_AC_BE, }, + { IWL_TX_FIFO_BK, IEEE80211_AC_BK, }, + { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, + { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, +}; + +static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = { + { IWL_TX_FIFO_VO, IEEE80211_AC_VO, }, + { IWL_TX_FIFO_VI, IEEE80211_AC_VI, }, + { IWL_TX_FIFO_BE, IEEE80211_AC_BE, }, + { IWL_TX_FIFO_BK, IEEE80211_AC_BK, }, + { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, }, + { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, }, + { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, }, + { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, }, + { IWL_TX_FIFO_BE_IPAN, 2, }, + { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, + { IWL_TX_FIFO_AUX, IWL_AC_UNSET, }, +}; + +static const u8 iwlagn_bss_ac_to_fifo[] = { + IWL_TX_FIFO_VO, + IWL_TX_FIFO_VI, + IWL_TX_FIFO_BE, + IWL_TX_FIFO_BK, +}; +static const u8 iwlagn_bss_ac_to_queue[] = { + 0, 1, 2, 3, +}; +static const u8 iwlagn_pan_ac_to_fifo[] = { + IWL_TX_FIFO_VO_IPAN, + IWL_TX_FIFO_VI_IPAN, + IWL_TX_FIFO_BE_IPAN, + IWL_TX_FIFO_BK_IPAN, +}; +static const u8 iwlagn_pan_ac_to_queue[] = { + 7, 6, 5, 4, +}; + +static int iwl_trans_pcie_start_device(struct iwl_trans *trans) +{ + int ret; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + trans->shrd->ucode_owner = IWL_OWNERSHIP_DRIVER; + trans_pcie->ac_to_queue[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_queue; + trans_pcie->ac_to_queue[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_queue; + + trans_pcie->ac_to_fifo[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_fifo; + trans_pcie->ac_to_fifo[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_fifo; + + trans_pcie->mcast_queue[IWL_RXON_CTX_BSS] = 0; + trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE; + + if ((hw_params(trans).sku & EEPROM_SKU_CAP_AMT_ENABLE) && + iwl_trans_pcie_prepare_card_hw(trans)) { + IWL_WARN(trans, "Exit HW not ready\n"); + return -EIO; + } + + /* If platform's RF_KILL switch is NOT set to KILL */ + if (iwl_read32(bus(trans), CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) + clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status); + else + set_bit(STATUS_RF_KILL_HW, &trans->shrd->status); + + if (iwl_is_rfkill(trans->shrd)) { + iwl_set_hw_rfkill_state(priv(trans), true); + iwl_enable_interrupts(trans); + return -ERFKILL; + } + + iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF); + + ret = iwl_nic_init(trans); + if (ret) { + IWL_ERR(trans, "Unable to init nic\n"); + return ret; + } + + /* make sure rfkill handshake bits are cleared */ + iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + + /* clear (again), then enable host interrupts */ + iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF); + iwl_enable_interrupts(trans); + + /* really make sure rfkill handshake bits are cleared */ + iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + + return 0; +} + +/* + * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask + * must be called under priv->shrd->lock and mac access + */ +static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask) +{ + iwl_write_prph(bus(trans), SCD_TXFACT, mask); +} + +static void iwl_trans_pcie_tx_start(struct iwl_trans *trans) +{ + const struct queue_to_fifo_ac *queue_to_fifo; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + u32 a; + unsigned long flags; + int i, chan; + u32 reg_val; + + spin_lock_irqsave(&trans->shrd->lock, flags); + + trans_pcie->scd_base_addr = + iwl_read_prph(bus(trans), SCD_SRAM_BASE_ADDR); + a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND; + /* reset conext data memory */ + for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND; + a += 4) + iwl_write_targ_mem(bus(trans), a, 0); + /* reset tx status memory */ + for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND; + a += 4) + iwl_write_targ_mem(bus(trans), a, 0); + for (; a < trans_pcie->scd_base_addr + + SCD_TRANS_TBL_OFFSET_QUEUE(hw_params(trans).max_txq_num); + a += 4) + iwl_write_targ_mem(bus(trans), a, 0); + + iwl_write_prph(bus(trans), SCD_DRAM_BASE_ADDR, + trans_pcie->scd_bc_tbls.dma >> 10); + + /* Enable DMA channel */ + for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++) + iwl_write_direct32(bus(trans), FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + + /* Update FH chicken bits */ + reg_val = iwl_read_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); + + iwl_write_prph(bus(trans), SCD_QUEUECHAIN_SEL, + SCD_QUEUECHAIN_SEL_ALL(trans)); + iwl_write_prph(bus(trans), SCD_AGGR_SEL, 0); + + /* initiate the queues */ + for (i = 0; i < hw_params(trans).max_txq_num; i++) { + iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(i), 0); + iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, 0 | (i << 8)); + iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(i), 0); + iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr + + SCD_CONTEXT_QUEUE_OFFSET(i) + + sizeof(u32), + ((SCD_WIN_SIZE << + SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & + SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | + ((SCD_FRAME_LIMIT << + SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & + SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); + } + + iwl_write_prph(bus(trans), SCD_INTERRUPT_MASK, + IWL_MASK(0, hw_params(trans).max_txq_num)); + + /* Activate all Tx DMA/FIFO channels */ + iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7)); + + /* map queues to FIFOs */ + if (trans->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS)) + queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo; + else + queue_to_fifo = iwlagn_default_queue_to_tx_fifo; + + iwl_trans_set_wr_ptrs(trans, trans->shrd->cmd_queue, 0); + + /* make sure all queue are not stopped */ + memset(&trans_pcie->queue_stopped[0], 0, + sizeof(trans_pcie->queue_stopped)); + for (i = 0; i < 4; i++) + atomic_set(&trans_pcie->queue_stop_count[i], 0); + + /* reset to 0 to enable all the queue first */ + trans_pcie->txq_ctx_active_msk = 0; + + BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) < + IWLAGN_FIRST_AMPDU_QUEUE); + BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) < + IWLAGN_FIRST_AMPDU_QUEUE); + + for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) { + int fifo = queue_to_fifo[i].fifo; + int ac = queue_to_fifo[i].ac; + + iwl_txq_ctx_activate(trans_pcie, i); + + if (fifo == IWL_TX_FIFO_UNUSED) + continue; + + if (ac != IWL_AC_UNSET) + iwl_set_swq_id(&trans_pcie->txq[i], ac, i); + iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i], + fifo, 0); + } + + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + /* Enable L1-Active */ + iwl_clear_bits_prph(bus(trans), APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); +} + +/** + * iwlagn_txq_ctx_stop - Stop all Tx DMA channels + */ +static int iwl_trans_tx_stop(struct iwl_trans *trans) +{ + int ch, txq_id; + unsigned long flags; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + /* Turn off all Tx DMA fifos */ + spin_lock_irqsave(&trans->shrd->lock, flags); + + iwl_trans_txq_set_sched(trans, 0); + + /* Stop each Tx DMA channel, and wait for it to be idle */ + for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { + iwl_write_direct32(bus(trans), + FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); + if (iwl_poll_direct_bit(bus(trans), FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), + 1000)) + IWL_ERR(trans, "Failing on timeout while stopping" + " DMA channel %d [0x%08x]", ch, + iwl_read_direct32(bus(trans), + FH_TSSR_TX_STATUS_REG)); + } + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + if (!trans_pcie->txq) { + IWL_WARN(trans, "Stopping tx queues that aren't allocated..."); + return 0; + } + + /* Unmap DMA from host system and free skb's */ + for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) + iwl_tx_queue_unmap(trans, txq_id); + + return 0; +} + +static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans) +{ + unsigned long flags; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + spin_lock_irqsave(&trans->shrd->lock, flags); + iwl_disable_interrupts(trans); + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + /* wait to make sure we flush pending tasklet*/ + synchronize_irq(bus(trans)->irq); + tasklet_kill(&trans_pcie->irq_tasklet); +} + +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) +{ + /* stop and reset the on-board processor */ + iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); + + /* tell the device to stop sending interrupts */ + iwl_trans_pcie_disable_sync_irq(trans); + + /* device going down, Stop using ICT table */ + iwl_disable_ict(trans); + + /* + * If a HW restart happens during firmware loading, + * then the firmware loading might call this function + * and later it might be called again due to the + * restart. So don't process again if the device is + * already dead. + */ + if (test_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status)) { + iwl_trans_tx_stop(trans); + iwl_trans_rx_stop(trans); + + /* Power-down device's busmaster DMA clocks */ + iwl_write_prph(bus(trans), APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); + udelay(5); + } + + /* Make sure (redundant) we've released our request to stay awake */ + iwl_clear_bit(bus(trans), CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + + /* Stop the device, and put it in low power state */ + iwl_apm_stop(priv(trans)); +} + +static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, + u8 sta_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload; + struct iwl_cmd_meta *out_meta; + struct iwl_tx_queue *txq; + struct iwl_queue *q; + + dma_addr_t phys_addr = 0; + dma_addr_t txcmd_phys; + dma_addr_t scratch_phys; + u16 len, firstlen, secondlen; + u16 seq_number = 0; + u8 wait_write_ptr = 0; + u8 txq_id; + u8 tid = 0; + bool is_agg = false; + __le16 fc = hdr->frame_control; + u8 hdr_len = ieee80211_hdrlen(fc); + + /* + * Send this frame after DTIM -- there's a special queue + * reserved for this for contexts that support AP mode. + */ + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + txq_id = trans_pcie->mcast_queue[ctx]; + + /* + * The microcode will clear the more data + * bit in the last frame it transmits. + */ + hdr->frame_control |= + cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) + txq_id = IWL_AUX_QUEUE; + else + txq_id = + trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)]; + + if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { + u8 *qc = NULL; + struct iwl_tid_data *tid_data; + qc = ieee80211_get_qos_ctl(hdr); + tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; + tid_data = &trans->shrd->tid_data[sta_id][tid]; + + if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) + return -1; + + seq_number = tid_data->seq_number; + seq_number &= IEEE80211_SCTL_SEQ; + hdr->seq_ctrl = hdr->seq_ctrl & + cpu_to_le16(IEEE80211_SCTL_FRAG); + hdr->seq_ctrl |= cpu_to_le16(seq_number); + seq_number += 0x10; + /* aggregation is on for this <sta,tid> */ + if (info->flags & IEEE80211_TX_CTL_AMPDU) { + WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON); + txq_id = tid_data->agg.txq_id; + is_agg = true; + } + } + + /* Copy MAC header from skb into command buffer */ + memcpy(tx_cmd->hdr, hdr, hdr_len); + + txq = &trans_pcie->txq[txq_id]; + q = &txq->q; + + /* Set up driver data for this TFD */ + txq->skbs[q->write_ptr] = skb; + txq->cmd[q->write_ptr] = dev_cmd; + + dev_cmd->hdr.cmd = REPLY_TX; + dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | + INDEX_TO_SEQ(q->write_ptr))); + + /* Set up first empty entry in queue's array of Tx/cmd buffers */ + out_meta = &txq->meta[q->write_ptr]; + + /* + * Use the first empty entry in this queue's command buffer array + * to contain the Tx command and MAC header concatenated together + * (payload data will be in another buffer). + * Size of this varies, due to varying MAC header length. + * If end is not dword aligned, we'll have 2 extra bytes at the end + * of the MAC header (device reads on dword boundaries). + * We'll tell device about this padding later. + */ + len = sizeof(struct iwl_tx_cmd) + + sizeof(struct iwl_cmd_header) + hdr_len; + firstlen = (len + 3) & ~3; + + /* Tell NIC about any 2-byte padding after MAC header */ + if (firstlen != len) + tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; + + /* Physical address of this Tx command's header (not MAC header!), + * within command buffer array. */ + txcmd_phys = dma_map_single(bus(trans)->dev, + &dev_cmd->hdr, firstlen, + DMA_BIDIRECTIONAL); + if (unlikely(dma_mapping_error(bus(trans)->dev, txcmd_phys))) + return -1; + dma_unmap_addr_set(out_meta, mapping, txcmd_phys); + dma_unmap_len_set(out_meta, len, firstlen); + + if (!ieee80211_has_morefrags(fc)) { + txq->need_update = 1; + } else { + wait_write_ptr = 1; + txq->need_update = 0; + } + + /* Set up TFD's 2nd entry to point directly to remainder of skb, + * if any (802.11 null frames have no payload). */ + secondlen = skb->len - hdr_len; + if (secondlen > 0) { + phys_addr = dma_map_single(bus(trans)->dev, skb->data + hdr_len, + secondlen, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(bus(trans)->dev, phys_addr))) { + dma_unmap_single(bus(trans)->dev, + dma_unmap_addr(out_meta, mapping), + dma_unmap_len(out_meta, len), + DMA_BIDIRECTIONAL); + return -1; + } + } + + /* Attach buffers to TFD */ + iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1); + if (secondlen > 0) + iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, + secondlen, 0); + + scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + + offsetof(struct iwl_tx_cmd, scratch); + + /* take back ownership of DMA buffer to enable update */ + dma_sync_single_for_cpu(bus(trans)->dev, txcmd_phys, firstlen, + DMA_BIDIRECTIONAL); + tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); + + IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n", + le16_to_cpu(dev_cmd->hdr.sequence)); + IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); + iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); + iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); + + /* Set up entry for this TFD in Tx byte-count array */ + if (is_agg) + iwl_trans_txq_update_byte_cnt_tbl(trans, txq, + le16_to_cpu(tx_cmd->len)); + + dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen, + DMA_BIDIRECTIONAL); + + trace_iwlwifi_dev_tx(priv(trans), + &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr], + sizeof(struct iwl_tfd), + &dev_cmd->hdr, firstlen, + skb->data + hdr_len, secondlen); + + /* Tell device the write index *just past* this latest filled TFD */ + q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); + iwl_txq_update_write_ptr(trans, txq); + + if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { + trans->shrd->tid_data[sta_id][tid].tfds_in_queue++; + if (!ieee80211_has_morefrags(fc)) + trans->shrd->tid_data[sta_id][tid].seq_number = + seq_number; + } + + /* + * At this point the frame is "transmitted" successfully + * and we will get a TX status notification eventually, + * regardless of the value of ret. "ret" only indicates + * whether or not we should update the write pointer. + */ + if (iwl_queue_space(q) < q->high_mark) { + if (wait_write_ptr) { + txq->need_update = 1; + iwl_txq_update_write_ptr(trans, txq); + } else { + iwl_stop_queue(trans, txq); + } + } + return 0; +} + +static void iwl_trans_pcie_kick_nic(struct iwl_trans *trans) +{ + /* Remove all resets to allow NIC to operate */ + iwl_write32(bus(trans), CSR_RESET, 0); +} + +static int iwl_trans_pcie_request_irq(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + int err; + + trans_pcie->inta_mask = CSR_INI_SET_MASK; + + tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long)) + iwl_irq_tasklet, (unsigned long)trans); + + iwl_alloc_isr_ict(trans); + + err = request_irq(bus(trans)->irq, iwl_isr_ict, IRQF_SHARED, + DRV_NAME, trans); + if (err) { + IWL_ERR(trans, "Error allocating IRQ %d\n", bus(trans)->irq); + iwl_free_isr_ict(trans); + return err; + } + + INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish); + return 0; +} + +static int iwlagn_txq_check_empty(struct iwl_trans *trans, + int sta_id, u8 tid, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_queue *q = &trans_pcie->txq[txq_id].q; + struct iwl_tid_data *tid_data = &trans->shrd->tid_data[sta_id][tid]; + + lockdep_assert_held(&trans->shrd->sta_lock); + + switch (trans->shrd->tid_data[sta_id][tid].agg.state) { + case IWL_EMPTYING_HW_QUEUE_DELBA: + /* We are reclaiming the last packet of the */ + /* aggregated HW queue */ + if ((txq_id == tid_data->agg.txq_id) && + (q->read_ptr == q->write_ptr)) { + IWL_DEBUG_HT(trans, + "HW queue empty: continue DELBA flow\n"); + iwl_trans_pcie_txq_agg_disable(trans, txq_id); + tid_data->agg.state = IWL_AGG_OFF; + iwl_stop_tx_ba_trans_ready(priv(trans), + NUM_IWL_RXON_CTX, + sta_id, tid); + iwl_wake_queue(trans, &trans_pcie->txq[txq_id]); + } + break; + case IWL_EMPTYING_HW_QUEUE_ADDBA: + /* We are reclaiming the last packet of the queue */ + if (tid_data->tfds_in_queue == 0) { + IWL_DEBUG_HT(trans, + "HW queue empty: continue ADDBA flow\n"); + tid_data->agg.state = IWL_AGG_ON; + iwl_start_tx_ba_trans_ready(priv(trans), + NUM_IWL_RXON_CTX, + sta_id, tid); + } + break; + default: + break; + } + + return 0; +} + +static void iwl_free_tfds_in_queue(struct iwl_trans *trans, + int sta_id, int tid, int freed) +{ + lockdep_assert_held(&trans->shrd->sta_lock); + + if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed) + trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed; + else { + IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n", + trans->shrd->tid_data[sta_id][tid].tfds_in_queue, + freed); + trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0; + } +} + +static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, + int txq_id, int ssn, u32 status, + struct sk_buff_head *skbs) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id]; + enum iwl_agg_state agg_state; + /* n_bd is usually 256 => n_bd - 1 = 0xff */ + int tfd_num = ssn & (txq->q.n_bd - 1); + int freed = 0; + bool cond; + + txq->time_stamp = jiffies; + + if (txq->sched_retry) { + agg_state = + trans->shrd->tid_data[txq->sta_id][txq->tid].agg.state; + cond = (agg_state != IWL_EMPTYING_HW_QUEUE_DELBA); + } else { + cond = (status != TX_STATUS_FAIL_PASSIVE_NO_RX); + } + + if (txq->q.read_ptr != tfd_num) { + IWL_DEBUG_TX_REPLY(trans, "Retry scheduler reclaim " + "scd_ssn=%d idx=%d txq=%d swq=%d\n", + ssn , tfd_num, txq_id, txq->swq_id); + freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs); + if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond) + iwl_wake_queue(trans, txq); + } + + iwl_free_tfds_in_queue(trans, sta_id, tid, freed); + iwlagn_txq_check_empty(trans, sta_id, tid, txq_id); +} + +static void iwl_trans_pcie_free(struct iwl_trans *trans) +{ + iwl_trans_pcie_tx_free(trans); + iwl_trans_pcie_rx_free(trans); + free_irq(bus(trans)->irq, trans); + iwl_free_isr_ict(trans); + trans->shrd->trans = NULL; + kfree(trans); +} + +#ifdef CONFIG_PM_SLEEP +static int iwl_trans_pcie_suspend(struct iwl_trans *trans) +{ + /* + * This function is called when system goes into suspend state + * mac80211 will call iwlagn_mac_stop() from the mac80211 suspend + * function first but since iwlagn_mac_stop() has no knowledge of + * who the caller is, + * it will not call apm_ops.stop() to stop the DMA operation. + * Calling apm_ops.stop here to make sure we stop the DMA. + * + * But of course ... if we have configured WoWLAN then we did other + * things already :-) + */ + if (!trans->shrd->wowlan) { + iwl_apm_stop(priv(trans)); + } else { + iwl_disable_interrupts(trans); + iwl_clear_bit(bus(trans), CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + } + + return 0; +} + +static int iwl_trans_pcie_resume(struct iwl_trans *trans) +{ + bool hw_rfkill = false; + + iwl_enable_interrupts(trans); + + if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) & + CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) + hw_rfkill = true; + + if (hw_rfkill) + set_bit(STATUS_RF_KILL_HW, &trans->shrd->status); + else + clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status); + + iwl_set_hw_rfkill_state(priv(trans), hw_rfkill); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx) +{ + u8 ac, txq_id; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + for (ac = 0; ac < AC_NUM; ac++) { + txq_id = trans_pcie->ac_to_queue[ctx][ac]; + IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n", + ac, + (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0) + ? "stopped" : "awake"); + iwl_wake_queue(trans, &trans_pcie->txq[txq_id]); + } +} + +const struct iwl_trans_ops trans_ops_pcie; + +static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd) +{ + struct iwl_trans *iwl_trans = kzalloc(sizeof(struct iwl_trans) + + sizeof(struct iwl_trans_pcie), + GFP_KERNEL); + if (iwl_trans) { + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(iwl_trans); + iwl_trans->ops = &trans_ops_pcie; + iwl_trans->shrd = shrd; + trans_pcie->trans = iwl_trans; + spin_lock_init(&iwl_trans->hcmd_lock); + } + + return iwl_trans; +} + +static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + iwl_stop_queue(trans, &trans_pcie->txq[txq_id]); +} + +#define IWL_FLUSH_WAIT_MS 2000 + +static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq; + struct iwl_queue *q; + int cnt; + unsigned long now = jiffies; + int ret = 0; + + /* waiting for all the tx frames complete might take a while */ + for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) { + if (cnt == trans->shrd->cmd_queue) + continue; + txq = &trans_pcie->txq[cnt]; + q = &txq->q; + while (q->read_ptr != q->write_ptr && !time_after(jiffies, + now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) + msleep(1); + + if (q->read_ptr != q->write_ptr) { + IWL_ERR(trans, "fail to flush all tx fifo queues\n"); + ret = -ETIMEDOUT; + break; + } + } + return ret; +} + +/* + * On every watchdog tick we check (latest) time stamp. If it does not + * change during timeout period and queue is not empty we reset firmware. + */ +static int iwl_trans_pcie_check_stuck_queue(struct iwl_trans *trans, int cnt) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq = &trans_pcie->txq[cnt]; + struct iwl_queue *q = &txq->q; + unsigned long timeout; + + if (q->read_ptr == q->write_ptr) { + txq->time_stamp = jiffies; + return 0; + } + + timeout = txq->time_stamp + + msecs_to_jiffies(hw_params(trans).wd_timeout); + + if (time_after(jiffies, timeout)) { + IWL_ERR(trans, "Queue %d stuck for %u ms.\n", q->id, + hw_params(trans).wd_timeout); + IWL_ERR(trans, "Current read_ptr %d write_ptr %d\n", + q->read_ptr, q->write_ptr); + return 1; + } + + return 0; +} + +static const char *get_fh_string(int cmd) +{ + switch (cmd) { + IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); + IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); + IWL_CMD(FH_RSCSR_CHNL0_WPTR); + IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); + IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); + IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); + IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); + IWL_CMD(FH_TSSR_TX_STATUS_REG); + IWL_CMD(FH_TSSR_TX_ERROR_REG); + default: + return "UNKNOWN"; + } +} + +int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display) +{ + int i; +#ifdef CONFIG_IWLWIFI_DEBUG + int pos = 0; + size_t bufsz = 0; +#endif + static const u32 fh_tbl[] = { + FH_RSCSR_CHNL0_STTS_WPTR_REG, + FH_RSCSR_CHNL0_RBDCB_BASE_REG, + FH_RSCSR_CHNL0_WPTR, + FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_MEM_RSSR_SHARED_CTRL_REG, + FH_MEM_RSSR_RX_STATUS_REG, + FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, + FH_TSSR_TX_STATUS_REG, + FH_TSSR_TX_ERROR_REG + }; +#ifdef CONFIG_IWLWIFI_DEBUG + if (display) { + bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; + *buf = kmalloc(bufsz, GFP_KERNEL); + if (!*buf) + return -ENOMEM; + pos += scnprintf(*buf + pos, bufsz - pos, + "FH register values:\n"); + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { + pos += scnprintf(*buf + pos, bufsz - pos, + " %34s: 0X%08x\n", + get_fh_string(fh_tbl[i]), + iwl_read_direct32(bus(trans), fh_tbl[i])); + } + return pos; + } +#endif + IWL_ERR(trans, "FH register values:\n"); + for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) { + IWL_ERR(trans, " %34s: 0X%08x\n", + get_fh_string(fh_tbl[i]), + iwl_read_direct32(bus(trans), fh_tbl[i])); + } + return 0; +} + +static const char *get_csr_string(int cmd) +{ + switch (cmd) { + IWL_CMD(CSR_HW_IF_CONFIG_REG); + IWL_CMD(CSR_INT_COALESCING); + IWL_CMD(CSR_INT); + IWL_CMD(CSR_INT_MASK); + IWL_CMD(CSR_FH_INT_STATUS); + IWL_CMD(CSR_GPIO_IN); + IWL_CMD(CSR_RESET); + IWL_CMD(CSR_GP_CNTRL); + IWL_CMD(CSR_HW_REV); + IWL_CMD(CSR_EEPROM_REG); + IWL_CMD(CSR_EEPROM_GP); + IWL_CMD(CSR_OTP_GP_REG); + IWL_CMD(CSR_GIO_REG); + IWL_CMD(CSR_GP_UCODE_REG); + IWL_CMD(CSR_GP_DRIVER_REG); + IWL_CMD(CSR_UCODE_DRV_GP1); + IWL_CMD(CSR_UCODE_DRV_GP2); + IWL_CMD(CSR_LED_REG); + IWL_CMD(CSR_DRAM_INT_TBL_REG); + IWL_CMD(CSR_GIO_CHICKEN_BITS); + IWL_CMD(CSR_ANA_PLL_CFG); + IWL_CMD(CSR_HW_REV_WA_REG); + IWL_CMD(CSR_DBG_HPET_MEM_REG); + default: + return "UNKNOWN"; + } +} + +void iwl_dump_csr(struct iwl_trans *trans) +{ + int i; + static const u32 csr_tbl[] = { + CSR_HW_IF_CONFIG_REG, + CSR_INT_COALESCING, + CSR_INT, + CSR_INT_MASK, + CSR_FH_INT_STATUS, + CSR_GPIO_IN, + CSR_RESET, + CSR_GP_CNTRL, + CSR_HW_REV, + CSR_EEPROM_REG, + CSR_EEPROM_GP, + CSR_OTP_GP_REG, + CSR_GIO_REG, + CSR_GP_UCODE_REG, + CSR_GP_DRIVER_REG, + CSR_UCODE_DRV_GP1, + CSR_UCODE_DRV_GP2, + CSR_LED_REG, + CSR_DRAM_INT_TBL_REG, + CSR_GIO_CHICKEN_BITS, + CSR_ANA_PLL_CFG, + CSR_HW_REV_WA_REG, + CSR_DBG_HPET_MEM_REG + }; + IWL_ERR(trans, "CSR values:\n"); + IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is " + "CSR_INT_PERIODIC_REG)\n"); + for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { + IWL_ERR(trans, " %25s: 0X%08x\n", + get_csr_string(csr_tbl[i]), + iwl_read32(bus(trans), csr_tbl[i])); + } +} + +#ifdef CONFIG_IWLWIFI_DEBUGFS +/* create and remove of files */ +#define DEBUGFS_ADD_FILE(name, parent, mode) do { \ + if (!debugfs_create_file(#name, mode, parent, trans, \ + &iwl_dbgfs_##name##_ops)) \ + return -ENOMEM; \ +} while (0) + +/* file operation */ +#define DEBUGFS_READ_FUNC(name) \ +static ssize_t iwl_dbgfs_##name##_read(struct file *file, \ + char __user *user_buf, \ + size_t count, loff_t *ppos); + +#define DEBUGFS_WRITE_FUNC(name) \ +static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ + const char __user *user_buf, \ + size_t count, loff_t *ppos); + + +static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +#define DEBUGFS_READ_FILE_OPS(name) \ + DEBUGFS_READ_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .read = iwl_dbgfs_##name##_read, \ + .open = iwl_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ +}; + +#define DEBUGFS_WRITE_FILE_OPS(name) \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .open = iwl_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ +}; + +#define DEBUGFS_READ_WRITE_FILE_OPS(name) \ + DEBUGFS_READ_FUNC(name); \ + DEBUGFS_WRITE_FUNC(name); \ +static const struct file_operations iwl_dbgfs_##name##_ops = { \ + .write = iwl_dbgfs_##name##_write, \ + .read = iwl_dbgfs_##name##_read, \ + .open = iwl_dbgfs_open_file_generic, \ + .llseek = generic_file_llseek, \ +}; + +static ssize_t iwl_dbgfs_tx_queue_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_tx_queue *txq; + struct iwl_queue *q; + char *buf; + int pos = 0; + int cnt; + int ret; + const size_t bufsz = sizeof(char) * 64 * hw_params(trans).max_txq_num; + + if (!trans_pcie->txq) { + IWL_ERR(trans, "txq not ready\n"); + return -EAGAIN; + } + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) { + txq = &trans_pcie->txq[cnt]; + q = &txq->q; + pos += scnprintf(buf + pos, bufsz - pos, + "hwq %.2d: read=%u write=%u stop=%d" + " swq_id=%#.2x (ac %d/hwq %d)\n", + cnt, q->read_ptr, q->write_ptr, + !!test_bit(cnt, trans_pcie->queue_stopped), + txq->swq_id, txq->swq_id & 3, + (txq->swq_id >> 2) & 0x1f); + if (cnt >= 4) + continue; + /* for the ACs, display the stop count too */ + pos += scnprintf(buf + pos, bufsz - pos, + " stop-count: %d\n", + atomic_read(&trans_pcie->queue_stop_count[cnt])); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_rx_queue_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_rx_queue *rxq = &trans_pcie->rxq; + char buf[256]; + int pos = 0; + const size_t bufsz = sizeof(buf); + + pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n", + rxq->read); + pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n", + rxq->write); + pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n", + rxq->free_count); + if (rxq->rb_stts) { + pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n", + le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF); + } else { + pos += scnprintf(buf + pos, bufsz - pos, + "closed_rb_num: Not Allocated\n"); + } + return simple_read_from_buffer(user_buf, count, ppos, buf, pos); +} + +static ssize_t iwl_dbgfs_log_event_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + char *buf; + int pos = 0; + ssize_t ret = -ENOMEM; + + ret = pos = iwl_dump_nic_event_log(trans, true, &buf, true); + if (buf) { + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + } + return ret; +} + +static ssize_t iwl_dbgfs_log_event_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + u32 event_log_flag; + char buf[8]; + int buf_size; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &event_log_flag) != 1) + return -EFAULT; + if (event_log_flag == 1) + iwl_dump_nic_event_log(trans, true, NULL, false); + + return count; +} + +static ssize_t iwl_dbgfs_interrupt_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) { + + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct isr_statistics *isr_stats = &trans_pcie->isr_stats; + + int pos = 0; + char *buf; + int bufsz = 24 * 64; /* 24 items * 64 char per item */ + ssize_t ret; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERR(trans, "Can not allocate Buffer\n"); + return -ENOMEM; + } + + pos += scnprintf(buf + pos, bufsz - pos, + "Interrupt Statistics Report:\n"); + + pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n", + isr_stats->hw); + pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n", + isr_stats->sw); + if (isr_stats->sw || isr_stats->hw) { + pos += scnprintf(buf + pos, bufsz - pos, + "\tLast Restarting Code: 0x%X\n", + isr_stats->err_code); + } +#ifdef CONFIG_IWLWIFI_DEBUG + pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n", + isr_stats->sch); + pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n", + isr_stats->alive); +#endif + pos += scnprintf(buf + pos, bufsz - pos, + "HW RF KILL switch toggled:\t %u\n", isr_stats->rfkill); + + pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n", + isr_stats->ctkill); + + pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n", + isr_stats->wakeup); + + pos += scnprintf(buf + pos, bufsz - pos, + "Rx command responses:\t\t %u\n", isr_stats->rx); + + pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n", + isr_stats->tx); + + pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n", + isr_stats->unhandled); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + +static ssize_t iwl_dbgfs_interrupt_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + struct iwl_trans_pcie *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + struct isr_statistics *isr_stats = &trans_pcie->isr_stats; + + char buf[8]; + int buf_size; + u32 reset_flag; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%x", &reset_flag) != 1) + return -EFAULT; + if (reset_flag == 0) + memset(isr_stats, 0, sizeof(*isr_stats)); + + return count; +} + +static ssize_t iwl_dbgfs_csr_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + char buf[8]; + int buf_size; + int csr; + + memset(buf, 0, sizeof(buf)); + buf_size = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + if (sscanf(buf, "%d", &csr) != 1) + return -EFAULT; + + iwl_dump_csr(trans); + + return count; +} + +static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_trans *trans = file->private_data; + char *buf; + int pos = 0; + ssize_t ret = -EFAULT; + + ret = pos = iwl_dump_fh(trans, &buf, true); + if (buf) { + ret = simple_read_from_buffer(user_buf, + count, ppos, buf, pos); + kfree(buf); + } + + return ret; +} + +DEBUGFS_READ_WRITE_FILE_OPS(log_event); +DEBUGFS_READ_WRITE_FILE_OPS(interrupt); +DEBUGFS_READ_FILE_OPS(fh_reg); +DEBUGFS_READ_FILE_OPS(rx_queue); +DEBUGFS_READ_FILE_OPS(tx_queue); +DEBUGFS_WRITE_FILE_OPS(csr); + +/* + * Create the debugfs files and directories + * + */ +static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, + struct dentry *dir) +{ + DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR); + DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR); + DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(csr, dir, S_IWUSR); + DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); + return 0; +} +#else +static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, + struct dentry *dir) +{ return 0; } + +#endif /*CONFIG_IWLWIFI_DEBUGFS */ + +const struct iwl_trans_ops trans_ops_pcie = { + .alloc = iwl_trans_pcie_alloc, + .request_irq = iwl_trans_pcie_request_irq, + .start_device = iwl_trans_pcie_start_device, + .prepare_card_hw = iwl_trans_pcie_prepare_card_hw, + .stop_device = iwl_trans_pcie_stop_device, + + .tx_start = iwl_trans_pcie_tx_start, + .wake_any_queue = iwl_trans_pcie_wake_any_queue, + + .send_cmd = iwl_trans_pcie_send_cmd, + + .tx = iwl_trans_pcie_tx, + .reclaim = iwl_trans_pcie_reclaim, + + .tx_agg_disable = iwl_trans_pcie_tx_agg_disable, + .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc, + .tx_agg_setup = iwl_trans_pcie_tx_agg_setup, + + .kick_nic = iwl_trans_pcie_kick_nic, + + .free = iwl_trans_pcie_free, + .stop_queue = iwl_trans_pcie_stop_queue, + + .dbgfs_register = iwl_trans_pcie_dbgfs_register, + + .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty, + .check_stuck_queue = iwl_trans_pcie_check_stuck_queue, + +#ifdef CONFIG_PM_SLEEP + .suspend = iwl_trans_pcie_suspend, + .resume = iwl_trans_pcie_resume, +#endif +}; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c deleted file mode 100644 index 474860290404..000000000000 --- a/drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c +++ /dev/null @@ -1,979 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved. - * - * Portions of this file are derived from the ipw3945 project, as well - * as portions of the ieee80211 subsystem header files. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * Intel Linux Wireless <ilw@linux.intel.com> - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - * - *****************************************************************************/ -#include <linux/sched.h> -#include <linux/wait.h> -#include <linux/gfp.h> - -#include "iwl-dev.h" -#include "iwl-agn.h" -#include "iwl-core.h" -#include "iwl-io.h" -#include "iwl-helpers.h" -#include "iwl-trans-int-pcie.h" - -/****************************************************************************** - * - * RX path functions - * - ******************************************************************************/ - -/* - * Rx theory of operation - * - * Driver allocates a circular buffer of Receive Buffer Descriptors (RBDs), - * each of which point to Receive Buffers to be filled by the NIC. These get - * used not only for Rx frames, but for any command response or notification - * from the NIC. The driver and NIC manage the Rx buffers by means - * of indexes into the circular buffer. - * - * Rx Queue Indexes - * The host/firmware share two index registers for managing the Rx buffers. - * - * The READ index maps to the first position that the firmware may be writing - * to -- the driver can read up to (but not including) this position and get - * good data. - * The READ index is managed by the firmware once the card is enabled. - * - * The WRITE index maps to the last position the driver has read from -- the - * position preceding WRITE is the last slot the firmware can place a packet. - * - * The queue is empty (no good data) if WRITE = READ - 1, and is full if - * WRITE = READ. - * - * During initialization, the host sets up the READ queue position to the first - * INDEX position, and WRITE to the last (READ - 1 wrapped) - * - * When the firmware places a packet in a buffer, it will advance the READ index - * and fire the RX interrupt. The driver can then query the READ index and - * process as many packets as possible, moving the WRITE index forward as it - * resets the Rx queue buffers with new memory. - * - * The management in the driver is as follows: - * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free. When - * iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled - * to replenish the iwl->rxq->rx_free. - * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the - * iwl->rxq is replenished and the READ INDEX is updated (updating the - * 'processed' and 'read' driver indexes as well) - * + A received packet is processed and handed to the kernel network stack, - * detached from the iwl->rxq. The driver 'processed' index is updated. - * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free - * list. If there are no allocated buffers in iwl->rxq->rx_free, the READ - * INDEX is not incremented and iwl->status(RX_STALLED) is set. If there - * were enough free buffers and RX_STALLED is set it is cleared. - * - * - * Driver sequence: - * - * iwl_rx_queue_alloc() Allocates rx_free - * iwl_rx_replenish() Replenishes rx_free list from rx_used, and calls - * iwl_rx_queue_restock - * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx - * queue, updates firmware pointers, and updates - * the WRITE index. If insufficient rx_free buffers - * are available, schedules iwl_rx_replenish - * - * -- enable interrupts -- - * ISR - iwl_rx() Detach iwl_rx_mem_buffers from pool up to the - * READ INDEX, detaching the SKB from the pool. - * Moves the packet buffer from queue to rx_used. - * Calls iwl_rx_queue_restock to refill any empty - * slots. - * ... - * - */ - -/** - * iwl_rx_queue_space - Return number of free slots available in queue. - */ -static int iwl_rx_queue_space(const struct iwl_rx_queue *q) -{ - int s = q->read - q->write; - if (s <= 0) - s += RX_QUEUE_SIZE; - /* keep some buffer to not confuse full and empty queue */ - s -= 2; - if (s < 0) - s = 0; - return s; -} - -/** - * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue - */ -void iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, - struct iwl_rx_queue *q) -{ - unsigned long flags; - u32 reg; - - spin_lock_irqsave(&q->lock, flags); - - if (q->need_update == 0) - goto exit_unlock; - - if (priv->cfg->base_params->shadow_reg_enable) { - /* shadow register enabled */ - /* Device expects a multiple of 8 */ - q->write_actual = (q->write & ~0x7); - iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write_actual); - } else { - /* If power-saving is in use, make sure device is awake */ - if (test_bit(STATUS_POWER_PMI, &priv->status)) { - reg = iwl_read32(priv, CSR_UCODE_DRV_GP1); - - if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { - IWL_DEBUG_INFO(priv, - "Rx queue requesting wakeup," - " GP1 = 0x%x\n", reg); - iwl_set_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - goto exit_unlock; - } - - q->write_actual = (q->write & ~0x7); - iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, - q->write_actual); - - /* Else device is assumed to be awake */ - } else { - /* Device expects a multiple of 8 */ - q->write_actual = (q->write & ~0x7); - iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR, - q->write_actual); - } - } - q->need_update = 0; - - exit_unlock: - spin_unlock_irqrestore(&q->lock, flags); -} - -/** - * iwlagn_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr - */ -static inline __le32 iwlagn_dma_addr2rbd_ptr(struct iwl_priv *priv, - dma_addr_t dma_addr) -{ - return cpu_to_le32((u32)(dma_addr >> 8)); -} - -/** - * iwlagn_rx_queue_restock - refill RX queue from pre-allocated pool - * - * If there are slots in the RX queue that need to be restocked, - * and we have free pre-allocated buffers, fill the ranks as much - * as we can, pulling from rx_free. - * - * This moves the 'write' index forward to catch up with 'processed', and - * also updates the memory address in the firmware to reference the new - * target buffer. - */ -static void iwlagn_rx_queue_restock(struct iwl_priv *priv) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - struct list_head *element; - struct iwl_rx_mem_buffer *rxb; - unsigned long flags; - - spin_lock_irqsave(&rxq->lock, flags); - while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) { - /* The overwritten rxb must be a used one */ - rxb = rxq->queue[rxq->write]; - BUG_ON(rxb && rxb->page); - - /* Get next free Rx buffer, remove from free list */ - element = rxq->rx_free.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); - list_del(element); - - /* Point to Rx buffer via next RBD in circular buffer */ - rxq->bd[rxq->write] = iwlagn_dma_addr2rbd_ptr(priv, - rxb->page_dma); - rxq->queue[rxq->write] = rxb; - rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; - rxq->free_count--; - } - spin_unlock_irqrestore(&rxq->lock, flags); - /* If the pre-allocated buffer pool is dropping low, schedule to - * refill it */ - if (rxq->free_count <= RX_LOW_WATERMARK) - queue_work(priv->workqueue, &priv->rx_replenish); - - - /* If we've added more space for the firmware to place data, tell it. - * Increment device's write pointer in multiples of 8. */ - if (rxq->write_actual != (rxq->write & ~0x7)) { - spin_lock_irqsave(&rxq->lock, flags); - rxq->need_update = 1; - spin_unlock_irqrestore(&rxq->lock, flags); - iwl_rx_queue_update_write_ptr(priv, rxq); - } -} - -/** - * iwlagn_rx_replenish - Move all used packet from rx_used to rx_free - * - * When moving to rx_free an SKB is allocated for the slot. - * - * Also restock the Rx queue via iwl_rx_queue_restock. - * This is called as a scheduled work item (except for during initialization) - */ -static void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - struct list_head *element; - struct iwl_rx_mem_buffer *rxb; - struct page *page; - unsigned long flags; - gfp_t gfp_mask = priority; - - while (1) { - spin_lock_irqsave(&rxq->lock, flags); - if (list_empty(&rxq->rx_used)) { - spin_unlock_irqrestore(&rxq->lock, flags); - return; - } - spin_unlock_irqrestore(&rxq->lock, flags); - - if (rxq->free_count > RX_LOW_WATERMARK) - gfp_mask |= __GFP_NOWARN; - - if (priv->hw_params.rx_page_order > 0) - gfp_mask |= __GFP_COMP; - - /* Alloc a new receive buffer */ - page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); - if (!page) { - if (net_ratelimit()) - IWL_DEBUG_INFO(priv, "alloc_pages failed, " - "order: %d\n", - priv->hw_params.rx_page_order); - - if ((rxq->free_count <= RX_LOW_WATERMARK) && - net_ratelimit()) - IWL_CRIT(priv, "Failed to alloc_pages with %s." - "Only %u free buffers remaining.\n", - priority == GFP_ATOMIC ? - "GFP_ATOMIC" : "GFP_KERNEL", - rxq->free_count); - /* We don't reschedule replenish work here -- we will - * call the restock method and if it still needs - * more buffers it will schedule replenish */ - return; - } - - spin_lock_irqsave(&rxq->lock, flags); - - if (list_empty(&rxq->rx_used)) { - spin_unlock_irqrestore(&rxq->lock, flags); - __free_pages(page, priv->hw_params.rx_page_order); - return; - } - element = rxq->rx_used.next; - rxb = list_entry(element, struct iwl_rx_mem_buffer, list); - list_del(element); - - spin_unlock_irqrestore(&rxq->lock, flags); - - BUG_ON(rxb->page); - rxb->page = page; - /* Get physical address of the RB */ - rxb->page_dma = dma_map_page(priv->bus->dev, page, 0, - PAGE_SIZE << priv->hw_params.rx_page_order, - DMA_FROM_DEVICE); - /* dma address must be no more than 36 bits */ - BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36)); - /* and also 256 byte aligned! */ - BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); - - spin_lock_irqsave(&rxq->lock, flags); - - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - - spin_unlock_irqrestore(&rxq->lock, flags); - } -} - -void iwlagn_rx_replenish(struct iwl_priv *priv) -{ - unsigned long flags; - - iwlagn_rx_allocate(priv, GFP_KERNEL); - - spin_lock_irqsave(&priv->lock, flags); - iwlagn_rx_queue_restock(priv); - spin_unlock_irqrestore(&priv->lock, flags); -} - -static void iwlagn_rx_replenish_now(struct iwl_priv *priv) -{ - iwlagn_rx_allocate(priv, GFP_ATOMIC); - - iwlagn_rx_queue_restock(priv); -} - -void iwl_bg_rx_replenish(struct work_struct *data) -{ - struct iwl_priv *priv = - container_of(data, struct iwl_priv, rx_replenish); - - if (test_bit(STATUS_EXIT_PENDING, &priv->status)) - return; - - mutex_lock(&priv->mutex); - iwlagn_rx_replenish(priv); - mutex_unlock(&priv->mutex); -} - -/** - * iwl_rx_handle - Main entry function for receiving responses from uCode - * - * Uses the priv->rx_handlers callback function array to invoke - * the appropriate handlers, including command responses, - * frame-received notifications, and other notifications. - */ -static void iwl_rx_handle(struct iwl_priv *priv) -{ - struct iwl_rx_mem_buffer *rxb; - struct iwl_rx_packet *pkt; - struct iwl_rx_queue *rxq = &priv->rxq; - u32 r, i; - int reclaim; - unsigned long flags; - u8 fill_rx = 0; - u32 count = 8; - int total_empty; - - /* uCode's read index (stored in shared DRAM) indicates the last Rx - * buffer that the driver may process (last buffer filled by ucode). */ - r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; - i = rxq->read; - - /* Rx interrupt, but nothing sent from uCode */ - if (i == r) - IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); - - /* calculate total frames need to be restock after handling RX */ - total_empty = r - rxq->write_actual; - if (total_empty < 0) - total_empty += RX_QUEUE_SIZE; - - if (total_empty > (RX_QUEUE_SIZE / 2)) - fill_rx = 1; - - while (i != r) { - int len; - - rxb = rxq->queue[i]; - - /* If an RXB doesn't have a Rx queue slot associated with it, - * then a bug has been introduced in the queue refilling - * routines -- catch it here */ - if (WARN_ON(rxb == NULL)) { - i = (i + 1) & RX_QUEUE_MASK; - continue; - } - - rxq->queue[i] = NULL; - - dma_unmap_page(priv->bus->dev, rxb->page_dma, - PAGE_SIZE << priv->hw_params.rx_page_order, - DMA_FROM_DEVICE); - pkt = rxb_addr(rxb); - - IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, - i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); - - len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK; - len += sizeof(u32); /* account for status word */ - trace_iwlwifi_dev_rx(priv, pkt, len); - - /* Reclaim a command buffer only if this packet is a response - * to a (driver-originated) command. - * If the packet (e.g. Rx frame) originated from uCode, - * there is no command buffer to reclaim. - * Ucode should set SEQ_RX_FRAME bit if ucode-originated, - * but apparently a few don't get set; catch them here. */ - reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && - (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && - (pkt->hdr.cmd != REPLY_RX) && - (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && - (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && - (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && - (pkt->hdr.cmd != REPLY_TX); - - iwl_rx_dispatch(priv, rxb); - - /* - * XXX: After here, we should always check rxb->page - * against NULL before touching it or its virtual - * memory (pkt). Because some rx_handler might have - * already taken or freed the pages. - */ - - if (reclaim) { - /* Invoke any callbacks, transfer the buffer to caller, - * and fire off the (possibly) blocking - * trans_send_cmd() - * as we reclaim the driver command queue */ - if (rxb->page) - iwl_tx_cmd_complete(priv, rxb); - else - IWL_WARN(priv, "Claim null rxb?\n"); - } - - /* Reuse the page if possible. For notification packets and - * SKBs that fail to Rx correctly, add them back into the - * rx_free list for reuse later. */ - spin_lock_irqsave(&rxq->lock, flags); - if (rxb->page != NULL) { - rxb->page_dma = dma_map_page(priv->bus->dev, rxb->page, - 0, PAGE_SIZE << priv->hw_params.rx_page_order, - DMA_FROM_DEVICE); - list_add_tail(&rxb->list, &rxq->rx_free); - rxq->free_count++; - } else - list_add_tail(&rxb->list, &rxq->rx_used); - - spin_unlock_irqrestore(&rxq->lock, flags); - - i = (i + 1) & RX_QUEUE_MASK; - /* If there are a lot of unused frames, - * restock the Rx queue so ucode wont assert. */ - if (fill_rx) { - count++; - if (count >= 8) { - rxq->read = i; - iwlagn_rx_replenish_now(priv); - count = 0; - } - } - } - - /* Backtrack one entry */ - rxq->read = i; - if (fill_rx) - iwlagn_rx_replenish_now(priv); - else - iwlagn_rx_queue_restock(priv); -} - -/* tasklet for iwlagn interrupt */ -void iwl_irq_tasklet(struct iwl_priv *priv) -{ - u32 inta = 0; - u32 handled = 0; - unsigned long flags; - u32 i; -#ifdef CONFIG_IWLWIFI_DEBUG - u32 inta_mask; -#endif - - spin_lock_irqsave(&priv->lock, flags); - - /* Ack/clear/reset pending uCode interrupts. - * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, - */ - /* There is a hardware bug in the interrupt mask function that some - * interrupts (i.e. CSR_INT_BIT_SCD) can still be generated even if - * they are disabled in the CSR_INT_MASK register. Furthermore the - * ICT interrupt handling mechanism has another bug that might cause - * these unmasked interrupts fail to be detected. We workaround the - * hardware bugs here by ACKing all the possible interrupts so that - * interrupt coalescing can still be achieved. - */ - iwl_write32(priv, CSR_INT, priv->inta | ~priv->inta_mask); - - inta = priv->inta; - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & IWL_DL_ISR) { - /* just for debug */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); - IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x\n ", - inta, inta_mask); - } -#endif - - spin_unlock_irqrestore(&priv->lock, flags); - - /* saved interrupt in inta variable now we can reset priv->inta */ - priv->inta = 0; - - /* Now service all interrupt bits discovered above. */ - if (inta & CSR_INT_BIT_HW_ERR) { - IWL_ERR(priv, "Hardware error detected. Restarting.\n"); - - /* Tell the device to stop sending interrupts */ - iwl_disable_interrupts(priv); - - priv->isr_stats.hw++; - iwl_irq_handle_error(priv); - - handled |= CSR_INT_BIT_HW_ERR; - - return; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - /* NIC fires this, but we don't use it, redundant with WAKEUP */ - if (inta & CSR_INT_BIT_SCD) { - IWL_DEBUG_ISR(priv, "Scheduler finished to transmit " - "the frame/frames.\n"); - priv->isr_stats.sch++; - } - - /* Alive notification via Rx interrupt will do the real work */ - if (inta & CSR_INT_BIT_ALIVE) { - IWL_DEBUG_ISR(priv, "Alive interrupt\n"); - priv->isr_stats.alive++; - } - } -#endif - /* Safely ignore these bits for debug checks below */ - inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - - /* HW RF KILL switch toggled */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_WARN(priv, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio" : "enable radio"); - - priv->isr_stats.rfkill++; - - /* driver only loads ucode once setting the interface up. - * the driver allows loading the ucode even if the radio - * is killed. Hence update the killswitch state here. The - * rfkill handler will care about restarting if needed. - */ - if (!test_bit(STATUS_ALIVE, &priv->status)) { - if (hw_rf_kill) - set_bit(STATUS_RF_KILL_HW, &priv->status); - else - clear_bit(STATUS_RF_KILL_HW, &priv->status); - wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rf_kill); - } - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERR(priv, "Microcode CT kill error detected.\n"); - priv->isr_stats.ctkill++; - handled |= CSR_INT_BIT_CT_KILL; - } - - /* Error detected by uCode */ - if (inta & CSR_INT_BIT_SW_ERR) { - IWL_ERR(priv, "Microcode SW error detected. " - " Restarting 0x%X.\n", inta); - priv->isr_stats.sw++; - iwl_irq_handle_error(priv); - handled |= CSR_INT_BIT_SW_ERR; - } - - /* uCode wakes up after power-down sleep */ - if (inta & CSR_INT_BIT_WAKEUP) { - IWL_DEBUG_ISR(priv, "Wakeup interrupt\n"); - iwl_rx_queue_update_write_ptr(priv, &priv->rxq); - for (i = 0; i < priv->hw_params.max_txq_num; i++) - iwl_txq_update_write_ptr(priv, &priv->txq[i]); - - priv->isr_stats.wakeup++; - - handled |= CSR_INT_BIT_WAKEUP; - } - - /* All uCode command responses, including Tx command responses, - * Rx "responses" (frame-received notification), and other - * notifications from uCode come through here*/ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX | - CSR_INT_BIT_RX_PERIODIC)) { - IWL_DEBUG_ISR(priv, "Rx interrupt\n"); - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { - handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); - iwl_write32(priv, CSR_FH_INT_STATUS, - CSR_FH_INT_RX_MASK); - } - if (inta & CSR_INT_BIT_RX_PERIODIC) { - handled |= CSR_INT_BIT_RX_PERIODIC; - iwl_write32(priv, CSR_INT, CSR_INT_BIT_RX_PERIODIC); - } - /* Sending RX interrupt require many steps to be done in the - * the device: - * 1- write interrupt to current index in ICT table. - * 2- dma RX frame. - * 3- update RX shared data to indicate last write index. - * 4- send interrupt. - * This could lead to RX race, driver could receive RX interrupt - * but the shared data changes does not reflect this; - * periodic interrupt will detect any dangling Rx activity. - */ - - /* Disable periodic interrupt; we use it as just a one-shot. */ - iwl_write8(priv, CSR_INT_PERIODIC_REG, - CSR_INT_PERIODIC_DIS); - iwl_rx_handle(priv); - - /* - * Enable periodic interrupt in 8 msec only if we received - * real RX interrupt (instead of just periodic int), to catch - * any dangling Rx interrupt. If it was just the periodic - * interrupt, there was no dangling Rx activity, and no need - * to extend the periodic interrupt; one-shot is enough. - */ - if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) - iwl_write8(priv, CSR_INT_PERIODIC_REG, - CSR_INT_PERIODIC_ENA); - - priv->isr_stats.rx++; - } - - /* This "Tx" DMA channel is used only for loading uCode */ - if (inta & CSR_INT_BIT_FH_TX) { - iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); - IWL_DEBUG_ISR(priv, "uCode load interrupt\n"); - priv->isr_stats.tx++; - handled |= CSR_INT_BIT_FH_TX; - /* Wake up uCode load routine, now that load is complete */ - priv->ucode_write_complete = 1; - wake_up_interruptible(&priv->wait_command_queue); - } - - if (inta & ~handled) { - IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled); - priv->isr_stats.unhandled++; - } - - if (inta & ~(priv->inta_mask)) { - IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n", - inta & ~priv->inta_mask); - } - - /* Re-enable all interrupts */ - /* only Re-enable if disabled by irq */ - if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl_enable_interrupts(priv); - /* Re-enable RF_KILL if it occurred */ - else if (handled & CSR_INT_BIT_RF_KILL) - iwl_enable_rfkill_int(priv); -} - -/****************************************************************************** - * - * ICT functions - * - ******************************************************************************/ -#define ICT_COUNT (PAGE_SIZE/sizeof(u32)) - -/* Free dram table */ -void iwl_free_isr_ict(struct iwl_priv *priv) -{ - if (priv->ict_tbl_vir) { - dma_free_coherent(priv->bus->dev, - (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, - priv->ict_tbl_vir, - priv->ict_tbl_dma); - priv->ict_tbl_vir = NULL; - memset(&priv->ict_tbl_dma, 0, - sizeof(priv->ict_tbl_dma)); - memset(&priv->aligned_ict_tbl_dma, 0, - sizeof(priv->aligned_ict_tbl_dma)); - } -} - - -/* allocate dram shared table it is a PAGE_SIZE aligned - * also reset all data related to ICT table interrupt. - */ -int iwl_alloc_isr_ict(struct iwl_priv *priv) -{ - - /* allocate shrared data table */ - priv->ict_tbl_vir = - dma_alloc_coherent(priv->bus->dev, - (sizeof(u32) * ICT_COUNT) + PAGE_SIZE, - &priv->ict_tbl_dma, GFP_KERNEL); - if (!priv->ict_tbl_vir) - return -ENOMEM; - - /* align table to PAGE_SIZE boundary */ - priv->aligned_ict_tbl_dma = - ALIGN(priv->ict_tbl_dma, PAGE_SIZE); - - IWL_DEBUG_ISR(priv, "ict dma addr %Lx dma aligned %Lx diff %d\n", - (unsigned long long)priv->ict_tbl_dma, - (unsigned long long)priv->aligned_ict_tbl_dma, - (int)(priv->aligned_ict_tbl_dma - - priv->ict_tbl_dma)); - - priv->ict_tbl = priv->ict_tbl_vir + - (priv->aligned_ict_tbl_dma - - priv->ict_tbl_dma); - - IWL_DEBUG_ISR(priv, "ict vir addr %p vir aligned %p diff %d\n", - priv->ict_tbl, priv->ict_tbl_vir, - (int)(priv->aligned_ict_tbl_dma - - priv->ict_tbl_dma)); - - /* reset table and index to all 0 */ - memset(priv->ict_tbl_vir, 0, - (sizeof(u32) * ICT_COUNT) + PAGE_SIZE); - priv->ict_index = 0; - - /* add periodic RX interrupt */ - priv->inta_mask |= CSR_INT_BIT_RX_PERIODIC; - return 0; -} - -/* Device is going up inform it about using ICT interrupt table, - * also we need to tell the driver to start using ICT interrupt. - */ -int iwl_reset_ict(struct iwl_priv *priv) -{ - u32 val; - unsigned long flags; - - if (!priv->ict_tbl_vir) - return 0; - - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - - memset(&priv->ict_tbl[0], 0, sizeof(u32) * ICT_COUNT); - - val = priv->aligned_ict_tbl_dma >> PAGE_SHIFT; - - val |= CSR_DRAM_INT_TBL_ENABLE; - val |= CSR_DRAM_INIT_TBL_WRAP_CHECK; - - IWL_DEBUG_ISR(priv, "CSR_DRAM_INT_TBL_REG =0x%X " - "aligned dma address %Lx\n", - val, - (unsigned long long)priv->aligned_ict_tbl_dma); - - iwl_write32(priv, CSR_DRAM_INT_TBL_REG, val); - priv->use_ict = true; - priv->ict_index = 0; - iwl_write32(priv, CSR_INT, priv->inta_mask); - iwl_enable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -/* Device is going down disable ict interrupt usage */ -void iwl_disable_ict(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - priv->use_ict = false; - spin_unlock_irqrestore(&priv->lock, flags); -} - -static irqreturn_t iwl_isr(int irq, void *data) -{ - struct iwl_priv *priv = data; - u32 inta, inta_mask; - unsigned long flags; -#ifdef CONFIG_IWLWIFI_DEBUG - u32 inta_fh; -#endif - if (!priv) - return IRQ_NONE; - - spin_lock_irqsave(&priv->lock, flags); - - /* Disable (but don't clear!) interrupts here to avoid - * back-to-back ISRs and sporadic interrupts from our NIC. - * If we have something to service, the tasklet will re-enable ints. - * If we *don't* have something, we'll re-enable before leaving here. */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* Discover which interrupts are active/pending */ - inta = iwl_read32(priv, CSR_INT); - - /* Ignore interrupt if there's nothing in NIC to service. - * This may be due to IRQ shared with another device, - * or due to sporadic interrupts thrown from our NIC. */ - if (!inta) { - IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); - goto none; - } - - if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { - /* Hardware disappeared. It might have already raised - * an interrupt */ - IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta); - goto unplugged; - } - -#ifdef CONFIG_IWLWIFI_DEBUG - if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) { - inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS); - IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, " - "fh 0x%08x\n", inta, inta_mask, inta_fh); - } -#endif - - priv->inta |= inta; - /* iwl_irq_tasklet() will service interrupts and re-enable them */ - if (likely(inta)) - tasklet_schedule(&priv->irq_tasklet); - else if (test_bit(STATUS_INT_ENABLED, &priv->status) && - !priv->inta) - iwl_enable_interrupts(priv); - - unplugged: - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_HANDLED; - - none: - /* re-enable interrupts here since we don't have anything to service. */ - /* only Re-enable if disabled by irq and no schedules tasklet. */ - if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) - iwl_enable_interrupts(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_NONE; -} - -/* interrupt handler using ict table, with this interrupt driver will - * stop using INTA register to get device's interrupt, reading this register - * is expensive, device will write interrupts in ICT dram table, increment - * index then will fire interrupt to driver, driver will OR all ICT table - * entries from current index up to table entry with 0 value. the result is - * the interrupt we need to service, driver will set the entries back to 0 and - * set index. - */ -irqreturn_t iwl_isr_ict(int irq, void *data) -{ - struct iwl_priv *priv = data; - u32 inta, inta_mask; - u32 val = 0; - unsigned long flags; - - if (!priv) - return IRQ_NONE; - - /* dram interrupt table not set yet, - * use legacy interrupt. - */ - if (!priv->use_ict) - return iwl_isr(irq, data); - - spin_lock_irqsave(&priv->lock, flags); - - /* Disable (but don't clear!) interrupts here to avoid - * back-to-back ISRs and sporadic interrupts from our NIC. - * If we have something to service, the tasklet will re-enable ints. - * If we *don't* have something, we'll re-enable before leaving here. - */ - inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - - /* Ignore interrupt if there's nothing in NIC to service. - * This may be due to IRQ shared with another device, - * or due to sporadic interrupts thrown from our NIC. */ - if (!priv->ict_tbl[priv->ict_index]) { - IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0\n"); - goto none; - } - - /* read all entries that not 0 start with ict_index */ - while (priv->ict_tbl[priv->ict_index]) { - - val |= le32_to_cpu(priv->ict_tbl[priv->ict_index]); - IWL_DEBUG_ISR(priv, "ICT index %d value 0x%08X\n", - priv->ict_index, - le32_to_cpu( - priv->ict_tbl[priv->ict_index])); - priv->ict_tbl[priv->ict_index] = 0; - priv->ict_index = iwl_queue_inc_wrap(priv->ict_index, - ICT_COUNT); - - } - - /* We should not get this value, just ignore it. */ - if (val == 0xffffffff) - val = 0; - - /* - * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit - * (bit 15 before shifting it to 31) to clear when using interrupt - * coalescing. fortunately, bits 18 and 19 stay set when this happens - * so we use them to decide on the real state of the Rx bit. - * In order words, bit 15 is set if bit 18 or bit 19 are set. - */ - if (val & 0xC0000) - val |= 0x8000; - - inta = (0xff & val) | ((0xff00 & val) << 16); - IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x ict 0x%08x\n", - inta, inta_mask, val); - - inta &= priv->inta_mask; - priv->inta |= inta; - - /* iwl_irq_tasklet() will service interrupts and re-enable them */ - if (likely(inta)) - tasklet_schedule(&priv->irq_tasklet); - else if (test_bit(STATUS_INT_ENABLED, &priv->status) && - !priv->inta) { - /* Allow interrupt if was disabled by this handler and - * no tasklet was schedules, We should not enable interrupt, - * tasklet will enable it. - */ - iwl_enable_interrupts(priv); - } - - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_HANDLED; - - none: - /* re-enable interrupts here since we don't have anything to service. - * only Re-enable if disabled by irq. - */ - if (test_bit(STATUS_INT_ENABLED, &priv->status) && !priv->inta) - iwl_enable_interrupts(priv); - - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_NONE; -} diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c index 41f0de914008..1b20c4fb791b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans.c @@ -60,1113 +60,18 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ -#include "iwl-dev.h" -#include "iwl-trans.h" -#include "iwl-core.h" -#include "iwl-helpers.h" -#include "iwl-trans-int-pcie.h" -/*TODO remove uneeded includes when the transport layer tx_free will be here */ -#include "iwl-agn.h" -#include "iwl-core.h" - -static int iwl_trans_rx_alloc(struct iwl_priv *priv) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - struct device *dev = priv->bus->dev; - - memset(&priv->rxq, 0, sizeof(priv->rxq)); - - spin_lock_init(&rxq->lock); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - - if (WARN_ON(rxq->bd || rxq->rb_stts)) - return -EINVAL; - - /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */ - rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, - &rxq->bd_dma, GFP_KERNEL); - if (!rxq->bd) - goto err_bd; - memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE); - - /*Allocate the driver's pointer to receive buffer status */ - rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts), - &rxq->rb_stts_dma, GFP_KERNEL); - if (!rxq->rb_stts) - goto err_rb_stts; - memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); - - return 0; - -err_rb_stts: - dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, - rxq->bd, rxq->bd_dma); - memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); - rxq->bd = NULL; -err_bd: - return -ENOMEM; -} - -static void iwl_trans_rxq_free_rx_bufs(struct iwl_priv *priv) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - int i; - - /* Fill the rx_used queue with _all_ of the Rx buffers */ - for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { - /* In the reset function, these buffers may have been allocated - * to an SKB, so we need to unmap and free potential storage */ - if (rxq->pool[i].page != NULL) { - dma_unmap_page(priv->bus->dev, rxq->pool[i].page_dma, - PAGE_SIZE << priv->hw_params.rx_page_order, - DMA_FROM_DEVICE); - __iwl_free_pages(priv, rxq->pool[i].page); - rxq->pool[i].page = NULL; - } - list_add_tail(&rxq->pool[i].list, &rxq->rx_used); - } -} - -static void iwl_trans_rx_hw_init(struct iwl_priv *priv, - struct iwl_rx_queue *rxq) -{ - u32 rb_size; - const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */ - u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */ - - rb_timeout = RX_RB_TIMEOUT; - - if (iwlagn_mod_params.amsdu_size_8K) - rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K; - else - rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K; - - /* Stop Rx DMA */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - - /* Reset driver's Rx queue write index */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); - - /* Tell device where to find RBD circular buffer in DRAM */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG, - (u32)(rxq->bd_dma >> 8)); - - /* Tell device where in DRAM to update its Rx status */ - iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, - rxq->rb_stts_dma >> 4); - - /* Enable Rx DMA - * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in - * the credit mechanism in 5000 HW RX FIFO - * Direct rx interrupts to hosts - * Rx buffer size 4 or 8k - * RB timeout 0x10 - * 256 RBDs - */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | - FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | - FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | - rb_size| - (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| - (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); - - /* Set interrupt coalescing timer to default (2048 usecs) */ - iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); -} - -static int iwl_rx_init(struct iwl_priv *priv) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - int i, err; - unsigned long flags; - - if (!rxq->bd) { - err = iwl_trans_rx_alloc(priv); - if (err) - return err; - } - - spin_lock_irqsave(&rxq->lock, flags); - INIT_LIST_HEAD(&rxq->rx_free); - INIT_LIST_HEAD(&rxq->rx_used); - - iwl_trans_rxq_free_rx_bufs(priv); - - for (i = 0; i < RX_QUEUE_SIZE; i++) - rxq->queue[i] = NULL; - - /* Set us so that we have processed and used all buffers, but have - * not restocked the Rx queue with fresh buffers */ - rxq->read = rxq->write = 0; - rxq->write_actual = 0; - rxq->free_count = 0; - spin_unlock_irqrestore(&rxq->lock, flags); - - iwlagn_rx_replenish(priv); - - iwl_trans_rx_hw_init(priv, rxq); - - spin_lock_irqsave(&priv->lock, flags); - rxq->need_update = 1; - iwl_rx_queue_update_write_ptr(priv, rxq); - spin_unlock_irqrestore(&priv->lock, flags); - - return 0; -} - -static void iwl_trans_rx_free(struct iwl_priv *priv) -{ - struct iwl_rx_queue *rxq = &priv->rxq; - unsigned long flags; - - /*if rxq->bd is NULL, it means that nothing has been allocated, - * exit now */ - if (!rxq->bd) { - IWL_DEBUG_INFO(priv, "Free NULL rx context\n"); - return; - } - - spin_lock_irqsave(&rxq->lock, flags); - iwl_trans_rxq_free_rx_bufs(priv); - spin_unlock_irqrestore(&rxq->lock, flags); - - dma_free_coherent(priv->bus->dev, sizeof(__le32) * RX_QUEUE_SIZE, - rxq->bd, rxq->bd_dma); - memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); - rxq->bd = NULL; - - if (rxq->rb_stts) - dma_free_coherent(priv->bus->dev, - sizeof(struct iwl_rb_status), - rxq->rb_stts, rxq->rb_stts_dma); - else - IWL_DEBUG_INFO(priv, "Free rxq->rb_stts which is NULL\n"); - memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma)); - rxq->rb_stts = NULL; -} - -static int iwl_trans_rx_stop(struct iwl_priv *priv) -{ - - /* stop Rx DMA */ - iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - return iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, - FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); -} - -static inline int iwlagn_alloc_dma_ptr(struct iwl_priv *priv, - struct iwl_dma_ptr *ptr, size_t size) -{ - if (WARN_ON(ptr->addr)) - return -EINVAL; - - ptr->addr = dma_alloc_coherent(priv->bus->dev, size, - &ptr->dma, GFP_KERNEL); - if (!ptr->addr) - return -ENOMEM; - ptr->size = size; - return 0; -} - -static inline void iwlagn_free_dma_ptr(struct iwl_priv *priv, - struct iwl_dma_ptr *ptr) -{ - if (unlikely(!ptr->addr)) - return; - - dma_free_coherent(priv->bus->dev, ptr->size, ptr->addr, ptr->dma); - memset(ptr, 0, sizeof(*ptr)); -} - -static int iwl_trans_txq_alloc(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int slots_num, u32 txq_id) -{ - size_t tfd_sz = priv->hw_params.tfd_size * TFD_QUEUE_SIZE_MAX; - int i; - - if (WARN_ON(txq->meta || txq->cmd || txq->txb || txq->tfds)) - return -EINVAL; - - txq->q.n_window = slots_num; - - txq->meta = kzalloc(sizeof(txq->meta[0]) * slots_num, - GFP_KERNEL); - txq->cmd = kzalloc(sizeof(txq->cmd[0]) * slots_num, - GFP_KERNEL); - - if (!txq->meta || !txq->cmd) - goto error; - - for (i = 0; i < slots_num; i++) { - txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd), - GFP_KERNEL); - if (!txq->cmd[i]) - goto error; - } - - /* Alloc driver data array and TFD circular buffer */ - /* Driver private data, only for Tx (not command) queues, - * not shared with device. */ - if (txq_id != priv->cmd_queue) { - txq->txb = kzalloc(sizeof(txq->txb[0]) * - TFD_QUEUE_SIZE_MAX, GFP_KERNEL); - if (!txq->txb) { - IWL_ERR(priv, "kmalloc for auxiliary BD " - "structures failed\n"); - goto error; - } - } else { - txq->txb = NULL; - } - - /* Circular buffer of transmit frame descriptors (TFDs), - * shared with device */ - txq->tfds = dma_alloc_coherent(priv->bus->dev, tfd_sz, &txq->q.dma_addr, - GFP_KERNEL); - if (!txq->tfds) { - IWL_ERR(priv, "dma_alloc_coherent(%zd) failed\n", tfd_sz); - goto error; - } - txq->q.id = txq_id; - - return 0; -error: - kfree(txq->txb); - txq->txb = NULL; - /* since txq->cmd has been zeroed, - * all non allocated cmd[i] will be NULL */ - if (txq->cmd) - for (i = 0; i < slots_num; i++) - kfree(txq->cmd[i]); - kfree(txq->meta); - kfree(txq->cmd); - txq->meta = NULL; - txq->cmd = NULL; - - return -ENOMEM; - -} - -static int iwl_trans_txq_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, - int slots_num, u32 txq_id) -{ - int ret; - - txq->need_update = 0; - memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num); - - /* - * For the default queues 0-3, set up the swq_id - * already -- all others need to get one later - * (if they need one at all). - */ - if (txq_id < 4) - iwl_set_swq_id(txq, txq_id, txq_id); - - /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise - * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */ - BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1)); - - /* Initialize queue's high/low-water marks, and head/tail indexes */ - ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, - txq_id); - if (ret) - return ret; - - /* - * Tell nic where to find circular buffer of Tx Frame Descriptors for - * given Tx queue, and enable the DMA channel used for that queue. - * Circular buffer (TFD queue in DRAM) physical base address */ - iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), - txq->q.dma_addr >> 8); - - return 0; -} - -/** - * iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's - */ -static void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id) -{ - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; - - if (!q->n_bd) - return; - - while (q->write_ptr != q->read_ptr) { - /* The read_ptr needs to bound by q->n_window */ - iwlagn_txq_free_tfd(priv, txq, get_cmd_index(q, q->read_ptr)); - q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); - } -} - -/** - * iwl_tx_queue_free - Deallocate DMA queue. - * @txq: Transmit queue to deallocate. - * - * Empty queue by removing and destroying all BD's. - * Free all buffers. - * 0-fill, but do not free "txq" descriptor structure. - */ -static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) -{ - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct device *dev = priv->bus->dev; - int i; - if (WARN_ON(!txq)) - return; - - iwl_tx_queue_unmap(priv, txq_id); - - /* De-alloc array of command/tx buffers */ - for (i = 0; i < txq->q.n_window; i++) - kfree(txq->cmd[i]); - - /* De-alloc circular buffer of TFDs */ - if (txq->q.n_bd) { - dma_free_coherent(dev, priv->hw_params.tfd_size * - txq->q.n_bd, txq->tfds, txq->q.dma_addr); - memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr)); - } - - /* De-alloc array of per-TFD driver data */ - kfree(txq->txb); - txq->txb = NULL; - - /* deallocate arrays */ - kfree(txq->cmd); - kfree(txq->meta); - txq->cmd = NULL; - txq->meta = NULL; - - /* 0-fill queue descriptor structure */ - memset(txq, 0, sizeof(*txq)); -} - -/** - * iwl_trans_tx_free - Free TXQ Context - * - * Destroy all TX DMA queues and structures - */ -static void iwl_trans_tx_free(struct iwl_priv *priv) -{ - int txq_id; - - /* Tx queues */ - if (priv->txq) { - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl_tx_queue_free(priv, txq_id); - } - - kfree(priv->txq); - priv->txq = NULL; - - iwlagn_free_dma_ptr(priv, &priv->kw); - - iwlagn_free_dma_ptr(priv, &priv->scd_bc_tbls); -} - -/** - * iwl_trans_tx_alloc - allocate TX context - * Allocate all Tx DMA structures and initialize them - * - * @param priv - * @return error code - */ -static int iwl_trans_tx_alloc(struct iwl_priv *priv) -{ - int ret; - int txq_id, slots_num; - - /*It is not allowed to alloc twice, so warn when this happens. - * We cannot rely on the previous allocation, so free and fail */ - if (WARN_ON(priv->txq)) { - ret = -EINVAL; - goto error; - } - - ret = iwlagn_alloc_dma_ptr(priv, &priv->scd_bc_tbls, - priv->hw_params.scd_bc_tbls_size); - if (ret) { - IWL_ERR(priv, "Scheduler BC Table allocation failed\n"); - goto error; - } - - /* Alloc keep-warm buffer */ - ret = iwlagn_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE); - if (ret) { - IWL_ERR(priv, "Keep Warm allocation failed\n"); - goto error; - } - - priv->txq = kzalloc(sizeof(struct iwl_tx_queue) * - priv->cfg->base_params->num_of_queues, GFP_KERNEL); - if (!priv->txq) { - IWL_ERR(priv, "Not enough memory for txq\n"); - ret = ENOMEM; - goto error; - } - - /* Alloc and init all Tx queues, including the command queue (#4/#9) */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - slots_num = (txq_id == priv->cmd_queue) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_trans_txq_alloc(priv, &priv->txq[txq_id], slots_num, - txq_id); - if (ret) { - IWL_ERR(priv, "Tx %d queue alloc failed\n", txq_id); - goto error; - } - } - - return 0; - -error: - trans_tx_free(&priv->trans); - - return ret; -} -static int iwl_tx_init(struct iwl_priv *priv) -{ - int ret; - int txq_id, slots_num; - unsigned long flags; - bool alloc = false; - - if (!priv->txq) { - ret = iwl_trans_tx_alloc(priv); - if (ret) - goto error; - alloc = true; - } - - spin_lock_irqsave(&priv->lock, flags); - - /* Turn off all Tx DMA fifos */ - iwl_write_prph(priv, SCD_TXFACT, 0); - - /* Tell NIC where to find the "keep warm" buffer */ - iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Alloc and init all Tx queues, including the command queue (#4/#9) */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - slots_num = (txq_id == priv->cmd_queue) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - ret = iwl_trans_txq_init(priv, &priv->txq[txq_id], slots_num, - txq_id); - if (ret) { - IWL_ERR(priv, "Tx %d queue init failed\n", txq_id); - goto error; - } - } - - return 0; -error: - /*Upon error, free only if we allocated something */ - if (alloc) - trans_tx_free(&priv->trans); - return ret; -} - -static void iwl_set_pwr_vmain(struct iwl_priv *priv) -{ -/* - * (for documentation purposes) - * to set power to V_AUX, do: - - if (pci_pme_capable(priv->pci_dev, PCI_D3cold)) - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VAUX, - ~APMG_PS_CTRL_MSK_PWR_SRC); - */ - - iwl_set_bits_mask_prph(priv, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, - ~APMG_PS_CTRL_MSK_PWR_SRC); -} - -static int iwl_nic_init(struct iwl_priv *priv) -{ - unsigned long flags; - - /* nic_init */ - spin_lock_irqsave(&priv->lock, flags); - iwl_apm_init(priv); - - /* Set interrupt coalescing calibration timer to default (512 usecs) */ - iwl_write8(priv, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF); - - spin_unlock_irqrestore(&priv->lock, flags); - iwl_set_pwr_vmain(priv); - - priv->cfg->lib->nic_config(priv); - - /* Allocate the RX queue, or reset if it is already allocated */ - iwl_rx_init(priv); - - /* Allocate or reset and init all Tx and Command queues */ - if (iwl_tx_init(priv)) - return -ENOMEM; - - if (priv->cfg->base_params->shadow_reg_enable) { - /* enable shadow regs in HW */ - iwl_set_bit(priv, CSR_MAC_SHADOW_REG_CTRL, - 0x800FFFFF); - } - - set_bit(STATUS_INIT, &priv->status); - - return 0; -} - -#define HW_READY_TIMEOUT (50) - -/* Note: returns poll_bit return value, which is >= 0 if success */ -static int iwl_set_hw_ready(struct iwl_priv *priv) -{ - int ret; - - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_NIC_READY); - - /* See if we got it */ - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, - CSR_HW_IF_CONFIG_REG_BIT_NIC_READY, - HW_READY_TIMEOUT); - - IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : ""); - return ret; -} - -/* Note: returns standard 0/-ERROR code */ -static int iwl_trans_prepare_card_hw(struct iwl_priv *priv) -{ - int ret; - - IWL_DEBUG_INFO(priv, "iwl_trans_prepare_card_hw enter\n"); - - ret = iwl_set_hw_ready(priv); - if (ret >= 0) - return 0; - - /* If HW is not ready, prepare the conditions to check again */ - iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_PREPARE); - - ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG, - ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, - CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000); - - if (ret < 0) - return ret; - - /* HW should be ready by now, check again. */ - ret = iwl_set_hw_ready(priv); - if (ret >= 0) - return 0; - return ret; -} - -static int iwl_trans_start_device(struct iwl_priv *priv) -{ - int ret; - - priv->ucode_owner = IWL_OWNERSHIP_DRIVER; - - if ((priv->cfg->sku & EEPROM_SKU_CAP_AMT_ENABLE) && - iwl_trans_prepare_card_hw(priv)) { - IWL_WARN(priv, "Exit HW not ready\n"); - return -EIO; - } - - /* If platform's RF_KILL switch is NOT set to KILL */ - if (iwl_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) - clear_bit(STATUS_RF_KILL_HW, &priv->status); - else - set_bit(STATUS_RF_KILL_HW, &priv->status); - - if (iwl_is_rfkill(priv)) { - wiphy_rfkill_set_hw_state(priv->hw->wiphy, true); - iwl_enable_interrupts(priv); - return -ERFKILL; - } - - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - - ret = iwl_nic_init(priv); - if (ret) { - IWL_ERR(priv, "Unable to init nic\n"); - return ret; - } - - /* make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - - /* clear (again), then enable host interrupts */ - iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl_enable_interrupts(priv); - - /* really make sure rfkill handshake bits are cleared */ - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - - return 0; -} - -/* - * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask - * must be called under priv->lock and mac access - */ -static void iwl_trans_txq_set_sched(struct iwl_priv *priv, u32 mask) -{ - iwl_write_prph(priv, SCD_TXFACT, mask); -} - -#define IWL_AC_UNSET -1 - -struct queue_to_fifo_ac { - s8 fifo, ac; -}; - -static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = { - { IWL_TX_FIFO_VO, IEEE80211_AC_VO, }, - { IWL_TX_FIFO_VI, IEEE80211_AC_VI, }, - { IWL_TX_FIFO_BE, IEEE80211_AC_BE, }, - { IWL_TX_FIFO_BK, IEEE80211_AC_BK, }, - { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, - { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, }, -}; - -static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = { - { IWL_TX_FIFO_VO, IEEE80211_AC_VO, }, - { IWL_TX_FIFO_VI, IEEE80211_AC_VI, }, - { IWL_TX_FIFO_BE, IEEE80211_AC_BE, }, - { IWL_TX_FIFO_BK, IEEE80211_AC_BK, }, - { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, }, - { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, }, - { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, }, - { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, }, - { IWL_TX_FIFO_BE_IPAN, 2, }, - { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, }, -}; -static void iwl_trans_tx_start(struct iwl_priv *priv) -{ - const struct queue_to_fifo_ac *queue_to_fifo; - struct iwl_rxon_context *ctx; - u32 a; - unsigned long flags; - int i, chan; - u32 reg_val; - - spin_lock_irqsave(&priv->lock, flags); - - priv->scd_base_addr = iwl_read_prph(priv, SCD_SRAM_BASE_ADDR); - a = priv->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND; - /* reset conext data memory */ - for (; a < priv->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND; - a += 4) - iwl_write_targ_mem(priv, a, 0); - /* reset tx status memory */ - for (; a < priv->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND; - a += 4) - iwl_write_targ_mem(priv, a, 0); - for (; a < priv->scd_base_addr + - SCD_TRANS_TBL_OFFSET_QUEUE(priv->hw_params.max_txq_num); a += 4) - iwl_write_targ_mem(priv, a, 0); - - iwl_write_prph(priv, SCD_DRAM_BASE_ADDR, - priv->scd_bc_tbls.dma >> 10); - - /* Enable DMA channel */ - for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++) - iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); - - /* Update FH chicken bits */ - reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG); - iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG, - reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); - - iwl_write_prph(priv, SCD_QUEUECHAIN_SEL, - SCD_QUEUECHAIN_SEL_ALL(priv)); - iwl_write_prph(priv, SCD_AGGR_SEL, 0); - - /* initiate the queues */ - for (i = 0; i < priv->hw_params.max_txq_num; i++) { - iwl_write_prph(priv, SCD_QUEUE_RDPTR(i), 0); - iwl_write_direct32(priv, HBUS_TARG_WRPTR, 0 | (i << 8)); - iwl_write_targ_mem(priv, priv->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(i), 0); - iwl_write_targ_mem(priv, priv->scd_base_addr + - SCD_CONTEXT_QUEUE_OFFSET(i) + - sizeof(u32), - ((SCD_WIN_SIZE << - SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & - SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | - ((SCD_FRAME_LIMIT << - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & - SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); - } - - iwl_write_prph(priv, SCD_INTERRUPT_MASK, - IWL_MASK(0, priv->hw_params.max_txq_num)); - - /* Activate all Tx DMA/FIFO channels */ - iwl_trans_txq_set_sched(priv, IWL_MASK(0, 7)); - - /* map queues to FIFOs */ - if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)) - queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo; - else - queue_to_fifo = iwlagn_default_queue_to_tx_fifo; - - iwl_trans_set_wr_ptrs(priv, priv->cmd_queue, 0); - - /* make sure all queue are not stopped */ - memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped)); - for (i = 0; i < 4; i++) - atomic_set(&priv->queue_stop_count[i], 0); - for_each_context(priv, ctx) - ctx->last_tx_rejected = false; - - /* reset to 0 to enable all the queue first */ - priv->txq_ctx_active_msk = 0; - - BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) != 10); - BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) != 10); - - for (i = 0; i < 10; i++) { - int fifo = queue_to_fifo[i].fifo; - int ac = queue_to_fifo[i].ac; - - iwl_txq_ctx_activate(priv, i); - - if (fifo == IWL_TX_FIFO_UNUSED) - continue; - - if (ac != IWL_AC_UNSET) - iwl_set_swq_id(&priv->txq[i], ac, i); - iwl_trans_tx_queue_set_status(priv, &priv->txq[i], fifo, 0); - } - - spin_unlock_irqrestore(&priv->lock, flags); - - /* Enable L1-Active */ - iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); -} - -/** - * iwlagn_txq_ctx_stop - Stop all Tx DMA channels - */ -static int iwl_trans_tx_stop(struct iwl_priv *priv) -{ - int ch, txq_id; - unsigned long flags; - - /* Turn off all Tx DMA fifos */ - spin_lock_irqsave(&priv->lock, flags); - - iwl_trans_txq_set_sched(priv, 0); - - /* Stop each Tx DMA channel, and wait for it to be idle */ - for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { - iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); - if (iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), - 1000)) - IWL_ERR(priv, "Failing on timeout while stopping" - " DMA channel %d [0x%08x]", ch, - iwl_read_direct32(priv, FH_TSSR_TX_STATUS_REG)); - } - spin_unlock_irqrestore(&priv->lock, flags); - - if (!priv->txq) { - IWL_WARN(priv, "Stopping tx queues that aren't allocated..."); - return 0; - } - - /* Unmap DMA from host system and free skb's */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl_tx_queue_unmap(priv, txq_id); - - return 0; -} - -static void iwl_trans_stop_device(struct iwl_priv *priv) -{ - unsigned long flags; - - /* stop and reset the on-board processor */ - iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&priv->lock, flags); - iwl_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - trans_sync_irq(&priv->trans); - - /* device going down, Stop using ICT table */ - iwl_disable_ict(priv); - - /* - * If a HW restart happens during firmware loading, - * then the firmware loading might call this function - * and later it might be called again due to the - * restart. So don't process again if the device is - * already dead. - */ - if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) { - iwl_trans_tx_stop(priv); - iwl_trans_rx_stop(priv); - - /* Power-down device's busmaster DMA clocks */ - iwl_write_prph(priv, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); - udelay(5); - } - - /* Make sure (redundant) we've released our request to stay awake */ - iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - - /* Stop the device, and put it in low power state */ - iwl_apm_stop(priv); -} - -static struct iwl_tx_cmd *iwl_trans_get_tx_cmd(struct iwl_priv *priv, - int txq_id) -{ - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; - struct iwl_device_cmd *dev_cmd; - - if (unlikely(iwl_queue_space(q) < q->high_mark)) - return NULL; - - /* - * Set up the Tx-command (not MAC!) header. - * Store the chosen Tx queue and TFD index within the sequence field; - * after Tx, uCode's Tx response will return this value so driver can - * locate the frame within the tx queue and do post-tx processing. - */ - dev_cmd = txq->cmd[q->write_ptr]; - memset(dev_cmd, 0, sizeof(*dev_cmd)); - dev_cmd->hdr.cmd = REPLY_TX; - dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) | - INDEX_TO_SEQ(q->write_ptr))); - return &dev_cmd->cmd.tx; -} - -static int iwl_trans_tx(struct iwl_priv *priv, struct sk_buff *skb, - struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu, - struct iwl_rxon_context *ctx) -{ - struct iwl_tx_queue *txq = &priv->txq[txq_id]; - struct iwl_queue *q = &txq->q; - struct iwl_device_cmd *dev_cmd = txq->cmd[q->write_ptr]; - struct iwl_cmd_meta *out_meta; - - dma_addr_t phys_addr = 0; - dma_addr_t txcmd_phys; - dma_addr_t scratch_phys; - u16 len, firstlen, secondlen; - u8 wait_write_ptr = 0; - u8 hdr_len = ieee80211_hdrlen(fc); - - /* Set up driver data for this TFD */ - memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); - txq->txb[q->write_ptr].skb = skb; - txq->txb[q->write_ptr].ctx = ctx; - - /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_meta = &txq->meta[q->write_ptr]; - - /* - * Use the first empty entry in this queue's command buffer array - * to contain the Tx command and MAC header concatenated together - * (payload data will be in another buffer). - * Size of this varies, due to varying MAC header length. - * If end is not dword aligned, we'll have 2 extra bytes at the end - * of the MAC header (device reads on dword boundaries). - * We'll tell device about this padding later. - */ - len = sizeof(struct iwl_tx_cmd) + - sizeof(struct iwl_cmd_header) + hdr_len; - firstlen = (len + 3) & ~3; - - /* Tell NIC about any 2-byte padding after MAC header */ - if (firstlen != len) - tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK; - - /* Physical address of this Tx command's header (not MAC header!), - * within command buffer array. */ - txcmd_phys = dma_map_single(priv->bus->dev, - &dev_cmd->hdr, firstlen, - DMA_BIDIRECTIONAL); - if (unlikely(dma_mapping_error(priv->bus->dev, txcmd_phys))) - return -1; - dma_unmap_addr_set(out_meta, mapping, txcmd_phys); - dma_unmap_len_set(out_meta, len, firstlen); - - if (!ieee80211_has_morefrags(fc)) { - txq->need_update = 1; - } else { - wait_write_ptr = 1; - txq->need_update = 0; - } - - /* Set up TFD's 2nd entry to point directly to remainder of skb, - * if any (802.11 null frames have no payload). */ - secondlen = skb->len - hdr_len; - if (secondlen > 0) { - phys_addr = dma_map_single(priv->bus->dev, skb->data + hdr_len, - secondlen, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(priv->bus->dev, phys_addr))) { - dma_unmap_single(priv->bus->dev, - dma_unmap_addr(out_meta, mapping), - dma_unmap_len(out_meta, len), - DMA_BIDIRECTIONAL); - return -1; - } - } - - /* Attach buffers to TFD */ - iwlagn_txq_attach_buf_to_tfd(priv, txq, txcmd_phys, firstlen, 1); - if (secondlen > 0) - iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, - secondlen, 0); - - scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd, scratch); - - /* take back ownership of DMA buffer to enable update */ - dma_sync_single_for_cpu(priv->bus->dev, txcmd_phys, firstlen, - DMA_BIDIRECTIONAL); - tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); - - IWL_DEBUG_TX(priv, "sequence nr = 0X%x\n", - le16_to_cpu(dev_cmd->hdr.sequence)); - IWL_DEBUG_TX(priv, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); - iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); - - /* Set up entry for this TFD in Tx byte-count array */ - if (ampdu) - iwl_trans_txq_update_byte_cnt_tbl(priv, txq, - le16_to_cpu(tx_cmd->len)); - - dma_sync_single_for_device(priv->bus->dev, txcmd_phys, firstlen, - DMA_BIDIRECTIONAL); - - trace_iwlwifi_dev_tx(priv, - &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr], - sizeof(struct iwl_tfd), - &dev_cmd->hdr, firstlen, - skb->data + hdr_len, secondlen); - - /* Tell device the write index *just past* this latest filled TFD */ - q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); - iwl_txq_update_write_ptr(priv, txq); - - /* - * At this point the frame is "transmitted" successfully - * and we will get a TX status notification eventually, - * regardless of the value of ret. "ret" only indicates - * whether or not we should update the write pointer. - */ - if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) { - if (wait_write_ptr) { - txq->need_update = 1; - iwl_txq_update_write_ptr(priv, txq); - } else { - iwl_stop_queue(priv, txq); - } - } - return 0; -} - -static void iwl_trans_kick_nic(struct iwl_priv *priv) -{ - /* Remove all resets to allow NIC to operate */ - iwl_write32(priv, CSR_RESET, 0); -} - -static void iwl_trans_sync_irq(struct iwl_priv *priv) -{ - /* wait to make sure we flush pending tasklet*/ - synchronize_irq(priv->bus->irq); - tasklet_kill(&priv->irq_tasklet); -} - -static void iwl_trans_free(struct iwl_priv *priv) -{ - free_irq(priv->bus->irq, priv); - iwl_free_isr_ict(priv); -} - -static const struct iwl_trans_ops trans_ops = { - .start_device = iwl_trans_start_device, - .prepare_card_hw = iwl_trans_prepare_card_hw, - .stop_device = iwl_trans_stop_device, - - .tx_start = iwl_trans_tx_start, - - .rx_free = iwl_trans_rx_free, - .tx_free = iwl_trans_tx_free, - - .send_cmd = iwl_send_cmd, - .send_cmd_pdu = iwl_send_cmd_pdu, - - .get_tx_cmd = iwl_trans_get_tx_cmd, - .tx = iwl_trans_tx, - - .txq_agg_disable = iwl_trans_txq_agg_disable, - .txq_agg_setup = iwl_trans_txq_agg_setup, - - .kick_nic = iwl_trans_kick_nic, - - .sync_irq = iwl_trans_sync_irq, - .free = iwl_trans_free, -}; +#include "iwl-trans.h" -int iwl_trans_register(struct iwl_trans *trans, struct iwl_priv *priv) +int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id, + u32 flags, u16 len, const void *data) { - int err; - - priv->trans.ops = &trans_ops; - priv->trans.priv = priv; - - tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl_irq_tasklet, (unsigned long)priv); - - iwl_alloc_isr_ict(priv); - - err = request_irq(priv->bus->irq, iwl_isr_ict, IRQF_SHARED, - DRV_NAME, priv); - if (err) { - IWL_ERR(priv, "Error allocating IRQ %d\n", priv->bus->irq); - iwl_free_isr_ict(priv); - return err; - } - - INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); + struct iwl_host_cmd cmd = { + .id = id, + .len = { len, }, + .data = { data, }, + .flags = flags, + }; - return 0; + return iwl_trans_send_cmd(trans, &cmd); } diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 7993aa7ae668..c5923125c3f9 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -63,163 +63,289 @@ #ifndef __iwl_trans_h__ #define __iwl_trans_h__ +#include <linux/debugfs.h> +#include <linux/skbuff.h> + +#include "iwl-shared.h" +#include "iwl-commands.h" + /*This file includes the declaration that are exported from the transport * layer */ struct iwl_priv; -struct iwl_rxon_context; -struct iwl_host_cmd; +struct iwl_shared; + +#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) +#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ) +#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4) + +enum { + CMD_SYNC = 0, + CMD_ASYNC = BIT(0), + CMD_WANT_SKB = BIT(1), + CMD_ON_DEMAND = BIT(2), +}; + +#define DEF_CMD_PAYLOAD_SIZE 320 + +/** + * struct iwl_device_cmd + * + * For allocation of the command and tx queues, this establishes the overall + * size of the largest command we send to uCode, except for commands that + * aren't fully copied and use other TFD space. + */ +struct iwl_device_cmd { + struct iwl_cmd_header hdr; /* uCode API */ + u8 payload[DEF_CMD_PAYLOAD_SIZE]; +} __packed; + +#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd)) + +#define IWL_MAX_CMD_TFDS 2 + +enum iwl_hcmd_dataflag { + IWL_HCMD_DFL_NOCOPY = BIT(0), +}; + +/** + * struct iwl_host_cmd - Host command to the uCode + * @data: array of chunks that composes the data of the host command + * @reply_page: pointer to the page that holds the response to the host command + * @handler_status: return value of the handler of the command + * (put in setup_rx_handlers) - valid for SYNC mode only + * @callback: + * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC + * @len: array of the lenths of the chunks in data + * @dataflags: + * @id: id of the host command + */ +struct iwl_host_cmd { + const void *data[IWL_MAX_CMD_TFDS]; + unsigned long reply_page; + int handler_status; + + u32 flags; + u16 len[IWL_MAX_CMD_TFDS]; + u8 dataflags[IWL_MAX_CMD_TFDS]; + u8 id; +}; /** * struct iwl_trans_ops - transport specific operations + * @alloc: allocates the meta data (not the queues themselves) + * @request_irq: requests IRQ - will be called before the FW load in probe flow * @start_device: allocates and inits all the resources for the transport * layer. * @prepare_card_hw: claim the ownership on the HW. Will be called during * probe. * @tx_start: starts and configures all the Tx fifo - usually done once the fw * is alive. + * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_* * @stop_device:stops the whole device (embedded CPU put to reset) - * @rx_free: frees the rx memory - * @tx_free: frees the tx memory * @send_cmd:send a host command - * @send_cmd_pdu:send a host command: flags can be CMD_* - * @get_tx_cmd: returns a pointer to a new Tx cmd for the upper layer use * @tx: send an skb - * @txq_agg_setup: setup a tx queue for AMPDU - will be called once the HW is + * @reclaim: free packet until ssn. Returns a list of freed packets. + * @tx_agg_alloc: allocate resources for a TX BA session + * @tx_agg_setup: setup a tx queue for AMPDU - will be called once the HW is * ready and a successful ADDBA response has been received. - * @txq_agg_disable: de-configure a Tx queue to send AMPDUs + * @tx_agg_disable: de-configure a Tx queue to send AMPDUs * @kick_nic: remove the RESET from the embedded CPU and let it run - * @sync_irq: the upper layer will typically disable interrupt and call this - * handler. After this handler returns, it is guaranteed that all - * the ISR / tasklet etc... have finished running and the transport - * layer shall not pass any Rx. * @free: release all the ressource for the transport layer itself such as * irq, tasklet etc... + * @stop_queue: stop a specific queue + * @check_stuck_queue: check if a specific queue is stuck + * @wait_tx_queue_empty: wait until all tx queues are empty + * @dbgfs_register: add the dbgfs files under this directory. Files will be + * automatically deleted. + * @suspend: stop the device unless WoWLAN is configured + * @resume: resume activity of the device */ struct iwl_trans_ops { - int (*start_device)(struct iwl_priv *priv); - int (*prepare_card_hw)(struct iwl_priv *priv); - void (*stop_device)(struct iwl_priv *priv); - void (*tx_start)(struct iwl_priv *priv); - void (*tx_free)(struct iwl_priv *priv); - void (*rx_free)(struct iwl_priv *priv); + struct iwl_trans *(*alloc)(struct iwl_shared *shrd); + int (*request_irq)(struct iwl_trans *iwl_trans); + int (*start_device)(struct iwl_trans *trans); + int (*prepare_card_hw)(struct iwl_trans *trans); + void (*stop_device)(struct iwl_trans *trans); + void (*tx_start)(struct iwl_trans *trans); + + void (*wake_any_queue)(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx); - int (*send_cmd)(struct iwl_priv *priv, struct iwl_host_cmd *cmd); + int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); - int (*send_cmd_pdu)(struct iwl_priv *priv, u8 id, u32 flags, u16 len, - const void *data); - struct iwl_tx_cmd * (*get_tx_cmd)(struct iwl_priv *priv, int txq_id); - int (*tx)(struct iwl_priv *priv, struct sk_buff *skb, - struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu, - struct iwl_rxon_context *ctx); + int (*tx)(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, + u8 sta_id); + void (*reclaim)(struct iwl_trans *trans, int sta_id, int tid, + int txq_id, int ssn, u32 status, + struct sk_buff_head *skbs); - int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, - u16 ssn_idx, u8 tx_fifo); - void (*txq_agg_setup)(struct iwl_priv *priv, int sta_id, int tid, - int frame_limit); + int (*tx_agg_disable)(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, int sta_id, + int tid); + int (*tx_agg_alloc)(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, int sta_id, int tid, + u16 *ssn); + void (*tx_agg_setup)(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, int sta_id, int tid, + int frame_limit); - void (*kick_nic)(struct iwl_priv *priv); + void (*kick_nic)(struct iwl_trans *trans); - void (*sync_irq)(struct iwl_priv *priv); - void (*free)(struct iwl_priv *priv); + void (*free)(struct iwl_trans *trans); + + void (*stop_queue)(struct iwl_trans *trans, int q); + + int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir); + int (*check_stuck_queue)(struct iwl_trans *trans, int q); + int (*wait_tx_queue_empty)(struct iwl_trans *trans); +#ifdef CONFIG_PM_SLEEP + int (*suspend)(struct iwl_trans *trans); + int (*resume)(struct iwl_trans *trans); +#endif }; +/** + * struct iwl_trans - transport common data + * @ops - pointer to iwl_trans_ops + * @shrd - pointer to iwl_shared which holds shared data from the upper layer + * @hcmd_lock: protects HCMD + */ struct iwl_trans { const struct iwl_trans_ops *ops; - struct iwl_priv *priv; + struct iwl_shared *shrd; + spinlock_t hcmd_lock; + + /* pointer to trans specific struct */ + /*Ensure that this pointer will always be aligned to sizeof pointer */ + char trans_specific[0] __attribute__((__aligned__(sizeof(void *)))); }; -static inline int trans_start_device(struct iwl_trans *trans) +static inline int iwl_trans_request_irq(struct iwl_trans *trans) { - return trans->ops->start_device(trans->priv); + return trans->ops->request_irq(trans); } -static inline int trans_prepare_card_hw(struct iwl_trans *trans) +static inline int iwl_trans_start_device(struct iwl_trans *trans) { - return trans->ops->prepare_card_hw(trans->priv); + return trans->ops->start_device(trans); } -static inline void trans_stop_device(struct iwl_trans *trans) +static inline int iwl_trans_prepare_card_hw(struct iwl_trans *trans) { - trans->ops->stop_device(trans->priv); + return trans->ops->prepare_card_hw(trans); } -static inline void trans_tx_start(struct iwl_trans *trans) +static inline void iwl_trans_stop_device(struct iwl_trans *trans) { - trans->ops->tx_start(trans->priv); + trans->ops->stop_device(trans); } -static inline void trans_rx_free(struct iwl_trans *trans) +static inline void iwl_trans_tx_start(struct iwl_trans *trans) { - trans->ops->rx_free(trans->priv); + trans->ops->tx_start(trans); } -static inline void trans_tx_free(struct iwl_trans *trans) +static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx) { - trans->ops->tx_free(trans->priv); + trans->ops->wake_any_queue(trans, ctx); } -static inline int trans_send_cmd(struct iwl_trans *trans, + +static inline int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { - return trans->ops->send_cmd(trans->priv, cmd); + return trans->ops->send_cmd(trans, cmd); +} + +int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id, + u32 flags, u16 len, const void *data); + +static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx, + u8 sta_id) +{ + return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id); } -static inline int trans_send_cmd_pdu(struct iwl_trans *trans, u8 id, u32 flags, - u16 len, const void *data) +static inline void iwl_trans_reclaim(struct iwl_trans *trans, int sta_id, + int tid, int txq_id, int ssn, u32 status, + struct sk_buff_head *skbs) { - return trans->ops->send_cmd_pdu(trans->priv, id, flags, len, data); + trans->ops->reclaim(trans, sta_id, tid, txq_id, ssn, status, skbs); } -static inline struct iwl_tx_cmd *trans_get_tx_cmd(struct iwl_trans *trans, - int txq_id) +static inline int iwl_trans_tx_agg_disable(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, + int sta_id, int tid) { - return trans->ops->get_tx_cmd(trans->priv, txq_id); + return trans->ops->tx_agg_disable(trans, ctx, sta_id, tid); } -static inline int trans_tx(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_tx_cmd *tx_cmd, int txq_id, __le16 fc, bool ampdu, - struct iwl_rxon_context *ctx) +static inline int iwl_trans_tx_agg_alloc(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, + int sta_id, int tid, u16 *ssn) { - return trans->ops->tx(trans->priv, skb, tx_cmd, txq_id, fc, ampdu, ctx); + return trans->ops->tx_agg_alloc(trans, ctx, sta_id, tid, ssn); } -static inline int trans_txq_agg_disable(struct iwl_trans *trans, u16 txq_id, - u16 ssn_idx, u8 tx_fifo) + +static inline void iwl_trans_tx_agg_setup(struct iwl_trans *trans, + enum iwl_rxon_context_id ctx, + int sta_id, int tid, + int frame_limit) { - return trans->ops->txq_agg_disable(trans->priv, txq_id, - ssn_idx, tx_fifo); + trans->ops->tx_agg_setup(trans, ctx, sta_id, tid, frame_limit); } -static inline void trans_txq_agg_setup(struct iwl_trans *trans, int sta_id, - int tid, int frame_limit) +static inline void iwl_trans_kick_nic(struct iwl_trans *trans) { - trans->ops->txq_agg_setup(trans->priv, sta_id, tid, frame_limit); + trans->ops->kick_nic(trans); } -static inline void trans_kick_nic(struct iwl_trans *trans) +static inline void iwl_trans_free(struct iwl_trans *trans) { - trans->ops->kick_nic(trans->priv); + trans->ops->free(trans); } -static inline void trans_sync_irq(struct iwl_trans *trans) +static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q) { - trans->ops->sync_irq(trans->priv); + trans->ops->stop_queue(trans, q); } -static inline void trans_free(struct iwl_trans *trans) +static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) +{ + return trans->ops->wait_tx_queue_empty(trans); +} + +static inline int iwl_trans_check_stuck_queue(struct iwl_trans *trans, int q) +{ + return trans->ops->check_stuck_queue(trans, q); +} +static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans, + struct dentry *dir) { - trans->ops->free(trans->priv); + return trans->ops->dbgfs_register(trans, dir); } -int iwl_trans_register(struct iwl_trans *trans, struct iwl_priv *priv); +#ifdef CONFIG_PM_SLEEP +static inline int iwl_trans_suspend(struct iwl_trans *trans) +{ + return trans->ops->suspend(trans); +} -/*TODO: this functions should NOT be exported from trans module - export it - * until the reclaim flow will be brought to the transport module too */ +static inline int iwl_trans_resume(struct iwl_trans *trans) +{ + return trans->ops->resume(trans); +} +#endif -struct iwl_tx_queue; -void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, - struct iwl_tx_queue *txq); +/***************************************************** +* Transport layers implementations +******************************************************/ +extern const struct iwl_trans_ops trans_ops_pcie; #endif /* __iwl_trans_h__ */ diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index ed57e4402800..c42be81e979e 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -187,13 +187,17 @@ static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, struct key_params*)) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - struct iwm_key *key = &iwm->keys[key_index]; + struct iwm_key *key; struct key_params params; IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index); + if (key_index >= IWM_NUM_KEYS) + return -ENOENT; + memset(¶ms, 0, sizeof(params)); + key = &iwm->keys[key_index]; params.cipher = key->cipher; params.key_len = key->key_len; params.seq_len = key->seq_len; diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README index 1453eec82a99..91f2ca90c70f 100644 --- a/drivers/net/wireless/libertas/README +++ b/drivers/net/wireless/libertas/README @@ -238,28 +238,3 @@ hostsleep echo "1" > hostsleep : enable host sleep. echo "0" > hostsleep : disable host sleep -======================== -IWCONFIG COMMANDS -======================== -power period - - This command is used to configure the station in deep sleep mode / - auto deep sleep mode. - - The timer is implemented to monitor the activities (command, event, - etc.). When an activity is detected station will exit from deep - sleep mode automatically and restart the timer. At timer expiry - (no activity for defined time period) the deep sleep mode is entered - automatically. - - Note: this command is for SDIO interface only. - - Usage: - To enable deep sleep mode do: - iwconfig wlan0 power period 0 - To enable auto deep sleep mode with idle time period 5 seconds do: - iwconfig wlan0 power period 5 - To disable deep sleep/auto deep sleep mode do: - iwconfig wlan0 power period -1 - -============================================================================== diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index b456a53b64b1..ff6378276ff0 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -19,6 +19,7 @@ #include "decl.h" #include "cfg.h" #include "cmd.h" +#include "mesh.h" #define CHAN2G(_channel, _freq, _flags) { \ @@ -442,13 +443,16 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy, struct lbs_private *priv = wiphy_priv(wiphy); int ret = -ENOTSUPP; - lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d", - channel->center_freq, channel_type); + lbs_deb_enter_args(LBS_DEB_CFG80211, "iface %s freq %d, type %d", + netdev_name(netdev), channel->center_freq, channel_type); if (channel_type != NL80211_CHAN_NO_HT) goto out; - ret = lbs_set_channel(priv, channel->hw_value); + if (netdev == priv->mesh_dev) + ret = lbs_mesh_set_channel(priv, channel->hw_value); + else + ret = lbs_set_channel(priv, channel->hw_value); out: lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret); @@ -691,7 +695,7 @@ static void lbs_scan_worker(struct work_struct *work) tlv = scan_cmd->tlvbuffer; /* add SSID TLV */ - if (priv->scan_req->n_ssids) + if (priv->scan_req->n_ssids && priv->scan_req->ssids[0].ssid_len > 0) tlv += lbs_add_ssid_tlv(tlv, priv->scan_req->ssids[0].ssid, priv->scan_req->ssids[0].ssid_len); @@ -708,7 +712,7 @@ static void lbs_scan_worker(struct work_struct *work) if (priv->scan_channel < priv->scan_req->n_channels) { cancel_delayed_work(&priv->scan_work); - if (!priv->stopping) + if (netif_running(priv->dev)) queue_delayed_work(priv->work_thread, &priv->scan_work, msecs_to_jiffies(300)); } @@ -732,7 +736,6 @@ static void lbs_scan_worker(struct work_struct *work) cfg80211_scan_done(priv->scan_req, false); priv->scan_req = NULL; - priv->last_scan = jiffies; } /* Restart network */ @@ -1292,27 +1295,32 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, int ret = 0; u8 preamble = RADIO_PREAMBLE_SHORT; + if (dev == priv->mesh_dev) + return -EOPNOTSUPP; + lbs_deb_enter(LBS_DEB_CFG80211); if (!sme->bssid) { - /* Run a scan if one isn't in-progress already and if the last - * scan was done more than 2 seconds ago. - */ - if (priv->scan_req == NULL && - time_after(jiffies, priv->last_scan + (2 * HZ))) { - struct cfg80211_scan_request *creq; + struct cfg80211_scan_request *creq; - creq = _new_connect_scan_req(wiphy, sme); - if (!creq) { - ret = -EINVAL; - goto done; - } + /* + * Scan for the requested network after waiting for existing + * scans to finish. + */ + lbs_deb_assoc("assoc: waiting for existing scans\n"); + wait_event_interruptible_timeout(priv->scan_q, + (priv->scan_req == NULL), + (15 * HZ)); - lbs_deb_assoc("assoc: scanning for compatible AP\n"); - _internal_start_scan(priv, true, creq); + creq = _new_connect_scan_req(wiphy, sme); + if (!creq) { + ret = -EINVAL; + goto done; } - /* Wait for any in-progress scan to complete */ + lbs_deb_assoc("assoc: scanning for compatible AP\n"); + _internal_start_scan(priv, true, creq); + lbs_deb_assoc("assoc: waiting for scan to complete\n"); wait_event_interruptible_timeout(priv->scan_q, (priv->scan_req == NULL), @@ -1402,28 +1410,23 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev, return ret; } -static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) +int lbs_disconnect(struct lbs_private *priv, u16 reason) { - struct lbs_private *priv = wiphy_priv(wiphy); struct cmd_ds_802_11_deauthenticate cmd; - - lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); - - /* store for lbs_cfg_ret_disconnect() */ - priv->disassoc_reason = reason_code; + int ret; memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); /* Mildly ugly to use a locally store my own BSSID ... */ memcpy(cmd.macaddr, &priv->assoc_bss, ETH_ALEN); - cmd.reasoncode = cpu_to_le16(reason_code); + cmd.reasoncode = cpu_to_le16(reason); - if (lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd)) - return -EFAULT; + ret = lbs_cmd_with_response(priv, CMD_802_11_DEAUTHENTICATE, &cmd); + if (ret) + return ret; cfg80211_disconnected(priv->dev, - priv->disassoc_reason, + reason, NULL, 0, GFP_KERNEL); priv->connect_status = LBS_DISCONNECTED; @@ -1431,6 +1434,21 @@ static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, return 0; } +static int lbs_cfg_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct lbs_private *priv = wiphy_priv(wiphy); + + if (dev == priv->mesh_dev) + return -EOPNOTSUPP; + + lbs_deb_enter_args(LBS_DEB_CFG80211, "reason_code %d", reason_code); + + /* store for lbs_cfg_ret_disconnect() */ + priv->disassoc_reason = reason_code; + + return lbs_disconnect(priv, reason_code); +} static int lbs_cfg_set_default_key(struct wiphy *wiphy, struct net_device *netdev, @@ -1439,6 +1457,9 @@ static int lbs_cfg_set_default_key(struct wiphy *wiphy, { struct lbs_private *priv = wiphy_priv(wiphy); + if (netdev == priv->mesh_dev) + return -EOPNOTSUPP; + lbs_deb_enter(LBS_DEB_CFG80211); if (key_index != priv->wep_tx_key) { @@ -1460,6 +1481,9 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev, u16 key_type; int ret = 0; + if (netdev == priv->mesh_dev) + return -EOPNOTSUPP; + lbs_deb_enter(LBS_DEB_CFG80211); lbs_deb_assoc("add_key: cipher 0x%x, mac_addr %pM\n", @@ -1603,6 +1627,9 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev, s8 signal, noise; int ret; + if (dev == priv->mesh_dev) + return -EOPNOTSUPP; + if (idx != 0) ret = -ENOENT; @@ -1636,28 +1663,23 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev, struct lbs_private *priv = wiphy_priv(wiphy); int ret = 0; - lbs_deb_enter(LBS_DEB_CFG80211); + if (dev == priv->mesh_dev) + return -EOPNOTSUPP; switch (type) { case NL80211_IFTYPE_MONITOR: - ret = lbs_set_monitor_mode(priv, 1); - break; case NL80211_IFTYPE_STATION: - if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) - ret = lbs_set_monitor_mode(priv, 0); - if (!ret) - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1); - break; case NL80211_IFTYPE_ADHOC: - if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) - ret = lbs_set_monitor_mode(priv, 0); - if (!ret) - ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2); break; default: - ret = -ENOTSUPP; + return -EOPNOTSUPP; } + lbs_deb_enter(LBS_DEB_CFG80211); + + if (priv->iface_running) + ret = lbs_set_iface_type(priv, type); + if (!ret) priv->wdev->iftype = type; @@ -1959,6 +1981,9 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_bss *bss; DECLARE_SSID_BUF(ssid_buf); + if (dev == priv->mesh_dev) + return -EOPNOTSUPP; + lbs_deb_enter(LBS_DEB_CFG80211); if (!params->channel) { @@ -1995,6 +2020,9 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev) struct cmd_ds_802_11_ad_hoc_stop cmd; int ret = 0; + if (dev == priv->mesh_dev) + return -EOPNOTSUPP; + lbs_deb_enter(LBS_DEB_CFG80211); memset(&cmd, 0, sizeof(cmd)); @@ -2117,6 +2145,8 @@ int lbs_cfg_register(struct lbs_private *priv) BIT(NL80211_IFTYPE_ADHOC); if (lbs_rtap_supported(priv)) wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); + if (lbs_mesh_activated(priv)) + wdev->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MESH_POINT); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &lbs_band_2ghz; diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h index 4f46bb744bee..a02ee151710e 100644 --- a/drivers/net/wireless/libertas/cfg.h +++ b/drivers/net/wireless/libertas/cfg.h @@ -17,5 +17,6 @@ void lbs_send_disconnect_notification(struct lbs_private *priv); void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); void lbs_scan_deinit(struct lbs_private *priv); +int lbs_disconnect(struct lbs_private *priv, u16 reason); #endif diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index dbd24a4607ec..e08ab1de3d9d 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1088,7 +1088,7 @@ void __lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, if (!cmd->callback || cmd->callback == lbs_cmd_async_callback) __lbs_cleanup_and_insert_cmd(priv, cmd); priv->cur_cmd = NULL; - wake_up_interruptible(&priv->waitq); + wake_up(&priv->waitq); } void lbs_complete_command(struct lbs_private *priv, struct cmd_ctrl_node *cmd, @@ -1627,7 +1627,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, lbs_deb_host("PREP_CMD: cmdnode is NULL\n"); /* Wake up main thread to execute next command */ - wake_up_interruptible(&priv->waitq); + wake_up(&priv->waitq); cmdnode = ERR_PTR(-ENOBUFS); goto done; } @@ -1647,7 +1647,7 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv, cmdnode->cmdwaitqwoken = 0; lbs_queue_cmd(priv, cmdnode); - wake_up_interruptible(&priv->waitq); + wake_up(&priv->waitq); done: lbs_deb_leave_args(LBS_DEB_HOST, "ret %p", cmdnode); diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index da0b05bb89fe..bc951ab4b681 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -9,6 +9,7 @@ #include <linux/netdevice.h> #include <linux/firmware.h> +#include <linux/nl80211.h> /* Should be terminated by a NULL entry */ struct lbs_fw_table { @@ -43,10 +44,15 @@ int lbs_start_card(struct lbs_private *priv); void lbs_stop_card(struct lbs_private *priv); void lbs_host_to_card_done(struct lbs_private *priv); +int lbs_start_iface(struct lbs_private *priv); +int lbs_stop_iface(struct lbs_private *priv); +int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type); + int lbs_rtap_supported(struct lbs_private *priv); int lbs_set_mac_address(struct net_device *dev, void *addr); void lbs_set_multicast_list(struct net_device *dev); +void lbs_update_mcast(struct lbs_private *priv); int lbs_suspend(struct lbs_private *priv); int lbs_resume(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index adb3490e3cf5..f3fd447131c2 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -6,7 +6,6 @@ #ifndef _LBS_DEV_H_ #define _LBS_DEV_H_ -#include "mesh.h" #include "defs.h" #include "host.h" @@ -22,6 +21,17 @@ struct sleep_params { uint16_t sp_reserved; }; +/* Mesh statistics */ +struct lbs_mesh_stats { + u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ + u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ + u32 fwd_drop_ttl; /* Fwd: TTL zero */ + u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ + u32 fwd_drop_noroute; /* Fwd: No route to Destination */ + u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ + u32 drop_blind; /* Rx: Dropped by blinding table */ + u32 tx_failed_cnt; /* Tx: Failed transmissions */ +}; /* Private structure for the MV device */ struct lbs_private { @@ -36,7 +46,6 @@ struct lbs_private { /* CFG80211 */ struct wireless_dev *wdev; bool wiphy_registered; - bool stopping; struct cfg80211_scan_request *scan_req; u8 assoc_bss[ETH_ALEN]; u8 disassoc_reason; @@ -86,11 +95,14 @@ struct lbs_private { /* Hardware access */ void *card; + bool iface_running; u8 fw_ready; u8 surpriseremoved; u8 setup_fw_on_resume; int (*hw_host_to_card) (struct lbs_private *priv, u8 type, u8 *payload, u16 nb); void (*reset_card) (struct lbs_private *priv); + int (*power_save) (struct lbs_private *priv); + int (*power_restore) (struct lbs_private *priv); int (*enter_deep_sleep) (struct lbs_private *priv); int (*exit_deep_sleep) (struct lbs_private *priv); int (*reset_deep_sleep_wakeup) (struct lbs_private *priv); @@ -146,6 +158,7 @@ struct lbs_private { /* protected by hard_start_xmit serialization */ u8 txretrycount; struct sk_buff *currenttxskb; + struct timer_list tx_lockup_timer; /* Locks */ struct mutex lock; @@ -167,9 +180,20 @@ struct lbs_private { wait_queue_head_t scan_q; /* Whether the scan was initiated internally and not by cfg80211 */ bool internal_scan; - unsigned long last_scan; }; extern struct cmd_confirm_sleep confirm_sleep; +/* Check if there is an interface active. */ +static inline int lbs_iface_active(struct lbs_private *priv) +{ + int r; + + r = netif_running(priv->dev); + if (priv->mesh_dev) + r |= netif_running(priv->mesh_dev); + + return r; +} + #endif diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 4dfb3bfd2cf3..885ddc1c4fed 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -5,6 +5,7 @@ #include "decl.h" #include "cmd.h" +#include "mesh.h" static void lbs_ethtool_get_drvinfo(struct net_device *dev, diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index 387786e1b394..c962e21762dc 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -39,6 +39,7 @@ #include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio.h> #include <linux/mmc/host.h> +#include <linux/pm_runtime.h> #include "host.h" #include "decl.h" @@ -47,6 +48,8 @@ #include "cmd.h" #include "if_sdio.h" +static void if_sdio_interrupt(struct sdio_func *func); + /* The if_sdio_remove() callback function is called when * user removes this module from kernel space or ejects * the card from the slot. The driver handles these 2 cases @@ -757,6 +760,136 @@ out: return ret; } +/********************************************************************/ +/* Power management */ +/********************************************************************/ + +static int if_sdio_power_on(struct if_sdio_card *card) +{ + struct sdio_func *func = card->func; + struct lbs_private *priv = card->priv; + struct mmc_host *host = func->card->host; + int ret; + + sdio_claim_host(func); + + ret = sdio_enable_func(func); + if (ret) + goto release; + + /* For 1-bit transfers to the 8686 model, we need to enable the + * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 + * bit to allow access to non-vendor registers. */ + if ((card->model == MODEL_8686) && + (host->caps & MMC_CAP_SDIO_IRQ) && + (host->ios.bus_width == MMC_BUS_WIDTH_1)) { + u8 reg; + + func->card->quirks |= MMC_QUIRK_LENIENT_FN0; + reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); + if (ret) + goto disable; + + reg |= SDIO_BUS_ECSI; + sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); + if (ret) + goto disable; + } + + card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); + if (ret) + goto disable; + + card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; + if (ret) + goto disable; + + card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; + if (ret) + goto disable; + + sdio_release_host(func); + ret = if_sdio_prog_firmware(card); + sdio_claim_host(func); + if (ret) + goto disable; + + /* + * Get rx_unit if the chip is SD8688 or newer. + * SD8385 & SD8686 do not have rx_unit. + */ + if ((card->model != MODEL_8385) + && (card->model != MODEL_8686)) + card->rx_unit = if_sdio_read_rx_unit(card); + else + card->rx_unit = 0; + + /* + * Set up the interrupt handler late. + * + * If we set it up earlier, the (buggy) hardware generates a spurious + * interrupt, even before the interrupt has been enabled, with + * CCCR_INTx = 0. + * + * We register the interrupt handler late so that we can handle any + * spurious interrupts, and also to avoid generation of that known + * spurious interrupt in the first place. + */ + ret = sdio_claim_irq(func, if_sdio_interrupt); + if (ret) + goto disable; + + /* + * Enable interrupts now that everything is set up + */ + sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); + if (ret) + goto release_irq; + + sdio_release_host(func); + + /* + * FUNC_INIT is required for SD8688 WLAN/BT multiple functions + */ + if (card->model == MODEL_8688) { + struct cmd_header cmd; + + memset(&cmd, 0, sizeof(cmd)); + + lbs_deb_sdio("send function INIT command\n"); + if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), + lbs_cmd_copyback, (unsigned long) &cmd)) + netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n"); + } + + priv->fw_ready = 1; + + return 0; + +release_irq: + sdio_release_irq(func); +disable: + sdio_disable_func(func); +release: + sdio_release_host(func); + return ret; +} + +static int if_sdio_power_off(struct if_sdio_card *card) +{ + struct sdio_func *func = card->func; + struct lbs_private *priv = card->priv; + + priv->fw_ready = 0; + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_disable_func(func); + sdio_release_host(func); + return 0; +} + + /*******************************************************************/ /* Libertas callbacks */ /*******************************************************************/ @@ -923,6 +1056,32 @@ static void if_sdio_reset_card(struct lbs_private *priv) schedule_work(&card_reset_work); } +static int if_sdio_power_save(struct lbs_private *priv) +{ + struct if_sdio_card *card = priv->card; + int ret; + + flush_workqueue(card->workqueue); + + ret = if_sdio_power_off(card); + + /* Let runtime PM know the card is powered off */ + pm_runtime_put_sync(&card->func->dev); + + return ret; +} + +static int if_sdio_power_restore(struct lbs_private *priv) +{ + struct if_sdio_card *card = priv->card; + + /* Make sure the card will not be powered off by runtime PM */ + pm_runtime_get_sync(&card->func->dev); + + return if_sdio_power_on(card); +} + + /*******************************************************************/ /* SDIO callbacks */ /*******************************************************************/ @@ -976,7 +1135,6 @@ static int if_sdio_probe(struct sdio_func *func, int ret, i; unsigned int model; struct if_sdio_packet *packet; - struct mmc_host *host = func->card->host; lbs_deb_enter(LBS_DEB_SDIO); @@ -1033,45 +1191,6 @@ static int if_sdio_probe(struct sdio_func *func, goto free; } - sdio_claim_host(func); - - ret = sdio_enable_func(func); - if (ret) - goto release; - - /* For 1-bit transfers to the 8686 model, we need to enable the - * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0 - * bit to allow access to non-vendor registers. */ - if ((card->model == MODEL_8686) && - (host->caps & MMC_CAP_SDIO_IRQ) && - (host->ios.bus_width == MMC_BUS_WIDTH_1)) { - u8 reg; - - func->card->quirks |= MMC_QUIRK_LENIENT_FN0; - reg = sdio_f0_readb(func, SDIO_CCCR_IF, &ret); - if (ret) - goto release_int; - - reg |= SDIO_BUS_ECSI; - sdio_f0_writeb(func, reg, SDIO_CCCR_IF, &ret); - if (ret) - goto release_int; - } - - card->ioport = sdio_readb(func, IF_SDIO_IOPORT, &ret); - if (ret) - goto release_int; - - card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 1, &ret) << 8; - if (ret) - goto release_int; - - card->ioport |= sdio_readb(func, IF_SDIO_IOPORT + 2, &ret) << 16; - if (ret) - goto release_int; - - sdio_release_host(func); - sdio_set_drvdata(func, card); lbs_deb_sdio("class = 0x%X, vendor = 0x%X, " @@ -1079,14 +1198,11 @@ static int if_sdio_probe(struct sdio_func *func, func->class, func->vendor, func->device, model, (unsigned)card->ioport); - ret = if_sdio_prog_firmware(card); - if (ret) - goto reclaim; priv = lbs_add_card(card, &func->dev); if (!priv) { ret = -ENOMEM; - goto reclaim; + goto free; } card->priv = priv; @@ -1097,62 +1213,21 @@ static int if_sdio_probe(struct sdio_func *func, priv->exit_deep_sleep = if_sdio_exit_deep_sleep; priv->reset_deep_sleep_wakeup = if_sdio_reset_deep_sleep_wakeup; priv->reset_card = if_sdio_reset_card; + priv->power_save = if_sdio_power_save; + priv->power_restore = if_sdio_power_restore; - sdio_claim_host(func); - - /* - * Get rx_unit if the chip is SD8688 or newer. - * SD8385 & SD8686 do not have rx_unit. - */ - if ((card->model != MODEL_8385) - && (card->model != MODEL_8686)) - card->rx_unit = if_sdio_read_rx_unit(card); - else - card->rx_unit = 0; - - /* - * Set up the interrupt handler late. - * - * If we set it up earlier, the (buggy) hardware generates a spurious - * interrupt, even before the interrupt has been enabled, with - * CCCR_INTx = 0. - * - * We register the interrupt handler late so that we can handle any - * spurious interrupts, and also to avoid generation of that known - * spurious interrupt in the first place. - */ - ret = sdio_claim_irq(func, if_sdio_interrupt); - if (ret) - goto disable; - - /* - * Enable interrupts now that everything is set up - */ - sdio_writeb(func, 0x0f, IF_SDIO_H_INT_MASK, &ret); - sdio_release_host(func); + ret = if_sdio_power_on(card); if (ret) - goto reclaim; - - priv->fw_ready = 1; - - /* - * FUNC_INIT is required for SD8688 WLAN/BT multiple functions - */ - if (card->model == MODEL_8688) { - struct cmd_header cmd; - - memset(&cmd, 0, sizeof(cmd)); - - lbs_deb_sdio("send function INIT command\n"); - if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd), - lbs_cmd_copyback, (unsigned long) &cmd)) - netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n"); - } + goto err_activate_card; ret = lbs_start_card(priv); + if_sdio_power_off(card); if (ret) goto err_activate_card; + /* Tell PM core that we don't need the card to be powered now */ + pm_runtime_put_noidle(&func->dev); + out: lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret); @@ -1161,14 +1236,6 @@ out: err_activate_card: flush_workqueue(card->workqueue); lbs_remove_card(priv); -reclaim: - sdio_claim_host(func); -release_int: - sdio_release_irq(func); -disable: - sdio_disable_func(func); -release: - sdio_release_host(func); free: destroy_workqueue(card->workqueue); while (card->packets) { @@ -1195,6 +1262,9 @@ static void if_sdio_remove(struct sdio_func *func) card = sdio_get_drvdata(func); + /* Undo decrement done above in if_sdio_probe */ + pm_runtime_get_noresume(&func->dev); + if (user_rmmod && (card->model == MODEL_8688)) { /* * FUNC_SHUTDOWN is required for SD8688 WLAN/BT @@ -1219,11 +1289,6 @@ static void if_sdio_remove(struct sdio_func *func) flush_workqueue(card->workqueue); destroy_workqueue(card->workqueue); - sdio_claim_host(func); - sdio_release_irq(func); - sdio_disable_func(func); - sdio_release_host(func); - while (card->packets) { packet = card->packets; card->packets = card->packets->next; diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index e0286cfbc91d..622ae6de0d8b 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -531,10 +531,6 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card, goto out; err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG, IF_SPI_CIC_CMD_DOWNLOAD_OVER); - goto out; - - lbs_deb_spi("waiting for helper to boot...\n"); - out: if (err) pr_err("failed to load helper firmware (err=%d)\n", err); diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index b5acc393a65a..8147f1e2a0b0 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -324,7 +324,7 @@ static int if_usb_probe(struct usb_interface *intf, } kparam_unblock_sysfs_write(fw_name); - if (!(priv = lbs_add_card(cardp, &udev->dev))) + if (!(priv = lbs_add_card(cardp, &intf->dev))) goto err_prog_firmware; cardp->priv = priv; @@ -956,7 +956,7 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp, priv->dnld_sent = DNLD_RES_RECEIVED; spin_unlock_irqrestore(&priv->driver_lock, flags); - wake_up_interruptible(&priv->waitq); + wake_up(&priv->waitq); return ret; } @@ -973,6 +973,23 @@ static const struct { { MODEL_8682, "libertas/usb8682.bin" } }; +#ifdef CONFIG_OLPC + +static int try_olpc_fw(struct if_usb_card *cardp) +{ + int retval = -ENOENT; + + /* try the OLPC firmware first; fall back to fw_table list */ + if (machine_is_olpc() && cardp->model == MODEL_8388) + retval = request_firmware(&cardp->fw, + "libertas/usb8388_olpc.bin", &cardp->udev->dev); + return retval; +} + +#else +static int try_olpc_fw(struct if_usb_card *cardp) { return -ENOENT; } +#endif /* !CONFIG_OLPC */ + static int get_fw(struct if_usb_card *cardp, const char *fwname) { int i; @@ -981,6 +998,10 @@ static int get_fw(struct if_usb_card *cardp, const char *fwname) if (fwname) return request_firmware(&cardp->fw, fwname, &cardp->udev->dev); + /* Handle OLPC firmware */ + if (try_olpc_fw(cardp) == 0) + return 0; + /* Otherwise search for firmware to use */ for (i = 0; i < ARRAY_SIZE(fw_table); i++) { if (fw_table[i].model != cardp->model) @@ -1112,6 +1133,15 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) if (priv->psstate != PS_STATE_FULL_POWER) return -1; +#ifdef CONFIG_OLPC + if (machine_is_olpc()) { + if (priv->wol_criteria == EHS_REMOVE_WAKEUP) + olpc_ec_wakeup_clear(EC_SCI_SRC_WLAN); + else + olpc_ec_wakeup_set(EC_SCI_SRC_WLAN); + } +#endif + ret = lbs_suspend(priv); if (ret) goto out; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 94652c5a25de..b03779bcd547 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -23,6 +23,7 @@ #include "cfg.h" #include "debugfs.h" #include "cmd.h" +#include "mesh.h" #define DRIVER_RELEASE_VERSION "323.p0" const char lbs_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION @@ -98,6 +99,69 @@ u8 lbs_data_rate_to_fw_index(u32 rate) return 0; } +int lbs_set_iface_type(struct lbs_private *priv, enum nl80211_iftype type) +{ + int ret = 0; + + switch (type) { + case NL80211_IFTYPE_MONITOR: + ret = lbs_set_monitor_mode(priv, 1); + break; + case NL80211_IFTYPE_STATION: + if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) + ret = lbs_set_monitor_mode(priv, 0); + if (!ret) + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 1); + break; + case NL80211_IFTYPE_ADHOC: + if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) + ret = lbs_set_monitor_mode(priv, 0); + if (!ret) + ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_BSS_TYPE, 2); + break; + default: + ret = -ENOTSUPP; + } + return ret; +} + +int lbs_start_iface(struct lbs_private *priv) +{ + struct cmd_ds_802_11_mac_address cmd; + int ret; + + if (priv->power_restore) { + ret = priv->power_restore(priv); + if (ret) + return ret; + } + + cmd.hdr.size = cpu_to_le16(sizeof(cmd)); + cmd.action = cpu_to_le16(CMD_ACT_SET); + memcpy(cmd.macadd, priv->current_addr, ETH_ALEN); + + ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd); + if (ret) { + lbs_deb_net("set MAC address failed\n"); + goto err; + } + + ret = lbs_set_iface_type(priv, priv->wdev->iftype); + if (ret) { + lbs_deb_net("set iface type failed\n"); + goto err; + } + + lbs_update_channel(priv); + + priv->iface_running = true; + return 0; + +err: + if (priv->power_save) + priv->power_save(priv); + return ret; +} /** * lbs_dev_open - open the ethX interface @@ -111,23 +175,65 @@ static int lbs_dev_open(struct net_device *dev) int ret = 0; lbs_deb_enter(LBS_DEB_NET); + if (!priv->iface_running) { + ret = lbs_start_iface(priv); + if (ret) + goto out; + } spin_lock_irq(&priv->driver_lock); - priv->stopping = false; - if (priv->connect_status == LBS_CONNECTED) - netif_carrier_on(dev); - else - netif_carrier_off(dev); + netif_carrier_off(dev); if (!priv->tx_pending_len) netif_wake_queue(dev); spin_unlock_irq(&priv->driver_lock); + +out: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } +static bool lbs_command_queue_empty(struct lbs_private *priv) +{ + unsigned long flags; + bool ret; + spin_lock_irqsave(&priv->driver_lock, flags); + ret = priv->cur_cmd == NULL && list_empty(&priv->cmdpendingq); + spin_unlock_irqrestore(&priv->driver_lock, flags); + return ret; +} + +int lbs_stop_iface(struct lbs_private *priv) +{ + unsigned long flags; + int ret = 0; + + lbs_deb_enter(LBS_DEB_MAIN); + + spin_lock_irqsave(&priv->driver_lock, flags); + priv->iface_running = false; + kfree_skb(priv->currenttxskb); + priv->currenttxskb = NULL; + priv->tx_pending_len = 0; + spin_unlock_irqrestore(&priv->driver_lock, flags); + + cancel_work_sync(&priv->mcast_work); + del_timer_sync(&priv->tx_lockup_timer); + + /* Disable command processing, and wait for all commands to complete */ + lbs_deb_main("waiting for commands to complete\n"); + wait_event(priv->waitq, lbs_command_queue_empty(priv)); + lbs_deb_main("all commands completed\n"); + + if (priv->power_save) + ret = priv->power_save(priv); + + lbs_deb_leave(LBS_DEB_MAIN); + return ret; +} + /** * lbs_eth_stop - close the ethX interface * @@ -140,18 +246,25 @@ static int lbs_eth_stop(struct net_device *dev) lbs_deb_enter(LBS_DEB_NET); + if (priv->connect_status == LBS_CONNECTED) + lbs_disconnect(priv, WLAN_REASON_DEAUTH_LEAVING); + spin_lock_irq(&priv->driver_lock); - priv->stopping = true; netif_stop_queue(dev); spin_unlock_irq(&priv->driver_lock); - schedule_work(&priv->mcast_work); + lbs_update_mcast(priv); cancel_delayed_work_sync(&priv->scan_work); if (priv->scan_req) { cfg80211_scan_done(priv->scan_req, false); priv->scan_req = NULL; } + netif_carrier_off(priv->dev); + + if (!lbs_iface_active(priv)) + lbs_stop_iface(priv); + lbs_deb_leave(LBS_DEB_NET); return 0; } @@ -163,13 +276,14 @@ void lbs_host_to_card_done(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_THREAD); spin_lock_irqsave(&priv->driver_lock, flags); + del_timer(&priv->tx_lockup_timer); priv->dnld_sent = DNLD_RES_RECEIVED; /* Wake main thread if commands are pending */ if (!priv->cur_cmd || priv->tx_pending_len > 0) { if (!priv->wakeup_dev_required) - wake_up_interruptible(&priv->waitq); + wake_up(&priv->waitq); } spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -182,29 +296,24 @@ int lbs_set_mac_address(struct net_device *dev, void *addr) int ret = 0; struct lbs_private *priv = dev->ml_priv; struct sockaddr *phwaddr = addr; - struct cmd_ds_802_11_mac_address cmd; lbs_deb_enter(LBS_DEB_NET); + /* + * Can only set MAC address when all interfaces are down, to be written + * to the hardware when one of them is brought up. + */ + if (lbs_iface_active(priv)) + return -EBUSY; + /* In case it was called from the mesh device */ dev = priv->dev; - cmd.hdr.size = cpu_to_le16(sizeof(cmd)); - cmd.action = cpu_to_le16(CMD_ACT_SET); - memcpy(cmd.macadd, phwaddr->sa_data, ETH_ALEN); - - ret = lbs_cmd_with_response(priv, CMD_802_11_MAC_ADDRESS, &cmd); - if (ret) { - lbs_deb_net("set MAC address failed\n"); - goto done; - } - memcpy(priv->current_addr, phwaddr->sa_data, ETH_ALEN); memcpy(dev->dev_addr, phwaddr->sa_data, ETH_ALEN); if (priv->mesh_dev) memcpy(priv->mesh_dev->dev_addr, phwaddr->sa_data, ETH_ALEN); -done: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); return ret; } @@ -258,18 +367,18 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, return i; } -static void lbs_set_mcast_worker(struct work_struct *work) +void lbs_update_mcast(struct lbs_private *priv) { - struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work); struct cmd_ds_mac_multicast_adr mcast_cmd; - int dev_flags; + int dev_flags = 0; int nr_addrs; int old_mac_control = priv->mac_control; lbs_deb_enter(LBS_DEB_NET); - dev_flags = priv->dev->flags; - if (priv->mesh_dev) + if (netif_running(priv->dev)) + dev_flags |= priv->dev->flags; + if (priv->mesh_dev && netif_running(priv->mesh_dev)) dev_flags |= priv->mesh_dev->flags; if (dev_flags & IFF_PROMISC) { @@ -315,6 +424,12 @@ static void lbs_set_mcast_worker(struct work_struct *work) lbs_deb_leave(LBS_DEB_NET); } +static void lbs_set_mcast_worker(struct work_struct *work) +{ + struct lbs_private *priv = container_of(work, struct lbs_private, mcast_work); + lbs_update_mcast(priv); +} + void lbs_set_multicast_list(struct net_device *dev) { struct lbs_private *priv = dev->ml_priv; @@ -504,6 +619,9 @@ static int lbs_thread(void *data) if (ret) { lbs_deb_tx("host_to_card failed %d\n", ret); priv->dnld_sent = DNLD_RES_RECEIVED; + } else { + mod_timer(&priv->tx_lockup_timer, + jiffies + (HZ * 5)); } priv->tx_pending_len = 0; if (!priv->currenttxskb) { @@ -520,6 +638,7 @@ static int lbs_thread(void *data) } del_timer(&priv->command_timer); + del_timer(&priv->tx_lockup_timer); del_timer(&priv->auto_deepsleep_timer); lbs_deb_leave(LBS_DEB_THREAD); @@ -647,13 +766,39 @@ static void lbs_cmd_timeout_handler(unsigned long data) if (priv->dnld_sent == DNLD_CMD_SENT) priv->dnld_sent = DNLD_RES_RECEIVED; - wake_up_interruptible(&priv->waitq); + wake_up(&priv->waitq); out: spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_leave(LBS_DEB_CMD); } /** + * lbs_tx_lockup_handler - handles the timeout of the passing of TX frames + * to the hardware. This is known to frequently happen with SD8686 when + * waking up after a Wake-on-WLAN-triggered resume. + * + * @data: &struct lbs_private pointer + */ +static void lbs_tx_lockup_handler(unsigned long data) +{ + struct lbs_private *priv = (struct lbs_private *)data; + unsigned long flags; + + lbs_deb_enter(LBS_DEB_TX); + spin_lock_irqsave(&priv->driver_lock, flags); + + netdev_info(priv->dev, "TX lockup detected\n"); + if (priv->reset_card) + priv->reset_card(priv); + + priv->dnld_sent = DNLD_RES_RECEIVED; + wake_up_interruptible(&priv->waitq); + + spin_unlock_irqrestore(&priv->driver_lock, flags); + lbs_deb_leave(LBS_DEB_TX); +} + +/** * auto_deepsleep_timer_fn - put the device back to deep sleep mode when * timer expires and no activity (command, event, data etc.) is detected. * @data: &struct lbs_private pointer @@ -739,6 +884,8 @@ static int lbs_init_adapter(struct lbs_private *priv) setup_timer(&priv->command_timer, lbs_cmd_timeout_handler, (unsigned long)priv); + setup_timer(&priv->tx_lockup_timer, lbs_tx_lockup_handler, + (unsigned long)priv); setup_timer(&priv->auto_deepsleep_timer, auto_deepsleep_timer_fn, (unsigned long)priv); @@ -776,6 +923,7 @@ static void lbs_free_adapter(struct lbs_private *priv) lbs_free_cmd_buffer(priv); kfifo_free(&priv->event_fifo); del_timer(&priv->command_timer); + del_timer(&priv->tx_lockup_timer); del_timer(&priv->auto_deepsleep_timer); lbs_deb_leave(LBS_DEB_MAIN); @@ -786,7 +934,7 @@ static const struct net_device_ops lbs_netdev_ops = { .ndo_stop = lbs_eth_stop, .ndo_start_xmit = lbs_hard_start_xmit, .ndo_set_mac_address = lbs_set_mac_address, - .ndo_set_multicast_list = lbs_set_multicast_list, + .ndo_set_rx_mode = lbs_set_multicast_list, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, }; @@ -889,10 +1037,6 @@ void lbs_remove_card(struct lbs_private *priv) lbs_remove_mesh(priv); lbs_scan_deinit(priv); - dev = priv->dev; - - cancel_work_sync(&priv->mcast_work); - /* worker thread destruction blocks on the in-flight command which * should have been cleared already in lbs_stop_card(). */ @@ -950,17 +1094,18 @@ int lbs_start_card(struct lbs_private *priv) if (ret) goto done; + if (!lbs_disablemesh) + lbs_init_mesh(priv); + else + pr_info("%s: mesh disabled\n", dev->name); + if (lbs_cfg_register(priv)) { pr_err("cannot register device\n"); goto done; } - lbs_update_channel(priv); - - if (!lbs_disablemesh) - lbs_init_mesh(priv); - else - pr_info("%s: mesh disabled\n", dev->name); + if (lbs_mesh_activated(priv)) + lbs_start_mesh(priv); lbs_debugfs_init_one(priv, dev); @@ -978,8 +1123,6 @@ EXPORT_SYMBOL_GPL(lbs_start_card); void lbs_stop_card(struct lbs_private *priv) { struct net_device *dev; - struct cmd_ctrl_node *cmdnode; - unsigned long flags; lbs_deb_enter(LBS_DEB_MAIN); @@ -992,30 +1135,6 @@ void lbs_stop_card(struct lbs_private *priv) lbs_debugfs_remove_one(priv); lbs_deinit_mesh(priv); - - /* Delete the timeout of the currently processing command */ - del_timer_sync(&priv->command_timer); - del_timer_sync(&priv->auto_deepsleep_timer); - - /* Flush pending command nodes */ - spin_lock_irqsave(&priv->driver_lock, flags); - lbs_deb_main("clearing pending commands\n"); - list_for_each_entry(cmdnode, &priv->cmdpendingq, list) { - cmdnode->result = -ENOENT; - cmdnode->cmdwaitqwoken = 1; - wake_up(&cmdnode->cmdwait_q); - } - - /* Flush the command the card is currently processing */ - if (priv->cur_cmd) { - lbs_deb_main("clearing current command\n"); - priv->cur_cmd->result = -ENOENT; - priv->cur_cmd->cmdwaitqwoken = 1; - wake_up(&priv->cur_cmd->cmdwait_q); - } - lbs_deb_main("done clearing commands\n"); - spin_unlock_irqrestore(&priv->driver_lock, flags); - unregister_netdev(dev); out: @@ -1036,7 +1155,7 @@ void lbs_queue_event(struct lbs_private *priv, u32 event) kfifo_in(&priv->event_fifo, (unsigned char *) &event, sizeof(u32)); - wake_up_interruptible(&priv->waitq); + wake_up(&priv->waitq); spin_unlock_irqrestore(&priv->driver_lock, flags); lbs_deb_leave(LBS_DEB_THREAD); @@ -1054,7 +1173,7 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx) BUG_ON(resp_idx > 1); priv->resp_idx = resp_idx; - wake_up_interruptible(&priv->waitq); + wake_up(&priv->waitq); lbs_deb_leave(LBS_DEB_THREAD); } diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index be72c08ea2a7..e87c031b298f 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -129,6 +129,19 @@ static int lbs_mesh_config(struct lbs_private *priv, uint16_t action, return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } +int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel) +{ + return lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, channel); +} + +static uint16_t lbs_mesh_get_channel(struct lbs_private *priv) +{ + struct wireless_dev *mesh_wdev = priv->mesh_dev->ieee80211_ptr; + if (mesh_wdev->channel) + return mesh_wdev->channel->hw_value; + else + return 1; +} /*************************************************************************** * Mesh sysfs support @@ -812,7 +825,6 @@ static void lbs_persist_config_remove(struct net_device *dev) */ int lbs_init_mesh(struct lbs_private *priv) { - struct net_device *dev = priv->dev; int ret = 0; lbs_deb_enter(LBS_DEB_MESH); @@ -837,11 +849,9 @@ int lbs_init_mesh(struct lbs_private *priv) useful */ priv->mesh_tlv = TLV_TYPE_OLD_MESH_ID; - if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->channel)) { + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) { priv->mesh_tlv = TLV_TYPE_MESH_ID; - if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->channel)) + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) priv->mesh_tlv = 0; } } else @@ -851,23 +861,16 @@ int lbs_init_mesh(struct lbs_private *priv) * 0x100+37; Do not invoke command with old TLV. */ priv->mesh_tlv = TLV_TYPE_MESH_ID; - if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, - priv->channel)) + if (lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, 1)) priv->mesh_tlv = 0; } /* Stop meshing until interface is brought up */ - lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, 1); if (priv->mesh_tlv) { sprintf(priv->mesh_ssid, "mesh"); priv->mesh_ssid_len = 4; - - lbs_add_mesh(priv); - - if (device_create_file(&dev->dev, &dev_attr_lbs_mesh)) - netdev_err(dev, "cannot register lbs_mesh attribute\n"); - ret = 1; } @@ -875,6 +878,13 @@ int lbs_init_mesh(struct lbs_private *priv) return ret; } +void lbs_start_mesh(struct lbs_private *priv) +{ + lbs_add_mesh(priv); + + if (device_create_file(&priv->dev->dev, &dev_attr_lbs_mesh)) + netdev_err(priv->dev, "cannot register lbs_mesh attribute\n"); +} int lbs_deinit_mesh(struct lbs_private *priv) { @@ -904,7 +914,8 @@ static int lbs_mesh_stop(struct net_device *dev) struct lbs_private *priv = dev->ml_priv; lbs_deb_enter(LBS_DEB_MESH); - lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, priv->channel); + lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_STOP, + lbs_mesh_get_channel(priv)); spin_lock_irq(&priv->driver_lock); @@ -913,7 +924,9 @@ static int lbs_mesh_stop(struct net_device *dev) spin_unlock_irq(&priv->driver_lock); - schedule_work(&priv->mcast_work); + lbs_update_mcast(priv); + if (!lbs_iface_active(priv)) + lbs_stop_iface(priv); lbs_deb_leave(LBS_DEB_MESH); return 0; @@ -931,6 +944,11 @@ static int lbs_mesh_dev_open(struct net_device *dev) int ret = 0; lbs_deb_enter(LBS_DEB_NET); + if (!priv->iface_running) { + ret = lbs_start_iface(priv); + if (ret) + goto out; + } spin_lock_irq(&priv->driver_lock); @@ -947,7 +965,8 @@ static int lbs_mesh_dev_open(struct net_device *dev) spin_unlock_irq(&priv->driver_lock); - ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, priv->channel); + ret = lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, + lbs_mesh_get_channel(priv)); out: lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret); @@ -959,7 +978,7 @@ static const struct net_device_ops mesh_netdev_ops = { .ndo_stop = lbs_mesh_stop, .ndo_start_xmit = lbs_hard_start_xmit, .ndo_set_mac_address = lbs_set_mac_address, - .ndo_set_multicast_list = lbs_set_multicast_list, + .ndo_set_rx_mode = lbs_set_multicast_list, }; /** @@ -971,18 +990,32 @@ static const struct net_device_ops mesh_netdev_ops = { static int lbs_add_mesh(struct lbs_private *priv) { struct net_device *mesh_dev = NULL; + struct wireless_dev *mesh_wdev; int ret = 0; lbs_deb_enter(LBS_DEB_MESH); /* Allocate a virtual mesh device */ + mesh_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!mesh_wdev) { + lbs_deb_mesh("init mshX wireless device failed\n"); + ret = -ENOMEM; + goto done; + } + mesh_dev = alloc_netdev(0, "msh%d", ether_setup); if (!mesh_dev) { lbs_deb_mesh("init mshX device failed\n"); ret = -ENOMEM; - goto done; + goto err_free_wdev; } + + mesh_wdev->iftype = NL80211_IFTYPE_MESH_POINT; + mesh_wdev->wiphy = priv->wdev->wiphy; + mesh_wdev->netdev = mesh_dev; + mesh_dev->ml_priv = priv; + mesh_dev->ieee80211_ptr = mesh_wdev; priv->mesh_dev = mesh_dev; mesh_dev->netdev_ops = &mesh_netdev_ops; @@ -996,7 +1029,7 @@ static int lbs_add_mesh(struct lbs_private *priv) ret = register_netdev(mesh_dev); if (ret) { pr_err("cannot register mshX virtual interface\n"); - goto err_free; + goto err_free_netdev; } ret = sysfs_create_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); @@ -1012,9 +1045,12 @@ static int lbs_add_mesh(struct lbs_private *priv) err_unregister: unregister_netdev(mesh_dev); -err_free: +err_free_netdev: free_netdev(mesh_dev); +err_free_wdev: + kfree(mesh_wdev); + done: lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret); return ret; @@ -1035,6 +1071,7 @@ void lbs_remove_mesh(struct lbs_private *priv) lbs_persist_config_remove(mesh_dev); unregister_netdev(mesh_dev); priv->mesh_dev = NULL; + kfree(mesh_dev->ieee80211_ptr); free_netdev(mesh_dev); lbs_deb_leave(LBS_DEB_MESH); } diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h index 50144913f2ab..6603f341c874 100644 --- a/drivers/net/wireless/libertas/mesh.h +++ b/drivers/net/wireless/libertas/mesh.h @@ -9,30 +9,25 @@ #include <net/lib80211.h> #include "host.h" +#include "dev.h" #ifdef CONFIG_LIBERTAS_MESH -/* Mesh statistics */ -struct lbs_mesh_stats { - u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ - u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ - u32 fwd_drop_ttl; /* Fwd: TTL zero */ - u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ - u32 fwd_drop_noroute; /* Fwd: No route to Destination */ - u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ - u32 drop_blind; /* Rx: Dropped by blinding table */ - u32 tx_failed_cnt; /* Tx: Failed transmissions */ -}; - - struct net_device; -struct lbs_private; int lbs_init_mesh(struct lbs_private *priv); +void lbs_start_mesh(struct lbs_private *priv); int lbs_deinit_mesh(struct lbs_private *priv); void lbs_remove_mesh(struct lbs_private *priv); +static inline bool lbs_mesh_activated(struct lbs_private *priv) +{ + /* Mesh SSID is only programmed after successful init */ + return priv->mesh_ssid_len != 0; +} + +int lbs_mesh_set_channel(struct lbs_private *priv, u8 channel); /* Sending / Receiving */ @@ -67,11 +62,13 @@ void lbs_mesh_ethtool_get_strings(struct net_device *dev, #define lbs_init_mesh(priv) #define lbs_deinit_mesh(priv) +#define lbs_start_mesh(priv) #define lbs_add_mesh(priv) #define lbs_remove_mesh(priv) #define lbs_mesh_set_dev(priv, dev, rxpd) (dev) #define lbs_mesh_set_txpd(priv, dev, txpd) -#define lbs_mesh_config(priv, enable, chan) +#define lbs_mesh_set_channel(priv, channel) (0) +#define lbs_mesh_activated(priv) (false) #endif diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index bfb8898ae518..62e10eeadd7e 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -15,6 +15,7 @@ #include "radiotap.h" #include "decl.h" #include "dev.h" +#include "mesh.h" struct eth803hdr { u8 dest_addr[6]; diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index a6e85134cfe1..8f127520d786 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -12,6 +12,7 @@ #include "decl.h" #include "defs.h" #include "dev.h" +#include "mesh.h" /** * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 031cd89b1768..68455a2307cb 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -612,6 +612,12 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, rx_status.freq = data->channel->center_freq; rx_status.band = data->channel->band; rx_status.rate_idx = info->control.rates[0].idx; + if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) + rx_status.flag |= RX_FLAG_HT; + if (info->control.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + rx_status.flag |= RX_FLAG_40MHZ; + if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) + rx_status.flag |= RX_FLAG_SHORT_GI; /* TODO: simulate real signal strength (and optional packet loss) */ rx_status.signal = data->power_level - 50; @@ -964,7 +970,8 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, } static int mac80211_hwsim_conf_tx( - struct ieee80211_hw *hw, u16 queue, + struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { wiphy_debug(hw->wiphy, diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c index 1a453a605b3f..079e5532e686 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/mwifiex/11n_aggr.c @@ -193,7 +193,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_src = skb_dequeue(&pra_list->skb_head); pra_list->total_pkts_size -= skb_src->len; - pra_list->total_pkts--; atomic_dec(&priv->wmm.tx_pkts_queued); @@ -247,8 +246,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, tx_param.next_pkt_len = 0; ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb_aggr->data, - skb_aggr->len, &tx_param); + skb_aggr, &tx_param); switch (ret) { case -EBUSY: spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -269,7 +267,6 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv, skb_queue_tail(&pra_list->skb_head, skb_aggr); pra_list->total_pkts_size += skb_aggr->len; - pra_list->total_pkts++; atomic_inc(&priv->wmm.tx_pkts_queued); diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h index 9c6dca7ab02c..900e1c62a0cc 100644 --- a/drivers/net/wireless/mwifiex/11n_aggr.h +++ b/drivers/net/wireless/mwifiex/11n_aggr.h @@ -21,6 +21,7 @@ #define _MWIFIEX_11N_AGGR_H_ #define PKT_TYPE_AMSDU 0xE6 +#define MIN_NUM_AMSDU 2 int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv, struct sk_buff *skb); diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig index 86962920cef3..8f2797aa0c60 100644 --- a/drivers/net/wireless/mwifiex/Kconfig +++ b/drivers/net/wireless/mwifiex/Kconfig @@ -19,3 +19,14 @@ config MWIFIEX_SDIO If you choose to build it as a module, it will be called mwifiex_sdio. + +config MWIFIEX_PCIE + tristate "Marvell WiFi-Ex Driver for PCIE 8766" + depends on MWIFIEX && PCI + select FW_LOADER + ---help--- + This adds support for wireless adapters based on Marvell + 8766 chipset with PCIe interface. + + If you choose to build it as a module, it will be called + mwifiex_pcie. diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index 42cb733ea33a..b0257ad1bbed 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile @@ -39,3 +39,6 @@ obj-$(CONFIG_MWIFIEX) += mwifiex.o mwifiex_sdio-y += sdio.o obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o + +mwifiex_pcie-y += pcie.o +obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 352d2c5da1fc..462c71067bfb 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -543,12 +543,28 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, ret = -EFAULT; } + /* + * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid + * MCS index values for us are 0 to 7. + */ + if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 8)) { + sinfo->txrate.mcs = priv->tx_rate; + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + /* 40MHz rate */ + if (priv->tx_htinfo & BIT(1)) + sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + /* SGI enabled */ + if (priv->tx_htinfo & BIT(2)) + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + } + sinfo->rx_bytes = priv->stats.rx_bytes; sinfo->tx_bytes = priv->stats.tx_bytes; sinfo->rx_packets = priv->stats.rx_packets; sinfo->tx_packets = priv->stats.tx_packets; - sinfo->signal = priv->w_stats.qual.level; - sinfo->txrate.legacy = rate.rate; + sinfo->signal = priv->qual_level; + /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */ + sinfo->txrate.legacy = rate.rate * 5; return ret; } @@ -565,8 +581,6 @@ mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - mwifiex_dump_station_info(priv, sinfo); - if (!priv->media_connected) return -ENOENT; if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) @@ -768,6 +782,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) struct mwifiex_bss_info bss_info; int ie_len; u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)]; + enum ieee80211_band band; if (mwifiex_get_bss_info(priv, &bss_info)) return -1; @@ -780,9 +795,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) bss_info.ssid.ssid_len); ie_len = ie_buf[1] + sizeof(struct ieee_types_header); + band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); chan = __ieee80211_get_channel(priv->wdev->wiphy, ieee80211_channel_to_frequency(bss_info.bss_chan, - priv->curr_bss_params.band)); + band)); cfg80211_inform_bss(priv->wdev->wiphy, chan, bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, @@ -793,139 +809,6 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv) } /* - * This function informs the CFG802.11 subsystem of a new BSS connection. - * - * The following information are sent to the CFG802.11 subsystem - * to register the new BSS connection. If we do not register the new BSS, - * a kernel panic will result. - * - MAC address - * - Capabilities - * - Beacon period - * - RSSI value - * - Channel - * - Supported rates IE - * - Extended capabilities IE - * - DS parameter set IE - * - HT Capability IE - * - Vendor Specific IE (221) - * - WPA IE - * - RSN IE - */ -static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *ssid) -{ - struct mwifiex_bssdescriptor *scan_table; - int i, j; - struct ieee80211_channel *chan; - u8 *ie, *ie_buf; - u32 ie_len; - u8 *beacon; - int beacon_size; - u8 element_id, element_len; - -#define MAX_IE_BUF 2048 - ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); - if (!ie_buf) { - dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n", - __func__); - return -ENOMEM; - } - - scan_table = priv->adapter->scan_table; - for (i = 0; i < priv->adapter->num_in_scan_table; i++) { - if (ssid) { - /* Inform specific BSS only */ - if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, - ssid->ssid_len)) - continue; - } - memset(ie_buf, 0, MAX_IE_BUF); - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = scan_table[i].ssid.ssid_len; - memcpy(&ie_buf[sizeof(struct ieee_types_header)], - scan_table[i].ssid.ssid, ie_buf[1]); - - ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header); - ie_len = ie_buf[1] + sizeof(struct ieee_types_header); - - ie[0] = WLAN_EID_SUPP_RATES; - - for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { - if (!scan_table[i].supported_rates[j]) - break; - else - ie[j + sizeof(struct ieee_types_header)] = - scan_table[i].supported_rates[j]; - } - - ie[1] = j; - ie_len += ie[1] + sizeof(struct ieee_types_header); - - beacon = scan_table[i].beacon_buf; - beacon_size = scan_table[i].beacon_buf_size; - - /* Skip time stamp, beacon interval and capability */ - - if (beacon) { - beacon += sizeof(scan_table[i].beacon_period) - + sizeof(scan_table[i].time_stamp) + - +sizeof(scan_table[i].cap_info_bitmap); - - beacon_size -= sizeof(scan_table[i].beacon_period) - + sizeof(scan_table[i].time_stamp) - + sizeof(scan_table[i].cap_info_bitmap); - } - - while (beacon_size >= sizeof(struct ieee_types_header)) { - ie = ie_buf + ie_len; - element_id = *beacon; - element_len = *(beacon + 1); - if (beacon_size < (int) element_len + - sizeof(struct ieee_types_header)) { - dev_err(priv->adapter->dev, "%s: in processing" - " IE, bytes left < IE length\n", - __func__); - break; - } - switch (element_id) { - case WLAN_EID_EXT_CAPABILITY: - case WLAN_EID_DS_PARAMS: - case WLAN_EID_HT_CAPABILITY: - case WLAN_EID_VENDOR_SPECIFIC: - case WLAN_EID_RSN: - case WLAN_EID_BSS_AC_ACCESS_DELAY: - ie[0] = element_id; - ie[1] = element_len; - memcpy(&ie[sizeof(struct ieee_types_header)], - (u8 *) beacon - + sizeof(struct ieee_types_header), - element_len); - ie_len += ie[1] + - sizeof(struct ieee_types_header); - break; - default: - break; - } - beacon += element_len + - sizeof(struct ieee_types_header); - beacon_size -= element_len + - sizeof(struct ieee_types_header); - } - chan = ieee80211_get_channel(priv->wdev->wiphy, - scan_table[i].freq); - cfg80211_inform_bss(priv->wdev->wiphy, chan, - scan_table[i].mac_address, - 0, scan_table[i].cap_info_bitmap, - scan_table[i].beacon_period, - ie_buf, ie_len, - scan_table[i].rssi, GFP_KERNEL); - } - - kfree(ie_buf); - return 0; -} - -/* * This function connects with a BSS. * * This function handles both Infra and Ad-Hoc modes. It also performs @@ -937,8 +820,7 @@ static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv, * For Infra mode, the function returns failure if the specified SSID * is not found in scan table. However, for Ad-Hoc mode, it can create * the IBSS if it does not exist. On successful completion in either case, - * the function notifies the CFG802.11 subsystem of the new BSS connection, - * otherwise the kernel will panic. + * the function notifies the CFG802.11 subsystem of the new BSS connection. */ static int mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, @@ -946,11 +828,11 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, struct cfg80211_connect_params *sme, bool privacy) { struct mwifiex_802_11_ssid req_ssid; - struct mwifiex_ssid_bssid ssid_bssid; int ret, auth_type = 0; + struct cfg80211_bss *bss = NULL; + u8 is_scanning_required = 0; memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid)); - memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); req_ssid.ssid_len = ssid_len; if (ssid_len > IEEE80211_MAX_SSID_LEN) { @@ -1028,30 +910,48 @@ done: return -EFAULT; } + /* + * Scan entries are valid for some time (15 sec). So we can save one + * active scan time if we just try cfg80211_get_bss first. If it fails + * then request scan and cfg80211_get_bss() again for final output. + */ + while (1) { + if (is_scanning_required) { + /* Do specific SSID scanning */ + if (mwifiex_request_scan(priv, &req_ssid)) { + dev_err(priv->adapter->dev, "scan error\n"); + return -EFAULT; + } + } - memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid)); - - if (mode != NL80211_IFTYPE_ADHOC) { - if (mwifiex_find_best_bss(priv, &ssid_bssid)) - return -EFAULT; - /* Inform the BSS information to kernel, otherwise - * kernel will give a panic after successful assoc */ - if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid)) - return -EFAULT; + /* Find the BSS we want using available scan results */ + if (mode == NL80211_IFTYPE_ADHOC) + bss = cfg80211_get_bss(priv->wdev->wiphy, channel, + bssid, ssid, ssid_len, + WLAN_CAPABILITY_IBSS, + WLAN_CAPABILITY_IBSS); + else + bss = cfg80211_get_bss(priv->wdev->wiphy, channel, + bssid, ssid, ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); + + if (!bss) { + if (is_scanning_required) { + dev_warn(priv->adapter->dev, "assoc: requested " + "bss not found in scan results\n"); + break; + } + is_scanning_required = 1; + } else { + dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", + (char *) req_ssid.ssid, bss->bssid); + memcpy(&priv->cfg_bssid, bss->bssid, ETH_ALEN); + break; + } } - dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n", - (char *) req_ssid.ssid, ssid_bssid.bssid); - - memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6); - - /* Connect to BSS by ESSID */ - memset(&ssid_bssid.bssid, 0, ETH_ALEN); - - if (!netif_queue_stopped(priv->netdev)) - netif_stop_queue(priv->netdev); - - if (mwifiex_bss_start(priv, &ssid_bssid)) + if (mwifiex_bss_start(priv, bss, &req_ssid)) return -EFAULT; if (mode == NL80211_IFTYPE_ADHOC) { @@ -1262,8 +1162,150 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } +/* + * create a new virtual interface with the given name + */ +struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter; + struct net_device *dev; + void *mdev_priv; + + if (!priv) + return NULL; + + adapter = priv->adapter; + if (!adapter) + return NULL; + + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + if (priv->bss_mode) { + wiphy_err(wiphy, "cannot create multiple" + " station/adhoc interfaces\n"); + return NULL; + } + + if (type == NL80211_IFTYPE_UNSPECIFIED) + priv->bss_mode = NL80211_IFTYPE_STATION; + else + priv->bss_mode = type; + + priv->bss_type = MWIFIEX_BSS_TYPE_STA; + priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; + priv->bss_priority = 0; + priv->bss_role = MWIFIEX_BSS_ROLE_STA; + priv->bss_index = 0; + priv->bss_num = 0; + + break; + default: + wiphy_err(wiphy, "type not supported\n"); + return NULL; + } + + dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name, + ether_setup, 1); + if (!dev) { + wiphy_err(wiphy, "no memory available for netdevice\n"); + goto error; + } + + dev_net_set(dev, wiphy_net(wiphy)); + dev->ieee80211_ptr = priv->wdev; + dev->ieee80211_ptr->iftype = priv->bss_mode; + memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN); + memcpy(dev->perm_addr, wiphy->perm_addr, ETH_ALEN); + SET_NETDEV_DEV(dev, wiphy_dev(wiphy)); + + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; + dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; + + mdev_priv = netdev_priv(dev); + *((unsigned long *) mdev_priv) = (unsigned long) priv; + + priv->netdev = dev; + mwifiex_init_priv_params(priv, dev); + + SET_NETDEV_DEV(dev, adapter->dev); + + /* Register network device */ + if (register_netdevice(dev)) { + wiphy_err(wiphy, "cannot register virtual network device\n"); + goto error; + } + + sema_init(&priv->async_sem, 1); + priv->scan_pending_on_block = false; + + dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); + +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_init(priv); +#endif + return dev; +error: + if (dev && (dev->reg_state == NETREG_UNREGISTERED)) + free_netdev(dev); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + + return NULL; +} +EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); + +/* + * del_virtual_intf: remove the virtual interface determined by dev + */ +int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + + if (!priv || !dev) + return 0; + +#ifdef CONFIG_DEBUG_FS + mwifiex_dev_debugfs_remove(priv); +#endif + + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); + + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + + if (dev->reg_state == NETREG_REGISTERED) + unregister_netdevice(dev); + + if (dev->reg_state == NETREG_UNREGISTERED) + free_netdev(dev); + + /* Clear the priv in adapter */ + priv->netdev = NULL; + + priv->media_connected = false; + + cancel_work_sync(&priv->cfg_workqueue); + flush_workqueue(priv->workqueue); + destroy_workqueue(priv->workqueue); + + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + + return 0; +} +EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf); + /* station cfg80211 operations */ static struct cfg80211_ops mwifiex_cfg80211_ops = { + .add_virtual_intf = mwifiex_add_virtual_intf, + .del_virtual_intf = mwifiex_del_virtual_intf, .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf, .scan = mwifiex_cfg80211_scan, .connect = mwifiex_cfg80211_connect, @@ -1288,8 +1330,7 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { * default parameters and handler function pointers, and finally * registers the device. */ -int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, - struct mwifiex_private *priv) +int mwifiex_register_cfg80211(struct mwifiex_private *priv) { int ret; void *wdev_priv; @@ -1329,12 +1370,15 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, wdev->wiphy->cipher_suites = mwifiex_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); - memcpy(wdev->wiphy->perm_addr, mac, 6); + memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN); wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; /* We are using custom domains */ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + /* Reserve space for bss band information */ + wdev->wiphy->bss_priv_size = sizeof(u8); + wdev->wiphy->reg_notifier = mwifiex_reg_notifier; /* Set struct mwifiex_private pointer in wiphy_priv */ @@ -1356,17 +1400,8 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac, "info: successfully registered wiphy device\n"); } - dev_net_set(dev, wiphy_net(wdev->wiphy)); - dev->ieee80211_ptr = wdev; - memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6); - memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6); - SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); priv->wdev = wdev; - dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT; - dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN; - return ret; } @@ -1416,13 +1451,8 @@ mwifiex_cfg80211_results(struct work_struct *work) MWIFIEX_SCAN_TYPE_ACTIVE; scan_req->chan_list[i].scan_time = 0; } - if (mwifiex_set_user_scan_ioctl(priv, scan_req)) { + if (mwifiex_set_user_scan_ioctl(priv, scan_req)) ret = -EFAULT; - goto done; - } - if (mwifiex_inform_bss_from_scan_result(priv, NULL)) - ret = -EFAULT; -done: priv->scan_result_status = ret; dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n", __func__); diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h index c4db8f36aa16..8d010f2500c5 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.h +++ b/drivers/net/wireless/mwifiex/cfg80211.h @@ -24,8 +24,7 @@ #include "main.h" -int mwifiex_register_cfg80211(struct net_device *, u8 *, - struct mwifiex_private *); +int mwifiex_register_cfg80211(struct mwifiex_private *); void mwifiex_cfg80211_results(struct work_struct *work); #endif diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index d0cada5a29a0..f2e6de03805c 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -48,7 +48,7 @@ static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 }; -u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, +static u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, 0xb0, 0x48, 0x60, 0x6c, 0 }; static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18, @@ -57,19 +57,19 @@ static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04, 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51, 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 }; -u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; +static u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 }; -u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, +static u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 }; -u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, +static u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c, 0x12, 0x16, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, 0 }; u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30, 0x32, 0x40, 0x41, 0xff }; -u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; +static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 }; /* * This function maps an index in supported rates table into diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index b5352afb8714..ac278156d390 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -40,8 +40,12 @@ mwifiex_init_cmd_node(struct mwifiex_private *priv, { cmd_node->priv = priv; cmd_node->cmd_oid = cmd_oid; - cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; - priv->adapter->cmd_wait_q_required = false; + if (priv->adapter->cmd_wait_q_required) { + cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required; + priv->adapter->cmd_wait_q_required = false; + cmd_node->cmd_wait_q_woken = false; + cmd_node->condition = &cmd_node->cmd_wait_q_woken; + } cmd_node->data_buf = data_buf; cmd_node->cmd_skb = cmd_node->skb; } @@ -90,8 +94,11 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter, cmd_node->data_buf = NULL; cmd_node->wait_q_enabled = false; + if (cmd_node->cmd_skb) + skb_trim(cmd_node->cmd_skb, 0); + if (cmd_node->resp_skb) { - dev_kfree_skb_any(cmd_node->resp_skb); + adapter->if_ops.cmdrsp_complete(adapter, cmd_node->resp_skb); cmd_node->resp_skb = NULL; } } @@ -173,8 +180,7 @@ static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv, skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, - cmd_node->cmd_skb->data, - cmd_node->cmd_skb->len, NULL); + cmd_node->cmd_skb, NULL); skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN); @@ -235,8 +241,7 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter) skb_push(adapter->sleep_cfm, INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD, - adapter->sleep_cfm->data, - adapter->sleep_cfm->len, NULL); + adapter->sleep_cfm, NULL); skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN); if (ret == -1) { @@ -399,8 +404,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) adapter->event_cause = 0; adapter->event_skb = NULL; - - dev_kfree_skb_any(skb); + adapter->if_ops.event_complete(adapter, skb); return ret; } @@ -418,7 +422,6 @@ int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no, struct mwifiex_adapter *adapter = priv->adapter; adapter->cmd_wait_q_required = true; - adapter->cmd_wait_q.condition = false; ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid, data_buf); @@ -511,10 +514,12 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, } /* Send command */ - if (cmd_no == HostCmd_CMD_802_11_SCAN) + if (cmd_no == HostCmd_CMD_802_11_SCAN) { mwifiex_queue_scan_cmd(priv, cmd_node); - else + } else { + adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + } return ret; } @@ -535,7 +540,7 @@ mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter, return; if (cmd_node->wait_q_enabled) - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, cmd_node); /* Clean the node */ mwifiex_clean_cmd_node(adapter, cmd_node); @@ -882,7 +887,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) adapter->curr_cmd->wait_q_enabled = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); } /* Cancel all pending command */ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags); @@ -893,7 +898,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter) if (cmd_node->wait_q_enabled) { adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, cmd_node); cmd_node->wait_q_enabled = false; } mwifiex_insert_cmd_to_free_q(adapter, cmd_node); @@ -976,7 +981,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); } /* diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 94ddc9038cb3..ae17ce02a3d0 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -98,7 +98,6 @@ struct mwifiex_802_11_ssid { struct mwifiex_wait_queue { wait_queue_head_t wait; - u16 condition; int status; }; @@ -114,14 +113,6 @@ struct mwifiex_txinfo { u8 bss_index; }; -struct mwifiex_bss_attr { - u8 bss_type; - u8 frame_type; - u8 active; - u8 bss_priority; - u8 bss_num; -}; - enum mwifiex_wmm_ac_e { WMM_AC_BK, WMM_AC_BE, diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 4fee0993b186..0cc5d73cb0c1 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -57,12 +57,6 @@ struct tx_packet_hdr { #define GET_FW_DEFAULT_BANDS(adapter) \ ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS) -extern u8 supported_rates_b[B_SUPPORTED_RATES]; -extern u8 supported_rates_g[G_SUPPORTED_RATES]; -extern u8 supported_rates_bg[BG_SUPPORTED_RATES]; -extern u8 supported_rates_a[A_SUPPORTED_RATES]; -extern u8 supported_rates_n[N_SUPPORTED_RATES]; - #define HostCmd_WEP_KEY_INDEX_MASK 0x3fff #define KEY_INFO_ENABLED 0x01 @@ -84,7 +78,8 @@ enum KEY_TYPE_ID { #define MAX_FIRMWARE_POLL_TRIES 100 -#define FIRMWARE_READY 0xfedc +#define FIRMWARE_READY_SDIO 0xfedc +#define FIRMWARE_READY_PCIE 0xfedcba00 enum MWIFIEX_802_11_PRIVACY_FILTER { MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL, @@ -221,7 +216,7 @@ enum MWIFIEX_802_11_WEP_STATUS { #define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5 #define HostCmd_CMD_CAU_REG_ACCESS 0x00ed #define HostCmd_CMD_SET_BSS_MODE 0x00f7 - +#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa enum ENH_PS_MODES { EN_PS = 1, @@ -821,6 +816,14 @@ struct host_cmd_ds_txpwr_cfg { __le32 mode; } __packed; +struct mwifiex_bcn_param { + u8 bssid[ETH_ALEN]; + u8 rssi; + __le32 timestamp[2]; + __le16 beacon_period; + __le16 cap_info_bitmap; +} __packed; + #define MWIFIEX_USER_SCAN_CHAN_MAX 50 #define MWIFIEX_MAX_SSID_LIST_LENGTH 10 @@ -862,13 +865,6 @@ struct mwifiex_user_scan_ssid { struct mwifiex_user_scan_cfg { /* - * Flag set to keep the previous scan table intact - * - * If set, the scan results will accumulate, replacing any previous - * matched entries for a BSS with the new scan data - */ - u8 keep_previous_scan; - /* * BSS mode to be sent in the firmware command */ u8 bss_mode; @@ -1136,6 +1132,30 @@ struct host_cmd_ds_set_bss_mode { u8 con_type; } __packed; +struct host_cmd_ds_pcie_details { + /* TX buffer descriptor ring address */ + u32 txbd_addr_lo; + u32 txbd_addr_hi; + /* TX buffer descriptor ring count */ + u32 txbd_count; + + /* RX buffer descriptor ring address */ + u32 rxbd_addr_lo; + u32 rxbd_addr_hi; + /* RX buffer descriptor ring count */ + u32 rxbd_count; + + /* Event buffer descriptor ring address */ + u32 evtbd_addr_lo; + u32 evtbd_addr_hi; + /* Event buffer descriptor ring count */ + u32 evtbd_count; + + /* Sleep cookie buffer physical address */ + u32 sleep_cookie_addr_lo; + u32 sleep_cookie_addr_hi; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -1183,6 +1203,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_rf_reg_access rf_reg; struct host_cmd_ds_pmic_reg_access pmic_reg; struct host_cmd_ds_set_bss_mode bss_mode; + struct host_cmd_ds_pcie_details pcie_host_spec; struct host_cmd_ds_802_11_eeprom_access eeprom; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 3f1559e61320..d792b3fb7c16 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -76,7 +76,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) memset(priv->curr_addr, 0xff, ETH_ALEN); priv->pkt_tx_ctrl = 0; - priv->bss_mode = NL80211_IFTYPE_STATION; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; priv->data_rate = 0; /* Initially indicate the rate as auto */ priv->is_data_rate_auto = true; priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; @@ -152,19 +152,6 @@ static int mwifiex_init_priv(struct mwifiex_private *priv) static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter) { int ret; - u32 buf_size; - struct mwifiex_bssdescriptor *temp_scan_table; - - /* Allocate buffer to store the BSSID list */ - buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP; - temp_scan_table = kzalloc(buf_size, GFP_KERNEL); - if (!temp_scan_table) { - dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n", - __func__); - return -ENOMEM; - } - - adapter->scan_table = temp_scan_table; /* Allocate command buffer */ ret = mwifiex_alloc_cmd_buffer(adapter); @@ -204,7 +191,12 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) (adapter->sleep_cfm->data); adapter->cmd_sent = false; - adapter->data_sent = true; + + if (adapter->iface_type == MWIFIEX_PCIE) + adapter->data_sent = false; + else + adapter->data_sent = true; + adapter->cmd_resp_received = false; adapter->event_received = false; adapter->data_received = false; @@ -222,14 +214,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME; adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME; - adapter->num_in_scan_table = 0; - memset(adapter->scan_table, 0, - (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP)); adapter->scan_probes = 1; - memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf)); - adapter->bcn_buf_end = adapter->bcn_buf; - adapter->multiple_dtim = 1; adapter->local_listen_interval = 0; /* default value in firmware @@ -297,6 +283,34 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) } /* + * This function releases the lock variables and frees the locks and + * associated locks. + */ +static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) +{ + struct mwifiex_private *priv; + s32 i, j; + + /* Free lists */ + list_del(&adapter->cmd_free_q); + list_del(&adapter->cmd_pending_q); + list_del(&adapter->scan_pending_q); + + for (i = 0; i < adapter->priv_num; i++) + list_del(&adapter->bss_prio_tbl[i].bss_prio_head); + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i]) { + priv = adapter->priv[i]; + for (j = 0; j < MAX_NUM_TID; ++j) + list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); + list_del(&priv->tx_ba_stream_tbl_ptr); + list_del(&priv->rx_reorder_tbl_ptr); + } + } +} + +/* * This function frees the adapter structure. * * The freeing operation is done recursively, by canceling all @@ -326,8 +340,6 @@ mwifiex_free_adapter(struct mwifiex_adapter *adapter) del_timer(&adapter->cmd_timer); dev_dbg(adapter->dev, "info: free scan table\n"); - kfree(adapter->scan_table); - adapter->scan_table = NULL; adapter->if_ops.cleanup_if(adapter); @@ -392,34 +404,6 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) } /* - * This function releases the lock variables and frees the locks and - * associated locks. - */ -void mwifiex_free_lock_list(struct mwifiex_adapter *adapter) -{ - struct mwifiex_private *priv; - s32 i, j; - - /* Free lists */ - list_del(&adapter->cmd_free_q); - list_del(&adapter->cmd_pending_q); - list_del(&adapter->scan_pending_q); - - for (i = 0; i < adapter->priv_num; i++) - list_del(&adapter->bss_prio_tbl[i].bss_prio_head); - - for (i = 0; i < adapter->priv_num; i++) { - if (adapter->priv[i]) { - priv = adapter->priv[i]; - for (j = 0; j < MAX_NUM_TID; ++j) - list_del(&priv->wmm.tid_tbl_ptr[j].ra_list); - list_del(&priv->tx_ba_stream_tbl_ptr); - list_del(&priv->rx_reorder_tbl_ptr); - } - } -} - -/* * This function initializes the firmware. * * The following operations are performed sequentially - @@ -602,11 +586,13 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter) int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, struct mwifiex_fw_image *pmfw) { - int ret, winner; + int ret; u32 poll_num = 1; + adapter->winner = 0; + /* Check if firmware is already running */ - ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner); + ret = adapter->if_ops.check_fw_status(adapter, poll_num); if (!ret) { dev_notice(adapter->dev, "WLAN FW already running! Skip FW download\n"); @@ -615,7 +601,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, poll_num = MAX_FIRMWARE_POLL_TRIES; /* Check if we are the winner for downloading FW */ - if (!winner) { + if (!adapter->winner) { dev_notice(adapter->dev, "Other interface already running!" " Skip FW download\n"); @@ -633,7 +619,7 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter, poll_fw: /* Check if the firmware is downloaded successfully or not */ - ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL); + ret = adapter->if_ops.check_fw_status(adapter, poll_num); if (ret) { dev_err(adapter->dev, "FW failed to be active in time\n"); return -1; diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index f6bcc868562f..e0b68e7c8ca2 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -134,7 +134,6 @@ struct mwifiex_ver_ext { struct mwifiex_bss_info { u32 bss_mode; struct mwifiex_802_11_ssid ssid; - u32 scan_table_idx; u32 bss_chan; u32 region_code; u32 media_connected; @@ -307,10 +306,12 @@ struct mwifiex_ds_read_eeprom { u8 value[MAX_EEPROM_DATA]; }; +#define IEEE_MAX_IE_SIZE 256 + struct mwifiex_ds_misc_gen_ie { u32 type; u32 len; - u8 ie_data[IW_CUSTOM_MAX]; + u8 ie_data[IEEE_MAX_IE_SIZE]; }; struct mwifiex_ds_misc_cmd { diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 644e2e405cb5..62b4c2938608 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -147,13 +147,12 @@ static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, u8 *ptr = rate1, *tmp; u32 i, j; - tmp = kmalloc(rate1_size, GFP_KERNEL); + tmp = kmemdup(rate1, rate1_size, GFP_KERNEL); if (!tmp) { dev_err(priv->adapter->dev, "failed to alloc tmp buf\n"); return -ENOMEM; } - memcpy(tmp, rate1, rate1_size); memset(rate1, 0, rate1_size); for (i = 0; rate2[i] && i < rate2_size; i++) { @@ -224,32 +223,6 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, } /* - * This function updates the scan entry TSF timestamps to reflect - * a new association. - */ -static void -mwifiex_update_tsf_timestamps(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *new_bss_desc) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 table_idx; - long long new_tsf_base; - signed long long tsf_delta; - - memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base)); - - tsf_delta = new_tsf_base - new_bss_desc->network_tsf; - - dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, " - "0x%016llx -> 0x%016llx\n", - new_bss_desc->network_tsf, new_tsf_base); - - for (table_idx = 0; table_idx < adapter->num_in_scan_table; - table_idx++) - adapter->scan_table[table_idx].network_tsf += tsf_delta; -} - -/* * This function appends a WAPI IE. * * This function is called from the network join command preparation routine. @@ -639,12 +612,6 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, priv->curr_bss_params.band = (u8) bss_desc->bss_band; - /* - * Adjust the timestamps in the scan table to be relative to the newly - * associated AP's TSF - */ - mwifiex_update_tsf_timestamps(priv, bss_desc); - if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) priv->curr_bss_params.wmm_enabled = true; else diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index e5fc53dc6887..67e6db7d672d 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -26,21 +26,6 @@ const char driver_version[] = "mwifiex " VERSION " (%s) "; -static struct mwifiex_bss_attr mwifiex_bss_sta[] = { - {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0}, -}; - -static int drv_mode = DRV_MODE_STA; - -/* Supported drv_mode table */ -static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { - { - .drv_mode = DRV_MODE_STA, - .intf_num = ARRAY_SIZE(mwifiex_bss_sta), - .bss_attr = mwifiex_bss_sta, - }, -}; - /* * This function registers the device and performs all the necessary * initializations. @@ -57,7 +42,6 @@ static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = { * proper cleanup before exiting. */ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, - struct mwifiex_drv_mode *drv_mode_ptr, void **padapter) { struct mwifiex_adapter *adapter; @@ -78,44 +62,20 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, goto error; adapter->priv_num = 0; - for (i = 0; i < drv_mode_ptr->intf_num; i++) { - adapter->priv[i] = NULL; - - if (!drv_mode_ptr->bss_attr[i].active) - continue; - /* Allocate memory for private structure */ - adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private), - GFP_KERNEL); - if (!adapter->priv[i]) { - dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n", - __func__, i); - goto error; - } - - adapter->priv_num++; - adapter->priv[i]->adapter = adapter; - /* Save bss_type, frame_type & bss_priority */ - adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type; - adapter->priv[i]->frame_type = - drv_mode_ptr->bss_attr[i].frame_type; - adapter->priv[i]->bss_priority = - drv_mode_ptr->bss_attr[i].bss_priority; - - if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA) - adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA; - else if (drv_mode_ptr->bss_attr[i].bss_type == - MWIFIEX_BSS_TYPE_UAP) - adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP; - - /* Save bss_index & bss_num */ - adapter->priv[i]->bss_index = i; - adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num; + /* Allocate memory for private structure */ + adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), + GFP_KERNEL); + if (!adapter->priv[0]) { + dev_err(adapter->dev, "%s: failed to alloc priv[0]\n", + __func__); + goto error; } - adapter->drv_mode = drv_mode_ptr; - if (mwifiex_init_lock_list(adapter)) - goto error; + adapter->priv_num++; + + adapter->priv[0]->adapter = adapter; + mwifiex_init_lock_list(adapter); init_timer(&adapter->cmd_timer); adapter->cmd_timer.function = mwifiex_cmd_timeout_func; @@ -126,9 +86,9 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, error: dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n"); - mwifiex_free_lock_list(adapter); - for (i = 0; i < drv_mode_ptr->intf_num; i++) + for (i = 0; i < adapter->priv_num; i++) kfree(adapter->priv[i]); + kfree(adapter); return -1; @@ -316,38 +276,6 @@ exit_main_proc: } /* - * This function initializes the software. - * - * The main work includes allocating and initializing the adapter structure - * and initializing the private structures. - */ -static int -mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops, void **padapter) -{ - int i; - struct mwifiex_drv_mode *drv_mode_ptr; - - /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */ - drv_mode_ptr = NULL; - for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) { - if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) { - drv_mode_ptr = &mwifiex_drv_mode_tbl[i]; - break; - } - } - - if (!drv_mode_ptr) { - pr_err("invalid drv_mode=%d\n", drv_mode); - return -1; - } - - if (mwifiex_register(card, if_ops, drv_mode_ptr, padapter)) - return -1; - - return 0; -} - -/* * This function frees the adapter structure. * * Additionally, this closes the netlink socket, frees the timers @@ -627,7 +555,7 @@ static const struct net_device_ops mwifiex_netdev_ops = { .ndo_set_mac_address = mwifiex_set_mac_address, .ndo_tx_timeout = mwifiex_tx_timeout, .ndo_get_stats = mwifiex_get_stats, - .ndo_set_multicast_list = mwifiex_set_multicast_list, + .ndo_set_rx_mode = mwifiex_set_multicast_list, }; /* @@ -649,8 +577,8 @@ static const struct net_device_ops mwifiex_netdev_ops = { * * In addition, the CFG80211 work queue is also created. */ -static void -mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) +void mwifiex_init_priv_params(struct mwifiex_private *priv, + struct net_device *dev) { dev->netdev_ops = &mwifiex_netdev_ops; /* Initialize private structure */ @@ -664,118 +592,6 @@ mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev) } /* - * This function adds a new logical interface. - * - * It allocates, initializes and registers the interface by performing - * the following opearations - - * - Allocate a new net device structure - * - Assign device name - * - Register the new device with CFG80211 subsystem - * - Initialize semaphore and private structure - * - Register the new device with kernel - * - Create the complete debug FS structure if configured - */ -static struct mwifiex_private *mwifiex_add_interface( - struct mwifiex_adapter *adapter, - u8 bss_index, u8 bss_type) -{ - struct net_device *dev; - struct mwifiex_private *priv; - void *mdev_priv; - - dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d", - ether_setup, 1); - if (!dev) { - dev_err(adapter->dev, "no memory available for netdevice\n"); - goto error; - } - - if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr, - adapter->priv[bss_index]) != 0) { - dev_err(adapter->dev, "cannot register netdevice with cfg80211\n"); - goto error; - } - /* Save the priv pointer in netdev */ - priv = adapter->priv[bss_index]; - mdev_priv = netdev_priv(dev); - *((unsigned long *) mdev_priv) = (unsigned long) priv; - - priv->netdev = dev; - - sema_init(&priv->async_sem, 1); - priv->scan_pending_on_block = false; - - mwifiex_init_priv_params(priv, dev); - - SET_NETDEV_DEV(dev, adapter->dev); - - /* Register network device */ - if (register_netdev(dev)) { - dev_err(adapter->dev, "cannot register virtual network device\n"); - goto error; - } - - dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name); -#ifdef CONFIG_DEBUG_FS - mwifiex_dev_debugfs_init(priv); -#endif - return priv; -error: - if (dev) - free_netdev(dev); - return NULL; -} - -/* - * This function removes a logical interface. - * - * It deregisters, resets and frees the interface by performing - * the following operations - - * - Disconnect the device if connected, send wireless event to - * notify applications. - * - Remove the debug FS structure if configured - * - Unregister the device from kernel - * - Free the net device structure - * - Cancel all works and destroy work queue - * - Unregister and free the wireless device from CFG80211 subsystem - */ -static void -mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index) -{ - struct net_device *dev; - struct mwifiex_private *priv = adapter->priv[bss_index]; - - if (!priv) - return; - dev = priv->netdev; - - if (priv->media_connected) - priv->media_connected = false; - -#ifdef CONFIG_DEBUG_FS - mwifiex_dev_debugfs_remove(priv); -#endif - /* Last reference is our one */ - dev_dbg(adapter->dev, "info: %s: refcnt = %d\n", - dev->name, netdev_refcnt_read(dev)); - - if (dev->reg_state == NETREG_REGISTERED) - unregister_netdev(dev); - - /* Clear the priv in adapter */ - priv->netdev = NULL; - if (dev) - free_netdev(dev); - - cancel_work_sync(&priv->cfg_workqueue); - flush_workqueue(priv->workqueue); - destroy_workqueue(priv->workqueue); - wiphy_unregister(priv->wdev->wiphy); - wiphy_free(priv->wdev->wiphy); - kfree(priv->wdev); -} - -/* * This function check if command is pending. */ int is_command_pending(struct mwifiex_adapter *adapter) @@ -845,19 +661,22 @@ mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter) */ int mwifiex_add_card(void *card, struct semaphore *sem, - struct mwifiex_if_ops *if_ops) + struct mwifiex_if_ops *if_ops, u8 iface_type) { - int i; struct mwifiex_adapter *adapter; + char fmt[64]; + struct mwifiex_private *priv; if (down_interruptible(sem)) goto exit_sem_err; - if (mwifiex_init_sw(card, if_ops, (void **)&adapter)) { + if (mwifiex_register(card, if_ops, (void **)&adapter)) { pr_err("%s: software init failed\n", __func__); goto err_init_sw; } + adapter->iface_type = iface_type; + adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING; adapter->surprise_removed = false; init_waitqueue_head(&adapter->init_wait_q); @@ -866,8 +685,8 @@ mwifiex_add_card(void *card, struct semaphore *sem, init_waitqueue_head(&adapter->hs_activate_wait_q); adapter->cmd_wait_q_required = false; init_waitqueue_head(&adapter->cmd_wait_q.wait); - adapter->cmd_wait_q.condition = false; adapter->cmd_wait_q.status = 0; + adapter->scan_wait_q_woken = false; adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE"); if (!adapter->workqueue) @@ -887,21 +706,37 @@ mwifiex_add_card(void *card, struct semaphore *sem, goto err_init_fw; } - /* Add interfaces */ - for (i = 0; i < adapter->drv_mode->intf_num; i++) { - if (!mwifiex_add_interface(adapter, i, - adapter->drv_mode->bss_attr[i].bss_type)) { - goto err_add_intf; - } + priv = adapter->priv[0]; + + if (mwifiex_register_cfg80211(priv) != 0) { + dev_err(adapter->dev, "cannot register netdevice" + " with cfg80211\n"); + goto err_init_fw; } + rtnl_lock(); + /* Create station interface by default */ + if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d", + NL80211_IFTYPE_STATION, NULL, NULL)) { + rtnl_unlock(); + dev_err(adapter->dev, "cannot create default station" + " interface\n"); + goto err_add_intf; + } + + rtnl_unlock(); + up(sem); + mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); + dev_notice(adapter->dev, "driver_version = %s\n", fmt); + return 0; err_add_intf: - for (i = 0; i < adapter->priv_num; i++) - mwifiex_remove_interface(adapter, i); + rtnl_lock(); + mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); + rtnl_unlock(); err_init_fw: pr_debug("info: %s: unregister device\n", __func__); adapter->if_ops.unregister_dev(adapter); @@ -956,7 +791,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) /* Stop data */ for (i = 0; i < adapter->priv_num; i++) { priv = adapter->priv[i]; - if (priv) { + if (priv && priv->netdev) { if (!netif_queue_stopped(priv->netdev)) netif_stop_queue(priv->netdev); if (netif_carrier_ok(priv->netdev)) @@ -981,9 +816,24 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) atomic_read(&adapter->cmd_pending)); } - /* Remove interface */ - for (i = 0; i < adapter->priv_num; i++) - mwifiex_remove_interface(adapter, i); + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + + if (!priv) + continue; + + rtnl_lock(); + mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); + rtnl_unlock(); + } + + priv = adapter->priv[0]; + if (!priv) + goto exit_remove; + + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + kfree(priv->wdev); mwifiex_terminate_workqueue(adapter); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 2215c3c97354..30f138b6fa4c 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -37,6 +37,7 @@ #include "ioctl.h" #include "util.h" #include "fw.h" +#include "pcie.h" extern const char driver_version[]; @@ -45,14 +46,7 @@ enum { MWIFIEX_SYNC_CMD }; -#define DRV_MODE_STA 0x1 - -struct mwifiex_drv_mode { - u16 drv_mode; - u16 intf_num; - struct mwifiex_bss_attr *bss_attr; -}; - +#define MWIFIEX_MAX_AP 64 #define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) @@ -114,6 +108,8 @@ struct mwifiex_drv_mode { #define MAX_FREQUENCY_BAND_BG 2484 +#define MWIFIEX_EVENT_HEADER_LEN 4 + struct mwifiex_dbg { u32 num_cmd_host_to_card_failure; u32 num_cmd_sleep_cfm_host_to_card_failure; @@ -163,6 +159,11 @@ enum MWIFIEX_PS_STATE { PS_STATE_SLEEP }; +enum mwifiex_iface_type { + MWIFIEX_SDIO, + MWIFIEX_PCIE, +}; + struct mwifiex_add_ba_param { u32 tx_win_size; u32 rx_win_size; @@ -180,7 +181,6 @@ struct mwifiex_ra_list_tbl { struct sk_buff_head skb_head; u8 ra[ETH_ALEN]; u32 total_pkts_size; - u32 total_pkts; u32 is_11n_enabled; }; @@ -227,27 +227,10 @@ struct ieee_types_header { u8 len; } __packed; -struct ieee_obss_scan_param { - u16 obss_scan_passive_dwell; - u16 obss_scan_active_dwell; - u16 bss_chan_width_trigger_scan_int; - u16 obss_scan_passive_total; - u16 obss_scan_active_total; - u16 bss_width_chan_trans_delay; - u16 obss_scan_active_threshold; -} __packed; - -struct ieee_types_obss_scan_param { - struct ieee_types_header ieee_hdr; - struct ieee_obss_scan_param obss_scan; -} __packed; - #define MWIFIEX_SUPPORTED_RATES 14 #define MWIFIEX_SUPPORTED_RATES_EXT 32 -#define IEEE_MAX_IE_SIZE 256 - struct ieee_types_vendor_specific { struct ieee_types_vendor_header vend_hdr; u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)]; @@ -291,8 +274,6 @@ struct mwifiex_bssdescriptor { u16 bss_co_2040_offset; u8 *bcn_ext_cap; u16 ext_cap_offset; - struct ieee_types_obss_scan_param *bcn_obss_scan; - u16 overlap_bss_offset; struct ieee_types_vendor_specific *bcn_wpa_ie; u16 wpa_offset; struct ieee_types_generic *bcn_rsn_ie; @@ -301,8 +282,6 @@ struct mwifiex_bssdescriptor { u16 wapi_offset; u8 *beacon_buf; u32 beacon_buf_size; - u32 beacon_buf_size_max; - }; struct mwifiex_current_bss_params { @@ -468,7 +447,7 @@ struct mwifiex_private { struct dentry *dfs_dev_dir; #endif u8 nick_name[16]; - struct iw_statistics w_stats; + u8 qual_level, qual_noise; u16 current_key_index; struct semaphore async_sem; u8 scan_pending_on_block; @@ -541,33 +520,38 @@ struct cmd_ctrl_node { void *data_buf; u32 wait_q_enabled; struct sk_buff *skb; + u8 *condition; + u8 cmd_wait_q_woken; }; struct mwifiex_if_ops { int (*init_if) (struct mwifiex_adapter *); void (*cleanup_if) (struct mwifiex_adapter *); - int (*check_fw_status) (struct mwifiex_adapter *, u32, int *); + int (*check_fw_status) (struct mwifiex_adapter *, u32); int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *); int (*register_dev) (struct mwifiex_adapter *); void (*unregister_dev) (struct mwifiex_adapter *); int (*enable_int) (struct mwifiex_adapter *); int (*process_int_status) (struct mwifiex_adapter *); - int (*host_to_card) (struct mwifiex_adapter *, u8, - u8 *payload, u32 pkt_len, + int (*host_to_card) (struct mwifiex_adapter *, u8, struct sk_buff *, struct mwifiex_tx_param *); int (*wakeup) (struct mwifiex_adapter *); int (*wakeup_complete) (struct mwifiex_adapter *); + /* Interface specific functions */ void (*update_mp_end_port) (struct mwifiex_adapter *, u16); void (*cleanup_mpa_buf) (struct mwifiex_adapter *); + int (*cmdrsp_complete) (struct mwifiex_adapter *, struct sk_buff *); + int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *); }; struct mwifiex_adapter { + u8 iface_type; struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM]; u8 priv_num; - struct mwifiex_drv_mode *drv_mode; const struct firmware *firmware; char fw_name[32]; + int winner; struct device *dev; bool surprise_removed; u32 fw_release_number; @@ -624,15 +608,11 @@ struct mwifiex_adapter { u32 scan_processing; u16 region_code; struct mwifiex_802_11d_domain_reg domain_reg; - struct mwifiex_bssdescriptor *scan_table; - u32 num_in_scan_table; u16 scan_probes; u32 scan_mode; u16 specific_scan_time; u16 active_scan_time; u16 passive_scan_time; - u8 bcn_buf[MAX_SCAN_BEACON_BUFFER]; - u8 *bcn_buf_end; u8 fw_bands; u8 adhoc_start_band; u8 config_bands; @@ -673,10 +653,11 @@ struct mwifiex_adapter { u32 arp_filter_size; u16 cmd_wait_q_required; struct mwifiex_wait_queue cmd_wait_q; + u8 scan_wait_q_woken; + struct cmd_ctrl_node *cmd_queued; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); -void mwifiex_free_lock_list(struct mwifiex_adapter *adapter); int mwifiex_init_fw(struct mwifiex_adapter *adapter); @@ -692,7 +673,8 @@ int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb); int mwifiex_process_event(struct mwifiex_adapter *adapter); -int mwifiex_complete_cmd(struct mwifiex_adapter *adapter); +int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node); int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, u16 cmd_action, u32 cmd_oid, void *data_buf); @@ -726,8 +708,6 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags); int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, struct sk_buff *skb, int status); -int mwifiex_recv_packet_complete(struct mwifiex_adapter *, - struct sk_buff *skb, int status); void mwifiex_clean_txrx(struct mwifiex_private *priv); u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv); void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter); @@ -757,21 +737,12 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, int mwifiex_process_sta_event(struct mwifiex_private *); void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb); int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta); -int mwifiex_scan_networks(struct mwifiex_private *priv, - const struct mwifiex_user_scan_cfg *user_scan_in); int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, struct mwifiex_scan_cmd_config *scan_cfg); void mwifiex_queue_scan_cmd(struct mwifiex_private *priv, struct cmd_ctrl_node *cmd_node); int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); -s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *ssid, u8 *bssid, - u32 mode); -s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, - u32 mode); -int mwifiex_find_best_network(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *req_ssid_bssid); s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, struct mwifiex_802_11_ssid *ssid2); int mwifiex_associate(struct mwifiex_private *priv, @@ -782,7 +753,6 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); void mwifiex_reset_connect_state(struct mwifiex_private *priv); -void mwifiex_2040_coex_event(struct mwifiex_private *priv); u8 mwifiex_band_to_radio_type(u8 band); int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac); int mwifiex_adhoc_start(struct mwifiex_private *priv, @@ -823,6 +793,8 @@ int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv, int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, struct host_cmd_ds_command *resp); int is_command_pending(struct mwifiex_adapter *adapter); +void mwifiex_init_priv_params(struct mwifiex_private *priv, + struct net_device *dev); /* * This function checks if the queuing is RA based or not. @@ -912,7 +884,7 @@ struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index); int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown); -int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *); +int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *); void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version, @@ -922,11 +894,8 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, struct net_device *dev); int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter); -int mwifiex_bss_start(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid); -int mwifiex_set_hs_params(struct mwifiex_private *priv, - u16 action, int cmd_type, - struct mwifiex_ds_hs_cfg *hscfg); +int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, + struct mwifiex_802_11_ssid *req_ssid); int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); int mwifiex_enable_hs(struct mwifiex_adapter *adapter); int mwifiex_disable_auto_ds(struct mwifiex_private *priv); @@ -934,8 +903,6 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, struct mwifiex_ds_get_signal *signal); int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate); -int mwifiex_find_best_bss(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid); int mwifiex_request_scan(struct mwifiex_private *priv, struct mwifiex_802_11_ssid *req_ssid); int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, @@ -984,12 +951,26 @@ int mwifiex_main_process(struct mwifiex_adapter *); int mwifiex_bss_set_channel(struct mwifiex_private *, struct mwifiex_chan_freq_power *cfp); -int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *, - struct mwifiex_ssid_bssid *); int mwifiex_set_radio_band_cfg(struct mwifiex_private *, struct mwifiex_ds_band_cfg *); int mwifiex_get_bss_info(struct mwifiex_private *, struct mwifiex_bss_info *); +int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, + u8 *bssid, s32 rssi, u8 *ie_buf, + size_t ie_len, u16 beacon_period, + u16 cap_info_bitmap, u8 band, + struct mwifiex_bssdescriptor *bss_desc); +int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry, + u8 *ie_buf, u32 ie_len); +int mwifiex_check_network_compatibility(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc); + +struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, + char *name, enum nl80211_iftype type, + u32 *flags, struct vif_params *params); +int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); + #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c new file mode 100644 index 000000000000..d34acf082d3a --- /dev/null +++ b/drivers/net/wireless/mwifiex/pcie.c @@ -0,0 +1,1948 @@ +/* + * Marvell Wireless LAN device driver: PCIE specific handling + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include <linux/firmware.h> + +#include "decl.h" +#include "ioctl.h" +#include "util.h" +#include "fw.h" +#include "main.h" +#include "wmm.h" +#include "11n.h" +#include "pcie.h" + +#define PCIE_VERSION "1.0" +#define DRV_NAME "Marvell mwifiex PCIe" + +static u8 user_rmmod; + +static struct mwifiex_if_ops pcie_ops; + +static struct semaphore add_remove_card_sem; +static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter); +static int mwifiex_pcie_resume(struct pci_dev *pdev); + +/* + * This function is called after skb allocation to update + * "skb->cb" with physical address of data pointer. + */ +static phys_addr_t *mwifiex_update_sk_buff_pa(struct sk_buff *skb) +{ + phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb); + + *buf_pa = (phys_addr_t)virt_to_phys(skb->data); + + return buf_pa; +} + +/* + * This function reads sleep cookie and checks if FW is ready + */ +static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) +{ + u32 *cookie_addr; + struct pcie_service_card *card = adapter->card; + + if (card->sleep_cookie) { + cookie_addr = (u32 *)card->sleep_cookie->data; + dev_dbg(adapter->dev, "info: ACCESS_HW: sleep cookie=0x%x\n", + *cookie_addr); + if (*cookie_addr == FW_AWAKE_COOKIE) + return true; + } + + return false; +} + +/* + * This function probes an mwifiex device and registers it. It allocates + * the card structure, enables PCIE function number and initiates the + * device registration and initialization procedure by adding a logical + * interface. + */ +static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct pcie_service_card *card; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", + pdev->vendor, pdev->device, pdev->revision); + + card = kzalloc(sizeof(struct pcie_service_card), GFP_KERNEL); + if (!card) { + pr_err("%s: failed to alloc memory\n", __func__); + return -ENOMEM; + } + + card->dev = pdev; + + if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops, + MWIFIEX_PCIE)) { + pr_err("%s failed\n", __func__); + kfree(card); + return -1; + } + + return 0; +} + +/* + * This function removes the interface and frees up the card structure. + */ +static void mwifiex_pcie_remove(struct pci_dev *pdev) +{ + struct pcie_service_card *card; + struct mwifiex_adapter *adapter; + int i; + + card = pci_get_drvdata(pdev); + if (!card) + return; + + adapter = card->adapter; + if (!adapter || !adapter->priv_num) + return; + + if (user_rmmod) { +#ifdef CONFIG_PM + if (adapter->is_suspended) + mwifiex_pcie_resume(pdev); +#endif + + for (i = 0; i < adapter->priv_num; i++) + if ((GET_BSS_ROLE(adapter->priv[i]) == + MWIFIEX_BSS_ROLE_STA) && + adapter->priv[i]->media_connected) + mwifiex_deauthenticate(adapter->priv[i], NULL); + + mwifiex_disable_auto_ds(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY)); + + mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY), + MWIFIEX_FUNC_SHUTDOWN); + } + + mwifiex_remove_card(card->adapter, &add_remove_card_sem); + kfree(card); +} + +/* + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not suspended, this function allocates and sends a host + * sleep activate request to the firmware and turns off the traffic. + */ +static int mwifiex_pcie_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct mwifiex_adapter *adapter; + struct pcie_service_card *card; + int hs_actived, i; + + if (pdev) { + card = (struct pcie_service_card *) pci_get_drvdata(pdev); + if (!card || card->adapter) { + pr_err("Card or adapter structure is not valid\n"); + return 0; + } + } else { + pr_err("PCIE device is not specified\n"); + return 0; + } + + adapter = card->adapter; + + hs_actived = mwifiex_enable_hs(adapter); + + /* Indicate device suspended */ + adapter->is_suspended = true; + + for (i = 0; i < adapter->priv_num; i++) + netif_carrier_off(adapter->priv[i]->netdev); + + return 0; +} + +/* + * Kernel needs to suspend all functions separately. Therefore all + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * + * If already not resumed, this function turns on the traffic and + * sends a host sleep cancel request to the firmware. + */ +static int mwifiex_pcie_resume(struct pci_dev *pdev) +{ + struct mwifiex_adapter *adapter; + struct pcie_service_card *card; + int i; + + if (pdev) { + card = (struct pcie_service_card *) pci_get_drvdata(pdev); + if (!card || !card->adapter) { + pr_err("Card or adapter structure is not valid\n"); + return 0; + } + } else { + pr_err("PCIE device is not specified\n"); + return 0; + } + + adapter = card->adapter; + + if (!adapter->is_suspended) { + dev_warn(adapter->dev, "Device already resumed\n"); + return 0; + } + + adapter->is_suspended = false; + + for (i = 0; i < adapter->priv_num; i++) + if (adapter->priv[i]->media_connected) + netif_carrier_on(adapter->priv[i]->netdev); + + mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), + MWIFIEX_ASYNC_CMD); + + return 0; +} + +#define PCIE_VENDOR_ID_MARVELL (0x11ab) +#define PCIE_DEVICE_ID_MARVELL_88W8766P (0x2b30) + +static DEFINE_PCI_DEVICE_TABLE(mwifiex_ids) = { + { + PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + }, + {}, +}; + +MODULE_DEVICE_TABLE(pci, mwifiex_ids); + +/* PCI Device Driver */ +static struct pci_driver __refdata mwifiex_pcie = { + .name = "mwifiex_pcie", + .id_table = mwifiex_ids, + .probe = mwifiex_pcie_probe, + .remove = mwifiex_pcie_remove, +#ifdef CONFIG_PM + /* Power Management Hooks */ + .suspend = mwifiex_pcie_suspend, + .resume = mwifiex_pcie_resume, +#endif +}; + +/* + * This function writes data into PCIE card register. + */ +static int mwifiex_write_reg(struct mwifiex_adapter *adapter, int reg, u32 data) +{ + struct pcie_service_card *card = adapter->card; + + iowrite32(data, card->pci_mmap1 + reg); + + return 0; +} + +/* + * This function reads data from PCIE card register. + */ +static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data) +{ + struct pcie_service_card *card = adapter->card; + + *data = ioread32(card->pci_mmap1 + reg); + + return 0; +} + +/* + * This function wakes up the card. + * + * A host power up command is written to the card configuration + * register to wake up the card. + */ +static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter) +{ + int i = 0; + + while (mwifiex_pcie_ok_to_access_hw(adapter)) { + i++; + udelay(10); + /* 50ms max wait */ + if (i == 50000) + break; + } + + dev_dbg(adapter->dev, "event: Wakeup device...\n"); + + /* Enable interrupts or any chip access will wakeup device */ + if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, HOST_INTR_MASK)) { + dev_warn(adapter->dev, "Enable host interrupt failed\n"); + return -1; + } + + dev_dbg(adapter->dev, "PCIE wakeup: Setting PS_STATE_AWAKE\n"); + adapter->ps_state = PS_STATE_AWAKE; + + return 0; +} + +/* + * This function is called after the card has woken up. + * + * The card configuration register is reset. + */ +static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter) +{ + dev_dbg(adapter->dev, "cmd: Wakeup device completed\n"); + + return 0; +} + +/* + * This function disables the host interrupt. + * + * The host interrupt mask is read, the disable bit is reset and + * written back to the card host interrupt mask register. + */ +static int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter) +{ + if (mwifiex_pcie_ok_to_access_hw(adapter)) { + if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, + 0x00000000)) { + dev_warn(adapter->dev, "Disable host interrupt failed\n"); + return -1; + } + } + + return 0; +} + +/* + * This function enables the host interrupt. + * + * The host interrupt enable mask is written to the card + * host interrupt mask register. + */ +static int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter) +{ + if (mwifiex_pcie_ok_to_access_hw(adapter)) { + /* Simply write the mask to the register */ + if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK, + HOST_INTR_MASK)) { + dev_warn(adapter->dev, "Enable host interrupt failed\n"); + return -1; + } + } + + return 0; +} + +/* + * This function creates buffer descriptor ring for TX + */ +static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + struct sk_buff *skb; + int i; + phys_addr_t *buf_pa; + + /* + * driver maintaines the write pointer and firmware maintaines the read + * pointer. The write pointer starts at 0 (zero) while the read pointer + * starts at zero with rollover bit set + */ + card->txbd_wrptr = 0; + card->txbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; + + /* allocate shared memory for the BD ring and divide the same in to + several descriptors */ + card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * + MWIFIEX_MAX_TXRX_BD; + dev_dbg(adapter->dev, "info: txbd_ring: Allocating %d bytes\n", + card->txbd_ring_size); + card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL); + if (!card->txbd_ring_vbase) { + dev_err(adapter->dev, "Unable to allocate buffer for txbd ring.\n"); + kfree(card->txbd_ring_vbase); + return -1; + } + card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase); + + dev_dbg(adapter->dev, "info: txbd_ring - base: %p, pbase: %#x:%x," + "len: %x\n", card->txbd_ring_vbase, + (u32)card->txbd_ring_pbase, + (u32)((u64)card->txbd_ring_pbase >> 32), + card->txbd_ring_size); + + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + card->txbd_ring[i] = (struct mwifiex_pcie_buf_desc *) + (card->txbd_ring_vbase + + (sizeof(struct mwifiex_pcie_buf_desc) * i)); + + /* Allocate buffer here so that firmware can DMA data from it */ + skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); + if (!skb) { + dev_err(adapter->dev, "Unable to allocate skb for TX ring.\n"); + kfree(card->txbd_ring_vbase); + return -ENOMEM; + } + buf_pa = mwifiex_update_sk_buff_pa(skb); + + skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE); + dev_dbg(adapter->dev, "info: TX ring: add new skb base: %p, " + "buf_base: %p, buf_pbase: %#x:%x, " + "buf_len: %#x\n", skb, skb->data, + (u32)*buf_pa, (u32)(((u64)*buf_pa >> 32)), + skb->len); + + card->tx_buf_list[i] = skb; + card->txbd_ring[i]->paddr = *buf_pa; + card->txbd_ring[i]->len = (u16)skb->len; + card->txbd_ring[i]->flags = 0; + } + + return 0; +} + +static int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + int i; + + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + if (card->tx_buf_list[i]) + dev_kfree_skb_any(card->tx_buf_list[i]); + card->tx_buf_list[i] = NULL; + card->txbd_ring[i]->paddr = 0; + card->txbd_ring[i]->len = 0; + card->txbd_ring[i]->flags = 0; + card->txbd_ring[i] = NULL; + } + + kfree(card->txbd_ring_vbase); + card->txbd_ring_size = 0; + card->txbd_wrptr = 0; + card->txbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->txbd_ring_vbase = NULL; + + return 0; +} + +/* + * This function creates buffer descriptor ring for RX + */ +static int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + struct sk_buff *skb; + int i; + phys_addr_t *buf_pa; + + /* + * driver maintaines the read pointer and firmware maintaines the write + * pointer. The write pointer starts at 0 (zero) while the read pointer + * starts at zero with rollover bit set + */ + card->rxbd_wrptr = 0; + card->rxbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; + + card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * + MWIFIEX_MAX_TXRX_BD; + dev_dbg(adapter->dev, "info: rxbd_ring: Allocating %d bytes\n", + card->rxbd_ring_size); + card->rxbd_ring_vbase = kzalloc(card->rxbd_ring_size, GFP_KERNEL); + if (!card->rxbd_ring_vbase) { + dev_err(adapter->dev, "Unable to allocate buffer for " + "rxbd_ring.\n"); + return -1; + } + card->rxbd_ring_pbase = virt_to_phys(card->rxbd_ring_vbase); + + dev_dbg(adapter->dev, "info: rxbd_ring - base: %p, pbase: %#x:%x," + "len: %#x\n", card->rxbd_ring_vbase, + (u32)card->rxbd_ring_pbase, + (u32)((u64)card->rxbd_ring_pbase >> 32), + card->rxbd_ring_size); + + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + card->rxbd_ring[i] = (struct mwifiex_pcie_buf_desc *) + (card->rxbd_ring_vbase + + (sizeof(struct mwifiex_pcie_buf_desc) * i)); + + /* Allocate skb here so that firmware can DMA data from it */ + skb = dev_alloc_skb(MWIFIEX_RX_DATA_BUF_SIZE); + if (!skb) { + dev_err(adapter->dev, "Unable to allocate skb for RX ring.\n"); + kfree(card->rxbd_ring_vbase); + return -ENOMEM; + } + buf_pa = mwifiex_update_sk_buff_pa(skb); + skb_put(skb, MWIFIEX_RX_DATA_BUF_SIZE); + + dev_dbg(adapter->dev, "info: RX ring: add new skb base: %p, " + "buf_base: %p, buf_pbase: %#x:%x, " + "buf_len: %#x\n", skb, skb->data, + (u32)*buf_pa, (u32)((u64)*buf_pa >> 32), + skb->len); + + card->rx_buf_list[i] = skb; + card->rxbd_ring[i]->paddr = *buf_pa; + card->rxbd_ring[i]->len = (u16)skb->len; + card->rxbd_ring[i]->flags = 0; + } + + return 0; +} + +/* + * This function deletes Buffer descriptor ring for RX + */ +static int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + int i; + + for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) { + if (card->rx_buf_list[i]) + dev_kfree_skb_any(card->rx_buf_list[i]); + card->rx_buf_list[i] = NULL; + card->rxbd_ring[i]->paddr = 0; + card->rxbd_ring[i]->len = 0; + card->rxbd_ring[i]->flags = 0; + card->rxbd_ring[i] = NULL; + } + + kfree(card->rxbd_ring_vbase); + card->rxbd_ring_size = 0; + card->rxbd_wrptr = 0; + card->rxbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->rxbd_ring_vbase = NULL; + + return 0; +} + +/* + * This function creates buffer descriptor ring for Events + */ +static int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + struct sk_buff *skb; + int i; + phys_addr_t *buf_pa; + + /* + * driver maintaines the read pointer and firmware maintaines the write + * pointer. The write pointer starts at 0 (zero) while the read pointer + * starts at zero with rollover bit set + */ + card->evtbd_wrptr = 0; + card->evtbd_rdptr |= MWIFIEX_BD_FLAG_ROLLOVER_IND; + + card->evtbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) * + MWIFIEX_MAX_EVT_BD; + dev_dbg(adapter->dev, "info: evtbd_ring: Allocating %d bytes\n", + card->evtbd_ring_size); + card->evtbd_ring_vbase = kzalloc(card->evtbd_ring_size, GFP_KERNEL); + if (!card->evtbd_ring_vbase) { + dev_err(adapter->dev, "Unable to allocate buffer. " + "Terminating download\n"); + return -1; + } + card->evtbd_ring_pbase = virt_to_phys(card->evtbd_ring_vbase); + + dev_dbg(adapter->dev, "info: CMDRSP/EVT bd_ring - base: %p, " + "pbase: %#x:%x, len: %#x\n", card->evtbd_ring_vbase, + (u32)card->evtbd_ring_pbase, + (u32)((u64)card->evtbd_ring_pbase >> 32), + card->evtbd_ring_size); + + for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { + card->evtbd_ring[i] = (struct mwifiex_pcie_buf_desc *) + (card->evtbd_ring_vbase + + (sizeof(struct mwifiex_pcie_buf_desc) * i)); + + /* Allocate skb here so that firmware can DMA data from it */ + skb = dev_alloc_skb(MAX_EVENT_SIZE); + if (!skb) { + dev_err(adapter->dev, "Unable to allocate skb for EVENT buf.\n"); + kfree(card->evtbd_ring_vbase); + return -ENOMEM; + } + buf_pa = mwifiex_update_sk_buff_pa(skb); + skb_put(skb, MAX_EVENT_SIZE); + + dev_dbg(adapter->dev, "info: Evt ring: add new skb. base: %p, " + "buf_base: %p, buf_pbase: %#x:%x, " + "buf_len: %#x\n", skb, skb->data, + (u32)*buf_pa, (u32)((u64)*buf_pa >> 32), + skb->len); + + card->evt_buf_list[i] = skb; + card->evtbd_ring[i]->paddr = *buf_pa; + card->evtbd_ring[i]->len = (u16)skb->len; + card->evtbd_ring[i]->flags = 0; + } + + return 0; +} + +/* + * This function deletes Buffer descriptor ring for Events + */ +static int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + int i; + + for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) { + if (card->evt_buf_list[i]) + dev_kfree_skb_any(card->evt_buf_list[i]); + card->evt_buf_list[i] = NULL; + card->evtbd_ring[i]->paddr = 0; + card->evtbd_ring[i]->len = 0; + card->evtbd_ring[i]->flags = 0; + card->evtbd_ring[i] = NULL; + } + + kfree(card->evtbd_ring_vbase); + card->evtbd_wrptr = 0; + card->evtbd_rdptr = 0 | MWIFIEX_BD_FLAG_ROLLOVER_IND; + card->evtbd_ring_size = 0; + card->evtbd_ring_vbase = NULL; + + return 0; +} + +/* + * This function allocates a buffer for CMDRSP + */ +static int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + struct sk_buff *skb; + + /* Allocate memory for receiving command response data */ + skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE); + if (!skb) { + dev_err(adapter->dev, "Unable to allocate skb for command " + "response data.\n"); + return -ENOMEM; + } + mwifiex_update_sk_buff_pa(skb); + skb_put(skb, MWIFIEX_UPLD_SIZE); + card->cmdrsp_buf = skb; + + skb = NULL; + /* Allocate memory for sending command to firmware */ + skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER); + if (!skb) { + dev_err(adapter->dev, "Unable to allocate skb for command " + "data.\n"); + return -ENOMEM; + } + mwifiex_update_sk_buff_pa(skb); + skb_put(skb, MWIFIEX_SIZE_OF_CMD_BUFFER); + card->cmd_buf = skb; + + return 0; +} + +/* + * This function deletes a buffer for CMDRSP + */ +static int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card; + + if (!adapter) + return 0; + + card = adapter->card; + + if (card && card->cmdrsp_buf) + dev_kfree_skb_any(card->cmdrsp_buf); + + if (card && card->cmd_buf) + dev_kfree_skb_any(card->cmd_buf); + + return 0; +} + +/* + * This function allocates a buffer for sleep cookie + */ +static int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter) +{ + struct sk_buff *skb; + struct pcie_service_card *card = adapter->card; + + /* Allocate memory for sleep cookie */ + skb = dev_alloc_skb(sizeof(u32)); + if (!skb) { + dev_err(adapter->dev, "Unable to allocate skb for sleep " + "cookie!\n"); + return -ENOMEM; + } + mwifiex_update_sk_buff_pa(skb); + skb_put(skb, sizeof(u32)); + + /* Init val of Sleep Cookie */ + *(u32 *)skb->data = FW_AWAKE_COOKIE; + + dev_dbg(adapter->dev, "alloc_scook: sleep cookie=0x%x\n", + *((u32 *)skb->data)); + + /* Save the sleep cookie */ + card->sleep_cookie = skb; + + return 0; +} + +/* + * This function deletes buffer for sleep cookie + */ +static int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card; + + if (!adapter) + return 0; + + card = adapter->card; + + if (card && card->sleep_cookie) { + dev_kfree_skb_any(card->sleep_cookie); + card->sleep_cookie = NULL; + } + + return 0; +} + +/* + * This function sends data buffer to device + */ +static int +mwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb) +{ + struct pcie_service_card *card = adapter->card; + u32 wrindx, rdptr; + phys_addr_t *buf_pa; + __le16 *tmp; + + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + mwifiex_pm_wakeup_card(adapter); + + /* Read the TX ring read pointer set by firmware */ + if (mwifiex_read_reg(adapter, REG_TXBD_RDPTR, &rdptr)) { + dev_err(adapter->dev, "SEND DATA: failed to read " + "REG_TXBD_RDPTR\n"); + return -1; + } + + wrindx = card->txbd_wrptr & MWIFIEX_TXBD_MASK; + + dev_dbg(adapter->dev, "info: SEND DATA: <Rd: %#x, Wr: %#x>\n", rdptr, + card->txbd_wrptr); + if (((card->txbd_wrptr & MWIFIEX_TXBD_MASK) != + (rdptr & MWIFIEX_TXBD_MASK)) || + ((card->txbd_wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) != + (rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { + struct sk_buff *skb_data; + u8 *payload; + + adapter->data_sent = true; + skb_data = card->tx_buf_list[wrindx]; + memcpy(skb_data->data, skb->data, skb->len); + payload = skb_data->data; + tmp = (__le16 *)&payload[0]; + *tmp = cpu_to_le16((u16)skb->len); + tmp = (__le16 *)&payload[2]; + *tmp = cpu_to_le16(MWIFIEX_TYPE_DATA); + skb_put(skb_data, MWIFIEX_RX_DATA_BUF_SIZE - skb_data->len); + skb_trim(skb_data, skb->len); + buf_pa = MWIFIEX_SKB_PACB(skb_data); + card->txbd_ring[wrindx]->paddr = *buf_pa; + card->txbd_ring[wrindx]->len = (u16)skb_data->len; + card->txbd_ring[wrindx]->flags = MWIFIEX_BD_FLAG_FIRST_DESC | + MWIFIEX_BD_FLAG_LAST_DESC; + + if ((++card->txbd_wrptr & MWIFIEX_TXBD_MASK) == + MWIFIEX_MAX_TXRX_BD) + card->txbd_wrptr = ((card->txbd_wrptr & + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ + MWIFIEX_BD_FLAG_ROLLOVER_IND); + + /* Write the TX ring write pointer in to REG_TXBD_WRPTR */ + if (mwifiex_write_reg(adapter, REG_TXBD_WRPTR, + card->txbd_wrptr)) { + dev_err(adapter->dev, "SEND DATA: failed to write " + "REG_TXBD_WRPTR\n"); + return 0; + } + + /* Send the TX ready interrupt */ + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_DNLD_RDY)) { + dev_err(adapter->dev, "SEND DATA: failed to assert " + "door-bell interrupt.\n"); + return -1; + } + dev_dbg(adapter->dev, "info: SEND DATA: Updated <Rd: %#x, Wr: " + "%#x> and sent packet to firmware " + "successfully\n", rdptr, + card->txbd_wrptr); + } else { + dev_dbg(adapter->dev, "info: TX Ring full, can't send anymore " + "packets to firmware\n"); + adapter->data_sent = true; + /* Send the TX ready interrupt */ + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_DNLD_RDY)) + dev_err(adapter->dev, "SEND DATA: failed to assert " + "door-bell interrupt\n"); + return -EBUSY; + } + + return 0; +} + +/* + * This function handles received buffer ring and + * dispatches packets to upper + */ +static int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + u32 wrptr, rd_index; + int ret = 0; + struct sk_buff *skb_tmp = NULL; + + /* Read the RX ring Write pointer set by firmware */ + if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { + dev_err(adapter->dev, "RECV DATA: failed to read " + "REG_TXBD_RDPTR\n"); + ret = -1; + goto done; + } + + while (((wrptr & MWIFIEX_RXBD_MASK) != + (card->rxbd_rdptr & MWIFIEX_RXBD_MASK)) || + ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == + (card->rxbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { + struct sk_buff *skb_data; + u16 rx_len; + + rd_index = card->rxbd_rdptr & MWIFIEX_RXBD_MASK; + skb_data = card->rx_buf_list[rd_index]; + + /* Get data length from interface header - + first byte is len, second byte is type */ + rx_len = *((u16 *)skb_data->data); + dev_dbg(adapter->dev, "info: RECV DATA: Rd=%#x, Wr=%#x, " + "Len=%d\n", card->rxbd_rdptr, wrptr, rx_len); + skb_tmp = dev_alloc_skb(rx_len); + if (!skb_tmp) { + dev_dbg(adapter->dev, "info: Failed to alloc skb " + "for RX\n"); + ret = -EBUSY; + goto done; + } + + skb_put(skb_tmp, rx_len); + + memcpy(skb_tmp->data, skb_data->data + INTF_HEADER_LEN, rx_len); + if ((++card->rxbd_rdptr & MWIFIEX_RXBD_MASK) == + MWIFIEX_MAX_TXRX_BD) { + card->rxbd_rdptr = ((card->rxbd_rdptr & + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ + MWIFIEX_BD_FLAG_ROLLOVER_IND); + } + dev_dbg(adapter->dev, "info: RECV DATA: <Rd: %#x, Wr: %#x>\n", + card->rxbd_rdptr, wrptr); + + /* Write the RX ring read pointer in to REG_RXBD_RDPTR */ + if (mwifiex_write_reg(adapter, REG_RXBD_RDPTR, + card->rxbd_rdptr)) { + dev_err(adapter->dev, "RECV DATA: failed to " + "write REG_RXBD_RDPTR\n"); + ret = -1; + goto done; + } + + /* Read the RX ring Write pointer set by firmware */ + if (mwifiex_read_reg(adapter, REG_RXBD_WRPTR, &wrptr)) { + dev_err(adapter->dev, "RECV DATA: failed to read " + "REG_TXBD_RDPTR\n"); + ret = -1; + goto done; + } + dev_dbg(adapter->dev, "info: RECV DATA: Received packet from " + "firmware successfully\n"); + mwifiex_handle_rx_packet(adapter, skb_tmp); + } + +done: + if (ret && skb_tmp) + dev_kfree_skb_any(skb_tmp); + return ret; +} + +/* + * This function downloads the boot command to device + */ +static int +mwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) +{ + phys_addr_t *buf_pa = MWIFIEX_SKB_PACB(skb); + + if (!(skb->data && skb->len && *buf_pa)) { + dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x:%x, " + "%x>\n", __func__, skb->data, skb->len, + (u32)*buf_pa, (u32)((u64)*buf_pa >> 32)); + return -1; + } + + /* Write the lower 32bits of the physical address to scratch + * register 0 */ + if (mwifiex_write_reg(adapter, PCIE_SCRATCH_0_REG, (u32)*buf_pa)) { + dev_err(adapter->dev, "%s: failed to write download command " + "to boot code.\n", __func__); + return -1; + } + + /* Write the upper 32bits of the physical address to scratch + * register 1 */ + if (mwifiex_write_reg(adapter, PCIE_SCRATCH_1_REG, + (u32)((u64)*buf_pa >> 32))) { + dev_err(adapter->dev, "%s: failed to write download command " + "to boot code.\n", __func__); + return -1; + } + + /* Write the command length to scratch register 2 */ + if (mwifiex_write_reg(adapter, PCIE_SCRATCH_2_REG, skb->len)) { + dev_err(adapter->dev, "%s: failed to write command length to " + "scratch register 2\n", __func__); + return -1; + } + + /* Ring the door bell */ + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_DOOR_BELL)) { + dev_err(adapter->dev, "%s: failed to assert door-bell " + "interrupt.\n", __func__); + return -1; + } + + return 0; +} + +/* + * This function downloads commands to the device + */ +static int +mwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb) +{ + struct pcie_service_card *card = adapter->card; + int ret = 0; + phys_addr_t *cmd_buf_pa; + phys_addr_t *cmdrsp_buf_pa; + + if (!(skb->data && skb->len)) { + dev_err(adapter->dev, "Invalid parameter in %s <%p, %#x>\n", + __func__, skb->data, skb->len); + return -1; + } + + /* Make sure a command response buffer is available */ + if (!card->cmdrsp_buf) { + dev_err(adapter->dev, "No response buffer available, send " + "command failed\n"); + return -EBUSY; + } + + /* Make sure a command buffer is available */ + if (!card->cmd_buf) { + dev_err(adapter->dev, "Command buffer not available\n"); + return -EBUSY; + } + + adapter->cmd_sent = true; + /* Copy the given skb in to DMA accessable shared buffer */ + skb_put(card->cmd_buf, MWIFIEX_SIZE_OF_CMD_BUFFER - card->cmd_buf->len); + skb_trim(card->cmd_buf, skb->len); + memcpy(card->cmd_buf->data, skb->data, skb->len); + + /* To send a command, the driver will: + 1. Write the 64bit physical address of the data buffer to + SCRATCH1 + SCRATCH0 + 2. Ring the door bell (i.e. set the door bell interrupt) + + In response to door bell interrupt, the firmware will perform + the DMA of the command packet (first header to obtain the total + length and then rest of the command). + */ + + if (card->cmdrsp_buf) { + cmdrsp_buf_pa = MWIFIEX_SKB_PACB(card->cmdrsp_buf); + /* Write the lower 32bits of the cmdrsp buffer physical + address */ + if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, + (u32)*cmdrsp_buf_pa)) { + dev_err(adapter->dev, "Failed to write download command to boot code.\n"); + ret = -1; + goto done; + } + /* Write the upper 32bits of the cmdrsp buffer physical + address */ + if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, + (u32)((u64)*cmdrsp_buf_pa >> 32))) { + dev_err(adapter->dev, "Failed to write download command" + " to boot code.\n"); + ret = -1; + goto done; + } + } + + cmd_buf_pa = MWIFIEX_SKB_PACB(card->cmd_buf); + /* Write the lower 32bits of the physical address to REG_CMD_ADDR_LO */ + if (mwifiex_write_reg(adapter, REG_CMD_ADDR_LO, + (u32)*cmd_buf_pa)) { + dev_err(adapter->dev, "Failed to write download command " + "to boot code.\n"); + ret = -1; + goto done; + } + /* Write the upper 32bits of the physical address to REG_CMD_ADDR_HI */ + if (mwifiex_write_reg(adapter, REG_CMD_ADDR_HI, + (u32)((u64)*cmd_buf_pa >> 32))) { + dev_err(adapter->dev, "Failed to write download command " + "to boot code.\n"); + ret = -1; + goto done; + } + + /* Write the command length to REG_CMD_SIZE */ + if (mwifiex_write_reg(adapter, REG_CMD_SIZE, + card->cmd_buf->len)) { + dev_err(adapter->dev, "Failed to write command length to " + "REG_CMD_SIZE\n"); + ret = -1; + goto done; + } + + /* Ring the door bell */ + if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, + CPU_INTR_DOOR_BELL)) { + dev_err(adapter->dev, "Failed to assert door-bell " + "interrupt.\n"); + ret = -1; + goto done; + } + +done: + if (ret) + adapter->cmd_sent = false; + + return 0; +} + +/* + * This function handles command complete interrupt + */ +static int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + int count = 0; + + dev_dbg(adapter->dev, "info: Rx CMD Response\n"); + + if (!adapter->curr_cmd) { + skb_pull(card->cmdrsp_buf, INTF_HEADER_LEN); + if (adapter->ps_state == PS_STATE_SLEEP_CFM) { + mwifiex_process_sleep_confirm_resp(adapter, + card->cmdrsp_buf->data, + card->cmdrsp_buf->len); + while (mwifiex_pcie_ok_to_access_hw(adapter) && + (count++ < 10)) + udelay(50); + } else { + dev_err(adapter->dev, "There is no command but " + "got cmdrsp\n"); + } + memcpy(adapter->upld_buf, card->cmdrsp_buf->data, + min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, + card->cmdrsp_buf->len)); + skb_push(card->cmdrsp_buf, INTF_HEADER_LEN); + } else if (mwifiex_pcie_ok_to_access_hw(adapter)) { + skb_pull(card->cmdrsp_buf, INTF_HEADER_LEN); + adapter->curr_cmd->resp_skb = card->cmdrsp_buf; + adapter->cmd_resp_received = true; + /* Take the pointer and set it to CMD node and will + return in the response complete callback */ + card->cmdrsp_buf = NULL; + + /* Clear the cmd-rsp buffer address in scratch registers. This + will prevent firmware from writing to the same response + buffer again. */ + if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_LO, 0)) { + dev_err(adapter->dev, "cmd_done: failed to clear " + "cmd_rsp address.\n"); + return -1; + } + /* Write the upper 32bits of the cmdrsp buffer physical + address */ + if (mwifiex_write_reg(adapter, REG_CMDRSP_ADDR_HI, 0)) { + dev_err(adapter->dev, "cmd_done: failed to clear " + "cmd_rsp address.\n"); + return -1; + } + } + + return 0; +} + +/* + * Command Response processing complete handler + */ +static int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + struct pcie_service_card *card = adapter->card; + + if (skb) { + card->cmdrsp_buf = skb; + skb_push(card->cmdrsp_buf, INTF_HEADER_LEN); + } + + return 0; +} + +/* + * This function handles firmware event ready interrupt + */ +static int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; + u32 wrptr, event; + + if (adapter->event_received) { + dev_dbg(adapter->dev, "info: Event being processed, "\ + "do not process this interrupt just yet\n"); + return 0; + } + + if (rdptr >= MWIFIEX_MAX_EVT_BD) { + dev_dbg(adapter->dev, "info: Invalid read pointer...\n"); + return -1; + } + + /* Read the event ring write pointer set by firmware */ + if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { + dev_err(adapter->dev, "EventReady: failed to read REG_EVTBD_WRPTR\n"); + return -1; + } + + dev_dbg(adapter->dev, "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>", + card->evtbd_rdptr, wrptr); + if (((wrptr & MWIFIEX_EVTBD_MASK) != + (card->evtbd_rdptr & MWIFIEX_EVTBD_MASK)) || + ((wrptr & MWIFIEX_BD_FLAG_ROLLOVER_IND) == + (card->evtbd_rdptr & MWIFIEX_BD_FLAG_ROLLOVER_IND))) { + struct sk_buff *skb_cmd; + __le16 data_len = 0; + u16 evt_len; + + dev_dbg(adapter->dev, "info: Read Index: %d\n", rdptr); + skb_cmd = card->evt_buf_list[rdptr]; + /* Take the pointer and set it to event pointer in adapter + and will return back after event handling callback */ + card->evt_buf_list[rdptr] = NULL; + card->evtbd_ring[rdptr]->paddr = 0; + card->evtbd_ring[rdptr]->len = 0; + card->evtbd_ring[rdptr]->flags = 0; + + event = *(u32 *) &skb_cmd->data[INTF_HEADER_LEN]; + adapter->event_cause = event; + /* The first 4bytes will be the event transfer header + len is 2 bytes followed by type which is 2 bytes */ + memcpy(&data_len, skb_cmd->data, sizeof(__le16)); + evt_len = le16_to_cpu(data_len); + + skb_pull(skb_cmd, INTF_HEADER_LEN); + dev_dbg(adapter->dev, "info: Event length: %d\n", evt_len); + + if ((evt_len > 0) && (evt_len < MAX_EVENT_SIZE)) + memcpy(adapter->event_body, skb_cmd->data + + MWIFIEX_EVENT_HEADER_LEN, evt_len - + MWIFIEX_EVENT_HEADER_LEN); + + adapter->event_received = true; + adapter->event_skb = skb_cmd; + + /* Do not update the event read pointer here, wait till the + buffer is released. This is just to make things simpler, + we need to find a better method of managing these buffers. + */ + } + + return 0; +} + +/* + * Event processing complete handler + */ +static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + struct pcie_service_card *card = adapter->card; + int ret = 0; + u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK; + u32 wrptr; + phys_addr_t *buf_pa; + + if (!skb) + return 0; + + if (rdptr >= MWIFIEX_MAX_EVT_BD) + dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n", + rdptr); + + /* Read the event ring write pointer set by firmware */ + if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) { + dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_WRPTR\n"); + ret = -1; + goto done; + } + + if (!card->evt_buf_list[rdptr]) { + skb_push(skb, INTF_HEADER_LEN); + card->evt_buf_list[rdptr] = skb; + buf_pa = MWIFIEX_SKB_PACB(skb); + card->evtbd_ring[rdptr]->paddr = *buf_pa; + card->evtbd_ring[rdptr]->len = (u16)skb->len; + card->evtbd_ring[rdptr]->flags = 0; + skb = NULL; + } else { + dev_dbg(adapter->dev, "info: ERROR: Buffer is still valid at " + "index %d, <%p, %p>\n", rdptr, + card->evt_buf_list[rdptr], skb); + } + + if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) { + card->evtbd_rdptr = ((card->evtbd_rdptr & + MWIFIEX_BD_FLAG_ROLLOVER_IND) ^ + MWIFIEX_BD_FLAG_ROLLOVER_IND); + } + + dev_dbg(adapter->dev, "info: Updated <Rd: 0x%x, Wr: 0x%x>", + card->evtbd_rdptr, wrptr); + + /* Write the event ring read pointer in to REG_EVTBD_RDPTR */ + if (mwifiex_write_reg(adapter, REG_EVTBD_RDPTR, card->evtbd_rdptr)) { + dev_err(adapter->dev, "event_complete: failed to read REG_EVTBD_RDPTR\n"); + ret = -1; + goto done; + } + +done: + /* Free the buffer for failure case */ + if (ret && skb) + dev_kfree_skb_any(skb); + + dev_dbg(adapter->dev, "info: Check Events Again\n"); + ret = mwifiex_pcie_process_event_ready(adapter); + + return ret; +} + +/* + * This function downloads the firmware to the card. + * + * Firmware is downloaded to the card in blocks. Every block download + * is tested for CRC errors, and retried a number of times before + * returning failure. + */ +static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter, + struct mwifiex_fw_image *fw) +{ + int ret; + u8 *firmware = fw->fw_buf; + u32 firmware_len = fw->fw_len; + u32 offset = 0; + struct sk_buff *skb; + u32 txlen, tx_blocks = 0, tries, len; + u32 block_retry_cnt = 0; + + if (!adapter) { + pr_err("adapter structure is not valid\n"); + return -1; + } + + if (!firmware || !firmware_len) { + dev_err(adapter->dev, "No firmware image found! " + "Terminating download\n"); + return -1; + } + + dev_dbg(adapter->dev, "info: Downloading FW image (%d bytes)\n", + firmware_len); + + if (mwifiex_pcie_disable_host_int(adapter)) { + dev_err(adapter->dev, "%s: Disabling interrupts" + " failed.\n", __func__); + return -1; + } + + skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE); + if (!skb) { + ret = -ENOMEM; + goto done; + } + mwifiex_update_sk_buff_pa(skb); + + /* Perform firmware data transfer */ + do { + u32 ireg_intr = 0; + + /* More data? */ + if (offset >= firmware_len) + break; + + for (tries = 0; tries < MAX_POLL_TRIES; tries++) { + ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_2_REG, + &len); + if (ret) { + dev_warn(adapter->dev, "Failed reading length from boot code\n"); + goto done; + } + if (len) + break; + udelay(10); + } + + if (!len) { + break; + } else if (len > MWIFIEX_UPLD_SIZE) { + pr_err("FW download failure @ %d, invalid length %d\n", + offset, len); + ret = -1; + goto done; + } + + txlen = len; + + if (len & BIT(0)) { + block_retry_cnt++; + if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) { + pr_err("FW download failure @ %d, over max " + "retry count\n", offset); + ret = -1; + goto done; + } + dev_err(adapter->dev, "FW CRC error indicated by the " + "helper: len = 0x%04X, txlen = " + "%d\n", len, txlen); + len &= ~BIT(0); + /* Setting this to 0 to resend from same offset */ + txlen = 0; + } else { + block_retry_cnt = 0; + /* Set blocksize to transfer - checking for + last block */ + if (firmware_len - offset < txlen) + txlen = firmware_len - offset; + + dev_dbg(adapter->dev, "."); + + tx_blocks = + (txlen + MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD - 1) / + MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD; + + /* Copy payload to buffer */ + memmove(skb->data, &firmware[offset], txlen); + } + + skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len); + skb_trim(skb, tx_blocks * MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD); + + /* Send the boot command to device */ + if (mwifiex_pcie_send_boot_cmd(adapter, skb)) { + dev_err(adapter->dev, "Failed to send firmware download command\n"); + ret = -1; + goto done; + } + /* Wait for the command done interrupt */ + do { + if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS, + &ireg_intr)) { + dev_err(adapter->dev, "%s: Failed to read " + "interrupt status during " + "fw dnld.\n", __func__); + ret = -1; + goto done; + } + } while ((ireg_intr & CPU_INTR_DOOR_BELL) == + CPU_INTR_DOOR_BELL); + offset += txlen; + } while (true); + + dev_dbg(adapter->dev, "info:\nFW download over, size %d bytes\n", + offset); + + ret = 0; + +done: + dev_kfree_skb_any(skb); + return ret; +} + +/* + * This function checks the firmware status in card. + * + * The winner interface is also determined by this function. + */ +static int +mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num) +{ + int ret = 0; + u32 firmware_stat, winner_status; + u32 tries; + + /* Mask spurios interrupts */ + if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS_MASK, + HOST_INTR_MASK)) { + dev_warn(adapter->dev, "Write register failed\n"); + return -1; + } + + dev_dbg(adapter->dev, "Setting driver ready signature\n"); + if (mwifiex_write_reg(adapter, REG_DRV_READY, FIRMWARE_READY_PCIE)) { + dev_err(adapter->dev, "Failed to write driver ready signature\n"); + return -1; + } + + /* Wait for firmware initialization event */ + for (tries = 0; tries < poll_num; tries++) { + if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG, + &firmware_stat)) + ret = -1; + else + ret = 0; + if (ret) + continue; + if (firmware_stat == FIRMWARE_READY_PCIE) { + ret = 0; + break; + } else { + mdelay(100); + ret = -1; + } + } + + if (ret) { + if (mwifiex_read_reg(adapter, PCIE_SCRATCH_3_REG, + &winner_status)) + ret = -1; + else if (!winner_status) { + dev_err(adapter->dev, "PCI-E is the winner\n"); + adapter->winner = 1; + ret = -1; + } else { + dev_err(adapter->dev, "PCI-E is not the winner <%#x, %d>, exit download\n", + ret, adapter->winner); + ret = 0; + } + } + + return ret; +} + +/* + * This function reads the interrupt status from card. + */ +static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter) +{ + u32 pcie_ireg; + unsigned long flags; + + if (!mwifiex_pcie_ok_to_access_hw(adapter)) + return; + + if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) { + dev_warn(adapter->dev, "Read register failed\n"); + return; + } + + if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) { + + mwifiex_pcie_disable_host_int(adapter); + + /* Clear the pending interrupts */ + if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS, + ~pcie_ireg)) { + dev_warn(adapter->dev, "Write register failed\n"); + return; + } + spin_lock_irqsave(&adapter->int_lock, flags); + adapter->int_status |= pcie_ireg; + spin_unlock_irqrestore(&adapter->int_lock, flags); + + if (pcie_ireg & HOST_INTR_CMD_DONE) { + if ((adapter->ps_state == PS_STATE_SLEEP_CFM) || + (adapter->ps_state == PS_STATE_SLEEP)) { + mwifiex_pcie_enable_host_int(adapter); + if (mwifiex_write_reg(adapter, + PCIE_CPU_INT_EVENT, + CPU_INTR_SLEEP_CFM_DONE)) { + dev_warn(adapter->dev, "Write register" + " failed\n"); + return; + + } + } + } else if (!adapter->pps_uapsd_mode && + adapter->ps_state == PS_STATE_SLEEP) { + /* Potentially for PCIe we could get other + * interrupts like shared. Don't change power + * state until cookie is set */ + if (mwifiex_pcie_ok_to_access_hw(adapter)) + adapter->ps_state = PS_STATE_AWAKE; + } + } +} + +/* + * Interrupt handler for PCIe root port + * + * This function reads the interrupt status from firmware and assigns + * the main process in workqueue which will handle the interrupt. + */ +static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context) +{ + struct pci_dev *pdev = (struct pci_dev *)context; + struct pcie_service_card *card; + struct mwifiex_adapter *adapter; + + if (!pdev) { + pr_debug("info: %s: pdev is NULL\n", (u8 *)pdev); + goto exit; + } + + card = (struct pcie_service_card *) pci_get_drvdata(pdev); + if (!card || !card->adapter) { + pr_debug("info: %s: card=%p adapter=%p\n", __func__, card, + card ? card->adapter : NULL); + goto exit; + } + adapter = card->adapter; + + if (adapter->surprise_removed) + goto exit; + + mwifiex_interrupt_status(adapter); + queue_work(adapter->workqueue, &adapter->main_work); + +exit: + return IRQ_HANDLED; +} + +/* + * This function checks the current interrupt status. + * + * The following interrupts are checked and handled by this function - + * - Data sent + * - Command sent + * - Command received + * - Packets received + * - Events received + * + * In case of Rx packets received, the packets are uploaded from card to + * host and processed accordingly. + */ +static int mwifiex_process_int_status(struct mwifiex_adapter *adapter) +{ + int ret; + u32 pcie_ireg = 0; + unsigned long flags; + + spin_lock_irqsave(&adapter->int_lock, flags); + /* Clear out unused interrupts */ + adapter->int_status &= HOST_INTR_MASK; + spin_unlock_irqrestore(&adapter->int_lock, flags); + + while (adapter->int_status & HOST_INTR_MASK) { + if (adapter->int_status & HOST_INTR_DNLD_DONE) { + adapter->int_status &= ~HOST_INTR_DNLD_DONE; + if (adapter->data_sent) { + dev_dbg(adapter->dev, "info: DATA sent Interrupt\n"); + adapter->data_sent = false; + } + } + if (adapter->int_status & HOST_INTR_UPLD_RDY) { + adapter->int_status &= ~HOST_INTR_UPLD_RDY; + dev_dbg(adapter->dev, "info: Rx DATA\n"); + ret = mwifiex_pcie_process_recv_data(adapter); + if (ret) + return ret; + } + if (adapter->int_status & HOST_INTR_EVENT_RDY) { + adapter->int_status &= ~HOST_INTR_EVENT_RDY; + dev_dbg(adapter->dev, "info: Rx EVENT\n"); + ret = mwifiex_pcie_process_event_ready(adapter); + if (ret) + return ret; + } + + if (adapter->int_status & HOST_INTR_CMD_DONE) { + adapter->int_status &= ~HOST_INTR_CMD_DONE; + if (adapter->cmd_sent) { + dev_dbg(adapter->dev, "info: CMD sent Interrupt\n"); + adapter->cmd_sent = false; + } + /* Handle command response */ + ret = mwifiex_pcie_process_cmd_complete(adapter); + if (ret) + return ret; + } + + if (mwifiex_pcie_ok_to_access_hw(adapter)) { + if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, + &pcie_ireg)) { + dev_warn(adapter->dev, "Read register failed\n"); + return -1; + } + + if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) { + if (mwifiex_write_reg(adapter, + PCIE_HOST_INT_STATUS, ~pcie_ireg)) { + dev_warn(adapter->dev, "Write register" + " failed\n"); + return -1; + } + adapter->int_status |= pcie_ireg; + adapter->int_status &= HOST_INTR_MASK; + } + + } + } + dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n", + adapter->cmd_sent, adapter->data_sent); + mwifiex_pcie_enable_host_int(adapter); + + return 0; +} + +/* + * This function downloads data from driver to card. + * + * Both commands and data packets are transferred to the card by this + * function. + * + * This function adds the PCIE specific header to the front of the buffer + * before transferring. The header contains the length of the packet and + * the type. The firmware handles the packets based upon this set type. + */ +static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type, + struct sk_buff *skb, + struct mwifiex_tx_param *tx_param) +{ + if (!adapter || !skb) { + dev_err(adapter->dev, "Invalid parameter in %s <%p, %p>\n", + __func__, adapter, skb); + return -1; + } + + if (type == MWIFIEX_TYPE_DATA) + return mwifiex_pcie_send_data(adapter, skb); + else if (type == MWIFIEX_TYPE_CMD) + return mwifiex_pcie_send_cmd(adapter, skb); + + return 0; +} + +/* + * This function initializes the PCI-E host memory space, WCB rings, etc. + * + * The following initializations steps are followed - + * - Allocate TXBD ring buffers + * - Allocate RXBD ring buffers + * - Allocate event BD ring buffers + * - Allocate command response ring buffer + * - Allocate sleep cookie buffer + */ +static int mwifiex_pcie_init(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + int ret; + struct pci_dev *pdev = card->dev; + + pci_set_drvdata(pdev, card); + + ret = pci_enable_device(pdev); + if (ret) + goto err_enable_dev; + + pci_set_master(pdev); + + dev_dbg(adapter->dev, "try set_consistent_dma_mask(32)\n"); + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(adapter->dev, "set_dma_mask(32) failed\n"); + goto err_set_dma_mask; + } + + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(adapter->dev, "set_consistent_dma_mask(64) failed\n"); + goto err_set_dma_mask; + } + + ret = pci_request_region(pdev, 0, DRV_NAME); + if (ret) { + dev_err(adapter->dev, "req_reg(0) error\n"); + goto err_req_region0; + } + card->pci_mmap = pci_iomap(pdev, 0, 0); + if (!card->pci_mmap) { + dev_err(adapter->dev, "iomap(0) error\n"); + goto err_iomap0; + } + ret = pci_request_region(pdev, 2, DRV_NAME); + if (ret) { + dev_err(adapter->dev, "req_reg(2) error\n"); + goto err_req_region2; + } + card->pci_mmap1 = pci_iomap(pdev, 2, 0); + if (!card->pci_mmap1) { + dev_err(adapter->dev, "iomap(2) error\n"); + goto err_iomap2; + } + + dev_dbg(adapter->dev, "PCI memory map Virt0: %p PCI memory map Virt2: " + "%p\n", card->pci_mmap, card->pci_mmap1); + + card->cmdrsp_buf = NULL; + ret = mwifiex_pcie_create_txbd_ring(adapter); + if (ret) + goto err_cre_txbd; + ret = mwifiex_pcie_create_rxbd_ring(adapter); + if (ret) + goto err_cre_rxbd; + ret = mwifiex_pcie_create_evtbd_ring(adapter); + if (ret) + goto err_cre_evtbd; + ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter); + if (ret) + goto err_alloc_cmdbuf; + ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter); + if (ret) + goto err_alloc_cookie; + + return ret; + +err_alloc_cookie: + mwifiex_pcie_delete_cmdrsp_buf(adapter); +err_alloc_cmdbuf: + mwifiex_pcie_delete_evtbd_ring(adapter); +err_cre_evtbd: + mwifiex_pcie_delete_rxbd_ring(adapter); +err_cre_rxbd: + mwifiex_pcie_delete_txbd_ring(adapter); +err_cre_txbd: + pci_iounmap(pdev, card->pci_mmap1); +err_iomap2: + pci_release_region(pdev, 2); +err_req_region2: + pci_iounmap(pdev, card->pci_mmap); +err_iomap0: + pci_release_region(pdev, 0); +err_req_region0: +err_set_dma_mask: + pci_disable_device(pdev); +err_enable_dev: + pci_set_drvdata(pdev, NULL); + return ret; +} + +/* + * This function cleans up the allocated card buffers. + * + * The following are freed by this function - + * - TXBD ring buffers + * - RXBD ring buffers + * - Event BD ring buffers + * - Command response ring buffer + * - Sleep cookie buffer + */ +static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + struct pci_dev *pdev = card->dev; + + mwifiex_pcie_delete_sleep_cookie_buf(adapter); + mwifiex_pcie_delete_cmdrsp_buf(adapter); + mwifiex_pcie_delete_evtbd_ring(adapter); + mwifiex_pcie_delete_rxbd_ring(adapter); + mwifiex_pcie_delete_txbd_ring(adapter); + card->cmdrsp_buf = NULL; + + dev_dbg(adapter->dev, "Clearing driver ready signature\n"); + if (user_rmmod) { + if (mwifiex_write_reg(adapter, REG_DRV_READY, 0x00000000)) + dev_err(adapter->dev, "Failed to write driver not-ready signature\n"); + } + + if (pdev) { + pci_iounmap(pdev, card->pci_mmap); + pci_iounmap(pdev, card->pci_mmap1); + + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } +} + +/* + * This function registers the PCIE device. + * + * PCIE IRQ is claimed, block size is set and driver data is initialized. + */ +static int mwifiex_register_dev(struct mwifiex_adapter *adapter) +{ + int ret; + struct pcie_service_card *card = adapter->card; + struct pci_dev *pdev = card->dev; + + /* save adapter pointer in card */ + card->adapter = adapter; + + ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED, + "MRVL_PCIE", pdev); + if (ret) { + pr_err("request_irq failed: ret=%d\n", ret); + adapter->card = NULL; + return -1; + } + + adapter->dev = &pdev->dev; + strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME); + + return 0; +} + +/* + * This function unregisters the PCIE device. + * + * The PCIE IRQ is released, the function is disabled and driver + * data is set to null. + */ +static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter) +{ + struct pcie_service_card *card = adapter->card; + + if (card) { + dev_dbg(adapter->dev, "%s(): calling free_irq()\n", __func__); + free_irq(card->dev->irq, card->dev); + } +} + +static struct mwifiex_if_ops pcie_ops = { + .init_if = mwifiex_pcie_init, + .cleanup_if = mwifiex_pcie_cleanup, + .check_fw_status = mwifiex_check_fw_status, + .prog_fw = mwifiex_prog_fw_w_helper, + .register_dev = mwifiex_register_dev, + .unregister_dev = mwifiex_unregister_dev, + .enable_int = mwifiex_pcie_enable_host_int, + .process_int_status = mwifiex_process_int_status, + .host_to_card = mwifiex_pcie_host_to_card, + .wakeup = mwifiex_pm_wakeup_card, + .wakeup_complete = mwifiex_pm_wakeup_card_complete, + + /* PCIE specific */ + .cmdrsp_complete = mwifiex_pcie_cmdrsp_complete, + .event_complete = mwifiex_pcie_event_complete, + .update_mp_end_port = NULL, + .cleanup_mpa_buf = NULL, +}; + +/* + * This function initializes the PCIE driver module. + * + * This initiates the semaphore and registers the device with + * PCIE bus. + */ +static int mwifiex_pcie_init_module(void) +{ + int ret; + + pr_debug("Marvell 8766 PCIe Driver\n"); + + sema_init(&add_remove_card_sem, 1); + + /* Clear the flag in case user removes the card. */ + user_rmmod = 0; + + ret = pci_register_driver(&mwifiex_pcie); + if (ret) + pr_err("Driver register failed!\n"); + else + pr_debug("info: Driver registered successfully!\n"); + + return ret; +} + +/* + * This function cleans up the PCIE driver. + * + * The following major steps are followed for cleanup - + * - Resume the device if its suspended + * - Disconnect the device if connected + * - Shutdown the firmware + * - Unregister the device from PCIE bus. + */ +static void mwifiex_pcie_cleanup_module(void) +{ + if (!down_interruptible(&add_remove_card_sem)) + up(&add_remove_card_sem); + + /* Set the flag as user is removing this module. */ + user_rmmod = 1; + + pci_unregister_driver(&mwifiex_pcie); +} + +module_init(mwifiex_pcie_init_module); +module_exit(mwifiex_pcie_cleanup_module); + +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION); +MODULE_VERSION(PCIE_VERSION); +MODULE_LICENSE("GPL v2"); +MODULE_FIRMWARE("mrvl/pcie8766_uapsta.bin"); diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h new file mode 100644 index 000000000000..445ff21772e2 --- /dev/null +++ b/drivers/net/wireless/mwifiex/pcie.h @@ -0,0 +1,148 @@ +/* @file mwifiex_pcie.h + * + * @brief This file contains definitions for PCI-E interface. + * driver. + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#ifndef _MWIFIEX_PCIE_H +#define _MWIFIEX_PCIE_H + +#include <linux/pci.h> +#include <linux/pcieport_if.h> +#include <linux/interrupt.h> + +#include "main.h" + +#define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin" + +/* Constants for Buffer Descriptor (BD) rings */ +#define MWIFIEX_MAX_TXRX_BD 0x20 +#define MWIFIEX_TXBD_MASK 0x3F +#define MWIFIEX_RXBD_MASK 0x3F + +#define MWIFIEX_MAX_EVT_BD 0x04 +#define MWIFIEX_EVTBD_MASK 0x07 + +/* PCIE INTERNAL REGISTERS */ +#define PCIE_SCRATCH_0_REG 0xC10 +#define PCIE_SCRATCH_1_REG 0xC14 +#define PCIE_CPU_INT_EVENT 0xC18 +#define PCIE_CPU_INT_STATUS 0xC1C +#define PCIE_HOST_INT_STATUS 0xC30 +#define PCIE_HOST_INT_MASK 0xC34 +#define PCIE_HOST_INT_STATUS_MASK 0xC3C +#define PCIE_SCRATCH_2_REG 0xC40 +#define PCIE_SCRATCH_3_REG 0xC44 +#define PCIE_SCRATCH_4_REG 0xCC0 +#define PCIE_SCRATCH_5_REG 0xCC4 +#define PCIE_SCRATCH_6_REG 0xCC8 +#define PCIE_SCRATCH_7_REG 0xCCC +#define PCIE_SCRATCH_8_REG 0xCD0 +#define PCIE_SCRATCH_9_REG 0xCD4 +#define PCIE_SCRATCH_10_REG 0xCD8 +#define PCIE_SCRATCH_11_REG 0xCDC +#define PCIE_SCRATCH_12_REG 0xCE0 + +#define CPU_INTR_DNLD_RDY BIT(0) +#define CPU_INTR_DOOR_BELL BIT(1) +#define CPU_INTR_SLEEP_CFM_DONE BIT(2) +#define CPU_INTR_RESET BIT(3) + +#define HOST_INTR_DNLD_DONE BIT(0) +#define HOST_INTR_UPLD_RDY BIT(1) +#define HOST_INTR_CMD_DONE BIT(2) +#define HOST_INTR_EVENT_RDY BIT(3) +#define HOST_INTR_MASK (HOST_INTR_DNLD_DONE | \ + HOST_INTR_UPLD_RDY | \ + HOST_INTR_CMD_DONE | \ + HOST_INTR_EVENT_RDY) + +#define MWIFIEX_BD_FLAG_ROLLOVER_IND BIT(7) +#define MWIFIEX_BD_FLAG_FIRST_DESC BIT(0) +#define MWIFIEX_BD_FLAG_LAST_DESC BIT(1) +#define REG_CMD_ADDR_LO PCIE_SCRATCH_0_REG +#define REG_CMD_ADDR_HI PCIE_SCRATCH_1_REG +#define REG_CMD_SIZE PCIE_SCRATCH_2_REG + +#define REG_CMDRSP_ADDR_LO PCIE_SCRATCH_4_REG +#define REG_CMDRSP_ADDR_HI PCIE_SCRATCH_5_REG + +/* TX buffer description read pointer */ +#define REG_TXBD_RDPTR PCIE_SCRATCH_6_REG +/* TX buffer description write pointer */ +#define REG_TXBD_WRPTR PCIE_SCRATCH_7_REG +/* RX buffer description read pointer */ +#define REG_RXBD_RDPTR PCIE_SCRATCH_8_REG +/* RX buffer description write pointer */ +#define REG_RXBD_WRPTR PCIE_SCRATCH_9_REG +/* Event buffer description read pointer */ +#define REG_EVTBD_RDPTR PCIE_SCRATCH_10_REG +/* Event buffer description write pointer */ +#define REG_EVTBD_WRPTR PCIE_SCRATCH_11_REG +/* Driver ready signature write pointer */ +#define REG_DRV_READY PCIE_SCRATCH_12_REG + +/* Max retry number of command write */ +#define MAX_WRITE_IOMEM_RETRY 2 +/* Define PCIE block size for firmware download */ +#define MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD 256 +/* FW awake cookie after FW ready */ +#define FW_AWAKE_COOKIE (0xAA55AA55) + +struct mwifiex_pcie_buf_desc { + u64 paddr; + u16 len; + u16 flags; +} __packed; + +struct pcie_service_card { + struct pci_dev *dev; + struct mwifiex_adapter *adapter; + + u32 txbd_wrptr; + u32 txbd_rdptr; + u32 txbd_ring_size; + u8 *txbd_ring_vbase; + phys_addr_t txbd_ring_pbase; + struct mwifiex_pcie_buf_desc *txbd_ring[MWIFIEX_MAX_TXRX_BD]; + struct sk_buff *tx_buf_list[MWIFIEX_MAX_TXRX_BD]; + + u32 rxbd_wrptr; + u32 rxbd_rdptr; + u32 rxbd_ring_size; + u8 *rxbd_ring_vbase; + phys_addr_t rxbd_ring_pbase; + struct mwifiex_pcie_buf_desc *rxbd_ring[MWIFIEX_MAX_TXRX_BD]; + struct sk_buff *rx_buf_list[MWIFIEX_MAX_TXRX_BD]; + + u32 evtbd_wrptr; + u32 evtbd_rdptr; + u32 evtbd_ring_size; + u8 *evtbd_ring_vbase; + phys_addr_t evtbd_ring_pbase; + struct mwifiex_pcie_buf_desc *evtbd_ring[MWIFIEX_MAX_EVT_BD]; + struct sk_buff *evt_buf_list[MWIFIEX_MAX_EVT_BD]; + + struct sk_buff *cmd_buf; + struct sk_buff *cmdrsp_buf; + struct sk_buff *sleep_cookie; + void __iomem *pci_mmap; + void __iomem *pci_mmap1; +}; + +#endif /* _MWIFIEX_PCIE_H */ diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 6f88c8ab5de5..dae8dbb24a03 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -172,59 +172,6 @@ mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, } /* - * Sends IOCTL request to get the best BSS. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_find_best_bss(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) -{ - struct mwifiex_ssid_bssid tmp_ssid_bssid; - u8 *mac; - - if (!ssid_bssid) - return -1; - - memcpy(&tmp_ssid_bssid, ssid_bssid, - sizeof(struct mwifiex_ssid_bssid)); - - if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) { - memcpy(ssid_bssid, &tmp_ssid_bssid, - sizeof(struct mwifiex_ssid_bssid)); - mac = (u8 *) &ssid_bssid->bssid; - dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," - " %pM\n", ssid_bssid->ssid.ssid, mac); - return 0; - } - - return -1; -} - -/* - * Sends IOCTL request to start a scan with user configurations. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - * - * Upon completion, it also generates a wireless event to notify - * applications. - */ -int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, - struct mwifiex_user_scan_cfg *scan_req) -{ - int status; - - priv->adapter->cmd_wait_q.condition = false; - - status = mwifiex_scan_networks(priv, scan_req); - if (!status) - status = mwifiex_wait_queue_complete(priv->adapter); - - return status; -} - -/* * This function checks if wapi is enabled in driver and scanned network is * compatible with it. */ @@ -286,8 +233,7 @@ mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, */ static bool mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) + struct mwifiex_bssdescriptor *bss_desc) { if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled @@ -298,9 +244,9 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, * LinkSys WRT54G && bss_desc->privacy */ ) { - dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" + dev_dbg(priv->adapter->dev, "info: %s: WPA:" " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " - "EncMode=%#x privacy=%#x\n", __func__, index, + "EncMode=%#x privacy=%#x\n", __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, @@ -324,8 +270,7 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, */ static bool mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) + struct mwifiex_bssdescriptor *bss_desc) { if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled @@ -336,9 +281,9 @@ mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, * LinkSys WRT54G && bss_desc->privacy */ ) { - dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" + dev_dbg(priv->adapter->dev, "info: %s: WPA2: " " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " - "EncMode=%#x privacy=%#x\n", __func__, index, + "EncMode=%#x privacy=%#x\n", __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, @@ -383,8 +328,7 @@ mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, */ static bool mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) + struct mwifiex_bssdescriptor *bss_desc) { if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled @@ -395,9 +339,9 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, && priv->sec_info.encryption_mode && bss_desc->privacy) { dev_dbg(priv->adapter->dev, "info: %s: dynamic " - "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " + "WEP: wpa_ie=%#x wpa2_ie=%#x " "EncMode=%#x privacy=%#x\n", - __func__, index, + __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, @@ -430,42 +374,41 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, * Compatibility is not matched while roaming, except for mode. */ static s32 -mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) +mwifiex_is_network_compatible(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, u32 mode) { struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *bss_desc; - bss_desc = &adapter->scan_table[index]; bss_desc->disable_11n = false; /* Don't check for compatibility if roaming */ if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) - return index; + return 0; if (priv->wps.session_enable) { dev_dbg(adapter->dev, "info: return success directly in WPS period\n"); - return index; + return 0; } if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); - return index; + return 0; } if (bss_desc->bss_mode == mode) { if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { /* No security */ - return index; + return 0; } else if (mwifiex_is_network_compatible_for_static_wep(priv, bss_desc)) { /* Static WEP enabled */ dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); bss_desc->disable_11n = true; - return index; - } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, - index)) { + return 0; + } else if (mwifiex_is_network_compatible_for_wpa(priv, + bss_desc)) { /* WPA enabled */ if (((priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN) @@ -483,9 +426,9 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) return -1; } } - return index; + return 0; } else if (mwifiex_is_network_compatible_for_wpa2(priv, - bss_desc, index)) { + bss_desc)) { /* WPA2 enabled */ if (((priv->adapter->config_bands & BAND_GN || priv->adapter->config_bands & BAND_AN) @@ -503,22 +446,22 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) return -1; } } - return index; + return 0; } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, bss_desc)) { /* Ad-hoc AES enabled */ - return index; + return 0; } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, - bss_desc, index)) { + bss_desc)) { /* Dynamic WEP enabled */ - return index; + return 0; } /* Security doesn't match */ - dev_dbg(adapter->dev, "info: %s: failed: index=%d " + dev_dbg(adapter->dev, "info: %s: failed: " "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" "=%#x privacy=%#x\n", - __func__, index, + __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)).vend_hdr. element_id : 0, @@ -538,52 +481,6 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) } /* - * This function finds the best SSID in the scan list. - * - * It searches the scan table for the best SSID that also matches the current - * adapter network preference (mode, security etc.). - */ -static s32 -mwifiex_find_best_network_in_list(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 mode = priv->bss_mode; - s32 best_net = -1; - s32 best_rssi = 0; - u32 i; - - dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", - adapter->num_in_scan_table); - - for (i = 0; i < adapter->num_in_scan_table; i++) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table[i].rssi); - best_net = i; - } - } - break; - case NL80211_IFTYPE_UNSPECIFIED: - default: - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter->scan_table[i]. - rssi); - best_net = i; - } - break; - } - } - - return best_net; -} - -/* * This function creates a channel list for the driver to scan, based * on region/band information. * @@ -612,7 +509,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, sband = priv->wdev->wiphy->bands[band]; - for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) { + for (i = 0; (i < sband->n_channels) ; i++) { ch = &sband->channels[i]; if (ch->flags & IEEE80211_CHAN_DISABLED) continue; @@ -643,6 +540,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, scan_chan_list[chan_idx].chan_scan_mode_bitmap |= MWIFIEX_DISABLE_CHAN_FILT; } + chan_idx++; } } @@ -1161,34 +1059,13 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, } /* - * This function interprets a BSS scan response returned from the firmware. - * - * The various fixed fields and IEs are parsed and passed back for a BSS - * probe response or beacon from scan command. Information is recorded as - * needed in the scan table for that entry. - * - * The following IE types are recognized and parsed - - * - SSID - * - Supported rates - * - FH parameters set - * - DS parameters set - * - CF parameters set - * - IBSS parameters set - * - ERP information - * - Extended supported rates - * - Vendor specific (221) - * - RSN IE - * - WAPI IE - * - HT capability - * - HT operation - * - BSS Coexistence 20/40 - * - Extended capability - * - Overlapping BSS scan parameters + * This function parses provided beacon buffer and updates + * respective fields in bss descriptor structure. */ -static int -mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, - struct mwifiex_bssdescriptor *bss_entry, - u8 **beacon_info, u32 *bytes_left) +int +mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry, + u8 *ie_buf, u32 ie_len) { int ret = 0; u8 element_id; @@ -1196,135 +1073,43 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, struct ieee_types_ds_param_set *ds_param_set; struct ieee_types_cf_param_set *cf_param_set; struct ieee_types_ibss_param_set *ibss_param_set; - __le16 beacon_interval; - __le16 capabilities; u8 *current_ptr; u8 *rate; u8 element_len; u16 total_ie_len; u8 bytes_to_copy; u8 rate_size; - u16 beacon_size; u8 found_data_rate_ie; - u32 bytes_left_for_current_beacon; + u32 bytes_left; struct ieee_types_vendor_specific *vendor_ie; const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; found_data_rate_ie = false; rate_size = 0; - beacon_size = 0; - - if (*bytes_left >= sizeof(beacon_size)) { - /* Extract & convert beacon size from the command buffer */ - memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); - *bytes_left -= sizeof(beacon_size); - *beacon_info += sizeof(beacon_size); - } - - if (!beacon_size || beacon_size > *bytes_left) { - *beacon_info += *bytes_left; - *bytes_left = 0; - return -1; - } - - /* Initialize the current working beacon pointer for this BSS - iteration */ - current_ptr = *beacon_info; - - /* Advance the return beacon pointer past the current beacon */ - *beacon_info += beacon_size; - *bytes_left -= beacon_size; - - bytes_left_for_current_beacon = beacon_size; - - memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); - dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", - bss_entry->mac_address); - - current_ptr += ETH_ALEN; - bytes_left_for_current_beacon -= ETH_ALEN; - - if (bytes_left_for_current_beacon < 12) { - dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); - return -1; - } - - /* - * Next 4 fields are RSSI, time stamp, beacon interval, - * and capability information - */ - - /* RSSI is 1 byte long */ - bss_entry->rssi = (s32) (*current_ptr); - dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); - current_ptr += 1; - bytes_left_for_current_beacon -= 1; - - /* - * The RSSI is not part of the beacon/probe response. After we have - * advanced current_ptr past the RSSI field, save the remaining - * data for use at the application layer - */ - bss_entry->beacon_buf = current_ptr; - bss_entry->beacon_buf_size = bytes_left_for_current_beacon; - - /* Time stamp is 8 bytes long */ - memcpy(bss_entry->time_stamp, current_ptr, 8); - current_ptr += 8; - bytes_left_for_current_beacon -= 8; - - /* Beacon interval is 2 bytes long */ - memcpy(&beacon_interval, current_ptr, 2); - bss_entry->beacon_period = le16_to_cpu(beacon_interval); - current_ptr += 2; - bytes_left_for_current_beacon -= 2; - - /* Capability information is 2 bytes long */ - memcpy(&capabilities, current_ptr, 2); - dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", - capabilities); - bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); - current_ptr += 2; - bytes_left_for_current_beacon -= 2; - - /* Rest of the current buffer are IE's */ - dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", - bytes_left_for_current_beacon); - - if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { - dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); - bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; - } else { - bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; - } - - if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) - bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; - else - bss_entry->bss_mode = NL80211_IFTYPE_STATION; - + current_ptr = ie_buf; + bytes_left = ie_len; + bss_entry->beacon_buf = ie_buf; + bss_entry->beacon_buf_size = ie_len; /* Process variable IE */ - while (bytes_left_for_current_beacon >= 2) { + while (bytes_left >= 2) { element_id = *current_ptr; element_len = *(current_ptr + 1); total_ie_len = element_len + sizeof(struct ieee_types_header); - if (bytes_left_for_current_beacon < total_ie_len) { + if (bytes_left < total_ie_len) { dev_err(adapter->dev, "err: InterpretIE: in processing" " IE, bytes left < IE length\n"); - bytes_left_for_current_beacon = 0; - ret = -1; - continue; + return -1; } switch (element_id) { case WLAN_EID_SSID: bss_entry->ssid.ssid_len = element_len; memcpy(bss_entry->ssid.ssid, (current_ptr + 2), element_len); - dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", - bss_entry->ssid.ssid); + dev_dbg(adapter->dev, "info: InterpretIE: ssid: " + "%-32s\n", bss_entry->ssid.ssid); break; case WLAN_EID_SUPP_RATES: @@ -1471,13 +1256,6 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, sizeof(struct ieee_types_header) - bss_entry->beacon_buf); break; - case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: - bss_entry->bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - current_ptr; - bss_entry->overlap_bss_offset = (u16) (current_ptr - - bss_entry->beacon_buf); - break; default: break; } @@ -1485,577 +1263,13 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, current_ptr += element_len + 2; /* Need to account for IE ID and IE Len */ - bytes_left_for_current_beacon -= (element_len + 2); + bytes_left -= (element_len + 2); - } /* while (bytes_left_for_current_beacon > 2) */ + } /* while (bytes_left > 2) */ return ret; } /* - * This function adjusts the pointers used in beacon buffers to reflect - * shifts. - * - * The memory allocated for beacon buffers is of fixed sizes where all the - * saved beacons must be stored. New beacons are added in the free portion - * of this memory, space permitting; while duplicate beacon buffers are - * placed at the same start location. However, since duplicate beacon - * buffers may not match the size of the old one, all the following buffers - * in the memory must be shifted to either make space, or to fill up freed - * up space. - * - * This function is used to update the beacon buffer pointers that are past - * an existing beacon buffer that is updated with a new one of different - * size. The pointers are shifted by a fixed amount, either forward or - * backward. - * - * the following pointers in every affected beacon buffers are changed, if - * present - - * - WPA IE pointer - * - RSN IE pointer - * - WAPI IE pointer - * - HT capability IE pointer - * - HT information IE pointer - * - BSS coexistence 20/40 IE pointer - * - Extended capability IE pointer - * - Overlapping BSS scan parameter IE pointer - */ -static void -mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, - u8 *bcn_store, u32 rem_bcn_size, - u32 num_of_ent) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 adj_idx; - for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { - if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { - - if (advance) - adapter->scan_table[adj_idx].beacon_buf += - rem_bcn_size; - else - adapter->scan_table[adj_idx].beacon_buf -= - rem_bcn_size; - - if (adapter->scan_table[adj_idx].bcn_wpa_ie) - adapter->scan_table[adj_idx].bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].wpa_offset); - if (adapter->scan_table[adj_idx].bcn_rsn_ie) - adapter->scan_table[adj_idx].bcn_rsn_ie = - (struct ieee_types_generic *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].rsn_offset); - if (adapter->scan_table[adj_idx].bcn_wapi_ie) - adapter->scan_table[adj_idx].bcn_wapi_ie = - (struct ieee_types_generic *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].wapi_offset); - if (adapter->scan_table[adj_idx].bcn_ht_cap) - adapter->scan_table[adj_idx].bcn_ht_cap = - (struct ieee80211_ht_cap *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ht_cap_offset); - - if (adapter->scan_table[adj_idx].bcn_ht_info) - adapter->scan_table[adj_idx].bcn_ht_info = - (struct ieee80211_ht_info *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ht_info_offset); - if (adapter->scan_table[adj_idx].bcn_bss_co_2040) - adapter->scan_table[adj_idx].bcn_bss_co_2040 = - (u8 *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].bss_co_2040_offset); - if (adapter->scan_table[adj_idx].bcn_ext_cap) - adapter->scan_table[adj_idx].bcn_ext_cap = - (u8 *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ext_cap_offset); - if (adapter->scan_table[adj_idx].bcn_obss_scan) - adapter->scan_table[adj_idx].bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].overlap_bss_offset); - } - } -} - -/* - * This function updates the pointers used in beacon buffer for given bss - * descriptor to reflect shifts - * - * Following pointers are updated - * - WPA IE pointer - * - RSN IE pointer - * - WAPI IE pointer - * - HT capability IE pointer - * - HT information IE pointer - * - BSS coexistence 20/40 IE pointer - * - Extended capability IE pointer - * - Overlapping BSS scan parameter IE pointer - */ -static void -mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) -{ - if (beacon->bcn_wpa_ie) - beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) - (beacon->beacon_buf + beacon->wpa_offset); - if (beacon->bcn_rsn_ie) - beacon->bcn_rsn_ie = (struct ieee_types_generic *) - (beacon->beacon_buf + beacon->rsn_offset); - if (beacon->bcn_wapi_ie) - beacon->bcn_wapi_ie = (struct ieee_types_generic *) - (beacon->beacon_buf + beacon->wapi_offset); - if (beacon->bcn_ht_cap) - beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) - (beacon->beacon_buf + beacon->ht_cap_offset); - if (beacon->bcn_ht_info) - beacon->bcn_ht_info = (struct ieee80211_ht_info *) - (beacon->beacon_buf + beacon->ht_info_offset); - if (beacon->bcn_bss_co_2040) - beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + - beacon->bss_co_2040_offset); - if (beacon->bcn_ext_cap) - beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + - beacon->ext_cap_offset); - if (beacon->bcn_obss_scan) - beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) - (beacon->beacon_buf + beacon->overlap_bss_offset); -} - -/* - * This function stores a beacon or probe response for a BSS returned - * in the scan. - * - * This stores a new scan response or an update for a previous scan response. - * New entries need to verify that they do not exceed the total amount of - * memory allocated for the table. - * - * Replacement entries need to take into consideration the amount of space - * currently allocated for the beacon/probe response and adjust the entry - * as needed. - * - * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved - * for an entry in case it is a beacon since a probe response for the - * network will by larger per the standard. This helps to reduce the - * amount of memory copying to fit a new probe response into an entry - * already occupied by a network's previously stored beacon. - */ -static void -mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, - u32 beacon_idx, u32 num_of_ent, - struct mwifiex_bssdescriptor *new_beacon) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u8 *bcn_store; - u32 new_bcn_size; - u32 old_bcn_size; - u32 bcn_space; - - if (adapter->scan_table[beacon_idx].beacon_buf) { - - new_bcn_size = new_beacon->beacon_buf_size; - old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; - bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; - bcn_store = adapter->scan_table[beacon_idx].beacon_buf; - - /* Set the max to be the same as current entry unless changed - below */ - new_beacon->beacon_buf_size_max = bcn_space; - if (new_bcn_size == old_bcn_size) { - /* - * Beacon is the same size as the previous entry. - * Replace the previous contents with the scan result - */ - memcpy(bcn_store, new_beacon->beacon_buf, - new_beacon->beacon_buf_size); - - } else if (new_bcn_size <= bcn_space) { - /* - * New beacon size will fit in the amount of space - * we have previously allocated for it - */ - - /* Copy the new beacon buffer entry over the old one */ - memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); - - /* - * If the old beacon size was less than the maximum - * we had alloted for the entry, and the new entry - * is even smaller, reset the max size to the old - * beacon entry and compress the storage space - * (leaving a new pad space of (old_bcn_size - - * new_bcn_size). - */ - if (old_bcn_size < bcn_space - && new_bcn_size <= old_bcn_size) { - /* - * Old Beacon size is smaller than the alloted - * storage size. Shrink the alloted storage - * space. - */ - dev_dbg(adapter->dev, "info: AppControl:" - " smaller duplicate beacon " - "(%d), old = %d, new = %d, space = %d," - "left = %d\n", - beacon_idx, old_bcn_size, new_bcn_size, - bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* - * memmove (since the memory overlaps) the - * data after the beacon we just stored to the - * end of the current beacon. This cleans up - * any unused space the old larger beacon was - * using in the buffer - */ - memmove(bcn_store + old_bcn_size, - bcn_store + bcn_space, - adapter->bcn_buf_end - (bcn_store + - bcn_space)); - - /* - * Decrement the end pointer by the difference - * between the old larger size and the new - * smaller size since we are using less space - * due to the new beacon being smaller - */ - adapter->bcn_buf_end -= - (bcn_space - old_bcn_size); - - /* Set the maximum storage size to the old - beacon size */ - new_beacon->beacon_buf_size_max = old_bcn_size; - - /* Adjust beacon buffer pointers that are past - the current */ - mwifiex_adjust_beacon_buffer_ptrs(priv, 0, - bcn_store, (bcn_space - old_bcn_size), - num_of_ent); - } - } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) - < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { - /* - * Beacon is larger than space previously allocated - * (bcn_space) and there is enough space left in the - * beaconBuffer to store the additional data - */ - dev_dbg(adapter->dev, "info: AppControl:" - " larger duplicate beacon (%d), " - "old = %d, new = %d, space = %d, left = %d\n", - beacon_idx, old_bcn_size, new_bcn_size, - bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* - * memmove (since the memory overlaps) the data - * after the beacon we just stored to the end of - * the current beacon. This moves the data for - * the beacons after this further in memory to - * make space for the new larger beacon we are - * about to copy in. - */ - memmove(bcn_store + new_bcn_size, - bcn_store + bcn_space, - adapter->bcn_buf_end - (bcn_store + bcn_space)); - - /* Copy the new beacon buffer entry over the old one */ - memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); - - /* Move the beacon end pointer by the amount of new - beacon data we are adding */ - adapter->bcn_buf_end += (new_bcn_size - bcn_space); - - /* - * This entry is bigger than the alloted max space - * previously reserved. Increase the max space to - * be equal to the new beacon size - */ - new_beacon->beacon_buf_size_max = new_bcn_size; - - /* Adjust beacon buffer pointers that are past the - current */ - mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, - (new_bcn_size - bcn_space), - num_of_ent); - } else { - /* - * Beacon is larger than the previously allocated space, - * but there is not enough free space to store the - * additional data. - */ - dev_err(adapter->dev, "AppControl: larger duplicate " - " beacon (%d), old = %d new = %d, space = %d," - " left = %d\n", beacon_idx, old_bcn_size, - new_bcn_size, bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - adapter->bcn_buf))); - - /* Storage failure, keep old beacon intact */ - new_beacon->beacon_buf_size = old_bcn_size; - if (new_beacon->bcn_wpa_ie) - new_beacon->wpa_offset = - adapter->scan_table[beacon_idx]. - wpa_offset; - if (new_beacon->bcn_rsn_ie) - new_beacon->rsn_offset = - adapter->scan_table[beacon_idx]. - rsn_offset; - if (new_beacon->bcn_wapi_ie) - new_beacon->wapi_offset = - adapter->scan_table[beacon_idx]. - wapi_offset; - if (new_beacon->bcn_ht_cap) - new_beacon->ht_cap_offset = - adapter->scan_table[beacon_idx]. - ht_cap_offset; - if (new_beacon->bcn_ht_info) - new_beacon->ht_info_offset = - adapter->scan_table[beacon_idx]. - ht_info_offset; - if (new_beacon->bcn_bss_co_2040) - new_beacon->bss_co_2040_offset = - adapter->scan_table[beacon_idx]. - bss_co_2040_offset; - if (new_beacon->bcn_ext_cap) - new_beacon->ext_cap_offset = - adapter->scan_table[beacon_idx]. - ext_cap_offset; - if (new_beacon->bcn_obss_scan) - new_beacon->overlap_bss_offset = - adapter->scan_table[beacon_idx]. - overlap_bss_offset; - } - /* Point the new entry to its permanent storage space */ - new_beacon->beacon_buf = bcn_store; - mwifiex_update_beacon_buffer_ptrs(new_beacon); - } else { - /* - * No existing beacon data exists for this entry, check to see - * if we can fit it in the remaining space - */ - if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + - SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + - sizeof(adapter->bcn_buf))) { - - /* - * Copy the beacon buffer data from the local entry to - * the adapter dev struct buffer space used to store - * the raw beacon data for each entry in the scan table - */ - memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, - new_beacon->beacon_buf_size); - - /* Update the beacon ptr to point to the table save - area */ - new_beacon->beacon_buf = adapter->bcn_buf_end; - new_beacon->beacon_buf_size_max = - (new_beacon->beacon_buf_size + - SCAN_BEACON_ENTRY_PAD); - - mwifiex_update_beacon_buffer_ptrs(new_beacon); - - /* Increment the end pointer by the size reserved */ - adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; - - dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" - " sz=%03d, used = %04d, left = %04d\n", - beacon_idx, - new_beacon->beacon_buf_size, - (int)(adapter->bcn_buf_end - adapter->bcn_buf), - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - } else { - /* No space for new beacon */ - dev_dbg(adapter->dev, "info: AppControl: no space for" - " beacon (%d): %pM sz=%03d, left=%03d\n", - beacon_idx, new_beacon->mac_address, - new_beacon->beacon_buf_size, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* Storage failure; clear storage records for this - bcn */ - new_beacon->beacon_buf = NULL; - new_beacon->beacon_buf_size = 0; - new_beacon->beacon_buf_size_max = 0; - new_beacon->bcn_wpa_ie = NULL; - new_beacon->wpa_offset = 0; - new_beacon->bcn_rsn_ie = NULL; - new_beacon->rsn_offset = 0; - new_beacon->bcn_wapi_ie = NULL; - new_beacon->wapi_offset = 0; - new_beacon->bcn_ht_cap = NULL; - new_beacon->ht_cap_offset = 0; - new_beacon->bcn_ht_info = NULL; - new_beacon->ht_info_offset = 0; - new_beacon->bcn_bss_co_2040 = NULL; - new_beacon->bss_co_2040_offset = 0; - new_beacon->bcn_ext_cap = NULL; - new_beacon->ext_cap_offset = 0; - new_beacon->bcn_obss_scan = NULL; - new_beacon->overlap_bss_offset = 0; - } - } -} - -/* - * This function restores a beacon buffer of the current BSS descriptor. - */ -static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *curr_bss = - &priv->curr_bss_params.bss_descriptor; - unsigned long flags; - - if (priv->curr_bcn_buf && - ((adapter->bcn_buf_end + priv->curr_bcn_size) < - (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { - spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); - - /* restore the current beacon buffer */ - memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, - priv->curr_bcn_size); - curr_bss->beacon_buf = adapter->bcn_buf_end; - curr_bss->beacon_buf_size = priv->curr_bcn_size; - adapter->bcn_buf_end += priv->curr_bcn_size; - - /* adjust the pointers in the current BSS descriptor */ - if (curr_bss->bcn_wpa_ie) - curr_bss->bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (curr_bss->beacon_buf + - curr_bss->wpa_offset); - - if (curr_bss->bcn_rsn_ie) - curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) - (curr_bss->beacon_buf + - curr_bss->rsn_offset); - - if (curr_bss->bcn_ht_cap) - curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) - (curr_bss->beacon_buf + - curr_bss->ht_cap_offset); - - if (curr_bss->bcn_ht_info) - curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) - (curr_bss->beacon_buf + - curr_bss->ht_info_offset); - - if (curr_bss->bcn_bss_co_2040) - curr_bss->bcn_bss_co_2040 = - (u8 *) (curr_bss->beacon_buf + - curr_bss->bss_co_2040_offset); - - if (curr_bss->bcn_ext_cap) - curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + - curr_bss->ext_cap_offset); - - if (curr_bss->bcn_obss_scan) - curr_bss->bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (curr_bss->beacon_buf + - curr_bss->overlap_bss_offset); - - spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); - - dev_dbg(adapter->dev, "info: current beacon restored %d\n", - priv->curr_bcn_size); - } else { - dev_warn(adapter->dev, - "curr_bcn_buf not saved or bcn_buf has no space\n"); - } -} - -/* - * This function post processes the scan table after a new scan command has - * completed. - * - * It inspects each entry of the scan table and tries to find an entry that - * matches with our current associated/joined network from the scan. If - * one is found, the stored copy of the BSS descriptor of our current network - * is updated. - * - * It also debug dumps the current scan table contents after processing is over. - */ -static void -mwifiex_process_scan_results(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 j; - u32 i; - unsigned long flags; - - if (priv->media_connected) { - - j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. - bss_descriptor.ssid, - priv->curr_bss_params. - bss_descriptor.mac_address, - priv->bss_mode); - - if (j >= 0) { - spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); - priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; - priv->curr_bss_params.bss_descriptor.wpa_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; - priv->curr_bss_params.bss_descriptor.rsn_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; - priv->curr_bss_params.bss_descriptor.wapi_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; - priv->curr_bss_params.bss_descriptor.ht_cap_offset = - 0; - priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; - priv->curr_bss_params.bss_descriptor.ht_info_offset = - 0; - priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = - NULL; - priv->curr_bss_params.bss_descriptor. - bss_co_2040_offset = 0; - priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; - priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; - priv->curr_bss_params.bss_descriptor. - bcn_obss_scan = NULL; - priv->curr_bss_params.bss_descriptor. - overlap_bss_offset = 0; - priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; - priv->curr_bss_params.bss_descriptor.beacon_buf_size = - 0; - priv->curr_bss_params.bss_descriptor. - beacon_buf_size_max = 0; - - dev_dbg(adapter->dev, "info: Found current ssid/bssid" - " in list @ index #%d\n", j); - /* Make a copy of current BSSID descriptor */ - memcpy(&priv->curr_bss_params.bss_descriptor, - &adapter->scan_table[j], - sizeof(priv->curr_bss_params.bss_descriptor)); - - mwifiex_save_curr_bcn(priv); - spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); - - } else { - mwifiex_restore_curr_bcn(priv); - } - } - - for (i = 0; i < adapter->num_in_scan_table; i++) - dev_dbg(adapter->dev, "info: scan:(%02d) %pM " - "RSSI[%03d], SSID[%s]\n", - i, adapter->scan_table[i].mac_address, - (s32) adapter->scan_table[i].rssi, - adapter->scan_table[i].ssid.ssid); -} - -/* * This function converts radio type scan parameter to a band configuration * to be used in join command. */ @@ -2072,175 +1286,6 @@ mwifiex_radio_type_to_band(u8 radio_type) } /* - * This function deletes a specific indexed entry from the scan table. - * - * This also compacts the remaining entries and adjusts any buffering - * of beacon/probe response data if needed. - */ -static void -mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 del_idx; - u32 beacon_buf_adj; - u8 *beacon_buf; - - /* - * Shift the saved beacon buffer data for the scan table back over the - * entry being removed. Update the end of buffer pointer. Save the - * deleted buffer allocation size for pointer adjustments for entries - * compacted after the deleted index. - */ - beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; - - dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " - "removal = %d bytes\n", table_idx, beacon_buf_adj); - - /* Check if the table entry had storage allocated for its beacon */ - if (beacon_buf_adj) { - beacon_buf = adapter->scan_table[table_idx].beacon_buf; - - /* - * Remove the entry's buffer space, decrement the table end - * pointer by the amount we are removing - */ - adapter->bcn_buf_end -= beacon_buf_adj; - - dev_dbg(adapter->dev, "info: scan: delete entry %d," - " compact data: %p <- %p (sz = %d)\n", - table_idx, beacon_buf, - beacon_buf + beacon_buf_adj, - (int)(adapter->bcn_buf_end - beacon_buf)); - - /* - * Compact data storage. Copy all data after the deleted - * entry's end address (beacon_buf + beacon_buf_adj) back - * to the original start address (beacon_buf). - * - * Scan table entries affected by the move will have their - * entry pointer adjusted below. - * - * Use memmove since the dest/src memory regions overlap. - */ - memmove(beacon_buf, beacon_buf + beacon_buf_adj, - adapter->bcn_buf_end - beacon_buf); - } - - dev_dbg(adapter->dev, - "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", - table_idx, adapter->num_in_scan_table); - - /* Shift all of the entries after the table_idx back by one, compacting - the table and removing the requested entry */ - for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; - del_idx++) { - /* Copy the next entry over this one */ - memcpy(adapter->scan_table + del_idx, - adapter->scan_table + del_idx + 1, - sizeof(struct mwifiex_bssdescriptor)); - - /* - * Adjust this entry's pointer to its beacon buffer based on - * the removed/compacted entry from the deleted index. Don't - * decrement if the buffer pointer is NULL (no data stored for - * this entry). - */ - if (adapter->scan_table[del_idx].beacon_buf) { - adapter->scan_table[del_idx].beacon_buf -= - beacon_buf_adj; - if (adapter->scan_table[del_idx].bcn_wpa_ie) - adapter->scan_table[del_idx].bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (adapter->scan_table[del_idx]. - beacon_buf + - adapter->scan_table[del_idx]. - wpa_offset); - if (adapter->scan_table[del_idx].bcn_rsn_ie) - adapter->scan_table[del_idx].bcn_rsn_ie = - (struct ieee_types_generic *) - (adapter->scan_table[del_idx]. - beacon_buf + - adapter->scan_table[del_idx]. - rsn_offset); - if (adapter->scan_table[del_idx].bcn_wapi_ie) - adapter->scan_table[del_idx].bcn_wapi_ie = - (struct ieee_types_generic *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - wapi_offset); - if (adapter->scan_table[del_idx].bcn_ht_cap) - adapter->scan_table[del_idx].bcn_ht_cap = - (struct ieee80211_ht_cap *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ht_cap_offset); - - if (adapter->scan_table[del_idx].bcn_ht_info) - adapter->scan_table[del_idx].bcn_ht_info = - (struct ieee80211_ht_info *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ht_info_offset); - if (adapter->scan_table[del_idx].bcn_bss_co_2040) - adapter->scan_table[del_idx].bcn_bss_co_2040 = - (u8 *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - bss_co_2040_offset); - if (adapter->scan_table[del_idx].bcn_ext_cap) - adapter->scan_table[del_idx].bcn_ext_cap = - (u8 *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ext_cap_offset); - if (adapter->scan_table[del_idx].bcn_obss_scan) - adapter->scan_table[del_idx]. - bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - overlap_bss_offset); - } - } - - /* The last entry is invalid now that it has been deleted or moved - back */ - memset(adapter->scan_table + adapter->num_in_scan_table - 1, - 0x00, sizeof(struct mwifiex_bssdescriptor)); - - adapter->num_in_scan_table--; -} - -/* - * This function deletes all occurrences of a given SSID from the scan table. - * - * This iterates through the scan table and deletes all entries that match - * the given SSID. It also compacts the remaining scan table entries. - */ -static int -mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *del_ssid) -{ - s32 table_idx = -1; - - dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", - del_ssid->ssid); - - /* If the requested SSID is found in the table, delete it. Then keep - searching the table for multiple entires for the SSID until no - more are found */ - while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, - NL80211_IFTYPE_UNSPECIFIED)) >= 0) { - dev_dbg(priv->adapter->dev, - "info: Scan: Delete SSID Entry: Found Idx = %d\n", - table_idx); - mwifiex_scan_delete_table_entry(priv, table_idx); - } - - return table_idx == -1 ? -1 : 0; -} - -/* * This is an internal function used to start a scan based on an input * configuration. * @@ -2248,8 +1293,8 @@ mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table. */ -int mwifiex_scan_networks(struct mwifiex_private *priv, - const struct mwifiex_user_scan_cfg *user_scan_in) +static int mwifiex_scan_networks(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; @@ -2258,7 +1303,6 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, struct mwifiex_ie_types_chan_list_param_set *chan_list_out; u32 buf_size; struct mwifiex_chan_scan_param_set *scan_chan_list; - u8 keep_previous_scan; u8 filtered_scan; u8 scan_current_chan_only; u8 max_chan_per_scan; @@ -2295,24 +1339,11 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, return -ENOMEM; } - keep_previous_scan = false; - mwifiex_scan_setup_scan_config(priv, user_scan_in, &scan_cfg_out->config, &chan_list_out, scan_chan_list, &max_chan_per_scan, &filtered_scan, &scan_current_chan_only); - if (user_scan_in) - keep_previous_scan = user_scan_in->keep_previous_scan; - - - if (!keep_previous_scan) { - memset(adapter->scan_table, 0x00, - sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); - adapter->num_in_scan_table = 0; - adapter->bcn_buf_end = adapter->bcn_buf; - } - ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, &scan_cfg_out->config, chan_list_out, scan_chan_list); @@ -2326,6 +1357,7 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); + adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); } else { @@ -2344,6 +1376,29 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, } /* + * Sends IOCTL request to start a scan with user configurations. + * + * This function allocates the IOCTL request buffer, fills it + * with requisite parameters and calls the IOCTL handler. + * + * Upon completion, it also generates a wireless event to notify + * applications. + */ +int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, + struct mwifiex_user_scan_cfg *scan_req) +{ + int status; + + priv->adapter->scan_wait_q_woken = false; + + status = mwifiex_scan_networks(priv, scan_req); + if (!status) + status = mwifiex_wait_queue_complete(priv->adapter); + + return status; +} + +/* * This function prepares a scan command to be sent to the firmware. * * This uses the scan command configuration sent to the command processing @@ -2379,6 +1434,112 @@ int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, } /* + * This function checks compatibility of requested network with current + * driver settings. + */ +int mwifiex_check_network_compatibility(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + int ret = -1; + + if (!bss_desc) + return -1; + + if ((mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, + (u8) bss_desc->bss_band, (u16) bss_desc->channel))) { + switch (priv->bss_mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + ret = mwifiex_is_network_compatible(priv, bss_desc, + priv->bss_mode); + if (ret) + dev_err(priv->adapter->dev, "cannot find ssid " + "%s\n", bss_desc->ssid.ssid); + break; + default: + ret = 0; + } + } + + return ret; +} + +static int +mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, + s32 rssi, const u8 *ie_buf, size_t ie_len, + u16 beacon_period, u16 cap_info_bitmap, u8 band) +{ + struct mwifiex_bssdescriptor *bss_desc = NULL; + int ret; + unsigned long flags; + u8 *beacon_ie; + + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), + GFP_KERNEL); + if (!bss_desc) { + dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); + return -ENOMEM; + } + + beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL); + if (!beacon_ie) { + dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); + return -ENOMEM; + } + + ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie, + ie_len, beacon_period, + cap_info_bitmap, band, bss_desc); + if (ret) + goto done; + + ret = mwifiex_check_network_compatibility(priv, bss_desc); + if (ret) + goto done; + + /* Update current bss descriptor parameters */ + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL; + priv->curr_bss_params.bss_descriptor.wpa_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL; + priv->curr_bss_params.bss_descriptor.rsn_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL; + priv->curr_bss_params.bss_descriptor.wapi_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL; + priv->curr_bss_params.bss_descriptor.ht_cap_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL; + priv->curr_bss_params.bss_descriptor.ht_info_offset = + 0; + priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 = + NULL; + priv->curr_bss_params.bss_descriptor. + bss_co_2040_offset = 0; + priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL; + priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0; + priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; + priv->curr_bss_params.bss_descriptor.beacon_buf_size = + 0; + + /* Make a copy of current BSSID descriptor */ + memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc, + sizeof(priv->curr_bss_params.bss_descriptor)); + mwifiex_save_curr_bcn(priv); + spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); + +done: + kfree(bss_desc); + kfree(beacon_ie); + return 0; +} + +static void mwifiex_free_bss_priv(struct cfg80211_bss *bss) +{ + kfree(bss->priv); +} + +/* * This function handles the command response of scan. * * The response buffer for the scan command has the following @@ -2404,23 +1565,19 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, struct mwifiex_adapter *adapter = priv->adapter; struct cmd_ctrl_node *cmd_node; struct host_cmd_ds_802_11_scan_rsp *scan_rsp; - struct mwifiex_bssdescriptor *bss_new_entry = NULL; struct mwifiex_ie_types_data *tlv_data; struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; u8 *bss_info; u32 scan_resp_size; u32 bytes_left; - u32 num_in_table; - u32 bss_idx; u32 idx; u32 tlv_buf_size; - long long tsf_val; struct mwifiex_chan_freq_power *cfp; struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; struct chan_band_param_set *chan_band; - u8 band; u8 is_bgscan_resp; unsigned long flags; + struct cfg80211_bss *bss; is_bgscan_resp = (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_BG_SCAN_QUERY); @@ -2430,7 +1587,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, scan_rsp = &resp->params.scan_resp; - if (scan_rsp->number_of_sets > IW_MAX_AP) { + if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) { dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", scan_rsp->number_of_sets); ret = -1; @@ -2447,7 +1604,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, "info: SCAN_RESP: returned %d APs before parsing\n", scan_rsp->number_of_sets); - num_in_table = adapter->num_in_scan_table; bss_info = scan_rsp->bss_desc_and_tlv_buffer; /* @@ -2479,125 +1635,149 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, (struct mwifiex_ie_types_data **) &chan_band_tlv); - /* - * Process each scan response returned (scan_rsp->number_of_sets). - * Save the information in the bss_new_entry and then insert into the - * driver scan table either as an update to an existing entry - * or as an addition at the end of the table - */ - bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), - GFP_KERNEL); - if (!bss_new_entry) { - dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); - return -ENOMEM; - } - for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { - /* Zero out the bss_new_entry we are about to store info in */ - memset(bss_new_entry, 0x00, - sizeof(struct mwifiex_bssdescriptor)); - - if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, - &bss_info, - &bytes_left)) { - /* Error parsing/interpreting scan response, skipped */ - dev_err(adapter->dev, "SCAN_RESP: " - "mwifiex_interpret_bss_desc_with_ie " - "returned ERROR\n"); - continue; + u8 bssid[ETH_ALEN]; + s32 rssi; + const u8 *ie_buf; + size_t ie_len; + int channel = -1; + u64 network_tsf = 0; + u16 beacon_size = 0; + u32 curr_bcn_bytes; + u32 freq; + u16 beacon_period; + u16 cap_info_bitmap; + u8 *current_ptr; + struct mwifiex_bcn_param *bcn_param; + + if (bytes_left >= sizeof(beacon_size)) { + /* Extract & convert beacon size from command buffer */ + memcpy(&beacon_size, bss_info, sizeof(beacon_size)); + bytes_left -= sizeof(beacon_size); + bss_info += sizeof(beacon_size); } - /* Process the data fields and IEs returned for this BSS */ - dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", - bss_new_entry->mac_address); + if (!beacon_size || beacon_size > bytes_left) { + bss_info += bytes_left; + bytes_left = 0; + return -1; + } - /* Search the scan table for the same bssid */ - for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { - if (memcmp(bss_new_entry->mac_address, - adapter->scan_table[bss_idx].mac_address, - sizeof(bss_new_entry->mac_address))) { - continue; + /* Initialize the current working beacon pointer for this BSS + * iteration */ + current_ptr = bss_info; + + /* Advance the return beacon pointer past the current beacon */ + bss_info += beacon_size; + bytes_left -= beacon_size; + + curr_bcn_bytes = beacon_size; + + /* + * First 5 fields are bssid, RSSI, time stamp, beacon interval, + * and capability information + */ + if (curr_bcn_bytes < sizeof(struct mwifiex_bcn_param)) { + dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); + continue; + } + bcn_param = (struct mwifiex_bcn_param *)current_ptr; + current_ptr += sizeof(*bcn_param); + curr_bcn_bytes -= sizeof(*bcn_param); + + memcpy(bssid, bcn_param->bssid, ETH_ALEN); + + rssi = (s32) (bcn_param->rssi); + dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", + rssi); + + beacon_period = le16_to_cpu(bcn_param->beacon_period); + + cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap); + dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", + cap_info_bitmap); + + /* Rest of the current buffer are IE's */ + ie_buf = current_ptr; + ie_len = curr_bcn_bytes; + dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP" + " = %d\n", curr_bcn_bytes); + + while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) { + u8 element_id, element_len; + + element_id = *current_ptr; + element_len = *(current_ptr + 1); + if (curr_bcn_bytes < element_len + + sizeof(struct ieee_types_header)) { + dev_err(priv->adapter->dev, "%s: in processing" + " IE, bytes left < IE length\n", + __func__); + goto done; } - /* - * If the SSID matches as well, it is a - * duplicate of this entry. Keep the bss_idx - * set to this entry so we replace the old - * contents in the table - */ - if ((bss_new_entry->ssid.ssid_len - == adapter->scan_table[bss_idx]. ssid.ssid_len) - && (!memcmp(bss_new_entry->ssid.ssid, - adapter->scan_table[bss_idx].ssid.ssid, - bss_new_entry->ssid.ssid_len))) { - dev_dbg(adapter->dev, "info: SCAN_RESP:" - " duplicate of index: %d\n", bss_idx); + if (element_id == WLAN_EID_DS_PARAMS) { + channel = *(u8 *) (current_ptr + + sizeof(struct ieee_types_header)); break; } - } - /* - * If the bss_idx is equal to the number of entries in - * the table, the new entry was not a duplicate; append - * it to the scan table - */ - if (bss_idx == num_in_table) { - /* Range check the bss_idx, keep it limited to - the last entry */ - if (bss_idx == IW_MAX_AP) - bss_idx--; - else - num_in_table++; + + current_ptr += element_len + + sizeof(struct ieee_types_header); + curr_bcn_bytes -= element_len + + sizeof(struct ieee_types_header); } /* - * Save the beacon/probe response returned for later application - * retrieval. Duplicate beacon/probe responses are updated if - * possible - */ - mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, - num_in_table, bss_new_entry); - /* * If the TSF TLV was appended to the scan results, save this * entry's TSF value in the networkTSF field.The networkTSF is * the firmware's TSF value at the time the beacon or probe * response was received. */ - if (tsf_tlv) { - memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] - , sizeof(tsf_val)); - memcpy(&bss_new_entry->network_tsf, &tsf_val, - sizeof(bss_new_entry->network_tsf)); - } - band = BAND_G; - if (chan_band_tlv) { - chan_band = &chan_band_tlv->chan_band_param[idx]; - band = mwifiex_radio_type_to_band(chan_band->radio_type - & (BIT(0) | BIT(1))); - } + if (tsf_tlv) + memcpy(&network_tsf, + &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], + sizeof(network_tsf)); + + if (channel != -1) { + struct ieee80211_channel *chan; + u8 band; + + band = BAND_G; + if (chan_band_tlv) { + chan_band = + &chan_band_tlv->chan_band_param[idx]; + band = mwifiex_radio_type_to_band( + chan_band->radio_type + & (BIT(0) | BIT(1))); + } - /* Save the band designation for this entry for use in join */ - bss_new_entry->bss_band = band; - cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, - (u8) bss_new_entry->bss_band, - (u16)bss_new_entry->channel); + cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211( + priv, (u8)band, (u16)channel); - if (cfp) - bss_new_entry->freq = cfp->freq; - else - bss_new_entry->freq = 0; + freq = cfp ? cfp->freq : 0; - /* Copy the locally created bss_new_entry to the scan table */ - memcpy(&adapter->scan_table[bss_idx], bss_new_entry, - sizeof(adapter->scan_table[bss_idx])); + chan = ieee80211_get_channel(priv->wdev->wiphy, freq); - } + if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + bss = cfg80211_inform_bss(priv->wdev->wiphy, + chan, bssid, network_tsf, + cap_info_bitmap, beacon_period, + ie_buf, ie_len, rssi, GFP_KERNEL); + *(u8 *)bss->priv = band; + bss->free_priv = mwifiex_free_bss_priv; - dev_dbg(adapter->dev, - "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", - scan_rsp->number_of_sets, - num_in_table - adapter->num_in_scan_table, num_in_table); - - /* Update the total number of BSSIDs in the scan table */ - adapter->num_in_scan_table = num_in_table; + if (priv->media_connected && !memcmp(bssid, + priv->curr_bss_params.bss_descriptor + .mac_address, ETH_ALEN)) + mwifiex_update_curr_bss_params(priv, + bssid, rssi, ie_buf, + ie_len, beacon_period, + cap_info_bitmap, band); + } + } else { + dev_dbg(adapter->dev, "missing BSS channel IE\n"); + } + } spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); if (list_empty(&adapter->scan_pending_q)) { @@ -2605,17 +1785,11 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); adapter->scan_processing = false; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - /* - * Process the resulting scan table: - * - Remove any bad ssids - * - Update our current BSS information from scan data - */ - mwifiex_process_scan_results(priv); /* Need to indicate IOCTL complete */ if (adapter->curr_cmd->wait_q_enabled) { adapter->cmd_wait_q.status = 0; - mwifiex_complete_cmd(adapter); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); } if (priv->report_scan_result) priv->report_scan_result = false; @@ -2636,7 +1810,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, } done: - kfree((u8 *) bss_new_entry); return ret; } @@ -2663,141 +1836,6 @@ int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) } /* - * This function finds a SSID in the scan table. - * - * A BSSID may optionally be provided to qualify the SSID. - * For non-Auto mode, further check is made to make sure the - * BSS found in the scan table is compatible with the current - * settings of the driver. - */ -s32 -mwifiex_find_ssid_in_list(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *ssid, u8 *bssid, - u32 mode) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 net = -1, j; - u8 best_rssi = 0; - u32 i; - - dev_dbg(adapter->dev, "info: num of entries in table = %d\n", - adapter->num_in_scan_table); - - /* - * Loop through the table until the maximum is reached or until a match - * is found based on the bssid field comparison - */ - for (i = 0; - i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); - i++) { - if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && - (!bssid - || !memcmp(adapter->scan_table[i].mac_address, bssid, - ETH_ALEN)) - && - (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 - (priv, (u8) adapter->scan_table[i].bss_band, - (u16) adapter->scan_table[i].channel))) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - j = mwifiex_is_network_compatible(priv, i, - mode); - - if (j >= 0) { - if (SCAN_RSSI - (adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table - [i].rssi); - net = i; - } - } else { - if (net == -1) - net = j; - } - break; - case NL80211_IFTYPE_UNSPECIFIED: - default: - /* - * Do not check compatibility if the mode - * requested is Auto/Unknown. Allows generic - * find to work without verifying against the - * Adapter security settings - */ - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table[i].rssi); - net = i; - } - break; - } - } - } - - return net; -} - -/* - * This function finds a specific compatible BSSID in the scan list. - * - * This function loops through the scan table looking for a compatible - * match. If a BSSID matches, but the BSS is found to be not compatible - * the function ignores it and continues to search through the rest of - * the entries in case there is an AP with multiple SSIDs assigned to - * the same BSSID. - */ -s32 -mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, - u32 mode) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 net = -1; - u32 i; - - if (!bssid) - return -1; - - dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", - adapter->num_in_scan_table); - - /* - * Look through the scan table for a compatible match. The ret return - * variable will be equal to the index in the scan table (greater - * than zero) if the network is compatible. The loop will continue - * past a matched bssid that is not compatible in case there is an - * AP with multiple SSIDs assigned to the same BSSID - */ - for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { - if (!memcmp - (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) - && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 - (priv, - (u8) adapter-> - scan_table[i]. - bss_band, - (u16) adapter-> - scan_table[i]. - channel)) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - net = mwifiex_is_network_compatible(priv, i, - mode); - break; - default: - net = i; - break; - } - } - } - - return net; -} - -/* * This function inserts scan command node to the scan pending queue. */ void @@ -2808,48 +1846,13 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv, unsigned long flags; cmd_node->wait_q_enabled = true; + cmd_node->condition = &adapter->scan_wait_q_woken; spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); list_add_tail(&cmd_node->list, &adapter->scan_pending_q); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); } /* - * This function finds an AP with specific ssid in the scan list. - */ -int mwifiex_find_best_network(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *req_ssid_bssid) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *req_bss; - s32 i; - - memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); - - i = mwifiex_find_best_network_in_list(priv); - - if (i >= 0) { - req_bss = &adapter->scan_table[i]; - memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, - sizeof(struct mwifiex_802_11_ssid)); - memcpy((u8 *) &req_ssid_bssid->bssid, - (u8 *) &req_bss->mac_address, ETH_ALEN); - - /* Make sure we are in the right mode */ - if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) - priv->bss_mode = req_bss->bss_mode; - } - - if (!req_ssid_bssid->ssid.ssid_len) - return -1; - - dev_dbg(adapter->dev, "info: Best network found = [%s], " - "[%pM]\n", req_ssid_bssid->ssid.ssid, - req_ssid_bssid->bssid); - - return 0; -} - -/* * This function sends a scan command for all available channels to the * firmware, filtered on a specific SSID. */ @@ -2874,8 +1877,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, return ret; } - mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); - scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); if (!scan_cfg) { dev_err(adapter->dev, "failed to alloc scan_cfg\n"); @@ -2884,7 +1885,6 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, req_ssid->ssid_len); - scan_cfg->keep_previous_scan = true; ret = mwifiex_scan_networks(priv, scan_cfg); @@ -2913,7 +1913,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv, } priv->scan_pending_on_block = true; - priv->adapter->cmd_wait_q.condition = false; + priv->adapter->scan_wait_q_woken = false; if (req_ssid && req_ssid->ssid_len != 0) /* Specific SSID scan */ @@ -2997,7 +1997,7 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) priv->curr_bcn_size = curr_bss->beacon_buf_size; kfree(priv->curr_bcn_buf); - priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, + priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size, GFP_KERNEL); if (!priv->curr_bcn_buf) { dev_err(priv->adapter->dev, @@ -3010,6 +2010,39 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) curr_bss->beacon_buf_size); dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", priv->curr_bcn_size); + + curr_bss->beacon_buf = priv->curr_bcn_buf; + + /* adjust the pointers in the current BSS descriptor */ + if (curr_bss->bcn_wpa_ie) + curr_bss->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (curr_bss->beacon_buf + + curr_bss->wpa_offset); + + if (curr_bss->bcn_rsn_ie) + curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) + (curr_bss->beacon_buf + + curr_bss->rsn_offset); + + if (curr_bss->bcn_ht_cap) + curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) + (curr_bss->beacon_buf + + curr_bss->ht_cap_offset); + + if (curr_bss->bcn_ht_info) + curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) + (curr_bss->beacon_buf + + curr_bss->ht_info_offset); + + if (curr_bss->bcn_bss_co_2040) + curr_bss->bcn_bss_co_2040 = + (u8 *) (curr_bss->beacon_buf + + curr_bss->bss_co_2040_offset); + + if (curr_bss->bcn_ext_cap) + curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + + curr_bss->ext_cap_offset); } /* diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index 82098ac483b8..283171bbcedf 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -89,7 +89,8 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) return -EIO; } - if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) { + if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops, + MWIFIEX_SDIO)) { pr_err("%s: add card failed\n", __func__); kfree(card); sdio_claim_host(func); @@ -830,7 +831,7 @@ done: * The winner interface is also determined by this function. */ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, - u32 poll_num, int *winner) + u32 poll_num) { int ret = 0; u16 firmware_stat; @@ -842,7 +843,7 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat); if (ret) continue; - if (firmware_stat == FIRMWARE_READY) { + if (firmware_stat == FIRMWARE_READY_SDIO) { ret = 0; break; } else { @@ -851,15 +852,15 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter, } } - if (winner && ret) { + if (ret) { if (mwifiex_read_reg (adapter, CARD_FW_STATUS0_REG, &winner_status)) winner_status = 0; if (winner_status) - *winner = 0; + adapter->winner = 0; else - *winner = 1; + adapter->winner = 1; } return ret; } @@ -1413,7 +1414,7 @@ tx_curr_single: * the type. The firmware handles the packets based upon this set type. */ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, - u8 type, u8 *payload, u32 pkt_len, + u8 type, struct sk_buff *skb, struct mwifiex_tx_param *tx_param) { struct sdio_mmc_card *card = adapter->card; @@ -1421,6 +1422,8 @@ static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter, u32 buf_block_len; u32 blk_size; u8 port = CTRL_PORT; + u8 *payload = (u8 *)skb->data; + u32 pkt_len = skb->len; /* Allocate buffer and copy payload */ blk_size = MWIFIEX_SDIO_BLOCK_SIZE; @@ -1722,6 +1725,8 @@ static struct mwifiex_if_ops sdio_ops = { /* SDIO specific */ .update_mp_end_port = mwifiex_update_mp_end_port, .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf, + .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete, + .event_complete = mwifiex_sdio_event_complete, }; /* diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h index 524f78f4ee69..3f711801e58a 100644 --- a/drivers/net/wireless/mwifiex/sdio.h +++ b/drivers/net/wireless/mwifiex/sdio.h @@ -169,9 +169,6 @@ /* Rx unit register */ #define CARD_RX_UNIT_REG 0x63 -/* Event header len w/o 4 bytes of interface header */ -#define MWIFIEX_EVENT_HEADER_LEN 4 - /* Max retry number of CMD53 write */ #define MAX_WRITE_IOMEM_RETRY 2 @@ -304,4 +301,25 @@ struct sdio_mmc_card { struct mwifiex_sdio_mpa_tx mpa_tx; struct mwifiex_sdio_mpa_rx mpa_rx; }; + +/* + * .cmdrsp_complete handler + */ +static inline int mwifiex_sdio_cmdrsp_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + return 0; +} + +/* + * .event_complete handler + */ +static inline int mwifiex_sdio_event_complete(struct mwifiex_adapter *adapter, + struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + return 0; +} + #endif /* _MWIFIEX_SDIO_H */ diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index c54ee287b878..ea6518d1c9e3 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -902,6 +902,59 @@ static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, } /* + * This function prepares command to set PCI-Express + * host buffer configuration + * + * Preparation includes - + * - Setting command ID, action and proper size + * - Setting host buffer configuration + * - Ensuring correct endian-ness + */ +static int +mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, u16 action) +{ + struct host_cmd_ds_pcie_details *host_spec = + &cmd->params.pcie_host_spec; + struct pcie_service_card *card = priv->adapter->card; + phys_addr_t *buf_pa; + + cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS); + cmd->size = cpu_to_le16(sizeof(struct + host_cmd_ds_pcie_details) + S_DS_GEN); + cmd->result = 0; + + memset(host_spec, 0, sizeof(struct host_cmd_ds_pcie_details)); + + if (action == HostCmd_ACT_GEN_SET) { + /* Send the ring base addresses and count to firmware */ + host_spec->txbd_addr_lo = (u32)(card->txbd_ring_pbase); + host_spec->txbd_addr_hi = + (u32)(((u64)card->txbd_ring_pbase)>>32); + host_spec->txbd_count = MWIFIEX_MAX_TXRX_BD; + host_spec->rxbd_addr_lo = (u32)(card->rxbd_ring_pbase); + host_spec->rxbd_addr_hi = + (u32)(((u64)card->rxbd_ring_pbase)>>32); + host_spec->rxbd_count = MWIFIEX_MAX_TXRX_BD; + host_spec->evtbd_addr_lo = + (u32)(card->evtbd_ring_pbase); + host_spec->evtbd_addr_hi = + (u32)(((u64)card->evtbd_ring_pbase)>>32); + host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD; + if (card->sleep_cookie) { + buf_pa = MWIFIEX_SKB_PACB(card->sleep_cookie); + host_spec->sleep_cookie_addr_lo = (u32) *buf_pa; + host_spec->sleep_cookie_addr_hi = + (u32) (((u64)*buf_pa) >> 32); + dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: " + "0x%x\n", host_spec->sleep_cookie_addr_lo); + } + } + + return 0; +} + +/* * This function prepares the commands before sending them to the firmware. * * This is a generic function which calls specific command preparation @@ -1079,6 +1132,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, host_cmd_ds_set_bss_mode) + S_DS_GEN); ret = 0; break; + case HostCmd_CMD_PCIE_DESC_DETAILS: + ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action); + break; default: dev_err(priv->adapter->dev, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -1095,6 +1151,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, * working state. * * The following commands are issued sequentially - + * - Set PCI-Express host buffer configuration (PCIE only) * - Function init (for first interface only) * - Read MAC address (for first interface only) * - Reconfigure Tx buffer size (for first interface only) @@ -1116,6 +1173,13 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) struct mwifiex_ds_11n_tx_cfg tx_cfg; if (first_sta) { + if (priv->adapter->iface_type == MWIFIEX_PCIE) { + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_PCIE_DESC_DETAILS, + HostCmd_ACT_GEN_SET, 0, NULL); + if (ret) + return -1; + } ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT, HostCmd_ACT_GEN_SET, 0, NULL); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 6804239d87bd..7a16b0c417af 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -952,6 +952,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_11N_CFG: ret = mwifiex_ret_11n_cfg(resp, data_buf); break; + case HostCmd_CMD_PCIE_DESC_DETAILS: + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index fc265cab0907..f204810e8338 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -130,8 +130,8 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); /* Reset wireless stats signal info */ - priv->w_stats.qual.level = 0; - priv->w_stats.qual.noise = 0; + priv->qual_level = 0; + priv->qual_noise = 0; } /* @@ -299,11 +299,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_BG_SCAN_REPORT: dev_dbg(adapter->dev, "event: BGS_REPORT\n"); - /* Clear the previous scan result */ - memset(adapter->scan_table, 0x00, - sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); - adapter->num_in_scan_table = 0; - adapter->bcn_buf_end = adapter->bcn_buf; ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_BG_SCAN_QUERY, HostCmd_ACT_GEN_GET, 0, NULL); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index c34ff8c4f4f8..ea4a29b7e331 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -55,7 +55,9 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { bool cancel_flag = false; int status = adapter->cmd_wait_q.status; + struct cmd_ctrl_node *cmd_queued = adapter->cmd_queued; + adapter->cmd_queued = NULL; dev_dbg(adapter->dev, "cmd pending\n"); atomic_inc(&adapter->cmd_pending); @@ -64,8 +66,8 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) /* Wait for completion */ wait_event_interruptible(adapter->cmd_wait_q.wait, - adapter->cmd_wait_q.condition); - if (!adapter->cmd_wait_q.condition) + *(cmd_queued->condition)); + if (!*(cmd_queued->condition)) cancel_flag = true; if (cancel_flag) { @@ -142,90 +144,146 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, } /* + * This function fills bss descriptor structure using provided + * information. + */ +int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, + u8 *bssid, s32 rssi, u8 *ie_buf, + size_t ie_len, u16 beacon_period, + u16 cap_info_bitmap, u8 band, + struct mwifiex_bssdescriptor *bss_desc) +{ + int ret; + + memcpy(bss_desc->mac_address, bssid, ETH_ALEN); + bss_desc->rssi = rssi; + bss_desc->beacon_buf = ie_buf; + bss_desc->beacon_buf_size = ie_len; + bss_desc->beacon_period = beacon_period; + bss_desc->cap_info_bitmap = cap_info_bitmap; + bss_desc->bss_band = band; + if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { + dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n"); + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; + } else { + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS) + bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; + else + bss_desc->bss_mode = NL80211_IFTYPE_STATION; + + ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc, + ie_buf, ie_len); + + return ret; +} + +/* * In Ad-Hoc mode, the IBSS is created if not found in scan list. * In both Ad-Hoc and infra mode, an deauthentication is performed * first. */ -int mwifiex_bss_start(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) +int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, + struct mwifiex_802_11_ssid *req_ssid) { int ret; struct mwifiex_adapter *adapter = priv->adapter; - s32 i = -1; + struct mwifiex_bssdescriptor *bss_desc = NULL; + u8 *beacon_ie = NULL; priv->scan_block = false; - if (!ssid_bssid) - return -1; + + if (bss) { + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), + GFP_KERNEL); + if (!bss_desc) { + dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); + return -ENOMEM; + } + + beacon_ie = kmemdup(bss->information_elements, + bss->len_beacon_ies, GFP_KERNEL); + if (!beacon_ie) { + kfree(bss_desc); + dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); + return -ENOMEM; + } + + ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal, + beacon_ie, bss->len_beacon_ies, + bss->beacon_interval, + bss->capability, + *(u8 *)bss->priv, bss_desc); + if (ret) + goto done; + } if (priv->bss_mode == NL80211_IFTYPE_STATION) { /* Infra mode */ ret = mwifiex_deauthenticate(priv, NULL); if (ret) - return ret; + goto done; - /* Search for the requested SSID in the scan table */ - if (ssid_bssid->ssid.ssid_len) - i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, - NULL, NL80211_IFTYPE_STATION); - else - i = mwifiex_find_bssid_in_list(priv, - (u8 *) &ssid_bssid->bssid, - NL80211_IFTYPE_STATION); - if (i < 0) - return -1; + ret = mwifiex_check_network_compatibility(priv, bss_desc); + if (ret) + goto done; - dev_dbg(adapter->dev, - "info: SSID found in scan list ... associating...\n"); + dev_dbg(adapter->dev, "info: SSID found in scan list ... " + "associating...\n"); + + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); /* Clear any past association response stored for * application retrieval */ priv->assoc_rsp_size = 0; - ret = mwifiex_associate(priv, &adapter->scan_table[i]); - if (ret) - return ret; + ret = mwifiex_associate(priv, bss_desc); + if (bss) + cfg80211_put_bss(bss); } else { /* Adhoc mode */ /* If the requested SSID matches current SSID, return */ - if (ssid_bssid->ssid.ssid_len && + if (bss_desc && bss_desc->ssid.ssid_len && (!mwifiex_ssid_cmp (&priv->curr_bss_params.bss_descriptor.ssid, - &ssid_bssid->ssid))) + &bss_desc->ssid))) { + kfree(bss_desc); + kfree(beacon_ie); return 0; + } /* Exit Adhoc mode first */ dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); ret = mwifiex_deauthenticate(priv, NULL); if (ret) - return ret; + goto done; priv->adhoc_is_link_sensed = false; - /* Search for the requested network in the scan table */ - if (ssid_bssid->ssid.ssid_len) - i = mwifiex_find_ssid_in_list(priv, - &ssid_bssid->ssid, NULL, - NL80211_IFTYPE_ADHOC); - else - i = mwifiex_find_bssid_in_list(priv, - (u8 *)&ssid_bssid->bssid, - NL80211_IFTYPE_ADHOC); + ret = mwifiex_check_network_compatibility(priv, bss_desc); + + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); - if (i >= 0) { + if (!ret) { dev_dbg(adapter->dev, "info: network found in scan" " list. Joining...\n"); - ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]); - if (ret) - return ret; + ret = mwifiex_adhoc_join(priv, bss_desc); + if (bss) + cfg80211_put_bss(bss); } else { dev_dbg(adapter->dev, "info: Network not found in " "the list, creating adhoc with ssid = %s\n", - ssid_bssid->ssid.ssid); - ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid); - if (ret) - return ret; + req_ssid->ssid); + ret = mwifiex_adhoc_start(priv, req_ssid); } } +done: + kfree(bss_desc); + kfree(beacon_ie); return ret; } @@ -235,8 +293,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, * This function prepares the correct firmware command and * issues it. */ -int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, - int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) +static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) { struct mwifiex_adapter *adapter = priv->adapter; @@ -376,7 +434,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_bssdescriptor *bss_desc; - s32 tbl_idx; if (!info) return -1; @@ -394,17 +451,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, info->region_code = adapter->region_code; - /* Scan table index if connected */ - info->scan_table_idx = 0; - if (priv->media_connected) { - tbl_idx = - mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, - bss_desc->mac_address, - priv->bss_mode); - if (tbl_idx >= 0) - info->scan_table_idx = tbl_idx; - } - info->media_connected = priv->media_connected; info->max_power_level = priv->max_tx_power_level; @@ -586,50 +632,6 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, } /* - * IOCTL request handler to find a particular BSS. - * - * The BSS can be searched with either a BSSID or a SSID. If none of - * these are provided, just the best BSS (best RSSI) is returned. - */ -int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *bss_desc; - u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - u8 mac[ETH_ALEN]; - int i = 0; - - if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { - i = mwifiex_find_bssid_in_list(priv, - (u8 *) ssid_bssid->bssid, - priv->bss_mode); - if (i < 0) { - memcpy(mac, ssid_bssid->bssid, sizeof(mac)); - dev_err(adapter->dev, "cannot find bssid %pM\n", mac); - return -1; - } - bss_desc = &adapter->scan_table[i]; - memcpy(&ssid_bssid->ssid, &bss_desc->ssid, - sizeof(struct mwifiex_802_11_ssid)); - } else if (ssid_bssid->ssid.ssid_len) { - i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, - priv->bss_mode); - if (i < 0) { - dev_err(adapter->dev, "cannot find ssid %s\n", - ssid_bssid->ssid.ssid); - return -1; - } - bss_desc = &adapter->scan_table[i]; - memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); - } else { - return mwifiex_find_best_network(priv, ssid_bssid); - } - - return 0; -} - -/* * IOCTL request handler to change Ad-Hoc channel. * * This function allocates the IOCTL request buffer, fills it @@ -653,6 +655,9 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) struct mwifiex_bss_info bss_info; struct mwifiex_ssid_bssid ssid_bssid; u16 curr_chan = 0; + struct cfg80211_bss *bss = NULL; + struct ieee80211_channel *chan; + enum ieee80211_band band; memset(&bss_info, 0, sizeof(bss_info)); @@ -688,12 +693,20 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) ret = -1; goto done; } - /* Start/Join Adhoc network */ - memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); - memcpy(&ssid_bssid.ssid, &bss_info.ssid, - sizeof(struct mwifiex_802_11_ssid)); - ret = mwifiex_bss_start(priv, &ssid_bssid); + band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); + chan = __ieee80211_get_channel(priv->wdev->wiphy, + ieee80211_channel_to_frequency(channel, band)); + + /* Find the BSS we want using available scan results */ + bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid, + bss_info.ssid.ssid, bss_info.ssid.ssid_len, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (!bss) + wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n", + bss_info.bssid); + + ret = mwifiex_bss_start(priv, bss, &bss_info.ssid); done: return ret; } @@ -709,51 +722,9 @@ done: static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate_cfg) { - struct mwifiex_adapter *adapter = priv->adapter; - rate_cfg->is_rate_auto = priv->is_data_rate_auto; - if (!priv->media_connected) { - switch (adapter->config_bands) { - case BAND_B: - /* Return the lowest supported rate for B band */ - rate_cfg->rate = supported_rates_b[0] & 0x7f; - break; - case BAND_G: - case BAND_G | BAND_GN: - /* Return the lowest supported rate for G band */ - rate_cfg->rate = supported_rates_g[0] & 0x7f; - break; - case BAND_B | BAND_G: - case BAND_A | BAND_B | BAND_G: - case BAND_A | BAND_B: - case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: - case BAND_B | BAND_G | BAND_GN: - /* Return the lowest supported rate for BG band */ - rate_cfg->rate = supported_rates_bg[0] & 0x7f; - break; - case BAND_A: - case BAND_A | BAND_G: - case BAND_A | BAND_G | BAND_AN | BAND_GN: - case BAND_A | BAND_AN: - /* Return the lowest supported rate for A band */ - rate_cfg->rate = supported_rates_a[0] & 0x7f; - break; - case BAND_GN: - /* Return the lowest supported rate for N band */ - rate_cfg->rate = supported_rates_n[0] & 0x7f; - break; - default: - dev_warn(adapter->dev, "invalid band %#x\n", - adapter->config_bands); - break; - } - } else { - return mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL); - } - - return 0; + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); } /* @@ -794,7 +765,7 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) break; } - if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) { + if ((i == MWIFIEX_SUPPORTED_RATES) || !rate[i]) { dev_err(adapter->dev, "fixed data rate %#x is out " "of range\n", rate_cfg->rate); return -1; @@ -860,10 +831,10 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, ret = mwifiex_rate_ioctl_cfg(priv, rate); if (!ret) { - if (rate && rate->is_rate_auto) + if (rate->is_rate_auto) rate->rate = mwifiex_index_to_data_rate(priv->tx_rate, priv->tx_htinfo); - else if (rate) + else rate->rate = priv->data_rate; } else { ret = -1; @@ -1280,9 +1251,9 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, if (!status) { if (signal->selector & BCN_RSSI_AVG_MASK) - priv->w_stats.qual.level = signal->bcn_rssi_avg; + priv->qual_level = signal->bcn_rssi_avg; if (signal->selector & BCN_NF_AVG_MASK) - priv->w_stats.qual.noise = signal->bcn_nf_avg; + priv->qual_noise = signal->bcn_nf_avg; } return status; @@ -1341,18 +1312,8 @@ int mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log) { - int ret; - - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, HostCmd_ACT_GEN_GET, 0, log); - - if (!ret) { - priv->w_stats.discard.fragment = log->fcs_error; - priv->w_stats.discard.retries = log->retry; - priv->w_stats.discard.misc = log->ack_failure; - } - - return ret; } /* @@ -1594,7 +1555,7 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) { struct mwifiex_ds_misc_gen_ie gen_ie; - if (ie_len > IW_CUSTOM_MAX) + if (ie_len > IEEE_MAX_IE_SIZE) return -EFAULT; gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c index 1822bfad8896..d97facd70e88 100644 --- a/drivers/net/wireless/mwifiex/sta_tx.c +++ b/drivers/net/wireless/mwifiex/sta_tx.c @@ -151,7 +151,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags) skb_push(skb, INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb->data, skb->len, NULL); + skb, NULL); switch (ret) { case -EBUSY: adapter->data_sent = true; diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 6190b2fa57a3..a206f412875f 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -78,7 +78,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, (struct txpd *) (head_ptr + INTF_HEADER_LEN); ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb->data, skb->len, tx_param); + skb, tx_param); } switch (ret) { @@ -87,7 +87,8 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb, (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) { priv->adapter->tx_lock_flag = false; - local_tx_pd->flags = 0; + if (local_tx_pd) + local_tx_pd->flags = 0; } dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); break; @@ -160,43 +161,3 @@ done: return 0; } -/* - * Packet receive completion callback handler. - * - * This function calls another completion callback handler which - * updates the statistics, and optionally updates the parent buffer - * use count before freeing the received packet. - */ -int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter, - struct sk_buff *skb, int status) -{ - struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb); - struct mwifiex_rxinfo *rx_info_parent; - struct mwifiex_private *priv; - struct sk_buff *skb_parent; - unsigned long flags; - - priv = adapter->priv[rx_info->bss_index]; - - if (priv && (status == -1)) - priv->stats.rx_dropped++; - - if (rx_info->parent) { - skb_parent = rx_info->parent; - rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent); - - spin_lock_irqsave(&priv->rx_pkt_lock, flags); - --rx_info_parent->use_count; - - if (!rx_info_parent->use_count) { - spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - dev_kfree_skb_any(skb_parent); - } else { - spin_unlock_irqrestore(&priv->rx_pkt_lock, flags); - } - } else { - dev_kfree_skb_any(skb); - } - - return 0; -} diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index d41291529bc0..06976f517f66 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -185,13 +185,14 @@ int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb) * corresponding waiting function. Otherwise, it processes the * IOCTL response and frees the response buffer. */ -int mwifiex_complete_cmd(struct mwifiex_adapter *adapter) +int mwifiex_complete_cmd(struct mwifiex_adapter *adapter, + struct cmd_ctrl_node *cmd_node) { atomic_dec(&adapter->cmd_pending); dev_dbg(adapter->dev, "cmd completed: status=%d\n", adapter->cmd_wait_q.status); - adapter->cmd_wait_q.condition = true; + *(cmd_node->condition) = true; if (adapter->cmd_wait_q.status == -ETIMEDOUT) dev_err(adapter->dev, "cmd timeout\n"); diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h index 9506afc6c0e4..f6d36b9654a0 100644 --- a/drivers/net/wireless/mwifiex/util.h +++ b/drivers/net/wireless/mwifiex/util.h @@ -22,11 +22,16 @@ static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb) { - return (struct mwifiex_rxinfo *)skb->cb; + return (struct mwifiex_rxinfo *)(skb->cb + sizeof(phys_addr_t)); } static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb) { - return (struct mwifiex_txinfo *)skb->cb; + return (struct mwifiex_txinfo *)(skb->cb + sizeof(phys_addr_t)); +} + +static inline phys_addr_t *MWIFIEX_SKB_PACB(struct sk_buff *skb) +{ + return (phys_addr_t *)skb->cb; } #endif /* !_MWIFIEX_UTIL_H_ */ diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 69e260b41711..6c239c3c8249 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -121,7 +121,6 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra) memcpy(ra_list->ra, ra, ETH_ALEN); ra_list->total_pkts_size = 0; - ra_list->total_pkts = 0; dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list); @@ -648,7 +647,6 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter, skb_queue_tail(&ra_list->skb_head, skb); ra_list->total_pkts_size += skb->len; - ra_list->total_pkts++; atomic_inc(&priv->wmm.tx_pkts_queued); @@ -975,6 +973,28 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, } /* + * This function checks if 11n aggregation is possible. + */ +static int +mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv, + struct mwifiex_ra_list_tbl *ptr, + int max_buf_size) +{ + int count = 0, total_size = 0; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&ptr->skb_head, skb, tmp) { + total_size += skb->len; + if (total_size >= max_buf_size) + break; + if (++count >= MIN_NUM_AMSDU) + return true; + } + + return false; +} + +/* * This function sends a single packet to firmware for transmission. */ static void @@ -1001,7 +1021,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb); ptr->total_pkts_size -= skb->len; - ptr->total_pkts--; if (!skb_queue_empty(&ptr->skb_head)) skb_next = skb_peek(&ptr->skb_head); @@ -1027,7 +1046,6 @@ mwifiex_send_single_packet(struct mwifiex_private *priv, skb_queue_tail(&ptr->skb_head, skb); ptr->total_pkts_size += skb->len; - ptr->total_pkts++; tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags); @@ -1107,8 +1125,8 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv, tx_param.next_pkt_len = ((skb_next) ? skb_next->len + sizeof(struct txpd) : 0); - ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, - skb->data, skb->len, &tx_param); + ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA, skb, + &tx_param); switch (ret) { case -EBUSY: dev_dbg(adapter->dev, "data: -EBUSY is returned\n"); @@ -1213,11 +1231,9 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) mwifiex_send_delba(priv, tid_del, ra, 1); } } -/* Minimum number of AMSDU */ -#define MIN_NUM_AMSDU 2 - if (mwifiex_is_amsdu_allowed(priv, tid) && - (ptr->total_pkts >= MIN_NUM_AMSDU)) + mwifiex_is_11n_aggragation_possible(priv, ptr, + adapter->tx_buf_size)) mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN, ptr_index, flags); /* ra_list_spinlock has been freed in diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index da36dbf8d871..995695c28d5c 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -4097,9 +4097,6 @@ static int mwl8k_set_key(struct ieee80211_hw *hw, if (rc) goto out; - - mwl8k_vif->is_hw_crypto_enabled = false; - } out: return rc; @@ -4918,7 +4915,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw, return ret; } -static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int mwl8k_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct mwl8k_priv *priv = hw->priv; @@ -5465,7 +5463,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) goto fail; for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) { - rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]); + rc = mwl8k_conf_tx(hw, NULL, i, &priv->wmm_params[i]); if (rc) goto fail; } @@ -5504,6 +5502,14 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv) /* Set rssi values to dBm */ hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL; + + /* + * Ask mac80211 to not to trigger PS mode + * based on PM bit of incoming frames. + */ + if (priv->ap_fw) + hw->flags |= IEEE80211_HW_AP_LINK_PS; + hw->vif_data_size = sizeof(struct mwl8k_vif); hw->sta_data_size = sizeof(struct mwl8k_sta); diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index ef7efe839bb8..b52acc4b4086 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2135,7 +2135,7 @@ static const struct net_device_ops orinoco_netdev_ops = { .ndo_open = orinoco_open, .ndo_stop = orinoco_stop, .ndo_start_xmit = orinoco_xmit, - .ndo_set_multicast_list = orinoco_set_multicast_list, + .ndo_set_rx_mode = orinoco_set_multicast_list, .ndo_change_mtu = orinoco_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index 811e87f8a349..0793e4265b43 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -1562,7 +1562,7 @@ static const struct net_device_ops ezusb_netdev_ops = { .ndo_open = orinoco_open, .ndo_stop = orinoco_stop, .ndo_start_xmit = ezusb_xmit, - .ndo_set_multicast_list = orinoco_set_multicast_list, + .ndo_set_rx_mode = orinoco_set_multicast_list, .ndo_change_mtu = orinoco_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c index bbb9beb206b1..33747e131a96 100644 --- a/drivers/net/wireless/orinoco/wext.c +++ b/drivers/net/wireless/orinoco/wext.c @@ -9,6 +9,7 @@ #include <linux/ieee80211.h> #include <net/iw_handler.h> #include <net/cfg80211.h> +#include <net/cfg80211-wext.h> #include "hermes.h" #include "hermes_rid.h" diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 54cc0bba66b9..8b6f363b3f7d 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -145,6 +145,7 @@ static int p54_fill_band_bitrates(struct ieee80211_hw *dev, static int p54_generate_band(struct ieee80211_hw *dev, struct p54_channel_list *list, + unsigned int *chan_num, enum ieee80211_band band) { struct p54_common *priv = dev->priv; @@ -190,7 +191,14 @@ static int p54_generate_band(struct ieee80211_hw *dev, tmp->channels[j].band = chan->band; tmp->channels[j].center_freq = chan->freq; + priv->survey[*chan_num].channel = &tmp->channels[j]; + priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM | + SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_BUSY | + SURVEY_INFO_CHANNEL_TIME_TX; + tmp->channels[j].hw_value = (*chan_num); j++; + (*chan_num)++; } if (j == 0) { @@ -263,7 +271,7 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; struct p54_channel_list *list; - unsigned int i, j, max_channel_num; + unsigned int i, j, k, max_channel_num; int ret = 0; u16 freq; @@ -283,6 +291,13 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) ret = -ENOMEM; goto free; } + priv->chan_num = max_channel_num; + priv->survey = kzalloc(sizeof(struct survey_info) * max_channel_num, + GFP_KERNEL); + if (!priv->survey) { + ret = -ENOMEM; + goto free; + } list->max_entries = max_channel_num; list->channels = kzalloc(sizeof(struct p54_channel_entry) * @@ -321,8 +336,9 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) sort(list->channels, list->entries, sizeof(struct p54_channel_entry), p54_compare_channels, NULL); + k = 0; for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) { - if (p54_generate_band(dev, list, i) == 0) + if (p54_generate_band(dev, list, &k, i) == 0) j++; } if (j == 0) { @@ -335,6 +351,10 @@ free: kfree(list->channels); kfree(list); } + if (ret) { + kfree(priv->survey); + priv->survey = NULL; + } return ret; } @@ -853,10 +873,12 @@ err: kfree(priv->output_limit); kfree(priv->curve_data); kfree(priv->rssi_db); + kfree(priv->survey); priv->iq_autocal = NULL; priv->output_limit = NULL; priv->curve_data = NULL; priv->rssi_db = NULL; + priv->survey = NULL; wiphy_err(dev->wiphy, "eeprom parse failed!\n"); return err; diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index b6a061cbbdec..53a3408931be 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -385,6 +385,7 @@ int p54_setup_mac(struct p54_common *priv) setup->v2.osc_start_delay = cpu_to_le16(65535); } p54_tx(priv, skb); + priv->phy_idle = mode == P54_FILTER_TYPE_HIBERNATE; return 0; } @@ -626,6 +627,7 @@ int p54_set_ps(struct p54_common *priv) psm->exclude[0] = WLAN_EID_TIM; p54_tx(priv, skb); + priv->phy_ps = mode != P54_PSM_CAM; return 0; } diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index a5a6d9e647bb..ad9ae04d07aa 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -204,13 +204,11 @@ static void p54_stop(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int i; - mutex_lock(&priv->conf_mutex); priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->softled_state = 0; - p54_set_leds(priv); - cancel_delayed_work_sync(&priv->work); - + mutex_lock(&priv->conf_mutex); + p54_set_leds(priv); priv->stop(dev); skb_queue_purge(&priv->tx_pending); skb_queue_purge(&priv->tx_queue); @@ -278,6 +276,42 @@ static void p54_remove_interface(struct ieee80211_hw *dev, mutex_unlock(&priv->conf_mutex); } +static int p54_wait_for_stats(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int ret; + + priv->update_stats = true; + ret = p54_fetch_statistics(priv); + if (ret) + return ret; + + ret = wait_for_completion_interruptible_timeout(&priv->stat_comp, HZ); + if (ret == 0) + return -ETIMEDOUT; + + return 0; +} + +static void p54_reset_stats(struct p54_common *priv) +{ + struct ieee80211_channel *chan = priv->curchan; + + if (chan) { + struct survey_info *info = &priv->survey[chan->hw_value]; + + /* only reset channel statistics, don't touch .filled, etc. */ + info->channel_time = 0; + info->channel_time_busy = 0; + info->channel_time_tx = 0; + } + + priv->update_stats = true; + priv->survey_raw.active = 0; + priv->survey_raw.cca = 0; + priv->survey_raw.tx = 0; +} + static int p54_config(struct ieee80211_hw *dev, u32 changed) { int ret = 0; @@ -288,19 +322,36 @@ static int p54_config(struct ieee80211_hw *dev, u32 changed) if (changed & IEEE80211_CONF_CHANGE_POWER) priv->output_power = conf->power_level << 2; if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + struct ieee80211_channel *oldchan; + WARN_ON(p54_wait_for_stats(dev)); + oldchan = priv->curchan; + priv->curchan = NULL; ret = p54_scan(priv, P54_SCAN_EXIT, 0); - if (ret) + if (ret) { + priv->curchan = oldchan; goto out; + } + /* + * TODO: Use the LM_SCAN_TRAP to determine the current + * operating channel. + */ + priv->curchan = priv->hw->conf.channel; + p54_reset_stats(priv); + WARN_ON(p54_fetch_statistics(priv)); } if (changed & IEEE80211_CONF_CHANGE_PS) { + WARN_ON(p54_wait_for_stats(dev)); ret = p54_set_ps(priv); if (ret) goto out; + WARN_ON(p54_wait_for_stats(dev)); } if (changed & IEEE80211_CONF_CHANGE_IDLE) { + WARN_ON(p54_wait_for_stats(dev)); ret = p54_setup_mac(priv); if (ret) goto out; + WARN_ON(p54_wait_for_stats(dev)); } out: @@ -353,7 +404,8 @@ static void p54_configure_filter(struct ieee80211_hw *dev, p54_set_groupfilter(priv); } -static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, +static int p54_conf_tx(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; @@ -384,7 +436,9 @@ static void p54_work(struct work_struct *work) * 2. cancel stuck frames / reset the device if necessary. */ - p54_fetch_statistics(priv); + mutex_lock(&priv->conf_mutex); + WARN_ON_ONCE(p54_fetch_statistics(priv)); + mutex_unlock(&priv->conf_mutex); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -541,16 +595,47 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx, struct survey_info *survey) { struct p54_common *priv = dev->priv; - struct ieee80211_conf *conf = &dev->conf; + struct ieee80211_channel *chan; + int err, tries; + bool in_use = false; - if (idx != 0) + if (idx >= priv->chan_num) return -ENOENT; - survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = clamp_t(s8, priv->noise, -128, 127); +#define MAX_TRIES 1 + for (tries = 0; tries < MAX_TRIES; tries++) { + chan = priv->curchan; + if (chan && chan->hw_value == idx) { + mutex_lock(&priv->conf_mutex); + err = p54_wait_for_stats(dev); + mutex_unlock(&priv->conf_mutex); + if (err) + return err; + + in_use = true; + } - return 0; + memcpy(survey, &priv->survey[idx], sizeof(*survey)); + + if (in_use) { + /* test if the reported statistics are valid. */ + if (survey->channel_time != 0) { + survey->filled |= SURVEY_INFO_IN_USE; + } else { + /* + * hw/fw has not accumulated enough sample sets. + * Wait for 100ms, this ought to be enough to + * to get at least one non-null set of channel + * usage statistics. + */ + msleep(100); + continue; + } + } + return 0; + } + return -ETIMEDOUT; +#undef MAX_TRIES } static unsigned int p54_flush_count(struct p54_common *priv) @@ -686,11 +771,14 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) mutex_init(&priv->conf_mutex); mutex_init(&priv->eeprom_mutex); + init_completion(&priv->stat_comp); init_completion(&priv->eeprom_comp); init_completion(&priv->beacon_comp); INIT_DELAYED_WORK(&priv->work, p54_work); memset(&priv->mc_maclist[0], ~0, ETH_ALEN); + priv->curchan = NULL; + p54_reset_stats(priv); return dev; } EXPORT_SYMBOL_GPL(p54_init_common); @@ -730,11 +818,13 @@ void p54_free_common(struct ieee80211_hw *dev) kfree(priv->curve_data); kfree(priv->rssi_db); kfree(priv->used_rxkeys); + kfree(priv->survey); priv->iq_autocal = NULL; priv->output_limit = NULL; priv->curve_data = NULL; priv->rssi_db = NULL; priv->used_rxkeys = NULL; + priv->survey = NULL; ieee80211_free_hw(dev); } EXPORT_SYMBOL_GPL(p54_free_common); diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 799d05e12595..452fa3a64aa1 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -199,6 +199,22 @@ struct p54_common { u8 tx_diversity_mask; unsigned int output_power; struct p54_rssi_db_entry *cur_rssi; + struct ieee80211_channel *curchan; + struct survey_info *survey; + unsigned int chan_num; + struct completion stat_comp; + bool update_stats; + struct { + unsigned int timestamp; + unsigned int cached_cca; + unsigned int cached_tx; + unsigned int cached_rssi; + u64 active; + u64 cca; + u64 tx; + u64 rssi; + } survey_raw; + int noise; /* calibration, output power limit and rssi<->dBm conversation data */ struct pda_iq_autocal_entry *iq_autocal; @@ -220,6 +236,8 @@ struct p54_common { u32 basic_rate_mask; u16 aid; u8 coverage_class; + bool phy_idle; + bool phy_ps; bool powersave_override; __le32 beacon_req_id; struct completion beacon_comp; diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 6d9204fef90b..f18df82eeb92 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -41,7 +41,6 @@ #endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */ MODULE_FIRMWARE("3826.arm"); -MODULE_ALIAS("stlc45xx"); /* * gpios should be handled in board files and provided via platform data, @@ -738,3 +737,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>"); MODULE_ALIAS("spi:cx3110x"); MODULE_ALIAS("spi:p54spi"); +MODULE_ALIAS("spi:stlc45xx"); diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 042842e704de..f485784a60ae 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/firmware.h> #include <linux/etherdevice.h> +#include <asm/div64.h> #include <net/mac80211.h> @@ -507,6 +508,8 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_statistics *stats = (struct p54_statistics *) hdr->data; struct sk_buff *tmp; + struct ieee80211_channel *chan; + unsigned int i, rssi, tx, cca, dtime, dtotal, dcca, dtx, drssi, unit; u32 tsf32; if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) @@ -523,8 +526,75 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb) priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise)); + /* + * STSW450X LMAC API page 26 - 3.8 Statistics + * "The exact measurement period can be derived from the + * timestamp member". + */ + dtime = tsf32 - priv->survey_raw.timestamp; + + /* + * STSW450X LMAC API page 26 - 3.8.1 Noise histogram + * The LMAC samples RSSI, CCA and transmit state at regular + * periods (typically 8 times per 1k [as in 1024] usec). + */ + cca = le32_to_cpu(stats->sample_cca); + tx = le32_to_cpu(stats->sample_tx); + rssi = 0; + for (i = 0; i < ARRAY_SIZE(stats->sample_noise); i++) + rssi += le32_to_cpu(stats->sample_noise[i]); + + dcca = cca - priv->survey_raw.cached_cca; + drssi = rssi - priv->survey_raw.cached_rssi; + dtx = tx - priv->survey_raw.cached_tx; + dtotal = dcca + drssi + dtx; + + /* + * update statistics when more than a second is over since the + * last call, or when a update is badly needed. + */ + if (dtotal && (priv->update_stats || dtime >= USEC_PER_SEC) && + dtime >= dtotal) { + priv->survey_raw.timestamp = tsf32; + priv->update_stats = false; + unit = dtime / dtotal; + + if (dcca) { + priv->survey_raw.cca += dcca * unit; + priv->survey_raw.cached_cca = cca; + } + if (dtx) { + priv->survey_raw.tx += dtx * unit; + priv->survey_raw.cached_tx = tx; + } + if (drssi) { + priv->survey_raw.rssi += drssi * unit; + priv->survey_raw.cached_rssi = rssi; + } + + /* 1024 usec / 8 times = 128 usec / time */ + if (!(priv->phy_ps || priv->phy_idle)) + priv->survey_raw.active += dtotal * unit; + else + priv->survey_raw.active += (dcca + dtx) * unit; + } + + chan = priv->curchan; + if (chan) { + struct survey_info *survey = &priv->survey[chan->hw_value]; + survey->noise = clamp_t(s8, priv->noise, -128, 127); + survey->channel_time = priv->survey_raw.active; + survey->channel_time_tx = priv->survey_raw.tx; + survey->channel_time_busy = priv->survey_raw.tx + + priv->survey_raw.cca; + do_div(survey->channel_time, 1024); + do_div(survey->channel_time_tx, 1024); + do_div(survey->channel_time_busy, 1024); + } + tmp = p54_find_and_unlink_skb(priv, hdr->req_id); dev_kfree_skb_any(tmp); + complete(&priv->stat_comp); } static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb) @@ -619,7 +689,7 @@ static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb, if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ)) *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; - if (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE) + if (info->flags & IEEE80211_TX_CTL_POLL_RESPONSE) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 2a06ebcd67c5..0021e4948512 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -273,7 +273,7 @@ static const struct net_device_ops ray_netdev_ops = { .ndo_start_xmit = ray_dev_start_xmit, .ndo_set_config = ray_dev_config, .ndo_get_stats = ray_get_stats, - .ndo_set_multicast_list = set_multicast_list, + .ndo_set_rx_mode = set_multicast_list, .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 29f938930667..0c13840a7de5 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -36,13 +36,11 @@ #include <linux/mii.h> #include <linux/usb.h> #include <linux/usb/cdc.h> -#include <linux/wireless.h> #include <linux/ieee80211.h> #include <linux/if_arp.h> #include <linux/ctype.h> #include <linux/spinlock.h> #include <linux/slab.h> -#include <net/iw_handler.h> #include <net/cfg80211.h> #include <linux/usb/usbnet.h> #include <linux/usb/rndis_host.h> @@ -3392,7 +3390,7 @@ static const struct net_device_ops rndis_wlan_netdev_ops = { .ndo_tx_timeout = usbnet_tx_timeout, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, - .ndo_set_multicast_list = rndis_wlan_set_multicast_list, + .ndo_set_rx_mode = rndis_wlan_set_multicast_list, }; static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 76bcc3547976..3a6b40239bc1 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -645,11 +645,6 @@ static void rt2400pci_start_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - /* - * Allow the tbtt tasklet to be scheduled. - */ - tasklet_enable(&rt2x00dev->tbtt_tasklet); - rt2x00pci_register_read(rt2x00dev, CSR14, ®); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); @@ -715,7 +710,7 @@ static void rt2400pci_stop_queue(struct data_queue *queue) /* * Wait for possibly running tbtt tasklets. */ - tasklet_disable(&rt2x00dev->tbtt_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); break; default: break; @@ -982,12 +977,6 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, if (state == STATE_RADIO_IRQ_ON) { rt2x00pci_register_read(rt2x00dev, CSR7, ®); rt2x00pci_register_write(rt2x00dev, CSR7, reg); - - /* - * Enable tasklets. - */ - tasklet_enable(&rt2x00dev->txstatus_tasklet); - tasklet_enable(&rt2x00dev->rxdone_tasklet); } /* @@ -1011,8 +1000,9 @@ static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev, * Ensure that all tasklets are finished before * disabling the interrupts. */ - tasklet_disable(&rt2x00dev->txstatus_tasklet); - tasklet_disable(&rt2x00dev->rxdone_tasklet); + tasklet_kill(&rt2x00dev->txstatus_tasklet); + tasklet_kill(&rt2x00dev->rxdone_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); } } @@ -1249,7 +1239,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry, * call, we must decrease the higher 32bits with 1 to get * to correct value. */ - tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw); + tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw, NULL); rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME); rx_high = upper_32_bits(tsf); @@ -1347,22 +1337,25 @@ static void rt2400pci_txstatus_tasklet(unsigned long data) /* * Enable all TXDONE interrupts again. */ - spin_lock_irq(&rt2x00dev->irqmask_lock); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { + spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00pci_register_read(rt2x00dev, CSR8, ®); - rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); - rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); - rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); - rt2x00pci_register_write(rt2x00dev, CSR8, reg); + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); - spin_unlock_irq(&rt2x00dev->irqmask_lock); + spin_unlock_irq(&rt2x00dev->irqmask_lock); + } } static void rt2400pci_tbtt_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; rt2x00lib_beacondone(rt2x00dev); - rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2400pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); } static void rt2400pci_rxdone_tasklet(unsigned long data) @@ -1370,7 +1363,7 @@ static void rt2400pci_rxdone_tasklet(unsigned long data) struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; if (rt2x00pci_rxdone(rt2x00dev)) tasklet_schedule(&rt2x00dev->rxdone_tasklet); - else + else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } @@ -1655,7 +1648,8 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int rt2400pci_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1668,7 +1662,7 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, if (queue != 0) return -EINVAL; - if (rt2x00mac_conf_tx(hw, queue, params)) + if (rt2x00mac_conf_tx(hw, vif, queue, params)) return -EINVAL; /* @@ -1680,7 +1674,8 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } -static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index c288d951c034..dcc0e1fcca77 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -735,11 +735,6 @@ static void rt2500pci_start_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, RXCSR0, reg); break; case QID_BEACON: - /* - * Allow the tbtt tasklet to be scheduled. - */ - tasklet_enable(&rt2x00dev->tbtt_tasklet); - rt2x00pci_register_read(rt2x00dev, CSR14, ®); rt2x00_set_field32(®, CSR14_TSF_COUNT, 1); rt2x00_set_field32(®, CSR14_TBCN, 1); @@ -805,7 +800,7 @@ static void rt2500pci_stop_queue(struct data_queue *queue) /* * Wait for possibly running tbtt tasklets. */ - tasklet_disable(&rt2x00dev->tbtt_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); break; default: break; @@ -1137,12 +1132,6 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, if (state == STATE_RADIO_IRQ_ON) { rt2x00pci_register_read(rt2x00dev, CSR7, ®); rt2x00pci_register_write(rt2x00dev, CSR7, reg); - - /* - * Enable tasklets. - */ - tasklet_enable(&rt2x00dev->txstatus_tasklet); - tasklet_enable(&rt2x00dev->rxdone_tasklet); } /* @@ -1165,8 +1154,9 @@ static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev, /* * Ensure that all tasklets are finished. */ - tasklet_disable(&rt2x00dev->txstatus_tasklet); - tasklet_disable(&rt2x00dev->rxdone_tasklet); + tasklet_kill(&rt2x00dev->txstatus_tasklet); + tasklet_kill(&rt2x00dev->rxdone_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); } } @@ -1479,22 +1469,25 @@ static void rt2500pci_txstatus_tasklet(unsigned long data) /* * Enable all TXDONE interrupts again. */ - spin_lock_irq(&rt2x00dev->irqmask_lock); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) { + spin_lock_irq(&rt2x00dev->irqmask_lock); - rt2x00pci_register_read(rt2x00dev, CSR8, ®); - rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); - rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); - rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); - rt2x00pci_register_write(rt2x00dev, CSR8, reg); + rt2x00pci_register_read(rt2x00dev, CSR8, ®); + rt2x00_set_field32(®, CSR8_TXDONE_TXRING, 0); + rt2x00_set_field32(®, CSR8_TXDONE_ATIMRING, 0); + rt2x00_set_field32(®, CSR8_TXDONE_PRIORING, 0); + rt2x00pci_register_write(rt2x00dev, CSR8, reg); - spin_unlock_irq(&rt2x00dev->irqmask_lock); + spin_unlock_irq(&rt2x00dev->irqmask_lock); + } } static void rt2500pci_tbtt_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; rt2x00lib_beacondone(rt2x00dev); - rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2500pci_enable_interrupt(rt2x00dev, CSR8_TBCN_EXPIRE); } static void rt2500pci_rxdone_tasklet(unsigned long data) @@ -1502,7 +1495,7 @@ static void rt2500pci_rxdone_tasklet(unsigned long data) struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; if (rt2x00pci_rxdone(rt2x00dev)) tasklet_schedule(&rt2x00dev->rxdone_tasklet); - else + else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE); } @@ -1973,7 +1966,8 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index c69a7d71f4ca..4778620347c4 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -664,6 +664,9 @@ /* * LED_CFG: LED control + * ON_PERIOD: LED active time (ms) during TX (only used for LED mode 1) + * OFF_PERIOD: LED inactive time (ms) during TX (only used for LED mode 1) + * SLOW_BLINK_PERIOD: LED blink interval in seconds (only used for LED mode 2) * color LED's: * 0: off * 1: blinking upon TX2 diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 0019dfd8fb01..3f183a15186e 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -493,7 +493,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, rt2x00_set_field32(&word, TXWI_W1_BW_WIN_SIZE, txdesc->u.ht.ba_size); rt2x00_set_field32(&word, TXWI_W1_WIRELESS_CLI_ID, test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags) ? - txdesc->key_idx : 0xff); + txdesc->key_idx : txdesc->u.ht.wcid); rt2x00_set_field32(&word, TXWI_W1_MPDU_TOTAL_BYTE_COUNT, txdesc->length); rt2x00_set_field32(&word, TXWI_W1_PACKETID_QUEUE, entry->queue->qid); @@ -601,7 +601,7 @@ void rt2800_process_rxwi(struct queue_entry *entry, } EXPORT_SYMBOL_GPL(rt2800_process_rxwi); -void rt2800_txdone_entry(struct queue_entry *entry, u32 status) +void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); @@ -609,13 +609,11 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status) u32 word; u16 mcs, real_mcs; int aggr, ampdu; - __le32 *txwi; /* * Obtain the status about this packet. */ txdesc.flags = 0; - txwi = rt2800_drv_get_txwi(entry); rt2x00_desc_read(txwi, 0, &word); mcs = rt2x00_get_field32(word, TXWI_W0_MCS); @@ -899,28 +897,12 @@ static void rt2800_brightness_set(struct led_classdev *led_cdev, } } -static int rt2800_blink_set(struct led_classdev *led_cdev, - unsigned long *delay_on, unsigned long *delay_off) -{ - struct rt2x00_led *led = - container_of(led_cdev, struct rt2x00_led, led_dev); - u32 reg; - - rt2800_register_read(led->rt2x00dev, LED_CFG, ®); - rt2x00_set_field32(®, LED_CFG_ON_PERIOD, *delay_on); - rt2x00_set_field32(®, LED_CFG_OFF_PERIOD, *delay_off); - rt2800_register_write(led->rt2x00dev, LED_CFG, reg); - - return 0; -} - static void rt2800_init_led(struct rt2x00_dev *rt2x00dev, struct rt2x00_led *led, enum led_type type) { led->rt2x00dev = rt2x00dev; led->type = type; led->led_dev.brightness_set = rt2800_brightness_set; - led->led_dev.blink_set = rt2800_blink_set; led->flags = LED_INITIALIZED; } #endif /* CONFIG_RT2X00_LIB_LEDS */ @@ -928,11 +910,51 @@ static void rt2800_init_led(struct rt2x00_dev *rt2x00dev, /* * Configuration handlers. */ -static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_crypto *crypto, - struct ieee80211_key_conf *key) +static void rt2800_config_wcid(struct rt2x00_dev *rt2x00dev, + const u8 *address, + int wcid) { struct mac_wcid_entry wcid_entry; + u32 offset; + + offset = MAC_WCID_ENTRY(wcid); + + memset(&wcid_entry, 0xff, sizeof(wcid_entry)); + if (address) + memcpy(wcid_entry.mac, address, ETH_ALEN); + + rt2800_register_multiwrite(rt2x00dev, offset, + &wcid_entry, sizeof(wcid_entry)); +} + +static void rt2800_delete_wcid_attr(struct rt2x00_dev *rt2x00dev, int wcid) +{ + u32 offset; + offset = MAC_WCID_ATTR_ENTRY(wcid); + rt2800_register_write(rt2x00dev, offset, 0); +} + +static void rt2800_config_wcid_attr_bssidx(struct rt2x00_dev *rt2x00dev, + int wcid, u32 bssidx) +{ + u32 offset = MAC_WCID_ATTR_ENTRY(wcid); + u32 reg; + + /* + * The BSS Idx numbers is split in a main value of 3 bits, + * and a extended field for adding one additional bit to the value. + */ + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, (bssidx & 0x7)); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT, + (bssidx & 0x8) >> 3); + rt2800_register_write(rt2x00dev, offset, reg); +} + +static void rt2800_config_wcid_attr_cipher(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ struct mac_iveiv_entry iveiv_entry; u32 offset; u32 reg; @@ -952,14 +974,16 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev, (crypto->cipher & 0x7)); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER_EXT, (crypto->cipher & 0x8) >> 3); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX, - (crypto->bssidx & 0x7)); - rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_BSS_IDX_EXT, - (crypto->bssidx & 0x8) >> 3); rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, crypto->cipher); rt2800_register_write(rt2x00dev, offset, reg); } else { - rt2800_register_write(rt2x00dev, offset, 0); + /* Delete the cipher without touching the bssidx */ + rt2800_register_read(rt2x00dev, offset, ®); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_KEYTAB, 0); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER, 0); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_CIPHER_EXT, 0); + rt2x00_set_field32(®, MAC_WCID_ATTRIBUTE_RX_WIUDF, 0); + rt2800_register_write(rt2x00dev, offset, reg); } offset = MAC_IVEIV_ENTRY(key->hw_key_idx); @@ -972,14 +996,6 @@ static void rt2800_config_wcid_attr(struct rt2x00_dev *rt2x00dev, iveiv_entry.iv[3] |= key->keyidx << 6; rt2800_register_multiwrite(rt2x00dev, offset, &iveiv_entry, sizeof(iveiv_entry)); - - offset = MAC_WCID_ENTRY(key->hw_key_idx); - - memset(&wcid_entry, 0, sizeof(wcid_entry)); - if (crypto->cmd == SET_KEY) - memcpy(wcid_entry.mac, crypto->address, ETH_ALEN); - rt2800_register_multiwrite(rt2x00dev, offset, - &wcid_entry, sizeof(wcid_entry)); } int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, @@ -1026,20 +1042,24 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, /* * Update WCID information */ - rt2800_config_wcid_attr(rt2x00dev, crypto, key); + rt2800_config_wcid(rt2x00dev, crypto->address, key->hw_key_idx); + rt2800_config_wcid_attr_bssidx(rt2x00dev, key->hw_key_idx, + crypto->bssidx); + rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key); return 0; } EXPORT_SYMBOL_GPL(rt2800_config_shared_key); -static inline int rt2800_find_pairwise_keyslot(struct rt2x00_dev *rt2x00dev) +static inline int rt2800_find_wcid(struct rt2x00_dev *rt2x00dev) { + struct mac_wcid_entry wcid_entry; int idx; - u32 offset, reg; + u32 offset; /* - * Search for the first free pairwise key entry and return the - * corresponding index. + * Search for the first free WCID entry and return the corresponding + * index. * * Make sure the WCID starts _after_ the last possible shared key * entry (>32). @@ -1049,11 +1069,17 @@ static inline int rt2800_find_pairwise_keyslot(struct rt2x00_dev *rt2x00dev) * first 222 entries. */ for (idx = 33; idx <= 222; idx++) { - offset = MAC_WCID_ATTR_ENTRY(idx); - rt2800_register_read(rt2x00dev, offset, ®); - if (!reg) + offset = MAC_WCID_ENTRY(idx); + rt2800_register_multiread(rt2x00dev, offset, &wcid_entry, + sizeof(wcid_entry)); + if (is_broadcast_ether_addr(wcid_entry.mac)) return idx; } + + /* + * Use -1 to indicate that we don't have any more space in the WCID + * table. + */ return -1; } @@ -1063,13 +1089,15 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, { struct hw_key_entry key_entry; u32 offset; - int idx; if (crypto->cmd == SET_KEY) { - idx = rt2800_find_pairwise_keyslot(rt2x00dev); - if (idx < 0) + /* + * Allow key configuration only for STAs that are + * known by the hw. + */ + if (crypto->wcid < 0) return -ENOSPC; - key->hw_key_idx = idx; + key->hw_key_idx = crypto->wcid; memcpy(key_entry.key, crypto->key, sizeof(key_entry.key)); @@ -1086,12 +1114,59 @@ int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, /* * Update WCID information */ - rt2800_config_wcid_attr(rt2x00dev, crypto, key); + rt2800_config_wcid_attr_cipher(rt2x00dev, crypto, key); return 0; } EXPORT_SYMBOL_GPL(rt2800_config_pairwise_key); +int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + int wcid; + struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); + + /* + * Find next free WCID. + */ + wcid = rt2800_find_wcid(rt2x00dev); + + /* + * Store selected wcid even if it is invalid so that we can + * later decide if the STA is uploaded into the hw. + */ + sta_priv->wcid = wcid; + + /* + * No space left in the device, however, we can still communicate + * with the STA -> No error. + */ + if (wcid < 0) + return 0; + + /* + * Clean up WCID attributes and write STA address to the device. + */ + rt2800_delete_wcid_attr(rt2x00dev, wcid); + rt2800_config_wcid(rt2x00dev, sta->addr, wcid); + rt2800_config_wcid_attr_bssidx(rt2x00dev, wcid, + rt2x00lib_get_bssidx(rt2x00dev, vif)); + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_sta_add); + +int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid) +{ + /* + * Remove WCID entry, no need to clean the attributes as they will + * get renewed when the WCID is reused. + */ + rt2800_config_wcid(rt2x00dev, NULL, wcid); + + return 0; +} +EXPORT_SYMBOL_GPL(rt2800_sta_remove); + void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -2771,11 +2846,8 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) SHARED_KEY_MODE_ENTRY(i), 0); for (i = 0; i < 256; i++) { - static const u32 wcid[2] = { 0xffffffff, 0x00ffffff }; - rt2800_register_multiwrite(rt2x00dev, MAC_WCID_ENTRY(i), - wcid, sizeof(wcid)); - - rt2800_register_write(rt2x00dev, MAC_WCID_ATTR_ENTRY(i), 0); + rt2800_config_wcid(rt2x00dev, NULL, i); + rt2800_delete_wcid_attr(rt2x00dev, i); rt2800_register_write(rt2x00dev, MAC_IVEIV_ENTRY(i), 0); } @@ -4326,7 +4398,8 @@ int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) } EXPORT_SYMBOL_GPL(rt2800_set_rts_threshold); -int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2800_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -4342,7 +4415,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; @@ -4394,7 +4467,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, } EXPORT_SYMBOL_GPL(rt2800_conf_tx); -u64 rt2800_get_tsf(struct ieee80211_hw *hw) +u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; @@ -4414,8 +4487,19 @@ int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size) { + struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv; int ret = 0; + /* + * Don't allow aggregation for stations the hardware isn't aware + * of because tx status reports for frames to an unknown station + * always contain wcid=255 and thus we can't distinguish between + * multiple stations which leads to unwanted situations when the + * hw reorders frames due to aggregation. + */ + if (sta_priv->wcid < 0) + return 1; + switch (action) { case IEEE80211_AMPDU_RX_START: case IEEE80211_AMPDU_RX_STOP: diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h index 69deb3148ae7..8c3c281904fe 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/rt2x00/rt2800lib.h @@ -152,7 +152,7 @@ void rt2800_write_tx_data(struct queue_entry *entry, struct txentry_desc *txdesc); void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc); -void rt2800_txdone_entry(struct queue_entry *entry, u32 status); +void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32* txwi); void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); void rt2800_clear_beacon(struct queue_entry *entry); @@ -166,6 +166,9 @@ int rt2800_config_shared_key(struct rt2x00_dev *rt2x00dev, int rt2800_config_pairwise_key(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key); +int rt2800_sta_add(struct rt2x00_dev *rt2x00dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int rt2800_sta_remove(struct rt2x00_dev *rt2x00dev, int wcid); void rt2800_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags); void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf, @@ -194,9 +197,10 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev); void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, u16 *iv16); int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); -int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2800_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params); -u64 rt2800_get_tsf(struct ieee80211_hw *hw); +u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn, diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index ebc17ad61dec..da48c8ac27bd 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -200,13 +200,6 @@ static void rt2800pci_start_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg); break; case QID_BEACON: - /* - * Allow beacon tasklets to be scheduled for periodic - * beacon updates. - */ - tasklet_enable(&rt2x00dev->tbtt_tasklet); - tasklet_enable(&rt2x00dev->pretbtt_tasklet); - rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, ®); rt2x00_set_field32(®, BCN_TIME_CFG_TSF_TICKING, 1); rt2x00_set_field32(®, BCN_TIME_CFG_TBTT_ENABLE, 1); @@ -269,10 +262,13 @@ static void rt2800pci_stop_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg); /* - * Wait for tbtt tasklets to finish. + * Wait for current invocation to finish. The tasklet + * won't be scheduled anymore afterwards since we disabled + * the TBTT and PRE TBTT timer. */ - tasklet_disable(&rt2x00dev->tbtt_tasklet); - tasklet_disable(&rt2x00dev->pretbtt_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); + tasklet_kill(&rt2x00dev->pretbtt_tasklet); + break; default: break; @@ -437,14 +433,6 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, if (state == STATE_RADIO_IRQ_ON) { rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, ®); rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg); - - /* - * Enable tasklets. The beacon related tasklets are - * enabled when the beacon queue is started. - */ - tasklet_enable(&rt2x00dev->txstatus_tasklet); - tasklet_enable(&rt2x00dev->rxdone_tasklet); - tasklet_enable(&rt2x00dev->autowake_tasklet); } spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); @@ -472,12 +460,13 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, if (state == STATE_RADIO_IRQ_OFF) { /* - * Ensure that all tasklets are finished before - * disabling the interrupts. + * Wait for possibly running tasklets to finish. */ - tasklet_disable(&rt2x00dev->txstatus_tasklet); - tasklet_disable(&rt2x00dev->rxdone_tasklet); - tasklet_disable(&rt2x00dev->autowake_tasklet); + tasklet_kill(&rt2x00dev->txstatus_tasklet); + tasklet_kill(&rt2x00dev->rxdone_tasklet); + tasklet_kill(&rt2x00dev->autowake_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); + tasklet_kill(&rt2x00dev->pretbtt_tasklet); } } @@ -630,11 +619,11 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry, /* * Initialize TX descriptor */ - rt2x00_desc_read(txd, 0, &word); + word = 0; rt2x00_set_field32(&word, TXD_W0_SD_PTR0, skbdesc->skb_dma); rt2x00_desc_write(txd, 0, word); - rt2x00_desc_read(txd, 1, &word); + word = 0; rt2x00_set_field32(&word, TXD_W1_SD_LEN1, entry->skb->len); rt2x00_set_field32(&word, TXD_W1_LAST_SEC1, !test_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags)); @@ -645,12 +634,12 @@ static void rt2800pci_write_tx_desc(struct queue_entry *entry, rt2x00_set_field32(&word, TXD_W1_DMA_DONE, 0); rt2x00_desc_write(txd, 1, word); - rt2x00_desc_read(txd, 2, &word); + word = 0; rt2x00_set_field32(&word, TXD_W2_SD_PTR1, skbdesc->skb_dma + TXWI_DESC_SIZE); rt2x00_desc_write(txd, 2, word); - rt2x00_desc_read(txd, 3, &word); + word = 0; rt2x00_set_field32(&word, TXD_W3_WIV, !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W3_QSEL, 2); @@ -771,7 +760,7 @@ static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev) } entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE); - rt2800_txdone_entry(entry, status); + rt2800_txdone_entry(entry, status, rt2800pci_get_txwi(entry)); if (--max_tx_done == 0) break; @@ -813,14 +802,16 @@ static void rt2800pci_pretbtt_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; rt2x00lib_pretbtt(rt2x00dev); - rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_PRE_TBTT); } static void rt2800pci_tbtt_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; rt2x00lib_beacondone(rt2x00dev); - rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TBTT); } static void rt2800pci_rxdone_tasklet(unsigned long data) @@ -828,7 +819,7 @@ static void rt2800pci_rxdone_tasklet(unsigned long data) struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; if (rt2x00pci_rxdone(rt2x00dev)) tasklet_schedule(&rt2x00dev->rxdone_tasklet); - else + else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE); } @@ -836,7 +827,8 @@ static void rt2800pci_autowake_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; rt2800pci_wakeup(rt2x00dev); - rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_AUTO_WAKEUP); } static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev) @@ -1023,6 +1015,8 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .get_tkip_seq = rt2800_get_tkip_seq, .set_rts_threshold = rt2800_set_rts_threshold, + .sta_add = rt2x00mac_sta_add, + .sta_remove = rt2x00mac_sta_remove, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2800_conf_tx, .get_tsf = rt2800_get_tsf, @@ -1084,6 +1078,8 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { .config_erp = rt2800_config_erp, .config_ant = rt2800_config_ant, .config = rt2800_config, + .sta_add = rt2800_sta_add, + .sta_remove = rt2800_sta_remove, }; static const struct data_queue_desc rt2800pci_queue_rx = { @@ -1161,6 +1157,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { #endif #ifdef CONFIG_RT2800PCI_RT53XX { PCI_DEVICE(0x1814, 0x5390) }, + { PCI_DEVICE(0x1814, 0x539a) }, { PCI_DEVICE(0x1814, 0x539f) }, #endif { 0, } diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index dbf501ca317f..f1565792f270 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -542,7 +542,8 @@ static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev) } if (entry) - rt2800_txdone_entry(entry, reg); + rt2800_txdone_entry(entry, reg, + rt2800usb_get_txwi(entry)); } } @@ -759,6 +760,8 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = { .get_stats = rt2x00mac_get_stats, .get_tkip_seq = rt2800_get_tkip_seq, .set_rts_threshold = rt2800_set_rts_threshold, + .sta_add = rt2x00mac_sta_add, + .sta_remove = rt2x00mac_sta_remove, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2800_conf_tx, .get_tsf = rt2800_get_tsf, @@ -816,6 +819,8 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { .config_erp = rt2800_config_erp, .config_ant = rt2800_config_ant, .config = rt2800_config, + .sta_add = rt2800_sta_add, + .sta_remove = rt2800_sta_remove, }; static const struct data_queue_desc rt2800usb_queue_rx = { diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index f82bfeb79ebb..2ec5c00235e6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -478,6 +478,8 @@ struct rt2x00lib_crypto { u8 key[16]; u8 tx_mic[8]; u8 rx_mic[8]; + + int wcid; }; /* @@ -512,6 +514,19 @@ struct rt2x00intf_conf { }; /* + * Private structure for storing STA details + * wcid: Wireless Client ID + */ +struct rt2x00_sta { + int wcid; +}; + +static inline struct rt2x00_sta* sta_to_rt2x00_sta(struct ieee80211_sta *sta) +{ + return (struct rt2x00_sta *)sta->drv_priv; +} + +/* * rt2x00lib callback functions. */ struct rt2x00lib_ops { @@ -620,6 +635,11 @@ struct rt2x00lib_ops { void (*config) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int changed_flags); + int (*sta_add) (struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + int (*sta_remove) (struct rt2x00_dev *rt2x00dev, + int wcid); }; /* @@ -1226,6 +1246,12 @@ static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev, #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ /* + * Utility functions. + */ +u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif); + +/* * Interrupt context handlers. */ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev); @@ -1261,6 +1287,10 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, #else #define rt2x00mac_set_key NULL #endif /* CONFIG_RT2X00_LIB_CRYPTO */ +int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw); void rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw); int rt2x00mac_get_stats(struct ieee80211_hw *hw, @@ -1269,7 +1299,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params); void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop); diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0955c941317f..e1fb2a8569be 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -33,6 +33,22 @@ #include "rt2x00lib.h" /* + * Utility functions. + */ +u32 rt2x00lib_get_bssidx(struct rt2x00_dev *rt2x00dev, + struct ieee80211_vif *vif) +{ + /* + * When in STA mode, bssidx is always 0 otherwise local_address[5] + * contains the bss number, see BSS_ID_MASK comments for details. + */ + if (rt2x00dev->intf_sta_count) + return 0; + return vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1); +} +EXPORT_SYMBOL_GPL(rt2x00lib_get_bssidx); + +/* * Radio control handlers. */ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -915,6 +931,11 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE; /* + * Tell mac80211 about the size of our private STA structure. + */ + rt2x00dev->hw->sta_data_size = sizeof(struct rt2x00_sta); + + /* * Allocate tx status FIFO for driver use. */ if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) { @@ -946,7 +967,6 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) tasklet_init(&rt2x00dev->taskletname, \ rt2x00dev->ops->lib->taskletname, \ (unsigned long)rt2x00dev); \ - tasklet_disable(&rt2x00dev->taskletname); \ } RT2X00_TASKLET_INIT(txstatus_tasklet); diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 4ccf23805973..bf0acff07807 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -494,6 +494,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct rt2x00lib_crypto crypto; static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; + struct rt2x00_sta *sta_priv = NULL; if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) return 0; @@ -504,24 +505,18 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, memset(&crypto, 0, sizeof(crypto)); - /* - * When in STA mode, bssidx is always 0 otherwise local_address[5] - * contains the bss number, see BSS_ID_MASK comments for details. - */ - if (rt2x00dev->intf_sta_count) - crypto.bssidx = 0; - else - crypto.bssidx = vif->addr[5] & (rt2x00dev->ops->max_ap_intf - 1); - + crypto.bssidx = rt2x00lib_get_bssidx(rt2x00dev, vif); crypto.cipher = rt2x00crypto_key_to_cipher(key); if (crypto.cipher == CIPHER_NONE) return -EOPNOTSUPP; crypto.cmd = cmd; - if (sta) + if (sta) { crypto.address = sta->addr; - else + sta_priv = sta_to_rt2x00_sta(sta); + crypto.wcid = sta_priv->wcid; + } else crypto.address = bcast_addr; if (crypto.cipher == CIPHER_TKIP) @@ -560,6 +555,39 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, EXPORT_SYMBOL_GPL(rt2x00mac_set_key); #endif /* CONFIG_RT2X00_LIB_CRYPTO */ +int rt2x00mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); + + /* + * If there's no space left in the device table store + * -1 as wcid but tell mac80211 everything went ok. + */ + if (rt2x00dev->ops->lib->sta_add(rt2x00dev, vif, sta)) + sta_priv->wcid = -1; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00mac_sta_add); + +int rt2x00mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct rt2x00_dev *rt2x00dev = hw->priv; + struct rt2x00_sta *sta_priv = sta_to_rt2x00_sta(sta); + + /* + * If we never sent the STA to the device no need to clean it up. + */ + if (sta_priv->wcid < 0) + return 0; + + return rt2x00dev->ops->lib->sta_remove(rt2x00dev, sta_priv->wcid); +} +EXPORT_SYMBOL_GPL(rt2x00mac_sta_remove); + void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -685,7 +713,8 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); -int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +int rt2x00mac_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 29edb9fbe6f1..5adfb3eab9cd 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -310,11 +310,16 @@ static void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev, struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0]; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct rt2x00_sta *sta_priv = NULL; - if (tx_info->control.sta) + if (tx_info->control.sta) { txdesc->u.ht.mpdu_density = tx_info->control.sta->ht_cap.ampdu_density; + sta_priv = sta_to_rt2x00_sta(tx_info->control.sta); + txdesc->u.ht.wcid = sta_priv->wcid; + } + txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */ /* diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index f2100f4ddcff..349008d1fb28 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -288,8 +288,8 @@ enum txentry_desc_flags { * @signal: PLCP signal. * @service: PLCP service. * @msc: MCS. - * @stbc: STBC. - * @ba_size: BA size. + * @stbc: Use Space Time Block Coding (only available for MCS rates < 8). + * @ba_size: Size of the recepients RX reorder buffer - 1. * @rate_mode: Rate mode (See @enum rate_modulation). * @mpdu_density: MDPU density. * @retry_limit: Max number of retries. @@ -321,6 +321,7 @@ struct txentry_desc { u8 ba_size; u8 mpdu_density; enum txop txop; + int wcid; } ht; } u; diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 53110b83bf6e..bf55b4a311e3 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -1142,11 +1142,6 @@ static void rt61pci_start_queue(struct data_queue *queue) rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg); break; case QID_BEACON: - /* - * Allow the tbtt tasklet to be scheduled. - */ - tasklet_enable(&rt2x00dev->tbtt_tasklet); - rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 1); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 1); @@ -1230,7 +1225,7 @@ static void rt61pci_stop_queue(struct data_queue *queue) /* * Wait for possibly running tbtt tasklets. */ - tasklet_disable(&rt2x00dev->tbtt_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); break; default: break; @@ -1731,13 +1726,6 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, ®); rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg); - - /* - * Enable tasklets. - */ - tasklet_enable(&rt2x00dev->txstatus_tasklet); - tasklet_enable(&rt2x00dev->rxdone_tasklet); - tasklet_enable(&rt2x00dev->autowake_tasklet); } /* @@ -1772,9 +1760,10 @@ static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev, /* * Ensure that all tasklets are finished. */ - tasklet_disable(&rt2x00dev->txstatus_tasklet); - tasklet_disable(&rt2x00dev->rxdone_tasklet); - tasklet_disable(&rt2x00dev->autowake_tasklet); + tasklet_kill(&rt2x00dev->txstatus_tasklet); + tasklet_kill(&rt2x00dev->rxdone_tasklet); + tasklet_kill(&rt2x00dev->autowake_tasklet); + tasklet_kill(&rt2x00dev->tbtt_tasklet); } } @@ -2300,22 +2289,24 @@ static void rt61pci_txstatus_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; rt61pci_txdone(rt2x00dev); - rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_TXDONE); } static void rt61pci_tbtt_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; rt2x00lib_beacondone(rt2x00dev); - rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_BEACON_DONE); } static void rt61pci_rxdone_tasklet(unsigned long data) { struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data; if (rt2x00pci_rxdone(rt2x00dev)) - rt2x00pci_rxdone(rt2x00dev); - else + tasklet_schedule(&rt2x00dev->rxdone_tasklet); + else if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE); } @@ -2325,7 +2316,8 @@ static void rt61pci_autowake_tasklet(unsigned long data) rt61pci_wakeup(rt2x00dev); rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff); - rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP); + if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) + rt61pci_enable_mcu_interrupt(rt2x00dev, MCU_INT_MASK_CSR_TWAKEUP); } static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance) @@ -2891,7 +2883,8 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +static int rt61pci_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2907,7 +2900,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; @@ -2948,7 +2941,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, return 0; } -static u64 rt61pci_get_tsf(struct ieee80211_hw *hw) +static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 0baeb894f093..cfb19dbb0a67 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -2222,7 +2222,8 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, +static int rt73usb_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -2238,7 +2239,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, * we are free to update the registers based on the value * in the queue parameter. */ - retval = rt2x00mac_conf_tx(hw, queue_idx, params); + retval = rt2x00mac_conf_tx(hw, vif, queue_idx, params); if (retval) return retval; @@ -2279,7 +2280,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, return 0; } -static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) +static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rt2x00_dev *rt2x00dev = hw->priv; u64 tsf; diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 66b29dc07cc3..0082015ff664 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -669,7 +669,8 @@ static void rtl8180_stop(struct ieee80211_hw *dev) rtl8180_free_tx_ring(dev, i); } -static u64 rtl8180_get_tsf(struct ieee80211_hw *dev) +static u64 rtl8180_get_tsf(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { struct rtl8180_priv *priv = dev->priv; @@ -701,7 +702,7 @@ static void rtl8180_beacon_work(struct work_struct *work) * TODO: make hardware update beacon timestamp */ mgmt = (struct ieee80211_mgmt *)skb->data; - mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev)); + mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev, vif)); /* TODO: use actual beacon queue */ skb_set_queue_mapping(skb, 0); diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index 1e0be14d10d4..24873b55b55c 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -1241,7 +1241,8 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); } -static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, +static int rtl8187_conf_tx(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct rtl8187_priv *priv = dev->priv; @@ -1277,7 +1278,7 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, return 0; } -static u64 rtl8187_get_tsf(struct ieee80211_hw *dev) +static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif) { struct rtl8187_priv *priv = dev->priv; diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 0b598db38da9..d4fdd2a5a739 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -311,6 +311,8 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_CONNECTION_MONITOR | + /* IEEE80211_HW_SUPPORTS_CQM_RSSI | */ IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0; /* swlps or hwlps has been set in diff chip in init_sw_vars */ @@ -664,6 +666,167 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw) return hw_rate; } +/* mac80211's rate_idx is like this: + * + * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ + * + * B/G rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC92_RATE1M-->DESC92_RATE54M ==> idx is 0-->11, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 + * + * 5G band:rx_status->band == IEEE80211_BAND_5GHZ + * A rate: + * (rx_status->flag & RX_FLAG_HT) = 0, + * DESC92_RATE6M-->DESC92_RATE54M ==> idx is 0-->7, + * + * N rate: + * (rx_status->flag & RX_FLAG_HT) = 1, + * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15 + */ +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, + bool isht, u8 desc_rate, bool first_ampdu) +{ + int rate_idx; + + if (false == isht) { + if (IEEE80211_BAND_2GHZ == hw->conf.channel->band) { + switch (desc_rate) { + case DESC92_RATE1M: + rate_idx = 0; + break; + case DESC92_RATE2M: + rate_idx = 1; + break; + case DESC92_RATE5_5M: + rate_idx = 2; + break; + case DESC92_RATE11M: + rate_idx = 3; + break; + case DESC92_RATE6M: + rate_idx = 4; + break; + case DESC92_RATE9M: + rate_idx = 5; + break; + case DESC92_RATE12M: + rate_idx = 6; + break; + case DESC92_RATE18M: + rate_idx = 7; + break; + case DESC92_RATE24M: + rate_idx = 8; + break; + case DESC92_RATE36M: + rate_idx = 9; + break; + case DESC92_RATE48M: + rate_idx = 10; + break; + case DESC92_RATE54M: + rate_idx = 11; + break; + default: + rate_idx = 0; + break; + } + } else { + switch (desc_rate) { + case DESC92_RATE6M: + rate_idx = 0; + break; + case DESC92_RATE9M: + rate_idx = 1; + break; + case DESC92_RATE12M: + rate_idx = 2; + break; + case DESC92_RATE18M: + rate_idx = 3; + break; + case DESC92_RATE24M: + rate_idx = 4; + break; + case DESC92_RATE36M: + rate_idx = 5; + break; + case DESC92_RATE48M: + rate_idx = 6; + break; + case DESC92_RATE54M: + rate_idx = 7; + break; + default: + rate_idx = 0; + break; + } + } + + } else { + + switch (desc_rate) { + case DESC92_RATEMCS0: + rate_idx = 0; + break; + case DESC92_RATEMCS1: + rate_idx = 1; + break; + case DESC92_RATEMCS2: + rate_idx = 2; + break; + case DESC92_RATEMCS3: + rate_idx = 3; + break; + case DESC92_RATEMCS4: + rate_idx = 4; + break; + case DESC92_RATEMCS5: + rate_idx = 5; + break; + case DESC92_RATEMCS6: + rate_idx = 6; + break; + case DESC92_RATEMCS7: + rate_idx = 7; + break; + case DESC92_RATEMCS8: + rate_idx = 8; + break; + case DESC92_RATEMCS9: + rate_idx = 9; + break; + case DESC92_RATEMCS10: + rate_idx = 10; + break; + case DESC92_RATEMCS11: + rate_idx = 11; + break; + case DESC92_RATEMCS12: + rate_idx = 12; + break; + case DESC92_RATEMCS13: + rate_idx = 13; + break; + case DESC92_RATEMCS14: + rate_idx = 14; + break; + case DESC92_RATEMCS15: + rate_idx = 15; + break; + default: + rate_idx = 0; + break; + } + } + return rate_idx; +} +EXPORT_SYMBOL(rtlwifi_rate_mapping); + void rtl_get_tcb_desc(struct ieee80211_hw *hw, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, @@ -689,7 +852,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, *So tcb_desc->hw_rate is just used for *special data and mgt frames */ - if (info->control.rates[0].idx == 0 && + if (info->control.rates[0].idx == 0 || ieee80211_is_nullfunc(fc)) { tcb_desc->use_driver_rate = true; tcb_desc->ratr_index = RATR_INX_WIRELESS_MC; @@ -977,7 +1140,7 @@ void rtl_watchdog_wq_callback(void *data) } /* - *<3> to check if traffic busy, if + *<2> to check if traffic busy, if * busytraffic we don't change channel */ if (mac->link_state >= MAC80211_LINKED) { diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index a91f3eee59c8..4ae905983d0d 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -140,4 +140,6 @@ u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid); extern struct attribute_group rtl_attribute_group; +int rtlwifi_rate_mapping(struct ieee80211_hw *hw, + bool isht, u8 desc_rate, bool first_ampdu); #endif diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c index 04c4e9eb6ee6..3f0f056fae9c 100644 --- a/drivers/net/wireless/rtlwifi/core.c +++ b/drivers/net/wireless/rtlwifi/core.c @@ -504,7 +504,8 @@ static int _rtl_get_hal_qnum(u16 queue) *for mac80211 VO=0, VI=1, BE=2, BK=3 *for rtl819x BE=0, BK=1, VI=2, VO=3 */ -static int rtl_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int rtl_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *param) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -775,7 +776,7 @@ out: mutex_unlock(&rtlpriv->locks.conf_mutex); } -static u64 rtl_op_get_tsf(struct ieee80211_hw *hw) +static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); u64 tsf; @@ -784,7 +785,8 @@ static u64 rtl_op_get_tsf(struct ieee80211_hw *hw) return tsf; } -static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) +static void rtl_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u64 tsf) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_mac *mac = rtl_mac(rtl_priv(hw)); @@ -794,7 +796,8 @@ static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf) rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss)); } -static void rtl_op_reset_tsf(struct ieee80211_hw *hw) +static void rtl_op_reset_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct rtl_priv *rtlpriv = rtl_priv(hw); u8 tmp = 0; diff --git a/drivers/net/wireless/rtlwifi/debug.c b/drivers/net/wireless/rtlwifi/debug.c index 5fa73852cb66..1b5cb7153a52 100644 --- a/drivers/net/wireless/rtlwifi/debug.c +++ b/drivers/net/wireless/rtlwifi/debug.c @@ -33,8 +33,6 @@ void rtl_dbgp_flag_init(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); u8 i; - rtlpriv->dbg.global_debuglevel = DBG_EMERG; - rtlpriv->dbg.global_debugcomponents = COMP_ERR | COMP_FW | COMP_INIT | COMP_RECV | COMP_SEND | COMP_MLME | COMP_SCAN | COMP_INTR | COMP_LED | COMP_SEC | diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index f8648b7288d5..177a8e669241 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -218,7 +218,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; - u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; u8 num4bytes = pcipriv->ndis_adapter.num4bytes; /*Retrieve original configuration settings. */ u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg; @@ -254,9 +253,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw) udelay(50); /*4 Disable Pci Bridge ASPM */ - rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + (num4bytes << 2)); - rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg); + pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), + pcibridge_linkctrlreg); udelay(50); } @@ -277,7 +275,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum; u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum; u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor; - u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; u8 num4bytes = pcipriv->ndis_adapter.num4bytes; u16 aspmlevel; u8 u_pcibridge_aspmsetting; @@ -293,8 +290,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) } /*4 Enable Pci Bridge ASPM */ - rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + (num4bytes << 2)); u_pcibridge_aspmsetting = pcipriv->ndis_adapter.pcibridge_linkctrlreg | @@ -303,7 +298,8 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) u_pcibridge_aspmsetting &= ~BIT(0); - rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting); + pci_write_config_byte(rtlpci->pdev, (num4bytes << 2), + u_pcibridge_aspmsetting); RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("PlatformEnableASPM():PciBridge busnumber[%x], " @@ -335,25 +331,18 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw) static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) { - struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); - u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; + struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); bool status = false; u8 offset_e0; unsigned offset_e4; - rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + 0xE0); - rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0); + pci_write_config_byte(rtlpci->pdev, 0xe0, 0xa0); - rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + 0xE0); - rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0); + pci_read_config_byte(rtlpci->pdev, 0xe0, &offset_e0); if (offset_e0 == 0xA0) { - rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + 0xE4); - rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4); + pci_read_config_dword(rtlpci->pdev, 0xe4, &offset_e4); if (offset_e4 & BIT(23)) status = true; } @@ -364,17 +353,15 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw) static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw) { struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); + struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset; - u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport; u8 linkctrl_reg; u8 num4bbytes; num4bbytes = (capabilityoffset + 0x10) / 4; /*Read Link Control Register */ - rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS, - pcicfg_addrport + (num4bbytes << 2)); - rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg); + pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg); pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg; } @@ -1718,10 +1705,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, PCI_SLOT(bridge_pdev->devfn); pcipriv->ndis_adapter.pcibridge_funcnum = PCI_FUNC(bridge_pdev->devfn); - pcipriv->ndis_adapter.pcicfg_addrport = - (pcipriv->ndis_adapter.pcibridge_busnum << 16) | - (pcipriv->ndis_adapter.pcibridge_devnum << 11) | - (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31); pcipriv->ndis_adapter.pcibridge_pciehdr_offset = pci_pcie_cap(bridge_pdev); pcipriv->ndis_adapter.num4bytes = @@ -2010,36 +1993,25 @@ call rtl_mac_stop() from the mac80211 suspend function first, So there is no need to call hw_disable here. ****************************************/ -int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state) +int rtl_pci_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct rtl_priv *rtlpriv = rtl_priv(hw); rtlpriv->cfg->ops->hw_suspend(hw); rtl_deinit_rfkill(hw); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, PCI_D3hot); return 0; } EXPORT_SYMBOL(rtl_pci_suspend); -int rtl_pci_resume(struct pci_dev *pdev) +int rtl_pci_resume(struct device *dev) { - int ret; + struct pci_dev *pdev = to_pci_dev(dev); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct rtl_priv *rtlpriv = rtl_priv(hw); - pci_set_power_state(pdev, PCI_D0); - ret = pci_enable_device(pdev); - if (ret) { - RT_ASSERT(false, ("ERR: <======\n")); - return ret; - } - - pci_restore_state(pdev); - rtlpriv->cfg->ops->hw_resume(hw); rtl_init_rfkill(hw); return 0; diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h index c53c62046747..ebe0b42c0518 100644 --- a/drivers/net/wireless/rtlwifi/pci.h +++ b/drivers/net/wireless/rtlwifi/pci.h @@ -212,7 +212,6 @@ struct mp_adapter { u16 pcibridge_vendorid; u16 pcibridge_deviceid; - u32 pcicfg_addrport; u8 num4bytes; u8 pcibridge_pciehdr_offset; @@ -238,8 +237,8 @@ extern struct rtl_intf_ops rtl_pci_ops; int __devinit rtl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtl_pci_disconnect(struct pci_dev *pdev); -int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state); -int rtl_pci_resume(struct pci_dev *pdev); +int rtl_pci_suspend(struct device *dev); +int rtl_pci_resume(struct device *dev); static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr) { @@ -273,29 +272,4 @@ static inline void pci_write32_async(struct rtl_priv *rtlpriv, writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr); } -static inline void rtl_pci_raw_write_port_ulong(u32 port, u32 val) -{ - outl(val, port); -} - -static inline void rtl_pci_raw_write_port_uchar(u32 port, u8 val) -{ - outb(val, port); -} - -static inline void rtl_pci_raw_read_port_uchar(u32 port, u8 *pval) -{ - *pval = inb(port); -} - -static inline void rtl_pci_raw_read_port_ushort(u32 port, u16 *pval) -{ - *pval = inw(port); -} - -static inline void rtl_pci_raw_read_port_ulong(u32 port, u32 *pval) -{ - *pval = inl(port); -} - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h index 35ff7df41a1d..9fc804d89d65 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h @@ -142,8 +142,22 @@ enum version_8192c { VERSION_UNKNOWN = 0x88, }; +#define CUT_VERSION_MASK (BIT(6)|BIT(7)) +#define CHIP_VENDOR_UMC BIT(5) +#define CHIP_VENDOR_UMC_B_CUT BIT(6) /* Chip version for ECO */ +#define IS_VENDOR_UMC_A_CUT(version) ((IS_CHIP_VENDOR_UMC(version)) ? \ + ((GET_CVID_CUT_VERSION(version)) ? false : true) : false) #define IS_CHIP_VER_B(version) ((version & CHIP_VER_B) ? true : false) +#define IS_VENDOR_UMC_A_CUT(version) ((IS_CHIP_VENDOR_UMC(version)) ? \ + ((GET_CVID_CUT_VERSION(version)) ? false : true) : false) #define IS_92C_SERIAL(version) ((version & CHIP_92C_BITMASK) ? true : false) +#define IS_CHIP_VENDOR_UMC(version) \ + ((version & CHIP_VENDOR_UMC) ? true : false) +#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK) +#define IS_81xxC_VENDOR_UMC_B_CUT(version) \ + ((IS_CHIP_VENDOR_UMC(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == CHIP_VENDOR_UMC_B_CUT) ? \ + true : false) : false) enum rtl819x_loopback_e { RTL819X_NO_LOOPBACK = 0, @@ -220,41 +234,6 @@ enum rtl_desc_qsel { QSLT_CMD = 0x13, }; -enum rtl_desc92c_rate { - DESC92C_RATE1M = 0x00, - DESC92C_RATE2M = 0x01, - DESC92C_RATE5_5M = 0x02, - DESC92C_RATE11M = 0x03, - - DESC92C_RATE6M = 0x04, - DESC92C_RATE9M = 0x05, - DESC92C_RATE12M = 0x06, - DESC92C_RATE18M = 0x07, - DESC92C_RATE24M = 0x08, - DESC92C_RATE36M = 0x09, - DESC92C_RATE48M = 0x0a, - DESC92C_RATE54M = 0x0b, - - DESC92C_RATEMCS0 = 0x0c, - DESC92C_RATEMCS1 = 0x0d, - DESC92C_RATEMCS2 = 0x0e, - DESC92C_RATEMCS3 = 0x0f, - DESC92C_RATEMCS4 = 0x10, - DESC92C_RATEMCS5 = 0x11, - DESC92C_RATEMCS6 = 0x12, - DESC92C_RATEMCS7 = 0x13, - DESC92C_RATEMCS8 = 0x14, - DESC92C_RATEMCS9 = 0x15, - DESC92C_RATEMCS10 = 0x16, - DESC92C_RATEMCS11 = 0x17, - DESC92C_RATEMCS12 = 0x18, - DESC92C_RATEMCS13 = 0x19, - DESC92C_RATEMCS14 = 0x1a, - DESC92C_RATEMCS15 = 0x1b, - DESC92C_RATEMCS15_SG = 0x1c, - DESC92C_RATEMCS32 = 0x20, -}; - struct phy_sts_cck_8192s_t { u8 adc_pwdb_X[4]; u8 sq_rpt; @@ -267,108 +246,4 @@ struct h2c_cmd_8192c { u8 *p_cmdbuffer; }; -/* NOTE: reference to rtl8192c_rates struct */ -static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT, - u8 desc_rate, bool first_ampdu) -{ - struct rtl_priv *rtlpriv = rtl_priv(hw); - int rate_idx = 0; - - if (first_ampdu) { - if (false == isHT) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG, - ("Rate %d is not support, set to " - "1M rate.\n", desc_rate)); - rate_idx = 0; - break; - } - } else { - rate_idx = 11; - } - return rate_idx; - } - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - /* TODO: How to mapping MCS rate? */ - /* NOTE: referenc to __ieee80211_rx */ - default: - rate_idx = 11; - break; - } - return rate_idx; -} - #endif diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c index 373dc78af1dc..a48404cc2b96 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c @@ -92,6 +92,8 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); const struct firmware *firmware; + struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + char *fw_name = NULL; rtl8192ce_bt_reg_init(hw); @@ -129,10 +131,16 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0); + /* for debug level */ + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; /* for LPS & IPS */ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + if (!rtlpriv->psc.inactiveps) + pr_info("rtl8192ce: Power Save off (module option)\n"); + if (!rtlpriv->psc.fwctrl_lps) + pr_info("rtl8192ce: FW Power Save off (module option)\n"); rtlpriv->psc.reg_fwctrl_lps = 3; rtlpriv->psc.reg_max_lps_awakeintvl = 5; /* for ASPM, you can close aspm through @@ -155,8 +163,14 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) } /* request fw */ - err = request_firmware(&firmware, rtlpriv->cfg->fw_name, - rtlpriv->io.dev); + if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && + !IS_92C_SERIAL(rtlhal->version)) + fw_name = "rtlwifi/rtl8192cfwU.bin"; + else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) + fw_name = "rtlwifi/rtl8192cfwU_B.bin"; + else + fw_name = rtlpriv->cfg->fw_name; + err = request_firmware(&firmware, fw_name, rtlpriv->io.dev); if (err) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Failed to request firmware!\n")); @@ -241,6 +255,7 @@ static struct rtl_mod_params rtl92ce_mod_params = { .inactiveps = true, .swctrl_lps = false, .fwctrl_lps = true, + .debug = DBG_EMERG, }; static struct rtl_hal_cfg rtl92ce_hal_cfg = { @@ -318,21 +333,21 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M, - - .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, }; DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = { @@ -351,27 +366,35 @@ MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless"); MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cfwU.bin"); +MODULE_FIRMWARE("rtlwifi/rtl8192cfwU_B.bin"); module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92ce_mod_params.debug, int, 0444); module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444); module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444); -MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); -MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); -MODULE_PARM_DESC(fwlps, "using linked fw control power save " - "(default 1 is open)\n"); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static const struct dev_pm_ops rtlwifi_pm_ops = { + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, + .freeze = rtl_pci_suspend, + .thaw = rtl_pci_resume, + .poweroff = rtl_pci_suspend, + .restore = rtl_pci_resume, +}; static struct pci_driver rtl92ce_driver = { .name = KBUILD_MODNAME, .id_table = rtl92ce_pci_ids, .probe = rtl_pci_probe, .remove = rtl_pci_disconnect, - -#ifdef CONFIG_PM - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, -#endif - + .driver.pm = &rtlwifi_pm_ops, }; static int __init rtl92ce_module_init(void) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c index 230bbe900d8d..4fb5ae24dee0 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c @@ -48,104 +48,6 @@ static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) -{ - int rate_idx; - - if (first_ampdu) { - if (false == isht) { - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - rate_idx = 11; - } - - return rate_idx; - } - - switch (desc_rate) { - case DESC92C_RATE1M: - rate_idx = 0; - break; - case DESC92C_RATE2M: - rate_idx = 1; - break; - case DESC92C_RATE5_5M: - rate_idx = 2; - break; - case DESC92C_RATE11M: - rate_idx = 3; - break; - case DESC92C_RATE6M: - rate_idx = 4; - break; - case DESC92C_RATE9M: - rate_idx = 5; - break; - case DESC92C_RATE12M: - rate_idx = 6; - break; - case DESC92C_RATE18M: - rate_idx = 7; - break; - case DESC92C_RATE24M: - rate_idx = 8; - break; - case DESC92C_RATE36M: - rate_idx = 9; - break; - case DESC92C_RATE48M: - rate_idx = 10; - break; - case DESC92C_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 11; - break; - } - return rate_idx; -} - static u8 _rtl92c_query_rxpwrpercentage(char antpower) { if ((antpower <= -100) || (antpower >= 20)) @@ -336,8 +238,8 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw, pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; - if (pdesc->rxht && pdesc->rxmcs >= DESC92C_RATEMCS8 && - pdesc->rxmcs <= DESC92C_RATEMCS15) + if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 && + pdesc->rxmcs <= DESC92_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -670,12 +572,10 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw, if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; - rx_status->rate_idx = _rtl92ce_rate_mapping((bool) - GET_RX_DESC_RXHT(pdesc), - (u8) - GET_RX_DESC_RXMCS(pdesc), - (bool) - GET_RX_DESC_PAGGR(pdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + (bool)GET_RX_DESC_RXHT(pdesc), + (u8)GET_RX_DESC_RXMCS(pdesc), + (bool)GET_RX_DESC_PAGGR(pdesc)); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { @@ -768,7 +668,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_BW(pdesc, 0); SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, - ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? + ((tcb_desc->rts_rate <= DESC92_RATE54M) ? (tcb_desc->rts_use_shortpreamble ? 1 : 0) : (tcb_desc->rts_use_shortgi ? 1 : 0))); @@ -886,7 +786,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, if (firstseg) SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN); - SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); SET_TX_DESC_SEQ(pdesc, 0); diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h index 0f1177137501..c8977a50ca36 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h @@ -537,12 +537,6 @@ do { \ memset(__pdesc, 0, _size); \ } while (0); -#define RX_HAL_IS_CCK_RATE(_pdesc)\ - (_pdesc->rxmcs == DESC92C_RATE1M || \ - _pdesc->rxmcs == DESC92C_RATE2M || \ - _pdesc->rxmcs == DESC92C_RATE5_5M || \ - _pdesc->rxmcs == DESC92C_RATE11M) - struct rx_fwinfo_92c { u8 gain_trsw[4]; u8 pwdb_all; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h index c54940ea72fe..d097efb1e717 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h @@ -50,10 +50,6 @@ #define IS_VENDOR_UMC(version) \ (((version) & CHIP_VENDOR_UMC) ? true : false) -#define IS_VENDOR_UMC_A_CUT(version) \ - (((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6) | BIT(7))) ? \ - false : true) : false) - #define IS_VENDOR_8723_A_CUT(version) \ (((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6))) ? \ false : true) : false) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 194fc693c1fa..060a06f4a885 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -892,8 +892,8 @@ static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw, pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; if (GET_RX_DESC_RX_MCS(pdesc) && - GET_RX_DESC_RX_MCS(pdesc) >= DESC92C_RATEMCS8 && - GET_RX_DESC_RX_MCS(pdesc) <= DESC92C_RATEMCS15) + GET_RX_DESC_RX_MCS(pdesc) >= DESC92_RATEMCS8 && + GET_RX_DESC_RX_MCS(pdesc) <= DESC92_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h index 298fdb724aa5..626d88e88e26 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.h @@ -87,12 +87,6 @@ void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter); u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw); -#define RX_HAL_IS_CCK_RATE(_pdesc)\ - (GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE1M ||\ - GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE2M ||\ - GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE5_5M ||\ - GET_RX_DESC_RX_MCS(_pdesc) == DESC92C_RATE11M) - struct rx_fwinfo_92c { u8 gain_trsw[4]; u8 pwdb_all; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c index 17a8e9628512..1e851aae58db 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c @@ -104,7 +104,7 @@ void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw, tx_agc[RF90_PATH_A] = 0x10101010; tx_agc[RF90_PATH_B] = 0x10101010; } else if (rtlpriv->dm.dynamic_txhighpower_lvl == - TXHIGHPWRLEVEL_LEVEL2) { + TXHIGHPWRLEVEL_LEVEL1) { tx_agc[RF90_PATH_A] = 0x00000000; tx_agc[RF90_PATH_B] = 0x00000000; } else{ diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index ef63c0df006a..feed1ed8d9b6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -60,6 +60,7 @@ static int rtl92cu_init_sw_vars(struct ieee80211_hw *hw) rtlpriv->dm.dm_flag = 0; rtlpriv->dm.disable_framebursting = 0; rtlpriv->dm.thermalvalue = 0; + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; rtlpriv->rtlhal.pfirmware = vmalloc(0x4000); if (!rtlpriv->rtlhal.pfirmware) { RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, @@ -149,8 +150,14 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = { static struct rtl_mod_params rtl92cu_mod_params = { .sw_crypto = 0, + .debug = DBG_EMERG, }; +module_param_named(swenc, rtl92cu_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92cu_mod_params.debug, int, 0444); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = { /* rx */ .in_ep_num = RTL92C_USB_BULK_IN_NUM, @@ -241,20 +248,20 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92C_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92C_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92C_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92C_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92C_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92C_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92C_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92C_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92C_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92C_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92C_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92C_RATE54M, - .maps[RTL_RC_HT_RATEMCS7] = DESC92C_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, }; #define USB_VENDER_ID_REALTEK 0x0bda diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c index 3e52a5496224..bc33b147f44f 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c @@ -337,10 +337,10 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw, rx_status->flag |= RX_FLAG_MACTIME_MPDU; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; - rx_status->rate_idx = _rtl92c_rate_mapping(hw, - (bool)GET_RX_DESC_RX_HT(pdesc), - (u8)GET_RX_DESC_RX_MCS(pdesc), - (bool)GET_RX_DESC_PAGGR(pdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + (bool)GET_RX_DESC_RX_HT(pdesc), + (u8)GET_RX_DESC_RX_MCS(pdesc), + (bool)GET_RX_DESC_PAGGR(pdesc)); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92c *)(pdesc + RTL_RX_DESC_SIZE); @@ -406,11 +406,10 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb) if (GET_RX_DESC_RX_HT(rxdesc)) rx_status->flag |= RX_FLAG_HT; /* Data rate */ - rx_status->rate_idx = _rtl92c_rate_mapping(hw, - (bool)GET_RX_DESC_RX_HT(rxdesc), - (u8)GET_RX_DESC_RX_MCS(rxdesc), - (bool)GET_RX_DESC_PAGGR(rxdesc) - ); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + (bool)GET_RX_DESC_RX_HT(rxdesc), + (u8)GET_RX_DESC_RX_MCS(rxdesc), + (bool)GET_RX_DESC_PAGGR(rxdesc)); /* There is a phy status after this rx descriptor. */ if (GET_RX_DESC_PHY_STATUS(rxdesc)) { p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE); @@ -545,7 +544,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_BW(txdesc, 0); SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(txdesc, - ((tcb_desc->rts_rate <= DESC92C_RATE54M) ? + ((tcb_desc->rts_rate <= DESC92_RATE54M) ? (tcb_desc->rts_use_shortpreamble ? 1 : 0) : (tcb_desc->rts_use_shortgi ? 1 : 0))); if (mac->bw_40) { @@ -644,7 +643,7 @@ void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc, } SET_TX_DESC_USE_RATE(pDesc, 1); /* use data rate which is set by Sw */ SET_TX_DESC_OWN(pDesc, 1); - SET_TX_DESC_TX_RATE(pDesc, DESC92C_RATE1M); + SET_TX_DESC_TX_RATE(pDesc, DESC92_RATE1M); _rtl_tx_desc_checksum(pDesc); } @@ -660,7 +659,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw, memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE); if (firstseg) SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE); - SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); SET_TX_DESC_SEQ(pdesc, 0); SET_TX_DESC_LINIP(pdesc, 0); SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/def.h b/drivers/net/wireless/rtlwifi/rtl8192de/def.h index f0f5f9bfbb7b..946304771748 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/def.h @@ -122,60 +122,99 @@ #define GET_C2H_CMD_FEEDBACK_CCX_SEQ(__pcmdfbhdr) \ LE_BITS_TO_4BYTE(((__pcmdfbhdr) + 4), 20, 12) -/* - * 92D chip ver: - * BIT8: IS 92D - * BIT9: single phy - * BIT10: C-cut - * BIT11: D-cut - */ - -/* Chip specific */ -#define CHIP_92C BIT(0) -#define CHIP_92C_1T2R BIT(1) -#define CHIP_8723 BIT(2) /* RTL8723 With BT feature */ -#define CHIP_8723_DRV_REV BIT(3) /* RTL8723 Driver Revised */ -#define NORMAL_CHIP BIT(4) -#define CHIP_VENDOR_UMC BIT(5) -#define CHIP_VENDOR_UMC_B_CUT BIT(6) /* Chip version for ECO */ +enum version_8192d { + VERSION_TEST_CHIP_88C = 0x0000, + VERSION_TEST_CHIP_92C = 0x0020, + VERSION_TEST_UMC_CHIP_8723 = 0x0081, + VERSION_NORMAL_TSMC_CHIP_88C = 0x0008, + VERSION_NORMAL_TSMC_CHIP_92C = 0x0028, + VERSION_NORMAL_TSMC_CHIP_92C_1T2R = 0x0018, + VERSION_NORMAL_UMC_CHIP_88C_A_CUT = 0x0088, + VERSION_NORMAL_UMC_CHIP_92C_A_CUT = 0x00a8, + VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT = 0x0098, + VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089, + VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089, + VERSION_NORMAL_UMC_CHIP_88C_B_CUT = 0x1088, + VERSION_NORMAL_UMC_CHIP_92C_B_CUT = 0x10a8, + VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT = 0x1090, + VERSION_TEST_CHIP_92D_SINGLEPHY = 0x0022, + VERSION_TEST_CHIP_92D_DUALPHY = 0x0002, + VERSION_NORMAL_CHIP_92D_SINGLEPHY = 0x002a, + VERSION_NORMAL_CHIP_92D_DUALPHY = 0x000a, + VERSION_NORMAL_CHIP_92D_C_CUT_SINGLEPHY = 0x202a, + VERSION_NORMAL_CHIP_92D_C_CUT_DUALPHY = 0x200a, + VERSION_NORMAL_CHIP_92D_D_CUT_SINGLEPHY = 0x302a, + VERSION_NORMAL_CHIP_92D_D_CUT_DUALPHY = 0x300a, + VERSION_NORMAL_CHIP_92D_E_CUT_SINGLEPHY = 0x402a, + VERSION_NORMAL_CHIP_92D_E_CUT_DUALPHY = 0x400a, +}; /* for 92D */ -#define CHIP_92D BIT(8) #define CHIP_92D_SINGLEPHY BIT(9) +#define C_CUT_VERSION BIT(13) +#define D_CUT_VERSION ((BIT(12)|BIT(13))) +#define E_CUT_VERSION BIT(14) + +/* Chip specific */ +#define CHIP_BONDING_IDENTIFIER(_value) (((_value)>>22)&0x3) +#define CHIP_BONDING_92C_1T2R 0x1 +#define CHIP_BONDING_88C_USB_MCARD 0x2 +#define CHIP_BONDING_88C_USB_HP 0x1 + +/* [15:12] IC version(CUT): A-cut=0, B-cut=1, C-cut=2, D-cut=3 */ +/* [7] Manufacturer: TSMC=0, UMC=1 */ +/* [6:4] RF type: 1T1R=0, 1T2R=1, 2T2R=2 */ +/* [3] Chip type: TEST=0, NORMAL=1 */ +/* [2:0] IC type: 81xxC=0, 8723=1, 92D=2 */ +#define CHIP_8723 BIT(0) +#define CHIP_92D BIT(1) +#define NORMAL_CHIP BIT(3) +#define RF_TYPE_1T1R (~(BIT(4)|BIT(5)|BIT(6))) +#define RF_TYPE_1T2R BIT(4) +#define RF_TYPE_2T2R BIT(5) +#define CHIP_VENDOR_UMC BIT(7) +#define B_CUT_VERSION BIT(12) + +/* MASK */ +#define IC_TYPE_MASK (BIT(0)|BIT(1)|BIT(2)) +#define CHIP_TYPE_MASK BIT(3) +#define RF_TYPE_MASK (BIT(4)|BIT(5)|BIT(6)) +#define MANUFACTUER_MASK BIT(7) +#define ROM_VERSION_MASK (BIT(11)|BIT(10)|BIT(9)|BIT(8)) +#define CUT_VERSION_MASK (BIT(15)|BIT(14)|BIT(13)|BIT(12)) + + +/* Get element */ +#define GET_CVID_IC_TYPE(version) ((version) & IC_TYPE_MASK) +#define GET_CVID_CHIP_TYPE(version) ((version) & CHIP_TYPE_MASK) +#define GET_CVID_RF_TYPE(version) ((version) & RF_TYPE_MASK) +#define GET_CVID_MANUFACTUER(version) ((version) & MANUFACTUER_MASK) +#define GET_CVID_ROM_VERSION(version) ((version) & ROM_VERSION_MASK) +#define GET_CVID_CUT_VERSION(version) ((version) & CUT_VERSION_MASK) + +#define IS_1T1R(version) ((GET_CVID_RF_TYPE(version)) ? \ + false : true) +#define IS_1T2R(version) ((GET_CVID_RF_TYPE(version) == \ + RF_TYPE_1T2R) ? true : false) +#define IS_2T2R(version) ((GET_CVID_RF_TYPE(version) == \ + RF_TYPE_2T2R) ? true : false) + +#define IS_92D_SINGLEPHY(version) ((IS_92D(version)) ? \ + (IS_2T2R(version) ? true : false) : false) +#define IS_92D(version) ((GET_CVID_IC_TYPE(version) == \ + CHIP_92D) ? true : false) +#define IS_92D_C_CUT(version) ((IS_92D(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == \ + 0x2000) ? true : false) : false) +#define IS_92D_D_CUT(version) ((IS_92D(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == \ + 0x3000) ? true : false) : false) +#define IS_92D_E_CUT(version) ((IS_92D(version)) ? \ + ((GET_CVID_CUT_VERSION(version) == \ + 0x4000) ? true : false) : false) #define CHIP_92D_C_CUT BIT(10) #define CHIP_92D_D_CUT BIT(11) -enum version_8192d { - VERSION_TEST_CHIP_88C = 0x00, - VERSION_TEST_CHIP_92C = 0x01, - VERSION_NORMAL_TSMC_CHIP_88C = 0x10, - VERSION_NORMAL_TSMC_CHIP_92C = 0x11, - VERSION_NORMAL_TSMC_CHIP_92C_1T2R = 0x13, - VERSION_NORMAL_UMC_CHIP_88C_A_CUT = 0x30, - VERSION_NORMAL_UMC_CHIP_92C_A_CUT = 0x31, - VERSION_NORMAL_UMC_CHIP_92C_1T2R_A_CUT = 0x33, - VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT = 0x34, - VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT = 0x3c, - VERSION_NORMAL_UMC_CHIP_88C_B_CUT = 0x70, - VERSION_NORMAL_UMC_CHIP_92C_B_CUT = 0x71, - VERSION_NORMAL_UMC_CHIP_92C_1T2R_B_CUT = 0x73, - VERSION_TEST_CHIP_92D_SINGLEPHY = 0x300, - VERSION_TEST_CHIP_92D_DUALPHY = 0x100, - VERSION_NORMAL_CHIP_92D_SINGLEPHY = 0x310, - VERSION_NORMAL_CHIP_92D_DUALPHY = 0x110, - VERSION_NORMAL_CHIP_92D_C_CUT_SINGLEPHY = 0x710, - VERSION_NORMAL_CHIP_92D_C_CUT_DUALPHY = 0x510, - VERSION_NORMAL_CHIP_92D_D_CUT_SINGLEPHY = 0xB10, - VERSION_NORMAL_CHIP_92D_D_CUT_DUALPHY = 0x910, -}; - -#define IS_92D_SINGLEPHY(version) \ - ((version & CHIP_92D_SINGLEPHY) ? true : false) -#define IS_92D_C_CUT(version) \ - ((version & CHIP_92D_C_CUT) ? true : false) -#define IS_92D_D_CUT(version) \ - ((version & CHIP_92D_D_CUT) ? true : false) - enum rf_optype { RF_OP_BY_SW_3WIRE = 0, RF_OP_BY_FW, @@ -193,41 +232,6 @@ enum rtl_desc_qsel { QSLT_CMD = 0x13, }; -enum rtl_desc92d_rate { - DESC92D_RATE1M = 0x00, - DESC92D_RATE2M = 0x01, - DESC92D_RATE5_5M = 0x02, - DESC92D_RATE11M = 0x03, - - DESC92D_RATE6M = 0x04, - DESC92D_RATE9M = 0x05, - DESC92D_RATE12M = 0x06, - DESC92D_RATE18M = 0x07, - DESC92D_RATE24M = 0x08, - DESC92D_RATE36M = 0x09, - DESC92D_RATE48M = 0x0a, - DESC92D_RATE54M = 0x0b, - - DESC92D_RATEMCS0 = 0x0c, - DESC92D_RATEMCS1 = 0x0d, - DESC92D_RATEMCS2 = 0x0e, - DESC92D_RATEMCS3 = 0x0f, - DESC92D_RATEMCS4 = 0x10, - DESC92D_RATEMCS5 = 0x11, - DESC92D_RATEMCS6 = 0x12, - DESC92D_RATEMCS7 = 0x13, - DESC92D_RATEMCS8 = 0x14, - DESC92D_RATEMCS9 = 0x15, - DESC92D_RATEMCS10 = 0x16, - DESC92D_RATEMCS11 = 0x17, - DESC92D_RATEMCS12 = 0x18, - DESC92D_RATEMCS13 = 0x19, - DESC92D_RATEMCS14 = 0x1a, - DESC92D_RATEMCS15 = 0x1b, - DESC92D_RATEMCS15_SG = 0x1c, - DESC92D_RATEMCS32 = 0x20, -}; - enum channel_plan { CHPL_FCC = 0, CHPL_IC = 1, diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c index 0073cf106af2..f5bd3a3cd34a 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c @@ -1608,17 +1608,16 @@ static void _rtl92de_read_txpower_info(struct ieee80211_hw *hw, tempval[0] = hwinfo[EEPROM_IQK_DELTA] & 0x03; tempval[1] = (hwinfo[EEPROM_LCK_DELTA] & 0x0C) >> 2; rtlefuse->txpwr_fromeprom = true; - if (IS_92D_D_CUT(rtlpriv->rtlhal.version)) { + if (IS_92D_D_CUT(rtlpriv->rtlhal.version) || + IS_92D_E_CUT(rtlpriv->rtlhal.version)) { rtlefuse->internal_pa_5g[0] = - !((hwinfo[EEPROM_TSSI_A_5G] & - BIT(6)) >> 6); + !((hwinfo[EEPROM_TSSI_A_5G] & BIT(6)) >> 6); rtlefuse->internal_pa_5g[1] = - !((hwinfo[EEPROM_TSSI_B_5G] & - BIT(6)) >> 6); - RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, + !((hwinfo[EEPROM_TSSI_B_5G] & BIT(6)) >> 6); + RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Is D cut,Internal PA0 %d Internal PA1 %d\n", - rtlefuse->internal_pa_5g[0], - rtlefuse->internal_pa_5g[1])) + rtlefuse->internal_pa_5g[0], + rtlefuse->internal_pa_5g[1])) } rtlefuse->eeprom_c9 = hwinfo[EEPROM_RF_OPT6]; rtlefuse->eeprom_cc = hwinfo[EEPROM_RF_OPT7]; diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c index 351765df517d..691f80092185 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c @@ -146,10 +146,16 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw) rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD); + /* for debug level */ + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; /* for LPS & IPS */ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + if (!rtlpriv->psc.inactiveps) + pr_info("rtl8192ce: Power Save off (module option)\n"); + if (!rtlpriv->psc.fwctrl_lps) + pr_info("rtl8192ce: FW Power Save off (module option)\n"); rtlpriv->psc.reg_fwctrl_lps = 3; rtlpriv->psc.reg_max_lps_awakeintvl = 5; /* for ASPM, you can close aspm through @@ -263,6 +269,7 @@ static struct rtl_mod_params rtl92de_mod_params = { .inactiveps = true, .swctrl_lps = true, .fwctrl_lps = false, + .debug = DBG_EMERG, }; static struct rtl_hal_cfg rtl92de_hal_cfg = { @@ -340,21 +347,21 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BcnInt | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92D_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92D_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92D_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92D_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92D_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92D_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92D_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92D_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92D_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92D_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92D_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92D_RATE54M, - - .maps[RTL_RC_HT_RATEMCS7] = DESC92D_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92D_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, }; static struct pci_device_id rtl92de_pci_ids[] __devinitdata = { @@ -373,25 +380,31 @@ MODULE_DESCRIPTION("Realtek 8192DE 802.11n Dual Mac PCI wireless"); MODULE_FIRMWARE("rtlwifi/rtl8192defw.bin"); module_param_named(swenc, rtl92de_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92de_mod_params.debug, int, 0444); module_param_named(ips, rtl92de_mod_params.inactiveps, bool, 0444); module_param_named(swlps, rtl92de_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl92de_mod_params.fwctrl_lps, bool, 0444); -MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); -MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); -MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1" - " is open)\n"); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); + +static const struct dev_pm_ops rtlwifi_pm_ops = { + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, + .freeze = rtl_pci_suspend, + .thaw = rtl_pci_resume, + .poweroff = rtl_pci_suspend, + .restore = rtl_pci_resume, +}; static struct pci_driver rtl92de_driver = { .name = KBUILD_MODNAME, .id_table = rtl92de_pci_ids, .probe = rtl_pci_probe, .remove = rtl_pci_disconnect, - -#ifdef CONFIG_PM - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, -#endif - + .driver.pm = &rtlwifi_pm_ops, }; /* add global spin lock to solve the problem that diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c index dc86fcb0b3a3..3637c0c33525 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c @@ -48,99 +48,6 @@ static u8 _rtl92de_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue) return skb->priority; } -static int _rtl92de_rate_mapping(bool isht, u8 desc_rate) -{ - int rate_idx; - - if (false == isht) { - switch (desc_rate) { - case DESC92D_RATE1M: - rate_idx = 0; - break; - case DESC92D_RATE2M: - rate_idx = 1; - break; - case DESC92D_RATE5_5M: - rate_idx = 2; - break; - case DESC92D_RATE11M: - rate_idx = 3; - break; - case DESC92D_RATE6M: - rate_idx = 4; - break; - case DESC92D_RATE9M: - rate_idx = 5; - break; - case DESC92D_RATE12M: - rate_idx = 6; - break; - case DESC92D_RATE18M: - rate_idx = 7; - break; - case DESC92D_RATE24M: - rate_idx = 8; - break; - case DESC92D_RATE36M: - rate_idx = 9; - break; - case DESC92D_RATE48M: - rate_idx = 10; - break; - case DESC92D_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - return rate_idx; - } else { - switch (desc_rate) { - case DESC92D_RATE1M: - rate_idx = 0; - break; - case DESC92D_RATE2M: - rate_idx = 1; - break; - case DESC92D_RATE5_5M: - rate_idx = 2; - break; - case DESC92D_RATE11M: - rate_idx = 3; - break; - case DESC92D_RATE6M: - rate_idx = 4; - break; - case DESC92D_RATE9M: - rate_idx = 5; - break; - case DESC92D_RATE12M: - rate_idx = 6; - break; - case DESC92D_RATE18M: - rate_idx = 7; - break; - case DESC92D_RATE24M: - rate_idx = 8; - break; - case DESC92D_RATE36M: - rate_idx = 9; - break; - case DESC92D_RATE48M: - rate_idx = 10; - break; - case DESC92D_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 11; - break; - } - return rate_idx; - } -} - static u8 _rtl92d_query_rxpwrpercentage(char antpower) { if ((antpower <= -100) || (antpower >= 20)) @@ -328,8 +235,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw, pstats->rx_pwdb_all = pwdb_all; pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; - if (pdesc->rxht && pdesc->rxmcs >= DESC92D_RATEMCS8 && - pdesc->rxmcs <= DESC92D_RATEMCS15) + if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 && + pdesc->rxmcs <= DESC92_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -609,10 +516,10 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, rx_status->flag |= RX_FLAG_MACTIME_MPDU; if (stats->decrypted) rx_status->flag |= RX_FLAG_DECRYPTED; - rx_status->rate_idx = _rtl92de_rate_mapping((bool) - GET_RX_DESC_RXHT(pdesc), - (u8) - GET_RX_DESC_RXMCS(pdesc)); + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + (bool)GET_RX_DESC_RXHT(pdesc), + (u8)GET_RX_DESC_RXMCS(pdesc), + (bool)GET_RX_DESC_PAGGR(pdesc)); rx_status->mactime = GET_RX_DESC_TSFL(pdesc); if (phystatus) { p_drvinfo = (struct rx_fwinfo_92d *)(skb->data + @@ -705,14 +612,14 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, } /* 5G have no CCK rate */ if (rtlhal->current_bandtype == BAND_ON_5G) - if (ptcb_desc->hw_rate < DESC92D_RATE6M) - ptcb_desc->hw_rate = DESC92D_RATE6M; + if (ptcb_desc->hw_rate < DESC92_RATE6M) + ptcb_desc->hw_rate = DESC92_RATE6M; SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate); if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); if (rtlhal->macphymode == DUALMAC_DUALPHY && - ptcb_desc->hw_rate == DESC92D_RATEMCS7) + ptcb_desc->hw_rate == DESC92_RATEMCS7) SET_TX_DESC_DATA_SHORTGI(pdesc, 1); if (info->flags & IEEE80211_TX_CTL_AMPDU) { @@ -728,13 +635,13 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0)); /* 5G have no CCK rate */ if (rtlhal->current_bandtype == BAND_ON_5G) - if (ptcb_desc->rts_rate < DESC92D_RATE6M) - ptcb_desc->rts_rate = DESC92D_RATE6M; + if (ptcb_desc->rts_rate < DESC92_RATE6M) + ptcb_desc->rts_rate = DESC92_RATE6M; SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate); SET_TX_DESC_RTS_BW(pdesc, 0); SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= - DESC92D_RATE54M) ? + DESC92_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); if (bw_40) { @@ -844,9 +751,9 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw, * The braces are needed no matter what checkpatch says */ if (rtlhal->current_bandtype == BAND_ON_5G) { - SET_TX_DESC_TX_RATE(pdesc, DESC92D_RATE6M); + SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE6M); } else { - SET_TX_DESC_TX_RATE(pdesc, DESC92D_RATE1M); + SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M); } SET_TX_DESC_SEQ(pdesc, 0); SET_TX_DESC_LINIP(pdesc, 0); diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h index 992d6766e667..4d55d0b6816d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.h +++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.h @@ -537,12 +537,6 @@ do { \ memset((void *)__pdesc, 0, _size); \ } while (0); -#define RX_HAL_IS_CCK_RATE(_pdesc)\ - (_pdesc->rxmcs == DESC92D_RATE1M || \ - _pdesc->rxmcs == DESC92D_RATE2M || \ - _pdesc->rxmcs == DESC92D_RATE5_5M || \ - _pdesc->rxmcs == DESC92D_RATE11M) - /* For 92D early mode */ #define SET_EARLYMODE_PKTNUM(__paddr, __value) \ SET_BITS_OFFSET_LE(__paddr, 0, 3, __value) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h index 69828f2b3fab..c6c044816d39 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h @@ -33,37 +33,6 @@ #define RX_CMD_QUEUE 1 #define RX_MAX_QUEUE 2 -#define DESC92S_RATE1M 0x00 -#define DESC92S_RATE2M 0x01 -#define DESC92S_RATE5_5M 0x02 -#define DESC92S_RATE11M 0x03 -#define DESC92S_RATE6M 0x04 -#define DESC92S_RATE9M 0x05 -#define DESC92S_RATE12M 0x06 -#define DESC92S_RATE18M 0x07 -#define DESC92S_RATE24M 0x08 -#define DESC92S_RATE36M 0x09 -#define DESC92S_RATE48M 0x0a -#define DESC92S_RATE54M 0x0b -#define DESC92S_RATEMCS0 0x0c -#define DESC92S_RATEMCS1 0x0d -#define DESC92S_RATEMCS2 0x0e -#define DESC92S_RATEMCS3 0x0f -#define DESC92S_RATEMCS4 0x10 -#define DESC92S_RATEMCS5 0x11 -#define DESC92S_RATEMCS6 0x12 -#define DESC92S_RATEMCS7 0x13 -#define DESC92S_RATEMCS8 0x14 -#define DESC92S_RATEMCS9 0x15 -#define DESC92S_RATEMCS10 0x16 -#define DESC92S_RATEMCS11 0x17 -#define DESC92S_RATEMCS12 0x18 -#define DESC92S_RATEMCS13 0x19 -#define DESC92S_RATEMCS14 0x1a -#define DESC92S_RATEMCS15 0x1b -#define DESC92S_RATEMCS15_SG 0x1c -#define DESC92S_RATEMCS32 0x20 - #define SHORT_SLOT_TIME 9 #define NON_SHORT_SLOT_TIME 20 @@ -490,11 +459,11 @@ do { \ #define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \ SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val) -#define RX_HAL_IS_CCK_RATE(_pdesc)\ - (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE1M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE2M || \ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE5_5M ||\ - GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE11M) +#define SE_RX_HAL_IS_CCK_RATE(_pdesc)\ + (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE2M || \ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\ + GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE11M) enum rf_optype { RF_OP_BY_SW_3WIRE = 0, diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c index d59f66cb7768..c474486e3911 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c @@ -1382,7 +1382,7 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34); /* Reset MAC-IO and CPU and Core Digital BIT10/11/15 */ - tmpu1b = rtl_read_byte(rtlpriv, SYS_FUNC_EN + 1); + tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1); /* If IPS we need to turn LED on. So we not * not disable BIT 3/7 of reg3. */ @@ -1391,7 +1391,7 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) else tmpu1b &= 0x73; - rtl_write_byte(rtlpriv, SYS_FUNC_EN + 1, tmpu1b); + rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b); /* wait for BIT 10/11/15 to pull high automatically!! */ mdelay(1); @@ -1428,15 +1428,15 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0))); /* Set Digital Vdd to Retention isolation Path. */ - tmpu2b = rtl_read_word(rtlpriv, SYS_ISO_CTRL); - rtl_write_word(rtlpriv, SYS_ISO_CTRL, (tmpu2b | BIT(11))); + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL); + rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11))); /* For warm reboot NIC disappera bug. */ - tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN); - rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(13))); + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13))); - rtl_write_byte(rtlpriv, SYS_ISO_CTRL + 1, 0x68); + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68); /* Enable AFE PLL Macro Block */ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL); @@ -1447,17 +1447,17 @@ static void _rtl92se_power_domain_init(struct ieee80211_hw *hw) mdelay(1); /* Release isolation AFE PLL & MD */ - rtl_write_byte(rtlpriv, SYS_ISO_CTRL, 0xA6); + rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6); /* Enable MAC clock */ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11))); /* Enable Core digital and enable IOREG R/W */ - tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN); - rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11))); + tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11))); /* enable REG_EN */ - rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); + rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15))); /* Switch the control path. */ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR); diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h index ea32ef2d4098..11f125c030ce 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h @@ -735,6 +735,7 @@ #define HWSET_MAX_SIZE_92S 128 #define EFUSE_MAX_SECTION 16 #define EFUSE_REAL_CONTENT_LEN 512 +#define EFUSE_OOB_PROTECT_BYTES 15 #define RTL8190_EEPROM_ID 0x8129 #define EEPROM_HPON 0x02 diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index 3876078a63de..3ec9a0d41baf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -160,10 +160,16 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw) rtlpci->first_init = true; + /* for debug level */ + rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug; /* for LPS & IPS */ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps; rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; + if (!rtlpriv->psc.inactiveps) + pr_info("rtl8192ce: Power Save off (module option)\n"); + if (!rtlpriv->psc.fwctrl_lps) + pr_info("rtl8192ce: FW Power Save off (module option)\n"); rtlpriv->psc.reg_fwctrl_lps = 3; rtlpriv->psc.reg_max_lps_awakeintvl = 5; /* for ASPM, you can close aspm through @@ -268,6 +274,7 @@ static struct rtl_mod_params rtl92se_mod_params = { .inactiveps = true, .swctrl_lps = true, .fwctrl_lps = false, + .debug = DBG_EMERG, }; /* Because memory R/W bursting will cause system hang/crash @@ -300,6 +307,7 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = { .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE_92S, .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION, .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN, + .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES, .maps[RWCAM] = REG_RWCAM, .maps[WCAMI] = REG_WCAMI, @@ -348,21 +356,21 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = { .maps[RTL_IMR_ROK] = IMR_ROK, .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER), - .maps[RTL_RC_CCK_RATE1M] = DESC92S_RATE1M, - .maps[RTL_RC_CCK_RATE2M] = DESC92S_RATE2M, - .maps[RTL_RC_CCK_RATE5_5M] = DESC92S_RATE5_5M, - .maps[RTL_RC_CCK_RATE11M] = DESC92S_RATE11M, - .maps[RTL_RC_OFDM_RATE6M] = DESC92S_RATE6M, - .maps[RTL_RC_OFDM_RATE9M] = DESC92S_RATE9M, - .maps[RTL_RC_OFDM_RATE12M] = DESC92S_RATE12M, - .maps[RTL_RC_OFDM_RATE18M] = DESC92S_RATE18M, - .maps[RTL_RC_OFDM_RATE24M] = DESC92S_RATE24M, - .maps[RTL_RC_OFDM_RATE36M] = DESC92S_RATE36M, - .maps[RTL_RC_OFDM_RATE48M] = DESC92S_RATE48M, - .maps[RTL_RC_OFDM_RATE54M] = DESC92S_RATE54M, - - .maps[RTL_RC_HT_RATEMCS7] = DESC92S_RATEMCS7, - .maps[RTL_RC_HT_RATEMCS15] = DESC92S_RATEMCS15, + .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M, + .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M, + .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M, + .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M, + .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M, + .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M, + .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M, + .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M, + .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M, + .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M, + .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M, + .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M, + + .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7, + .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15, }; static struct pci_device_id rtl92se_pci_ids[] __devinitdata = { @@ -378,31 +386,37 @@ MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids); MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>"); MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>"); +MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless"); MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin"); module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444); +module_param_named(debug, rtl92se_mod_params.debug, int, 0444); module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444); module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444); module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444); -MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n"); -MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n"); -MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1 is " - "open)\n"); +MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); +MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); +MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); +MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n"); +MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); +static const struct dev_pm_ops rtlwifi_pm_ops = { + .suspend = rtl_pci_suspend, + .resume = rtl_pci_resume, + .freeze = rtl_pci_suspend, + .thaw = rtl_pci_resume, + .poweroff = rtl_pci_suspend, + .restore = rtl_pci_resume, +}; static struct pci_driver rtl92se_driver = { .name = KBUILD_MODNAME, .id_table = rtl92se_pci_ids, .probe = rtl_pci_probe, .remove = rtl_pci_disconnect, - -#ifdef CONFIG_PM - .suspend = rtl_pci_suspend, - .resume = rtl_pci_resume, -#endif - + .driver.pm = &rtlwifi_pm_ops, }; static int __init rtl92se_module_init(void) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c index cffe30851f79..fbebe3ea0a22 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c @@ -51,104 +51,6 @@ static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue) return skb->priority; } -static int _rtl92se_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu) -{ - int rate_idx = 0; - - if (first_ampdu) { - if (false == isht) { - switch (desc_rate) { - case DESC92S_RATE1M: - rate_idx = 0; - break; - case DESC92S_RATE2M: - rate_idx = 1; - break; - case DESC92S_RATE5_5M: - rate_idx = 2; - break; - case DESC92S_RATE11M: - rate_idx = 3; - break; - case DESC92S_RATE6M: - rate_idx = 4; - break; - case DESC92S_RATE9M: - rate_idx = 5; - break; - case DESC92S_RATE12M: - rate_idx = 6; - break; - case DESC92S_RATE18M: - rate_idx = 7; - break; - case DESC92S_RATE24M: - rate_idx = 8; - break; - case DESC92S_RATE36M: - rate_idx = 9; - break; - case DESC92S_RATE48M: - rate_idx = 10; - break; - case DESC92S_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 0; - break; - } - } else { - rate_idx = 11; - } - - return rate_idx; - } - - switch (desc_rate) { - case DESC92S_RATE1M: - rate_idx = 0; - break; - case DESC92S_RATE2M: - rate_idx = 1; - break; - case DESC92S_RATE5_5M: - rate_idx = 2; - break; - case DESC92S_RATE11M: - rate_idx = 3; - break; - case DESC92S_RATE6M: - rate_idx = 4; - break; - case DESC92S_RATE9M: - rate_idx = 5; - break; - case DESC92S_RATE12M: - rate_idx = 6; - break; - case DESC92S_RATE18M: - rate_idx = 7; - break; - case DESC92S_RATE24M: - rate_idx = 8; - break; - case DESC92S_RATE36M: - rate_idx = 9; - break; - case DESC92S_RATE48M: - rate_idx = 10; - break; - case DESC92S_RATE54M: - rate_idx = 11; - break; - default: - rate_idx = 11; - break; - } - return rate_idx; -} - static u8 _rtl92s_query_rxpwrpercentage(char antpower) { if ((antpower <= -100) || (antpower >= 20)) @@ -222,18 +124,15 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, u8 i, max_spatial_stream; u32 rssi, total_rssi = 0; bool in_powersavemode = false; - bool is_cck_rate; + bool is_cck = pstats->is_cck; - is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc); pstats->packet_matchbssid = packet_match_bssid; pstats->packet_toself = packet_toself; - pstats->is_cck = is_cck_rate; pstats->packet_beacon = packet_beacon; - pstats->is_cck = is_cck_rate; pstats->rx_mimo_signalquality[0] = -1; pstats->rx_mimo_signalquality[1] = -1; - if (is_cck_rate) { + if (is_cck) { u8 report, cck_highpwr; cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo; @@ -344,9 +243,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, pstats->rxpower = rx_pwr_all; pstats->recvsignalpower = rx_pwr_all; - if (GET_RX_STATUS_DESC_RX_HT(pdesc) && - GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92S_RATEMCS8 && - GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92S_RATEMCS15) + if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 && + pstats->rate <= DESC92_RATEMCS15) max_spatial_stream = 2; else max_spatial_stream = 1; @@ -364,7 +262,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw, } } - if (is_cck_rate) + if (is_cck) pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw, pwdb_all)); else if (rf_rx_num != 0) @@ -616,6 +514,8 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, { struct rx_fwinfo *p_drvinfo; u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc); + struct ieee80211_hdr *hdr; + bool first_ampdu = false; stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc); stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8; @@ -628,8 +528,12 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc); stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc); stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1); + stats->isfirst_ampdu = (bool) ((GET_RX_STATUS_DESC_PAGGR(pdesc) == 1) + && (GET_RX_STATUS_DESC_FAGGR(pdesc) == 1)); stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc); stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc); + stats->is_ht = (bool)GET_RX_STATUS_DESC_RX_HT(pdesc); + stats->is_cck = SE_RX_HAL_IS_CCK_RATE(pdesc); if (stats->hwerror) return false; @@ -637,30 +541,39 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats, rx_status->freq = hw->conf.channel->center_freq; rx_status->band = hw->conf.channel->band; - if (GET_RX_STATUS_DESC_CRC32(pdesc)) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + hdr = (struct ieee80211_hdr *)(skb->data + stats->rx_drvinfo_size + + stats->rx_bufshift); - if (!GET_RX_STATUS_DESC_SWDEC(pdesc)) - rx_status->flag |= RX_FLAG_DECRYPTED; + if (stats->crc) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - if (GET_RX_STATUS_DESC_BW(pdesc)) + if (stats->rx_is40Mhzpacket) rx_status->flag |= RX_FLAG_40MHZ; - if (GET_RX_STATUS_DESC_RX_HT(pdesc)) + if (stats->is_ht) rx_status->flag |= RX_FLAG_HT; rx_status->flag |= RX_FLAG_MACTIME_MPDU; - if (stats->decrypted) - rx_status->flag |= RX_FLAG_DECRYPTED; - - rx_status->rate_idx = _rtl92se_rate_mapping((bool) - GET_RX_STATUS_DESC_RX_HT(pdesc), - (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc), - (bool)GET_RX_STATUS_DESC_PAGGR(pdesc)); + /* hw will set stats->decrypted true, if it finds the + * frame is open data frame or mgmt frame, + * hw will not decrypt robust managment frame + * for IEEE80211w but still set stats->decrypted + * true, so here we should set it back to undecrypted + * for IEEE80211w frame, and mac80211 sw will help + * to decrypt it */ + if (stats->decrypted) { + if ((ieee80211_is_robust_mgmt_frame(hdr)) && + (ieee80211_has_protected(hdr->frame_control))) + rx_status->flag &= ~RX_FLAG_DECRYPTED; + else + rx_status->flag |= RX_FLAG_DECRYPTED; + } + rx_status->rate_idx = rtlwifi_rate_mapping(hw, + stats->is_ht, stats->rate, first_ampdu); - rx_status->mactime = GET_RX_STATUS_DESC_TSFL(pdesc); + rx_status->mactime = stats->timestamp_low; if (phystatus) { p_drvinfo = (struct rx_fwinfo *)(skb->data + stats->rx_bufshift); @@ -723,14 +636,14 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid); SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >= - DESC92S_RATEMCS0) ? 1 : 0)); + DESC92_RATEMCS0) ? 1 : 0)); if (rtlhal->version == VERSION_8192S_ACUT) { - if (ptcb_desc->hw_rate == DESC92S_RATE1M || - ptcb_desc->hw_rate == DESC92S_RATE2M || - ptcb_desc->hw_rate == DESC92S_RATE5_5M || - ptcb_desc->hw_rate == DESC92S_RATE11M) { - ptcb_desc->hw_rate = DESC92S_RATE12M; + if (ptcb_desc->hw_rate == DESC92_RATE1M || + ptcb_desc->hw_rate == DESC92_RATE2M || + ptcb_desc->hw_rate == DESC92_RATE5_5M || + ptcb_desc->hw_rate == DESC92_RATE11M) { + ptcb_desc->hw_rate = DESC92_RATE12M; } } @@ -759,7 +672,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0); SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc); SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <= - DESC92S_RATE54M) ? + DESC92_RATE54M) ? (ptcb_desc->rts_use_shortpreamble ? 1 : 0) : (ptcb_desc->rts_use_shortgi ? 1 : 0))); diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index 4bf3cf457ef0..b42c2e2b2055 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -191,44 +191,6 @@ static void _usb_write32_async(struct rtl_priv *rtlpriv, u32 addr, u32 val) _usb_write_async(to_usb_device(dev), addr, val, 4); } -static int _usb_nbytes_read_write(struct usb_device *udev, bool read, u32 addr, - u16 len, u8 *pdata) -{ - int status; - u8 request; - u16 wvalue; - u16 index; - - request = REALTEK_USB_VENQT_CMD_REQ; - index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ - wvalue = (u16)addr; - if (read) - status = _usbctrl_vendorreq_sync_read(udev, request, wvalue, - index, pdata, len); - else - status = _usbctrl_vendorreq_async_write(udev, request, wvalue, - index, pdata, len); - return status; -} - -static int _usb_readN_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len, - u8 *pdata) -{ - struct device *dev = rtlpriv->io.dev; - - return _usb_nbytes_read_write(to_usb_device(dev), true, addr, len, - pdata); -} - -static int _usb_writeN_async(struct rtl_priv *rtlpriv, u32 addr, u16 len, - u8 *pdata) -{ - struct device *dev = rtlpriv->io.dev; - - return _usb_nbytes_read_write(to_usb_device(dev), false, addr, len, - pdata); -} - static void _rtl_usb_io_handler_init(struct device *dev, struct ieee80211_hw *hw) { @@ -239,11 +201,9 @@ static void _rtl_usb_io_handler_init(struct device *dev, rtlpriv->io.write8_async = _usb_write8_async; rtlpriv->io.write16_async = _usb_write16_async; rtlpriv->io.write32_async = _usb_write32_async; - rtlpriv->io.writeN_async = _usb_writeN_async; rtlpriv->io.read8_sync = _usb_read8_sync; rtlpriv->io.read16_sync = _usb_read16_sync; rtlpriv->io.read32_sync = _usb_read32_sync; - rtlpriv->io.readN_sync = _usb_readN_sync; } static void _rtl_usb_io_handler_release(struct ieee80211_hw *hw) diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index d3c3ffd38984..713c7ddba8eb 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -165,6 +165,12 @@ enum hardware_type { #define IS_HARDWARE_TYPE_8723U(rtlhal) \ (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U) +#define RX_HAL_IS_CCK_RATE(_pdesc)\ + (_pdesc->rxmcs == DESC92_RATE1M || \ + _pdesc->rxmcs == DESC92_RATE2M || \ + _pdesc->rxmcs == DESC92_RATE5_5M || \ + _pdesc->rxmcs == DESC92_RATE11M) + enum scan_operation_backup_opt { SCAN_OPT_BACKUP = 0, SCAN_OPT_RESTORE, @@ -386,6 +392,41 @@ enum rtl_hal_state { _HAL_STATE_START = 1, }; +enum rtl_desc92_rate { + DESC92_RATE1M = 0x00, + DESC92_RATE2M = 0x01, + DESC92_RATE5_5M = 0x02, + DESC92_RATE11M = 0x03, + + DESC92_RATE6M = 0x04, + DESC92_RATE9M = 0x05, + DESC92_RATE12M = 0x06, + DESC92_RATE18M = 0x07, + DESC92_RATE24M = 0x08, + DESC92_RATE36M = 0x09, + DESC92_RATE48M = 0x0a, + DESC92_RATE54M = 0x0b, + + DESC92_RATEMCS0 = 0x0c, + DESC92_RATEMCS1 = 0x0d, + DESC92_RATEMCS2 = 0x0e, + DESC92_RATEMCS3 = 0x0f, + DESC92_RATEMCS4 = 0x10, + DESC92_RATEMCS5 = 0x11, + DESC92_RATEMCS6 = 0x12, + DESC92_RATEMCS7 = 0x13, + DESC92_RATEMCS8 = 0x14, + DESC92_RATEMCS9 = 0x15, + DESC92_RATEMCS10 = 0x16, + DESC92_RATEMCS11 = 0x17, + DESC92_RATEMCS12 = 0x18, + DESC92_RATEMCS13 = 0x19, + DESC92_RATEMCS14 = 0x1a, + DESC92_RATEMCS15 = 0x1b, + DESC92_RATEMCS15_SG = 0x1c, + DESC92_RATEMCS32 = 0x20, +}; + enum rtl_var_map { /*reg map */ SYS_ISO_CTRL = 0, @@ -409,6 +450,7 @@ enum rtl_var_map { EFUSE_HWSET_MAX_SIZE, EFUSE_MAX_SECTION_MAP, EFUSE_REAL_CONTENT_SIZE, + EFUSE_OOB_PROTECT_BYTES_LEN, /*CAM map */ RWCAM, @@ -901,16 +943,12 @@ struct rtl_io { unsigned long pci_base_addr; /*device I/O address */ void (*write8_async) (struct rtl_priv *rtlpriv, u32 addr, u8 val); - void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, u16 val); - void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, u32 val); - int (*writeN_async) (struct rtl_priv *rtlpriv, u32 addr, u16 len, - u8 *pdata); + void (*write16_async) (struct rtl_priv *rtlpriv, u32 addr, __le16 val); + void (*write32_async) (struct rtl_priv *rtlpriv, u32 addr, __le32 val); u8(*read8_sync) (struct rtl_priv *rtlpriv, u32 addr); u16(*read16_sync) (struct rtl_priv *rtlpriv, u32 addr); u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr); - int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len, - u8 *pdata); }; @@ -1287,6 +1325,7 @@ struct rtl_stats { s8 rx_mimo_signalquality[2]; bool packet_matchbssid; bool is_cck; + bool is_ht; bool packet_toself; bool packet_beacon; /*for rssi */ char cck_adc_pwdb[4]; /*for rx path selection */ @@ -1448,6 +1487,9 @@ struct rtl_mod_params { /* default: 0 = using hardware encryption */ int sw_crypto; + /* default: 0 = DBG_EMERG (0)*/ + int debug; + /* default: 1 = using no linked power save */ bool inactiveps; diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h index 79ca5273c9e9..ee4f2b391822 100644 --- a/drivers/net/wireless/wl1251/cmd.h +++ b/drivers/net/wireless/wl1251/cmd.h @@ -269,7 +269,7 @@ struct cmd_join { u8 bss_type; u8 channel; u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 ctrl; /* JOIN_CMD_CTRL_* */ u8 tx_mgt_frame_rate; /* OBSOLETE */ u8 tx_mgt_frame_mod; /* OBSOLETE */ diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c index a14a48c99cdc..ba3268ea81fe 100644 --- a/drivers/net/wireless/wl1251/main.c +++ b/drivers/net/wireless/wl1251/main.c @@ -1158,7 +1158,8 @@ static struct ieee80211_channel wl1251_channels[] = { { .hw_value = 13, .center_freq = 2472}, }; -static int wl1251_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int wl1251_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { enum wl1251_acx_ps_scheme ps_scheme; diff --git a/drivers/net/wireless/wl1251/wl12xx_80211.h b/drivers/net/wireless/wl1251/wl12xx_80211.h index 1417b1445c3d..04ed51495772 100644 --- a/drivers/net/wireless/wl1251/wl12xx_80211.h +++ b/drivers/net/wireless/wl1251/wl12xx_80211.h @@ -76,7 +76,7 @@ struct wl12xx_ie_header { struct wl12xx_ie_ssid { struct wl12xx_ie_header header; - char ssid[IW_ESSID_MAX_SIZE]; + char ssid[IEEE80211_MAX_SSID_LEN]; } __packed; struct wl12xx_ie_rates { diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig index 07bcb1548d8b..3fe388b87c2e 100644 --- a/drivers/net/wireless/wl12xx/Kconfig +++ b/drivers/net/wireless/wl12xx/Kconfig @@ -19,16 +19,6 @@ config WL12XX If you choose to build a module, it will be called wl12xx. Say N if unsure. -config WL12XX_HT - bool "TI wl12xx 802.11 HT support (EXPERIMENTAL)" - depends on WL12XX && EXPERIMENTAL - default n - ---help--- - This will enable 802.11 HT support in the wl12xx module. - - That configuration is temporary due to the code incomplete and - still in testing process. - config WL12XX_SPI tristate "TI wl12xx SPI support" depends on WL12XX && SPI_MASTER diff --git a/drivers/net/wireless/wl12xx/Makefile b/drivers/net/wireless/wl12xx/Makefile index 521c0414e52e..621b3483ca2c 100644 --- a/drivers/net/wireless/wl12xx/Makefile +++ b/drivers/net/wireless/wl12xx/Makefile @@ -1,16 +1,16 @@ wl12xx-objs = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \ boot.o init.o debugfs.o scan.o -wl12xx_spi-objs = spi.o +wl12xx_spi-objs = spi.o wl12xx_sdio-objs = sdio.o -wl12xx_sdio_test-objs = sdio_test.o +wl12xx_sdio_test-objs = sdio_test.o wl12xx-$(CONFIG_NL80211_TESTMODE) += testmode.o obj-$(CONFIG_WL12XX) += wl12xx.o obj-$(CONFIG_WL12XX_SPI) += wl12xx_spi.o obj-$(CONFIG_WL12XX_SDIO) += wl12xx_sdio.o -obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o +obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o # small builtin driver bit obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx_platform_data.o diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c index 34f6ab53e519..ca044a743191 100644 --- a/drivers/net/wireless/wl12xx/acx.c +++ b/drivers/net/wireless/wl12xx/acx.c @@ -46,6 +46,7 @@ int wl1271_acx_wake_up_conditions(struct wl1271 *wl) goto out; } + wake_up->role_id = wl->role_id; wake_up->wake_up_event = wl->conf.conn.wake_up_event; wake_up->listen_interval = wl->conf.conn.listen_interval; @@ -99,6 +100,7 @@ int wl1271_acx_tx_power(struct wl1271 *wl, int power) goto out; } + acx->role_id = wl->role_id; acx->current_tx_power = power * 10; ret = wl1271_cmd_configure(wl, DOT11_CUR_TX_PWR, acx, sizeof(*acx)); @@ -126,6 +128,7 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl) } /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ + feature->role_id = wl->role_id; feature->data_flow_options = 0; feature->options = 0; @@ -181,34 +184,6 @@ out: return ret; } -int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter) -{ - struct acx_rx_config *rx_config; - int ret; - - wl1271_debug(DEBUG_ACX, "acx rx config"); - - rx_config = kzalloc(sizeof(*rx_config), GFP_KERNEL); - if (!rx_config) { - ret = -ENOMEM; - goto out; - } - - rx_config->config_options = cpu_to_le32(config); - rx_config->filter_options = cpu_to_le32(filter); - - ret = wl1271_cmd_configure(wl, ACX_RX_CFG, - rx_config, sizeof(*rx_config)); - if (ret < 0) { - wl1271_warning("failed to set rx config: %d", ret); - goto out; - } - -out: - kfree(rx_config); - return ret; -} - int wl1271_acx_pd_threshold(struct wl1271 *wl) { struct acx_packet_detection *pd; @@ -248,6 +223,7 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time) goto out; } + slot->role_id = wl->role_id; slot->wone_index = STATION_WONE_INDEX; slot->slot_time = slot_time; @@ -277,6 +253,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, } /* MAC filtering */ + acx->role_id = wl->role_id; acx->enabled = enable; acx->num_groups = mc_list_len; memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); @@ -306,6 +283,7 @@ int wl1271_acx_service_period_timeout(struct wl1271 *wl) wl1271_debug(DEBUG_ACX, "acx service period timeout"); + rx_timeout->role_id = wl->role_id; rx_timeout->ps_poll_timeout = cpu_to_le16(wl->conf.rx.ps_poll_timeout); rx_timeout->upsd_timeout = cpu_to_le16(wl->conf.rx.upsd_timeout); @@ -342,6 +320,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold) goto out; } + rts->role_id = wl->role_id; rts->threshold = cpu_to_le16((u16)rts_threshold); ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts)); @@ -401,6 +380,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) goto out; } + beacon_filter->role_id = wl->role_id; beacon_filter->enable = enable_filter; /* @@ -437,6 +417,7 @@ int wl1271_acx_beacon_filter_table(struct wl1271 *wl) } /* configure default beacon pass-through rules */ + ie_table->role_id = wl->role_id; ie_table->num_ie = 0; for (i = 0; i < wl->conf.conn.bcn_filt_ie_count; i++) { struct conf_bcn_filt_rule *r = &(wl->conf.conn.bcn_filt_ie[i]); @@ -498,6 +479,7 @@ int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable) timeout = wl->conf.conn.bss_lose_timeout; } + acx->role_id = wl->role_id; acx->synch_fail_thold = cpu_to_le32(threshold); acx->bss_lose_timeout = cpu_to_le32(timeout); @@ -544,43 +526,13 @@ out: return ret; } -int wl1271_acx_sta_sg_cfg(struct wl1271 *wl) -{ - struct acx_sta_bt_wlan_coex_param *param; - struct conf_sg_settings *c = &wl->conf.sg; - int i, ret; - - wl1271_debug(DEBUG_ACX, "acx sg sta cfg"); - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) { - ret = -ENOMEM; - goto out; - } - - /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++) - param->params[i] = cpu_to_le32(c->sta_params[i]); - param->param_idx = CONF_SG_PARAMS_ALL; - - ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); - if (ret < 0) { - wl1271_warning("failed to set sg config: %d", ret); - goto out; - } - -out: - kfree(param); - return ret; -} - -int wl1271_acx_ap_sg_cfg(struct wl1271 *wl) +int wl12xx_acx_sg_cfg(struct wl1271 *wl) { - struct acx_ap_bt_wlan_coex_param *param; + struct acx_bt_wlan_coex_param *param; struct conf_sg_settings *c = &wl->conf.sg; int i, ret; - wl1271_debug(DEBUG_ACX, "acx sg ap cfg"); + wl1271_debug(DEBUG_ACX, "acx sg cfg"); param = kzalloc(sizeof(*param), GFP_KERNEL); if (!param) { @@ -589,8 +541,8 @@ int wl1271_acx_ap_sg_cfg(struct wl1271 *wl) } /* BT-WLAN coext parameters */ - for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++) - param->params[i] = cpu_to_le32(c->ap_params[i]); + for (i = 0; i < CONF_SG_PARAMS_MAX; i++) + param->params[i] = cpu_to_le32(c->params[i]); param->param_idx = CONF_SG_PARAMS_ALL; ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param)); @@ -643,6 +595,7 @@ int wl1271_acx_bcn_dtim_options(struct wl1271 *wl) goto out; } + bb->role_id = wl->role_id; bb->beacon_rx_timeout = cpu_to_le16(wl->conf.conn.beacon_rx_timeout); bb->broadcast_timeout = cpu_to_le16(wl->conf.conn.broadcast_timeout); bb->rx_broadcast_in_ps = wl->conf.conn.rx_broadcast_in_ps; @@ -672,6 +625,7 @@ int wl1271_acx_aid(struct wl1271 *wl, u16 aid) goto out; } + acx_aid->role_id = wl->role_id; acx_aid->aid = cpu_to_le16(aid); ret = wl1271_cmd_configure(wl, ACX_AID, acx_aid, sizeof(*acx_aid)); @@ -727,6 +681,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble) goto out; } + acx->role_id = wl->role_id; acx->preamble = preamble; ret = wl1271_cmd_configure(wl, ACX_PREAMBLE_TYPE, acx, sizeof(*acx)); @@ -754,6 +709,7 @@ int wl1271_acx_cts_protect(struct wl1271 *wl, goto out; } + acx->role_id = wl->role_id; acx->ctsprotect = ctsprotect; ret = wl1271_cmd_configure(wl, ACX_CTS_PROTECTION, acx, sizeof(*acx)); @@ -785,9 +741,8 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) int wl1271_acx_sta_rate_policies(struct wl1271 *wl) { - struct acx_sta_rate_policy *acx; + struct acx_rate_policy *acx; struct conf_tx_rate_class *c = &wl->conf.tx.sta_rc_conf; - int idx = 0; int ret = 0; wl1271_debug(DEBUG_ACX, "acx rate policies"); @@ -799,25 +754,46 @@ int wl1271_acx_sta_rate_policies(struct wl1271 *wl) goto out; } + wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", + wl->basic_rate, wl->rate_set); + /* configure one basic rate class */ - idx = ACX_TX_BASIC_RATE; - acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate); - acx->rate_class[idx].short_retry_limit = c->short_retry_limit; - acx->rate_class[idx].long_retry_limit = c->long_retry_limit; - acx->rate_class[idx].aflags = c->aflags; + acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE); + acx->rate_policy.enabled_rates = cpu_to_le32(wl->basic_rate); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; + + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of rate policies failed: %d", ret); + goto out; + } /* configure one AP supported rate class */ - idx = ACX_TX_AP_FULL_RATE; - acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set); - acx->rate_class[idx].short_retry_limit = c->short_retry_limit; - acx->rate_class[idx].long_retry_limit = c->long_retry_limit; - acx->rate_class[idx].aflags = c->aflags; + acx->rate_policy_idx = cpu_to_le32(ACX_TX_AP_FULL_RATE); + acx->rate_policy.enabled_rates = cpu_to_le32(wl->rate_set); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; - acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); + ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("Setting of rate policies failed: %d", ret); + goto out; + } - wl1271_debug(DEBUG_ACX, "basic_rate: 0x%x, full_rate: 0x%x", - acx->rate_class[ACX_TX_BASIC_RATE].enabled_rates, - acx->rate_class[ACX_TX_AP_FULL_RATE].enabled_rates); + /* + * configure one rate class for basic p2p operations. + * (p2p packets should always go out with OFDM rates, even + * if we are currently connected to 11b AP) + */ + acx->rate_policy_idx = cpu_to_le32(ACX_TX_BASIC_RATE_P2P); + acx->rate_policy.enabled_rates = + cpu_to_le32(CONF_TX_RATE_MASK_BASIC_P2P); + acx->rate_policy.short_retry_limit = c->short_retry_limit; + acx->rate_policy.long_retry_limit = c->long_retry_limit; + acx->rate_policy.aflags = c->aflags; ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { @@ -833,7 +809,7 @@ out: int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c, u8 idx) { - struct acx_ap_rate_policy *acx; + struct acx_rate_policy *acx; int ret = 0; wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x", @@ -879,6 +855,7 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max, goto out; } + acx->role_id = wl->role_id; acx->ac = ac; acx->cw_min = cw_min; acx->cw_max = cpu_to_le16(cw_max); @@ -912,6 +889,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, goto out; } + acx->role_id = wl->role_id; acx->queue_id = queue_id; acx->channel_type = channel_type; acx->tsid = tsid; @@ -991,52 +969,9 @@ out: return ret; } -int wl1271_acx_ap_mem_cfg(struct wl1271 *wl) +int wl12xx_acx_mem_cfg(struct wl1271 *wl) { - struct wl1271_acx_ap_config_memory *mem_conf; - struct conf_memory_settings *mem; - int ret; - - wl1271_debug(DEBUG_ACX, "wl1271 mem cfg"); - - mem_conf = kzalloc(sizeof(*mem_conf), GFP_KERNEL); - if (!mem_conf) { - ret = -ENOMEM; - goto out; - } - - if (wl->chip.id == CHIP_ID_1283_PG20) - /* - * FIXME: The 128x AP FW does not yet support dynamic memory. - * Use the base memory configuration for 128x for now. This - * should be fine tuned in the future. - */ - mem = &wl->conf.mem_wl128x; - else - mem = &wl->conf.mem_wl127x; - - /* memory config */ - mem_conf->num_stations = mem->num_stations; - mem_conf->rx_mem_block_num = mem->rx_block_num; - mem_conf->tx_min_mem_block_num = mem->tx_min_block_num; - mem_conf->num_ssid_profiles = mem->ssid_profiles; - mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS); - - ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf, - sizeof(*mem_conf)); - if (ret < 0) { - wl1271_warning("wl1271 mem config failed: %d", ret); - goto out; - } - -out: - kfree(mem_conf); - return ret; -} - -int wl1271_acx_sta_mem_cfg(struct wl1271 *wl) -{ - struct wl1271_acx_sta_config_memory *mem_conf; + struct wl12xx_acx_config_memory *mem_conf; struct conf_memory_settings *mem; int ret; @@ -1179,6 +1114,7 @@ int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) goto out; } + acx->role_id = wl->role_id; acx->enable = enable ? CONF_BET_MODE_ENABLE : CONF_BET_MODE_DISABLE; acx->max_consecutive = wl->conf.conn.bet_max_consecutive; @@ -1206,6 +1142,7 @@ int wl1271_acx_arp_ip_filter(struct wl1271 *wl, u8 enable, __be32 address) goto out; } + acx->role_id = wl->role_id; acx->version = ACX_IPV4_VERSION; acx->enable = enable; @@ -1265,6 +1202,7 @@ int wl1271_acx_keep_alive_mode(struct wl1271 *wl, bool enable) goto out; } + acx->role_id = wl->role_id; acx->enabled = enable; ret = wl1271_cmd_configure(wl, ACX_KEEP_ALIVE_MODE, acx, sizeof(*acx)); @@ -1291,6 +1229,7 @@ int wl1271_acx_keep_alive_config(struct wl1271 *wl, u8 index, u8 tpl_valid) goto out; } + acx->role_id = wl->role_id; acx->period = cpu_to_le32(wl->conf.conn.keep_alive_interval); acx->index = index; acx->tpl_validation = tpl_valid; @@ -1324,6 +1263,7 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, wl->last_rssi_event = -1; + acx->role_id = wl->role_id; acx->pacing = cpu_to_le16(wl->conf.roam_trigger.trigger_pacing); acx->metric = WL1271_ACX_TRIG_METRIC_RSSI_BEACON; acx->type = WL1271_ACX_TRIG_TYPE_EDGE; @@ -1362,6 +1302,7 @@ int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl) goto out; } + acx->role_id = wl->role_id; acx->rssi_beacon = c->avg_weight_rssi_beacon; acx->rssi_data = c->avg_weight_rssi_data; acx->snr_beacon = c->avg_weight_snr_beacon; @@ -1380,14 +1321,15 @@ out: int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation) + bool allow_ht_operation, u8 hlid) { struct wl1271_acx_ht_capabilities *acx; - u8 mac_address[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; int ret = 0; u32 ht_capabilites = 0; - wl1271_debug(DEBUG_ACX, "acx ht capabilities setting"); + wl1271_debug(DEBUG_ACX, "acx ht capabilities setting " + "sta supp: %d sta cap: %d", ht_cap->ht_supported, + ht_cap->cap); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -1395,26 +1337,22 @@ int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, goto out; } - /* Allow HT Operation ? */ - if (allow_ht_operation) { - ht_capabilites = - WL1271_ACX_FW_CAP_HT_OPERATION; - if (ht_cap->cap & IEEE80211_HT_CAP_GRN_FLD) - ht_capabilites |= - WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT; - if (ht_cap->cap & IEEE80211_HT_CAP_SGI_20) - ht_capabilites |= - WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS; - if (ht_cap->cap & IEEE80211_HT_CAP_LSIG_TXOP_PROT) - ht_capabilites |= - WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION; + if (allow_ht_operation && ht_cap->ht_supported) { + /* no need to translate capabilities - use the spec values */ + ht_capabilites = ht_cap->cap; + + /* + * this bit is not employed by the spec but only by FW to + * indicate peer HT support + */ + ht_capabilites |= WL12XX_HT_CAP_HT_OPERATION; /* get data from A-MPDU parameters field */ acx->ampdu_max_length = ht_cap->ampdu_factor; acx->ampdu_min_spacing = ht_cap->ampdu_density; } - memcpy(acx->mac_address, mac_address, ETH_ALEN); + acx->hlid = hlid; acx->ht_capabilites = cpu_to_le32(ht_capabilites); ret = wl1271_cmd_configure(wl, ACX_PEER_HT_CAP, acx, sizeof(*acx)); @@ -1442,6 +1380,7 @@ int wl1271_acx_set_ht_information(struct wl1271 *wl, goto out; } + acx->role_id = wl->role_id; acx->ht_protection = (u8)(ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION); acx->rifs_mode = 0; @@ -1463,14 +1402,12 @@ out: } /* Configure BA session initiator/receiver parameters setting in the FW. */ -int wl1271_acx_set_ba_session(struct wl1271 *wl, - enum ieee80211_back_parties direction, - u8 tid_index, u8 policy) +int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl) { - struct wl1271_acx_ba_session_policy *acx; + struct wl1271_acx_ba_initiator_policy *acx; int ret; - wl1271_debug(DEBUG_ACX, "acx ba session setting"); + wl1271_debug(DEBUG_ACX, "acx ba initiator policy"); acx = kzalloc(sizeof(*acx), GFP_KERNEL); if (!acx) { @@ -1478,33 +1415,18 @@ int wl1271_acx_set_ba_session(struct wl1271 *wl, goto out; } - /* ANY role */ - acx->role_id = 0xff; - acx->tid = tid_index; - acx->enable = policy; - acx->ba_direction = direction; - - switch (direction) { - case WLAN_BACK_INITIATOR: - acx->win_size = wl->conf.ht.tx_ba_win_size; - acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; - break; - case WLAN_BACK_RECIPIENT: - acx->win_size = RX_BA_WIN_SIZE; - acx->inactivity_timeout = 0; - break; - default: - wl1271_error("Incorrect acx command id=%x\n", direction); - ret = -EINVAL; - goto out; - } + /* set for the current role */ + acx->role_id = wl->role_id; + acx->tid_bitmap = wl->conf.ht.tx_ba_tid_bitmap; + acx->win_size = wl->conf.ht.tx_ba_win_size; + acx->inactivity_timeout = wl->conf.ht.inactivity_timeout; ret = wl1271_cmd_configure(wl, - ACX_BA_SESSION_POLICY_CFG, + ACX_BA_SESSION_INIT_POLICY, acx, sizeof(*acx)); if (ret < 0) { - wl1271_warning("acx ba session setting failed: %d", ret); + wl1271_warning("acx ba initiator policy failed: %d", ret); goto out; } @@ -1514,8 +1436,8 @@ out: } /* setup BA session receiver setting in the FW. */ -int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, - bool enable) +int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, + u16 ssn, bool enable, u8 peer_hlid) { struct wl1271_acx_ba_receiver_setup *acx; int ret; @@ -1528,11 +1450,10 @@ int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, goto out; } - /* Single link for now */ - acx->link_id = 1; + acx->hlid = peer_hlid; acx->tid = tid_index; acx->enable = enable; - acx->win_size = 0; + acx->win_size = wl->conf.ht.rx_ba_win_size; acx->ssn = ssn; ret = wl1271_cmd_configure(wl, ACX_BA_SESSION_RX_SETUP, acx, @@ -1602,6 +1523,7 @@ int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable) if (!(conf_queues & BIT(i))) continue; + rx_streaming->role_id = wl->role_id; rx_streaming->tid = i; rx_streaming->enable = enable_queues & BIT(i); rx_streaming->period = wl->conf.rx_streaming.interval; @@ -1631,6 +1553,7 @@ int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl) if (!acx) return -ENOMEM; + acx->role_id = wl->role_id; acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries); ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx)); @@ -1699,31 +1622,6 @@ out: return ret; } -int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable) -{ - struct acx_ap_beacon_filter *acx = NULL; - int ret; - - wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) - return -ENOMEM; - - acx->enable = enable ? 1 : 0; - - ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT, - acx, sizeof(*acx)); - if (ret < 0) { - wl1271_warning("acx set ap beacon filter failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - int wl1271_acx_fm_coex(struct wl1271 *wl) { struct wl1271_acx_fm_coex *acx; @@ -1763,3 +1661,85 @@ out: kfree(acx); return ret; } + +int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl) +{ + struct wl12xx_acx_set_rate_mgmt_params *acx = NULL; + struct conf_rate_policy_settings *conf = &wl->conf.rate; + int ret; + + wl1271_debug(DEBUG_ACX, "acx set rate mgmt params"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->index = ACX_RATE_MGMT_ALL_PARAMS; + acx->rate_retry_score = cpu_to_le16(conf->rate_retry_score); + acx->per_add = cpu_to_le16(conf->per_add); + acx->per_th1 = cpu_to_le16(conf->per_th1); + acx->per_th2 = cpu_to_le16(conf->per_th2); + acx->max_per = cpu_to_le16(conf->max_per); + acx->inverse_curiosity_factor = conf->inverse_curiosity_factor; + acx->tx_fail_low_th = conf->tx_fail_low_th; + acx->tx_fail_high_th = conf->tx_fail_high_th; + acx->per_alpha_shift = conf->per_alpha_shift; + acx->per_add_shift = conf->per_add_shift; + acx->per_beta1_shift = conf->per_beta1_shift; + acx->per_beta2_shift = conf->per_beta2_shift; + acx->rate_check_up = conf->rate_check_up; + acx->rate_check_down = conf->rate_check_down; + memcpy(acx->rate_retry_policy, conf->rate_retry_policy, + sizeof(acx->rate_retry_policy)); + + ret = wl1271_cmd_configure(wl, ACX_SET_RATE_MGMT_PARAMS, + acx, sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx set rate mgmt params failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +int wl12xx_acx_config_hangover(struct wl1271 *wl) +{ + struct wl12xx_acx_config_hangover *acx; + struct conf_hangover_settings *conf = &wl->conf.hangover; + int ret; + + wl1271_debug(DEBUG_ACX, "acx config hangover"); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) { + ret = -ENOMEM; + goto out; + } + + acx->recover_time = cpu_to_le32(conf->recover_time); + acx->hangover_period = conf->hangover_period; + acx->dynamic_mode = conf->dynamic_mode; + acx->early_termination_mode = conf->early_termination_mode; + acx->max_period = conf->max_period; + acx->min_period = conf->min_period; + acx->increase_delta = conf->increase_delta; + acx->decrease_delta = conf->decrease_delta; + acx->quiet_time = conf->quiet_time; + acx->increase_time = conf->increase_time; + acx->window_size = acx->window_size; + + ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx, + sizeof(*acx)); + + if (ret < 0) { + wl1271_warning("acx config hangover failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; + +} diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h index d2eb86eccc04..e3f93b4b3429 100644 --- a/drivers/net/wireless/wl12xx/acx.h +++ b/drivers/net/wireless/wl12xx/acx.h @@ -101,6 +101,17 @@ struct acx_error_counter { __le32 seq_num_miss; } __packed; +enum wl12xx_role { + WL1271_ROLE_STA = 0, + WL1271_ROLE_IBSS, + WL1271_ROLE_AP, + WL1271_ROLE_DEVICE, + WL1271_ROLE_P2P_CL, + WL1271_ROLE_P2P_GO, + + WL12XX_INVALID_ROLE_TYPE = 0xff +}; + enum wl1271_psm_mode { /* Active mode */ WL1271_PSM_CAM = 0, @@ -160,94 +171,6 @@ struct acx_rx_msdu_lifetime { __le32 lifetime; } __packed; -/* - * RX Config Options Table - * Bit Definition - * === ========== - * 31:14 Reserved - * 13 Copy RX Status - when set, write three receive status words - * to top of rx'd MPDUs. - * When cleared, do not write three status words (added rev 1.5) - * 12 Reserved - * 11 RX Complete upon FCS error - when set, give rx complete - * interrupt for FCS errors, after the rx filtering, e.g. unicast - * frames not to us with FCS error will not generate an interrupt. - * 10 SSID Filter Enable - When set, the WiLink discards all beacon, - * probe request, and probe response frames with an SSID that does - * not match the SSID specified by the host in the START/JOIN - * command. - * When clear, the WiLink receives frames with any SSID. - * 9 Broadcast Filter Enable - When set, the WiLink discards all - * broadcast frames. When clear, the WiLink receives all received - * broadcast frames. - * 8:6 Reserved - * 5 BSSID Filter Enable - When set, the WiLink discards any frames - * with a BSSID that does not match the BSSID specified by the - * host. - * When clear, the WiLink receives frames from any BSSID. - * 4 MAC Addr Filter - When set, the WiLink discards any frames - * with a destination address that does not match the MAC address - * of the adaptor. - * When clear, the WiLink receives frames destined to any MAC - * address. - * 3 Promiscuous - When set, the WiLink receives all valid frames - * (i.e., all frames that pass the FCS check). - * When clear, only frames that pass the other filters specified - * are received. - * 2 FCS - When set, the WiLink includes the FCS with the received - * frame. - * When cleared, the FCS is discarded. - * 1 PLCP header - When set, write all data from baseband to frame - * buffer including PHY header. - * 0 Reserved - Always equal to 0. - * - * RX Filter Options Table - * Bit Definition - * === ========== - * 31:12 Reserved - Always equal to 0. - * 11 Association - When set, the WiLink receives all association - * related frames (association request/response, reassocation - * request/response, and disassociation). When clear, these frames - * are discarded. - * 10 Auth/De auth - When set, the WiLink receives all authentication - * and de-authentication frames. When clear, these frames are - * discarded. - * 9 Beacon - When set, the WiLink receives all beacon frames. - * When clear, these frames are discarded. - * 8 Contention Free - When set, the WiLink receives all contention - * free frames. - * When clear, these frames are discarded. - * 7 Control - When set, the WiLink receives all control frames. - * When clear, these frames are discarded. - * 6 Data - When set, the WiLink receives all data frames. - * When clear, these frames are discarded. - * 5 FCS Error - When set, the WiLink receives frames that have FCS - * errors. - * When clear, these frames are discarded. - * 4 Management - When set, the WiLink receives all management - * frames. - * When clear, these frames are discarded. - * 3 Probe Request - When set, the WiLink receives all probe request - * frames. - * When clear, these frames are discarded. - * 2 Probe Response - When set, the WiLink receives all probe - * response frames. - * When clear, these frames are discarded. - * 1 RTS/CTS/ACK - When set, the WiLink receives all RTS, CTS and ACK - * frames. - * When clear, these frames are discarded. - * 0 Rsvd Type/Sub Type - When set, the WiLink receives all frames - * that have reserved frame types and sub types as defined by the - * 802.11 specification. - * When clear, these frames are discarded. - */ -struct acx_rx_config { - struct acx_header header; - - __le32 config_options; - __le32 filter_options; -} __packed; - struct acx_packet_detection { struct acx_header header; @@ -267,9 +190,10 @@ enum acx_slot_type { struct acx_slot { struct acx_header header; + u8 role_id; u8 wone_index; /* Reserved */ u8 slot_time; - u8 reserved[6]; + u8 reserved[5]; } __packed; @@ -279,29 +203,35 @@ struct acx_slot { struct acx_dot11_grp_addr_tbl { struct acx_header header; + u8 role_id; u8 enabled; u8 num_groups; - u8 pad[2]; + u8 pad[1]; u8 mac_table[ADDRESS_GROUP_MAX_LEN]; } __packed; struct acx_rx_timeout { struct acx_header header; + u8 role_id; + u8 reserved; __le16 ps_poll_timeout; __le16 upsd_timeout; + u8 padding[2]; } __packed; struct acx_rts_threshold { struct acx_header header; + u8 role_id; + u8 reserved; __le16 threshold; - u8 pad[2]; } __packed; struct acx_beacon_filter_option { struct acx_header header; + u8 role_id; u8 enable; /* * The number of beacons without the unicast TIM @@ -311,7 +241,7 @@ struct acx_beacon_filter_option { * without the unicast TIM bit set are dropped. */ u8 max_num_beacons; - u8 pad[2]; + u8 pad[1]; } __packed; /* @@ -350,14 +280,17 @@ struct acx_beacon_filter_option { struct acx_beacon_filter_ie_table { struct acx_header header; + u8 role_id; u8 num_ie; - u8 pad[3]; + u8 pad[2]; u8 table[BEACON_FILTER_TABLE_MAX_SIZE]; } __packed; struct acx_conn_monit_params { struct acx_header header; + u8 role_id; + u8 padding[3]; __le32 synch_fail_thold; /* number of beacons missed */ __le32 bss_lose_timeout; /* number of TU's from synch fail */ } __packed; @@ -369,23 +302,14 @@ struct acx_bt_wlan_coex { u8 pad[3]; } __packed; -struct acx_sta_bt_wlan_coex_param { - struct acx_header header; - - __le32 params[CONF_SG_STA_PARAMS_MAX]; - u8 param_idx; - u8 padding[3]; -} __packed; - -struct acx_ap_bt_wlan_coex_param { +struct acx_bt_wlan_coex_param { struct acx_header header; - __le32 params[CONF_SG_AP_PARAMS_MAX]; + __le32 params[CONF_SG_PARAMS_MAX]; u8 param_idx; u8 padding[3]; } __packed; - struct acx_dco_itrim_params { struct acx_header header; @@ -406,15 +330,16 @@ struct acx_energy_detection { struct acx_beacon_broadcast { struct acx_header header; - __le16 beacon_rx_timeout; - __le16 broadcast_timeout; - + u8 role_id; /* Enables receiving of broadcast packets in PS mode */ u8 rx_broadcast_in_ps; + __le16 beacon_rx_timeout; + __le16 broadcast_timeout; + /* Consecutive PS Poll failures before updating the host */ u8 ps_poll_threshold; - u8 pad[2]; + u8 pad[1]; } __packed; struct acx_event_mask { @@ -424,35 +349,6 @@ struct acx_event_mask { __le32 high_event_mask; /* Unused */ } __packed; -#define CFG_RX_FCS BIT(2) -#define CFG_RX_ALL_GOOD BIT(3) -#define CFG_UNI_FILTER_EN BIT(4) -#define CFG_BSSID_FILTER_EN BIT(5) -#define CFG_MC_FILTER_EN BIT(6) -#define CFG_MC_ADDR0_EN BIT(7) -#define CFG_MC_ADDR1_EN BIT(8) -#define CFG_BC_REJECT_EN BIT(9) -#define CFG_SSID_FILTER_EN BIT(10) -#define CFG_RX_INT_FCS_ERROR BIT(11) -#define CFG_RX_INT_ENCRYPTED BIT(12) -#define CFG_RX_WR_RX_STATUS BIT(13) -#define CFG_RX_FILTER_NULTI BIT(14) -#define CFG_RX_RESERVE BIT(15) -#define CFG_RX_TIMESTAMP_TSF BIT(16) - -#define CFG_RX_RSV_EN BIT(0) -#define CFG_RX_RCTS_ACK BIT(1) -#define CFG_RX_PRSP_EN BIT(2) -#define CFG_RX_PREQ_EN BIT(3) -#define CFG_RX_MGMT_EN BIT(4) -#define CFG_RX_FCS_ERROR BIT(5) -#define CFG_RX_DATA_EN BIT(6) -#define CFG_RX_CTL_EN BIT(7) -#define CFG_RX_CF_EN BIT(8) -#define CFG_RX_BCN_EN BIT(9) -#define CFG_RX_AUTH_EN BIT(10) -#define CFG_RX_ASSOC_EN BIT(11) - #define SCAN_PASSIVE BIT(0) #define SCAN_5GHZ_BAND BIT(1) #define SCAN_TRIGGERED BIT(2) @@ -465,6 +361,8 @@ struct acx_event_mask { struct acx_feature_config { struct acx_header header; + u8 role_id; + u8 padding[3]; __le32 options; __le32 data_flow_options; } __packed; @@ -472,16 +370,18 @@ struct acx_feature_config { struct acx_current_tx_power { struct acx_header header; + u8 role_id; u8 current_tx_power; - u8 padding[3]; + u8 padding[2]; } __packed; struct acx_wake_up_condition { struct acx_header header; + u8 role_id; u8 wake_up_event; /* Only one bit can be set */ u8 listen_interval; - u8 pad[2]; + u8 pad[1]; } __packed; struct acx_aid { @@ -490,8 +390,9 @@ struct acx_aid { /* * To be set when associated with an AP. */ + u8 role_id; + u8 reserved; __le16 aid; - u8 pad[2]; } __packed; enum acx_preamble_type { @@ -506,8 +407,9 @@ struct acx_preamble { * When set, the WiLink transmits the frames with a short preamble and * when cleared, the WiLink transmits the frames with a long preamble. */ + u8 role_id; u8 preamble; - u8 padding[3]; + u8 padding[2]; } __packed; enum acx_ctsprotect_type { @@ -517,8 +419,9 @@ enum acx_ctsprotect_type { struct acx_ctsprotect { struct acx_header header; + u8 role_id; u8 ctsprotect; - u8 padding[3]; + u8 padding[2]; } __packed; struct acx_tx_statistics { @@ -753,18 +656,10 @@ struct acx_rate_class { #define ACX_TX_BASIC_RATE 0 #define ACX_TX_AP_FULL_RATE 1 -#define ACX_TX_RATE_POLICY_CNT 2 -struct acx_sta_rate_policy { - struct acx_header header; - - __le32 rate_class_cnt; - struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES]; -} __packed; - - +#define ACX_TX_BASIC_RATE_P2P 2 #define ACX_TX_AP_MODE_MGMT_RATE 4 #define ACX_TX_AP_MODE_BCST_RATE 5 -struct acx_ap_rate_policy { +struct acx_rate_policy { struct acx_header header; __le32 rate_policy_idx; @@ -773,22 +668,23 @@ struct acx_ap_rate_policy { struct acx_ac_cfg { struct acx_header header; + u8 role_id; u8 ac; + u8 aifsn; u8 cw_min; __le16 cw_max; - u8 aifsn; - u8 reserved; __le16 tx_op_limit; } __packed; struct acx_tid_config { struct acx_header header; + u8 role_id; u8 queue_id; u8 channel_type; u8 tsid; u8 ps_scheme; u8 ack_policy; - u8 padding[3]; + u8 padding[2]; __le32 apsd_conf[2]; } __packed; @@ -804,19 +700,7 @@ struct acx_tx_config_options { __le16 tx_compl_threshold; /* number of packets */ } __packed; -#define ACX_TX_DESCRIPTORS 32 - -struct wl1271_acx_ap_config_memory { - struct acx_header header; - - u8 rx_mem_block_num; - u8 tx_min_mem_block_num; - u8 num_stations; - u8 num_ssid_profiles; - __le32 total_tx_descriptors; -} __packed; - -struct wl1271_acx_sta_config_memory { +struct wl12xx_acx_config_memory { struct acx_header header; u8 rx_mem_block_num; @@ -890,9 +774,10 @@ struct wl1271_acx_rx_config_opt { struct wl1271_acx_bet_enable { struct acx_header header; + u8 role_id; u8 enable; u8 max_consecutive; - u8 padding[2]; + u8 padding[1]; } __packed; #define ACX_IPV4_VERSION 4 @@ -905,9 +790,10 @@ struct wl1271_acx_bet_enable { struct wl1271_acx_arp_filter { struct acx_header header; + u8 role_id; u8 version; /* ACX_IPV4_VERSION, ACX_IPV6_VERSION */ u8 enable; /* bitmap of enabled ARP filtering features */ - u8 padding[2]; + u8 padding[1]; u8 address[16]; /* The configured device IP address - all ARP requests directed to this IP address will pass through. For IPv4, the first four bytes are @@ -925,8 +811,9 @@ struct wl1271_acx_pm_config { struct wl1271_acx_keep_alive_mode { struct acx_header header; + u8 role_id; u8 enabled; - u8 padding[3]; + u8 padding[2]; } __packed; enum { @@ -942,11 +829,11 @@ enum { struct wl1271_acx_keep_alive_config { struct acx_header header; - __le32 period; + u8 role_id; u8 index; u8 tpl_validation; u8 trigger; - u8 padding; + __le32 period; } __packed; #define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0) @@ -990,26 +877,33 @@ enum { struct wl1271_acx_rssi_snr_trigger { struct acx_header header; - __le16 threshold; - __le16 pacing; /* 0 - 60000 ms */ + u8 role_id; u8 metric; u8 type; u8 dir; + __le16 threshold; + __le16 pacing; /* 0 - 60000 ms */ u8 hysteresis; u8 index; u8 enable; - u8 padding[2]; + u8 padding[1]; }; struct wl1271_acx_rssi_snr_avg_weights { struct acx_header header; + u8 role_id; + u8 padding[3]; u8 rssi_beacon; u8 rssi_data; u8 snr_beacon; u8 snr_data; }; + +/* special capability bit (not employed by the 802.11n spec) */ +#define WL12XX_HT_CAP_HT_OPERATION BIT(16) + /* * ACX_PEER_HT_CAP * Configure HT capabilities - declare the capabilities of the peer @@ -1018,28 +912,11 @@ struct wl1271_acx_rssi_snr_avg_weights { struct wl1271_acx_ht_capabilities { struct acx_header header; - /* - * bit 0 - Allow HT Operation - * bit 1 - Allow Greenfield format in TX - * bit 2 - Allow Short GI in TX - * bit 3 - Allow L-SIG TXOP Protection in TX - * bit 4 - Allow HT Control fields in TX. - * Note, driver will still leave space for HT control in packets - * regardless of the value of this field. FW will be responsible - * to drop the HT field from any frame when this Bit set to 0. - * bit 5 - Allow RD initiation in TXOP. FW is allowed to initate RD. - * Exact policy setting for this feature is TBD. - * Note, this bit can only be set to 1 if bit 3 is set to 1. - */ + /* bitmask of capability bits supported by the peer */ __le32 ht_capabilites; - /* - * Indicates to which peer these capabilities apply. - * For infrastructure use ff:ff:ff:ff:ff:ff that indicates relevance - * for all peers. - * Only valid for IBSS/DLS operation. - */ - u8 mac_address[ETH_ALEN]; + /* Indicates to which link these capabilities apply. */ + u8 hlid; /* * This the maximum A-MPDU length supported by the AP. The FW may not @@ -1049,16 +926,9 @@ struct wl1271_acx_ht_capabilities { /* This is the minimal spacing required when sending A-MPDUs to the AP*/ u8 ampdu_min_spacing; -} __packed; - -/* HT Capabilites Fw Bit Mask Mapping */ -#define WL1271_ACX_FW_CAP_HT_OPERATION BIT(0) -#define WL1271_ACX_FW_CAP_GREENFIELD_FRAME_FORMAT BIT(1) -#define WL1271_ACX_FW_CAP_SHORT_GI_FOR_20MHZ_PACKETS BIT(2) -#define WL1271_ACX_FW_CAP_LSIG_TXOP_PROTECTION BIT(3) -#define WL1271_ACX_FW_CAP_HT_CONTROL_FIELDS BIT(4) -#define WL1271_ACX_FW_CAP_RD_INITIATION BIT(5) + u8 padding; +} __packed; /* * ACX_HT_BSS_OPERATION @@ -1067,6 +937,8 @@ struct wl1271_acx_ht_capabilities { struct wl1271_acx_ht_information { struct acx_header header; + u8 role_id; + /* Values: 0 - RIFS not allowed, 1 - RIFS allowed */ u8 rifs_mode; @@ -1088,60 +960,51 @@ struct wl1271_acx_ht_information { */ u8 dual_cts_protection; - u8 padding[3]; + u8 padding[2]; } __packed; -#define RX_BA_WIN_SIZE 8 +#define RX_BA_MAX_SESSIONS 2 -struct wl1271_acx_ba_session_policy { +struct wl1271_acx_ba_initiator_policy { struct acx_header header; - /* - * Specifies role Id, Range 0-7, 0xFF means ANY role. - * Future use. For now this field is irrelevant - */ + + /* Specifies role Id, Range 0-7, 0xFF means ANY role. */ u8 role_id; + /* - * Specifies Link Id, Range 0-31, 0xFF means ANY Link Id. - * Not applicable if Role Id is set to ANY. + * Per TID setting for allowing TX BA. Set a bit to 1 to allow + * TX BA sessions for the corresponding TID. */ - u8 link_id; - - u8 tid; - - u8 enable; + u8 tid_bitmap; /* Windows size in number of packets */ - u16 win_size; + u8 win_size; - /* - * As initiator inactivity timeout in time units(TU) of 1024us. - * As receiver reserved - */ - u16 inactivity_timeout; + u8 padding1[1]; - /* Initiator = 1/Receiver = 0 */ - u8 ba_direction; + /* As initiator inactivity timeout in time units(TU) of 1024us */ + u16 inactivity_timeout; - u8 padding[3]; + u8 padding[2]; } __packed; struct wl1271_acx_ba_receiver_setup { struct acx_header header; - /* Specifies Link Id, Range 0-31, 0xFF means ANY Link Id */ - u8 link_id; + /* Specifies link id, range 0-31 */ + u8 hlid; u8 tid; u8 enable; - u8 padding[1]; - /* Windows size in number of packets */ - u16 win_size; + u8 win_size; /* BA session starting sequence number. RANGE 0-FFF */ u16 ssn; + + u8 padding[2]; } __packed; struct wl1271_acx_fw_tsf_information { @@ -1158,6 +1021,7 @@ struct wl1271_acx_fw_tsf_information { struct wl1271_acx_ps_rx_streaming { struct acx_header header; + u8 role_id; u8 tid; u8 enable; @@ -1166,17 +1030,20 @@ struct wl1271_acx_ps_rx_streaming { /* timeout before first trigger (0-200 msec) */ u8 timeout; + u8 padding[3]; } __packed; struct wl1271_acx_ap_max_tx_retry { struct acx_header header; + u8 role_id; + u8 padding_1; + /* * the number of frames transmission failures before * issuing the aging event. */ __le16 max_tx_retry; - u8 padding_1[2]; } __packed; struct wl1271_acx_config_ps { @@ -1195,13 +1062,6 @@ struct wl1271_acx_inconnection_sta { u8 padding1[2]; } __packed; -struct acx_ap_beacon_filter { - struct acx_header header; - - u8 enable; - u8 pad[3]; -} __packed; - /* * ACX_FM_COEX_CFG * set the FM co-existence parameters. @@ -1261,6 +1121,47 @@ struct wl1271_acx_fm_coex { u8 swallow_clk_diff; } __packed; +#define ACX_RATE_MGMT_ALL_PARAMS 0xff +struct wl12xx_acx_set_rate_mgmt_params { + struct acx_header header; + + u8 index; /* 0xff to configure all params */ + u8 padding1; + __le16 rate_retry_score; + __le16 per_add; + __le16 per_th1; + __le16 per_th2; + __le16 max_per; + u8 inverse_curiosity_factor; + u8 tx_fail_low_th; + u8 tx_fail_high_th; + u8 per_alpha_shift; + u8 per_add_shift; + u8 per_beta1_shift; + u8 per_beta2_shift; + u8 rate_check_up; + u8 rate_check_down; + u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; + u8 padding2[2]; +} __packed; + +struct wl12xx_acx_config_hangover { + struct acx_header header; + + __le32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; + u8 padding[2]; +} __packed; + enum { ACX_WAKE_UP_CONDITIONS = 0x0002, ACX_MEM_CFG = 0x0003, @@ -1268,10 +1169,7 @@ enum { ACX_AC_CFG = 0x0007, ACX_MEM_MAP = 0x0008, ACX_AID = 0x000A, - /* ACX_FW_REV is missing in the ref driver, but seems to work */ - ACX_FW_REV = 0x000D, ACX_MEDIUM_USAGE = 0x000F, - ACX_RX_CFG = 0x0010, ACX_TX_QUEUE_CFG = 0x0011, /* FIXME: only used by wl1251 */ ACX_STATISTICS = 0x0013, /* Debug API */ ACX_PWR_CONSUMPTION_STATISTICS = 0x0014, @@ -1279,7 +1177,6 @@ enum { ACX_TID_CFG = 0x001A, ACX_PS_RX_STREAMING = 0x001B, ACX_BEACON_FILTER_OPT = 0x001F, - ACX_AP_BEACON_FILTER_OPT = 0x0020, ACX_NOISE_HIST = 0x0021, ACX_HDK_VERSION = 0x0022, /* ??? */ ACX_PD_THRESHOLD = 0x0023, @@ -1287,7 +1184,6 @@ enum { ACX_CCA_THRESHOLD = 0x0025, ACX_EVENT_MBOX_MASK = 0x0026, ACX_CONN_MONIT_PARAMS = 0x002D, - ACX_CONS_TX_FAILURE = 0x002F, ACX_BCN_DTIM_OPTIONS = 0x0031, ACX_SG_ENABLE = 0x0032, ACX_SG_CFG = 0x0033, @@ -1314,11 +1210,14 @@ enum { ACX_RSSI_SNR_WEIGHTS = 0x0052, ACX_KEEP_ALIVE_MODE = 0x0053, ACX_SET_KEEP_ALIVE_CONFIG = 0x0054, - ACX_BA_SESSION_POLICY_CFG = 0x0055, + ACX_BA_SESSION_INIT_POLICY = 0x0055, ACX_BA_SESSION_RX_SETUP = 0x0056, ACX_PEER_HT_CAP = 0x0057, ACX_HT_BSS_OPERATION = 0x0058, ACX_COEX_ACTIVITY = 0x0059, + ACX_BURST_MODE = 0x005C, + ACX_SET_RATE_MGMT_PARAMS = 0x005D, + ACX_SET_RATE_ADAPT_PARAMS = 0x0060, ACX_SET_DCO_ITRIM_PARAMS = 0x0061, ACX_GEN_FW_CMD = 0x0070, ACX_HOST_IF_CFG_BITMAP = 0x0071, @@ -1342,7 +1241,6 @@ int wl1271_acx_feature_cfg(struct wl1271 *wl); int wl1271_acx_mem_map(struct wl1271 *wl, struct acx_header *mem_map, size_t len); int wl1271_acx_rx_msdu_life_time(struct wl1271 *wl); -int wl1271_acx_rx_config(struct wl1271 *wl, u32 config, u32 filter); int wl1271_acx_pd_threshold(struct wl1271 *wl); int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time); int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, @@ -1354,8 +1252,7 @@ int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); int wl1271_acx_beacon_filter_table(struct wl1271 *wl); int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable); int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable); -int wl1271_acx_sta_sg_cfg(struct wl1271 *wl); -int wl1271_acx_ap_sg_cfg(struct wl1271 *wl); +int wl12xx_acx_sg_cfg(struct wl1271 *wl); int wl1271_acx_cca_threshold(struct wl1271 *wl); int wl1271_acx_bcn_dtim_options(struct wl1271 *wl); int wl1271_acx_aid(struct wl1271 *wl, u16 aid); @@ -1374,8 +1271,7 @@ int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type, u32 apsd_conf0, u32 apsd_conf1); int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold); int wl1271_acx_tx_config_options(struct wl1271 *wl); -int wl1271_acx_ap_mem_cfg(struct wl1271 *wl); -int wl1271_acx_sta_mem_cfg(struct wl1271 *wl); +int wl12xx_acx_mem_cfg(struct wl1271 *wl); int wl1271_acx_init_mem_config(struct wl1271 *wl); int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap); int wl1271_acx_init_rx_interrupt(struct wl1271 *wl); @@ -1390,20 +1286,19 @@ int wl1271_acx_rssi_snr_trigger(struct wl1271 *wl, bool enable, int wl1271_acx_rssi_snr_avg_weights(struct wl1271 *wl); int wl1271_acx_set_ht_capabilities(struct wl1271 *wl, struct ieee80211_sta_ht_cap *ht_cap, - bool allow_ht_operation); + bool allow_ht_operation, u8 hlid); int wl1271_acx_set_ht_information(struct wl1271 *wl, u16 ht_operation_mode); -int wl1271_acx_set_ba_session(struct wl1271 *wl, - enum ieee80211_back_parties direction, - u8 tid_index, u8 policy); -int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn, - bool enable); +int wl12xx_acx_set_ba_initiator_policy(struct wl1271 *wl); +int wl12xx_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, + u16 ssn, bool enable, u8 peer_hlid); int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime); int wl1271_acx_ps_rx_streaming(struct wl1271 *wl, bool enable); int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl); int wl1271_acx_config_ps(struct wl1271 *wl); int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); -int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable); int wl1271_acx_fm_coex(struct wl1271 *wl); +int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); +int wl12xx_acx_config_hangover(struct wl1271 *wl); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index 5ebc64d89407..d4e628db76b0 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -107,16 +107,6 @@ static unsigned int wl12xx_get_fw_ver_quirks(struct wl1271 *wl) unsigned int quirks = 0; unsigned int *fw_ver = wl->chip.fw_ver; - /* Only for wl127x */ - if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) && - /* Check STA version */ - (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && - (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) || - /* Check AP version */ - ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) && - (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN)))) - quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS; - /* Only new station firmwares support routing fw logs to the host */ if ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) && (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_FWLOG_STA_MIN)) @@ -304,9 +294,7 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) */ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) || wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) { - /* for now 11a is unsupported in AP mode */ - if (wl->bss_type != BSS_TYPE_AP_BSS && - nvs->general_params.dual_mode_select) + if (nvs->general_params.dual_mode_select) wl->enable_11a = true; } @@ -504,21 +492,19 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl) wl->event_mask = BSS_LOSE_EVENT_ID | SCAN_COMPLETE_EVENT_ID | PS_REPORT_EVENT_ID | - JOIN_EVENT_COMPLETE_ID | DISCONNECT_EVENT_COMPLETE_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | PSPOLL_DELIVERY_FAILURE_EVENT_ID | SOFT_GEMINI_SENSE_EVENT_ID | PERIODIC_SCAN_REPORT_EVENT_ID | - PERIODIC_SCAN_COMPLETE_EVENT_ID; - - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID | - INACTIVE_STA_EVENT_ID | - MAX_TX_RETRY_EVENT_ID; - else - wl->event_mask |= DUMMY_PACKET_EVENT_ID | - BA_SESSION_RX_CONSTRAINT_EVENT_ID; + PERIODIC_SCAN_COMPLETE_EVENT_ID | + DUMMY_PACKET_EVENT_ID | + PEER_REMOVE_COMPLETE_EVENT_ID | + BA_SESSION_RX_CONSTRAINT_EVENT_ID | + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID | + INACTIVE_STA_EVENT_ID | + MAX_TX_RETRY_EVENT_ID | + CHANNEL_SWITCH_COMPLETE_EVENT_ID; ret = wl1271_event_unmask(wl); if (ret < 0) { @@ -549,13 +535,13 @@ static void wl1271_boot_hw_version(struct wl1271 *wl) { u32 fuse; - fuse = wl1271_top_reg_read(wl, REG_FUSE_DATA_2_1); + if (wl->chip.id == CHIP_ID_1283_PG20) + fuse = wl1271_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); + else + fuse = wl1271_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); fuse = (fuse & PG_VER_MASK) >> PG_VER_OFFSET; wl->hw_pg_ver = (s8)fuse; - - if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3) - wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; } static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) @@ -696,7 +682,8 @@ static int wl127x_boot_clk(struct wl1271 *wl) u32 pause; u32 clk; - wl1271_boot_hw_version(wl); + if (((wl->hw_pg_ver & PG_MAJOR_VER_MASK) >> PG_MAJOR_VER_OFFSET) < 3) + wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION; if (wl->ref_clock == CONF_REF_CLK_19_2_E || wl->ref_clock == CONF_REF_CLK_38_4_E || @@ -750,6 +737,8 @@ int wl1271_load_firmware(struct wl1271 *wl) u32 tmp, clk; int selected_clock = -1; + wl1271_boot_hw_version(wl); + if (wl->chip.id == CHIP_ID_1283_PG20) { ret = wl128x_boot_clk(wl, &selected_clock); if (ret < 0) @@ -781,9 +770,6 @@ int wl1271_load_firmware(struct wl1271 *wl) clk |= (wl->ref_clock << 1) << 4; } - if (wl->quirks & WL12XX_QUIRK_LPD_MODE) - clk |= SCRATCH_ENABLE_LPD; - wl1271_write32(wl, DRPW_SCRATCH_START, clk); wl1271_set_partition(wl, &part_table[PART_WORK]); @@ -852,9 +838,6 @@ int wl1271_boot(struct wl1271 *wl) /* Enable firmware interrupts now */ wl1271_boot_enable_interrupts(wl); - /* set the wl1271 default filters */ - wl1271_set_default_filters(wl); - wl1271_event_mbox_config(wl); out: diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h index e8f8255bbabe..06dad9380fa7 100644 --- a/drivers/net/wireless/wl12xx/boot.h +++ b/drivers/net/wireless/wl12xx/boot.h @@ -55,7 +55,8 @@ struct wl1271_static_data { #define OCP_REG_CLK_POLARITY 0x0cb2 #define OCP_REG_CLK_PULL 0x0cb4 -#define REG_FUSE_DATA_2_1 0x050a +#define WL127X_REG_FUSE_DATA_2_1 0x050a +#define WL128X_REG_FUSE_DATA_2_1 0x2152 #define PG_VER_MASK 0x3c #define PG_VER_OFFSET 2 diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 97dd237a9580..a52299e548fa 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -134,11 +134,6 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) /* Override the REF CLK from the NVS with the one from platform data */ gen_parms->general_params.ref_clock = wl->ref_clock; - /* LPD mode enable (bits 6-7) in WL1271 AP mode only */ - if (wl->quirks & WL12XX_QUIRK_LPD_MODE) - gen_parms->general_params.general_settings |= - GENERAL_SETTINGS_DRPW_LPD; - ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer); if (ret < 0) { wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); @@ -363,63 +358,476 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) return 0; } -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type) +int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id) { - struct wl1271_cmd_join *join; - int ret, i; - u8 *bssid; + struct wl12xx_cmd_role_enable *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role enable"); + + if (WARN_ON(*role_id != WL12XX_INVALID_ROLE_ID)) + return -EBUSY; - join = kzalloc(sizeof(*join), GFP_KERNEL); - if (!join) { + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { ret = -ENOMEM; goto out; } - wl1271_debug(DEBUG_CMD, "cmd join"); + /* get role id */ + cmd->role_id = find_first_zero_bit(wl->roles_map, WL12XX_MAX_ROLES); + if (cmd->role_id >= WL12XX_MAX_ROLES) { + ret = -EBUSY; + goto out_free; + } + + memcpy(cmd->mac_address, wl->mac_addr, ETH_ALEN); + cmd->role_type = role_type; + + ret = wl1271_cmd_send(wl, CMD_ROLE_ENABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto out_free; + } + + __set_bit(cmd->role_id, wl->roles_map); + *role_id = cmd->role_id; + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id) +{ + struct wl12xx_cmd_role_disable *cmd; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role disable"); + + if (WARN_ON(*role_id == WL12XX_INVALID_ROLE_ID)) + return -ENOENT; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + cmd->role_id = *role_id; + + ret = wl1271_cmd_send(wl, CMD_ROLE_DISABLE, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role disable"); + goto out_free; + } + + __clear_bit(*role_id, wl->roles_map); + *role_id = WL12XX_INVALID_ROLE_ID; + +out_free: + kfree(cmd); + +out: + return ret; +} + +static int wl12xx_allocate_link(struct wl1271 *wl, u8 *hlid) +{ + u8 link = find_first_zero_bit(wl->links_map, WL12XX_MAX_LINKS); + if (link >= WL12XX_MAX_LINKS) + return -EBUSY; + + __set_bit(link, wl->links_map); + *hlid = link; + return 0; +} + +static void wl12xx_free_link(struct wl1271 *wl, u8 *hlid) +{ + if (*hlid == WL12XX_INVALID_LINK_ID) + return; + + __clear_bit(*hlid, wl->links_map); + *hlid = WL12XX_INVALID_LINK_ID; +} + +static int wl12xx_get_new_session_id(struct wl1271 *wl) +{ + if (wl->session_counter >= SESSION_COUNTER_MAX) + wl->session_counter = 0; + + wl->session_counter++; + + return wl->session_counter; +} - /* Reverse order BSSID */ - bssid = (u8 *) &join->bssid_lsb; - for (i = 0; i < ETH_ALEN; i++) - bssid[i] = wl->bssid[ETH_ALEN - i - 1]; +int wl12xx_cmd_role_start_dev(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_start *cmd; + int ret; - join->rx_config_options = cpu_to_le32(wl->rx_config); - join->rx_filter_options = cpu_to_le32(wl->rx_filter); - join->bss_type = bss_type; - join->basic_rate_set = cpu_to_le32(wl->basic_rate_set); - join->supported_rate_set = cpu_to_le32(wl->rate_set); + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + wl1271_debug(DEBUG_CMD, "cmd role start dev %d", wl->dev_role_id); + + cmd->role_id = wl->dev_role_id; if (wl->band == IEEE80211_BAND_5GHZ) - join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; + cmd->band = WL12XX_BAND_5GHZ; + cmd->channel = wl->channel; + + if (wl->dev_hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, &wl->dev_hlid); + if (ret) + goto out_free; + } + cmd->device.hlid = wl->dev_hlid; + cmd->device.session = wl->session_counter; - join->beacon_interval = cpu_to_le16(wl->beacon_int); - join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d", + cmd->role_id, cmd->device.hlid, cmd->device.session); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto err_hlid; + } - join->channel = wl->channel; - join->ssid_len = wl->ssid_len; - memcpy(join->ssid, wl->ssid, wl->ssid_len); + goto out_free; - join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; +err_hlid: + /* clear links on error */ + __clear_bit(wl->dev_hlid, wl->links_map); + wl->dev_hlid = WL12XX_INVALID_LINK_ID; - wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x", - join->basic_rate_set, join->supported_rate_set); - ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0); +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_stop_dev(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + if (WARN_ON(wl->dev_hlid == WL12XX_INVALID_LINK_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role stop dev"); + + cmd->role_id = wl->dev_role_id; + cmd->disc_type = DISCONNECT_IMMEDIATE; + cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); + + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop"); + goto out_free; + } + + ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); if (ret < 0) { - wl1271_error("failed to initiate cmd join"); + wl1271_error("cmd role stop dev event completion error"); goto out_free; } - ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID); + wl12xx_free_link(wl, &wl->dev_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_start_sta(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_start *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role start sta %d", wl->role_id); + + cmd->role_id = wl->role_id; + if (wl->band == IEEE80211_BAND_5GHZ) + cmd->band = WL12XX_BAND_5GHZ; + cmd->channel = wl->channel; + cmd->sta.basic_rate_set = cpu_to_le32(wl->basic_rate_set); + cmd->sta.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->sta.ssid_type = WL12XX_SSID_TYPE_ANY; + cmd->sta.ssid_len = wl->ssid_len; + memcpy(cmd->sta.ssid, wl->ssid, wl->ssid_len); + memcpy(cmd->sta.bssid, wl->bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wl->rate_set); + + if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, &wl->sta_hlid); + if (ret) + goto out_free; + } + cmd->sta.hlid = wl->sta_hlid; + cmd->sta.session = wl12xx_get_new_session_id(wl); + cmd->sta.remote_rates = cpu_to_le32(wl->rate_set); + + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " + "basic_rate_set: 0x%x, remote_rates: 0x%x", + wl->role_id, cmd->sta.hlid, cmd->sta.session, + wl->basic_rate_set, wl->rate_set); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role start sta"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error. */ + wl12xx_free_link(wl, &wl->sta_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +/* use this function to stop ibss as well */ +int wl12xx_cmd_role_stop_sta(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + if (WARN_ON(wl->sta_hlid == WL12XX_INVALID_LINK_ID)) + return -EINVAL; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role stop sta %d", wl->role_id); + + cmd->role_id = wl->role_id; + cmd->disc_type = DISCONNECT_IMMEDIATE; + cmd->reason = cpu_to_le16(WLAN_REASON_UNSPECIFIED); + + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop sta"); + goto out_free; + } + + wl12xx_free_link(wl, &wl->sta_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_start_ap(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_start *cmd; + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + int ret; + + wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id); + + /* trying to use hidden SSID with an old hostapd version */ + if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) { + wl1271_error("got a null SSID from beacon/bss"); + ret = -EINVAL; + goto out; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl12xx_allocate_link(wl, &wl->ap_global_hlid); if (ret < 0) - wl1271_error("cmd join event completion error"); + goto out_free; + + ret = wl12xx_allocate_link(wl, &wl->ap_bcast_hlid); + if (ret < 0) + goto out_free_global; + + cmd->role_id = wl->role_id; + cmd->ap.aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); + cmd->ap.bss_index = WL1271_AP_BSS_INDEX; + cmd->ap.global_hlid = wl->ap_global_hlid; + cmd->ap.broadcast_hlid = wl->ap_bcast_hlid; + cmd->ap.basic_rate_set = cpu_to_le32(wl->basic_rate_set); + cmd->ap.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->ap.dtim_interval = bss_conf->dtim_period; + cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP; + cmd->channel = wl->channel; + + if (!bss_conf->hidden_ssid) { + /* take the SSID from the beacon for backward compatibility */ + cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC; + cmd->ap.ssid_len = wl->ssid_len; + memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len); + } else { + cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN; + cmd->ap.ssid_len = bss_conf->ssid_len; + memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len); + } + + cmd->ap.local_rates = cpu_to_le32(0xffffffff); + + switch (wl->band) { + case IEEE80211_BAND_2GHZ: + cmd->band = RADIO_BAND_2_4GHZ; + break; + case IEEE80211_BAND_5GHZ: + cmd->band = RADIO_BAND_5GHZ; + break; + default: + wl1271_warning("ap start - unknown band: %d", (int)wl->band); + cmd->band = RADIO_BAND_2_4GHZ; + break; + } + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role start ap"); + goto out_free_bcast; + } + + goto out_free; + +out_free_bcast: + wl12xx_free_link(wl, &wl->ap_bcast_hlid); + +out_free_global: + wl12xx_free_link(wl, &wl->ap_global_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_stop_ap(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_stop *cmd; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role stop ap %d", wl->role_id); + + cmd->role_id = wl->role_id; + + ret = wl1271_cmd_send(wl, CMD_ROLE_STOP, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role stop ap"); + goto out_free; + } + + wl12xx_free_link(wl, &wl->ap_bcast_hlid); + wl12xx_free_link(wl, &wl->ap_global_hlid); + +out_free: + kfree(cmd); + +out: + return ret; +} + +int wl12xx_cmd_role_start_ibss(struct wl1271 *wl) +{ + struct wl12xx_cmd_role_start *cmd; + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + int ret; + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + wl1271_debug(DEBUG_CMD, "cmd role start ibss %d", wl->role_id); + + cmd->role_id = wl->role_id; + if (wl->band == IEEE80211_BAND_5GHZ) + cmd->band = WL12XX_BAND_5GHZ; + cmd->channel = wl->channel; + cmd->ibss.basic_rate_set = cpu_to_le32(wl->basic_rate_set); + cmd->ibss.beacon_interval = cpu_to_le16(wl->beacon_int); + cmd->ibss.dtim_interval = bss_conf->dtim_period; + cmd->ibss.ssid_type = WL12XX_SSID_TYPE_ANY; + cmd->ibss.ssid_len = wl->ssid_len; + memcpy(cmd->ibss.ssid, wl->ssid, wl->ssid_len); + memcpy(cmd->ibss.bssid, wl->bssid, ETH_ALEN); + cmd->sta.local_rates = cpu_to_le32(wl->rate_set); + + if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) { + ret = wl12xx_allocate_link(wl, &wl->sta_hlid); + if (ret) + goto out_free; + } + cmd->ibss.hlid = wl->sta_hlid; + cmd->ibss.remote_rates = cpu_to_le32(wl->rate_set); + + wl1271_debug(DEBUG_CMD, "role start: roleid=%d, hlid=%d, session=%d " + "basic_rate_set: 0x%x, remote_rates: 0x%x", + wl->role_id, cmd->sta.hlid, cmd->sta.session, + wl->basic_rate_set, wl->rate_set); + + wl1271_debug(DEBUG_CMD, "wl->bssid = %pM", wl->bssid); + + ret = wl1271_cmd_send(wl, CMD_ROLE_START, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to initiate cmd role enable"); + goto err_hlid; + } + + goto out_free; + +err_hlid: + /* clear links on error. */ + wl12xx_free_link(wl, &wl->sta_hlid); out_free: - kfree(join); + kfree(cmd); out: return ret; } + /** * send test command to firmware * @@ -488,7 +896,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) struct acx_header *acx = buf; int ret; - wl1271_debug(DEBUG_CMD, "cmd configure"); + wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id); acx->id = cpu_to_le16(id); @@ -567,6 +975,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) goto out; } + ps_params->role_id = wl->role_id; ps_params->ps_mode = ps_mode; ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, @@ -698,6 +1107,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, { struct sk_buff *skb; int ret; + u32 rate; skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len, ie, ie_len); @@ -708,14 +1118,13 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl, wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate); + skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate_5); + skb->data, skb->len, 0, rate); out: dev_kfree_skb(skb); @@ -726,6 +1135,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct sk_buff *skb) { int ret; + u32 rate; if (!skb) skb = ieee80211_ap_probereq_get(wl->hw, wl->vif); @@ -734,14 +1144,13 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len); + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]); if (wl->band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate); + skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - skb->data, skb->len, 0, - wl->conf.tx.basic_rate_5); + skb->data, skb->len, 0, rate); if (ret < 0) wl1271_error("Unable to set ap probe request template."); @@ -813,9 +1222,9 @@ int wl1271_build_qos_null_data(struct wl1271 *wl) wl->basic_rate); } -int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id) +int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid) { - struct wl1271_cmd_set_sta_keys *cmd; + struct wl1271_cmd_set_keys *cmd; int ret = 0; wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); @@ -826,36 +1235,7 @@ int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id) goto out; } - cmd->id = id; - cmd->key_action = cpu_to_le16(KEY_SET_ID); - cmd->key_type = KEY_WEP; - - ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_warning("cmd set_default_wep_key failed: %d", ret); - goto out; - } - -out: - kfree(cmd); - - return ret; -} - -int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id) -{ - struct wl1271_cmd_set_ap_keys *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - cmd->hlid = WL1271_AP_BROADCAST_HLID; + cmd->hlid = hlid; cmd->key_id = id; cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; cmd->key_action = cpu_to_le16(KEY_SET_ID); @@ -863,7 +1243,7 @@ int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id) ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret); + wl1271_warning("cmd set_default_wep_key failed: %d", ret); goto out; } @@ -877,17 +1257,27 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16) { - struct wl1271_cmd_set_sta_keys *cmd; + struct wl1271_cmd_set_keys *cmd; int ret = 0; + /* hlid might have already been deleted */ + if (wl->sta_hlid == WL12XX_INVALID_LINK_ID) + return 0; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } - if (key_type != KEY_WEP) - memcpy(cmd->addr, addr, ETH_ALEN); + cmd->hlid = wl->sta_hlid; + + if (key_type == KEY_WEP) + cmd->lid_key_type = WEP_DEFAULT_LID_TYPE; + else if (is_broadcast_ether_addr(addr)) + cmd->lid_key_type = BROADCAST_LID_TYPE; + else + cmd->lid_key_type = UNICAST_LID_TYPE; cmd->key_action = cpu_to_le16(action); cmd->key_size = key_size; @@ -896,10 +1286,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); - /* we have only one SSID profile */ - cmd->ssid_profile = 0; - - cmd->id = id; + cmd->key_id = id; if (key_type == KEY_TKIP) { /* @@ -930,11 +1317,15 @@ out: return ret; } +/* + * TODO: merge with sta/ibss into 1 set_key function. + * note there are slight diffs + */ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16) { - struct wl1271_cmd_set_ap_keys *cmd; + struct wl1271_cmd_set_keys *cmd; int ret = 0; u8 lid_type; @@ -942,7 +1333,7 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, if (!cmd) return -ENOMEM; - if (hlid == WL1271_AP_BROADCAST_HLID) { + if (hlid == wl->ap_bcast_hlid) { if (key_type == KEY_WEP) lid_type = WEP_DEFAULT_LID_TYPE; else @@ -991,12 +1382,12 @@ out: return ret; } -int wl1271_cmd_disconnect(struct wl1271 *wl) +int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid) { - struct wl1271_cmd_disconnect *cmd; + struct wl12xx_cmd_set_peer_state *cmd; int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd disconnect"); + wl1271_debug(DEBUG_CMD, "cmd set peer state (hlid=%d)", hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1004,21 +1395,15 @@ int wl1271_cmd_disconnect(struct wl1271 *wl) goto out; } - cmd->rx_config_options = cpu_to_le32(wl->rx_config); - cmd->rx_filter_options = cpu_to_le32(wl->rx_filter); - /* disconnect reason is not used in immediate disconnections */ - cmd->type = DISCONNECT_IMMEDIATE; + cmd->hlid = hlid; + cmd->state = WL1271_CMD_STA_STATE_CONNECTED; - ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0); + ret = wl1271_cmd_send(wl, CMD_SET_PEER_STATE, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to send disconnect command"); + wl1271_error("failed to send set peer state command"); goto out_free; } - ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID); - if (ret < 0) - wl1271_error("cmd disconnect event completion error"); - out_free: kfree(cmd); @@ -1026,12 +1411,13 @@ out: return ret; } -int wl1271_cmd_set_sta_state(struct wl1271 *wl) +int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) { - struct wl1271_cmd_set_sta_state *cmd; - int ret = 0; + struct wl12xx_cmd_add_peer *cmd; + int i, ret; + u32 sta_rates; - wl1271_debug(DEBUG_CMD, "cmd set sta state"); + wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1039,11 +1425,33 @@ int wl1271_cmd_set_sta_state(struct wl1271 *wl) goto out; } - cmd->state = WL1271_CMD_STA_STATE_CONNECTED; + memcpy(cmd->addr, sta->addr, ETH_ALEN); + cmd->bss_index = WL1271_AP_BSS_INDEX; + cmd->aid = sta->aid; + cmd->hlid = hlid; + cmd->sp_len = sta->max_sp; + cmd->wmm = sta->wme ? 1 : 0; + + for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++) + if (sta->wme && (sta->uapsd_queues & BIT(i))) + cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER; + else + cmd->psd_type[i] = WL1271_PSD_LEGACY; + + sta_rates = sta->supp_rates[wl->band]; + if (sta->ht_cap.ht_supported) + sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET; - ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0); + cmd->supported_rates = + cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, + wl->band)); + + wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x", + cmd->supported_rates, sta->uapsd_queues); + + ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to send set STA state command"); + wl1271_error("failed to initiate cmd add peer"); goto out_free; } @@ -1054,23 +1462,12 @@ out: return ret; } -int wl1271_cmd_start_bss(struct wl1271 *wl) +int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) { - struct wl1271_cmd_bss_start *cmd; - struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + struct wl12xx_cmd_remove_peer *cmd; int ret; - wl1271_debug(DEBUG_CMD, "cmd start bss"); - - /* - * FIXME: We currently do not support hidden SSID. The real SSID - * should be fetched from mac80211 first. - */ - if (wl->ssid_len == 0) { - wl1271_warning("Hidden SSID currently not supported for AP"); - ret = -EINVAL; - goto out; - } + wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1078,40 +1475,24 @@ int wl1271_cmd_start_bss(struct wl1271 *wl) goto out; } - memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN); - - cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period); - cmd->bss_index = WL1271_AP_BSS_INDEX; - cmd->global_hlid = WL1271_AP_GLOBAL_HLID; - cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID; - cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set); - cmd->beacon_interval = cpu_to_le16(wl->beacon_int); - cmd->dtim_interval = bss_conf->dtim_period; - cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP; - cmd->channel = wl->channel; - cmd->ssid_len = wl->ssid_len; - cmd->ssid_type = SSID_TYPE_PUBLIC; - memcpy(cmd->ssid, wl->ssid, wl->ssid_len); - - switch (wl->band) { - case IEEE80211_BAND_2GHZ: - cmd->band = RADIO_BAND_2_4GHZ; - break; - case IEEE80211_BAND_5GHZ: - cmd->band = RADIO_BAND_5GHZ; - break; - default: - wl1271_warning("bss start - unknown band: %d", (int)wl->band); - cmd->band = RADIO_BAND_2_4GHZ; - break; - } + cmd->hlid = hlid; + /* We never send a deauth, mac80211 is in charge of this */ + cmd->reason_opcode = 0; + cmd->send_deauth_flag = 0; - ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0); + ret = wl1271_cmd_send(wl, CMD_REMOVE_PEER, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to initiate cmd start bss"); + wl1271_error("failed to initiate cmd remove peer"); goto out_free; } + /* + * We are ok with a timeout here. The event is sometimes not sent + * due to a firmware bug. + */ + wl1271_cmd_wait_for_event_or_timeout(wl, + PEER_REMOVE_COMPLETE_EVENT_ID); + out_free: kfree(cmd); @@ -1119,12 +1500,12 @@ out: return ret; } -int wl1271_cmd_stop_bss(struct wl1271 *wl) +int wl12xx_cmd_config_fwlog(struct wl1271 *wl) { - struct wl1271_cmd_bss_start *cmd; - int ret; + struct wl12xx_cmd_config_fwlog *cmd; + int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd stop bss"); + wl1271_debug(DEBUG_CMD, "cmd config firmware logger"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1132,11 +1513,15 @@ int wl1271_cmd_stop_bss(struct wl1271 *wl) goto out; } - cmd->bss_index = WL1271_AP_BSS_INDEX; + cmd->logger_mode = wl->conf.fwlog.mode; + cmd->log_severity = wl->conf.fwlog.severity; + cmd->timestamp = wl->conf.fwlog.timestamp; + cmd->output = wl->conf.fwlog.output; + cmd->threshold = wl->conf.fwlog.threshold; - ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0); + ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to initiate cmd stop bss"); + wl1271_error("failed to send config firmware logger command"); goto out_free; } @@ -1147,12 +1532,12 @@ out: return ret; } -int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) +int wl12xx_cmd_start_fwlog(struct wl1271 *wl) { - struct wl1271_cmd_add_sta *cmd; - int ret; + struct wl12xx_cmd_start_fwlog *cmd; + int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid); + wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1160,23 +1545,35 @@ int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid) goto out; } - /* currently we don't support UAPSD */ - cmd->sp_len = 0; + ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("failed to send start firmware logger command"); + goto out_free; + } - memcpy(cmd->addr, sta->addr, ETH_ALEN); - cmd->bss_index = WL1271_AP_BSS_INDEX; - cmd->aid = sta->aid; - cmd->hlid = hlid; - cmd->wmm = sta->wme ? 1 : 0; +out_free: + kfree(cmd); - cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl, - sta->supp_rates[wl->band])); +out: + return ret; +} - wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates); +int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) +{ + struct wl12xx_cmd_stop_fwlog *cmd; + int ret = 0; - ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0); + wl1271_debug(DEBUG_CMD, "cmd stop firmware logger"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to initiate cmd add sta"); + wl1271_error("failed to send stop firmware logger command"); goto out_free; } @@ -1187,12 +1584,15 @@ out: return ret; } -int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) +static int wl12xx_cmd_roc(struct wl1271 *wl, u8 role_id) { - struct wl1271_cmd_remove_sta *cmd; - int ret; + struct wl12xx_cmd_roc *cmd; + int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid); + wl1271_debug(DEBUG_CMD, "cmd roc %d (%d)", wl->channel, role_id); + + if (WARN_ON(role_id == WL12XX_INVALID_ROLE_ID)) + return -EINVAL; cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1200,23 +1600,28 @@ int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid) goto out; } - cmd->hlid = hlid; - /* We never send a deauth, mac80211 is in charge of this */ - cmd->reason_opcode = 0; - cmd->send_deauth_flag = 0; + cmd->role_id = role_id; + cmd->channel = wl->channel; + switch (wl->band) { + case IEEE80211_BAND_2GHZ: + cmd->band = RADIO_BAND_2_4GHZ; + break; + case IEEE80211_BAND_5GHZ: + cmd->band = RADIO_BAND_5GHZ; + break; + default: + wl1271_error("roc - unknown band: %d", (int)wl->band); + ret = -EINVAL; + goto out_free; + } - ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0); + + ret = wl1271_cmd_send(wl, CMD_REMAIN_ON_CHANNEL, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to initiate cmd remove sta"); + wl1271_error("failed to send ROC command"); goto out_free; } - /* - * We are ok with a timeout here. The event is sometimes not sent - * due to a firmware bug. - */ - wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID); - out_free: kfree(cmd); @@ -1224,28 +1629,24 @@ out: return ret; } -int wl12xx_cmd_config_fwlog(struct wl1271 *wl) +static int wl12xx_cmd_croc(struct wl1271 *wl, u8 role_id) { - struct wl12xx_cmd_config_fwlog *cmd; + struct wl12xx_cmd_croc *cmd; int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd config firmware logger"); + wl1271_debug(DEBUG_CMD, "cmd croc (%d)", role_id); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; goto out; } + cmd->role_id = role_id; - cmd->logger_mode = wl->conf.fwlog.mode; - cmd->log_severity = wl->conf.fwlog.severity; - cmd->timestamp = wl->conf.fwlog.timestamp; - cmd->output = wl->conf.fwlog.output; - cmd->threshold = wl->conf.fwlog.threshold; - - ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0); + ret = wl1271_cmd_send(wl, CMD_CANCEL_REMAIN_ON_CHANNEL, cmd, + sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to send config firmware logger command"); + wl1271_error("failed to send ROC command"); goto out_free; } @@ -1256,12 +1657,52 @@ out: return ret; } -int wl12xx_cmd_start_fwlog(struct wl1271 *wl) +int wl12xx_roc(struct wl1271 *wl, u8 role_id) { - struct wl12xx_cmd_start_fwlog *cmd; int ret = 0; - wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); + if (WARN_ON(test_bit(role_id, wl->roc_map))) + return 0; + + ret = wl12xx_cmd_roc(wl, role_id); + if (ret < 0) + goto out; + + ret = wl1271_cmd_wait_for_event(wl, + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID); + if (ret < 0) { + wl1271_error("cmd roc event completion error"); + goto out; + } + + __set_bit(role_id, wl->roc_map); +out: + return ret; +} + +int wl12xx_croc(struct wl1271 *wl, u8 role_id) +{ + int ret = 0; + + if (WARN_ON(!test_bit(role_id, wl->roc_map))) + return 0; + + ret = wl12xx_cmd_croc(wl, role_id); + if (ret < 0) + goto out; + + __clear_bit(role_id, wl->roc_map); +out: + return ret; +} + +int wl12xx_cmd_channel_switch(struct wl1271 *wl, + struct ieee80211_channel_switch *ch_switch) +{ + struct wl12xx_cmd_channel_switch *cmd; + int ret; + + wl1271_debug(DEBUG_ACX, "cmd channel switch"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1269,9 +1710,14 @@ int wl12xx_cmd_start_fwlog(struct wl1271 *wl) goto out; } - ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); + cmd->channel = ch_switch->channel->hw_value; + cmd->switch_time = ch_switch->count; + cmd->tx_suspend = ch_switch->block_tx; + cmd->flush = 0; /* this value is ignored by the FW */ + + ret = wl1271_cmd_send(wl, CMD_CHANNEL_SWITCH, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to send start firmware logger command"); + wl1271_error("failed to send channel switch command"); goto out_free; } @@ -1282,12 +1728,12 @@ out: return ret; } -int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) +int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl) { - struct wl12xx_cmd_stop_fwlog *cmd; - int ret = 0; + struct wl12xx_cmd_stop_channel_switch *cmd; + int ret; - wl1271_debug(DEBUG_CMD, "cmd stop firmware logger"); + wl1271_debug(DEBUG_ACX, "cmd stop channel switch"); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { @@ -1295,9 +1741,9 @@ int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) goto out; } - ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0); + ret = wl1271_cmd_send(wl, CMD_STOP_CHANNEL_SWICTH, cmd, sizeof(*cmd), 0); if (ret < 0) { - wl1271_error("failed to send stop firmware logger command"); + wl1271_error("failed to stop channel switch command"); goto out_free; } diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h index 1f7037292c15..b7bd42769aa7 100644 --- a/drivers/net/wireless/wl12xx/cmd.h +++ b/drivers/net/wireless/wl12xx/cmd.h @@ -36,7 +36,15 @@ int wl128x_cmd_general_parms(struct wl1271 *wl); int wl1271_cmd_radio_parms(struct wl1271 *wl); int wl128x_cmd_radio_parms(struct wl1271 *wl); int wl1271_cmd_ext_radio_parms(struct wl1271 *wl); -int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type); +int wl12xx_cmd_role_enable(struct wl1271 *wl, u8 role_type, u8 *role_id); +int wl12xx_cmd_role_disable(struct wl1271 *wl, u8 *role_id); +int wl12xx_cmd_role_start_dev(struct wl1271 *wl); +int wl12xx_cmd_role_stop_dev(struct wl1271 *wl); +int wl12xx_cmd_role_start_sta(struct wl1271 *wl); +int wl12xx_cmd_role_stop_sta(struct wl1271 *wl); +int wl12xx_cmd_role_start_ap(struct wl1271 *wl); +int wl12xx_cmd_role_stop_ap(struct wl1271 *wl); +int wl12xx_cmd_role_start_ibss(struct wl1271 *wl); int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); @@ -56,23 +64,24 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr); int wl1271_build_qos_null_data(struct wl1271 *wl); int wl1271_cmd_build_klv_null_data(struct wl1271 *wl); -int wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id); -int wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id); +int wl12xx_cmd_set_default_wep_key(struct wl1271 *wl, u8 id, u8 hlid); int wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, const u8 *addr, u32 tx_seq_32, u16 tx_seq_16); int wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, u16 tx_seq_16); -int wl1271_cmd_disconnect(struct wl1271 *wl); -int wl1271_cmd_set_sta_state(struct wl1271 *wl); -int wl1271_cmd_start_bss(struct wl1271 *wl); -int wl1271_cmd_stop_bss(struct wl1271 *wl); -int wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); -int wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid); +int wl12xx_cmd_set_peer_state(struct wl1271 *wl, u8 hlid); +int wl12xx_roc(struct wl1271 *wl, u8 role_id); +int wl12xx_croc(struct wl1271 *wl, u8 role_id); +int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid); +int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); +int wl12xx_cmd_channel_switch(struct wl1271 *wl, + struct ieee80211_channel_switch *ch_switch); +int wl12xx_cmd_stop_channel_switch(struct wl1271 *wl); enum wl1271_commands { CMD_INTERROGATE = 1, /*use this to read information elements*/ @@ -83,25 +92,21 @@ enum wl1271_commands { CMD_DISABLE_TX = 6, CMD_SCAN = 8, CMD_STOP_SCAN = 9, - CMD_START_JOIN = 11, CMD_SET_KEYS = 12, CMD_READ_MEMORY = 13, CMD_WRITE_MEMORY = 14, CMD_SET_TEMPLATE = 19, CMD_TEST = 23, CMD_NOISE_HIST = 28, - CMD_LNA_CONTROL = 32, + CMD_QUIET_ELEMENT_SET_STATE = 29, CMD_SET_BCN_MODE = 33, CMD_MEASUREMENT = 34, CMD_STOP_MEASUREMENT = 35, - CMD_DISCONNECT = 36, CMD_SET_PS_MODE = 37, CMD_CHANNEL_SWITCH = 38, CMD_STOP_CHANNEL_SWICTH = 39, CMD_AP_DISCOVERY = 40, CMD_STOP_AP_DISCOVERY = 41, - CMD_SPS_SCAN = 42, - CMD_STOP_SPS_SCAN = 43, CMD_HEALTH_CHECK = 45, CMD_DEBUG = 46, CMD_TRIGGER_SCAN_TO = 47, @@ -109,16 +114,30 @@ enum wl1271_commands { CMD_CONNECTION_SCAN_SSID_CFG = 49, CMD_START_PERIODIC_SCAN = 50, CMD_STOP_PERIODIC_SCAN = 51, - CMD_SET_STA_STATE = 52, - CMD_CONFIG_FWLOGGER = 53, - CMD_START_FWLOGGER = 54, - CMD_STOP_FWLOGGER = 55, + CMD_SET_PEER_STATE = 52, + CMD_REMAIN_ON_CHANNEL = 53, + CMD_CANCEL_REMAIN_ON_CHANNEL = 54, - /* AP mode commands */ - CMD_BSS_START = 60, - CMD_BSS_STOP = 61, - CMD_ADD_STA = 62, - CMD_REMOVE_STA = 63, + CMD_CONFIG_FWLOGGER = 55, + CMD_START_FWLOGGER = 56, + CMD_STOP_FWLOGGER = 57, + + /* AP commands */ + CMD_ADD_PEER = 62, + CMD_REMOVE_PEER = 63, + + /* Role API */ + CMD_ROLE_ENABLE = 70, + CMD_ROLE_DISABLE = 71, + CMD_ROLE_START = 72, + CMD_ROLE_STOP = 73, + + /* WIFI Direct */ + CMD_WFD_START_DISCOVERY = 80, + CMD_WFD_STOP_DISCOVERY = 81, + CMD_WFD_ATTRIBUTE_CONFIG = 82, + + CMD_NOP = 100, NUM_COMMANDS, MAX_COMMAND_ID = 0xFFFF, @@ -147,21 +166,20 @@ enum cmd_templ { CMD_TEMPL_CTS, /* * For CTS-to-self (FastCTS) mechanism * for BT/WLAN coexistence (SoftGemini). */ - CMD_TEMPL_ARP_RSP, - CMD_TEMPL_LINK_MEASUREMENT_REPORT, - - /* AP-mode specific */ - CMD_TEMPL_AP_BEACON = 13, + CMD_TEMPL_AP_BEACON, CMD_TEMPL_AP_PROBE_RESPONSE, - CMD_TEMPL_AP_ARP_RSP, + CMD_TEMPL_ARP_RSP, CMD_TEMPL_DEAUTH_AP, + CMD_TEMPL_TEMPORARY, + CMD_TEMPL_LINK_MEASUREMENT_REPORT, CMD_TEMPL_MAX = 0xff }; /* unit ms */ #define WL1271_COMMAND_TIMEOUT 2000 -#define WL1271_CMD_TEMPL_MAX_SIZE 252 +#define WL1271_CMD_TEMPL_DFLT_SIZE 252 +#define WL1271_CMD_TEMPL_MAX_SIZE 548 #define WL1271_EVENT_TIMEOUT 750 struct wl1271_cmd_header { @@ -193,6 +211,8 @@ enum { CMD_STATUS_WRONG_NESTING = 19, CMD_STATUS_TIMEOUT = 21, /* Driver internal use.*/ CMD_STATUS_FW_RESET = 22, /* Driver internal use.*/ + CMD_STATUS_TEMPLATE_OOM = 23, + CMD_STATUS_NO_RX_BA_SESSION = 24, MAX_COMMAND_STATUS = 0xff }; @@ -210,38 +230,114 @@ enum { #define WL1271_JOIN_CMD_TX_SESSION_OFFSET 1 #define WL1271_JOIN_CMD_BSS_TYPE_5GHZ 0x10 -struct wl1271_cmd_join { +struct wl12xx_cmd_role_enable { struct wl1271_cmd_header header; - __le32 bssid_lsb; - __le16 bssid_msb; - __le16 beacon_interval; /* in TBTTs */ - __le32 rx_config_options; - __le32 rx_filter_options; + u8 role_id; + u8 role_type; + u8 mac_address[ETH_ALEN]; +} __packed; - /* - * The target uses this field to determine the rate at - * which to transmit control frame responses (such as - * ACK or CTS frames). - */ - __le32 basic_rate_set; - __le32 supported_rate_set; - u8 dtim_interval; - /* - * bits 0-2: This bitwise field specifies the type - * of BSS to start or join (BSS_TYPE_*). - * bit 4: Band - The radio band in which to join - * or start. - * 0 - 2.4GHz band - * 1 - 5GHz band - * bits 3, 5-7: Reserved - */ - u8 bss_type; +struct wl12xx_cmd_role_disable { + struct wl1271_cmd_header header; + + u8 role_id; + u8 padding[3]; +} __packed; + +enum wl12xx_band { + WL12XX_BAND_2_4GHZ = 0, + WL12XX_BAND_5GHZ = 1, + WL12XX_BAND_JAPAN_4_9_GHZ = 2, + WL12XX_BAND_DEFAULT = WL12XX_BAND_2_4GHZ, + WL12XX_BAND_INVALID = 0x7E, + WL12XX_BAND_MAX_RADIO = 0x7F, +}; + +struct wl12xx_cmd_role_start { + struct wl1271_cmd_header header; + + u8 role_id; + u8 band; u8 channel; - u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; - u8 ctrl; /* JOIN_CMD_CTRL_* */ - u8 reserved[3]; + u8 padding; + + union { + struct { + u8 hlid; + u8 session; + u8 padding_1[54]; + } __packed device; + /* sta & p2p_cli use the same struct */ + struct { + u8 bssid[ETH_ALEN]; + u8 hlid; /* data hlid */ + u8 session; + __le32 remote_rates; /* remote supported rates */ + + /* + * The target uses this field to determine the rate at + * which to transmit control frame responses (such as + * ACK or CTS frames). + */ + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + __le16 beacon_interval; /* in TBTTs */ + } __packed sta; + struct { + u8 bssid[ETH_ALEN]; + u8 hlid; /* data hlid */ + u8 dtim_interval; + __le32 remote_rates; /* remote supported rates */ + + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + __le16 beacon_interval; /* in TBTTs */ + + u8 padding_1[4]; + } __packed ibss; + /* ap & p2p_go use the same struct */ + struct { + __le16 aging_period; /* in secs */ + u8 beacon_expiry; /* in ms */ + u8 bss_index; + /* The host link id for the AP's global queue */ + u8 global_hlid; + /* The host link id for the AP's broadcast queue */ + u8 broadcast_hlid; + + __le16 beacon_interval; /* in TBTTs */ + + __le32 basic_rate_set; + __le32 local_rates; /* local supported rates */ + + u8 dtim_interval; + + u8 ssid_type; + u8 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + + u8 padding_1[5]; + } __packed ap; + }; +} __packed; + +struct wl12xx_cmd_role_stop { + struct wl1271_cmd_header header; + + u8 role_id; + u8 disc_type; /* only STA and P2P_CLI */ + __le16 reason; /* only STA and P2P_CLI */ } __packed; struct cmd_enabledisable_path { @@ -287,8 +383,9 @@ enum wl1271_cmd_ps_mode { struct wl1271_cmd_ps_params { struct wl1271_cmd_header header; + u8 role_id; u8 ps_mode; /* STATION_* */ - u8 padding[3]; + u8 padding[2]; } __packed; /* HW encryption keys */ @@ -301,6 +398,12 @@ enum wl1271_cmd_key_action { MAX_KEY_ACTION = 0xffff, }; +enum wl1271_cmd_lid_key_type { + UNICAST_LID_TYPE = 0, + BROADCAST_LID_TYPE = 1, + WEP_DEFAULT_LID_TYPE = 2 +}; + enum wl1271_cmd_key_type { KEY_NONE = 0, KEY_WEP = 1, @@ -309,44 +412,7 @@ enum wl1271_cmd_key_type { KEY_GEM = 4, }; -/* FIXME: Add description for key-types */ - -struct wl1271_cmd_set_sta_keys { - struct wl1271_cmd_header header; - - /* Ignored for default WEP key */ - u8 addr[ETH_ALEN]; - - /* key_action_e */ - __le16 key_action; - - __le16 reserved_1; - - /* key size in bytes */ - u8 key_size; - - /* key_type_e */ - u8 key_type; - u8 ssid_profile; - - /* - * TKIP, AES: frame's key id field. - * For WEP default key: key id; - */ - u8 id; - u8 reserved_2[6]; - u8 key[MAX_KEY_SIZE]; - __le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY]; - __le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY]; -} __packed; - -enum wl1271_cmd_lid_key_type { - UNICAST_LID_TYPE = 0, - BROADCAST_LID_TYPE = 1, - WEP_DEFAULT_LID_TYPE = 2 -}; - -struct wl1271_cmd_set_ap_keys { +struct wl1271_cmd_set_keys { struct wl1271_cmd_header header; /* @@ -496,69 +562,46 @@ enum wl1271_disconnect_type { DISCONNECT_DISASSOC }; -struct wl1271_cmd_disconnect { - struct wl1271_cmd_header header; - - __le32 rx_config_options; - __le32 rx_filter_options; - - __le16 reason; - u8 type; - - u8 padding; -} __packed; - #define WL1271_CMD_STA_STATE_CONNECTED 1 -struct wl1271_cmd_set_sta_state { +struct wl12xx_cmd_set_peer_state { struct wl1271_cmd_header header; + u8 hlid; u8 state; - u8 padding[3]; + u8 padding[2]; } __packed; -enum wl1271_ssid_type { - SSID_TYPE_PUBLIC = 0, - SSID_TYPE_HIDDEN = 1 +struct wl12xx_cmd_roc { + struct wl1271_cmd_header header; + + u8 role_id; + u8 channel; + u8 band; + u8 padding; }; -struct wl1271_cmd_bss_start { +struct wl12xx_cmd_croc { struct wl1271_cmd_header header; - /* wl1271_ssid_type */ - u8 ssid_type; - u8 ssid_len; - u8 ssid[IW_ESSID_MAX_SIZE]; - u8 padding_1[2]; + u8 role_id; + u8 padding[3]; +}; - /* Basic rate set */ - __le32 basic_rate_set; - /* Aging period in seconds*/ - __le16 aging_period; +enum wl12xx_ssid_type { + WL12XX_SSID_TYPE_PUBLIC = 0, + WL12XX_SSID_TYPE_HIDDEN = 1, + WL12XX_SSID_TYPE_ANY = 2, +}; - /* - * This field specifies the time between target beacon - * transmission times (TBTTs), in time units (TUs). - * Valid values are 1 to 1024. - */ - __le16 beacon_interval; - u8 bssid[ETH_ALEN]; - u8 bss_index; - /* Radio band */ - u8 band; - u8 channel; - /* The host link id for the AP's global queue */ - u8 global_hlid; - /* The host link id for the AP's broadcast queue */ - u8 broadcast_hlid; - /* DTIM count */ - u8 dtim_interval; - /* Beacon expiry time in ms */ - u8 beacon_expiry; - u8 padding_2[3]; -} __packed; +enum wl1271_psd_type { + WL1271_PSD_LEGACY = 0, + WL1271_PSD_UPSD_TRIGGER = 1, + WL1271_PSD_LEGACY_PSPOLL = 2, + WL1271_PSD_SAPSD = 3 +}; -struct wl1271_cmd_add_sta { +struct wl12xx_cmd_add_peer { struct wl1271_cmd_header header; u8 addr[ETH_ALEN]; @@ -572,7 +615,7 @@ struct wl1271_cmd_add_sta { u8 padding1; } __packed; -struct wl1271_cmd_remove_sta { +struct wl12xx_cmd_remove_peer { struct wl1271_cmd_header header; u8 hlid; @@ -637,4 +680,21 @@ struct wl12xx_cmd_stop_fwlog { struct wl1271_cmd_header header; } __packed; +struct wl12xx_cmd_channel_switch { + struct wl1271_cmd_header header; + + /* The new serving channel */ + u8 channel; + /* Relative time of the serving channel switch in TBTT units */ + u8 switch_time; + /* 1: Suspend TX till switch time; 0: Do not suspend TX */ + u8 tx_suspend; + /* 1: Flush TX at switch time; 0: Do not flush */ + u8 flush; +} __packed; + +struct wl12xx_cmd_stop_channel_switch { + struct wl1271_cmd_header header; +} __packed; + #endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h index 6080e01d92c6..04bb8fbf93f9 100644 --- a/drivers/net/wireless/wl12xx/conf.h +++ b/drivers/net/wireless/wl12xx/conf.h @@ -99,40 +99,75 @@ enum { enum { /* - * PER threshold in PPM of the BT voice + * Configure the min and max time BT gains the antenna + * in WLAN / BT master basic rate * - * Range: 0 - 10000000 + * Range: 0 - 255 (ms) */ - CONF_SG_BT_PER_THRESHOLD = 0, + CONF_SG_ACL_BT_MASTER_MIN_BR = 0, + CONF_SG_ACL_BT_MASTER_MAX_BR, /* - * Number of consequent RX_ACTIVE activities to override BT voice - * frames to ensure WLAN connection + * Configure the min and max time BT gains the antenna + * in WLAN / BT slave basic rate * - * Range: 0 - 100 + * Range: 0 - 255 (ms) */ - CONF_SG_HV3_MAX_OVERRIDE, + CONF_SG_ACL_BT_SLAVE_MIN_BR, + CONF_SG_ACL_BT_SLAVE_MAX_BR, /* - * Defines the PER threshold of the BT voice + * Configure the min and max time BT gains the antenna + * in WLAN / BT master EDR * - * Range: 0 - 65000 + * Range: 0 - 255 (ms) */ - CONF_SG_BT_NFS_SAMPLE_INTERVAL, + CONF_SG_ACL_BT_MASTER_MIN_EDR, + CONF_SG_ACL_BT_MASTER_MAX_EDR, /* - * Defines the load ratio of BT + * Configure the min and max time BT gains the antenna + * in WLAN / BT slave EDR * - * Range: 0 - 100 (%) + * Range: 0 - 255 (ms) */ - CONF_SG_BT_LOAD_RATIO, + CONF_SG_ACL_BT_SLAVE_MIN_EDR, + CONF_SG_ACL_BT_SLAVE_MAX_EDR, /* - * Defines whether the SG will force WLAN host to enter/exit PSM + * The maximum time WLAN can gain the antenna + * in WLAN PSM / BT master/slave BR * - * Range: 1 - SG can force, 0 - host handles PSM + * Range: 0 - 255 (ms) */ - CONF_SG_AUTO_PS_MODE, + CONF_SG_ACL_WLAN_PS_MASTER_BR, + CONF_SG_ACL_WLAN_PS_SLAVE_BR, + + /* + * The maximum time WLAN can gain the antenna + * in WLAN PSM / BT master/slave EDR + * + * Range: 0 - 255 (ms) + */ + CONF_SG_ACL_WLAN_PS_MASTER_EDR, + CONF_SG_ACL_WLAN_PS_SLAVE_EDR, + + /* TODO: explain these values */ + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR, + CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR, + CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR, + + CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR, + CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR, + CONF_SG_ACL_PASSIVE_SCAN_BT_BR, + CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR, + CONF_SG_ACL_PASSIVE_SCAN_BT_EDR, + CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR, /* * Compensation percentage of probe requests when scan initiated @@ -151,102 +186,70 @@ enum { CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3, /* - * Defines antenna configuration (single/dual antenna) - * - * Range: 0 - single antenna, 1 - dual antenna - */ - CONF_SG_ANTENNA_CONFIGURATION, - - /* - * The threshold (percent) of max consequtive beacon misses before - * increasing priority of beacon reception. - * - * Range: 0 - 100 (%) - */ - CONF_SG_BEACON_MISS_PERCENT, - - /* - * The rate threshold below which receiving a data frame from the AP - * will increase the priority of the data frame above BT traffic. - * - * Range: 0,2, 5(=5.5), 6, 9, 11, 12, 18, 24, 36, 48, 54 - */ - CONF_SG_RATE_ADAPT_THRESH, - - /* - * Not used currently. + * Compensation percentage of WLAN active scan window if initiated + * during BT A2DP * - * Range: 0 + * Range: 0 - 1000 (%) */ - CONF_SG_RATE_ADAPT_SNR, + CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT master basic rate + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP BR * - * Range: 0 - 255 (ms) + * Range: 0 - 1000 (%) */ - CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR, - CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR, + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR, /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT master basic rate + * Compensation percentage of WLAN passive scan window if initiated + * during BT A2DP EDR * - * Range: 0 - 255 (ms) + * Range: 0 - 1000 (%) */ - CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR, + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR, /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT slave basic rate + * Compensation percentage of WLAN passive scan window if initiated + * during BT voice * - * Range: 0 - 255 (ms) + * Range: 0 - 1000 (%) */ - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR, - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR, + CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, - /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT slave basic rate - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR, + /* TODO: explain these values */ + CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN, + CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN, + CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN, /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT master EDR + * Defines whether the SG will force WLAN host to enter/exit PSM * - * Range: 0 - 255 (ms) + * Range: 1 - SG can force, 0 - host handles PSM */ - CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR, - CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR, + CONF_SG_STA_FORCE_PS_IN_BT_SCO, /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT master EDR + * Defines antenna configuration (single/dual antenna) * - * Range: 0 - 255 (ms) + * Range: 0 - single antenna, 1 - dual antenna */ - CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR, + CONF_SG_ANTENNA_CONFIGURATION, /* - * Configure the min and max time BT gains the antenna - * in WLAN PSM / BT slave EDR + * The threshold (percent) of max consecutive beacon misses before + * increasing priority of beacon reception. * - * Range: 0 - 255 (ms) + * Range: 0 - 100 (%) */ - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR, - CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR, + CONF_SG_BEACON_MISS_PERCENT, /* - * The time after it expires no new WLAN trigger frame is trasmitted - * in WLAN PSM / BT slave EDR + * Protection time of the DHCP procedure. * - * Range: 0 - 255 (ms) + * Range: 0 - 100000 (ms) */ - CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR, + CONF_SG_DHCP_TIME, /* * RX guard time before the beginning of a new BT voice frame during @@ -273,166 +276,59 @@ enum { */ CONF_SG_ADAPTIVE_RXT_TXT, - /* - * The used WLAN legacy service period during active BT ACL link - * - * Range: 0 - 255 (ms) - */ - CONF_SG_PS_POLL_TIMEOUT, + /* TODO: explain this value */ + CONF_SG_GENERAL_USAGE_BIT_MAP, /* - * The used WLAN UPSD service period during active BT ACL link + * Number of consecutive BT voice frames not interrupted by WLAN * - * Range: 0 - 255 (ms) - */ - CONF_SG_UPSD_TIMEOUT, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN Active / BT master EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR, - CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR, - - /* - * The maximum time WLAN can gain the antenna for - * in WLAN Active / BT master EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR, - - /* - * Configure the min and max time BT gains the antenna - * in WLAN Active / BT slave EDR - * - * Range: 0 - 255 (ms) - */ - CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR, - CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR, - - /* - * The maximum time WLAN can gain the antenna for - * in WLAN Active / BT slave EDR - * - * Range: 0 - 255 (ms) + * Range: 0 - 100 */ - CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR, + CONF_SG_HV3_MAX_SERVED, /* - * Configure the min and max time BT gains the antenna - * in WLAN Active / BT basic rate + * The used WLAN legacy service period during active BT ACL link * * Range: 0 - 255 (ms) */ - CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR, - CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR, + CONF_SG_PS_POLL_TIMEOUT, /* - * The maximum time WLAN can gain the antenna for - * in WLAN Active / BT basic rate + * The used WLAN UPSD service period during active BT ACL link * * Range: 0 - 255 (ms) */ - CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT voice - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3, - - /* - * Compensation percentage of WLAN passive scan window if initiated - * during BT A2DP - * - * Range: 0 - 1000 (%) - */ - CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP, + CONF_SG_UPSD_TIMEOUT, - /* - * Fixed time ensured for BT traffic to gain the antenna during WLAN - * passive scan. - * - * Range: 0 - 1000 ms - */ - CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME, + CONF_SG_CONSECUTIVE_CTS_THRESHOLD, + CONF_SG_STA_RX_WINDOW_AFTER_DTIM, + CONF_SG_STA_CONNECTION_PROTECTION_TIME, - /* - * Fixed time ensured for WLAN traffic to gain the antenna during WLAN - * passive scan. - * - * Range: 0 - 1000 ms - */ - CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME, + /* AP params */ + CONF_AP_BEACON_MISS_TX, + CONF_AP_RX_WINDOW_AFTER_BEACON, + CONF_AP_BEACON_WINDOW_INTERVAL, + CONF_AP_CONNECTION_PROTECTION_TIME, + CONF_AP_BT_ACL_VAL_BT_SERVE_TIME, + CONF_AP_BT_ACL_VAL_WL_SERVE_TIME, - /* - * Number of consequent BT voice frames not interrupted by WLAN - * - * Range: 0 - 100 - */ - CONF_SG_HV3_MAX_SERVED, - - /* - * Protection time of the DHCP procedure. - * - * Range: 0 - 100000 (ms) - */ - CONF_SG_DHCP_TIME, - - /* - * Compensation percentage of WLAN active scan window if initiated - * during BT A2DP - * - * Range: 0 - 1000 (%) - */ - CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP, CONF_SG_TEMP_PARAM_1, CONF_SG_TEMP_PARAM_2, CONF_SG_TEMP_PARAM_3, CONF_SG_TEMP_PARAM_4, CONF_SG_TEMP_PARAM_5, - - /* - * AP beacon miss - * - * Range: 0 - 255 - */ - CONF_SG_AP_BEACON_MISS_TX, - - /* - * AP RX window length - * - * Range: 0 - 50 - */ - CONF_SG_RX_WINDOW_LENGTH, - - /* - * AP connection protection time - * - * Range: 0 - 5000 - */ - CONF_SG_AP_CONNECTION_PROTECTION_TIME, - CONF_SG_TEMP_PARAM_6, CONF_SG_TEMP_PARAM_7, CONF_SG_TEMP_PARAM_8, CONF_SG_TEMP_PARAM_9, CONF_SG_TEMP_PARAM_10, - CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1, - CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1, - + CONF_SG_PARAMS_MAX, CONF_SG_PARAMS_ALL = 0xff }; struct conf_sg_settings { - u32 sta_params[CONF_SG_STA_PARAMS_MAX]; - u32 ap_params[CONF_SG_AP_PARAMS_MAX]; + u32 params[CONF_SG_PARAMS_MAX]; u8 state; }; @@ -520,13 +416,17 @@ struct conf_rx_settings { u8 queue_type; }; -#define CONF_TX_MAX_RATE_CLASSES 8 +#define CONF_TX_MAX_RATE_CLASSES 10 #define CONF_TX_RATE_MASK_UNSPECIFIED 0 #define CONF_TX_RATE_MASK_BASIC (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS) #define CONF_TX_RATE_RETRY_LIMIT 10 +/* basic rates for p2p operations (probe req/resp, etc.) */ +#define CONF_TX_RATE_MASK_BASIC_P2P (CONF_HW_BIT_RATE_6MBPS | \ + CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS) + /* * Rates supported for data packets when operating as AP. Note the absence * of the 22Mbps rate. There is a FW limitation on 12 rates so we must drop @@ -545,6 +445,11 @@ struct conf_rx_settings { CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ CONF_HW_BIT_RATE_54MBPS) +#define CONF_TX_MCS_RATES (CONF_HW_BIT_RATE_MCS_0 | \ + CONF_HW_BIT_RATE_MCS_1 | CONF_HW_BIT_RATE_MCS_2 | \ + CONF_HW_BIT_RATE_MCS_3 | CONF_HW_BIT_RATE_MCS_4 | \ + CONF_HW_BIT_RATE_MCS_5 | CONF_HW_BIT_RATE_MCS_6 | \ + CONF_HW_BIT_RATE_MCS_7) /* * Default rates for management traffic when operating in AP mode. This @@ -553,12 +458,10 @@ struct conf_rx_settings { #define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS) -/* - * Default rates for working as IBSS. use 11b rates - */ +/* default rates for working as IBSS (11b and OFDM) */ #define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \ - CONF_HW_BIT_RATE_11MBPS); + CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES); struct conf_tx_rate_class { @@ -661,6 +564,9 @@ struct conf_tx_ac_category { #define CONF_TX_MAX_TID_COUNT 8 +/* Allow TX BA on all TIDs but 6,7. These are currently reserved in the FW */ +#define CONF_TX_BA_ENABLED_TID_BITMAP 0x3F + enum { CONF_CHANNEL_TYPE_DCF = 0, /* DC/LEGACY*/ CONF_CHANNEL_TYPE_EDCF = 1, /* EDCA*/ @@ -913,7 +819,7 @@ struct conf_conn_settings { struct conf_bcn_filt_rule bcn_filt_ie[CONF_MAX_BCN_FILT_IE_COUNT]; /* - * The number of consequtive beacons to lose, before the firmware + * The number of consecutive beacons to lose, before the firmware * becomes out of synch. * * Range: u32 @@ -951,7 +857,7 @@ struct conf_conn_settings { u8 rx_broadcast_in_ps; /* - * Consequtive PS Poll failures before sending event to driver + * Consecutive PS Poll failures before sending event to driver * * Range: u8 */ @@ -1012,14 +918,6 @@ struct conf_conn_settings { u8 psm_entry_nullfunc_retries; /* - * Specifies the time to linger in active mode after successfully - * transmitting the PSM entry null-func frame. - * - * Range 0 - 255 TU's - */ - u8 psm_entry_hangover_period; - - /* * * Specifies the interval of the connection keep-alive null-func * frame in ms. @@ -1199,8 +1097,12 @@ struct conf_rf_settings { }; struct conf_ht_setting { - u16 tx_ba_win_size; + u8 rx_ba_win_size; + u8 tx_ba_win_size; u16 inactivity_timeout; + + /* bitmap of enabled TIDs for TX BA sessions */ + u8 tx_ba_tid_bitmap; }; struct conf_memory_settings { @@ -1309,6 +1211,39 @@ struct conf_fwlog { u8 threshold; }; +#define ACX_RATE_MGMT_NUM_OF_RATES 13 +struct conf_rate_policy_settings { + u16 rate_retry_score; + u16 per_add; + u16 per_th1; + u16 per_th2; + u16 max_per; + u8 inverse_curiosity_factor; + u8 tx_fail_low_th; + u8 tx_fail_high_th; + u8 per_alpha_shift; + u8 per_add_shift; + u8 per_beta1_shift; + u8 per_beta2_shift; + u8 rate_check_up; + u8 rate_check_down; + u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES]; +}; + +struct conf_hangover_settings { + u32 recover_time; + u8 hangover_period; + u8 dynamic_mode; + u8 early_termination_mode; + u8 max_period; + u8 min_period; + u8 increase_delta; + u8 decrease_delta; + u8 quiet_time; + u8 increase_time; + u8 window_size; +}; + struct conf_drv_settings { struct conf_sg_settings sg; struct conf_rx_settings rx; @@ -1326,6 +1261,8 @@ struct conf_drv_settings { struct conf_fm_coex fm_coex; struct conf_rx_streaming_settings rx_streaming; struct conf_fwlog fwlog; + struct conf_rate_policy_settings rate; + struct conf_hangover_settings hangover; u8 hci_io_ds; }; diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c index 37934b5601cd..3999fd528302 100644 --- a/drivers/net/wireless/wl12xx/debugfs.c +++ b/drivers/net/wireless/wl12xx/debugfs.c @@ -265,18 +265,10 @@ static ssize_t gpio_power_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) { - return -EFAULT; - } - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in gpio_power"); return -EINVAL; @@ -339,10 +331,11 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, #define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x") DRIVER_STATE_PRINT_INT(tx_blocks_available); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks[0]); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks[1]); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks[2]); - DRIVER_STATE_PRINT_INT(tx_allocated_blocks[3]); + DRIVER_STATE_PRINT_INT(tx_allocated_blocks); + DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]); + DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]); + DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]); + DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]); DRIVER_STATE_PRINT_INT(tx_frames_cnt); DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]); DRIVER_STATE_PRINT_INT(tx_queue_count[0]); @@ -352,10 +345,7 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(tx_packets_count); DRIVER_STATE_PRINT_INT(tx_results_count); DRIVER_STATE_PRINT_LHEX(flags); - DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]); - DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]); - DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]); - DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]); + DRIVER_STATE_PRINT_INT(tx_blocks_freed); DRIVER_STATE_PRINT_INT(tx_security_last_seq_lsb); DRIVER_STATE_PRINT_INT(rx_counter); DRIVER_STATE_PRINT_INT(session_counter); @@ -369,9 +359,6 @@ static ssize_t driver_state_read(struct file *file, char __user *user_buf, DRIVER_STATE_PRINT_INT(beacon_int); DRIVER_STATE_PRINT_INT(psm_entry_retry); DRIVER_STATE_PRINT_INT(ps_poll_failures); - DRIVER_STATE_PRINT_HEX(filters); - DRIVER_STATE_PRINT_HEX(rx_config); - DRIVER_STATE_PRINT_HEX(rx_filter); DRIVER_STATE_PRINT_INT(power_level); DRIVER_STATE_PRINT_INT(rssi_thold); DRIVER_STATE_PRINT_INT(last_rssi_event); @@ -432,17 +419,10 @@ static ssize_t dtim_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value for dtim_interval"); return -EINVAL; @@ -497,17 +477,10 @@ static ssize_t beacon_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value for beacon_interval"); return -EINVAL; @@ -547,17 +520,10 @@ static ssize_t rx_streaming_interval_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in rx_streaming_interval!"); return -EINVAL; @@ -606,17 +572,10 @@ static ssize_t rx_streaming_always_write(struct file *file, size_t count, loff_t *ppos) { struct wl1271 *wl = file->private_data; - char buf[10]; - size_t len; unsigned long value; int ret; - len = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, user_buf, len)) - return -EFAULT; - buf[len] = '\0'; - - ret = kstrtoul(buf, 0, &value); + ret = kstrtoul_from_user(user_buf, count, 10, &value); if (ret < 0) { wl1271_warning("illegal value in rx_streaming_write!"); return -EINVAL; @@ -660,6 +619,47 @@ static const struct file_operations rx_streaming_always_ops = { .llseek = default_llseek, }; +static ssize_t beacon_filtering_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + char buf[10]; + size_t len; + unsigned long value; + int ret; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + buf[len] = '\0'; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value for beacon_filtering!"); + return -EINVAL; + } + + mutex_lock(&wl->mutex); + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_beacon_filter_opt(wl, !!value); + + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations beacon_filtering_ops = { + .write = beacon_filtering_write, + .open = wl1271_open_file_generic, + .llseek = default_llseek, +}; + static int wl1271_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -772,6 +772,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(driver_state, rootdir); DEBUGFS_ADD(dtim_interval, rootdir); DEBUGFS_ADD(beacon_interval, rootdir); + DEBUGFS_ADD(beacon_filtering, rootdir); streaming = debugfs_create_dir("rx_streaming", rootdir); if (!streaming || IS_ERR(streaming)) diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c index 304aaa2ee011..674ad2a9e409 100644 --- a/drivers/net/wireless/wl12xx/event.c +++ b/drivers/net/wireless/wl12xx/event.c @@ -171,19 +171,26 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl, wl->last_rssi_event = event; } -static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed) +static void wl1271_stop_ba_event(struct wl1271 *wl) { - /* Convert the value to bool */ - wl->ba_allowed = !!ba_allowed; - - /* - * Return in case: - * there are not BA open or the event indication is to allowed BA - */ - if ((!wl->ba_rx_bitmap) || (wl->ba_allowed)) - return; + if (wl->bss_type != BSS_TYPE_AP_BSS) { + if (!wl->ba_rx_bitmap) + return; + ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, + wl->bssid); + } else { + int i; + struct wl1271_link *lnk; + for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) { + lnk = &wl->links[i]; + if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap) + continue; - ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid); + ieee80211_stop_rx_ba_session(wl->vif, + lnk->ba_bitmap, + lnk->addr); + } + } } static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl, @@ -283,15 +290,32 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) wl1271_event_rssi_trigger(wl, mbox); } - if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) { + if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. " - "ba_allowed = 0x%x", mbox->ba_allowed); + "ba_allowed = 0x%x", mbox->rx_ba_allowed); - if (wl->vif) - wl1271_stop_ba_event(wl, mbox->ba_allowed); + wl->ba_allowed = !!mbox->rx_ba_allowed; + + if (wl->vif && !wl->ba_allowed) + wl1271_stop_ba_event(wl); + } + + if ((vector & CHANNEL_SWITCH_COMPLETE_EVENT_ID) && !is_ap) { + wl1271_debug(DEBUG_EVENT, "CHANNEL_SWITCH_COMPLETE_EVENT_ID. " + "status = 0x%x", + mbox->channel_switch_status); + /* + * That event uses for two cases: + * 1) channel switch complete with status=0 + * 2) channel switch failed status=1 + */ + if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags) && + (wl->vif)) + ieee80211_chswitch_done(wl->vif, + mbox->channel_switch_status ? false : true); } - if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) { + if ((vector & DUMMY_PACKET_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); if (wl->vif) wl1271_tx_dummy_packet(wl); diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h index e524ad6fe4e3..49c1a0ede5b1 100644 --- a/drivers/net/wireless/wl12xx/event.h +++ b/drivers/net/wireless/wl12xx/event.h @@ -49,32 +49,27 @@ enum { MEASUREMENT_START_EVENT_ID = BIT(8), MEASUREMENT_COMPLETE_EVENT_ID = BIT(9), SCAN_COMPLETE_EVENT_ID = BIT(10), - SCHEDULED_SCAN_COMPLETE_EVENT_ID = BIT(11), + WFD_DISCOVERY_COMPLETE_EVENT_ID = BIT(11), AP_DISCOVERY_COMPLETE_EVENT_ID = BIT(12), PS_REPORT_EVENT_ID = BIT(13), PSPOLL_DELIVERY_FAILURE_EVENT_ID = BIT(14), DISCONNECT_EVENT_COMPLETE_ID = BIT(15), - JOIN_EVENT_COMPLETE_ID = BIT(16), + /* BIT(16) is reserved */ CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17), BSS_LOSE_EVENT_ID = BIT(18), REGAINED_BSS_EVENT_ID = BIT(19), MAX_TX_RETRY_EVENT_ID = BIT(20), - /* STA: dummy paket for dynamic mem blocks */ - DUMMY_PACKET_EVENT_ID = BIT(21), - /* AP: STA remove complete */ - STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), + DUMMY_PACKET_EVENT_ID = BIT(21), SOFT_GEMINI_SENSE_EVENT_ID = BIT(22), - /* STA: SG prediction */ - SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23), - /* AP: Inactive STA */ - INACTIVE_STA_EVENT_ID = BIT(23), + CHANGE_AUTO_MODE_TIMEOUT_EVENT_ID = BIT(23), SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24), PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25), - DBG_EVENT_ID = BIT(26), - HEALTH_CHECK_REPLY_EVENT_ID = BIT(27), + INACTIVE_STA_EVENT_ID = BIT(26), + PEER_REMOVE_COMPLETE_EVENT_ID = BIT(27), PERIODIC_SCAN_COMPLETE_EVENT_ID = BIT(28), PERIODIC_SCAN_REPORT_EVENT_ID = BIT(29), BA_SESSION_RX_CONSTRAINT_EVENT_ID = BIT(30), + REMAIN_ON_CHANNEL_COMPLETE_EVENT_ID = BIT(31), EVENT_MBOX_ALL_EVENT_ID = 0x7fffffff, }; @@ -83,15 +78,6 @@ enum { EVENT_ENTER_POWER_SAVE_SUCCESS, }; -struct event_debug_report { - u8 debug_event_id; - u8 num_params; - __le16 pad; - __le32 report_1; - __le32 report_2; - __le32 report_3; -} __packed; - #define NUM_OF_RSSI_SNR_TRIGGERS 8 struct event_mailbox { @@ -100,49 +86,45 @@ struct event_mailbox { __le32 reserved_1; __le32 reserved_2; - u8 dbg_event_id; - u8 num_relevant_params; - __le16 reserved_3; - __le32 event_report_p1; - __le32 event_report_p2; - __le32 event_report_p3; - u8 number_of_scan_results; u8 scan_tag; - u8 reserved_4[2]; - __le32 compl_scheduled_scan_status; + u8 completed_scan_status; + u8 reserved_3; - __le16 scheduled_scan_attended_channels; u8 soft_gemini_sense_info; u8 soft_gemini_protective_info; s8 rssi_snr_trigger_metric[NUM_OF_RSSI_SNR_TRIGGERS]; u8 channel_switch_status; u8 scheduled_scan_status; u8 ps_status; + /* tuned channel (roc) */ + u8 roc_channel; - /* AP FW only */ - u8 hlid_removed; + __le16 hlid_removed_bitmap; - /* a bitmap of hlids for stations that have been inactive too long */ + /* bitmap of aged stations (by HLID) */ __le16 sta_aging_status; - /* a bitmap of hlids for stations which didn't respond to TX */ + /* bitmap of stations (by HLID) which exceeded max tx retries */ __le16 sta_tx_retry_exceeded; - /* - * Bitmap, Each bit set represents the Role ID for which this constraint - * is set. Range: 0 - FF, FF means ANY role - */ - u8 ba_role_id; - /* - * Bitmap, Each bit set represents the Link ID for which this constraint - * is set. Not applicable if ba_role_id is set to ANY role (FF). - * Range: 0 - FFFF, FFFF means ANY link in that role - */ - u8 ba_link_id; - u8 ba_allowed; - - u8 reserved_5[21]; + /* discovery completed results */ + u8 discovery_tag; + u8 number_of_preq_results; + u8 number_of_prsp_results; + u8 reserved_5; + + /* rx ba constraint */ + u8 role_id; /* 0xFF means any role. */ + u8 rx_ba_allowed; + u8 reserved_6[2]; + + u8 ps_poll_delivery_failure_role_ids; + u8 stopped_role_ids; + u8 started_role_ids; + u8 change_auto_mode_timeout; + + u8 reserved_7[12]; } __packed; int wl1271_event_unmask(struct wl1271 *wl); diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index c3e9a2e4410e..04db64c94e9a 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c @@ -39,13 +39,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) /* send empty templates for fw memory reservation */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, + WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, - NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0, + NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; @@ -70,15 +70,13 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, - sizeof - (struct wl12xx_probe_resp_template), + WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template), + WL1271_CMD_TEMPL_DFLT_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; @@ -92,7 +90,7 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl) for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, - WL1271_CMD_TEMPL_MAX_SIZE, i, + WL1271_CMD_TEMPL_DFLT_SIZE, i, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; @@ -105,6 +103,7 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl) { struct wl12xx_disconn_template *tmpl; int ret; + u32 rate; tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); if (!tmpl) { @@ -115,9 +114,9 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl) tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_DEAUTH); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, - tmpl, sizeof(*tmpl), 0, - wl1271_tx_min_rate_get(wl)); + tmpl, sizeof(*tmpl), 0, rate); out: kfree(tmpl); @@ -128,6 +127,7 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl) { struct ieee80211_hdr_3addr *nullfunc; int ret; + u32 rate; nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); if (!nullfunc) { @@ -144,9 +144,9 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl) memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN); memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, - sizeof(*nullfunc), 0, - wl1271_tx_min_rate_get(wl)); + sizeof(*nullfunc), 0, rate); out: kfree(nullfunc); @@ -157,6 +157,7 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) { struct ieee80211_qos_hdr *qosnull; int ret; + u32 rate; qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); if (!qosnull) { @@ -173,9 +174,9 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN); memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN); + rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, - sizeof(*qosnull), 0, - wl1271_tx_min_rate_get(wl)); + sizeof(*qosnull), 0, rate); out: kfree(qosnull); @@ -191,15 +192,13 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl) * reserve memory for later. */ ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, - sizeof - (struct wl12xx_probe_resp_template), + WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, - sizeof - (struct wl12xx_beacon_template), + WL1271_CMD_TEMPL_MAX_SIZE, 0, WL1271_RATE_AUTOMATIC); if (ret < 0) return ret; @@ -227,7 +226,7 @@ static int wl1271_ap_init_templates_config(struct wl1271 *wl) return 0; } -static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) +static int wl12xx_init_rx_config(struct wl1271 *wl) { int ret; @@ -235,10 +234,6 @@ static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) if (ret < 0) return ret; - ret = wl1271_acx_rx_config(wl, config, filter); - if (ret < 0) - return ret; - return 0; } @@ -285,10 +280,7 @@ int wl1271_init_pta(struct wl1271 *wl) { int ret; - if (wl->bss_type == BSS_TYPE_AP_BSS) - ret = wl1271_acx_ap_sg_cfg(wl); - else - ret = wl1271_acx_sta_sg_cfg(wl); + ret = wl12xx_acx_sg_cfg(wl); if (ret < 0) return ret; @@ -392,7 +384,7 @@ static int wl1271_sta_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_sta_mem_cfg(wl); + ret = wl12xx_acx_mem_cfg(wl); if (ret < 0) return ret; @@ -408,12 +400,6 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl) { int ret, i; - ret = wl1271_cmd_set_sta_default_wep_key(wl, wl->default_key); - if (ret < 0) { - wl1271_warning("couldn't set default key"); - return ret; - } - /* disable all keep-alive templates */ for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { ret = wl1271_acx_keep_alive_config(wl, i, @@ -451,7 +437,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl) if (ret < 0) return ret; - ret = wl1271_acx_ap_mem_cfg(wl); + ret = wl12xx_acx_mem_cfg(wl); if (ret < 0) return ret; @@ -483,7 +469,7 @@ int wl1271_ap_init_templates(struct wl1271 *wl) * when operating as AP we want to receive external beacons for * configuring ERP protection. */ - ret = wl1271_acx_set_ap_beacon_filter(wl, false); + ret = wl1271_acx_beacon_filter_opt(wl, false); if (ret < 0) return ret; @@ -515,7 +501,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl) return ret; /* use the min basic rate for AP broadcast/multicast */ - rc.enabled_rates = wl1271_tx_min_rate_get(wl); + rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); rc.short_retry_limit = 10; rc.long_retry_limit = 10; rc.aflags = 0; @@ -532,6 +518,9 @@ int wl1271_init_ap_rates(struct wl1271 *wl) else supported_rates = CONF_TX_AP_ENABLED_RATES; + /* unconditionally enable HT rates */ + supported_rates |= CONF_TX_MCS_RATES; + /* configure unicast TX rate classes */ for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { rc.enabled_rates = supported_rates; @@ -546,41 +535,24 @@ int wl1271_init_ap_rates(struct wl1271 *wl) return 0; } -static void wl1271_check_ba_support(struct wl1271 *wl) -{ - /* validate FW cose ver x.x.x.50-60.x */ - if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) && - (wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) { - wl->ba_support = true; - return; - } - - wl->ba_support = false; -} - static int wl1271_set_ba_policies(struct wl1271 *wl) { - u8 tid_index; - int ret = 0; - /* Reset the BA RX indicators */ wl->ba_rx_bitmap = 0; wl->ba_allowed = true; + wl->ba_rx_session_count = 0; - /* validate that FW support BA */ - wl1271_check_ba_support(wl); + /* BA is supported in STA/AP modes */ + if (wl->bss_type != BSS_TYPE_AP_BSS && + wl->bss_type != BSS_TYPE_STA_BSS) { + wl->ba_support = false; + return 0; + } - if (wl->ba_support) - /* 802.11n initiator BA session setting */ - for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT; - ++tid_index) { - ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR, - tid_index, true); - if (ret < 0) - break; - } + wl->ba_support = true; - return ret; + /* 802.11n initiator BA session setting */ + return wl12xx_acx_set_ba_initiator_policy(wl); } int wl1271_chip_specific_init(struct wl1271 *wl) @@ -650,11 +622,7 @@ int wl1271_hw_init(struct wl1271 *wl) return ret; /* RX config */ - ret = wl1271_init_rx_config(wl, - RX_CFG_PROMISCUOUS | RX_CFG_TSF, - RX_FILTER_OPTION_DEF); - /* RX_CONFIG_OPTION_ANY_DST_ANY_BSS, - RX_FILTER_OPTION_FILTER_ALL); */ + ret = wl12xx_init_rx_config(wl); if (ret < 0) goto out_free_memmap; @@ -733,11 +701,20 @@ int wl1271_hw_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; + ret = wl12xx_acx_set_rate_mgmt_params(wl); + if (ret < 0) + goto out_free_memmap; + /* Configure initiator BA sessions policies */ ret = wl1271_set_ba_policies(wl); if (ret < 0) goto out_free_memmap; + /* configure hangover */ + ret = wl12xx_acx_config_hangover(wl); + if (ret < 0) + goto out_free_memmap; + return 0; out_free_memmap: diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index a2fe4f506ada..e839341dfafe 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -186,6 +186,5 @@ int wl1271_free_hw(struct wl1271 *wl); irqreturn_t wl1271_irq(int irq, void *data); bool wl1271_set_block_size(struct wl1271 *wl); int wl1271_tx_dummy_packet(struct wl1271 *wl); -void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters); #endif diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index b70ae40ad660..884f82b63219 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c @@ -52,110 +52,67 @@ static struct conf_drv_settings default_conf = { .sg = { - .sta_params = { - [CONF_SG_BT_PER_THRESHOLD] = 7500, - [CONF_SG_HV3_MAX_OVERRIDE] = 0, - [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, - [CONF_SG_BT_LOAD_RATIO] = 200, - [CONF_SG_AUTO_PS_MODE] = 1, - [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, - [CONF_SG_ANTENNA_CONFIGURATION] = 0, - [CONF_SG_BEACON_MISS_PERCENT] = 60, - [CONF_SG_RATE_ADAPT_THRESH] = 12, - [CONF_SG_RATE_ADAPT_SNR] = 0, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 30, - [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 8, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 50, - /* Note: with UPSD, this should be 4 */ - [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 8, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 20, - /* Note: with UPDS, this should be 15 */ - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, - /* Note: with UPDS, this should be 50 */ - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 40, - /* Note: with UPDS, this should be 10 */ - [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 20, - [CONF_SG_RXT] = 1200, - [CONF_SG_TXT] = 1000, - [CONF_SG_ADAPTIVE_RXT_TXT] = 1, - [CONF_SG_PS_POLL_TIMEOUT] = 10, - [CONF_SG_UPSD_TIMEOUT] = 10, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8, - [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800, - [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75, - [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15, - [CONF_SG_HV3_MAX_SERVED] = 6, - [CONF_SG_DHCP_TIME] = 5000, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, - }, - .ap_params = { - [CONF_SG_BT_PER_THRESHOLD] = 7500, - [CONF_SG_HV3_MAX_OVERRIDE] = 0, - [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400, - [CONF_SG_BT_LOAD_RATIO] = 50, - [CONF_SG_AUTO_PS_MODE] = 1, - [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, - [CONF_SG_ANTENNA_CONFIGURATION] = 0, - [CONF_SG_BEACON_MISS_PERCENT] = 60, - [CONF_SG_RATE_ADAPT_THRESH] = 64, - [CONF_SG_RATE_ADAPT_SNR] = 1, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7, - [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8, - [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25, - [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25, - [CONF_SG_RXT] = 1200, - [CONF_SG_TXT] = 1000, - [CONF_SG_ADAPTIVE_RXT_TXT] = 1, - [CONF_SG_PS_POLL_TIMEOUT] = 10, - [CONF_SG_UPSD_TIMEOUT] = 10, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8, - [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20, - [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50, - [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, - [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800, - [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75, - [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15, - [CONF_SG_HV3_MAX_SERVED] = 6, - [CONF_SG_DHCP_TIME] = 5000, - [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, - [CONF_SG_TEMP_PARAM_1] = 0, - [CONF_SG_TEMP_PARAM_2] = 0, - [CONF_SG_TEMP_PARAM_3] = 0, - [CONF_SG_TEMP_PARAM_4] = 0, - [CONF_SG_TEMP_PARAM_5] = 0, - [CONF_SG_AP_BEACON_MISS_TX] = 3, - [CONF_SG_RX_WINDOW_LENGTH] = 6, - [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50, - [CONF_SG_TEMP_PARAM_6] = 1, + .params = { + [CONF_SG_ACL_BT_MASTER_MIN_BR] = 10, + [CONF_SG_ACL_BT_MASTER_MAX_BR] = 180, + [CONF_SG_ACL_BT_SLAVE_MIN_BR] = 10, + [CONF_SG_ACL_BT_SLAVE_MAX_BR] = 180, + [CONF_SG_ACL_BT_MASTER_MIN_EDR] = 10, + [CONF_SG_ACL_BT_MASTER_MAX_EDR] = 80, + [CONF_SG_ACL_BT_SLAVE_MIN_EDR] = 10, + [CONF_SG_ACL_BT_SLAVE_MAX_EDR] = 80, + [CONF_SG_ACL_WLAN_PS_MASTER_BR] = 8, + [CONF_SG_ACL_WLAN_PS_SLAVE_BR] = 8, + [CONF_SG_ACL_WLAN_PS_MASTER_EDR] = 20, + [CONF_SG_ACL_WLAN_PS_SLAVE_EDR] = 20, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_BR] = 20, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_BR] = 35, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_BR] = 16, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_BR] = 35, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MIN_EDR] = 32, + [CONF_SG_ACL_WLAN_ACTIVE_MASTER_MAX_EDR] = 50, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MIN_EDR] = 28, + [CONF_SG_ACL_WLAN_ACTIVE_SLAVE_MAX_EDR] = 50, + [CONF_SG_ACL_ACTIVE_SCAN_WLAN_BR] = 10, + [CONF_SG_ACL_ACTIVE_SCAN_WLAN_EDR] = 20, + [CONF_SG_ACL_PASSIVE_SCAN_BT_BR] = 75, + [CONF_SG_ACL_PASSIVE_SCAN_WLAN_BR] = 15, + [CONF_SG_ACL_PASSIVE_SCAN_BT_EDR] = 27, + [CONF_SG_ACL_PASSIVE_SCAN_WLAN_EDR] = 17, + /* active scan params */ + [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50, + [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100, + /* passive scan params */ + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_BR] = 800, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP_EDR] = 200, + [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200, + /* passive scan in dual antenna params */ + [CONF_SG_CONSECUTIVE_HV3_IN_PASSIVE_SCAN] = 0, + [CONF_SG_BCN_HV3_COLLISION_THRESH_IN_PASSIVE_SCAN] = 0, + [CONF_SG_TX_RX_PROTECTION_BWIDTH_IN_PASSIVE_SCAN] = 0, + /* general params */ + [CONF_SG_STA_FORCE_PS_IN_BT_SCO] = 1, + [CONF_SG_ANTENNA_CONFIGURATION] = 0, + [CONF_SG_BEACON_MISS_PERCENT] = 60, + [CONF_SG_DHCP_TIME] = 5000, + [CONF_SG_RXT] = 1200, + [CONF_SG_TXT] = 1000, + [CONF_SG_ADAPTIVE_RXT_TXT] = 1, + [CONF_SG_GENERAL_USAGE_BIT_MAP] = 3, + [CONF_SG_HV3_MAX_SERVED] = 6, + [CONF_SG_PS_POLL_TIMEOUT] = 10, + [CONF_SG_UPSD_TIMEOUT] = 10, + [CONF_SG_CONSECUTIVE_CTS_THRESHOLD] = 2, + [CONF_SG_STA_RX_WINDOW_AFTER_DTIM] = 5, + [CONF_SG_STA_CONNECTION_PROTECTION_TIME] = 30, + /* AP params */ + [CONF_AP_BEACON_MISS_TX] = 3, + [CONF_AP_RX_WINDOW_AFTER_BEACON] = 10, + [CONF_AP_BEACON_WINDOW_INTERVAL] = 2, + [CONF_AP_CONNECTION_PROTECTION_TIME] = 0, + [CONF_AP_BT_ACL_VAL_BT_SERVE_TIME] = 25, + [CONF_AP_BT_ACL_VAL_WL_SERVE_TIME] = 25, }, .state = CONF_SG_PROTECTIVE, }, @@ -279,10 +236,9 @@ static struct conf_drv_settings default_conf = { .ps_poll_recovery_period = 700, .bet_enable = CONF_BET_MODE_ENABLE, .bet_max_consecutive = 50, - .psm_entry_retries = 5, + .psm_entry_retries = 8, .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, - .psm_entry_hangover_period = 1, .keep_alive_interval = 55000, .max_listen_interval = 20, }, @@ -310,8 +266,8 @@ static struct conf_drv_settings default_conf = { }, .sched_scan = { /* sched_scan requires dwell times in TU instead of TU/1000 */ - .min_dwell_time_active = 8, - .max_dwell_time_active = 30, + .min_dwell_time_active = 30, + .max_dwell_time_active = 60, .dwell_time_passive = 100, .dwell_time_dfs = 150, .num_probe_reqs = 2, @@ -329,8 +285,10 @@ static struct conf_drv_settings default_conf = { }, }, .ht = { + .rx_ba_win_size = 8, .tx_ba_win_size = 64, .inactivity_timeout = 10000, + .tx_ba_tid_bitmap = CONF_TX_BA_ENABLED_TID_BITMAP, }, .mem_wl127x = { .num_stations = 1, @@ -379,9 +337,44 @@ static struct conf_drv_settings default_conf = { .threshold = 0, }, .hci_io_ds = HCI_IO_DS_6MA, + .rate = { + .rate_retry_score = 32000, + .per_add = 8192, + .per_th1 = 2048, + .per_th2 = 4096, + .max_per = 8100, + .inverse_curiosity_factor = 5, + .tx_fail_low_th = 4, + .tx_fail_high_th = 10, + .per_alpha_shift = 4, + .per_add_shift = 13, + .per_beta1_shift = 10, + .per_beta2_shift = 8, + .rate_check_up = 2, + .rate_check_down = 12, + .rate_retry_policy = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + }, + }, + .hangover = { + .recover_time = 0, + .hangover_period = 20, + .dynamic_mode = 1, + .early_termination_mode = 1, + .max_period = 20, + .min_period = 1, + .increase_delta = 1, + .decrease_delta = 2, + .quiet_time = 4, + .increase_time = 1, + .window_size = 16, + }, }; static char *fwlog_param; +static bool bug_on_recovery; static void __wl1271_op_remove_interface(struct wl1271 *wl, bool reset_tx_queues); @@ -415,10 +408,12 @@ static int wl1271_check_operstate(struct wl1271 *wl, unsigned char operstate) if (test_and_set_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags)) return 0; - ret = wl1271_cmd_set_sta_state(wl); + ret = wl12xx_cmd_set_peer_state(wl, wl->sta_hlid); if (ret < 0) return ret; + wl12xx_croc(wl, wl->role_id); + wl1271_info("Association completed."); return 0; } @@ -718,7 +713,7 @@ static int wl1271_plt_init(struct wl1271 *wl) if (ret < 0) goto out_free_memmap; - ret = wl1271_acx_sta_mem_cfg(wl); + ret = wl12xx_acx_mem_cfg(wl); if (ret < 0) goto out_free_memmap; @@ -773,33 +768,52 @@ static int wl1271_plt_init(struct wl1271 *wl) return ret; } -static void wl1271_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_blks) +static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts) { - bool fw_ps; + bool fw_ps, single_sta; /* only regulate station links */ if (hlid < WL1271_AP_STA_HLID_START) return; fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); + single_sta = (wl->active_sta_count == 1); /* * Wake up from high level PS if the STA is asleep with too little - * blocks in FW or if the STA is awake. + * packets in FW or if the STA is awake. */ - if (!fw_ps || tx_blks < WL1271_PS_STA_MAX_BLOCKS) + if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_end(wl, hlid); - /* Start high-level PS if the STA is asleep with enough blocks in FW */ - else if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) + /* + * Start high-level PS if the STA is asleep with enough blocks in FW. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. + */ + else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } -static void wl1271_irq_update_links_status(struct wl1271 *wl, - struct wl1271_fw_ap_status *status) +bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) +{ + int id; + + /* global/broadcast "stations" are always active */ + if (hlid < WL1271_AP_STA_HLID_START) + return true; + + id = hlid - WL1271_AP_STA_HLID_START; + return test_bit(id, wl->ap_hlid_map); +} + +static void wl12xx_irq_update_links_status(struct wl1271 *wl, + struct wl12xx_fw_status *status) { u32 cur_fw_ps_map; - u8 hlid; + u8 hlid, cnt; + + /* TODO: also use link_fast_bitmap here */ cur_fw_ps_map = le32_to_cpu(status->link_ps_bitmap); if (wl->ap_fw_ps_map != cur_fw_ps_map) { @@ -812,45 +826,30 @@ static void wl1271_irq_update_links_status(struct wl1271 *wl, } for (hlid = WL1271_AP_STA_HLID_START; hlid < AP_MAX_LINKS; hlid++) { - u8 cnt = status->tx_lnk_free_blks[hlid] - - wl->links[hlid].prev_freed_blks; - - wl->links[hlid].prev_freed_blks = - status->tx_lnk_free_blks[hlid]; - wl->links[hlid].allocated_blks -= cnt; - - wl1271_irq_ps_regulate_link(wl, hlid, - wl->links[hlid].allocated_blks); - } -} + if (!wl1271_is_active_sta(wl, hlid)) + continue; -static u32 wl1271_tx_allocated_blocks(struct wl1271 *wl) -{ - int i; - u32 total_alloc_blocks = 0; + cnt = status->tx_lnk_free_pkts[hlid] - + wl->links[hlid].prev_freed_pkts; - for (i = 0; i < NUM_TX_QUEUES; i++) - total_alloc_blocks += wl->tx_allocated_blocks[i]; + wl->links[hlid].prev_freed_pkts = + status->tx_lnk_free_pkts[hlid]; + wl->links[hlid].allocated_pkts -= cnt; - return total_alloc_blocks; + wl12xx_irq_ps_regulate_link(wl, hlid, + wl->links[hlid].allocated_pkts); + } } -static void wl1271_fw_status(struct wl1271 *wl, - struct wl1271_fw_full_status *full_status) +static void wl12xx_fw_status(struct wl1271 *wl, + struct wl12xx_fw_status *status) { - struct wl1271_fw_common_status *status = &full_status->common; struct timespec ts; u32 old_tx_blk_count = wl->tx_blocks_available; - u32 freed_blocks = 0, ac_freed_blocks; + int avail, freed_blocks; int i; - if (wl->bss_type == BSS_TYPE_AP_BSS) { - wl1271_raw_read(wl, FW_STATUS_ADDR, status, - sizeof(struct wl1271_fw_ap_status), false); - } else { - wl1271_raw_read(wl, FW_STATUS_ADDR, status, - sizeof(struct wl1271_fw_sta_status), false); - } + wl1271_raw_read(wl, FW_STATUS_ADDR, status, sizeof(*status), false); wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " "drv_rx_counter = %d, tx_results_counter = %d)", @@ -859,42 +858,49 @@ static void wl1271_fw_status(struct wl1271 *wl, status->drv_rx_counter, status->tx_results_counter); - /* update number of available TX blocks */ for (i = 0; i < NUM_TX_QUEUES; i++) { - ac_freed_blocks = le32_to_cpu(status->tx_released_blks[i]) - - wl->tx_blocks_freed[i]; - freed_blocks += ac_freed_blocks; - - wl->tx_allocated_blocks[i] -= ac_freed_blocks; + /* prevent wrap-around in freed-packets counter */ + wl->tx_allocated_pkts[i] -= + (status->tx_released_pkts[i] - + wl->tx_pkts_freed[i]) & 0xff; - wl->tx_blocks_freed[i] = - le32_to_cpu(status->tx_released_blks[i]); + wl->tx_pkts_freed[i] = status->tx_released_pkts[i]; } - if (wl->bss_type == BSS_TYPE_AP_BSS) { - /* Update num of allocated TX blocks per link and ps status */ - wl1271_irq_update_links_status(wl, &full_status->ap); - wl->tx_blocks_available += freed_blocks; - } else { - int avail = full_status->sta.tx_total - - wl1271_tx_allocated_blocks(wl); + /* prevent wrap-around in total blocks counter */ + if (likely(wl->tx_blocks_freed <= + le32_to_cpu(status->total_released_blks))) + freed_blocks = le32_to_cpu(status->total_released_blks) - + wl->tx_blocks_freed; + else + freed_blocks = 0x100000000LL - wl->tx_blocks_freed + + le32_to_cpu(status->total_released_blks); - /* - * The FW might change the total number of TX memblocks before - * we get a notification about blocks being released. Thus, the - * available blocks calculation might yield a temporary result - * which is lower than the actual available blocks. Keeping in - * mind that only blocks that were allocated can be moved from - * TX to RX, tx_blocks_available should never decrease here. - */ - wl->tx_blocks_available = max((int)wl->tx_blocks_available, - avail); - } + wl->tx_blocks_freed = le32_to_cpu(status->total_released_blks); + + wl->tx_allocated_blocks -= freed_blocks; + + avail = le32_to_cpu(status->tx_total) - wl->tx_allocated_blocks; + + /* + * The FW might change the total number of TX memblocks before + * we get a notification about blocks being released. Thus, the + * available blocks calculation might yield a temporary result + * which is lower than the actual available blocks. Keeping in + * mind that only blocks that were allocated can be moved from + * TX to RX, tx_blocks_available should never decrease here. + */ + wl->tx_blocks_available = max((int)wl->tx_blocks_available, + avail); /* if more blocks are available now, tx work can be scheduled */ if (wl->tx_blocks_available > old_tx_blk_count) clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); + /* for AP update num of allocated TX blocks per link and ps status */ + if (wl->bss_type == BSS_TYPE_AP_BSS) + wl12xx_irq_update_links_status(wl, status); + /* update the host-chipset time offset */ getnstimeofday(&ts); wl->time_offset = (timespec_to_ns(&ts) >> 10) - @@ -967,8 +973,8 @@ irqreturn_t wl1271_irq(int irq, void *cookie) clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); smp_mb__after_clear_bit(); - wl1271_fw_status(wl, wl->fw_status); - intr = le32_to_cpu(wl->fw_status->common.intr); + wl12xx_fw_status(wl, wl->fw_status); + intr = le32_to_cpu(wl->fw_status->intr); intr &= WL1271_INTR_MASK; if (!intr) { done = true; @@ -987,7 +993,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie) if (likely(intr & WL1271_ACX_INTR_DATA)) { wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); - wl1271_rx(wl, &wl->fw_status->common); + wl12xx_rx(wl, wl->fw_status); /* Check if any tx blocks were freed */ spin_lock_irqsave(&wl->wl_lock, flags); @@ -1004,7 +1010,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie) } /* check for tx results */ - if (wl->fw_status->common.tx_results_counter != + if (wl->fw_status->tx_results_counter != (wl->tx_results_count & 0xff)) wl1271_tx_complete(wl); @@ -1056,25 +1062,10 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) const char *fw_name; int ret; - switch (wl->bss_type) { - case BSS_TYPE_AP_BSS: - if (wl->chip.id == CHIP_ID_1283_PG20) - fw_name = WL128X_AP_FW_NAME; - else - fw_name = WL127X_AP_FW_NAME; - break; - case BSS_TYPE_IBSS: - case BSS_TYPE_STA_BSS: - if (wl->chip.id == CHIP_ID_1283_PG20) - fw_name = WL128X_FW_NAME; - else - fw_name = WL1271_FW_NAME; - break; - default: - wl1271_error("no compatible firmware for bss_type %d", - wl->bss_type); - return -EINVAL; - } + if (wl->chip.id == CHIP_ID_1283_PG20) + fw_name = WL128X_FW_NAME; + else + fw_name = WL127X_FW_NAME; wl1271_debug(DEBUG_BOOT, "booting firmware %s", fw_name); @@ -1103,7 +1094,6 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) } memcpy(wl->fw, fw->data, wl->fw_len); - wl->fw_bss_type = wl->bss_type; ret = 0; out: @@ -1194,8 +1184,8 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) wl12xx_cmd_stop_fwlog(wl); /* Read the first memory block address */ - wl1271_fw_status(wl, wl->fw_status); - first_addr = __le32_to_cpu(wl->fw_status->sta.log_start_addr); + wl12xx_fw_status(wl, wl->fw_status); + first_addr = le32_to_cpu(wl->fw_status->log_start_addr); if (!first_addr) goto out; @@ -1211,7 +1201,7 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) * of each memory block hold the hardware address of the next * one. The last memory block points to the first one. */ - addr = __le32_to_cpup((__le32 *)block); + addr = le32_to_cpup((__le32 *)block); if (!wl12xx_copy_fwlog(wl, block + sizeof(addr), WL12XX_HW_BLOCK_SIZE - sizeof(addr))) break; @@ -1241,6 +1231,8 @@ static void wl1271_recovery_work(struct work_struct *work) wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x", wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4)); + BUG_ON(bug_on_recovery); + /* * Advance security sequence number to overcome potential progress * in the firmware during recovery. This doens't hurt if the network is @@ -1250,9 +1242,6 @@ static void wl1271_recovery_work(struct work_struct *work) test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING; - if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) - ieee80211_connection_loss(wl->vif); - /* Prevent spurious TX during FW restart */ ieee80211_stop_queues(wl->hw); @@ -1344,14 +1333,6 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", wl->chip.id); - /* - * 'end-of-transaction flag' and 'LPD mode flag' - * should be set in wl127x AP mode only - */ - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->quirks |= (WL12XX_QUIRK_END_OF_TRANSACTION | - WL12XX_QUIRK_LPD_MODE); - ret = wl1271_setup(wl); if (ret < 0) goto out; @@ -1374,8 +1355,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) goto out; } - /* Make sure the firmware type matches the BSS type */ - if (wl->fw == NULL || wl->fw_bss_type != wl->bss_type) { + if (wl->fw == NULL) { ret = wl1271_fetch_firmware(wl); if (ret < 0) goto out; @@ -1395,6 +1375,7 @@ out: int wl1271_plt_start(struct wl1271 *wl) { int retries = WL1271_BOOT_RETRIES; + struct wiphy *wiphy = wl->hw->wiphy; int ret; mutex_lock(&wl->mutex); @@ -1428,6 +1409,11 @@ int wl1271_plt_start(struct wl1271 *wl) wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver_str); + /* update hw/fw version info in wiphy struct */ + wiphy->hw_version = wl->chip.id; + strncpy(wiphy->fw_version, wl->chip.fw_ver_str, + sizeof(wiphy->fw_version)); + goto out; irq_disable: @@ -1504,10 +1490,25 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) q = wl1271_tx_get_queue(mapping); if (wl->bss_type == BSS_TYPE_AP_BSS) - hlid = wl1271_tx_get_hlid(skb); + hlid = wl12xx_tx_get_hlid_ap(wl, skb); spin_lock_irqsave(&wl->wl_lock, flags); + /* queue the packet */ + if (wl->bss_type == BSS_TYPE_AP_BSS) { + if (!wl1271_is_active_sta(wl, hlid)) { + wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", + hlid, q); + dev_kfree_skb(skb); + goto out; + } + + wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q); + skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); + } else { + skb_queue_tail(&wl->tx_queue[q], skb); + } + wl->tx_queue_count[q]++; /* @@ -1520,14 +1521,6 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) set_bit(q, &wl->stopped_queues_map); } - /* queue the packet */ - if (wl->bss_type == BSS_TYPE_AP_BSS) { - wl1271_debug(DEBUG_TX, "queue skb hlid %d q %d", hlid, q); - skb_queue_tail(&wl->links[hlid].tx_queue[q], skb); - } else { - skb_queue_tail(&wl->tx_queue[q], skb); - } - /* * The chip specific setup must run before the first TX packet - * before that, the tx_work will not be initialized! @@ -1537,13 +1530,20 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) !test_bit(WL1271_FLAG_TX_PENDING, &wl->flags)) ieee80211_queue_work(wl->hw, &wl->tx_work); +out: spin_unlock_irqrestore(&wl->wl_lock, flags); } int wl1271_tx_dummy_packet(struct wl1271 *wl) { unsigned long flags; - int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); + int q; + + /* no need to queue a new dummy packet if one is already pending */ + if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) + return 0; + + q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet)); spin_lock_irqsave(&wl->wl_lock, flags); set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); @@ -1673,7 +1673,7 @@ static int wl1271_configure_suspend_ap(struct wl1271 *wl) if (ret < 0) goto out_unlock; - ret = wl1271_acx_set_ap_beacon_filter(wl, true); + ret = wl1271_acx_beacon_filter_opt(wl, true); wl1271_ps_elp_sleep(wl); out_unlock: @@ -1711,7 +1711,7 @@ static void wl1271_configure_resume(struct wl1271 *wl) wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE, wl->basic_rate, true); } else if (is_ap) { - wl1271_acx_set_ap_beacon_filter(wl, false); + wl1271_acx_beacon_filter_opt(wl, false); } wl1271_ps_elp_sleep(wl); @@ -1803,9 +1803,6 @@ static int wl1271_op_start(struct ieee80211_hw *hw) * * The MAC address is first known when the corresponding interface * is added. That is where we will initialize the hardware. - * - * In addition, we currently have different firmwares for AP and managed - * operation. We will know which to boot according to interface type. */ return 0; @@ -1816,6 +1813,30 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); } +static u8 wl12xx_get_role_type(struct wl1271 *wl) +{ + switch (wl->bss_type) { + case BSS_TYPE_AP_BSS: + if (wl->p2p) + return WL1271_ROLE_P2P_GO; + else + return WL1271_ROLE_AP; + + case BSS_TYPE_STA_BSS: + if (wl->p2p) + return WL1271_ROLE_P2P_CL; + else + return WL1271_ROLE_STA; + + case BSS_TYPE_IBSS: + return WL1271_ROLE_IBSS; + + default: + wl1271_error("invalid bss_type: %d", wl->bss_type); + } + return WL12XX_INVALID_ROLE_TYPE; +} + static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1823,10 +1844,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, struct wiphy *wiphy = hw->wiphy; int retries = WL1271_BOOT_RETRIES; int ret = 0; + u8 role_type; bool booted = false; wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", - vif->type, vif->addr); + ieee80211_vif_type_p2p(vif), vif->addr); mutex_lock(&wl->mutex); if (wl->vif) { @@ -1846,7 +1868,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } - switch (vif->type) { + switch (ieee80211_vif_type_p2p(vif)) { + case NL80211_IFTYPE_P2P_CLIENT: + wl->p2p = 1; + /* fall-through */ case NL80211_IFTYPE_STATION: wl->bss_type = BSS_TYPE_STA_BSS; wl->set_bss_type = BSS_TYPE_STA_BSS; @@ -1855,6 +1880,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, wl->bss_type = BSS_TYPE_IBSS; wl->set_bss_type = BSS_TYPE_STA_BSS; break; + case NL80211_IFTYPE_P2P_GO: + wl->p2p = 1; + /* fall-through */ case NL80211_IFTYPE_AP: wl->bss_type = BSS_TYPE_AP_BSS; break; @@ -1863,6 +1891,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, goto out; } + role_type = wl12xx_get_role_type(wl); + if (role_type == WL12XX_INVALID_ROLE_TYPE) { + ret = -EINVAL; + goto out; + } memcpy(wl->mac_addr, vif->addr, ETH_ALEN); if (wl->state != WL1271_STATE_OFF) { @@ -1882,6 +1915,25 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, if (ret < 0) goto power_off; + if (wl->bss_type == BSS_TYPE_STA_BSS || + wl->bss_type == BSS_TYPE_IBSS) { + /* + * The device role is a special role used for + * rx and tx frames prior to association (as + * the STA role can get packets only from + * its associated bssid) + */ + ret = wl12xx_cmd_role_enable(wl, + WL1271_ROLE_DEVICE, + &wl->dev_role_id); + if (ret < 0) + goto irq_disable; + } + + ret = wl12xx_cmd_role_enable(wl, role_type, &wl->role_id); + if (ret < 0) + goto irq_disable; + ret = wl1271_hw_init(wl); if (ret < 0) goto irq_disable; @@ -1946,7 +1998,7 @@ out: static void __wl1271_op_remove_interface(struct wl1271 *wl, bool reset_tx_queues) { - int i; + int ret, i; wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); @@ -1971,6 +2023,31 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, ieee80211_scan_completed(wl->hw, true); } + if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { + /* disable active roles */ + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto deinit; + + if (wl->bss_type == BSS_TYPE_STA_BSS) { + ret = wl12xx_cmd_role_disable(wl, &wl->dev_role_id); + if (ret < 0) + goto deinit; + } + + ret = wl12xx_cmd_role_disable(wl, &wl->role_id); + if (ret < 0) + goto deinit; + + wl1271_ps_elp_sleep(wl); + } +deinit: + /* clear all hlids (except system_hlid) */ + wl->sta_hlid = WL12XX_INVALID_LINK_ID; + wl->dev_hlid = WL12XX_INVALID_LINK_ID; + wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; + wl->ap_global_hlid = WL12XX_INVALID_LINK_ID; + /* * this must be before the cancel_work calls below, so that the work * functions don't perform further work. @@ -1997,28 +2074,41 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, wl1271_power_off(wl); memset(wl->bssid, 0, ETH_ALEN); - memset(wl->ssid, 0, IW_ESSID_MAX_SIZE + 1); + memset(wl->ssid, 0, IEEE80211_MAX_SSID_LEN + 1); wl->ssid_len = 0; wl->bss_type = MAX_BSS_TYPE; wl->set_bss_type = MAX_BSS_TYPE; + wl->p2p = 0; wl->band = IEEE80211_BAND_2GHZ; wl->rx_counter = 0; wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->tx_blocks_available = 0; + wl->tx_allocated_blocks = 0; wl->tx_results_count = 0; wl->tx_packets_count = 0; wl->time_offset = 0; wl->session_counter = 0; wl->rate_set = CONF_TX_RATE_MASK_BASIC; + wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; + wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; wl->vif = NULL; - wl->filters = 0; + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; wl1271_free_ap_keys(wl); memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map)); wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; wl->sched_scanning = false; + wl->role_id = WL12XX_INVALID_ROLE_ID; + wl->dev_role_id = WL12XX_INVALID_ROLE_ID; + memset(wl->roles_map, 0, sizeof(wl->roles_map)); + memset(wl->links_map, 0, sizeof(wl->links_map)); + memset(wl->roc_map, 0, sizeof(wl->roc_map)); + wl->active_sta_count = 0; + + /* The system link is always allocated */ + __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); /* * this is performed after the cancel_work calls and the associated @@ -2027,9 +2117,11 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, */ wl->flags = 0; + wl->tx_blocks_freed = 0; + for (i = 0; i < NUM_TX_QUEUES; i++) { - wl->tx_blocks_freed[i] = 0; - wl->tx_allocated_blocks[i] = 0; + wl->tx_pkts_freed[i] = 0; + wl->tx_allocated_pkts[i] = 0; } wl1271_debugfs_reset(wl); @@ -2061,64 +2153,10 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, cancel_work_sync(&wl->recovery_work); } -void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) -{ - wl1271_set_default_filters(wl); - - /* combine requested filters with current filter config */ - filters = wl->filters | filters; - - wl1271_debug(DEBUG_FILTERS, "RX filters set: "); - - if (filters & FIF_PROMISC_IN_BSS) { - wl1271_debug(DEBUG_FILTERS, " - FIF_PROMISC_IN_BSS"); - wl->rx_config &= ~CFG_UNI_FILTER_EN; - wl->rx_config |= CFG_BSSID_FILTER_EN; - } - if (filters & FIF_BCN_PRBRESP_PROMISC) { - wl1271_debug(DEBUG_FILTERS, " - FIF_BCN_PRBRESP_PROMISC"); - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - wl->rx_config &= ~CFG_SSID_FILTER_EN; - } - if (filters & FIF_OTHER_BSS) { - wl1271_debug(DEBUG_FILTERS, " - FIF_OTHER_BSS"); - wl->rx_config &= ~CFG_BSSID_FILTER_EN; - } - if (filters & FIF_CONTROL) { - wl1271_debug(DEBUG_FILTERS, " - FIF_CONTROL"); - wl->rx_filter |= CFG_RX_CTL_EN; - } - if (filters & FIF_FCSFAIL) { - wl1271_debug(DEBUG_FILTERS, " - FIF_FCSFAIL"); - wl->rx_filter |= CFG_RX_FCS_ERROR; - } -} - -static int wl1271_dummy_join(struct wl1271 *wl) -{ - int ret = 0; - /* we need to use a dummy BSSID for now */ - static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, - 0xad, 0xbe, 0xef }; - - memcpy(wl->bssid, dummy_bssid, ETH_ALEN); - - /* pass through frames from all BSS */ - wl1271_configure_filters(wl, FIF_OTHER_BSS); - - ret = wl1271_cmd_join(wl, wl->set_bss_type); - if (ret < 0) - goto out; - - set_bit(WL1271_FLAG_JOINED, &wl->flags); - -out: - return ret; -} - static int wl1271_join(struct wl1271 *wl, bool set_assoc) { int ret; + bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS); /* * One of the side effects of the JOIN command is that is clears @@ -2135,12 +2173,13 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc) if (set_assoc) set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); - ret = wl1271_cmd_join(wl, wl->set_bss_type); + if (is_ibss) + ret = wl12xx_cmd_role_start_ibss(wl); + else + ret = wl12xx_cmd_role_start_sta(wl); if (ret < 0) goto out; - set_bit(WL1271_FLAG_JOINED, &wl->flags); - if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) goto out; @@ -2175,31 +2214,41 @@ static int wl1271_unjoin(struct wl1271 *wl) { int ret; + if (test_and_clear_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags)) { + wl12xx_cmd_stop_channel_switch(wl); + ieee80211_chswitch_done(wl->vif, false); + } + /* to stop listening to a channel, we disconnect */ - ret = wl1271_cmd_disconnect(wl); + ret = wl12xx_cmd_role_stop_sta(wl); if (ret < 0) goto out; - clear_bit(WL1271_FLAG_JOINED, &wl->flags); memset(wl->bssid, 0, ETH_ALEN); /* reset TX security counters on a clean disconnect */ wl->tx_security_last_seq_lsb = 0; wl->tx_security_seq = 0; - /* stop filtering packets based on bssid */ - wl1271_configure_filters(wl, FIF_OTHER_BSS); - out: return ret; } static void wl1271_set_band_rate(struct wl1271 *wl) { - if (wl->band == IEEE80211_BAND_2GHZ) - wl->basic_rate_set = wl->conf.tx.basic_rate; - else - wl->basic_rate_set = wl->conf.tx.basic_rate_5; + wl->basic_rate_set = wl->bitrate_masks[wl->band]; + wl->rate_set = wl->basic_rate_set; +} + +static bool wl12xx_is_roc(struct wl1271 *wl) +{ + u8 role_id; + + role_id = find_first_bit(wl->roc_map, WL12XX_MAX_ROLES); + if (role_id >= WL12XX_MAX_ROLES) + return false; + + return true; } static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) @@ -2207,12 +2256,17 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) int ret; if (idle) { - if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { - ret = wl1271_unjoin(wl); + /* no need to croc if we weren't busy (e.g. during boot) */ + if (wl12xx_is_roc(wl)) { + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_role_stop_dev(wl); if (ret < 0) goto out; } - wl->rate_set = wl1271_tx_min_rate_get(wl); + wl->rate_set = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -2223,18 +2277,17 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle) goto out; set_bit(WL1271_FLAG_IDLE, &wl->flags); } else { - /* increment the session counter */ - wl->session_counter++; - if (wl->session_counter >= SESSION_COUNTER_MAX) - wl->session_counter = 0; - /* The current firmware only supports sched_scan in idle */ if (wl->sched_scanning) { wl1271_scan_sched_scan_stop(wl); ieee80211_sched_scan_stopped(wl->hw); } - ret = wl1271_dummy_join(wl); + ret = wl12xx_cmd_role_start_dev(wl); + if (ret < 0) + goto out; + + ret = wl12xx_roc(wl, wl->dev_role_id); if (ret < 0) goto out; clear_bit(WL1271_FLAG_IDLE, &wl->flags); @@ -2295,6 +2348,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_CHANNEL && ((wl->band != conf->channel->band) || (wl->channel != channel))) { + /* send all pending packets */ + wl1271_tx_work_locked(wl); wl->band = conf->channel->band; wl->channel = channel; @@ -2308,17 +2363,41 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) wl1271_set_band_rate(wl); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) wl1271_warning("rate policy for channel " "failed %d", ret); - if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) { + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + if (wl12xx_is_roc(wl)) { + /* roaming */ + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out_sleep; + } ret = wl1271_join(wl, false); if (ret < 0) wl1271_warning("cmd join on channel " "failed %d", ret); + } else { + /* + * change the ROC channel. do it only if we are + * not idle. otherwise, CROC will be called + * anyway. + */ + if (wl12xx_is_roc(wl) && + !(conf->flags & IEEE80211_CONF_IDLE)) { + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out_sleep; + + ret = wl12xx_roc(wl, wl->dev_role_id); + if (ret < 0) + wl1271_warning("roc failed %d", + ret); + } } } } @@ -2458,18 +2537,11 @@ static void wl1271_op_configure_filter(struct ieee80211_hw *hw, goto out_sleep; } - /* determine, whether supported filter values have changed */ - if (changed == 0) - goto out_sleep; - - /* configure filters */ - wl->filters = *total; - wl1271_configure_filters(wl, 0); - - /* apply configured filters */ - ret = wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); - if (ret < 0) - goto out_sleep; + /* + * the fw doesn't provide an api to configure the filters. instead, + * the filters configuration is based on the active roles / ROC + * state. + */ out_sleep: wl1271_ps_elp_sleep(wl); @@ -2541,14 +2613,19 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl) bool wep_key_added = false; for (i = 0; i < MAX_NUM_KEYS; i++) { + u8 hlid; if (wl->recorded_ap_keys[i] == NULL) break; key = wl->recorded_ap_keys[i]; + hlid = key->hlid; + if (hlid == WL12XX_INVALID_LINK_ID) + hlid = wl->ap_bcast_hlid; + ret = wl1271_cmd_set_ap_key(wl, KEY_ADD_OR_REPLACE, key->id, key->key_type, key->key_size, key->key, - key->hlid, key->tx_seq_32, + hlid, key->tx_seq_32, key->tx_seq_16); if (ret < 0) goto out; @@ -2558,7 +2635,8 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl) } if (wep_key_added) { - ret = wl1271_cmd_set_ap_default_wep_key(wl, wl->default_key); + ret = wl12xx_cmd_set_default_wep_key(wl, wl->default_key, + wl->ap_bcast_hlid); if (ret < 0) goto out; } @@ -2583,7 +2661,7 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, wl_sta = (struct wl1271_station *)sta->drv_priv; hlid = wl_sta->hlid; } else { - hlid = WL1271_AP_BROADCAST_HLID; + hlid = wl->ap_bcast_hlid; } if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { @@ -2613,6 +2691,17 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + /* + * A STA set to GEM cipher requires 2 tx spare blocks. + * Return to default value when GEM cipher key is removed + */ + if (key_type == KEY_GEM) { + if (action == KEY_ADD_OR_REPLACE) + wl->tx_spare_blocks = 2; + else if (action == KEY_REMOVE) + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + } + addr = sta ? sta->addr : bcast_addr; if (is_zero_ether_addr(addr)) { @@ -2627,6 +2716,11 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, if (action == KEY_REMOVE && !is_broadcast_ether_addr(addr)) return 0; + /* don't remove key if hlid was already deleted */ + if (action == KEY_REMOVE && + wl->sta_hlid == WL12XX_INVALID_LINK_ID) + return 0; + ret = wl1271_cmd_set_sta_key(wl, action, id, key_type, key_size, key, addr, tx_seq_32, @@ -2636,8 +2730,9 @@ static int wl1271_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, /* the default WEP key needs to be configured at least once */ if (key_type == KEY_WEP) { - ret = wl1271_cmd_set_sta_default_wep_key(wl, - wl->default_key); + ret = wl12xx_cmd_set_default_wep_key(wl, + wl->default_key, + wl->sta_hlid); if (ret < 0) return ret; } @@ -2779,10 +2874,20 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1271_scan(hw->priv, ssid, len, req); + /* cancel ROC before scanning */ + if (wl12xx_is_roc(wl)) { + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { + /* don't allow scanning right now */ + ret = -EBUSY; + goto out_sleep; + } + wl12xx_croc(wl, wl->dev_role_id); + wl12xx_cmd_role_stop_dev(wl); + } + ret = wl1271_scan(hw->priv, ssid, len, req); +out_sleep: wl1271_ps_elp_sleep(wl); - out: mutex_unlock(&wl->mutex); @@ -2960,6 +3065,93 @@ static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb, return 0; } +static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset) +{ + int len; + const u8 *next, *end = skb->data + skb->len; + u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset, + skb->len - ieoffset); + if (!ie) + return; + len = ie[1] + 2; + next = ie + len; + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); +} + +static void wl12xx_remove_vendor_ie(struct sk_buff *skb, + unsigned int oui, u8 oui_type, + int ieoffset) +{ + int len; + const u8 *next, *end = skb->data + skb->len; + u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ieoffset, + skb->len - ieoffset); + if (!ie) + return; + len = ie[1] + 2; + next = ie + len; + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); +} + +static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl, + u8 *probe_rsp_data, + size_t probe_rsp_len, + u32 rates) +{ + struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf; + u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE]; + int ssid_ie_offset, ie_offset, templ_len; + const u8 *ptr; + + /* no need to change probe response if the SSID is set correctly */ + if (wl->ssid_len > 0) + return wl1271_cmd_template_set(wl, + CMD_TEMPL_AP_PROBE_RESPONSE, + probe_rsp_data, + probe_rsp_len, 0, + rates); + + if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) { + wl1271_error("probe_rsp template too big"); + return -EINVAL; + } + + /* start searching from IE offset */ + ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + + ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset, + probe_rsp_len - ie_offset); + if (!ptr) { + wl1271_error("No SSID in beacon!"); + return -EINVAL; + } + + ssid_ie_offset = ptr - probe_rsp_data; + ptr += (ptr[1] + 2); + + memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset); + + /* insert SSID from bss_conf */ + probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID; + probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len; + memcpy(probe_rsp_templ + ssid_ie_offset + 2, + bss_conf->ssid, bss_conf->ssid_len); + templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len; + + memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len, + ptr, probe_rsp_len - (ptr - probe_rsp_data)); + templ_len += probe_rsp_len - (ptr - probe_rsp_data); + + return wl1271_cmd_template_set(wl, + CMD_TEMPL_AP_PROBE_RESPONSE, + probe_rsp_templ, + templ_len, 0, + rates); +} + static int wl1271_bss_erp_info_changed(struct wl1271 *wl, struct ieee80211_bss_conf *bss_conf, u32 changed) @@ -3016,6 +3208,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, if ((changed & BSS_CHANGED_BEACON)) { struct ieee80211_hdr *hdr; + u32 min_rate; int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif); @@ -3031,28 +3224,46 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl, dev_kfree_skb(beacon); goto out; } + min_rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON : CMD_TEMPL_BEACON; ret = wl1271_cmd_template_set(wl, tmpl_id, beacon->data, beacon->len, 0, - wl1271_tx_min_rate_get(wl)); + min_rate); if (ret < 0) { dev_kfree_skb(beacon); goto out; } + /* remove TIM ie from probe response */ + wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset); + + /* + * remove p2p ie from probe response. + * the fw reponds to probe requests that don't include + * the p2p ie. probe requests with p2p ie will be passed, + * and will be responded by the supplicant (the spec + * forbids including the p2p ie when responding to probe + * requests that didn't include it). + */ + wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, ieoffset); + hdr = (struct ieee80211_hdr *) beacon->data; hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); - - tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE : - CMD_TEMPL_PROBE_RESPONSE; - ret = wl1271_cmd_template_set(wl, - tmpl_id, - beacon->data, - beacon->len, 0, - wl1271_tx_min_rate_get(wl)); + if (is_ap) + ret = wl1271_ap_set_probe_resp_tmpl(wl, + beacon->data, + beacon->len, + min_rate); + else + ret = wl1271_cmd_template_set(wl, + CMD_TEMPL_PROBE_RESPONSE, + beacon->data, + beacon->len, 0, + min_rate); dev_kfree_skb(beacon); if (ret < 0) goto out; @@ -3073,8 +3284,10 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if ((changed & BSS_CHANGED_BASIC_RATES)) { u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = wl1271_tx_min_rate_get(wl, + wl->basic_rate_set); ret = wl1271_init_ap_rates(wl); if (ret < 0) { @@ -3094,20 +3307,20 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, if ((changed & BSS_CHANGED_BEACON_ENABLED)) { if (bss_conf->enable_beacon) { if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { - ret = wl1271_cmd_start_bss(wl); + ret = wl12xx_cmd_role_start_ap(wl); if (ret < 0) goto out; - set_bit(WL1271_FLAG_AP_STARTED, &wl->flags); - wl1271_debug(DEBUG_AP, "started AP"); - ret = wl1271_ap_init_hwenc(wl); if (ret < 0) goto out; + + set_bit(WL1271_FLAG_AP_STARTED, &wl->flags); + wl1271_debug(DEBUG_AP, "started AP"); } } else { if (test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) { - ret = wl1271_cmd_stop_bss(wl); + ret = wl12xx_cmd_role_stop_ap(wl); if (ret < 0) goto out; @@ -3120,6 +3333,18 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl, ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed); if (ret < 0) goto out; + + /* Handle HT information change */ + if ((changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_information(wl, + bss_conf->ht_operation_mode); + if (ret < 0) { + wl1271_warning("Set ht information failed %d", ret); + goto out; + } + } + out: return; } @@ -3132,6 +3357,7 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, { bool do_join = false, set_assoc = false; bool is_ibss = (wl->bss_type == BSS_TYPE_IBSS); + bool ibss_joined = false; u32 sta_rate_set = 0; int ret; struct ieee80211_sta *sta; @@ -3145,14 +3371,28 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, goto out; } - if ((changed & BSS_CHANGED_BEACON_INT) && is_ibss) + if (changed & BSS_CHANGED_IBSS) { + if (bss_conf->ibss_joined) { + set_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags); + ibss_joined = true; + } else { + if (test_and_clear_bit(WL1271_FLAG_IBSS_JOINED, + &wl->flags)) { + wl1271_unjoin(wl); + wl12xx_cmd_role_start_dev(wl); + wl12xx_roc(wl, wl->dev_role_id); + } + } + } + + if ((changed & BSS_CHANGED_BEACON_INT) && ibss_joined) do_join = true; /* Need to update the SSID (for filtering etc) */ - if ((changed & BSS_CHANGED_BEACON) && is_ibss) + if ((changed & BSS_CHANGED_BEACON) && ibss_joined) do_join = true; - if ((changed & BSS_CHANGED_BEACON_ENABLED) && is_ibss) { + if ((changed & BSS_CHANGED_BEACON_ENABLED) && ibss_joined) { wl1271_debug(DEBUG_ADHOC, "ad-hoc beaconing: %s", bss_conf->enable_beacon ? "enabled" : "disabled"); @@ -3192,17 +3432,17 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (ret < 0) goto out; - /* filter out all packets not from this BSSID */ - wl1271_configure_filters(wl, 0); - /* Need to update the BSSID (for filtering etc) */ do_join = true; } } - rcu_read_lock(); - sta = ieee80211_find_sta(vif, bss_conf->bssid); - if (sta) { + if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { + rcu_read_lock(); + sta = ieee80211_find_sta(vif, bss_conf->bssid); + if (!sta) + goto sta_not_found; + /* save the supp_rates of the ap */ sta_rate_set = sta->supp_rates[wl->hw->conf.channel->band]; if (sta->ht_cap.ht_supported) @@ -3210,38 +3450,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, (sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET); sta_ht_cap = sta->ht_cap; sta_exists = true; - } - rcu_read_unlock(); - if (sta_exists) { - /* handle new association with HT and HT information change */ - if ((changed & BSS_CHANGED_HT) && - (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { - ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, - true); - if (ret < 0) { - wl1271_warning("Set ht cap true failed %d", - ret); - goto out; - } - ret = wl1271_acx_set_ht_information(wl, - bss_conf->ht_operation_mode); - if (ret < 0) { - wl1271_warning("Set ht information failed %d", - ret); - goto out; - } - } - /* handle new association without HT and disassociation */ - else if (changed & BSS_CHANGED_ASSOC) { - ret = wl1271_acx_set_ht_capabilities(wl, &sta_ht_cap, - false); - if (ret < 0) { - wl1271_warning("Set ht cap false failed %d", - ret); - goto out; - } - } +sta_not_found: + rcu_read_unlock(); } if ((changed & BSS_CHANGED_ASSOC)) { @@ -3258,12 +3469,15 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, * to use with control frames. */ rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, - rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); if (sta_rate_set) wl->rate_set = wl1271_tx_enabled_rates_get(wl, - sta_rate_set); + sta_rate_set, + wl->band); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -3291,25 +3505,14 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, ret = wl1271_acx_conn_monit_params(wl, true); if (ret < 0) goto out; - - /* If we want to go in PSM but we're not there yet */ - if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && - !test_bit(WL1271_FLAG_PSM, &wl->flags)) { - enum wl1271_cmd_ps_mode mode; - - mode = STATION_POWER_SAVE_MODE; - ret = wl1271_ps_set_mode(wl, mode, - wl->basic_rate, - true); - if (ret < 0) - goto out; - } } else { /* use defaults when not associated */ bool was_assoc = !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); - clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags); + bool was_ifup = + !!test_and_clear_bit(WL1271_FLAG_STA_STATE_SENT, + &wl->flags); wl->aid = 0; /* free probe-request template */ @@ -3321,7 +3524,8 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, /* revert back to minimum rates for the current band */ wl1271_set_band_rate(wl); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) goto out; @@ -3336,8 +3540,32 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, /* restore the bssid filter and go to dummy bssid */ if (was_assoc) { + u32 conf_flags = wl->hw->conf.flags; + /* + * we might have to disable roc, if there was + * no IF_OPER_UP notification. + */ + if (!was_ifup) { + ret = wl12xx_croc(wl, wl->role_id); + if (ret < 0) + goto out; + } + /* + * (we also need to disable roc in case of + * roaming on the same channel. until we will + * have a better flow...) + */ + if (test_bit(wl->dev_role_id, wl->roc_map)) { + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out; + } + wl1271_unjoin(wl); - wl1271_dummy_join(wl); + if (!(conf_flags & IEEE80211_CONF_IDLE)) { + wl12xx_cmd_role_start_dev(wl); + wl12xx_roc(wl, wl->dev_role_id); + } } } } @@ -3348,11 +3576,13 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, if (bss_conf->ibss_joined) { u32 rates = bss_conf->basic_rates; - wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, - rates); - wl->basic_rate = wl1271_tx_min_rate_get(wl); + wl->basic_rate_set = + wl1271_tx_enabled_rates_get(wl, rates, + wl->band); + wl->basic_rate = + wl1271_tx_min_rate_get(wl, wl->basic_rate_set); - /* by default, use 11b rates */ + /* by default, use 11b + OFDM rates */ wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES; ret = wl1271_acx_sta_rate_policies(wl); if (ret < 0) @@ -3398,7 +3628,81 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl, wl1271_warning("cmd join failed %d", ret); goto out; } - wl1271_check_operstate(wl, ieee80211_get_operstate(vif)); + + /* ROC until connected (after EAPOL exchange) */ + if (!is_ibss) { + ret = wl12xx_roc(wl, wl->role_id); + if (ret < 0) + goto out; + + wl1271_check_operstate(wl, + ieee80211_get_operstate(vif)); + } + /* + * stop device role if started (we might already be in + * STA role). TODO: make it better. + */ + if (wl->dev_role_id != WL12XX_INVALID_ROLE_ID) { + ret = wl12xx_croc(wl, wl->dev_role_id); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_role_stop_dev(wl); + if (ret < 0) + goto out; + } + + /* If we want to go in PSM but we're not there yet */ + if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && + !test_bit(WL1271_FLAG_PSM, &wl->flags)) { + enum wl1271_cmd_ps_mode mode; + + mode = STATION_POWER_SAVE_MODE; + ret = wl1271_ps_set_mode(wl, mode, + wl->basic_rate, + true); + if (ret < 0) + goto out; + } + } + + /* Handle new association with HT. Do this after join. */ + if (sta_exists) { + if ((changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_capabilities(wl, + &sta_ht_cap, + true, + wl->sta_hlid); + if (ret < 0) { + wl1271_warning("Set ht cap true failed %d", + ret); + goto out; + } + } + /* handle new association without HT and disassociation */ + else if (changed & BSS_CHANGED_ASSOC) { + ret = wl1271_acx_set_ht_capabilities(wl, + &sta_ht_cap, + false, + wl->sta_hlid); + if (ret < 0) { + wl1271_warning("Set ht cap false failed %d", + ret); + goto out; + } + } + } + + /* Handle HT information change. Done after join. */ + if ((changed & BSS_CHANGED_HT) && + (bss_conf->channel_type != NL80211_CHAN_NO_HT)) { + ret = wl1271_acx_set_ht_information(wl, + bss_conf->ht_operation_mode); + if (ret < 0) { + wl1271_warning("Set ht information failed %d", ret); + goto out; + } } out: @@ -3437,7 +3741,8 @@ out: mutex_unlock(&wl->mutex); } -static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int wl1271_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, u16 queue, const struct ieee80211_tx_queue_params *params) { struct wl1271 *wl = hw->priv; @@ -3508,7 +3813,8 @@ out: return ret; } -static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw) +static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct wl1271 *wl = hw->priv; @@ -3568,31 +3874,31 @@ static int wl1271_allocate_sta(struct wl1271 *wl, } wl_sta = (struct wl1271_station *)sta->drv_priv; - __set_bit(id, wl->ap_hlid_map); + set_bit(id, wl->ap_hlid_map); wl_sta->hlid = WL1271_AP_STA_HLID_START + id; *hlid = wl_sta->hlid; memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN); + wl->active_sta_count++; return 0; } -static void wl1271_free_sta(struct wl1271 *wl, u8 hlid) +void wl1271_free_sta(struct wl1271 *wl, u8 hlid) { int id = hlid - WL1271_AP_STA_HLID_START; - if (WARN_ON(!test_bit(id, wl->ap_hlid_map))) + if (hlid < WL1271_AP_STA_HLID_START) + return; + + if (!test_bit(id, wl->ap_hlid_map)) return; - __clear_bit(id, wl->ap_hlid_map); + clear_bit(id, wl->ap_hlid_map); memset(wl->links[hlid].addr, 0, ETH_ALEN); + wl->links[hlid].ba_bitmap = 0; wl1271_tx_reset_link_queues(wl, hlid); __clear_bit(hlid, &wl->ap_ps_map); __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); -} - -bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid) -{ - int id = hlid - WL1271_AP_STA_HLID_START; - return test_bit(id, wl->ap_hlid_map); + wl->active_sta_count--; } static int wl1271_op_sta_add(struct ieee80211_hw *hw, @@ -3621,7 +3927,15 @@ static int wl1271_op_sta_add(struct ieee80211_hw *hw, if (ret < 0) goto out_free_sta; - ret = wl1271_cmd_add_sta(wl, sta, hlid); + ret = wl12xx_cmd_add_peer(wl, sta, hlid); + if (ret < 0) + goto out_sleep; + + ret = wl12xx_cmd_set_peer_state(wl, hlid); + if (ret < 0) + goto out_sleep; + + ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, hlid); if (ret < 0) goto out_sleep; @@ -3664,7 +3978,7 @@ static int wl1271_op_sta_remove(struct ieee80211_hw *hw, if (ret < 0) goto out; - ret = wl1271_cmd_remove_sta(wl, wl_sta->hlid); + ret = wl12xx_cmd_remove_peer(wl, wl_sta->hlid); if (ret < 0) goto out_sleep; @@ -3686,6 +4000,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, { struct wl1271 *wl = hw->priv; int ret; + u8 hlid, *ba_bitmap; + + wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action, + tid); + + /* sanity check - the fields in FW are only 8bits wide */ + if (WARN_ON(tid > 0xFF)) + return -ENOTSUPP; mutex_lock(&wl->mutex); @@ -3694,6 +4016,20 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, goto out; } + if (wl->bss_type == BSS_TYPE_STA_BSS) { + hlid = wl->sta_hlid; + ba_bitmap = &wl->ba_rx_bitmap; + } else if (wl->bss_type == BSS_TYPE_AP_BSS) { + struct wl1271_station *wl_sta; + + wl_sta = (struct wl1271_station *)sta->drv_priv; + hlid = wl_sta->hlid; + ba_bitmap = &wl->links[hlid].ba_bitmap; + } else { + ret = -EINVAL; + goto out; + } + ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -3703,20 +4039,46 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - if ((wl->ba_support) && (wl->ba_allowed)) { - ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn, - true); - if (!ret) - wl->ba_rx_bitmap |= BIT(tid); - } else { + if (!wl->ba_support || !wl->ba_allowed) { ret = -ENOTSUPP; + break; + } + + if (wl->ba_rx_session_count >= RX_BA_MAX_SESSIONS) { + ret = -EBUSY; + wl1271_error("exceeded max RX BA sessions"); + break; + } + + if (*ba_bitmap & BIT(tid)) { + ret = -EINVAL; + wl1271_error("cannot enable RX BA session on active " + "tid: %d", tid); + break; + } + + ret = wl12xx_acx_set_ba_receiver_session(wl, tid, *ssn, true, + hlid); + if (!ret) { + *ba_bitmap |= BIT(tid); + wl->ba_rx_session_count++; } break; case IEEE80211_AMPDU_RX_STOP: - ret = wl1271_acx_set_ba_receiver_session(wl, tid, 0, false); - if (!ret) - wl->ba_rx_bitmap &= ~BIT(tid); + if (!(*ba_bitmap & BIT(tid))) { + ret = -EINVAL; + wl1271_error("no active RX BA session on tid: %d", + tid); + break; + } + + ret = wl12xx_acx_set_ba_receiver_session(wl, tid, 0, false, + hlid); + if (!ret) { + *ba_bitmap &= ~BIT(tid); + wl->ba_rx_session_count--; + } break; /* @@ -3742,6 +4104,60 @@ out: return ret; } +static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + const struct cfg80211_bitrate_mask *mask) +{ + struct wl1271 *wl = hw->priv; + int i; + + wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x", + mask->control[NL80211_BAND_2GHZ].legacy, + mask->control[NL80211_BAND_5GHZ].legacy); + + mutex_lock(&wl->mutex); + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) + wl->bitrate_masks[i] = + wl1271_tx_enabled_rates_get(wl, + mask->control[i].legacy, + i); + mutex_unlock(&wl->mutex); + + return 0; +} + +static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_channel_switch *ch_switch) +{ + struct wl1271 *wl = hw->priv; + int ret; + + wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) { + mutex_unlock(&wl->mutex); + ieee80211_chswitch_done(wl->vif, false); + return; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl12xx_cmd_channel_switch(wl, ch_switch); + + if (!ret) + set_bit(WL1271_FLAG_CS_PROGRESS, &wl->flags); + + wl1271_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); +} + static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -3858,7 +4274,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { /* 11n STA capabilities */ #define HW_RX_HIGHEST_RATE 72 -#ifdef CONFIG_WL12XX_HT #define WL12XX_HT_CAP { \ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \ @@ -3871,11 +4286,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = { .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \ }, \ } -#else -#define WL12XX_HT_CAP { \ - .ht_supported = false, \ -} -#endif /* can't be const, mac80211 writes to this */ static struct ieee80211_supported_band wl1271_band_2ghz = { @@ -4023,6 +4433,8 @@ static const struct ieee80211_ops wl1271_ops = { .sta_remove = wl1271_op_sta_remove, .ampdu_action = wl1271_op_ampdu_action, .tx_frames_pending = wl1271_tx_frames_pending, + .set_bitrate_mask = wl12xx_set_bitrate_mask, + .channel_switch = wl12xx_op_channel_switch, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -4126,7 +4538,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, return len; } -static DEVICE_ATTR(hw_pg_ver, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(hw_pg_ver, S_IRUGO, wl1271_sysfs_show_hw_pg_ver, NULL); static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, @@ -4275,23 +4687,32 @@ int wl1271_init_ieee80211(struct wl1271 *wl) IEEE80211_HW_SUPPORTS_CQM_RSSI | IEEE80211_HW_REPORTS_TX_ACK_STATUS | IEEE80211_HW_SPECTRUM_MGMT | - IEEE80211_HW_AP_LINK_PS; + IEEE80211_HW_AP_LINK_PS | + IEEE80211_HW_AMPDU_AGGREGATION | + IEEE80211_HW_TX_AMPDU_SETUP_IN_HW; wl->hw->wiphy->cipher_suites = cipher_suites; wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); wl->hw->wiphy->max_scan_ssids = 1; - wl->hw->wiphy->max_sched_scan_ssids = 1; + wl->hw->wiphy->max_sched_scan_ssids = 16; + wl->hw->wiphy->max_match_sets = 16; /* * Maximum length of elements in scanning probe request templates * should be the maximum length possible for a template, without * the IEEE80211 header of the template */ - wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE - + wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - sizeof(struct ieee80211_header); + wl->hw->wiphy->max_sched_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE - + sizeof(struct ieee80211_header); + + wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + ARRAY_SIZE(wl1271_channels_5ghz) > @@ -4335,6 +4756,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) int i, j, ret; unsigned int order; + BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS); + hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops); if (!hw) { wl1271_error("could not alloc ieee80211_hw"); @@ -4388,8 +4811,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->beacon_int = WL1271_DEFAULT_BEACON_INT; wl->default_key = 0; wl->rx_counter = 0; - wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER; wl->psm_entry_retry = 0; wl->power_level = WL1271_DEFAULT_POWER_LEVEL; wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; @@ -4402,7 +4823,6 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->hw_pg_ver = -1; wl->bss_type = MAX_BSS_TYPE; wl->set_bss_type = MAX_BSS_TYPE; - wl->fw_bss_type = MAX_BSS_TYPE; wl->last_tx_hlid = 0; wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; @@ -4411,12 +4831,24 @@ struct ieee80211_hw *wl1271_alloc_hw(void) wl->sched_scanning = false; wl->tx_security_seq = 0; wl->tx_security_last_seq_lsb = 0; - + wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + wl->role_id = WL12XX_INVALID_ROLE_ID; + wl->system_hlid = WL12XX_SYSTEM_HLID; + wl->sta_hlid = WL12XX_INVALID_LINK_ID; + wl->dev_role_id = WL12XX_INVALID_ROLE_ID; + wl->dev_hlid = WL12XX_INVALID_LINK_ID; + wl->session_counter = 0; + wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID; + wl->ap_global_hlid = WL12XX_INVALID_LINK_ID; + wl->active_sta_count = 0; setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer, (unsigned long) wl); wl->fwlog_size = 0; init_waitqueue_head(&wl->fwlog_waitq); + /* The system link is always allocated */ + __set_bit(WL12XX_SYSTEM_HLID, wl->links_map); + memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map)); for (i = 0; i < ACX_TX_DESCRIPTORS; i++) wl->tx_frames[i] = NULL; @@ -4428,6 +4860,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void) /* Apply default driver configuration. */ wl1271_conf_init(wl); + wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate; + wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5; order = get_order(WL1271_AGGR_BUFFER_SIZE); wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order); @@ -4523,6 +4957,10 @@ int wl1271_free_hw(struct wl1271 *wl) mutex_unlock(&wl->mutex); device_remove_bin_file(&wl->plat_dev->dev, &fwlog_attr); + + device_remove_file(&wl->plat_dev->dev, &dev_attr_hw_pg_ver); + + device_remove_file(&wl->plat_dev->dev, &dev_attr_bt_coex_state); platform_device_unregister(wl->plat_dev); free_page((unsigned long)wl->fwlog); dev_kfree_skb(wl->dummy_packet); @@ -4556,6 +4994,9 @@ module_param_named(fwlog, fwlog_param, charp, 0); MODULE_PARM_DESC(keymap, "FW logger options: continuous, ondemand, dbgpins or disable"); +module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR); +MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c index 3548377ab9c2..c15ebf2efd40 100644 --- a/drivers/net/wireless/wl12xx/ps.c +++ b/drivers/net/wireless/wl12xx/ps.c @@ -199,15 +199,19 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid) unsigned long flags; int filtered[NUM_TX_QUEUES]; - /* filter all frames currently the low level queus for this hlid */ + /* filter all frames currently in the low level queues for this hlid */ for (i = 0; i < NUM_TX_QUEUES; i++) { filtered[i] = 0; while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { + filtered[i]++; + + if (WARN_ON(wl12xx_is_dummy_packet(wl, skb))) + continue; + info = IEEE80211_SKB_CB(skb); info->flags |= IEEE80211_TX_STAT_TX_FILTERED; info->status.rates[0].idx = -1; ieee80211_tx_status_ni(wl->hw, skb); - filtered[i]++; } } @@ -226,8 +230,8 @@ void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues) if (test_bit(hlid, &wl->ap_ps_map)) return; - wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d blks %d " - "clean_queues %d", hlid, wl->links[hlid].allocated_blks, + wl1271_debug(DEBUG_PSM, "start mac80211 PSM on hlid %d pkts %d " + "clean_queues %d", hlid, wl->links[hlid].allocated_pkts, clean_queues); rcu_read_lock(); diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h index 440a4ee9cb42..3f570f397586 100644 --- a/drivers/net/wireless/wl12xx/reg.h +++ b/drivers/net/wireless/wl12xx/reg.h @@ -296,81 +296,6 @@ ===============================================*/ #define REG_EVENT_MAILBOX_PTR (SCR_PAD1) - -/* Misc */ - -#define REG_ENABLE_TX_RX (ENABLE) -/* - * Rx configuration (filter) information element - * --------------------------------------------- - */ -#define REG_RX_CONFIG (RX_CFG) -#define REG_RX_FILTER (RX_FILTER_CFG) - - -#define RX_CFG_ENABLE_PHY_HEADER_PLCP 0x0002 - -/* promiscuous - receives all valid frames */ -#define RX_CFG_PROMISCUOUS 0x0008 - -/* receives frames from any BSSID */ -#define RX_CFG_BSSID 0x0020 - -/* receives frames destined to any MAC address */ -#define RX_CFG_MAC 0x0010 - -#define RX_CFG_ENABLE_ONLY_MY_DEST_MAC 0x0010 -#define RX_CFG_ENABLE_ANY_DEST_MAC 0x0000 -#define RX_CFG_ENABLE_ONLY_MY_BSSID 0x0020 -#define RX_CFG_ENABLE_ANY_BSSID 0x0000 - -/* discards all broadcast frames */ -#define RX_CFG_DISABLE_BCAST 0x0200 - -#define RX_CFG_ENABLE_ONLY_MY_SSID 0x0400 -#define RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR 0x0800 -#define RX_CFG_COPY_RX_STATUS 0x2000 -#define RX_CFG_TSF 0x10000 - -#define RX_CONFIG_OPTION_ANY_DST_MY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_ANY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_ANY_DST_ANY_BSS (RX_CFG_ENABLE_ANY_DEST_MAC | \ - RX_CFG_ENABLE_ANY_BSSID) - -#define RX_CONFIG_OPTION_MY_DST_MY_BSS (RX_CFG_ENABLE_ONLY_MY_DEST_MAC\ - | RX_CFG_ENABLE_ONLY_MY_BSSID) - -#define RX_CONFIG_OPTION_FOR_SCAN (RX_CFG_ENABLE_PHY_HEADER_PLCP \ - | RX_CFG_ENABLE_RX_CMPLT_FCS_ERROR \ - | RX_CFG_COPY_RX_STATUS | RX_CFG_TSF) - -#define RX_CONFIG_OPTION_FOR_MEASUREMENT (RX_CFG_ENABLE_ANY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_JOIN (RX_CFG_ENABLE_ONLY_MY_BSSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_CONFIG_OPTION_FOR_IBSS_JOIN (RX_CFG_ENABLE_ONLY_MY_SSID | \ - RX_CFG_ENABLE_ONLY_MY_DEST_MAC) - -#define RX_FILTER_OPTION_DEF (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_CTL_EN | CFG_RX_BCN_EN\ - | CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) - -#define RX_FILTER_OPTION_FILTER_ALL 0 - -#define RX_FILTER_OPTION_DEF_PRSP_BCN (CFG_RX_PRSP_EN | CFG_RX_MGMT_EN\ - | CFG_RX_RCTS_ACK | CFG_RX_BCN_EN) - -#define RX_FILTER_OPTION_JOIN (CFG_RX_MGMT_EN | CFG_RX_DATA_EN\ - | CFG_RX_BCN_EN | CFG_RX_AUTH_EN\ - | CFG_RX_ASSOC_EN | CFG_RX_RCTS_ACK\ - | CFG_RX_PRSP_EN) - - /*=============================================== EEPROM Read/Write Request 32bit RW ------------------------------------------ diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c index 0450fb49dbb1..dee4cfe9ccc1 100644 --- a/drivers/net/wireless/wl12xx/rx.c +++ b/drivers/net/wireless/wl12xx/rx.c @@ -30,20 +30,28 @@ #include "rx.h" #include "io.h" -static u8 wl1271_rx_get_mem_block(struct wl1271_fw_common_status *status, +static u8 wl12xx_rx_get_mem_block(struct wl12xx_fw_status *status, u32 drv_rx_counter) { return le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & RX_MEM_BLOCK_MASK; } -static u32 wl1271_rx_get_buf_size(struct wl1271_fw_common_status *status, +static u32 wl12xx_rx_get_buf_size(struct wl12xx_fw_status *status, u32 drv_rx_counter) { return (le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & RX_BUF_SIZE_MASK) >> RX_BUF_SIZE_SHIFT_DIV; } +static bool wl12xx_rx_get_unaligned(struct wl12xx_fw_status *status, + u32 drv_rx_counter) +{ + /* Convert the value to bool */ + return !!(le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]) & + RX_BUF_UNALIGNED_PAYLOAD); +} + static void wl1271_rx_status(struct wl1271 *wl, struct wl1271_rx_descriptor *desc, struct ieee80211_rx_status *status, @@ -58,11 +66,9 @@ static void wl1271_rx_status(struct wl1271 *wl, status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band); -#ifdef CONFIG_WL12XX_HT /* 11n support */ if (desc->rate <= CONF_HW_RXTX_RATE_MCS0) status->flag |= RX_FLAG_HT; -#endif status->signal = desc->rssi; @@ -89,7 +95,8 @@ static void wl1271_rx_status(struct wl1271 *wl, } } -static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) +static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, + bool unaligned) { struct wl1271_rx_descriptor *desc; struct sk_buff *skb; @@ -97,6 +104,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) u8 *buf; u8 beacon = 0; u8 is_data = 0; + u8 reserved = unaligned ? NET_IP_ALIGN : 0; + u16 seq_num; /* * In PLT mode we seem to get frames and mac80211 warns about them, @@ -131,17 +140,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) return -EINVAL; } - skb = __dev_alloc_skb(length, GFP_KERNEL); + /* skb length not included rx descriptor */ + skb = __dev_alloc_skb(length + reserved - sizeof(*desc), GFP_KERNEL); if (!skb) { wl1271_error("Couldn't allocate RX frame"); return -ENOMEM; } - buf = skb_put(skb, length); - memcpy(buf, data, length); + /* reserve the unaligned payload(if any) */ + skb_reserve(skb, reserved); - /* now we pull the descriptor out of the buffer */ - skb_pull(skb, sizeof(*desc)); + buf = skb_put(skb, length - sizeof(*desc)); + + /* + * Copy packets from aggregation buffer to the skbs without rx + * descriptor and with packet payload aligned care. In case of unaligned + * packets copy the packets in offset of 2 bytes guarantee IP header + * payload aligned to 4 bytes. + */ + memcpy(buf, data + sizeof(*desc), length - sizeof(*desc)); hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_beacon(hdr->frame_control)) @@ -151,9 +168,11 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon); - wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, + seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; + wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb, skb->len - desc->pad_len, - beacon ? "beacon" : ""); + beacon ? "beacon" : "", + seq_num); skb_trim(skb, skb->len - desc->pad_len); @@ -163,7 +182,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length) return is_data; } -void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) +void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) { struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; u32 buf_size; @@ -175,12 +194,13 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) u32 pkt_offset; bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); bool had_data = false; + bool unaligned = false; while (drv_rx_counter != fw_rx_counter) { buf_size = 0; rx_counter = drv_rx_counter; while (rx_counter != fw_rx_counter) { - pkt_length = wl1271_rx_get_buf_size(status, rx_counter); + pkt_length = wl12xx_rx_get_buf_size(status, rx_counter); if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) break; buf_size += pkt_length; @@ -199,7 +219,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) * For aggregated packets, only the first memory block * should be retrieved. The FW takes care of the rest. */ - mem_block = wl1271_rx_get_mem_block(status, + mem_block = wl12xx_rx_get_mem_block(status, drv_rx_counter); wl->rx_mem_pool_addr.addr = (mem_block << 8) + @@ -220,8 +240,12 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) /* Split data into separate packets */ pkt_offset = 0; while (pkt_offset < buf_size) { - pkt_length = wl1271_rx_get_buf_size(status, + pkt_length = wl12xx_rx_get_buf_size(status, drv_rx_counter); + + unaligned = wl12xx_rx_get_unaligned(status, + drv_rx_counter); + /* * the handle data call can only fail in memory-outage * conditions, in that case the received frame will just @@ -229,7 +253,7 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) */ if (wl1271_rx_handle_data(wl, wl->aggr_buf + pkt_offset, - pkt_length) == 1) + pkt_length, unaligned) == 1) had_data = true; wl->rx_counter++; @@ -260,14 +284,3 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status) jiffies + msecs_to_jiffies(timeout)); } } - -void wl1271_set_default_filters(struct wl1271 *wl) -{ - if (wl->bss_type == BSS_TYPE_AP_BSS) { - wl->rx_config = WL1271_DEFAULT_AP_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_AP_RX_FILTER; - } else { - wl->rx_config = WL1271_DEFAULT_STA_RX_CONFIG; - wl->rx_filter = WL1271_DEFAULT_STA_RX_FILTER; - } -} diff --git a/drivers/net/wireless/wl12xx/rx.h b/drivers/net/wireless/wl12xx/rx.h index c88e3fa1d603..86ba6b1d0cdc 100644 --- a/drivers/net/wireless/wl12xx/rx.h +++ b/drivers/net/wireless/wl12xx/rx.h @@ -86,16 +86,18 @@ * Bits 3-5 - process_id tag (AP mode FW) * Bits 6-7 - reserved */ -#define WL1271_RX_DESC_STATUS_MASK 0x07 +#define WL1271_RX_DESC_STATUS_MASK 0x03 #define WL1271_RX_DESC_SUCCESS 0x00 #define WL1271_RX_DESC_DECRYPT_FAIL 0x01 #define WL1271_RX_DESC_MIC_FAIL 0x02 #define WL1271_RX_DESC_DRIVER_RX_Q_FAIL 0x03 -#define RX_MEM_BLOCK_MASK 0xFF -#define RX_BUF_SIZE_MASK 0xFFF00 -#define RX_BUF_SIZE_SHIFT_DIV 6 +#define RX_MEM_BLOCK_MASK 0xFF +#define RX_BUF_SIZE_MASK 0xFFF00 +#define RX_BUF_SIZE_SHIFT_DIV 6 +/* If set, the start of IP payload is not 4 bytes aligned */ +#define RX_BUF_UNALIGNED_PAYLOAD BIT(20) enum { WL12XX_RX_CLASS_UNKNOWN, @@ -119,16 +121,12 @@ struct wl1271_rx_descriptor { u8 snr; __le32 timestamp; u8 packet_class; - union { - u8 process_id; /* STA FW */ - u8 hlid; /* AP FW */ - } __packed; + u8 hlid; u8 pad_len; u8 reserved; } __packed; -void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status); +void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); -void wl1271_set_default_filters(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index edfe01c321ca..128ccb79318c 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -28,11 +28,14 @@ #include "scan.h" #include "acx.h" #include "ps.h" +#include "tx.h" void wl1271_scan_complete_work(struct work_struct *work) { struct delayed_work *dwork; struct wl1271 *wl; + int ret; + bool is_sta, is_ibss; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, scan_complete_work); @@ -50,21 +53,35 @@ void wl1271_scan_complete_work(struct work_struct *work) wl->scan.state = WL1271_SCAN_STATE_IDLE; memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch)); wl->scan.req = NULL; - ieee80211_scan_completed(wl->hw, false); - /* restore hardware connection monitoring template */ + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { - if (wl1271_ps_elp_wakeup(wl) == 0) { - wl1271_cmd_build_ap_probe_req(wl, wl->probereq); - wl1271_ps_elp_sleep(wl); - } + /* restore hardware connection monitoring template */ + wl1271_cmd_build_ap_probe_req(wl, wl->probereq); + } + + /* return to ROC if needed */ + is_sta = (wl->bss_type == BSS_TYPE_STA_BSS); + is_ibss = (wl->bss_type == BSS_TYPE_IBSS); + if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) || + (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) && + !test_bit(wl->dev_role_id, wl->roc_map)) { + /* restore remain on channel */ + wl12xx_cmd_role_start_dev(wl); + wl12xx_roc(wl, wl->dev_role_id); } + wl1271_ps_elp_sleep(wl); if (wl->scan.failed) { wl1271_info("Scan completed due to error."); wl12xx_queue_recovery_work(wl); } + ieee80211_scan_completed(wl->hw, false); + out: mutex_unlock(&wl->mutex); @@ -83,14 +100,18 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, for (i = 0, j = 0; i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; i++) { - flags = req->channels[i]->flags; if (!test_bit(i, wl->scan.scanned_ch) && !(flags & IEEE80211_CHAN_DISABLED) && - ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && - (req->channels[i]->band == band)) { - + (req->channels[i]->band == band) && + /* + * In passive scans, we scan all remaining + * channels, even if not marked as such. + * In active scans, we only scan channels not + * marked as passive. + */ + (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", req->channels[i]->band, req->channels[i]->center_freq); @@ -142,6 +163,10 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, int ret; u16 scan_options = 0; + /* skip active scans if we don't have SSIDs */ + if (!passive && wl->scan.req->n_ssids == 0) + return WL1271_NOTHING_TO_SCAN; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!cmd || !trigger) { @@ -149,13 +174,14 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, goto out; } - /* We always use high priority scans */ - scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; - - /* No SSIDs means that we have a forced passive scan */ - if (passive || wl->scan.req->n_ssids == 0) + if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; + if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) { + ret = -EINVAL; + goto out; + } + cmd->params.role_id = wl->role_id; cmd->params.scan_options = cpu_to_le16(scan_options); cmd->params.n_ch = wl1271_get_scan_channels(wl, wl->scan.req, @@ -167,10 +193,6 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, } cmd->params.tx_rate = cpu_to_le32(basic_rate); - cmd->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); - cmd->params.rx_filter_options = - cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); - cmd->params.n_probe_reqs = wl->conf.scan.num_probe_reqs; cmd->params.tx_rate = cpu_to_le32(basic_rate); cmd->params.tid_trigger = 0; @@ -186,6 +208,8 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, memcpy(cmd->params.ssid, wl->scan.ssid, wl->scan.ssid_len); } + memcpy(cmd->addr, wl->mac_addr, ETH_ALEN); + ret = wl1271_cmd_build_probe_req(wl, wl->scan.ssid, wl->scan.ssid_len, wl->scan.req->ie, wl->scan.req->ie_len, band); @@ -220,14 +244,17 @@ out: void wl1271_scan_stm(struct wl1271 *wl) { int ret = 0; + enum ieee80211_band band; + u32 rate; switch (wl->scan.state) { case WL1271_SCAN_STATE_IDLE: break; case WL1271_SCAN_STATE_2GHZ_ACTIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false, - wl->conf.tx.basic_rate); + band = IEEE80211_BAND_2GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE; wl1271_scan_stm(wl); @@ -236,8 +263,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_2GHZ_PASSIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true, - wl->conf.tx.basic_rate); + band = IEEE80211_BAND_2GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { if (wl->enable_11a) wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE; @@ -249,8 +277,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_5GHZ_ACTIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false, - wl->conf.tx.basic_rate_5); + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, false, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE; wl1271_scan_stm(wl); @@ -259,8 +288,9 @@ void wl1271_scan_stm(struct wl1271 *wl) break; case WL1271_SCAN_STATE_5GHZ_PASSIVE: - ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true, - wl->conf.tx.basic_rate_5); + band = IEEE80211_BAND_5GHZ; + rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]); + ret = wl1271_scan_send(wl, band, true, rate); if (ret == WL1271_NOTHING_TO_SCAN) { wl->scan.state = WL1271_SCAN_STATE_DONE; wl1271_scan_stm(wl); @@ -455,6 +485,105 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl, cfg->passive[2] || cfg->active[2]; } +/* Returns the scan type to be used or a negative value on error */ +static int +wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, + struct cfg80211_sched_scan_request *req) +{ + struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL; + struct cfg80211_match_set *sets = req->match_sets; + struct cfg80211_ssid *ssids = req->ssids; + int ret = 0, type, i, j, n_match_ssids = 0; + + wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list"); + + /* count the match sets that contain SSIDs */ + for (i = 0; i < req->n_match_sets; i++) + if (sets[i].ssid.ssid_len > 0) + n_match_ssids++; + + /* No filter, no ssids or only bcast ssid */ + if (!n_match_ssids && + (!req->n_ssids || + (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) { + type = SCAN_SSID_FILTER_ANY; + goto out; + } + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) { + ret = -ENOMEM; + goto out; + } + + if (!n_match_ssids) { + /* No filter, with ssids */ + type = SCAN_SSID_FILTER_DISABLED; + + for (i = 0; i < req->n_ssids; i++) { + cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ? + SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC; + cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid, + ssids[i].ssid_len); + cmd->n_ssids++; + } + } else { + type = SCAN_SSID_FILTER_LIST; + + /* Add all SSIDs from the filters */ + for (i = 0; i < req->n_match_sets; i++) { + /* ignore sets without SSIDs */ + if (!sets[i].ssid.ssid_len) + continue; + + cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC; + cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len; + memcpy(cmd->ssids[cmd->n_ssids].ssid, + sets[i].ssid.ssid, sets[i].ssid.ssid_len); + cmd->n_ssids++; + } + if ((req->n_ssids > 1) || + (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) { + /* + * Mark all the SSIDs passed in the SSID list as HIDDEN, + * so they're used in probe requests. + */ + for (i = 0; i < req->n_ssids; i++) { + for (j = 0; j < cmd->n_ssids; j++) + if (!memcmp(req->ssids[i].ssid, + cmd->ssids[j].ssid, + req->ssids[i].ssid_len)) { + cmd->ssids[j].type = + SCAN_SSID_TYPE_HIDDEN; + break; + } + /* Fail if SSID isn't present in the filters */ + if (j == req->n_ssids) { + ret = -EINVAL; + goto out_free; + } + } + } + } + + wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd)); + + ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd, + sizeof(*cmd), 0); + if (ret < 0) { + wl1271_error("cmd sched scan ssid list failed"); + goto out_free; + } + +out_free: + kfree(cmd); +out: + if (ret < 0) + return ret; + return type; +} + int wl1271_scan_sched_scan_config(struct wl1271 *wl, struct cfg80211_sched_scan_request *req, struct ieee80211_sched_scan_ies *ies) @@ -486,15 +615,14 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++) cfg->intervals[i] = cpu_to_le32(req->interval); - if (!force_passive && req->ssids[0].ssid_len && req->ssids[0].ssid) { - cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC; - cfg->ssid_len = req->ssids[0].ssid_len; - memcpy(cfg->ssid, req->ssids[0].ssid, - req->ssids[0].ssid_len); - } else { - cfg->filter_type = SCAN_SSID_FILTER_ANY; - cfg->ssid_len = 0; - } + cfg->ssid_len = 0; + ret = wl12xx_scan_sched_scan_ssid_list(wl, req); + if (ret < 0) + goto out; + + cfg->filter_type = ret; + + wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type); if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) { wl1271_error("scan channel list is empty"); diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h index d882e4da71b7..92115156522f 100644 --- a/drivers/net/wireless/wl12xx/scan.h +++ b/drivers/net/wireless/wl12xx/scan.h @@ -46,7 +46,10 @@ void wl1271_scan_sched_scan_results(struct wl1271 *wl); #define WL1271_SCAN_CURRENT_TX_PWR 0 #define WL1271_SCAN_OPT_ACTIVE 0 #define WL1271_SCAN_OPT_PASSIVE 1 +#define WL1271_SCAN_OPT_TRIGGERED_SCAN 2 #define WL1271_SCAN_OPT_PRIORITY_HIGH 4 +/* scan even if we fail to enter psm */ +#define WL1271_SCAN_OPT_FORCE 8 #define WL1271_SCAN_BAND_2_4_GHZ 0 #define WL1271_SCAN_BAND_5_GHZ 1 @@ -62,27 +65,27 @@ enum { }; struct basic_scan_params { - __le32 rx_config_options; - __le32 rx_filter_options; /* Scan option flags (WL1271_SCAN_OPT_*) */ __le16 scan_options; + u8 role_id; /* Number of scan channels in the list (maximum 30) */ u8 n_ch; /* This field indicates the number of probe requests to send per channel for an active scan */ u8 n_probe_reqs; - /* Rate bit field for sending the probes */ - __le32 tx_rate; u8 tid_trigger; u8 ssid_len; - /* in order to align */ - u8 padding1[2]; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 use_ssid_list; + + /* Rate bit field for sending the probes */ + __le32 tx_rate; + + u8 ssid[IEEE80211_MAX_SSID_LEN]; /* Band to scan */ u8 band; - u8 use_ssid_list; + u8 scan_tag; - u8 padding2; + u8 padding2[2]; } __packed; struct basic_scan_channel_params { @@ -105,6 +108,10 @@ struct wl1271_cmd_scan { struct basic_scan_params params; struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS]; + + /* src mac address */ + u8 addr[ETH_ALEN]; + u8 padding[2]; } __packed; struct wl1271_cmd_trigger_scan_to { @@ -167,7 +174,7 @@ struct wl1271_cmd_sched_scan_config { u8 filter_type; u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */ - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; u8 n_probe_reqs; /* Number of probes requests per channel */ @@ -184,7 +191,7 @@ struct wl1271_cmd_sched_scan_config { } __packed; -#define SCHED_SCAN_MAX_SSIDS 8 +#define SCHED_SCAN_MAX_SSIDS 16 enum { SCAN_SSID_TYPE_PUBLIC = 0, @@ -194,7 +201,7 @@ enum { struct wl1271_ssid { u8 type; u8 len; - u8 ssid[IW_ESSID_MAX_SIZE]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; /* u8 padding[2]; */ } __packed; diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c index fb1fd5af75ea..516a8980723c 100644 --- a/drivers/net/wireless/wl12xx/sdio.c +++ b/drivers/net/wireless/wl12xx/sdio.c @@ -412,7 +412,5 @@ module_exit(wl1271_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); -MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_FIRMWARE(WL127X_FW_NAME); MODULE_FIRMWARE(WL128X_FW_NAME); -MODULE_FIRMWARE(WL127X_AP_FW_NAME); -MODULE_FIRMWARE(WL128X_AP_FW_NAME); diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c index f28915392877..f25d5d9212e7 100644 --- a/drivers/net/wireless/wl12xx/sdio_test.c +++ b/drivers/net/wireless/wl12xx/sdio_test.c @@ -30,6 +30,7 @@ #include <linux/mmc/sdio_func.h> #include <linux/mmc/sdio_ids.h> #include <linux/mmc/card.h> +#include <linux/mmc/host.h> #include <linux/gpio.h> #include <linux/wl12xx.h> #include <linux/kthread.h> @@ -142,14 +143,23 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable) ret = pm_runtime_get_sync(&func->dev); if (ret < 0) goto out; + + /* Runtime PM might be disabled, power up the card manually */ + ret = mmc_power_restore_host(func->card->host); + if (ret < 0) + goto out; + sdio_claim_host(func); sdio_enable_func(func); - sdio_release_host(func); } else { - sdio_claim_host(func); sdio_disable_func(func); sdio_release_host(func); + /* Runtime PM might be disabled, power off the card manually */ + ret = mmc_power_save_host(func->card->host); + if (ret < 0) + goto out; + /* Power down the card */ ret = pm_runtime_put_sync(&func->dev); } @@ -193,7 +203,7 @@ static int wl1271_fetch_firmware(struct wl1271 *wl) ret = request_firmware(&fw, WL128X_FW_NAME, wl1271_wl_to_dev(wl)); else - ret = request_firmware(&fw, WL1271_FW_NAME, + ret = request_firmware(&fw, WL127X_FW_NAME, wl1271_wl_to_dev(wl)); if (ret < 0) { @@ -433,7 +443,6 @@ static int __devinit wl1271_probe(struct sdio_func *func, sdio_set_drvdata(func, wl_test); - /* power up the device */ ret = wl1271_chip_wakeup(wl); if (ret) { diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index e0b3736d7e19..0f9718677860 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -486,8 +486,6 @@ module_exit(wl1271_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); -MODULE_FIRMWARE(WL1271_FW_NAME); +MODULE_FIRMWARE(WL127X_FW_NAME); MODULE_FIRMWARE(WL128X_FW_NAME); -MODULE_FIRMWARE(WL127X_AP_FW_NAME); -MODULE_FIRMWARE(WL128X_AP_FW_NAME); MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 48fde96ce0d4..bad9e29d49b0 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c @@ -30,6 +30,7 @@ #include "reg.h" #include "ps.h" #include "tx.h" +#include "event.h" static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) { @@ -37,9 +38,10 @@ static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); if (is_ap) - ret = wl1271_cmd_set_ap_default_wep_key(wl, id); + ret = wl12xx_cmd_set_default_wep_key(wl, id, + wl->ap_bcast_hlid); else - ret = wl1271_cmd_set_sta_default_wep_key(wl, id); + ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid); if (ret < 0) return ret; @@ -77,9 +79,9 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, struct sk_buff *skb) { struct ieee80211_hdr *hdr; + int ret; - hdr = (struct ieee80211_hdr *)(skb->data + - sizeof(struct wl1271_tx_hw_descr)); + hdr = (struct ieee80211_hdr *)skb->data; /* * stop bssid-based filtering before transmitting authentication @@ -90,9 +92,19 @@ static int wl1271_tx_update_filters(struct wl1271 *wl, if (!ieee80211_is_auth(hdr->frame_control)) return 0; - wl1271_configure_filters(wl, FIF_OTHER_BSS); + if (wl->dev_hlid != WL12XX_INVALID_LINK_ID) + goto out; - return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); + wl1271_debug(DEBUG_CMD, "starting device role for roaming"); + ret = wl12xx_cmd_role_start_dev(wl); + if (ret < 0) + goto out; + + ret = wl12xx_roc(wl, wl->dev_role_id); + if (ret < 0) + goto out; +out: + return 0; } static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, @@ -113,25 +125,36 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) { - bool fw_ps; - u8 tx_blks; + bool fw_ps, single_sta; + u8 tx_pkts; /* only regulate station links */ if (hlid < WL1271_AP_STA_HLID_START) return; + if (WARN_ON(!wl1271_is_active_sta(wl, hlid))) + return; + fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); - tx_blks = wl->links[hlid].allocated_blks; + tx_pkts = wl->links[hlid].allocated_pkts; + single_sta = (wl->active_sta_count == 1); /* * if in FW PS and there is enough data in FW we can put the link * into high-level PS and clean out its TX queues. + * Make an exception if this is the only connected station. In this + * case FW-memory congestion is not a problem. */ - if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) + if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) wl1271_ps_link_start(wl, hlid, true); } -u8 wl1271_tx_get_hlid(struct sk_buff *skb) +bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) +{ + return wl->dummy_packet == skb; +} + +u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) { struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); @@ -144,14 +167,38 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb) } else { struct ieee80211_hdr *hdr; + if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) + return wl->system_hlid; + hdr = (struct ieee80211_hdr *)skb->data; if (ieee80211_is_mgmt(hdr->frame_control)) - return WL1271_AP_GLOBAL_HLID; + return wl->ap_global_hlid; else - return WL1271_AP_BROADCAST_HLID; + return wl->ap_bcast_hlid; } } +static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (wl12xx_is_dummy_packet(wl, skb)) + return wl->system_hlid; + + if (wl->bss_type == BSS_TYPE_AP_BSS) + return wl12xx_tx_get_hlid_ap(wl, skb); + + wl1271_tx_update_filters(wl, skb); + + if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || + test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) && + !ieee80211_is_auth(hdr->frame_control) && + !ieee80211_is_assoc_req(hdr->frame_control)) + return wl->sta_hlid; + else + return wl->dev_hlid; +} + static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, unsigned int packet_length) { @@ -169,12 +216,7 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, u32 len; u32 total_blocks; int id, ret = -EBUSY, ac; - u32 spare_blocks; - - if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) - spare_blocks = 2; - else - spare_blocks = 1; + u32 spare_blocks = wl->tx_spare_blocks; if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) return -EAGAIN; @@ -188,6 +230,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, in the firmware */ len = wl12xx_calc_packet_alignment(wl, total_len); + /* in case of a dummy packet, use default amount of spare mem blocks */ + if (unlikely(wl12xx_is_dummy_packet(wl, skb))) + spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; + total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + spare_blocks; @@ -206,12 +252,14 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, desc->id = id; wl->tx_blocks_available -= total_blocks; + wl->tx_allocated_blocks += total_blocks; ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); - wl->tx_allocated_blocks[ac] += total_blocks; + wl->tx_allocated_pkts[ac]++; - if (wl->bss_type == BSS_TYPE_AP_BSS) - wl->links[hlid].allocated_blks += total_blocks; + if (wl->bss_type == BSS_TYPE_AP_BSS && + hlid >= WL1271_AP_STA_HLID_START) + wl->links[hlid].allocated_pkts++; ret = 0; @@ -225,11 +273,6 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, return ret; } -static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) -{ - return wl->dummy_packet == skb; -} - static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, u32 extra, struct ieee80211_tx_info *control, u8 hlid) @@ -280,9 +323,9 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; } - if (wl->bss_type != BSS_TYPE_AP_BSS) { - desc->aid = hlid; + desc->hlid = hlid; + if (wl->bss_type != BSS_TYPE_AP_BSS) { /* if the packets are destined for AP (have a STA entry) send them with AP rate policies, otherwise use default basic rates */ @@ -291,18 +334,12 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, else rate_idx = ACX_TX_BASIC_RATE; } else { - desc->hlid = hlid; - switch (hlid) { - case WL1271_AP_GLOBAL_HLID: + if (hlid == wl->ap_global_hlid) rate_idx = ACX_TX_AP_MODE_MGMT_RATE; - break; - case WL1271_AP_BROADCAST_HLID: + else if (hlid == wl->ap_bcast_hlid) rate_idx = ACX_TX_AP_MODE_BCST_RATE; - break; - default: + else rate_idx = ac; - break; - } } tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; @@ -376,10 +413,11 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, } } - if (wl->bss_type == BSS_TYPE_AP_BSS) - hlid = wl1271_tx_get_hlid(skb); - else - hlid = TX_HW_DEFAULT_AID; + hlid = wl1271_tx_get_hlid(wl, skb); + if (hlid == WL12XX_INVALID_LINK_ID) { + wl1271_error("invalid hlid. dropping skb 0x%p", skb); + return -EINVAL; + } ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid); if (ret < 0) @@ -390,8 +428,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, if (wl->bss_type == BSS_TYPE_AP_BSS) { wl1271_tx_ap_update_inconnection_sta(wl, skb); wl1271_tx_regulate_link(wl, hlid); - } else { - wl1271_tx_update_filters(wl, skb); } /* @@ -414,20 +450,20 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, return total_len; } -u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, + enum ieee80211_band rate_band) { struct ieee80211_supported_band *band; u32 enabled_rates = 0; int bit; - band = wl->hw->wiphy->bands[wl->band]; + band = wl->hw->wiphy->bands[rate_band]; for (bit = 0; bit < band->n_bitrates; bit++) { if (rate_set & 0x1) enabled_rates |= band->bitrates[bit].hw_value; rate_set >>= 1; } -#ifdef CONFIG_WL12XX_HT /* MCS rates indication are on bits 16 - 23 */ rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; @@ -436,7 +472,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); rate_set >>= 1; } -#endif return enabled_rates; } @@ -462,20 +497,24 @@ void wl1271_handle_tx_low_watermark(struct wl1271 *wl) static struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, struct sk_buff_head *queues) { - int i, q = -1; - u32 min_blks = 0xffffffff; + int i, q = -1, ac; + u32 min_pkts = 0xffffffff; /* * Find a non-empty ac where: * 1. There are packets to transmit * 2. The FW has the least allocated blocks + * + * We prioritize the ACs according to VO>VI>BE>BK */ - for (i = 0; i < NUM_TX_QUEUES; i++) - if (!skb_queue_empty(&queues[i]) && - (wl->tx_allocated_blocks[i] < min_blks)) { - q = i; - min_blks = wl->tx_allocated_blocks[q]; + for (i = 0; i < NUM_TX_QUEUES; i++) { + ac = wl1271_tx_get_queue(i); + if (!skb_queue_empty(&queues[ac]) && + (wl->tx_allocated_pkts[ac] < min_pkts)) { + q = ac; + min_pkts = wl->tx_allocated_pkts[q]; } + } if (q == -1) return NULL; @@ -579,7 +618,7 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) if (wl12xx_is_dummy_packet(wl, skb)) { set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); } else if (wl->bss_type == BSS_TYPE_AP_BSS) { - u8 hlid = wl1271_tx_get_hlid(skb); + u8 hlid = wl1271_tx_get_hlid(wl, skb); skb_queue_head(&wl->links[hlid].tx_queue[q], skb); /* make sure we dequeue the same packet next time */ @@ -826,10 +865,14 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) total[i] = 0; while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); - info = IEEE80211_SKB_CB(skb); - info->status.rates[0].idx = -1; - info->status.rates[0].count = 0; - ieee80211_tx_status_ni(wl->hw, skb); + + if (!wl12xx_is_dummy_packet(wl, skb)) { + info = IEEE80211_SKB_CB(skb); + info->status.rates[0].idx = -1; + info->status.rates[0].count = 0; + ieee80211_tx_status_ni(wl->hw, skb); + } + total[i]++; } } @@ -852,9 +895,10 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) /* TX failure */ if (wl->bss_type == BSS_TYPE_AP_BSS) { for (i = 0; i < AP_MAX_LINKS; i++) { + wl1271_free_sta(wl, i); wl1271_tx_reset_link_queues(wl, i); - wl->links[i].allocated_blks = 0; - wl->links[i].prev_freed_blks = 0; + wl->links[i].allocated_pkts = 0; + wl->links[i].prev_freed_pkts = 0; } wl->last_tx_hlid = 0; @@ -871,10 +915,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) ieee80211_tx_status_ni(wl->hw, skb); } } - wl->tx_queue_count[i] = 0; } + + wl->ba_rx_bitmap = 0; } + for (i = 0; i < NUM_TX_QUEUES; i++) + wl->tx_queue_count[i] = 0; + wl->stopped_queues_map = 0; /* @@ -942,20 +990,10 @@ void wl1271_tx_flush(struct wl1271 *wl) wl1271_warning("Unable to flush all TX buffers, timed out."); } -u32 wl1271_tx_min_rate_get(struct wl1271 *wl) +u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) { - int i; - u32 rate = 0; - - if (!wl->basic_rate_set) { - WARN_ON(1); - wl->basic_rate_set = wl->conf.tx.basic_rate; - } - - for (i = 0; !rate; i++) { - if ((wl->basic_rate_set >> i) & 0x1) - rate = 1 << i; - } + if (WARN_ON(!rate_set)) + return 0; - return rate; + return BIT(__ffs(rate_set)); } diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h index 5d719b5a3d1d..dc4f09adf088 100644 --- a/drivers/net/wireless/wl12xx/tx.h +++ b/drivers/net/wireless/wl12xx/tx.h @@ -25,13 +25,11 @@ #ifndef __TX_H__ #define __TX_H__ +#define TX_HW_BLOCK_SPARE_DEFAULT 1 #define TX_HW_BLOCK_SIZE 252 #define TX_HW_MGMT_PKT_LIFETIME_TU 2000 #define TX_HW_AP_MODE_PKT_LIFETIME_TU 8000 -/* The chipset reference driver states, that the "aid" value 1 - * is for infra-BSS, but is still always used */ -#define TX_HW_DEFAULT_AID 1 #define TX_HW_ATTR_SAVE_RETRIES BIT(0) #define TX_HW_ATTR_HEADER_PAD BIT(1) @@ -116,12 +114,8 @@ struct wl1271_tx_hw_descr { u8 id; /* The packet TID value (as User-Priority) */ u8 tid; - union { - /* STA - Identifier of the remote STA in IBSS, 1 in infra-BSS */ - u8 aid; - /* AP - host link ID (HLID) */ - u8 hlid; - } __packed; + /* host link ID (HLID) */ + u8 hlid; u8 reserved; } __packed; @@ -133,7 +127,8 @@ enum wl1271_tx_hw_res_status { TX_TIMEOUT = 4, TX_KEY_NOT_FOUND = 5, TX_PEER_NOT_FOUND = 6, - TX_SESSION_MISMATCH = 7 + TX_SESSION_MISMATCH = 7, + TX_LINK_NOT_VALID = 8, }; struct wl1271_tx_hw_res_descr { @@ -214,10 +209,15 @@ void wl1271_tx_complete(struct wl1271 *wl); void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues); void wl1271_tx_flush(struct wl1271 *wl); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); -u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set); -u32 wl1271_tx_min_rate_get(struct wl1271 *wl); -u8 wl1271_tx_get_hlid(struct sk_buff *skb); +u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, + enum ieee80211_band rate_band); +u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set); +u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb); void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid); void wl1271_handle_tx_low_watermark(struct wl1271 *wl); +bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb); + +/* from main.c */ +void wl1271_free_sta(struct wl1271 *wl, u8 hlid); #endif diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h index 1a8751eb8140..1ec90fc7505e 100644 --- a/drivers/net/wireless/wl12xx/wl12xx.h +++ b/drivers/net/wireless/wl12xx/wl12xx.h @@ -112,28 +112,8 @@ extern u32 wl12xx_debug_level; true); \ } while (0) -#define WL1271_DEFAULT_STA_RX_CONFIG (CFG_UNI_FILTER_EN | \ - CFG_BSSID_FILTER_EN | \ - CFG_MC_FILTER_EN) - -#define WL1271_DEFAULT_STA_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PRSP_EN | \ - CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ - CFG_RX_CTL_EN | CFG_RX_BCN_EN | \ - CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) - -#define WL1271_DEFAULT_AP_RX_CONFIG 0 - -#define WL1271_DEFAULT_AP_RX_FILTER (CFG_RX_RCTS_ACK | CFG_RX_PREQ_EN | \ - CFG_RX_MGMT_EN | CFG_RX_DATA_EN | \ - CFG_RX_CTL_EN | CFG_RX_AUTH_EN | \ - CFG_RX_ASSOC_EN) - - - -#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin" -#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin" -#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin" -#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin" +#define WL127X_FW_NAME "ti-connectivity/wl127x-fw-3.bin" +#define WL128X_FW_NAME "ti-connectivity/wl128x-fw-3.bin" /* * wl127x and wl128x are using the same NVS file name. However, the @@ -157,25 +137,34 @@ extern u32 wl12xx_debug_level; #define WL1271_DEFAULT_BEACON_INT 100 #define WL1271_DEFAULT_DTIM_PERIOD 1 -#define WL1271_AP_GLOBAL_HLID 0 -#define WL1271_AP_BROADCAST_HLID 1 -#define WL1271_AP_STA_HLID_START 2 +#define WL12XX_MAX_ROLES 4 +#define WL12XX_MAX_LINKS 12 +#define WL12XX_INVALID_ROLE_ID 0xff +#define WL12XX_INVALID_LINK_ID 0xff + +/* Defined by FW as 0. Will not be freed or allocated. */ +#define WL12XX_SYSTEM_HLID 0 + +/* + * TODO: we currently don't support multirole. remove + * this constant from the code when we do. + */ +#define WL1271_AP_STA_HLID_START 3 /* - * When in AP-mode, we allow (at least) this number of mem-blocks + * When in AP-mode, we allow (at least) this number of packets * to be transmitted to FW for a STA in PS-mode. Only when packets are * present in the FW buffers it will wake the sleeping STA. We want to put * enough packets for the driver to transmit all of its buffered data before - * the STA goes to sleep again. But we don't want to take too much mem-blocks + * the STA goes to sleep again. But we don't want to take too much memory * as it might hurt the throughput of active STAs. - * The number of blocks (18) is enough for 2 large packets. */ -#define WL1271_PS_STA_MAX_BLOCKS (2 * 9) +#define WL1271_PS_STA_MAX_PACKETS 2 #define WL1271_AP_BSS_INDEX 0 #define WL1271_AP_DEF_BEACON_EXP 20 -#define ACX_TX_DESCRIPTORS 32 +#define ACX_TX_DESCRIPTORS 16 #define WL1271_AGGR_BUFFER_SIZE (4 * PAGE_SIZE) @@ -245,28 +234,24 @@ struct wl1271_stats { #define NUM_TX_QUEUES 4 #define NUM_RX_PKT_DESC 8 -#define AP_MAX_STATIONS 5 +#define AP_MAX_STATIONS 8 -/* Broadcast and Global links + links to stations */ -#define AP_MAX_LINKS (AP_MAX_STATIONS + 2) +/* Broadcast and Global links + system link + links to stations */ +/* + * TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all + * the places that use this. + */ +#define AP_MAX_LINKS (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START) -/* FW status registers common for AP/STA */ -struct wl1271_fw_common_status { +/* FW status registers */ +struct wl12xx_fw_status { __le32 intr; u8 fw_rx_counter; u8 drv_rx_counter; u8 reserved; u8 tx_results_counter; __le32 rx_pkt_descs[NUM_RX_PKT_DESC]; - __le32 tx_released_blks[NUM_TX_QUEUES]; __le32 fw_localtime; -} __packed; - -/* FW status registers for AP */ -struct wl1271_fw_ap_status { - struct wl1271_fw_common_status common; - - /* Next fields valid only in AP FW */ /* * A bitmap (where each bit represents a single HLID) @@ -274,29 +259,29 @@ struct wl1271_fw_ap_status { */ __le32 link_ps_bitmap; - /* Number of freed MBs per HLID */ - u8 tx_lnk_free_blks[AP_MAX_LINKS]; - u8 padding_1[1]; -} __packed; + /* + * A bitmap (where each bit represents a single HLID) to indicate + * if the station is in Fast mode + */ + __le32 link_fast_bitmap; -/* FW status registers for STA */ -struct wl1271_fw_sta_status { - struct wl1271_fw_common_status common; + /* Cumulative counter of total released mem blocks since FW-reset */ + __le32 total_released_blks; - u8 tx_total; - u8 reserved1; - __le16 reserved2; - __le32 log_start_addr; -} __packed; + /* Size (in Memory Blocks) of TX pool */ + __le32 tx_total; -struct wl1271_fw_full_status { - union { - struct wl1271_fw_common_status common; - struct wl1271_fw_sta_status sta; - struct wl1271_fw_ap_status ap; - }; -} __packed; + /* Cumulative counter of released packets per AC */ + u8 tx_released_pkts[NUM_TX_QUEUES]; + /* Cumulative counter of freed packets per HLID */ + u8 tx_lnk_free_pkts[WL12XX_MAX_LINKS]; + + /* Cumulative counter of released Voice memory blocks */ + u8 tx_voice_released_blks; + u8 padding_1[3]; + __le32 log_start_addr; +} __packed; struct wl1271_rx_mem_pool_addr { u32 addr; @@ -309,7 +294,7 @@ struct wl1271_scan { unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)]; bool failed; u8 state; - u8 ssid[IW_ESSID_MAX_SIZE+1]; + u8 ssid[IEEE80211_MAX_SSID_LEN+1]; size_t ssid_len; }; @@ -342,7 +327,7 @@ struct wl1271_ap_key { enum wl12xx_flags { WL1271_FLAG_STA_ASSOCIATED, - WL1271_FLAG_JOINED, + WL1271_FLAG_IBSS_JOINED, WL1271_FLAG_GPIO_POWER, WL1271_FLAG_TX_QUEUE_STOPPED, WL1271_FLAG_TX_PENDING, @@ -363,17 +348,21 @@ enum wl12xx_flags { WL1271_FLAG_SOFT_GEMINI, WL1271_FLAG_RX_STREAMING_STARTED, WL1271_FLAG_RECOVERY_IN_PROGRESS, + WL1271_FLAG_CS_PROGRESS, }; struct wl1271_link { /* AP-mode - TX queue per AC in link */ struct sk_buff_head tx_queue[NUM_TX_QUEUES]; - /* accounting for allocated / available TX blocks in FW */ - u8 allocated_blks; - u8 prev_freed_blks; + /* accounting for allocated / freed packets in FW */ + u8 allocated_pkts; + u8 prev_freed_pkts; u8 addr[ETH_ALEN]; + + /* bitmap of TIDs where RX BA sessions are active for this link */ + u8 ba_bitmap; }; struct wl1271 { @@ -405,7 +394,6 @@ struct wl1271 { u8 *fw; size_t fw_len; - u8 fw_bss_type; void *nvs; size_t nvs_len; @@ -415,18 +403,37 @@ struct wl1271 { u8 mac_addr[ETH_ALEN]; u8 bss_type; u8 set_bss_type; - u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 p2p; /* we are using p2p role */ + u8 ssid[IEEE80211_MAX_SSID_LEN + 1]; u8 ssid_len; int channel; + u8 role_id; + u8 dev_role_id; + u8 system_hlid; + u8 sta_hlid; + u8 dev_hlid; + u8 ap_global_hlid; + u8 ap_bcast_hlid; + + unsigned long links_map[BITS_TO_LONGS(WL12XX_MAX_LINKS)]; + unsigned long roles_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; + unsigned long roc_map[BITS_TO_LONGS(WL12XX_MAX_ROLES)]; struct wl1271_acx_mem_map *target_mem_map; /* Accounting for allocated / available TX blocks on HW */ - u32 tx_blocks_freed[NUM_TX_QUEUES]; + u32 tx_blocks_freed; u32 tx_blocks_available; - u32 tx_allocated_blocks[NUM_TX_QUEUES]; + u32 tx_allocated_blocks; u32 tx_results_count; + /* amount of spare TX blocks to use */ + u32 tx_spare_blocks; + + /* Accounting for allocated / available Tx packets in HW */ + u32 tx_pkts_freed[NUM_TX_QUEUES]; + u32 tx_allocated_pkts[NUM_TX_QUEUES]; + /* Transmitted TX packets counter for chipset interface */ u32 tx_packets_count; @@ -520,6 +527,7 @@ struct wl1271 { u32 basic_rate_set; u32 basic_rate; u32 rate_set; + u32 bitrate_masks[IEEE80211_NUM_BANDS]; /* The current band */ enum ieee80211_band band; @@ -535,10 +543,6 @@ struct wl1271 { struct work_struct rx_streaming_disable_work; struct timer_list rx_streaming_timer; - unsigned int filters; - unsigned int rx_config; - unsigned int rx_filter; - struct completion *elp_compl; struct completion *ps_compl; struct delayed_work elp_work; @@ -562,7 +566,7 @@ struct wl1271 { u32 buffer_cmd; u32 buffer_busyword[WL1271_BUSY_WORD_CNT]; - struct wl1271_fw_full_status *fw_status; + struct wl12xx_fw_status *fw_status; struct wl1271_tx_hw_res_if *tx_res_if; struct ieee80211_vif *vif; @@ -622,6 +626,12 @@ struct wl1271 { /* Platform limitations */ unsigned int platform_quirks; + + /* number of currently active RX BA sessions */ + int ba_rx_session_count; + + /* AP-mode - number of currently connected stations */ + int active_sta_count; }; struct wl1271_station { @@ -659,21 +669,9 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); /* Each RX/TX transaction requires an end-of-transaction transfer */ #define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0) -/* - * Older firmwares use 2 spare TX blocks - * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47) - */ -#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1) - /* WL128X requires aggregated packets to be aligned to the SDIO block size */ #define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2) -/* - * WL127X AP mode requires Low Power DRPw (LPD) enable to reduce power - * consumption - */ -#define WL12XX_QUIRK_LPD_MODE BIT(3) - /* Older firmwares did not implement the FW logger over bus feature */ #define WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED BIT(4) diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h index 18fe542360f2..f7971d3b0898 100644 --- a/drivers/net/wireless/wl12xx/wl12xx_80211.h +++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h @@ -77,7 +77,7 @@ struct wl12xx_ie_header { struct wl12xx_ie_ssid { struct wl12xx_ie_header header; - char ssid[IW_ESSID_MAX_SIZE]; + char ssid[IEEE80211_MAX_SSID_LEN]; } __packed; struct wl12xx_ie_rates { @@ -105,18 +105,6 @@ struct wl12xx_ie_country { /* Templates */ -struct wl12xx_beacon_template { - struct ieee80211_header header; - __le32 time_stamp[2]; - __le16 beacon_interval; - __le16 capability; - struct wl12xx_ie_ssid ssid; - struct wl12xx_ie_rates rates; - struct wl12xx_ie_rates ext_rates; - struct wl12xx_ie_ds_params ds_params; - struct wl12xx_ie_country country; -} __packed; - struct wl12xx_null_data_template { struct ieee80211_header header; } __packed; @@ -146,19 +134,6 @@ struct wl12xx_arp_rsp_template { __be32 target_ip; } __packed; - -struct wl12xx_probe_resp_template { - struct ieee80211_header header; - __le32 time_stamp[2]; - __le16 beacon_interval; - __le16 capability; - struct wl12xx_ie_ssid ssid; - struct wl12xx_ie_rates rates; - struct wl12xx_ie_rates ext_rates; - struct wl12xx_ie_ds_params ds_params; - struct wl12xx_ie_country country; -} __packed; - struct wl12xx_disconn_template { struct ieee80211_header header; __le16 disconn_reason; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 6bc7c92fbff7..98fbf54f6004 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -1781,7 +1781,7 @@ static int wl3501_get_encode(struct net_device *dev, keys, len_keys); if (rc) goto out; - tocopy = min_t(u8, len_keys, wrqu->encoding.length); + tocopy = min_t(u16, len_keys, wrqu->encoding.length); tocopy = min_t(u8, tocopy, 100); wrqu->encoding.length = tocopy; memcpy(extra, keys, tocopy); diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 415eec401e2e..8efa2f2d9579 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -1722,7 +1722,7 @@ static const struct net_device_ops zd1201_netdev_ops = { .ndo_stop = zd1201_net_stop, .ndo_start_xmit = zd1201_hard_start_xmit, .ndo_tx_timeout = zd1201_tx_timeout, - .ndo_set_multicast_list = zd1201_set_multicast, + .ndo_set_rx_mode = zd1201_set_multicast, .ndo_set_mac_address = zd1201_set_mac_address, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index cabfae1e70b1..0a70149df3fc 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1332,7 +1332,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw, } } -static u64 zd_op_get_tsf(struct ieee80211_hw *hw) +static u64 zd_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct zd_mac *mac = zd_hw_mac(hw); return zd_chip_get_tsf(&mac->chip); |