Index: head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h =================================================================== --- head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h (revision 280828) +++ head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300.h (revision 280829) @@ -1,1715 +1,1717 @@ /* * Copyright (c) 2013 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifndef _ATH_AR9300_H_ #define _ATH_AR9300_H_ #include "ar9300_freebsd_inc.h" #define AH_BIG_ENDIAN 4321 #define AH_LITTLE_ENDIAN 1234 #if _BYTE_ORDER == _BIG_ENDIAN #define AH_BYTE_ORDER AH_BIG_ENDIAN #else #define AH_BYTE_ORDER AH_LITTLE_ENDIAN #endif /* XXX doesn't belong here */ #define AR_EEPROM_MODAL_SPURS 5 /* * (a) this should be N(a), * (b) FreeBSD does define nitems, * (c) it doesn't have an AH_ prefix, sigh. */ #define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) #include "ah_internal.h" #include "ah_eeprom.h" #include "ah_devid.h" #include "ar9300eep.h" /* For Eeprom definitions */ #define AR9300_MAGIC 0x19741014 /* MAC register values */ #define INIT_CONFIG_STATUS 0x00000000 #define INIT_RSSI_THR 0x7 /* Missed beacon counter initialized to 0x7 (max is 0xff) */ #define INIT_RSSI_BEACON_WEIGHT 8 /* ave beacon rssi weight (0-16) */ /* * Various fifo fill before Tx start, in 64-byte units * i.e. put the frame in the air while still DMAing */ #define MIN_TX_FIFO_THRESHOLD 0x1 #define MAX_TX_FIFO_THRESHOLD (( 4096 / 64) - 1) #define INIT_TX_FIFO_THRESHOLD MIN_TX_FIFO_THRESHOLD #define CHANSEL_DIV 15 #define FCLK 40 #define COEFF ((FCLK * 5) / 2) #define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV) #define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV) #define CHANSEL_5G_DOT5MHZ 2188 /* * Receive Queue Fifo depth. */ enum RX_FIFO_DEPTH { HAL_HP_RXFIFO_DEPTH = 16, HAL_LP_RXFIFO_DEPTH = 128, }; /* * Gain support. */ #define NUM_CORNER_FIX_BITS_2133 7 #define CCK_OFDM_GAIN_DELTA 15 enum GAIN_PARAMS { GP_TXCLIP, GP_PD90, GP_PD84, GP_GSEL }; enum GAIN_PARAMS_2133 { GP_MIXGAIN_OVR, GP_PWD_138, GP_PWD_137, GP_PWD_136, GP_PWD_132, GP_PWD_131, GP_PWD_130, }; enum { HAL_RESET_POWER_ON, HAL_RESET_WARM, HAL_RESET_COLD, }; typedef struct _gain_opt_step { int16_t paramVal[NUM_CORNER_FIX_BITS_2133]; int32_t stepGain; int8_t stepName[16]; } GAIN_OPTIMIZATION_STEP; typedef struct { u_int32_t numStepsInLadder; u_int32_t defaultStepNum; GAIN_OPTIMIZATION_STEP optStep[10]; } GAIN_OPTIMIZATION_LADDER; typedef struct { u_int32_t currStepNum; u_int32_t currGain; u_int32_t targetGain; u_int32_t loTrig; u_int32_t hiTrig; u_int32_t gainFCorrection; u_int32_t active; GAIN_OPTIMIZATION_STEP *curr_step; } GAIN_VALUES; typedef struct { u_int16_t synth_center; u_int16_t ctl_center; u_int16_t ext_center; } CHAN_CENTERS; /* RF HAL structures */ typedef struct rf_hal_funcs { HAL_BOOL (*set_channel)(struct ath_hal *, struct ieee80211_channel *); HAL_BOOL (*get_chip_power_lim)(struct ath_hal *ah, struct ieee80211_channel *chan); } RF_HAL_FUNCS; struct ar9300_ani_default { u_int16_t m1_thresh_low; u_int16_t m2_thresh_low; u_int16_t m1_thresh; u_int16_t m2_thresh; u_int16_t m2_count_thr; u_int16_t m2_count_thr_low; u_int16_t m1_thresh_low_ext; u_int16_t m2_thresh_low_ext; u_int16_t m1_thresh_ext; u_int16_t m2_thresh_ext; u_int16_t firstep; u_int16_t firstep_low; u_int16_t cycpwr_thr1; u_int16_t cycpwr_thr1_ext; }; /* * Per-channel ANI state private to the driver. */ struct ar9300_ani_state { struct ieee80211_channel c; /* XXX ew? */ HAL_BOOL must_restore; HAL_BOOL ofdms_turn; u_int8_t ofdm_noise_immunity_level; u_int8_t cck_noise_immunity_level; u_int8_t spur_immunity_level; u_int8_t firstep_level; u_int8_t ofdm_weak_sig_detect_off; u_int8_t mrc_cck_off; /* Thresholds */ u_int32_t listen_time; u_int32_t ofdm_trig_high; u_int32_t ofdm_trig_low; int32_t cck_trig_high; int32_t cck_trig_low; int32_t rssi_thr_low; int32_t rssi_thr_high; int32_t rssi; /* The current RSSI */ u_int32_t tx_frame_count; /* Last tx_frame_count */ u_int32_t rx_frame_count; /* Last rx Frame count */ + u_int32_t rx_busy_count; /* Last rx busy count */ + u_int32_t rx_ext_busy_count; /* Last rx busy count; extension channel */ u_int32_t cycle_count; /* Last cycle_count (can detect wrap-around) */ u_int32_t ofdm_phy_err_count;/* OFDM err count since last reset */ u_int32_t cck_phy_err_count; /* CCK err count since last reset */ struct ar9300_ani_default ini_def; /* INI default values for ANI registers */ HAL_BOOL phy_noise_spur; /* based on OFDM/CCK Phy errors */ }; #define AR9300_ANI_POLLINTERVAL 1000 /* 1000 milliseconds between ANI poll */ #define AR9300_CHANNEL_SWITCH_TIME_USEC 1000 /* 1 millisecond needed to change channels */ #define HAL_PROCESS_ANI 0x00000001 /* ANI state setup */ #define HAL_RADAR_EN 0x80000000 /* Radar detect is capable */ #define HAL_AR_EN 0x40000000 /* AR detect is capable */ #define DO_ANI(ah) \ ((AH9300(ah)->ah_proc_phy_err & HAL_PROCESS_ANI)) struct ar9300_stats { u_int32_t ast_ani_niup; /* ANI increased noise immunity */ u_int32_t ast_ani_nidown; /* ANI decreased noise immunity */ u_int32_t ast_ani_spurup; /* ANI increased spur immunity */ u_int32_t ast_ani_spurdown;/* ANI descreased spur immunity */ u_int32_t ast_ani_ofdmon; /* ANI OFDM weak signal detect on */ u_int32_t ast_ani_ofdmoff;/* ANI OFDM weak signal detect off */ u_int32_t ast_ani_cckhigh;/* ANI CCK weak signal threshold high */ u_int32_t ast_ani_ccklow; /* ANI CCK weak signal threshold low */ u_int32_t ast_ani_stepup; /* ANI increased first step level */ u_int32_t ast_ani_stepdown;/* ANI decreased first step level */ u_int32_t ast_ani_ofdmerrs;/* ANI cumulative ofdm phy err count */ u_int32_t ast_ani_cckerrs;/* ANI cumulative cck phy err count */ u_int32_t ast_ani_reset; /* ANI parameters zero'd for non-STA */ u_int32_t ast_ani_lzero; /* ANI listen time forced to zero */ u_int32_t ast_ani_lneg; /* ANI listen time calculated < 0 */ HAL_MIB_STATS ast_mibstats; /* MIB counter stats */ HAL_NODE_STATS ast_nodestats; /* Latest rssi stats from driver */ }; struct ar9300_rad_reader { u_int16_t rd_index; u_int16_t rd_expSeq; u_int32_t rd_resetVal; u_int8_t rd_start; }; struct ar9300_rad_writer { u_int16_t wr_index; u_int16_t wr_seq; }; struct ar9300_radar_event { u_int32_t re_ts; /* 32 bit time stamp */ u_int8_t re_rssi; /* rssi of radar event */ u_int8_t re_dur; /* duration of radar pulse */ u_int8_t re_chanIndex; /* Channel of event */ }; struct ar9300_radar_q_elem { u_int32_t rq_seqNum; u_int32_t rq_busy; /* 32 bit to insure atomic read/write */ struct ar9300_radar_event rq_event; /* Radar event */ }; struct ar9300_radar_q_info { u_int16_t ri_qsize; /* q size */ u_int16_t ri_seqSize; /* Size of sequence ring */ struct ar9300_rad_reader ri_reader; /* State for the q reader */ struct ar9300_rad_writer ri_writer; /* state for the q writer */ }; #define HAL_MAX_ACK_RADAR_DUR 511 #define HAL_MAX_NUM_PEAKS 3 #define HAL_ARQ_SIZE 4096 /* 8K AR events for buffer size */ #define HAL_ARQ_SEQSIZE 4097 /* Sequence counter wrap for AR */ #define HAL_RADARQ_SIZE 1024 /* 1K radar events for buffer size */ #define HAL_RADARQ_SEQSIZE 1025 /* Sequence counter wrap for radar */ #define HAL_NUMRADAR_STATES 64 /* Number of radar channels we keep state for */ struct ar9300_ar_state { u_int16_t ar_prev_time_stamp; u_int32_t ar_prev_width; u_int32_t ar_phy_err_count[HAL_MAX_ACK_RADAR_DUR]; u_int32_t ar_ack_sum; u_int16_t ar_peak_list[HAL_MAX_NUM_PEAKS]; u_int32_t ar_packet_threshold; /* Thresh to determine traffic load */ u_int32_t ar_par_threshold; /* Thresh to determine peak */ u_int32_t ar_radar_rssi; /* Rssi threshold for AR event */ }; struct ar9300_radar_state { struct ieee80211_channel *rs_chan; /* Channel info */ u_int8_t rs_chan_index; /* Channel index in radar structure */ u_int32_t rs_num_radar_events; /* Number of radar events */ int32_t rs_firpwr; /* Thresh to check radar sig is gone */ u_int32_t rs_radar_rssi; /* Thresh to start radar det (dB) */ u_int32_t rs_height; /* Thresh for pulse height (dB)*/ u_int32_t rs_pulse_rssi; /* Thresh to check if pulse is gone (dB) */ u_int32_t rs_inband; /* Thresh to check if pusle is inband (0.5 dB) */ }; typedef struct { u_int8_t uc_receiver_errors; u_int8_t uc_bad_tlp_errors; u_int8_t uc_bad_dllp_errors; u_int8_t uc_replay_timeout_errors; u_int8_t uc_replay_number_rollover_errors; } ar_pcie_error_moniter_counters; #define AR9300_OPFLAGS_11A 0x01 /* if set, allow 11a */ #define AR9300_OPFLAGS_11G 0x02 /* if set, allow 11g */ #define AR9300_OPFLAGS_N_5G_HT40 0x04 /* if set, disable 5G HT40 */ #define AR9300_OPFLAGS_N_2G_HT40 0x08 /* if set, disable 2G HT40 */ #define AR9300_OPFLAGS_N_5G_HT20 0x10 /* if set, disable 5G HT20 */ #define AR9300_OPFLAGS_N_2G_HT20 0x20 /* if set, disable 2G HT20 */ /* * For Kite and later chipsets, the following bits are not being programmed in EEPROM * and so need to be enabled always. * Bit 0: en_fcc_mid, Bit 1: en_jap_mid, Bit 2: en_fcc_dfs_ht40 * Bit 3: en_jap_ht40, Bit 4: en_jap_dfs_ht40 */ #define AR9300_RDEXT_DEFAULT 0x1F #define AR9300_MAX_CHAINS 3 #define AR9300_NUM_CHAINS(chainmask) \ (((chainmask >> 2) & 1) + ((chainmask >> 1) & 1) + (chainmask & 1)) #define AR9300_CHAIN0_MASK 0x1 #define AR9300_CHAIN1_MASK 0x2 #define AR9300_CHAIN2_MASK 0x4 /* Support for multiple INIs */ struct ar9300_ini_array { const u_int32_t *ia_array; u_int32_t ia_rows; u_int32_t ia_columns; }; #define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ (iniarray)->ia_array = (const u_int32_t *)(array); \ (iniarray)->ia_rows = (rows); \ (iniarray)->ia_columns = (columns); \ } while (0) #define INI_RA(iniarray, row, column) (((iniarray)->ia_array)[(row) * ((iniarray)->ia_columns) + (column)]) #define INIT_CAL(_perCal) \ (_perCal)->cal_state = CAL_WAITING; \ (_perCal)->cal_next = AH_NULL; #define INSERT_CAL(_ahp, _perCal) \ do { \ if ((_ahp)->ah_cal_list_last == AH_NULL) { \ (_ahp)->ah_cal_list = (_ahp)->ah_cal_list_last = (_perCal); \ ((_ahp)->ah_cal_list_last)->cal_next = (_perCal); \ } else { \ ((_ahp)->ah_cal_list_last)->cal_next = (_perCal); \ (_ahp)->ah_cal_list_last = (_perCal); \ (_perCal)->cal_next = (_ahp)->ah_cal_list; \ } \ } while (0) typedef enum cal_types { IQ_MISMATCH_CAL = 0x1, TEMP_COMP_CAL = 0x2, } HAL_CAL_TYPES; typedef enum cal_state { CAL_INACTIVE, CAL_WAITING, CAL_RUNNING, CAL_DONE } HAL_CAL_STATE; /* Calibrate state */ #define MIN_CAL_SAMPLES 1 #define MAX_CAL_SAMPLES 64 #define INIT_LOG_COUNT 5 #define PER_MIN_LOG_COUNT 2 #define PER_MAX_LOG_COUNT 10 #define AR9300_NUM_BT_WEIGHTS 4 #define AR9300_NUM_WLAN_WEIGHTS 4 /* Per Calibration data structure */ typedef struct per_cal_data { HAL_CAL_TYPES cal_type; // Type of calibration u_int32_t cal_num_samples; // Number of SW samples to collect u_int32_t cal_count_max; // Number of HW samples to collect void (*cal_collect)(struct ath_hal *, u_int8_t); // Accumulator func void (*cal_post_proc)(struct ath_hal *, u_int8_t); // Post-processing func } HAL_PERCAL_DATA; /* List structure for calibration data */ typedef struct cal_list { const HAL_PERCAL_DATA *cal_data; HAL_CAL_STATE cal_state; struct cal_list *cal_next; } HAL_CAL_LIST; #define AR9300_NUM_CAL_TYPES 2 #define AR9300_PAPRD_TABLE_SZ 24 #define AR9300_PAPRD_GAIN_TABLE_SZ 32 #define AR9382_MAX_GPIO_PIN_NUM (16) #define AR9382_GPIO_PIN_8_RESERVED (8) #define AR9382_GPIO_9_INPUT_ONLY (9) #define AR9382_MAX_GPIO_INPUT_PIN_NUM (13) #define AR9382_GPIO_PIN_11_RESERVED (11) #define AR9382_MAX_JTAG_GPIO_PIN_NUM (3) /* Paprd tx power adjust data structure */ struct ar9300_paprd_pwr_adjust { u_int32_t target_rate; // rate index u_int32_t reg_addr; // register offset u_int32_t reg_mask; // mask of register u_int32_t reg_mask_offset; // mask offset of register u_int32_t sub_db; // offset value unit of dB }; struct ar9300NfLimits { int16_t max; int16_t min; int16_t nominal; }; #define AR9300_MAX_RATES 36 /* legacy(4) + ofdm(8) + HTSS(8) + HTDS(8) + HTTS(8)*/ struct ath_hal_9300 { struct ath_hal_private ah_priv; /* base class */ /* * Information retrieved from EEPROM. */ ar9300_eeprom_t ah_eeprom; GAIN_VALUES ah_gain_values; u_int8_t ah_macaddr[IEEE80211_ADDR_LEN]; u_int8_t ah_bssid[IEEE80211_ADDR_LEN]; u_int8_t ah_bssid_mask[IEEE80211_ADDR_LEN]; u_int16_t ah_assoc_id; /* * Runtime state. */ u_int32_t ah_mask_reg; /* copy of AR_IMR */ u_int32_t ah_mask2Reg; /* copy of AR_IMR_S2 */ u_int32_t ah_msi_reg; /* copy of AR_PCIE_MSI */ os_atomic_t ah_ier_ref_count; /* reference count for enabling interrupts */ struct ar9300_stats ah_stats; /* various statistics */ RF_HAL_FUNCS ah_rf_hal; u_int32_t ah_tx_desc_mask; /* mask for TXDESC */ u_int32_t ah_tx_ok_interrupt_mask; u_int32_t ah_tx_err_interrupt_mask; u_int32_t ah_tx_desc_interrupt_mask; u_int32_t ah_tx_eol_interrupt_mask; u_int32_t ah_tx_urn_interrupt_mask; HAL_TX_QUEUE_INFO ah_txq[HAL_NUM_TX_QUEUES]; HAL_SMPS_MODE ah_sm_power_mode; HAL_BOOL ah_chip_full_sleep; u_int32_t ah_atim_window; HAL_ANT_SETTING ah_diversity_control; /* antenna setting */ u_int16_t ah_antenna_switch_swap; /* Controls mapping of OID request */ u_int8_t ah_tx_chainmask_cfg; /* chain mask config */ u_int8_t ah_rx_chainmask_cfg; u_int32_t ah_beacon_rssi_threshold; /* cache beacon rssi threshold */ /* Calibration related fields */ HAL_CAL_TYPES ah_supp_cals; HAL_CAL_LIST ah_iq_cal_data; /* IQ Cal Data */ HAL_CAL_LIST ah_temp_comp_cal_data; /* Temperature Compensation Cal Data */ HAL_CAL_LIST *ah_cal_list; /* ptr to first cal in list */ HAL_CAL_LIST *ah_cal_list_last; /* ptr to last cal in list */ HAL_CAL_LIST *ah_cal_list_curr; /* ptr to current cal */ // IQ Cal aliases #define ah_total_power_meas_i ah_meas0.unsign #define ah_total_power_meas_q ah_meas1.unsign #define ah_total_iq_corr_meas ah_meas2.sign union { u_int32_t unsign[AR9300_MAX_CHAINS]; int32_t sign[AR9300_MAX_CHAINS]; } ah_meas0; union { u_int32_t unsign[AR9300_MAX_CHAINS]; int32_t sign[AR9300_MAX_CHAINS]; } ah_meas1; union { u_int32_t unsign[AR9300_MAX_CHAINS]; int32_t sign[AR9300_MAX_CHAINS]; } ah_meas2; union { u_int32_t unsign[AR9300_MAX_CHAINS]; int32_t sign[AR9300_MAX_CHAINS]; } ah_meas3; u_int16_t ah_cal_samples; /* end - Calibration related fields */ u_int32_t ah_tx6_power_in_half_dbm; /* power output for 6Mb tx */ u_int32_t ah_sta_id1_defaults; /* STA_ID1 default settings */ u_int32_t ah_misc_mode; /* MISC_MODE settings */ HAL_BOOL ah_get_plcp_hdr; /* setting about MISC_SEL_EVM */ enum { AUTO_32KHZ, /* use it if 32kHz crystal present */ USE_32KHZ, /* do it regardless */ DONT_USE_32KHZ, /* don't use it regardless */ } ah_enable32k_hz_clock; /* whether to sleep at 32kHz */ u_int32_t ah_ofdm_tx_power; int16_t ah_tx_power_index_offset; u_int ah_slot_time; /* user-specified slot time */ u_int ah_ack_timeout; /* user-specified ack timeout */ /* * XXX * 11g-specific stuff; belongs in the driver. */ u_int8_t ah_g_beacon_rate; /* fixed rate for G beacons */ u_int32_t ah_gpio_mask; /* copy of enabled GPIO mask */ u_int32_t ah_gpio_cause; /* copy of GPIO cause (sync and async) */ /* * RF Silent handling; setup according to the EEPROM. */ u_int32_t ah_gpio_select; /* GPIO pin to use */ u_int32_t ah_polarity; /* polarity to disable RF */ u_int32_t ah_gpio_bit; /* after init, prev value */ HAL_BOOL ah_eep_enabled; /* EEPROM bit for capability */ #ifdef ATH_BT_COEX /* * Bluetooth coexistence static setup according to the registry */ HAL_BT_MODULE ah_bt_module; /* Bluetooth module identifier */ u_int8_t ah_bt_coex_config_type; /* BT coex configuration */ u_int8_t ah_bt_active_gpio_select; /* GPIO pin for BT_ACTIVE */ u_int8_t ah_bt_priority_gpio_select; /* GPIO pin for BT_PRIORITY */ u_int8_t ah_wlan_active_gpio_select; /* GPIO pin for WLAN_ACTIVE */ u_int8_t ah_bt_active_polarity; /* Polarity of BT_ACTIVE */ HAL_BOOL ah_bt_coex_single_ant; /* Single or dual antenna configuration */ u_int8_t ah_bt_wlan_isolation; /* Isolation between BT and WLAN in dB */ /* * Bluetooth coexistence runtime settings */ HAL_BOOL ah_bt_coex_enabled; /* If Bluetooth coexistence is enabled */ u_int32_t ah_bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ u_int32_t ah_bt_coex_bt_weight[AR9300_NUM_BT_WEIGHTS]; /* Register setting for AR_BT_COEX_WEIGHT */ u_int32_t ah_bt_coex_wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; /* Register setting for AR_BT_COEX_WEIGHT */ u_int32_t ah_bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ u_int32_t ah_bt_coex_flag; /* Special tuning flags for BT coex */ #endif /* * Generic timer support */ u_int32_t ah_avail_gen_timers; /* mask of available timers */ u_int32_t ah_intr_gen_timer_trigger; /* generic timer trigger interrupt state */ u_int32_t ah_intr_gen_timer_thresh; /* generic timer trigger interrupt state */ HAL_BOOL ah_enable_tsf2; /* enable TSF2 for gen timer 8-15. */ /* * ANI & Radar support. */ u_int32_t ah_proc_phy_err; /* Process Phy errs */ u_int32_t ah_ani_period; /* ani update list period */ struct ar9300_ani_state *ah_curani; /* cached last reference */ struct ar9300_ani_state ah_ani[255]; /* per-channel state */ struct ar9300_radar_state ah_radar[HAL_NUMRADAR_STATES]; /* Per-Channel Radar detector state */ struct ar9300_radar_q_elem *ah_radarq; /* radar event queue */ struct ar9300_radar_q_info ah_radarq_info; /* radar event q read/write state */ struct ar9300_ar_state ah_ar; /* AR detector state */ struct ar9300_radar_q_elem *ah_arq; /* AR event queue */ struct ar9300_radar_q_info ah_arq_info; /* AR event q read/write state */ /* * Transmit power state. Note these are maintained * here so they can be retrieved by diagnostic tools. */ u_int16_t ah_rates_array[16]; /* * Tx queue interrupt state. */ u_int32_t ah_intr_txqs; HAL_BOOL ah_intr_mitigation_rx; /* rx Interrupt Mitigation Settings */ HAL_BOOL ah_intr_mitigation_tx; /* tx Interrupt Mitigation Settings */ /* * Extension Channel Rx Clear State */ u_int32_t ah_cycle_count; u_int32_t ah_ctl_busy; u_int32_t ah_ext_busy; /* HT CWM state */ HAL_HT_EXTPROTSPACING ah_ext_prot_spacing; u_int8_t ah_tx_chainmask; /* tx chain mask */ u_int8_t ah_rx_chainmask; /* rx chain mask */ /* optional tx chainmask */ u_int8_t ah_tx_chainmaskopt; u_int8_t ah_tx_cal_chainmask; /* tx cal chain mask */ u_int8_t ah_rx_cal_chainmask; /* rx cal chain mask */ int ah_hwp; void *ah_cal_mem; HAL_BOOL ah_emu_eeprom; HAL_ANI_CMD ah_ani_function; HAL_BOOL ah_rifs_enabled; u_int32_t ah_rifs_reg[11]; u_int32_t ah_rifs_sec_cnt; /* open-loop power control */ u_int32_t original_gain[22]; int32_t init_pdadc; int32_t pdadc_delta; /* cycle counts for beacon stuck diagnostics */ u_int32_t ah_cycles; u_int32_t ah_rx_clear; u_int32_t ah_rx_frame; u_int32_t ah_tx_frame; #define BB_HANG_SIG1 0 #define BB_HANG_SIG2 1 #define BB_HANG_SIG3 2 #define BB_HANG_SIG4 3 #define MAC_HANG_SIG1 4 #define MAC_HANG_SIG2 5 /* bb hang detection */ int ah_hang[6]; hal_hw_hangs_t ah_hang_wars; /* * Keytable type table */ #define AR_KEYTABLE_SIZE 128 /* XXX! */ uint8_t ah_keytype[AR_KEYTABLE_SIZE]; #undef AR_KEYTABLE_SIZE /* * Support for ar9300 multiple INIs */ struct ar9300_ini_array ah_ini_pcie_serdes; struct ar9300_ini_array ah_ini_pcie_serdes_low_power; struct ar9300_ini_array ah_ini_modes_additional; struct ar9300_ini_array ah_ini_modes_additional_40mhz; struct ar9300_ini_array ah_ini_modes_rxgain; struct ar9300_ini_array ah_ini_modes_rxgain_bounds; struct ar9300_ini_array ah_ini_modes_txgain; struct ar9300_ini_array ah_ini_japan2484; struct ar9300_ini_array ah_ini_radio_post_sys2ant; struct ar9300_ini_array ah_ini_BTCOEX_MAX_TXPWR; /* * New INI format starting with Osprey 2.0 INI. * Pre, core, post arrays for each sub-system (mac, bb, radio, soc) */ #define ATH_INI_PRE 0 #define ATH_INI_CORE 1 #define ATH_INI_POST 2 #define ATH_INI_NUM_SPLIT (ATH_INI_POST + 1) struct ar9300_ini_array ah_ini_mac[ATH_INI_NUM_SPLIT]; /* New INI format */ struct ar9300_ini_array ah_ini_bb[ATH_INI_NUM_SPLIT]; /* New INI format */ struct ar9300_ini_array ah_ini_radio[ATH_INI_NUM_SPLIT]; /* New INI format */ struct ar9300_ini_array ah_ini_soc[ATH_INI_NUM_SPLIT]; /* New INI format */ /* * Added to support DFS postamble array in INI that we need to apply * in DFS channels */ struct ar9300_ini_array ah_ini_dfs; #if ATH_WOW struct ar9300_ini_array ah_ini_pcie_serdes_wow; /* SerDes values during WOW sleep */ #endif /* To indicate EEPROM mapping used */ u_int32_t ah_immunity_vals[6]; HAL_BOOL ah_immunity_on; /* * snap shot of counter register for debug purposes */ #ifdef AH_DEBUG u_int32_t last_tf; u_int32_t last_rf; u_int32_t last_rc; u_int32_t last_cc; #endif HAL_BOOL ah_dma_stuck; /* Set to AH_TRUE when RX/TX DMA failed to stop. */ u_int32_t nf_tsf32; /* timestamp for NF calibration duration */ u_int32_t reg_dmn; /* Regulatory Domain */ int16_t twice_antenna_gain; /* Antenna Gain */ u_int16_t twice_antenna_reduction; /* Antenna Gain Allowed */ /* * Upper limit after factoring in the regulatory max, antenna gain and * multichain factor. No TxBF, CDD or STBC gain factored */ int16_t upper_limit[AR9300_MAX_CHAINS]; /* adjusted power for descriptor-based TPC for 1, 2, or 3 chains */ int16_t txpower[AR9300_MAX_RATES][AR9300_MAX_CHAINS]; /* adjusted power for descriptor-based TPC for 1, 2, or 3 chains with STBC*/ int16_t txpower_stbc[AR9300_MAX_RATES][AR9300_MAX_CHAINS]; /* Transmit Status ring support */ struct ar9300_txs *ts_ring; u_int16_t ts_tail; u_int16_t ts_size; u_int32_t ts_paddr_start; u_int32_t ts_paddr_end; /* Receive Buffer size */ #define HAL_RXBUFSIZE_DEFAULT 0xfff u_int16_t rx_buf_size; u_int32_t ah_wa_reg_val; // Store the permanent value of Reg 0x4004 so we dont have to R/M/W. (We should not be reading this register when in sleep states). /* Indicate the PLL source clock rate is 25Mhz or not. * clk_25mhz = 0 by default. */ u_int8_t clk_25mhz; /* For PAPRD uses */ u_int16_t small_signal_gain[AH_MAX_CHAINS]; u_int32_t pa_table[AH_MAX_CHAINS][AR9300_PAPRD_TABLE_SZ]; u_int32_t paprd_gain_table_entries[AR9300_PAPRD_GAIN_TABLE_SZ]; u_int32_t paprd_gain_table_index[AR9300_PAPRD_GAIN_TABLE_SZ]; u_int32_t ah_2g_paprd_rate_mask_ht20; /* Copy of eep->modal_header_2g.paprd_rate_mask_ht20 */ u_int32_t ah_2g_paprd_rate_mask_ht40; /* Copy of eep->modal_header_2g.paprd_rate_mask_ht40 */ u_int32_t ah_5g_paprd_rate_mask_ht20; /* Copy of eep->modal_header_5g.paprd_rate_mask_ht20 */ u_int32_t ah_5g_paprd_rate_mask_ht40; /* Copy of eep->modal_header_5g.paprd_rate_mask_ht40 */ u_int32_t paprd_training_power; /* For GreenTx use to store the default tx power */ u_int8_t ah_default_tx_power[ar9300_rate_size]; HAL_BOOL ah_paprd_broken; /* To store offsets of host interface registers */ struct { u_int32_t AR_RC; u_int32_t AR_WA; u_int32_t AR_PM_STATE; u_int32_t AR_H_INFOL; u_int32_t AR_H_INFOH; u_int32_t AR_PCIE_PM_CTRL; u_int32_t AR_HOST_TIMEOUT; u_int32_t AR_EEPROM; u_int32_t AR_SREV; u_int32_t AR_INTR_SYNC_CAUSE; u_int32_t AR_INTR_SYNC_CAUSE_CLR; u_int32_t AR_INTR_SYNC_ENABLE; u_int32_t AR_INTR_ASYNC_MASK; u_int32_t AR_INTR_SYNC_MASK; u_int32_t AR_INTR_ASYNC_CAUSE_CLR; u_int32_t AR_INTR_ASYNC_CAUSE; u_int32_t AR_INTR_ASYNC_ENABLE; u_int32_t AR_PCIE_SERDES; u_int32_t AR_PCIE_SERDES2; u_int32_t AR_GPIO_OUT; u_int32_t AR_GPIO_IN; u_int32_t AR_GPIO_OE_OUT; u_int32_t AR_GPIO_OE1_OUT; u_int32_t AR_GPIO_INTR_POL; u_int32_t AR_GPIO_INPUT_EN_VAL; u_int32_t AR_GPIO_INPUT_MUX1; u_int32_t AR_GPIO_INPUT_MUX2; u_int32_t AR_GPIO_OUTPUT_MUX1; u_int32_t AR_GPIO_OUTPUT_MUX2; u_int32_t AR_GPIO_OUTPUT_MUX3; u_int32_t AR_INPUT_STATE; u_int32_t AR_SPARE; u_int32_t AR_PCIE_CORE_RESET_EN; u_int32_t AR_CLKRUN; u_int32_t AR_EEPROM_STATUS_DATA; u_int32_t AR_OBS; u_int32_t AR_RFSILENT; u_int32_t AR_GPIO_PDPU; u_int32_t AR_GPIO_DS; u_int32_t AR_MISC; u_int32_t AR_PCIE_MSI; u_int32_t AR_TSF_SNAPSHOT_BT_ACTIVE; u_int32_t AR_TSF_SNAPSHOT_BT_PRIORITY; u_int32_t AR_TSF_SNAPSHOT_BT_CNTL; u_int32_t AR_PCIE_PHY_LATENCY_NFTS_ADJ; u_int32_t AR_TDMA_CCA_CNTL; u_int32_t AR_TXAPSYNC; u_int32_t AR_TXSYNC_INIT_SYNC_TMR; u_int32_t AR_INTR_PRIO_SYNC_CAUSE; u_int32_t AR_INTR_PRIO_SYNC_ENABLE; u_int32_t AR_INTR_PRIO_ASYNC_MASK; u_int32_t AR_INTR_PRIO_SYNC_MASK; u_int32_t AR_INTR_PRIO_ASYNC_CAUSE; u_int32_t AR_INTR_PRIO_ASYNC_ENABLE; } ah_hostifregs; u_int32_t ah_enterprise_mode; u_int32_t ah_radar1; u_int32_t ah_dc_offset; HAL_BOOL ah_hw_green_tx_enable; /* 1:enalbe H/W Green Tx */ HAL_BOOL ah_smartantenna_enable; /* 1:enalbe H/W */ u_int32_t ah_disable_cck; HAL_BOOL ah_lna_div_use_bt_ant_enable; /* 1:enable Rx(LNA) Diversity */ /* * Different types of memory where the calibration data might be stored. * All types are searched in Ar9300EepromRestore() in the order flash, eeprom, otp. * To disable searching a type, set its parameter to 0. */ int try_dram; int try_flash; int try_eeprom; int try_otp; #ifdef ATH_CAL_NAND_FLASH int try_nand; #endif /* * This is where we found the calibration data. */ int calibration_data_source; int calibration_data_source_address; /* * This is where we look for the calibration data. must be set before ath_attach() is called */ int calibration_data_try; int calibration_data_try_address; u_int8_t tx_iq_cal_enable : 1, tx_iq_cal_during_agc_cal : 1, tx_cl_cal_enable : 1; #if ATH_SUPPORT_MCI /* For MCI */ HAL_BOOL ah_mci_ready; u_int32_t ah_mci_int_raw; u_int32_t ah_mci_int_rx_msg; u_int32_t ah_mci_rx_status; u_int32_t ah_mci_cont_status; u_int8_t ah_mci_bt_state; u_int32_t ah_mci_gpm_addr; u_int8_t *ah_mci_gpm_buf; u_int32_t ah_mci_gpm_len; u_int32_t ah_mci_gpm_idx; u_int32_t ah_mci_sched_addr; u_int8_t *ah_mci_sched_buf; u_int8_t ah_mci_coex_major_version_wlan; u_int8_t ah_mci_coex_minor_version_wlan; u_int8_t ah_mci_coex_major_version_bt; u_int8_t ah_mci_coex_minor_version_bt; HAL_BOOL ah_mci_coex_bt_version_known; HAL_BOOL ah_mci_coex_wlan_channels_update; u_int32_t ah_mci_coex_wlan_channels[4]; HAL_BOOL ah_mci_coex_2g5g_update; HAL_BOOL ah_mci_coex_is_2g; HAL_BOOL ah_mci_query_bt; HAL_BOOL ah_mci_unhalt_bt_gpm; /* need send UNHALT */ HAL_BOOL ah_mci_halted_bt_gpm; /* HALT sent */ HAL_BOOL ah_mci_need_flush_btinfo; HAL_BOOL ah_mci_concur_tx_en; u_int8_t ah_mci_stomp_low_tx_pri; u_int8_t ah_mci_stomp_all_tx_pri; u_int8_t ah_mci_stomp_none_tx_pri; u_int32_t ah_mci_wlan_cal_seq; u_int32_t ah_mci_wlan_cal_done; #if ATH_SUPPORT_AIC HAL_BOOL ah_aic_enabled; u_int32_t ah_aic_sram[ATH_AIC_MAX_BT_CHANNEL]; #endif #endif /* ATH_SUPPORT_MCI */ u_int8_t ah_cac_quiet_enabled; #if ATH_WOW_OFFLOAD u_int32_t ah_mcast_filter_l32_set; u_int32_t ah_mcast_filter_u32_set; #endif HAL_BOOL ah_reduced_self_gen_mask; HAL_BOOL ah_chip_reset_done; HAL_BOOL ah_abort_txdma_norx; /* store previous passive RX Cal info */ HAL_BOOL ah_skip_rx_iq_cal; HAL_BOOL ah_rx_cal_complete; /* previous rx cal completed or not */ u_int32_t ah_rx_cal_chan; /* chan on which rx cal is done */ u_int32_t ah_rx_cal_chan_flag; u_int32_t ah_rx_cal_corr[AR9300_MAX_CHAINS]; /* Local additions for FreeBSD */ /* * These fields are in the top level HAL in the atheros * codebase; here we place them in the AR9300 HAL and * access them via accessor methods if the driver requires them. */ u_int32_t ah_ob_db1[3]; u_int32_t ah_db2[3]; u_int32_t ah_bb_panic_timeout_ms; u_int32_t ah_bb_panic_last_status; u_int32_t ah_tx_trig_level; u_int16_t ath_hal_spur_chans[AR_EEPROM_MODAL_SPURS][2]; int16_t nf_cw_int_delta; /* diff btwn nominal NF and CW interf threshold */ int ah_phyrestart_disabled; HAL_RSSI_TX_POWER green_tx_status; int green_ap_ps_on; int ah_enable_keysearch_always; int ah_fccaifs; int ah_reset_reason; int ah_dcs_enable; struct ar9300NfLimits nf_2GHz; struct ar9300NfLimits nf_5GHz; struct ar9300NfLimits *nfp; }; #define AH9300(_ah) ((struct ath_hal_9300 *)(_ah)) #define IS_9300_EMU(ah) \ (AH_PRIVATE(ah)->ah_devid == AR9300_DEVID_EMU_PCIE) #define ar9300_eep_data_in_flash(_ah) \ (!(AH_PRIVATE(_ah)->ah_flags & AH_USE_EEPROM)) #ifdef notyet // Need these additional conditions for IS_5GHZ_FAST_CLOCK_EN when we have valid eeprom contents. && \ ((ar9300_eeprom_get(AH9300(_ah), EEP_MINOR_REV) <= AR9300_EEP_MINOR_VER_16) || \ (ar9300_eeprom_get(AH9300(_ah), EEP_FSTCLK_5G)))) #endif /* * WAR for bug 6773. OS_DELAY() does a PIO READ on the PCI bus which allows * other cards' DMA reads to complete in the middle of our reset. */ #define WAR_6773(x) do { \ if ((++(x) % 64) == 0) \ OS_DELAY(1); \ } while (0) #define REG_WRITE_ARRAY(iniarray, column, regWr) do { \ int r; \ for (r = 0; r < ((iniarray)->ia_rows); r++) { \ OS_REG_WRITE(ah, INI_RA((iniarray), (r), 0), INI_RA((iniarray), r, (column)));\ WAR_6773(regWr); \ } \ } while (0) #define UPPER_5G_SUB_BANDSTART 5700 #define MID_5G_SUB_BANDSTART 5400 #define TRAINPOWER_DB_OFFSET 6 #define AH_PAPRD_GET_SCALE_FACTOR(_scale, _eep, _is2G, _channel) do{ if(_is2G) { _scale = (_eep->modal_header_2g.paprd_rate_mask_ht20>>25)&0x7; \ } else { \ if(_channel >= UPPER_5G_SUB_BANDSTART){ _scale = (_eep->modal_header_5g.paprd_rate_mask_ht20>>25)&0x7;} \ else if((UPPER_5G_SUB_BANDSTART < _channel) && (_channel >= MID_5G_SUB_BANDSTART)) \ { _scale = (_eep->modal_header_5g.paprd_rate_mask_ht40>>28)&0x7;} \ else { _scale = (_eep->modal_header_5g.paprd_rate_mask_ht40>>25)&0x7;} } }while(0) #ifdef AH_ASSERT #define ar9300FeatureNotSupported(feature, ah, func) \ ath_hal_printf(ah, # feature \ " not supported but called from %s\n", (func)), \ hal_assert(0) #else #define ar9300FeatureNotSupported(feature, ah, func) \ ath_hal_printf(ah, # feature \ " not supported but called from %s\n", (func)) #endif /* AH_ASSERT */ /* * Green Tx, Based on different RSSI of Received Beacon thresholds, * using different tx power by modified register tx power related values. * The thresholds are decided by system team. */ #define WB225_SW_GREEN_TX_THRES1_DB 56 /* in dB */ #define WB225_SW_GREEN_TX_THRES2_DB 41 /* in dB */ #define WB225_OB_CALIBRATION_VALUE 5 /* For Green Tx OLPC Delta Calibration Offset */ #define WB225_OB_GREEN_TX_SHORT_VALUE 1 /* For Green Tx OB value in short distance*/ #define WB225_OB_GREEN_TX_MIDDLE_VALUE 3 /* For Green Tx OB value in middle distance */ #define WB225_OB_GREEN_TX_LONG_VALUE 5 /* For Green Tx OB value in long distance */ #define WB225_BBPWRTXRATE9_SW_GREEN_TX_SHORT_VALUE 0x06060606 /* For SwGreen Tx BB_powertx_rate9 reg value in short distance */ #define WB225_BBPWRTXRATE9_SW_GREEN_TX_MIDDLE_VALUE 0x0E0E0E0E /* For SwGreen Tx BB_powertx_rate9 reg value in middle distance */ /* Tx power for short distacnce in SwGreenTx.*/ static const u_int8_t wb225_sw_gtx_tp_distance_short[ar9300_rate_size] = { 6, /*ALL_TARGET_LEGACY_6_24*/ 6, /*ALL_TARGET_LEGACY_36*/ 6, /*ALL_TARGET_LEGACY_48*/ 4, /*ALL_TARGET_LEGACY_54*/ 6, /*ALL_TARGET_LEGACY_1L_5L*/ 6, /*ALL_TARGET_LEGACY_5S*/ 6, /*ALL_TARGET_LEGACY_11L*/ 6, /*ALL_TARGET_LEGACY_11S*/ 6, /*ALL_TARGET_HT20_0_8_16*/ 6, /*ALL_TARGET_HT20_1_3_9_11_17_19*/ 4, /*ALL_TARGET_HT20_4*/ 4, /*ALL_TARGET_HT20_5*/ 4, /*ALL_TARGET_HT20_6*/ 2, /*ALL_TARGET_HT20_7*/ 0, /*ALL_TARGET_HT20_12*/ 0, /*ALL_TARGET_HT20_13*/ 0, /*ALL_TARGET_HT20_14*/ 0, /*ALL_TARGET_HT20_15*/ 0, /*ALL_TARGET_HT20_20*/ 0, /*ALL_TARGET_HT20_21*/ 0, /*ALL_TARGET_HT20_22*/ 0, /*ALL_TARGET_HT20_23*/ 6, /*ALL_TARGET_HT40_0_8_16*/ 6, /*ALL_TARGET_HT40_1_3_9_11_17_19*/ 4, /*ALL_TARGET_HT40_4*/ 4, /*ALL_TARGET_HT40_5*/ 4, /*ALL_TARGET_HT40_6*/ 2, /*ALL_TARGET_HT40_7*/ 0, /*ALL_TARGET_HT40_12*/ 0, /*ALL_TARGET_HT40_13*/ 0, /*ALL_TARGET_HT40_14*/ 0, /*ALL_TARGET_HT40_15*/ 0, /*ALL_TARGET_HT40_20*/ 0, /*ALL_TARGET_HT40_21*/ 0, /*ALL_TARGET_HT40_22*/ 0 /*ALL_TARGET_HT40_23*/ }; /* Tx power for middle distacnce in SwGreenTx.*/ static const u_int8_t wb225_sw_gtx_tp_distance_middle[ar9300_rate_size] = { 14, /*ALL_TARGET_LEGACY_6_24*/ 14, /*ALL_TARGET_LEGACY_36*/ 14, /*ALL_TARGET_LEGACY_48*/ 12, /*ALL_TARGET_LEGACY_54*/ 14, /*ALL_TARGET_LEGACY_1L_5L*/ 14, /*ALL_TARGET_LEGACY_5S*/ 14, /*ALL_TARGET_LEGACY_11L*/ 14, /*ALL_TARGET_LEGACY_11S*/ 14, /*ALL_TARGET_HT20_0_8_16*/ 14, /*ALL_TARGET_HT20_1_3_9_11_17_19*/ 14, /*ALL_TARGET_HT20_4*/ 14, /*ALL_TARGET_HT20_5*/ 12, /*ALL_TARGET_HT20_6*/ 10, /*ALL_TARGET_HT20_7*/ 0, /*ALL_TARGET_HT20_12*/ 0, /*ALL_TARGET_HT20_13*/ 0, /*ALL_TARGET_HT20_14*/ 0, /*ALL_TARGET_HT20_15*/ 0, /*ALL_TARGET_HT20_20*/ 0, /*ALL_TARGET_HT20_21*/ 0, /*ALL_TARGET_HT20_22*/ 0, /*ALL_TARGET_HT20_23*/ 14, /*ALL_TARGET_HT40_0_8_16*/ 14, /*ALL_TARGET_HT40_1_3_9_11_17_19*/ 14, /*ALL_TARGET_HT40_4*/ 14, /*ALL_TARGET_HT40_5*/ 12, /*ALL_TARGET_HT40_6*/ 10, /*ALL_TARGET_HT40_7*/ 0, /*ALL_TARGET_HT40_12*/ 0, /*ALL_TARGET_HT40_13*/ 0, /*ALL_TARGET_HT40_14*/ 0, /*ALL_TARGET_HT40_15*/ 0, /*ALL_TARGET_HT40_20*/ 0, /*ALL_TARGET_HT40_21*/ 0, /*ALL_TARGET_HT40_22*/ 0 /*ALL_TARGET_HT40_23*/ }; /* OLPC DeltaCalibration Offset unit in half dB.*/ static const u_int8_t wb225_gtx_olpc_cal_offset[6] = { 0, /* OB0*/ 16, /* OB1*/ 9, /* OB2*/ 5, /* OB3*/ 2, /* OB4*/ 0, /* OB5*/ }; /* * Definitions for HwGreenTx */ #define AR9485_HW_GREEN_TX_THRES1_DB 56 /* in dB */ #define AR9485_HW_GREEN_TX_THRES2_DB 41 /* in dB */ #define AR9485_BBPWRTXRATE9_HW_GREEN_TX_SHORT_VALUE 0x0C0C0A0A /* For HwGreen Tx BB_powertx_rate9 reg value in short distance */ #define AR9485_BBPWRTXRATE9_HW_GREEN_TX_MIDDLE_VALUE 0x10100E0E /* For HwGreenTx BB_powertx_rate9 reg value in middle distance */ /* Tx power for short distacnce in HwGreenTx.*/ static const u_int8_t ar9485_hw_gtx_tp_distance_short[ar9300_rate_size] = { 14, /*ALL_TARGET_LEGACY_6_24*/ 14, /*ALL_TARGET_LEGACY_36*/ 8, /*ALL_TARGET_LEGACY_48*/ 2, /*ALL_TARGET_LEGACY_54*/ 14, /*ALL_TARGET_LEGACY_1L_5L*/ 14, /*ALL_TARGET_LEGACY_5S*/ 14, /*ALL_TARGET_LEGACY_11L*/ 14, /*ALL_TARGET_LEGACY_11S*/ 12, /*ALL_TARGET_HT20_0_8_16*/ 12, /*ALL_TARGET_HT20_1_3_9_11_17_19*/ 12, /*ALL_TARGET_HT20_4*/ 12, /*ALL_TARGET_HT20_5*/ 8, /*ALL_TARGET_HT20_6*/ 2, /*ALL_TARGET_HT20_7*/ 0, /*ALL_TARGET_HT20_12*/ 0, /*ALL_TARGET_HT20_13*/ 0, /*ALL_TARGET_HT20_14*/ 0, /*ALL_TARGET_HT20_15*/ 0, /*ALL_TARGET_HT20_20*/ 0, /*ALL_TARGET_HT20_21*/ 0, /*ALL_TARGET_HT20_22*/ 0, /*ALL_TARGET_HT20_23*/ 10, /*ALL_TARGET_HT40_0_8_16*/ 10, /*ALL_TARGET_HT40_1_3_9_11_17_19*/ 10, /*ALL_TARGET_HT40_4*/ 10, /*ALL_TARGET_HT40_5*/ 6, /*ALL_TARGET_HT40_6*/ 2, /*ALL_TARGET_HT40_7*/ 0, /*ALL_TARGET_HT40_12*/ 0, /*ALL_TARGET_HT40_13*/ 0, /*ALL_TARGET_HT40_14*/ 0, /*ALL_TARGET_HT40_15*/ 0, /*ALL_TARGET_HT40_20*/ 0, /*ALL_TARGET_HT40_21*/ 0, /*ALL_TARGET_HT40_22*/ 0 /*ALL_TARGET_HT40_23*/ }; /* Tx power for middle distacnce in HwGreenTx.*/ static const u_int8_t ar9485_hw_gtx_tp_distance_middle[ar9300_rate_size] = { 18, /*ALL_TARGET_LEGACY_6_24*/ 18, /*ALL_TARGET_LEGACY_36*/ 14, /*ALL_TARGET_LEGACY_48*/ 12, /*ALL_TARGET_LEGACY_54*/ 18, /*ALL_TARGET_LEGACY_1L_5L*/ 18, /*ALL_TARGET_LEGACY_5S*/ 18, /*ALL_TARGET_LEGACY_11L*/ 18, /*ALL_TARGET_LEGACY_11S*/ 16, /*ALL_TARGET_HT20_0_8_16*/ 16, /*ALL_TARGET_HT20_1_3_9_11_17_19*/ 16, /*ALL_TARGET_HT20_4*/ 16, /*ALL_TARGET_HT20_5*/ 14, /*ALL_TARGET_HT20_6*/ 12, /*ALL_TARGET_HT20_7*/ 0, /*ALL_TARGET_HT20_12*/ 0, /*ALL_TARGET_HT20_13*/ 0, /*ALL_TARGET_HT20_14*/ 0, /*ALL_TARGET_HT20_15*/ 0, /*ALL_TARGET_HT20_20*/ 0, /*ALL_TARGET_HT20_21*/ 0, /*ALL_TARGET_HT20_22*/ 0, /*ALL_TARGET_HT20_23*/ 14, /*ALL_TARGET_HT40_0_8_16*/ 14, /*ALL_TARGET_HT40_1_3_9_11_17_19*/ 14, /*ALL_TARGET_HT40_4*/ 14, /*ALL_TARGET_HT40_5*/ 14, /*ALL_TARGET_HT40_6*/ 12, /*ALL_TARGET_HT40_7*/ 0, /*ALL_TARGET_HT40_12*/ 0, /*ALL_TARGET_HT40_13*/ 0, /*ALL_TARGET_HT40_14*/ 0, /*ALL_TARGET_HT40_15*/ 0, /*ALL_TARGET_HT40_20*/ 0, /*ALL_TARGET_HT40_21*/ 0, /*ALL_TARGET_HT40_22*/ 0 /*ALL_TARGET_HT40_23*/ }; /* MIMO Modes used in TPC calculations */ typedef enum { AR9300_DEF_MODE = 0, /* Could be CDD or Direct */ AR9300_TXBF_MODE, AR9300_STBC_MODE } AR9300_TXMODES; typedef enum { POSEIDON_STORED_REG_OBDB = 0, /* default OB/DB setting from ini */ POSEIDON_STORED_REG_TPC = 1, /* default txpower value in TPC reg */ POSEIDON_STORED_REG_BB_PWRTX_RATE9 = 2, /* default txpower value in * BB_powertx_rate9 reg */ POSEIDON_STORED_REG_SZ /* Can not add anymore */ } POSEIDON_STORED_REGS; typedef enum { POSEIDON_STORED_REG_G2_OLPC_OFFSET = 0,/* default OB/DB setting from ini */ POSEIDON_STORED_REG_G2_SZ /* should not exceed 3 */ } POSEIDON_STORED_REGS_G2; #if AH_NEED_TX_DATA_SWAP #if AH_NEED_RX_DATA_SWAP #define ar9300_init_cfg_reg(ah) OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB,0) #else #define ar9300_init_cfg_reg(ah) OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB,0) #endif #elif AH_NEED_RX_DATA_SWAP #define ar9300_init_cfg_reg(ah) OS_REG_RMW(ah, AR_CFG, AR_CFG_SWRB,0) #else #define ar9300_init_cfg_reg(ah) OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD,0) #endif extern HAL_BOOL ar9300_rf_attach(struct ath_hal *, HAL_STATUS *); struct ath_hal; extern struct ath_hal_9300 * ar9300_new_state(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status); extern struct ath_hal * ar9300_attach(u_int16_t devid, HAL_SOFTC sc, HAL_BUS_TAG st, HAL_BUS_HANDLE sh, uint16_t *eepromdata, HAL_OPS_CONFIG *ah_config, HAL_STATUS *status); extern void ar9300_detach(struct ath_hal *ah); extern void ar9300_read_revisions(struct ath_hal *ah); extern HAL_BOOL ar9300_chip_test(struct ath_hal *ah); extern HAL_BOOL ar9300_get_channel_edges(struct ath_hal *ah, u_int16_t flags, u_int16_t *low, u_int16_t *high); extern HAL_BOOL ar9300_fill_capability_info(struct ath_hal *ah); extern void ar9300_beacon_init(struct ath_hal *ah, u_int32_t next_beacon, u_int32_t beacon_period, u_int32_t beacon_period_fraction, HAL_OPMODE opmode); extern void ar9300_set_sta_beacon_timers(struct ath_hal *ah, const HAL_BEACON_STATE *); extern HAL_BOOL ar9300_is_interrupt_pending(struct ath_hal *ah); extern HAL_BOOL ar9300_get_pending_interrupts(struct ath_hal *ah, HAL_INT *, HAL_INT_TYPE, u_int8_t, HAL_BOOL); extern HAL_INT ar9300_get_interrupts(struct ath_hal *ah); extern HAL_INT ar9300_set_interrupts(struct ath_hal *ah, HAL_INT ints, HAL_BOOL); extern void ar9300_set_intr_mitigation_timer(struct ath_hal* ah, HAL_INT_MITIGATION reg, u_int32_t value); extern u_int32_t ar9300_get_intr_mitigation_timer(struct ath_hal* ah, HAL_INT_MITIGATION reg); extern u_int32_t ar9300_get_key_cache_size(struct ath_hal *); extern HAL_BOOL ar9300_is_key_cache_entry_valid(struct ath_hal *, u_int16_t entry); extern HAL_BOOL ar9300_reset_key_cache_entry(struct ath_hal *ah, u_int16_t entry); extern HAL_CHANNEL_INTERNAL * ar9300_check_chan(struct ath_hal *ah, const struct ieee80211_channel *chan); extern HAL_BOOL ar9300_set_key_cache_entry_mac(struct ath_hal *, u_int16_t entry, const u_int8_t *mac); extern HAL_BOOL ar9300_set_key_cache_entry(struct ath_hal *ah, u_int16_t entry, const HAL_KEYVAL *k, const u_int8_t *mac, int xor_key); extern HAL_BOOL ar9300_print_keycache(struct ath_hal *ah); #if ATH_SUPPORT_KEYPLUMB_WAR extern HAL_BOOL ar9300_check_key_cache_entry(struct ath_hal *ah, u_int16_t entry, const HAL_KEYVAL *k, int xorKey); #endif extern void ar9300_get_mac_address(struct ath_hal *ah, u_int8_t *mac); extern HAL_BOOL ar9300_set_mac_address(struct ath_hal *ah, const u_int8_t *); extern void ar9300_get_bss_id_mask(struct ath_hal *ah, u_int8_t *mac); extern HAL_BOOL ar9300_set_bss_id_mask(struct ath_hal *, const u_int8_t *); extern HAL_STATUS ar9300_select_ant_config(struct ath_hal *ah, u_int32_t cfg); #if 0 extern u_int32_t ar9300_ant_ctrl_common_get(struct ath_hal *ah, HAL_BOOL is_2ghz); #endif extern HAL_BOOL ar9300_ant_swcom_sel(struct ath_hal *ah, u_int8_t ops, u_int32_t *common_tbl1, u_int32_t *common_tbl2); extern HAL_BOOL ar9300_set_regulatory_domain(struct ath_hal *ah, u_int16_t reg_domain, HAL_STATUS *stats); extern u_int ar9300_get_wireless_modes(struct ath_hal *ah); extern void ar9300_enable_rf_kill(struct ath_hal *); extern HAL_BOOL ar9300_gpio_cfg_output(struct ath_hal *, u_int32_t gpio, HAL_GPIO_MUX_TYPE signalType); extern HAL_BOOL ar9300_gpio_cfg_output_led_off(struct ath_hal *, u_int32_t gpio, HAL_GPIO_MUX_TYPE signalType); extern HAL_BOOL ar9300_gpio_cfg_input(struct ath_hal *, u_int32_t gpio); extern HAL_BOOL ar9300_gpio_set(struct ath_hal *, u_int32_t gpio, u_int32_t val); extern u_int32_t ar9300_gpio_get(struct ath_hal *ah, u_int32_t gpio); extern u_int32_t ar9300_gpio_get_intr(struct ath_hal *ah); extern void ar9300_gpio_set_intr(struct ath_hal *ah, u_int, u_int32_t ilevel); extern u_int32_t ar9300_gpio_get_polarity(struct ath_hal *ah); extern void ar9300_gpio_set_polarity(struct ath_hal *ah, u_int32_t, u_int32_t); extern u_int32_t ar9300_gpio_get_mask(struct ath_hal *ah); extern int ar9300_gpio_set_mask(struct ath_hal *ah, u_int32_t mask, u_int32_t pol_map); extern void ar9300_set_led_state(struct ath_hal *ah, HAL_LED_STATE state); extern void ar9300_set_power_led_state(struct ath_hal *ah, u_int8_t enable); extern void ar9300_set_network_led_state(struct ath_hal *ah, u_int8_t enable); extern void ar9300_write_associd(struct ath_hal *ah, const u_int8_t *bssid, u_int16_t assoc_id); extern u_int32_t ar9300_ppm_get_rssi_dump(struct ath_hal *); extern u_int32_t ar9300_ppm_arm_trigger(struct ath_hal *); extern int ar9300_ppm_get_trigger(struct ath_hal *); extern u_int32_t ar9300_ppm_force(struct ath_hal *); extern void ar9300_ppm_un_force(struct ath_hal *); extern u_int32_t ar9300_ppm_get_force_state(struct ath_hal *); extern void ar9300_set_dcs_mode(struct ath_hal *ah, u_int32_t); extern u_int32_t ar9300_get_dcs_mode(struct ath_hal *ah); extern u_int32_t ar9300_get_tsf32(struct ath_hal *ah); extern u_int64_t ar9300_get_tsf64(struct ath_hal *ah); extern u_int32_t ar9300_get_tsf2_32(struct ath_hal *ah); extern void ar9300_set_tsf64(struct ath_hal *ah, u_int64_t tsf); extern void ar9300_reset_tsf(struct ath_hal *ah); extern void ar9300_set_basic_rate(struct ath_hal *ah, HAL_RATE_SET *pSet); extern u_int32_t ar9300_get_random_seed(struct ath_hal *ah); extern HAL_BOOL ar9300_detect_card_present(struct ath_hal *ah); extern void ar9300_update_mib_mac_stats(struct ath_hal *ah); extern void ar9300_get_mib_mac_stats(struct ath_hal *ah, HAL_MIB_STATS* stats); extern HAL_BOOL ar9300_is_japan_channel_spread_supported(struct ath_hal *ah); extern u_int32_t ar9300_get_cur_rssi(struct ath_hal *ah); extern u_int32_t ar9300_get_rssi_chain0(struct ath_hal *ah); extern u_int ar9300_get_def_antenna(struct ath_hal *ah); extern void ar9300_set_def_antenna(struct ath_hal *ah, u_int antenna); extern HAL_BOOL ar9300_set_antenna_switch(struct ath_hal *ah, HAL_ANT_SETTING settings, const struct ieee80211_channel *chan, u_int8_t *, u_int8_t *, u_int8_t *); extern HAL_BOOL ar9300_is_sleep_after_beacon_broken(struct ath_hal *ah); extern HAL_BOOL ar9300_set_slot_time(struct ath_hal *, u_int); extern HAL_BOOL ar9300_set_ack_timeout(struct ath_hal *, u_int); extern u_int ar9300_get_ack_timeout(struct ath_hal *); extern HAL_STATUS ar9300_set_quiet(struct ath_hal *ah, u_int32_t period, u_int32_t duration, u_int32_t next_start, HAL_QUIET_FLAG flag); extern void ar9300_set_pcu_config(struct ath_hal *); extern HAL_STATUS ar9300_get_capability(struct ath_hal *, HAL_CAPABILITY_TYPE, u_int32_t, u_int32_t *); extern HAL_BOOL ar9300_set_capability(struct ath_hal *, HAL_CAPABILITY_TYPE, u_int32_t, u_int32_t, HAL_STATUS *); extern HAL_BOOL ar9300_get_diag_state(struct ath_hal *ah, int request, const void *args, u_int32_t argsize, void **result, u_int32_t *resultsize); extern void ar9300_get_desc_info(struct ath_hal *ah, HAL_DESC_INFO *desc_info); extern uint32_t ar9300_get_11n_ext_busy(struct ath_hal *ah); extern void ar9300_set_11n_mac2040(struct ath_hal *ah, HAL_HT_MACMODE mode); extern HAL_HT_RXCLEAR ar9300_get_11n_rx_clear(struct ath_hal *ah); extern void ar9300_set_11n_rx_clear(struct ath_hal *ah, HAL_HT_RXCLEAR rxclear); extern HAL_BOOL ar9300_set_power_mode(struct ath_hal *ah, HAL_POWER_MODE mode, int set_chip); extern HAL_POWER_MODE ar9300_get_power_mode(struct ath_hal *ah); extern HAL_BOOL ar9300_set_power_mode_awake(struct ath_hal *ah, int set_chip); extern void ar9300_set_sm_power_mode(struct ath_hal *ah, HAL_SMPS_MODE mode); extern void ar9300_config_pci_power_save(struct ath_hal *ah, int restore, int power_off); extern void ar9300_force_tsf_sync(struct ath_hal *ah, const u_int8_t *bssid, u_int16_t assoc_id); #if ATH_WOW extern void ar9300_wow_apply_pattern(struct ath_hal *ah, u_int8_t *p_ath_pattern, u_int8_t *p_ath_mask, int32_t pattern_count, u_int32_t ath_pattern_len); //extern u_int32_t ar9300_wow_wake_up(struct ath_hal *ah,u_int8_t *chipPatternBytes); extern u_int32_t ar9300_wow_wake_up(struct ath_hal *ah, HAL_BOOL offloadEnable); extern bool ar9300_wow_enable(struct ath_hal *ah, u_int32_t pattern_enable, u_int32_t timeout_in_seconds, int clearbssid, HAL_BOOL offloadEnable); #if ATH_WOW_OFFLOAD /* ARP offload */ #define WOW_OFFLOAD_ARP_INFO_MAX 2 struct hal_wow_offload_arp_info { u_int32_t valid; u_int32_t id; u_int32_t Flags; union { u_int8_t u8[4]; u_int32_t u32; } RemoteIPv4Address; union { u_int8_t u8[4]; u_int32_t u32; } HostIPv4Address; union { u_int8_t u8[6]; u_int32_t u32[2]; } MacAddress; }; /* NS offload */ #define WOW_OFFLOAD_NS_INFO_MAX 2 struct hal_wow_offload_ns_info { u_int32_t valid; u_int32_t id; u_int32_t Flags; union { u_int8_t u8[16]; u_int32_t u32[4]; } RemoteIPv6Address; union { u_int8_t u8[16]; u_int32_t u32[4]; } SolicitedNodeIPv6Address; union { u_int8_t u8[6]; u_int32_t u32[2]; } MacAddress; union { u_int8_t u8[16]; u_int32_t u32[4]; } TargetIPv6Addresses[2]; }; extern void ar9300_wowoffload_prep(struct ath_hal *ah); extern void ar9300_wowoffload_post(struct ath_hal *ah); extern u_int32_t ar9300_wowoffload_download_rekey_data(struct ath_hal *ah, u_int32_t *data, u_int32_t size); extern void ar9300_wowoffload_retrieve_data(struct ath_hal *ah, void *buf, u_int32_t param); extern void ar9300_wowoffload_download_acer_magic(struct ath_hal *ah, HAL_BOOL valid, u_int8_t* datap, u_int32_t bytes); extern void ar9300_wowoffload_download_acer_swka(struct ath_hal *ah, u_int32_t id, HAL_BOOL valid, u_int32_t period, u_int32_t size, u_int32_t* datap); extern void ar9300_wowoffload_download_arp_info(struct ath_hal *ah, u_int32_t id, u_int32_t *data); extern void ar9300_wowoffload_download_ns_info(struct ath_hal *ah, u_int32_t id, u_int32_t *data); #endif /* ATH_WOW_OFFLOAD */ #endif extern HAL_BOOL ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask, HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change, HAL_STATUS *status, int is_scan); extern HAL_BOOL ar9300_lean_channel_change(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask); extern HAL_BOOL ar9300_set_reset_reg(struct ath_hal *ah, u_int32_t type); extern void ar9300_init_pll(struct ath_hal *ah, struct ieee80211_channel *chan); extern void ar9300_green_ap_ps_on_off( struct ath_hal *ah, u_int16_t rxMask); extern u_int16_t ar9300_is_single_ant_power_save_possible(struct ath_hal *ah); extern void ar9300_set_operating_mode(struct ath_hal *ah, int opmode); extern HAL_BOOL ar9300_phy_disable(struct ath_hal *ah); extern HAL_BOOL ar9300_disable(struct ath_hal *ah); extern HAL_BOOL ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *); extern HAL_BOOL ar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask, HAL_BOOL longcal, HAL_BOOL *isIQdone, int is_scan, u_int32_t *sched_cals); extern void ar9300_reset_cal_valid(struct ath_hal *ah, const struct ieee80211_channel *chan, HAL_BOOL *isIQdone, u_int32_t cal_type); extern void ar9300_iq_cal_collect(struct ath_hal *ah, u_int8_t num_chains); extern void ar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains); extern void ar9300_temp_comp_cal_collect(struct ath_hal *ah); extern void ar9300_temp_comp_calibration(struct ath_hal *ah, u_int8_t num_chains); extern int16_t ar9300_get_min_cca_pwr(struct ath_hal *ah); extern void ar9300_upload_noise_floor(struct ath_hal *ah, int is2G, int16_t nfarray[]); extern HAL_BOOL ar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit, u_int16_t extra_txpow, u_int16_t tpc_in_db); extern void ar9300_chain_noise_floor(struct ath_hal *ah, int16_t *nf_buf, struct ieee80211_channel *chan, int is_scan); extern int16_t ar9300_get_nf_from_reg(struct ath_hal *ah, struct ieee80211_channel *chan, int wait_time); extern int ar9300_get_rx_nf_offset(struct ath_hal *ah, struct ieee80211_channel *chan, int8_t *nf_pwr, int8_t *nf_cal); extern HAL_BOOL ar9300_load_nf(struct ath_hal *ah, int16_t nf[]); extern HAL_RFGAIN ar9300_get_rfgain(struct ath_hal *ah); extern const HAL_RATE_TABLE *ar9300_get_rate_table(struct ath_hal *, u_int mode); extern int16_t ar9300_get_rate_txpower(struct ath_hal *ah, u_int mode, u_int8_t rate_index, u_int8_t chainmask, u_int8_t mimo_mode); extern void ar9300_init_rate_txpower(struct ath_hal *ah, u_int mode, const struct ieee80211_channel *chan, u_int8_t powerPerRate[], u_int8_t chainmask); extern void ar9300_adjust_reg_txpower_cdd(struct ath_hal *ah, u_int8_t powerPerRate[]); extern HAL_STATUS ath_hal_get_rate_power_limit_from_eeprom(struct ath_hal *ah, u_int16_t freq, int8_t *max_rate_power, int8_t *min_rate_power); extern void ar9300_reset_tx_status_ring(struct ath_hal *ah); extern void ar9300_enable_mib_counters(struct ath_hal *); extern void ar9300_disable_mib_counters(struct ath_hal *); extern void ar9300_ani_attach(struct ath_hal *); extern void ar9300_ani_detach(struct ath_hal *); extern struct ar9300_ani_state *ar9300_ani_get_current_state(struct ath_hal *); extern struct ar9300_stats *ar9300_ani_get_current_stats(struct ath_hal *); extern HAL_BOOL ar9300_ani_control(struct ath_hal *, HAL_ANI_CMD cmd, int param); struct ath_rx_status; extern void ar9300_process_mib_intr(struct ath_hal *, const HAL_NODE_STATS *); extern void ar9300_ani_ar_poll(struct ath_hal *, const HAL_NODE_STATS *, const struct ieee80211_channel *, HAL_ANISTATS *); extern void ar9300_ani_reset(struct ath_hal *, HAL_BOOL is_scanning); extern void ar9300_ani_init_defaults(struct ath_hal *ah, HAL_HT_MACMODE macmode); extern void ar9300_enable_tpc(struct ath_hal *); extern HAL_BOOL ar9300_rf_gain_cap_apply(struct ath_hal *ah, int is2GHz); extern void ar9300_rx_gain_table_apply(struct ath_hal *ah); extern void ar9300_tx_gain_table_apply(struct ath_hal *ah); extern void ar9300_mat_enable(struct ath_hal *ah, int enable); extern void ar9300_dump_keycache(struct ath_hal *ah, int n, u_int32_t *entry); extern HAL_BOOL ar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal * ah, HAL_BOOL enable, const struct ieee80211_channel * chan); /* BB Panic Watchdog declarations */ #define HAL_BB_PANIC_WD_TMO 25 /* in ms, 0 to disable */ #define HAL_BB_PANIC_WD_TMO_HORNET 85 extern void ar9300_config_bb_panic_watchdog(struct ath_hal *); extern void ar9300_handle_bb_panic(struct ath_hal *); extern int ar9300_get_bb_panic_info(struct ath_hal *ah, struct hal_bb_panic_info *bb_panic); extern HAL_BOOL ar9300_handle_radar_bb_panic(struct ath_hal *ah); extern void ar9300_set_hal_reset_reason(struct ath_hal *ah, u_int8_t resetreason); /* DFS declarations */ extern void ar9300_check_dfs(struct ath_hal *ah, struct ieee80211_channel *chan); extern void ar9300_dfs_found(struct ath_hal *ah, struct ieee80211_channel *chan, u_int64_t nolTime); extern void ar9300_enable_dfs(struct ath_hal *ah, HAL_PHYERR_PARAM *pe); extern void ar9300_get_dfs_thresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe); extern HAL_BOOL ar9300_radar_wait(struct ath_hal *ah, struct ieee80211_channel *chan); extern struct dfs_pulse * ar9300_get_dfs_radars(struct ath_hal *ah, u_int32_t dfsdomain, int *numradars, struct dfs_bin5pulse **bin5pulses, int *numb5radars, HAL_PHYERR_PARAM *pe); extern void ar9300_adjust_difs(struct ath_hal *ah, u_int32_t val); extern u_int32_t ar9300_dfs_config_fft(struct ath_hal *ah, HAL_BOOL is_enable); extern void ar9300_cac_tx_quiet(struct ath_hal *ah, HAL_BOOL enable); extern void ar9300_dfs_cac_war(struct ath_hal *ah, u_int32_t start); extern struct ieee80211_channel * ar9300_get_extension_channel(struct ath_hal *ah); extern HAL_BOOL ar9300_is_fast_clock_enabled(struct ath_hal *ah); extern void ar9300_mark_phy_inactive(struct ath_hal *ah); /* Spectral scan declarations */ extern void ar9300_configure_spectral_scan(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss); extern void ar9300_set_cca_threshold(struct ath_hal *ah, u_int8_t thresh62); extern void ar9300_get_spectral_params(struct ath_hal *ah, HAL_SPECTRAL_PARAM *ss); extern HAL_BOOL ar9300_is_spectral_active(struct ath_hal *ah); extern HAL_BOOL ar9300_is_spectral_enabled(struct ath_hal *ah); extern void ar9300_start_spectral_scan(struct ath_hal *ah); extern void ar9300_stop_spectral_scan(struct ath_hal *ah); extern u_int32_t ar9300_get_spectral_config(struct ath_hal *ah); extern void ar9300_restore_spectral_config(struct ath_hal *ah, u_int32_t restoreval); int16_t ar9300_get_ctl_chan_nf(struct ath_hal *ah); int16_t ar9300_get_ext_chan_nf(struct ath_hal *ah); /* End spectral scan declarations */ /* Raw ADC capture functions */ extern void ar9300_enable_test_addac_mode(struct ath_hal *ah); extern void ar9300_disable_test_addac_mode(struct ath_hal *ah); extern void ar9300_begin_adc_capture(struct ath_hal *ah, int auto_agc_gain); extern HAL_STATUS ar9300_retrieve_capture_data(struct ath_hal *ah, u_int16_t chain_mask, int disable_dc_filter, void *sample_buf, u_int32_t *max_samples); extern HAL_STATUS ar9300_calc_adc_ref_powers(struct ath_hal *ah, int freq_mhz, int16_t *sample_min, int16_t *sample_max, int32_t *chain_ref_pwr, int num_chain_ref_pwr); extern HAL_STATUS ar9300_get_min_agc_gain(struct ath_hal *ah, int freq_mhz, int32_t *chain_gain, int num_chain_gain); extern HAL_BOOL ar9300_reset_11n(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_BOOL b_channel_change, HAL_STATUS *status); extern void ar9300_set_coverage_class(struct ath_hal *ah, u_int8_t coverageclass, int now); extern void ar9300_get_channel_centers(struct ath_hal *ah, const struct ieee80211_channel *chan, CHAN_CENTERS *centers); extern u_int16_t ar9300_get_ctl_center(struct ath_hal *ah, const struct ieee80211_channel *chan); extern u_int16_t ar9300_get_ext_center(struct ath_hal *ah, const struct ieee80211_channel *chan); extern u_int32_t ar9300_get_mib_cycle_counts_pct(struct ath_hal *, u_int32_t*, u_int32_t*, u_int32_t*); extern void ar9300_dma_reg_dump(struct ath_hal *); extern HAL_BOOL ar9300_set_11n_rx_rifs(struct ath_hal *ah, HAL_BOOL enable); extern HAL_BOOL ar9300_set_rifs_delay(struct ath_hal *ah, HAL_BOOL enable); extern HAL_BOOL ar9300_set_smart_antenna(struct ath_hal *ah, HAL_BOOL enable); extern HAL_BOOL ar9300_detect_bb_hang(struct ath_hal *ah); extern HAL_BOOL ar9300_detect_mac_hang(struct ath_hal *ah); #ifdef ATH_BT_COEX extern void ar9300_set_bt_coex_info(struct ath_hal *ah, HAL_BT_COEX_INFO *btinfo); extern void ar9300_bt_coex_config(struct ath_hal *ah, HAL_BT_COEX_CONFIG *btconf); extern void ar9300_bt_coex_set_qcu_thresh(struct ath_hal *ah, int qnum); extern void ar9300_bt_coex_set_weights(struct ath_hal *ah, u_int32_t stomp_type); extern void ar9300_bt_coex_setup_bmiss_thresh(struct ath_hal *ah, u_int32_t thresh); extern void ar9300_bt_coex_set_parameter(struct ath_hal *ah, u_int32_t type, u_int32_t value); extern void ar9300_bt_coex_disable(struct ath_hal *ah); extern int ar9300_bt_coex_enable(struct ath_hal *ah); extern void ar9300_init_bt_coex(struct ath_hal *ah); extern u_int32_t ar9300_get_bt_active_gpio(struct ath_hal *ah, u_int32_t reg); extern u_int32_t ar9300_get_wlan_active_gpio(struct ath_hal *ah, u_int32_t reg,u_int32_t bOn); #endif extern int ar9300_alloc_generic_timer(struct ath_hal *ah, HAL_GEN_TIMER_DOMAIN tsf); extern void ar9300_free_generic_timer(struct ath_hal *ah, int index); extern void ar9300_start_generic_timer(struct ath_hal *ah, int index, u_int32_t timer_next, u_int32_t timer_period); extern void ar9300_stop_generic_timer(struct ath_hal *ah, int index); extern void ar9300_get_gen_timer_interrupts(struct ath_hal *ah, u_int32_t *trigger, u_int32_t *thresh); extern void ar9300_start_tsf2(struct ath_hal *ah); extern void ar9300_chk_rssi_update_tx_pwr(struct ath_hal *ah, int rssi); extern HAL_BOOL ar9300_is_skip_paprd_by_greentx(struct ath_hal *ah); extern void ar9300_control_signals_for_green_tx_mode(struct ath_hal *ah); extern void ar9300_hwgreentx_set_pal_spare(struct ath_hal *ah, int value); extern HAL_BOOL ar9300_is_ani_noise_spur(struct ath_hal *ah); extern void ar9300_reset_hw_beacon_proc_crc(struct ath_hal *ah); extern int32_t ar9300_get_hw_beacon_rssi(struct ath_hal *ah); extern void ar9300_set_hw_beacon_rssi_threshold(struct ath_hal *ah, u_int32_t rssi_threshold); extern void ar9300_reset_hw_beacon_rssi(struct ath_hal *ah); extern void ar9300_set_hw_beacon_proc(struct ath_hal *ah, HAL_BOOL on); extern void ar9300_get_vow_stats(struct ath_hal *ah, HAL_VOWSTATS *p_stats, u_int8_t); extern int ar9300_get_spur_info(struct ath_hal * ah, int *enable, int len, u_int16_t *freq); extern int ar9300_set_spur_info(struct ath_hal * ah, int enable, int len, u_int16_t *freq); extern void ar9300_wow_set_gpio_reset_low(struct ath_hal * ah); extern HAL_BOOL ar9300_get_mib_cycle_counts(struct ath_hal *, HAL_SURVEY_SAMPLE *); extern void ar9300_clear_mib_counters(struct ath_hal *ah); /* EEPROM interface functions */ /* Common Interface functions */ extern HAL_STATUS ar9300_eeprom_attach(struct ath_hal *); extern u_int32_t ar9300_eeprom_get(struct ath_hal_9300 *ahp, EEPROM_PARAM param); extern u_int32_t ar9300_ini_fixup(struct ath_hal *ah, ar9300_eeprom_t *p_eep_data, u_int32_t reg, u_int32_t val); extern HAL_STATUS ar9300_eeprom_set_transmit_power(struct ath_hal *ah, ar9300_eeprom_t *p_eep_data, const struct ieee80211_channel *chan, u_int16_t cfg_ctl, u_int16_t twice_antenna_reduction, u_int16_t twice_max_regulatory_power, u_int16_t power_limit); extern void ar9300_eeprom_set_addac(struct ath_hal *, struct ieee80211_channel *); extern HAL_BOOL ar9300_eeprom_set_param(struct ath_hal *ah, EEPROM_PARAM param, u_int32_t value); extern HAL_BOOL ar9300_eeprom_set_board_values(struct ath_hal *, const struct ieee80211_channel *); extern HAL_BOOL ar9300_eeprom_read_word(struct ath_hal *, u_int off, u_int16_t *data); extern HAL_BOOL ar9300_eeprom_read(struct ath_hal *ah, long address, u_int8_t *buffer, int many); extern HAL_BOOL ar9300_otp_read(struct ath_hal *ah, u_int off, u_int32_t *data, HAL_BOOL is_wifi); extern HAL_BOOL ar9300_flash_read(struct ath_hal *, u_int off, u_int16_t *data); extern HAL_BOOL ar9300_flash_write(struct ath_hal *, u_int off, u_int16_t data); extern u_int ar9300_eeprom_dump_support(struct ath_hal *ah, void **pp_e); extern u_int8_t ar9300_eeprom_get_num_ant_config(struct ath_hal_9300 *ahp, HAL_FREQ_BAND freq_band); extern HAL_STATUS ar9300_eeprom_get_ant_cfg(struct ath_hal_9300 *ahp, const struct ieee80211_channel *chan, u_int8_t index, u_int16_t *config); extern u_int8_t* ar9300_eeprom_get_cust_data(struct ath_hal_9300 *ahp); extern u_int8_t *ar9300_eeprom_get_spur_chans_ptr(struct ath_hal *ah, HAL_BOOL is_2ghz); extern HAL_BOOL ar9300_interference_is_present(struct ath_hal *ah); extern HAL_BOOL ar9300_tuning_caps_apply(struct ath_hal *ah); extern void ar9300_disp_tpc_tables(struct ath_hal *ah); extern u_int8_t *ar9300_get_tpc_tables(struct ath_hal *ah); extern u_int8_t ar9300_eeprom_set_tx_gain_cap(struct ath_hal *ah, int *tx_gain_max); extern u_int8_t ar9300_eeprom_tx_gain_table_index_max_apply(struct ath_hal *ah, u_int16_t channel); /* Common EEPROM Help function */ extern void ar9300_set_immunity(struct ath_hal *ah, HAL_BOOL enable); extern void ar9300_get_hw_hangs(struct ath_hal *ah, hal_hw_hangs_t *hangs); extern u_int ar9300_mac_to_clks(struct ath_hal *ah, u_int clks); /* tx_bf interface */ #define ar9300_init_txbf(ah) #define ar9300_set_11n_txbf_sounding(ah, ds, series, cec, opt) #define ar9300_set_11n_txbf_cal(ah, ds, cal_pos, code_rate, cec, opt) #define ar9300_txbf_save_cv_from_compress( \ ah, key_idx, mimo_control, compress_rpt) \ false #define ar9300_txbf_save_cv_from_non_compress( \ ah, key_idx, mimo_control, non_compress_rpt) \ false #define ar9300_txbf_rc_update( \ ah, rx_status, local_h, csi_frame, ness_a, ness_b, bw) \ false #define ar9300_fill_csi_frame( \ ah, rx_status, bandwidth, local_h, csi_frame_body) \ 0 #define ar9300_fill_txbf_capabilities(ah) #define ar9300_get_txbf_capabilities(ah) NULL #define ar9300_txbf_set_key( \ ah, entry, rx_staggered_sounding, channel_estimation_cap, mmss) #define ar9300_read_key_cache_mac(ah, entry, mac) false #define ar9300_txbf_get_cv_cache_nr(ah, key_idx, nr) #define ar9300_set_selfgenrate_limit(ah, ts_ratecode) #define ar9300_reset_lowest_txrate(ah) #define ar9300_txbf_set_basic_set(ah) extern void ar9300_crdc_rx_notify(struct ath_hal *ah, struct ath_rx_status *rxs); extern void ar9300_chain_rssi_diff_compensation(struct ath_hal *ah); #if ATH_SUPPORT_MCI extern void ar9300_mci_bt_coex_set_weights(struct ath_hal *ah, u_int32_t stomp_type); extern void ar9300_mci_bt_coex_disable(struct ath_hal *ah); extern int ar9300_mci_bt_coex_enable(struct ath_hal *ah); extern void ar9300_mci_setup (struct ath_hal *ah, u_int32_t gpm_addr, void *gpm_buf, u_int16_t len, u_int32_t sched_addr); extern void ar9300_mci_remote_reset(struct ath_hal *ah, HAL_BOOL wait_done); extern void ar9300_mci_send_lna_transfer(struct ath_hal *ah, HAL_BOOL wait_done); extern void ar9300_mci_send_sys_waking(struct ath_hal *ah, HAL_BOOL wait_done); extern HAL_BOOL ar9300_mci_send_message (struct ath_hal *ah, u_int8_t header, u_int32_t flag, u_int32_t *payload, u_int8_t len, HAL_BOOL wait_done, HAL_BOOL check_bt); extern u_int32_t ar9300_mci_get_interrupt (struct ath_hal *ah, u_int32_t *mci_int, u_int32_t *mci_int_rx_msg); extern u_int32_t ar9300_mci_state (struct ath_hal *ah, u_int32_t state_type, u_int32_t *p_data); extern void ar9300_mci_reset (struct ath_hal *ah, HAL_BOOL en_int, HAL_BOOL is_2g, HAL_BOOL is_full_sleep); extern void ar9300_mci_send_coex_halt_bt_gpm(struct ath_hal *ah, HAL_BOOL halt, HAL_BOOL wait_done); extern void ar9300_mci_mute_bt(struct ath_hal *ah); extern u_int32_t ar9300_mci_wait_for_gpm(struct ath_hal *ah, u_int8_t gpm_type, u_int8_t gpm_opcode, int32_t time_out); extern void ar9300_mci_enable_interrupt(struct ath_hal *ah); extern void ar9300_mci_disable_interrupt(struct ath_hal *ah); extern void ar9300_mci_detach (struct ath_hal *ah); extern u_int32_t ar9300_mci_check_int (struct ath_hal *ah, u_int32_t ints); extern void ar9300_mci_sync_bt_state (struct ath_hal *ah); extern void ar9300_mci_2g5g_changed(struct ath_hal *ah, HAL_BOOL is_2g); extern void ar9300_mci_2g5g_switch(struct ath_hal *ah, HAL_BOOL wait_done); #if ATH_SUPPORT_AIC extern u_int32_t ar9300_aic_calibration (struct ath_hal *ah); extern u_int32_t ar9300_aic_start_normal (struct ath_hal *ah); #endif #endif extern HAL_STATUS ar9300_set_proxy_sta(struct ath_hal *ah, HAL_BOOL enable); extern HAL_BOOL ar9300_regulatory_domain_override( struct ath_hal *ah, u_int16_t regdmn); #if ATH_ANT_DIV_COMB extern void ar9300_ant_div_comb_get_config(struct ath_hal *ah, HAL_ANT_COMB_CONFIG* div_comb_conf); extern void ar9300_ant_div_comb_set_config(struct ath_hal *ah, HAL_ANT_COMB_CONFIG* div_comb_conf); #endif /* ATH_ANT_DIV_COMB */ extern void ar9300_disable_phy_restart(struct ath_hal *ah, int disable_phy_restart); extern void ar9300_enable_keysearch_always(struct ath_hal *ah, int enable); extern HAL_BOOL ar9300ForceVCS( struct ath_hal *ah); extern HAL_BOOL ar9300SetDfs3StreamFix(struct ath_hal *ah, u_int32_t val); extern HAL_BOOL ar9300Get3StreamSignature( struct ath_hal *ah); #ifdef ATH_TX99_DIAG #ifndef ATH_SUPPORT_HTC extern void ar9300_tx99_channel_pwr_update(struct ath_hal *ah, struct ieee80211_channel *c, u_int32_t txpower); extern void ar9300_tx99_chainmsk_setup(struct ath_hal *ah, int tx_chainmask); extern void ar9300_tx99_set_single_carrier(struct ath_hal *ah, int tx_chain_mask, int chtype); extern void ar9300_tx99_start(struct ath_hal *ah, u_int8_t *data); extern void ar9300_tx99_stop(struct ath_hal *ah); #endif /* ATH_SUPPORT_HTC */ #endif /* ATH_TX99_DIAG */ extern HAL_BOOL ar9300_set_ctl_pwr(struct ath_hal *ah, u_int8_t *ctl_array); extern void ar9300_set_txchainmaskopt(struct ath_hal *ah, u_int8_t mask); enum { AR9300_COEFF_TX_TYPE = 0, AR9300_COEFF_RX_TYPE }; #endif /* _ATH_AR9300_H_ */ Index: head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c =================================================================== --- head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c (revision 280828) +++ head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_ani.c (revision 280829) @@ -1,1282 +1,1304 @@ /* * Copyright (c) 2013 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "opt_ah.h" #include "ah.h" #include "ah_internal.h" #include "ah_desc.h" //#include "ah_pktlog.h" #include "ar9300/ar9300.h" #include "ar9300/ar9300reg.h" #include "ar9300/ar9300phy.h" extern void ar9300_set_rx_filter(struct ath_hal *ah, u_int32_t bits); extern u_int32_t ar9300_get_rx_filter(struct ath_hal *ah); #define HAL_ANI_DEBUG 1 /* * Anti noise immunity support. We track phy errors and react * to excessive errors by adjusting the noise immunity parameters. */ /****************************************************************************** * * New Ani Algorithm for Station side only * *****************************************************************************/ #define HAL_ANI_OFDM_TRIG_HIGH 1000 /* units are errors per second */ #define HAL_ANI_OFDM_TRIG_LOW 400 /* units are errors per second */ #define HAL_ANI_CCK_TRIG_HIGH 600 /* units are errors per second */ #define HAL_ANI_CCK_TRIG_LOW 300 /* units are errors per second */ #define HAL_ANI_USE_OFDM_WEAK_SIG AH_TRUE #define HAL_ANI_ENABLE_MRC_CCK AH_TRUE /* default is enabled */ #define HAL_ANI_DEF_SPUR_IMMUNE_LVL 3 #define HAL_ANI_DEF_FIRSTEP_LVL 2 #define HAL_ANI_RSSI_THR_HIGH 40 #define HAL_ANI_RSSI_THR_LOW 7 #define HAL_ANI_PERIOD 1000 #define HAL_NOISE_DETECT_PERIOD 100 #define HAL_NOISE_RECOVER_PERIOD 5000 #define HAL_SIG_FIRSTEP_SETTING_MIN 0 #define HAL_SIG_FIRSTEP_SETTING_MAX 20 #define HAL_SIG_SPUR_IMM_SETTING_MIN 0 #define HAL_SIG_SPUR_IMM_SETTING_MAX 22 #define HAL_EP_RND(x, mul) \ ((((x) % (mul)) >= ((mul) / 2)) ? ((x) + ((mul) - 1)) / (mul) : (x) / (mul)) #define BEACON_RSSI(ahp) \ HAL_EP_RND(ahp->ah_stats.ast_nodestats.ns_avgbrssi, \ HAL_RSSI_EP_MULTIPLIER) typedef int TABLE[]; /* * level: 0 1 2 3 4 5 6 7 8 * firstep_table: lvl 0-8, default 2 */ static const TABLE firstep_table = { -4, -2, 0, 2, 4, 6, 8, 10, 12}; /* cycpwr_thr1_table: lvl 0-7, default 3 */ static const TABLE cycpwr_thr1_table = { -6, -4, -2, 0, 2, 4, 6, 8 }; /* values here are relative to the INI */ typedef struct _HAL_ANI_OFDM_LEVEL_ENTRY { int spur_immunity_level; int fir_step_level; int ofdm_weak_signal_on; } HAL_ANI_OFDM_LEVEL_ENTRY; static const HAL_ANI_OFDM_LEVEL_ENTRY ofdm_level_table[] = { /* SI FS WS */ { 0, 0, 1 }, /* lvl 0 */ { 1, 1, 1 }, /* lvl 1 */ { 2, 2, 1 }, /* lvl 2 */ { 3, 2, 1 }, /* lvl 3 (default) */ { 4, 3, 1 }, /* lvl 4 */ { 5, 4, 1 }, /* lvl 5 */ { 6, 5, 1 }, /* lvl 6 */ { 7, 6, 1 }, /* lvl 7 */ { 7, 7, 1 }, /* lvl 8 */ { 7, 8, 0 } /* lvl 9 */ }; #define HAL_ANI_OFDM_NUM_LEVEL \ (sizeof(ofdm_level_table) / sizeof(ofdm_level_table[0])) #define HAL_ANI_OFDM_MAX_LEVEL (HAL_ANI_OFDM_NUM_LEVEL - 1) #define HAL_ANI_OFDM_DEF_LEVEL 3 /* default level - matches the INI settings */ typedef struct _HAL_ANI_CCK_LEVEL_ENTRY { int fir_step_level; int mrc_cck_on; } HAL_ANI_CCK_LEVEL_ENTRY; static const HAL_ANI_CCK_LEVEL_ENTRY cck_level_table[] = { /* FS MRC-CCK */ { 0, 1 }, /* lvl 0 */ { 1, 1 }, /* lvl 1 */ { 2, 1 }, /* lvl 2 (default) */ { 3, 1 }, /* lvl 3 */ { 4, 0 }, /* lvl 4 */ { 5, 0 }, /* lvl 5 */ { 6, 0 }, /* lvl 6 */ { 7, 0 }, /* lvl 7 (only for high rssi) */ { 8, 0 } /* lvl 8 (only for high rssi) */ }; #define HAL_ANI_CCK_NUM_LEVEL \ (sizeof(cck_level_table) / sizeof(cck_level_table[0])) #define HAL_ANI_CCK_MAX_LEVEL (HAL_ANI_CCK_NUM_LEVEL - 1) #define HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI (HAL_ANI_CCK_NUM_LEVEL - 3) #define HAL_ANI_CCK_DEF_LEVEL 2 /* default level - matches the INI settings */ /* * register values to turn OFDM weak signal detection OFF */ static const int m1_thresh_low_off = 127; static const int m2_thresh_low_off = 127; static const int m1_thresh_off = 127; static const int m2_thresh_off = 127; static const int m2_count_thr_off = 31; static const int m2_count_thr_low_off = 63; static const int m1_thresh_low_ext_off = 127; static const int m2_thresh_low_ext_off = 127; static const int m1_thresh_ext_off = 127; static const int m2_thresh_ext_off = 127; void ar9300_enable_mib_counters(struct ath_hal *ah) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Enable MIB counters\n", __func__); /* Clear the mib counters and save them in the stats */ ar9300_update_mib_mac_stats(ah); OS_REG_WRITE(ah, AR_FILT_OFDM, 0); OS_REG_WRITE(ah, AR_FILT_CCK, 0); OS_REG_WRITE(ah, AR_MIBC, ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) & 0x0f); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } void ar9300_disable_mib_counters(struct ath_hal *ah) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Disabling MIB counters\n", __func__); OS_REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); /* Clear the mib counters and save them in the stats */ ar9300_update_mib_mac_stats(ah); OS_REG_WRITE(ah, AR_FILT_OFDM, 0); OS_REG_WRITE(ah, AR_FILT_CCK, 0); } /* * This routine returns the index into the ani_state array that * corresponds to the channel in *chan. If no match is found and the * array is still not fully utilized, a new entry is created for the * channel. We assume the attach function has already initialized the * ah_ani values and only the channel field needs to be set. */ static int ar9300_get_ani_channel_index(struct ath_hal *ah, const struct ieee80211_channel *chan) { struct ath_hal_9300 *ahp = AH9300(ah); int i; for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) { /* XXX this doesn't distinguish between 20/40 channels */ if (ahp->ah_ani[i].c.ic_freq == chan->ic_freq) { return i; } if (ahp->ah_ani[i].c.ic_freq == 0) { ahp->ah_ani[i].c.ic_freq = chan->ic_freq; ahp->ah_ani[i].c.ic_flags = chan->ic_flags; return i; } } /* XXX statistic */ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: No more channel states left. Using channel 0\n", __func__); return 0; /* XXX gotta return something valid */ } /* * Return the current ANI state of the channel we're on */ struct ar9300_ani_state * ar9300_ani_get_current_state(struct ath_hal *ah) { return AH9300(ah)->ah_curani; } /* * Return the current statistics. */ struct ar9300_stats * ar9300_ani_get_current_stats(struct ath_hal *ah) { return &AH9300(ah)->ah_stats; } /* * Setup ANI handling. Sets all thresholds and levels to default level AND * resets the channel statistics */ void ar9300_ani_attach(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); int i; OS_MEMZERO(ahp->ah_ani, sizeof(ahp->ah_ani)); for (i = 0; i < ARRAY_LENGTH(ahp->ah_ani); i++) { ahp->ah_ani[i].ofdm_trig_high = HAL_ANI_OFDM_TRIG_HIGH; ahp->ah_ani[i].ofdm_trig_low = HAL_ANI_OFDM_TRIG_LOW; ahp->ah_ani[i].cck_trig_high = HAL_ANI_CCK_TRIG_HIGH; ahp->ah_ani[i].cck_trig_low = HAL_ANI_CCK_TRIG_LOW; ahp->ah_ani[i].rssi_thr_high = HAL_ANI_RSSI_THR_HIGH; ahp->ah_ani[i].rssi_thr_low = HAL_ANI_RSSI_THR_LOW; ahp->ah_ani[i].ofdm_noise_immunity_level = HAL_ANI_OFDM_DEF_LEVEL; ahp->ah_ani[i].cck_noise_immunity_level = HAL_ANI_CCK_DEF_LEVEL; ahp->ah_ani[i].ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG; ahp->ah_ani[i].spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL; ahp->ah_ani[i].firstep_level = HAL_ANI_DEF_FIRSTEP_LVL; ahp->ah_ani[i].mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK; ahp->ah_ani[i].ofdms_turn = AH_TRUE; ahp->ah_ani[i].must_restore = AH_FALSE; } /* * Since we expect some ongoing maintenance on the tables, * let's sanity check here. * The default level should not modify INI setting. */ HALASSERT(firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] == 0); HALASSERT(cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] == 0); HALASSERT( ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].fir_step_level == HAL_ANI_DEF_FIRSTEP_LVL); HALASSERT( ofdm_level_table[HAL_ANI_OFDM_DEF_LEVEL].spur_immunity_level == HAL_ANI_DEF_SPUR_IMMUNE_LVL); HALASSERT( cck_level_table[HAL_ANI_CCK_DEF_LEVEL].fir_step_level == HAL_ANI_DEF_FIRSTEP_LVL); /* Initialize and enable MIB Counters */ OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); ar9300_enable_mib_counters(ah); ahp->ah_ani_period = HAL_ANI_PERIOD; if (ah->ah_config.ath_hal_enable_ani) { ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; } } /* * Cleanup any ANI state setup. */ void ar9300_ani_detach(struct ath_hal *ah) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Detaching Ani\n", __func__); ar9300_disable_mib_counters(ah); OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); } /* * Initialize the ANI register values with default (ini) values. * This routine is called during a (full) hardware reset after * all the registers are initialised from the INI. */ void ar9300_ani_init_defaults(struct ath_hal *ah, HAL_HT_MACMODE macmode) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; int index; u_int32_t val; HALASSERT(chan != AH_NULL); index = ar9300_get_ani_channel_index(ah, chan); ani_state = &ahp->ah_ani[index]; ahp->ah_curani = ani_state; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ver %d.%d opmode %u chan %d Mhz/0x%x macmode %d\n", __func__, AH_PRIVATE(ah)->ah_macVersion, AH_PRIVATE(ah)->ah_macRev, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_flags, macmode); val = OS_REG_READ(ah, AR_PHY_SFCORR); ani_state->ini_def.m1_thresh = MS(val, AR_PHY_SFCORR_M1_THRESH); ani_state->ini_def.m2_thresh = MS(val, AR_PHY_SFCORR_M2_THRESH); ani_state->ini_def.m2_count_thr = MS(val, AR_PHY_SFCORR_M2COUNT_THR); val = OS_REG_READ(ah, AR_PHY_SFCORR_LOW); ani_state->ini_def.m1_thresh_low = MS(val, AR_PHY_SFCORR_LOW_M1_THRESH_LOW); ani_state->ini_def.m2_thresh_low = MS(val, AR_PHY_SFCORR_LOW_M2_THRESH_LOW); ani_state->ini_def.m2_count_thr_low = MS(val, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW); val = OS_REG_READ(ah, AR_PHY_SFCORR_EXT); ani_state->ini_def.m1_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH); ani_state->ini_def.m2_thresh_ext = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH); ani_state->ini_def.m1_thresh_low_ext = MS(val, AR_PHY_SFCORR_EXT_M1_THRESH_LOW); ani_state->ini_def.m2_thresh_low_ext = MS(val, AR_PHY_SFCORR_EXT_M2_THRESH_LOW); ani_state->ini_def.firstep = OS_REG_READ_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP); ani_state->ini_def.firstep_low = OS_REG_READ_FIELD( ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW); ani_state->ini_def.cycpwr_thr1 = OS_REG_READ_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1); ani_state->ini_def.cycpwr_thr1_ext = OS_REG_READ_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1); /* these levels just got reset to defaults by the INI */ ani_state->spur_immunity_level = HAL_ANI_DEF_SPUR_IMMUNE_LVL; ani_state->firstep_level = HAL_ANI_DEF_FIRSTEP_LVL; ani_state->ofdm_weak_sig_detect_off = !HAL_ANI_USE_OFDM_WEAK_SIG; ani_state->mrc_cck_off = !HAL_ANI_ENABLE_MRC_CCK; ani_state->cycle_count = 0; } /* * Set the ANI settings to match an OFDM level. */ static void ar9300_ani_set_odfm_noise_immunity_level(struct ath_hal *ah, u_int8_t ofdm_noise_immunity_level) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state = ahp->ah_curani; ani_state->rssi = BEACON_RSSI(ahp); HALDEBUG(ah, HAL_DEBUG_ANI, "**** %s: ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", __func__, ani_state->ofdm_noise_immunity_level, ofdm_noise_immunity_level, ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high); ani_state->ofdm_noise_immunity_level = ofdm_noise_immunity_level; if (ani_state->spur_immunity_level != ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level) { ar9300_ani_control( ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, ofdm_level_table[ofdm_noise_immunity_level].spur_immunity_level); } if (ani_state->firstep_level != ofdm_level_table[ofdm_noise_immunity_level].fir_step_level && ofdm_level_table[ofdm_noise_immunity_level].fir_step_level >= cck_level_table[ani_state->cck_noise_immunity_level].fir_step_level) { ar9300_ani_control( ah, HAL_ANI_FIRSTEP_LEVEL, ofdm_level_table[ofdm_noise_immunity_level].fir_step_level); } if ((AH_PRIVATE(ah)->ah_opmode != HAL_M_STA || ani_state->rssi <= ani_state->rssi_thr_high)) { if (ani_state->ofdm_weak_sig_detect_off) { /* * force on ofdm weak sig detect. */ ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, AH_TRUE); } } else if (ani_state->ofdm_weak_sig_detect_off == ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on) { ar9300_ani_control( ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, ofdm_level_table[ofdm_noise_immunity_level].ofdm_weak_signal_on); } } /* * Set the ANI settings to match a CCK level. */ static void ar9300_ani_set_cck_noise_immunity_level(struct ath_hal *ah, u_int8_t cck_noise_immunity_level) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state = ahp->ah_curani; int level; ani_state->rssi = BEACON_RSSI(ahp); HALDEBUG(ah, HAL_DEBUG_ANI, "**** %s: ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", __func__, ani_state->cck_noise_immunity_level, cck_noise_immunity_level, ani_state->rssi, ani_state->rssi_thr_low, ani_state->rssi_thr_high); if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA && ani_state->rssi <= ani_state->rssi_thr_low && cck_noise_immunity_level > HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI) { cck_noise_immunity_level = HAL_ANI_CCK_MAX_LEVEL_LOW_RSSI; } ani_state->cck_noise_immunity_level = cck_noise_immunity_level; level = ani_state->ofdm_noise_immunity_level; if (ani_state->firstep_level != cck_level_table[cck_noise_immunity_level].fir_step_level && cck_level_table[cck_noise_immunity_level].fir_step_level >= ofdm_level_table[level].fir_step_level) { ar9300_ani_control( ah, HAL_ANI_FIRSTEP_LEVEL, cck_level_table[cck_noise_immunity_level].fir_step_level); } if (ani_state->mrc_cck_off == cck_level_table[cck_noise_immunity_level].mrc_cck_on) { ar9300_ani_control( ah, HAL_ANI_MRC_CCK, cck_level_table[cck_noise_immunity_level].mrc_cck_on); } } /* * Control Adaptive Noise Immunity Parameters */ HAL_BOOL ar9300_ani_control(struct ath_hal *ah, HAL_ANI_CMD cmd, int param) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state = ahp->ah_curani; const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; int32_t value, value2; u_int level = param; u_int is_on; if (chan == NULL && cmd != HAL_ANI_MODE) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: ignoring cmd 0x%02x - no channel\n", __func__, cmd); return AH_FALSE; } switch (cmd & ahp->ah_ani_function) { case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: { int m1_thresh_low, m2_thresh_low; int m1_thresh, m2_thresh; int m2_count_thr, m2_count_thr_low; int m1_thresh_low_ext, m2_thresh_low_ext; int m1_thresh_ext, m2_thresh_ext; /* * is_on == 1 means ofdm weak signal detection is ON * (default, less noise imm) * is_on == 0 means ofdm weak signal detection is OFF * (more noise imm) */ is_on = param ? 1 : 0; if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) goto skip_ws_det; /* * make register setting for default (weak sig detect ON) * come from INI file */ m1_thresh_low = is_on ? ani_state->ini_def.m1_thresh_low : m1_thresh_low_off; m2_thresh_low = is_on ? ani_state->ini_def.m2_thresh_low : m2_thresh_low_off; m1_thresh = is_on ? ani_state->ini_def.m1_thresh : m1_thresh_off; m2_thresh = is_on ? ani_state->ini_def.m2_thresh : m2_thresh_off; m2_count_thr = is_on ? ani_state->ini_def.m2_count_thr : m2_count_thr_off; m2_count_thr_low = is_on ? ani_state->ini_def.m2_count_thr_low : m2_count_thr_low_off; m1_thresh_low_ext = is_on ? ani_state->ini_def.m1_thresh_low_ext : m1_thresh_low_ext_off; m2_thresh_low_ext = is_on ? ani_state->ini_def.m2_thresh_low_ext : m2_thresh_low_ext_off; m1_thresh_ext = is_on ? ani_state->ini_def.m1_thresh_ext : m1_thresh_ext_off; m2_thresh_ext = is_on ? ani_state->ini_def.m2_thresh_ext : m2_thresh_ext_off; OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW, m1_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW, m2_thresh_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH, m1_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH, m2_thresh); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR, m2_count_thr); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, m2_count_thr_low); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH_LOW, m1_thresh_low_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH_LOW, m2_thresh_low_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M1_THRESH, m1_thresh_ext); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_M2_THRESH, m2_thresh_ext); skip_ws_det: if (is_on) { OS_REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } else { OS_REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); } if (!is_on != ani_state->ofdm_weak_sig_detect_off) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: ofdm weak signal: %s=>%s\n", __func__, chan->ic_freq, !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", is_on ? "on" : "off"); if (is_on) { ahp->ah_stats.ast_ani_ofdmon++; } else { ahp->ah_stats.ast_ani_ofdmoff++; } ani_state->ofdm_weak_sig_detect_off = !is_on; } break; } case HAL_ANI_FIRSTEP_LEVEL: if (level >= ARRAY_LENGTH(firstep_table)) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: HAL_ANI_FIRSTEP_LEVEL level out of range (%u > %u)\n", __func__, level, (unsigned) ARRAY_LENGTH(firstep_table)); return AH_FALSE; } /* * make register setting relative to default * from INI file & cap value */ value = firstep_table[level] - firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + ani_state->ini_def.firstep; if (value < HAL_SIG_FIRSTEP_SETTING_MIN) { value = HAL_SIG_FIRSTEP_SETTING_MIN; } if (value > HAL_SIG_FIRSTEP_SETTING_MAX) { value = HAL_SIG_FIRSTEP_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, AR_PHY_FIND_SIG_FIRSTEP, value); /* * we need to set first step low register too * make register setting relative to default from INI file & cap value */ value2 = firstep_table[level] - firstep_table[HAL_ANI_DEF_FIRSTEP_LVL] + ani_state->ini_def.firstep_low; if (value2 < HAL_SIG_FIRSTEP_SETTING_MIN) { value2 = HAL_SIG_FIRSTEP_SETTING_MIN; } if (value2 > HAL_SIG_FIRSTEP_SETTING_MAX) { value2 = HAL_SIG_FIRSTEP_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_FIND_SIG_LOW, AR_PHY_FIND_SIG_LOW_FIRSTEP_LOW, value2); if (level != ani_state->firstep_level) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] firstep[level]=%d ini=%d\n", __func__, chan->ic_freq, ani_state->firstep_level, level, HAL_ANI_DEF_FIRSTEP_LVL, value, ani_state->ini_def.firstep); HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "firstep_low[level]=%d ini=%d\n", __func__, chan->ic_freq, ani_state->firstep_level, level, HAL_ANI_DEF_FIRSTEP_LVL, value2, ani_state->ini_def.firstep_low); if (level > ani_state->firstep_level) { ahp->ah_stats.ast_ani_stepup++; } else if (level < ani_state->firstep_level) { ahp->ah_stats.ast_ani_stepdown++; } ani_state->firstep_level = level; } break; case HAL_ANI_SPUR_IMMUNITY_LEVEL: if (level >= ARRAY_LENGTH(cycpwr_thr1_table)) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: HAL_ANI_SPUR_IMMUNITY_LEVEL level " "out of range (%u > %u)\n", __func__, level, (unsigned) ARRAY_LENGTH(cycpwr_thr1_table)); return AH_FALSE; } /* * make register setting relative to default from INI file & cap value */ value = cycpwr_thr1_table[level] - cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + ani_state->ini_def.cycpwr_thr1; if (value < HAL_SIG_SPUR_IMM_SETTING_MIN) { value = HAL_SIG_SPUR_IMM_SETTING_MIN; } if (value > HAL_SIG_SPUR_IMM_SETTING_MAX) { value = HAL_SIG_SPUR_IMM_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_TIMING5, AR_PHY_TIMING5_CYCPWR_THR1, value); /* * set AR_PHY_EXT_CCA for extension channel * make register setting relative to default from INI file & cap value */ value2 = cycpwr_thr1_table[level] - cycpwr_thr1_table[HAL_ANI_DEF_SPUR_IMMUNE_LVL] + ani_state->ini_def.cycpwr_thr1_ext; if (value2 < HAL_SIG_SPUR_IMM_SETTING_MIN) { value2 = HAL_SIG_SPUR_IMM_SETTING_MIN; } if (value2 > HAL_SIG_SPUR_IMM_SETTING_MAX) { value2 = HAL_SIG_SPUR_IMM_SETTING_MAX; } OS_REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, AR_PHY_EXT_CYCPWR_THR1, value2); if (level != ani_state->spur_immunity_level) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "cycpwr_thr1[level]=%d ini=%d\n", __func__, chan->ic_freq, ani_state->spur_immunity_level, level, HAL_ANI_DEF_SPUR_IMMUNE_LVL, value, ani_state->ini_def.cycpwr_thr1); HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: level %d=>%d[def:%d] " "cycpwr_thr1_ext[level]=%d ini=%d\n", __func__, chan->ic_freq, ani_state->spur_immunity_level, level, HAL_ANI_DEF_SPUR_IMMUNE_LVL, value2, ani_state->ini_def.cycpwr_thr1_ext); if (level > ani_state->spur_immunity_level) { ahp->ah_stats.ast_ani_spurup++; } else if (level < ani_state->spur_immunity_level) { ahp->ah_stats.ast_ani_spurdown++; } ani_state->spur_immunity_level = level; } break; case HAL_ANI_MRC_CCK: /* * is_on == 1 means MRC CCK ON (default, less noise imm) * is_on == 0 means MRC CCK is OFF (more noise imm) */ is_on = param ? 1 : 0; if (!AR_SREV_POSEIDON(ah)) { OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_ENABLE, is_on); OS_REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_MUX_REG, is_on); } if (!is_on != ani_state->mrc_cck_off) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ** ch %d: MRC CCK: %s=>%s\n", __func__, chan->ic_freq, !ani_state->mrc_cck_off ? "on" : "off", is_on ? "on" : "off"); if (is_on) { ahp->ah_stats.ast_ani_ccklow++; } else { ahp->ah_stats.ast_ani_cckhigh++; } ani_state->mrc_cck_off = !is_on; } break; case HAL_ANI_PRESENT: break; #ifdef AH_PRIVATE_DIAG case HAL_ANI_MODE: if (param == 0) { ahp->ah_proc_phy_err &= ~HAL_PROCESS_ANI; /* Turn off HW counters if we have them */ ar9300_ani_detach(ah); if (AH_PRIVATE(ah)->ah_curchan == NULL) { return AH_TRUE; } /* if we're turning off ANI, reset regs back to INI settings */ if (ah->ah_config.ath_hal_enable_ani) { HAL_ANI_CMD savefunc = ahp->ah_ani_function; /* temporarly allow all functions so we can reset */ ahp->ah_ani_function = HAL_ANI_ALL; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: disable all ANI functions\n", __func__); ar9300_ani_set_odfm_noise_immunity_level( ah, HAL_ANI_OFDM_DEF_LEVEL); ar9300_ani_set_cck_noise_immunity_level( ah, HAL_ANI_CCK_DEF_LEVEL); ahp->ah_ani_function = savefunc; } } else { /* normal/auto mode */ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enabled\n", __func__); ahp->ah_proc_phy_err |= HAL_PROCESS_ANI; if (AH_PRIVATE(ah)->ah_curchan == NULL) { return AH_TRUE; } ar9300_enable_mib_counters(ah); ar9300_ani_reset(ah, AH_FALSE); ani_state = ahp->ah_curani; } HALDEBUG(ah, HAL_DEBUG_ANI, "5 ANC: ahp->ah_proc_phy_err %x \n", ahp->ah_proc_phy_err); break; case HAL_ANI_PHYERR_RESET: ahp->ah_stats.ast_ani_ofdmerrs = 0; ahp->ah_stats.ast_ani_cckerrs = 0; break; #endif /* AH_PRIVATE_DIAG */ default: #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: invalid cmd 0x%02x (allowed=0x%02x)\n", __func__, cmd, ahp->ah_ani_function); #endif return AH_FALSE; } #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: ANI parameters: SI=%d, ofdm_ws=%s FS=%d MRCcck=%s listen_time=%d " "CC=%d listen=%d ofdm_errs=%d cck_errs=%d\n", __func__, ani_state->spur_immunity_level, !ani_state->ofdm_weak_sig_detect_off ? "on" : "off", ani_state->firstep_level, !ani_state->mrc_cck_off ? "on" : "off", ani_state->listen_time, ani_state->cycle_count, ani_state->listen_time, ani_state->ofdm_phy_err_count, ani_state->cck_phy_err_count); #endif #ifndef REMOVE_PKT_LOG /* do pktlog */ { struct log_ani log_data; /* Populate the ani log record */ log_data.phy_stats_disable = DO_ANI(ah); log_data.noise_immun_lvl = ani_state->ofdm_noise_immunity_level; log_data.spur_immun_lvl = ani_state->spur_immunity_level; log_data.ofdm_weak_det = ani_state->ofdm_weak_sig_detect_off; log_data.cck_weak_thr = ani_state->cck_noise_immunity_level; log_data.fir_lvl = ani_state->firstep_level; log_data.listen_time = ani_state->listen_time; log_data.cycle_count = ani_state->cycle_count; /* express ofdm_phy_err_count as errors/second */ log_data.ofdm_phy_err_count = ani_state->listen_time ? ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time : 0; /* express cck_phy_err_count as errors/second */ log_data.cck_phy_err_count = ani_state->listen_time ? ani_state->cck_phy_err_count * 1000 / ani_state->listen_time : 0; log_data.rssi = ani_state->rssi; /* clear interrupt context flag */ ath_hal_log_ani(AH_PRIVATE(ah)->ah_sc, &log_data, 0); } #endif return AH_TRUE; } static void ar9300_ani_restart(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; if (!DO_ANI(ah)) { return; } ani_state = ahp->ah_curani; ani_state->listen_time = 0; OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); /* Clear the mib counters and save them in the stats */ ar9300_update_mib_mac_stats(ah); ani_state->ofdm_phy_err_count = 0; ani_state->cck_phy_err_count = 0; } static void ar9300_ani_ofdm_err_trigger(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; if (!DO_ANI(ah)) { return; } ani_state = ahp->ah_curani; if (ani_state->ofdm_noise_immunity_level < HAL_ANI_OFDM_MAX_LEVEL) { ar9300_ani_set_odfm_noise_immunity_level( ah, ani_state->ofdm_noise_immunity_level + 1); } } static void ar9300_ani_cck_err_trigger(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; if (!DO_ANI(ah)) { return; } ani_state = ahp->ah_curani; if (ani_state->cck_noise_immunity_level < HAL_ANI_CCK_MAX_LEVEL) { ar9300_ani_set_cck_noise_immunity_level( ah, ani_state->cck_noise_immunity_level + 1); } } /* * Restore the ANI parameters in the HAL and reset the statistics. * This routine should be called for every hardware reset and for * every channel change. */ void ar9300_ani_reset(struct ath_hal *ah, HAL_BOOL is_scanning) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; const struct ieee80211_channel *chan = AH_PRIVATE(ah)->ah_curchan; HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); int index; HALASSERT(chan != AH_NULL); if (!DO_ANI(ah)) { return; } /* * we need to re-point to the correct ANI state since the channel * may have changed due to a fast channel change */ index = ar9300_get_ani_channel_index(ah, chan); ani_state = &ahp->ah_ani[index]; HALASSERT(ani_state != AH_NULL); ahp->ah_curani = ani_state; ahp->ah_stats.ast_ani_reset++; ani_state->phy_noise_spur = 0; /* only allow a subset of functions in AP mode */ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { if (IS_CHAN_2GHZ(ichan)) { ahp->ah_ani_function = (HAL_ANI_SPUR_IMMUNITY_LEVEL | HAL_ANI_FIRSTEP_LEVEL | HAL_ANI_MRC_CCK); } else { ahp->ah_ani_function = 0; } } /* always allow mode (on/off) to be controlled */ ahp->ah_ani_function |= HAL_ANI_MODE; if (is_scanning || (AH_PRIVATE(ah)->ah_opmode != HAL_M_STA && AH_PRIVATE(ah)->ah_opmode != HAL_M_IBSS)) { /* * If we're scanning or in AP mode, the defaults (ini) should be * in place. * For an AP we assume the historical levels for this channel are * probably outdated so start from defaults instead. */ if (ani_state->ofdm_noise_immunity_level != HAL_ANI_OFDM_DEF_LEVEL || ani_state->cck_noise_immunity_level != HAL_ANI_CCK_DEF_LEVEL) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Restore defaults: opmode %u chan %d Mhz/0x%x " "is_scanning=%d restore=%d ofdm:%d cck:%d\n", __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_flags, is_scanning, ani_state->must_restore, ani_state->ofdm_noise_immunity_level, ani_state->cck_noise_immunity_level); /* * for STA/IBSS, we want to restore the historical values later * (when we're not scanning) */ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_STA || AH_PRIVATE(ah)->ah_opmode == HAL_M_IBSS) { ar9300_ani_control(ah, HAL_ANI_SPUR_IMMUNITY_LEVEL, HAL_ANI_DEF_SPUR_IMMUNE_LVL); ar9300_ani_control( ah, HAL_ANI_FIRSTEP_LEVEL, HAL_ANI_DEF_FIRSTEP_LVL); ar9300_ani_control(ah, HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION, HAL_ANI_USE_OFDM_WEAK_SIG); ar9300_ani_control(ah, HAL_ANI_MRC_CCK, HAL_ANI_ENABLE_MRC_CCK); ani_state->must_restore = AH_TRUE; } else { ar9300_ani_set_odfm_noise_immunity_level( ah, HAL_ANI_OFDM_DEF_LEVEL); ar9300_ani_set_cck_noise_immunity_level( ah, HAL_ANI_CCK_DEF_LEVEL); } } } else { /* * restore historical levels for this channel */ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d " "restore=%d ofdm:%d cck:%d\n", __func__, AH_PRIVATE(ah)->ah_opmode, chan->ic_freq, chan->ic_flags, is_scanning, ani_state->must_restore, ani_state->ofdm_noise_immunity_level, ani_state->cck_noise_immunity_level); ar9300_ani_set_odfm_noise_immunity_level( ah, ani_state->ofdm_noise_immunity_level); ar9300_ani_set_cck_noise_immunity_level( ah, ani_state->cck_noise_immunity_level); ani_state->must_restore = AH_FALSE; } /* enable phy counters */ ar9300_ani_restart(ah); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); OS_REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); } /* * Process a MIB interrupt. We may potentially be invoked because * any of the MIB counters overflow/trigger so don't assume we're * here because a PHY error counter triggered. */ void ar9300_process_mib_intr(struct ath_hal *ah, const HAL_NODE_STATS *stats) { struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t phy_cnt1, phy_cnt2; #if 0 HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Processing Mib Intr\n", __func__); #endif /* Reset these counters regardless */ OS_REG_WRITE(ah, AR_FILT_OFDM, 0); OS_REG_WRITE(ah, AR_FILT_CCK, 0); if (!(OS_REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) { OS_REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); } /* Clear the mib counters and save them in the stats */ ar9300_update_mib_mac_stats(ah); ahp->ah_stats.ast_nodestats = *stats; if (!DO_ANI(ah)) { /* * We must always clear the interrupt cause by resetting * the phy error regs. */ OS_REG_WRITE(ah, AR_PHY_ERR_1, 0); OS_REG_WRITE(ah, AR_PHY_ERR_2, 0); return; } /* NB: these are not reset-on-read */ phy_cnt1 = OS_REG_READ(ah, AR_PHY_ERR_1); phy_cnt2 = OS_REG_READ(ah, AR_PHY_ERR_2); #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", __func__, phy_cnt1, phy_cnt1, phy_cnt2, phy_cnt2); #endif if (((phy_cnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || ((phy_cnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { /* NB: always restart to insure the h/w counters are reset */ ar9300_ani_restart(ah); } } static void ar9300_ani_lower_immunity(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state = ahp->ah_curani; if (ani_state->ofdm_noise_immunity_level > 0 && (ani_state->ofdms_turn || ani_state->cck_noise_immunity_level == 0)) { /* * lower OFDM noise immunity */ ar9300_ani_set_odfm_noise_immunity_level( ah, ani_state->ofdm_noise_immunity_level - 1); /* * only lower either OFDM or CCK errors per turn * we lower the other one next time */ return; } if (ani_state->cck_noise_immunity_level > 0) { /* * lower CCK noise immunity */ ar9300_ani_set_cck_noise_immunity_level( ah, ani_state->cck_noise_immunity_level - 1); } } /* convert HW counter values to ms using mode specifix clock rate */ //#define CLOCK_RATE(_ah) (ath_hal_chan_2_clock_rate_mhz(_ah) * 1000) #define CLOCK_RATE(_ah) (ath_hal_mac_clks(ah, 1000)) /* * Return an approximation of the time spent ``listening'' by * deducting the cycles spent tx'ing and rx'ing from the total * cycle count since our last call. A return value <0 indicates * an invalid/inconsistent time. */ static int32_t ar9300_ani_get_listen_time(struct ath_hal *ah, HAL_ANISTATS *ani_stats) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; u_int32_t tx_frame_count, rx_frame_count, cycle_count; + u_int32_t rx_busy_count, rx_ext_busy_count; int32_t listen_time; tx_frame_count = OS_REG_READ(ah, AR_TFCNT); rx_frame_count = OS_REG_READ(ah, AR_RFCNT); + rx_busy_count = OS_REG_READ(ah, AR_RCCNT); + rx_ext_busy_count = OS_REG_READ(ah, AR_EXTRCCNT); cycle_count = OS_REG_READ(ah, AR_CCCNT); ani_state = ahp->ah_curani; if (ani_state->cycle_count == 0 || ani_state->cycle_count > cycle_count) { /* * Cycle counter wrap (or initial call); it's not possible * to accurately calculate a value because the registers * right shift rather than wrap--so punt and return 0. */ listen_time = 0; ahp->ah_stats.ast_ani_lzero++; #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 1st call: ani_state->cycle_count=%d\n", __func__, ani_state->cycle_count); #endif } else { int32_t ccdelta = cycle_count - ani_state->cycle_count; int32_t rfdelta = rx_frame_count - ani_state->rx_frame_count; int32_t tfdelta = tx_frame_count - ani_state->tx_frame_count; + int32_t rcdelta = rx_busy_count - ani_state->rx_busy_count; + int32_t extrcdelta = rx_ext_busy_count - ani_state->rx_ext_busy_count; listen_time = (ccdelta - rfdelta - tfdelta) / CLOCK_RATE(ah); -#if HAL_ANI_DEBUG +//#if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, - "%s: cyclecount=%d, rfcount=%d, tfcount=%d, listen_time=%d " + "%s: cyclecount=%d, rfcount=%d, tfcount=%d, rcdelta=%d, extrcdelta=%d, listen_time=%d " "CLOCK_RATE=%d\n", - __func__, ccdelta, rfdelta, tfdelta, listen_time, CLOCK_RATE(ah)); -#endif + __func__, ccdelta, rfdelta, tfdelta, rcdelta, extrcdelta, + listen_time, CLOCK_RATE(ah)); +//#endif + /* Populate as appropriate */ + ani_stats->cyclecnt_diff = ccdelta; + ani_stats->rxclr_cnt = rcdelta; + ani_stats->txframecnt_diff = tfdelta; + ani_stats->rxframecnt_diff = rfdelta; + ani_stats->extrxclr_cnt = extrcdelta; + ani_stats->listen_time = listen_time; + ani_stats->valid = AH_TRUE; } ani_state->cycle_count = cycle_count; ani_state->tx_frame_count = tx_frame_count; ani_state->rx_frame_count = rx_frame_count; + ani_state->rx_busy_count = rx_busy_count; + ani_state->rx_ext_busy_count = rx_ext_busy_count; return listen_time; } /* * Do periodic processing. This routine is called from a timer */ void ar9300_ani_ar_poll(struct ath_hal *ah, const HAL_NODE_STATS *stats, const struct ieee80211_channel *chan, HAL_ANISTATS *ani_stats) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; int32_t listen_time; u_int32_t ofdm_phy_err_rate, cck_phy_err_rate; u_int32_t ofdm_phy_err_cnt, cck_phy_err_cnt; HAL_BOOL old_phy_noise_spur; ani_state = ahp->ah_curani; ahp->ah_stats.ast_nodestats = *stats; /* XXX optimize? */ if (ani_state == NULL) { /* should not happen */ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: can't poll - no ANI not initialized for this channel\n", __func__); return; } /* * ar9300_ani_ar_poll is never called while scanning but we may have been * scanning and now just restarted polling. In this case we need to * restore historical values. */ if (ani_state->must_restore) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: must restore - calling ar9300_ani_restart\n", __func__); ar9300_ani_reset(ah, AH_FALSE); return; } listen_time = ar9300_ani_get_listen_time(ah, ani_stats); if (listen_time <= 0) { ahp->ah_stats.ast_ani_lneg++; /* restart ANI period if listen_time is invalid */ HALDEBUG(ah, HAL_DEBUG_ANI, "%s: listen_time=%d - calling ar9300_ani_restart\n", __func__, listen_time); ar9300_ani_restart(ah); return; } /* XXX beware of overflow? */ ani_state->listen_time += listen_time; /* Clear the mib counters and save them in the stats */ ar9300_update_mib_mac_stats(ah); /* NB: these are not reset-on-read */ ofdm_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_1); cck_phy_err_cnt = OS_REG_READ(ah, AR_PHY_ERR_2); - + /* Populate HAL_ANISTATS */ + if (ani_stats) { + ani_stats->cckphyerr_cnt = + cck_phy_err_cnt - ani_state->cck_phy_err_count; + ani_stats->ofdmphyerrcnt_diff = + ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; + } /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ ahp->ah_stats.ast_ani_ofdmerrs += ofdm_phy_err_cnt - ani_state->ofdm_phy_err_count; ani_state->ofdm_phy_err_count = ofdm_phy_err_cnt; ahp->ah_stats.ast_ani_cckerrs += cck_phy_err_cnt - ani_state->cck_phy_err_count; ani_state->cck_phy_err_count = cck_phy_err_cnt; #if HAL_ANI_DEBUG HALDEBUG(ah, HAL_DEBUG_ANI, "%s: Errors: OFDM=0x%08x-0x0=%d CCK=0x%08x-0x0=%d\n", __func__, ofdm_phy_err_cnt, ofdm_phy_err_cnt, cck_phy_err_cnt, cck_phy_err_cnt); #endif /* * If ani is not enabled, return after we've collected * statistics */ if (!DO_ANI(ah)) { return; } ofdm_phy_err_rate = ani_state->ofdm_phy_err_count * 1000 / ani_state->listen_time; cck_phy_err_rate = ani_state->cck_phy_err_count * 1000 / ani_state->listen_time; HALDEBUG(ah, HAL_DEBUG_ANI, "%s: listen_time=%d OFDM:%d errs=%d/s CCK:%d errs=%d/s ofdm_turn=%d\n", __func__, listen_time, ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, ani_state->cck_noise_immunity_level, cck_phy_err_rate, ani_state->ofdms_turn); if (ani_state->listen_time >= HAL_NOISE_DETECT_PERIOD) { old_phy_noise_spur = ani_state->phy_noise_spur; if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && cck_phy_err_rate <= ani_state->cck_trig_low) { if (ani_state->listen_time >= HAL_NOISE_RECOVER_PERIOD) { ani_state->phy_noise_spur = 0; } } else { ani_state->phy_noise_spur = 1; } if (old_phy_noise_spur != ani_state->phy_noise_spur) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: enviroment change from %d to %d\n", __func__, old_phy_noise_spur, ani_state->phy_noise_spur); } } if (ani_state->listen_time > 5 * ahp->ah_ani_period) { /* * Check to see if need to lower immunity if * 5 ani_periods have passed */ if (ofdm_phy_err_rate <= ani_state->ofdm_trig_low && cck_phy_err_rate <= ani_state->cck_trig_low) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 1. listen_time=%d OFDM:%d errs=%d/s(<%d) " "CCK:%d errs=%d/s(<%d) -> ar9300_ani_lower_immunity\n", __func__, ani_state->listen_time, ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, ani_state->ofdm_trig_low, ani_state->cck_noise_immunity_level, cck_phy_err_rate, ani_state->cck_trig_low); ar9300_ani_lower_immunity(ah); ani_state->ofdms_turn = !ani_state->ofdms_turn; } HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 1 listen_time=%d ofdm=%d/s cck=%d/s - " "calling ar9300_ani_restart\n", __func__, ani_state->listen_time, ofdm_phy_err_rate, cck_phy_err_rate); ar9300_ani_restart(ah); } else if (ani_state->listen_time > ahp->ah_ani_period) { /* check to see if need to raise immunity */ if (ofdm_phy_err_rate > ani_state->ofdm_trig_high && (cck_phy_err_rate <= ani_state->cck_trig_high || ani_state->ofdms_turn)) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 2 listen_time=%d OFDM:%d errs=%d/s(>%d) -> " "ar9300_ani_ofdm_err_trigger\n", __func__, ani_state->listen_time, ani_state->ofdm_noise_immunity_level, ofdm_phy_err_rate, ani_state->ofdm_trig_high); ar9300_ani_ofdm_err_trigger(ah); ar9300_ani_restart(ah); ani_state->ofdms_turn = AH_FALSE; } else if (cck_phy_err_rate > ani_state->cck_trig_high) { HALDEBUG(ah, HAL_DEBUG_ANI, "%s: 3 listen_time=%d CCK:%d errs=%d/s(>%d) -> " "ar9300_ani_cck_err_trigger\n", __func__, ani_state->listen_time, ani_state->cck_noise_immunity_level, cck_phy_err_rate, ani_state->cck_trig_high); ar9300_ani_cck_err_trigger(ah); ar9300_ani_restart(ah); ani_state->ofdms_turn = AH_TRUE; } } } /* * The poll function above calculates short noise spurs, caused by non-80211 * devices, based on OFDM/CCK Phy errs. * If the noise is short enough, we don't want our ratectrl Algo to stop probing * higher rates, due to bad PER. */ HAL_BOOL ar9300_is_ani_noise_spur(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); struct ar9300_ani_state *ani_state; ani_state = ahp->ah_curani; return ani_state->phy_noise_spur; } Index: head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c =================================================================== --- head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c (revision 280828) +++ head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_freebsd.c (revision 280829) @@ -1,771 +1,786 @@ /* * Copyright (c) 2012, 2013 Adrian Chadd . * * 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 "opt_ah.h" #include "ah.h" #include "ah_internal.h" #include "ah_devid.h" #include "ah_desc.h" #include "ar9300.h" #include "ar9300reg.h" #include "ar9300phy.h" #include "ar9300desc.h" #include "ar9300_freebsd.h" #include "ar9300_stub.h" #include "ar9300_stub_funcs.h" #define FIX_NOISE_FLOOR 1 #define NEXT_TBTT_NOW 5 static HAL_BOOL ar9300ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix); static HAL_BOOL ar9300SetMulticastFilterIndex(struct ath_hal *ah, uint32_t ix); static void ar9300_beacon_set_beacon_timers(struct ath_hal *ah, const HAL_BEACON_TIMERS *bt); static void ar9300SetChainMasks(struct ath_hal *ah, uint32_t tx_chainmask, uint32_t rx_chainmask) { AH9300(ah)->ah_tx_chainmask = tx_chainmask & AH_PRIVATE(ah)->ah_caps.halTxChainMask; AH9300(ah)->ah_rx_chainmask = rx_chainmask & AH_PRIVATE(ah)->ah_caps.halRxChainMask; } static u_int ar9300GetSlotTime(struct ath_hal *ah) { u_int clks = OS_REG_READ(ah, AR_D_GBL_IFS_SLOT) & 0xffff; return (ath_hal_mac_usec(ah, clks)); /* convert from system clocks */ } static HAL_BOOL ar9300_freebsd_set_tx_power_limit(struct ath_hal *ah, uint32_t limit) { return (ar9300_set_tx_power_limit(ah, limit, 0, 0)); } static uint64_t ar9300_get_next_tbtt(struct ath_hal *ah) { return (OS_REG_READ(ah, AR_NEXT_TBTT_TIMER)); } /* * TODO: implement the antenna diversity control for AR9485 and * other LNA mixing based NICs. * * For now we'll just go with the HAL default and make these no-ops. */ static HAL_ANT_SETTING ar9300_freebsd_get_antenna_switch(struct ath_hal *ah) { return (HAL_ANT_VARIABLE); } static HAL_BOOL ar9300_freebsd_set_antenna_switch(struct ath_hal *ah, HAL_ANT_SETTING setting) { return (AH_TRUE); } static u_int ar9300_freebsd_get_cts_timeout(struct ath_hal *ah) { u_int clks = MS(OS_REG_READ(ah, AR_TIME_OUT), AR_TIME_OUT_CTS); return ath_hal_mac_usec(ah, clks); /* convert from system clocks */ } void ar9300_attach_freebsd_ops(struct ath_hal *ah) { /* Global functions */ ah->ah_detach = ar9300_detach; ah->ah_getRateTable = ar9300_get_rate_table; /* Reset functions */ ah->ah_reset = ar9300_reset_freebsd; ah->ah_phyDisable = ar9300_phy_disable; ah->ah_disable = ar9300_disable; ah->ah_configPCIE = ar9300_config_pcie_freebsd; // ah->ah_disablePCIE = ar9300_disable_pcie_phy; ah->ah_setPCUConfig = ar9300_set_pcu_config; // perCalibration ah->ah_perCalibrationN = ar9300_per_calibration_freebsd; ah->ah_resetCalValid = ar9300_reset_cal_valid_freebsd; ah->ah_setTxPowerLimit = ar9300_freebsd_set_tx_power_limit; ah->ah_getChanNoise = ath_hal_getChanNoise; /* Transmit functions */ ah->ah_setupTxQueue = ar9300_setup_tx_queue; ah->ah_setTxQueueProps = ar9300_set_tx_queue_props; ah->ah_getTxQueueProps = ar9300_get_tx_queue_props; ah->ah_releaseTxQueue = ar9300_release_tx_queue; ah->ah_resetTxQueue = ar9300_reset_tx_queue; ah->ah_getTxDP = ar9300_get_tx_dp; ah->ah_setTxDP = ar9300_set_tx_dp; ah->ah_numTxPending = ar9300_num_tx_pending; ah->ah_startTxDma = ar9300_start_tx_dma; ah->ah_stopTxDma = ar9300_stop_tx_dma_freebsd; ah->ah_setupTxDesc = ar9300_freebsd_setup_tx_desc; ah->ah_setupXTxDesc = ar9300_freebsd_setup_x_tx_desc; ah->ah_fillTxDesc = ar9300_freebsd_fill_tx_desc; ah->ah_procTxDesc = ar9300_freebsd_proc_tx_desc; ah->ah_getTxIntrQueue = ar9300_get_tx_intr_queue; // reqTxIntrDesc ah->ah_getTxCompletionRates = ar9300_freebsd_get_tx_completion_rates; ah->ah_setTxDescLink = ar9300_set_desc_link; ah->ah_getTxDescLink = ar9300_freebsd_get_desc_link; ah->ah_getTxDescLinkPtr = ar9300_get_desc_link_ptr; ah->ah_setupTxStatusRing = ar9300_setup_tx_status_ring; ah->ah_getTxRawTxDesc = ar9300_get_raw_tx_desc; ah->ah_updateTxTrigLevel = ar9300_update_tx_trig_level; /* RX functions */ ah->ah_getRxDP = ar9300_get_rx_dp; ah->ah_setRxDP = ar9300_set_rx_dp; ah->ah_enableReceive = ar9300_enable_receive; ah->ah_stopDmaReceive = ar9300_stop_dma_receive_freebsd; ah->ah_startPcuReceive = ar9300_start_pcu_receive_freebsd; ah->ah_stopPcuReceive = ar9300_stop_pcu_receive; ah->ah_setMulticastFilter = ar9300_set_multicast_filter; ah->ah_setMulticastFilterIndex = ar9300SetMulticastFilterIndex; ah->ah_clrMulticastFilterIndex = ar9300ClrMulticastFilterIndex; ah->ah_getRxFilter = ar9300_get_rx_filter; ah->ah_setRxFilter = ar9300_set_rx_filter; /* setupRxDesc */ ah->ah_procRxDesc = ar9300_proc_rx_desc_freebsd; ah->ah_rxMonitor = ar9300_ani_rxmonitor_freebsd; ah->ah_aniPoll = ar9300_ani_poll_freebsd; ah->ah_procMibEvent = ar9300_process_mib_intr; /* Misc functions */ ah->ah_getCapability = ar9300_get_capability; ah->ah_setCapability = ar9300_set_capability; ah->ah_getDiagState = ar9300_get_diag_state; ah->ah_getMacAddress = ar9300_get_mac_address; ah->ah_setMacAddress = ar9300_set_mac_address; ah->ah_getBssIdMask = ar9300_get_bss_id_mask; ah->ah_setBssIdMask = ar9300_set_bss_id_mask; ah->ah_setRegulatoryDomain = ar9300_set_regulatory_domain; ah->ah_setLedState = ar9300_set_led_state; ah->ah_writeAssocid = ar9300_write_associd; ah->ah_gpioCfgInput = ar9300_gpio_cfg_input; ah->ah_gpioCfgOutput = ar9300_gpio_cfg_output; ah->ah_gpioGet = ar9300_gpio_get; ah->ah_gpioSet = ar9300_gpio_set; ah->ah_gpioSetIntr = ar9300_gpio_set_intr; /* polarity */ /* mask */ ah->ah_getTsf32 = ar9300_get_tsf32; ah->ah_getTsf64 = ar9300_get_tsf64; ah->ah_resetTsf = ar9300_reset_tsf; ah->ah_detectCardPresent = ar9300_detect_card_present; // ah->ah_updateMibCounters = ar9300_update_mib_counters; ah->ah_getRfGain = ar9300_get_rfgain; ah->ah_getDefAntenna = ar9300_get_def_antenna; ah->ah_setDefAntenna = ar9300_set_def_antenna; ah->ah_getAntennaSwitch = ar9300_freebsd_get_antenna_switch; ah->ah_setAntennaSwitch = ar9300_freebsd_set_antenna_switch; // ah->ah_setSifsTime = ar9300_set_sifs_time; // ah->ah_getSifsTime = ar9300_get_sifs_time; ah->ah_setSlotTime = ar9300_set_slot_time; ah->ah_getSlotTime = ar9300GetSlotTime; ah->ah_getAckTimeout = ar9300_get_ack_timeout; ah->ah_setAckTimeout = ar9300_set_ack_timeout; // XXX ack/ctsrate // XXX CTS timeout ah->ah_getCTSTimeout = ar9300_freebsd_get_cts_timeout; // XXX decompmask // coverageclass ah->ah_setQuiet = ar9300_set_quiet; ah->ah_getMibCycleCounts = ar9300_freebsd_get_mib_cycle_counts; /* DFS functions */ ah->ah_enableDfs = ar9300_enable_dfs; ah->ah_getDfsThresh = ar9300_get_dfs_thresh; ah->ah_getDfsDefaultThresh = ar9300_freebsd_get_dfs_default_thresh; // procradarevent ah->ah_isFastClockEnabled = ar9300_is_fast_clock_enabled; ah->ah_get11nExtBusy = ar9300_get_11n_ext_busy; /* Key cache functions */ ah->ah_getKeyCacheSize = ar9300_get_key_cache_size; ah->ah_resetKeyCacheEntry = ar9300_reset_key_cache_entry; ah->ah_isKeyCacheEntryValid = ar9300_is_key_cache_entry_valid; ah->ah_setKeyCacheEntry = ar9300_set_key_cache_entry; ah->ah_setKeyCacheEntryMac = ar9300_set_key_cache_entry_mac; /* Power management functions */ ah->ah_setPowerMode = ar9300_set_power_mode; ah->ah_getPowerMode = ar9300_get_power_mode; /* Beacon functions */ /* ah_setBeaconTimers */ ah->ah_beaconInit = ar9300_freebsd_beacon_init; ah->ah_setBeaconTimers = ar9300_beacon_set_beacon_timers; ah->ah_setStationBeaconTimers = ar9300_set_sta_beacon_timers; /* ah_resetStationBeaconTimers */ ah->ah_getNextTBTT = ar9300_get_next_tbtt; /* Interrupt functions */ ah->ah_isInterruptPending = ar9300_is_interrupt_pending; ah->ah_getPendingInterrupts = ar9300_get_pending_interrupts_freebsd; ah->ah_getInterrupts = ar9300_get_interrupts; ah->ah_setInterrupts = ar9300_set_interrupts_freebsd; /* Regulatory/internal functions */ // AH_PRIVATE(ah)->ah_getNfAdjust = ar9300_get_nf_adjust; AH_PRIVATE(ah)->ah_eepromRead = ar9300_eeprom_read_word; // AH_PRIVATE(ah)->ah_getChipPowerLimits = ar9300_get_chip_power_limits; AH_PRIVATE(ah)->ah_getWirelessModes = ar9300_get_wireless_modes; AH_PRIVATE(ah)->ah_getChannelEdges = ar9300_get_channel_edges; AH_PRIVATE(ah)->ah_eepromRead = ar9300_eeprom_read_word; /* XXX ah_eeprom */ /* XXX ah_eeversion */ /* XXX ah_eepromDetach */ /* XXX ah_eepromGet */ AH_PRIVATE(ah)->ah_eepromGet = ar9300_eeprom_get_freebsd; /* XXX ah_eepromSet */ /* XXX ah_getSpurChan */ /* XXX ah_eepromDiag */ /* 802.11n functions */ ah->ah_chainTxDesc = ar9300_freebsd_chain_tx_desc; ah->ah_setupFirstTxDesc= ar9300_freebsd_setup_first_tx_desc; ah->ah_setupLastTxDesc = ar9300_freebsd_setup_last_tx_desc; ah->ah_set11nRateScenario = ar9300_freebsd_set_11n_rate_scenario; ah->ah_set11nTxDesc = ar9300_freebsd_setup_11n_desc; ah->ah_set11nAggrFirst = ar9300_set_11n_aggr_first; ah->ah_set11nAggrMiddle = ar9300_set_11n_aggr_middle; ah->ah_set11nAggrLast = ar9300_set_11n_aggr_last; ah->ah_clr11nAggr = ar9300_clr_11n_aggr; ah->ah_set11nBurstDuration = ar9300_set_11n_burst_duration; /* ah_get11nExtBusy */ ah->ah_set11nMac2040 = ar9300_set_11n_mac2040; ah->ah_setChainMasks = ar9300SetChainMasks; /* ah_get11nRxClear */ /* ah_set11nRxClear */ /* bluetooth coexistence functions */ ah->ah_btCoexSetInfo = ar9300_set_bt_coex_info; ah->ah_btCoexSetConfig = ar9300_bt_coex_config; ah->ah_btCoexSetQcuThresh = ar9300_bt_coex_set_qcu_thresh; ah->ah_btCoexSetWeights = ar9300_bt_coex_set_weights; ah->ah_btCoexSetBmissThresh = ar9300_bt_coex_setup_bmiss_thresh; ah->ah_btCoexSetParameter = ar9300_bt_coex_set_parameter; ah->ah_btCoexDisable = ar9300_bt_coex_disable; ah->ah_btCoexEnable = ar9300_bt_coex_enable; /* MCI bluetooth functions */ if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { ah->ah_btCoexSetWeights = ar9300_mci_bt_coex_set_weights; ah->ah_btCoexDisable = ar9300_mci_bt_coex_disable; ah->ah_btCoexEnable = ar9300_mci_bt_coex_enable; } ah->ah_btMciSetup = ar9300_mci_setup; ah->ah_btMciSendMessage = ar9300_mci_send_message; ah->ah_btMciGetInterrupt = ar9300_mci_get_interrupt; ah->ah_btMciGetState = ar9300_mci_state; ah->ah_btMciDetach = ar9300_mci_detach; /* LNA diversity functions */ ah->ah_divLnaConfGet = ar9300_ant_div_comb_get_config; ah->ah_divLnaConfSet = ar9300_ant_div_comb_set_config; } HAL_BOOL ar9300_reset_freebsd(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_BOOL bChannelChange, HAL_STATUS *status) { HAL_BOOL r; HAL_HT_MACMODE macmode; struct ath_hal_private *ap = AH_PRIVATE(ah); macmode = IEEE80211_IS_CHAN_HT40(chan) ? HAL_HT_MACMODE_2040 : HAL_HT_MACMODE_20; r = ar9300_reset(ah, opmode, chan, macmode, ap->ah_caps.halTxChainMask, ap->ah_caps.halRxChainMask, HAL_HT_EXTPROTSPACING_20, /* always 20Mhz channel spacing */ bChannelChange, status, AH_FALSE); /* XXX should really extend ath_hal_reset() */ return (r); } void ar9300_config_pcie_freebsd(struct ath_hal *ah, HAL_BOOL restore, HAL_BOOL powerOff) { ar9300_config_pci_power_save(ah, restore ? 1 : 0, powerOff ? 1 : 0); } /* * This is a copy from ar9300_eeprom_get(), purely because the FreeBSD * API is very silly and inconsistent. * * The AR93xx HAL doesn't call the eepromGetFlag() function, so this * only occurs for FreeBSD code. * * When I fix this particular API, I'll undo this. */ HAL_STATUS ar9300_eeprom_get_freebsd(struct ath_hal *ah, int param, void *val) { switch (param) { case AR_EEP_FSTCLK_5G: return HAL_OK; default: ath_hal_printf(ah, "%s: called, param=%d\n", __func__, param); return HAL_EIO; } } HAL_BOOL ar9300_stop_tx_dma_freebsd(struct ath_hal *ah, u_int q) { return ar9300_stop_tx_dma(ah, q, 1000); } void ar9300_ani_poll_freebsd(struct ath_hal *ah, const struct ieee80211_channel *chan) { HAL_NODE_STATS stats; HAL_ANISTATS anistats; + HAL_SURVEY_SAMPLE survey; OS_MEMZERO(&stats, sizeof(stats)); OS_MEMZERO(&anistats, sizeof(anistats)); + OS_MEMZERO(&survey, sizeof(survey)); ar9300_ani_ar_poll(ah, &stats, chan, &anistats); + + /* + * If ANI stats are valid, use them to update the + * channel survey. + */ + if (anistats.valid) { + survey.cycle_count = anistats.cyclecnt_diff; + survey.chan_busy = anistats.rxclr_cnt; + survey.ext_chan_busy = anistats.extrxclr_cnt; + survey.tx_busy = anistats.txframecnt_diff; + survey.rx_busy = anistats.rxframecnt_diff; + ath_hal_survey_add_sample(ah, &survey); + } } /* * Setup the configuration parameters in the style the AR9300 HAL * wants. */ void ar9300_config_defaults_freebsd(struct ath_hal *ah, HAL_OPS_CONFIG *ah_config) { /* Until FreeBSD's HAL does this by default - just copy */ OS_MEMCPY(&ah->ah_config, ah_config, sizeof(HAL_OPS_CONFIG)); ah->ah_config.ath_hal_enable_ani = AH_TRUE; } HAL_BOOL ar9300_stop_dma_receive_freebsd(struct ath_hal *ah) { return ar9300_stop_dma_receive(ah, 1000); } HAL_BOOL ar9300_get_pending_interrupts_freebsd(struct ath_hal *ah, HAL_INT *masked) { /* Non-MSI, so no MSI vector; and 'nortc' = 0 */ return ar9300_get_pending_interrupts(ah, masked, HAL_INT_LINE, 0, 0); } HAL_INT ar9300_set_interrupts_freebsd(struct ath_hal *ah, HAL_INT ints) { /* nortc = 0 */ return ar9300_set_interrupts(ah, ints, 0); } HAL_BOOL ar9300_per_calibration_freebsd(struct ath_hal *ah, struct ieee80211_channel *chan, u_int rxchainmask, HAL_BOOL long_cal, HAL_BOOL *isCalDone) { /* XXX fake scheduled calibrations for now */ u_int32_t sched_cals = 0xfffffff; return ar9300_calibration(ah, chan, AH_PRIVATE(ah)->ah_caps.halRxChainMask, long_cal, isCalDone, 0, /* is_scan */ &sched_cals); } HAL_BOOL ar9300_reset_cal_valid_freebsd(struct ath_hal *ah, const struct ieee80211_channel *chan) { HAL_BOOL is_cal_done = AH_TRUE; ar9300_reset_cal_valid(ah, chan, &is_cal_done, 0xffffffff); return (is_cal_done); } void ar9300_start_pcu_receive_freebsd(struct ath_hal *ah) { /* is_scanning flag == NULL */ ar9300_start_pcu_receive(ah, AH_FALSE); } /* * FreeBSD will just pass in the descriptor value as 'pa'. * The Atheros HAL treats 'pa' as the physical address of the RX * descriptor and 'bufaddr' as the physical address of the RX buffer. * I'm not sure why they didn't collapse them - the AR9300 RX descriptor * routine doesn't check 'pa'. */ HAL_STATUS ar9300_proc_rx_desc_freebsd(struct ath_hal *ah, struct ath_desc *ds, uint32_t pa, struct ath_desc *ds_next, uint64_t tsf, struct ath_rx_status *rxs) { return (ar9300_proc_rx_desc_fast(ah, ds, 0, ds_next, rxs, (void *) ds)); } void ar9300_ani_rxmonitor_freebsd(struct ath_hal *ah, const HAL_NODE_STATS *stats, const struct ieee80211_channel *chan) { } void ar9300_freebsd_get_desc_link(struct ath_hal *ah, void *ds, uint32_t *link) { struct ar9300_txc *ads = AR9300TXC(ds); (*link) = ads->ds_link; } /* * TX descriptor field setting wrappers - eek. */ HAL_BOOL ar9300_freebsd_setup_tx_desc(struct ath_hal *ah, struct ath_desc *ds, u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int txPower, u_int txRate0, u_int txTries0, u_int keyIx, u_int antMode, u_int flags, u_int rtsctsRate, u_int rtsCtsDuration, u_int compicvLen, u_int compivLen, u_int comp) { struct ath_hal_9300 *ahp = AH9300(ah); HAL_KEY_TYPE keyType = 0; /* XXX No padding */ if (keyIx != HAL_TXKEYIX_INVALID) keyType = ahp->ah_keytype[keyIx]; /* XXX bounds check keyix */ ar9300_set_11n_tx_desc(ah, ds, pktLen, type, txPower, keyIx, keyType, flags); return AH_TRUE; } HAL_BOOL ar9300_freebsd_setup_x_tx_desc(struct ath_hal *ah, struct ath_desc *ds, u_int txRate1, u_int txTries1, u_int txRate2, u_int txTries2, u_int txRate3, u_int txTries3) { #if 0 ath_hal_printf(ah, "%s: called, 0x%x/%d, 0x%x/%d, 0x%x/%d\n", __func__, txRate1, txTries1, txRate2, txTries2, txRate3, txTries3); #endif /* XXX should only be called during probe */ return (AH_TRUE); } HAL_BOOL ar9300_freebsd_fill_tx_desc(struct ath_hal *ah, struct ath_desc *ds, HAL_DMA_ADDR *bufListPtr, uint32_t *segLenPtr, u_int descId, u_int qid, HAL_BOOL firstSeg, HAL_BOOL lastSeg, const struct ath_desc *ds0) { HAL_KEY_TYPE keyType = 0; const struct ar9300_txc *ads = AR9300TXC_CONST(ds0); /* * FreeBSD's HAL doesn't pass the keytype to fill_tx_desc(); * it's copied as part of the descriptor chaining. * * So, extract it from ds0. */ keyType = MS(ads->ds_ctl17, AR_encr_type); return ar9300_fill_tx_desc(ah, ds, bufListPtr, segLenPtr, descId, qid, keyType, firstSeg, lastSeg, ds0); } HAL_BOOL ar9300_freebsd_get_tx_completion_rates(struct ath_hal *ah, const struct ath_desc *ds0, int *rates, int *tries) { ath_hal_printf(ah, "%s: called\n", __func__); return AH_FALSE; /* XXX for now */ } /* * 802.11n TX descriptor wrappers */ void ar9300_freebsd_set_11n_rate_scenario(struct ath_hal *ah, struct ath_desc *ds, u_int durUpdateEn, u_int rtsctsRate, HAL_11N_RATE_SERIES series[], u_int nseries, u_int flags) { /* lastds=NULL, rtscts_duration is 0, smart antenna is 0 */ ar9300_set_11n_rate_scenario(ah, (void *) ds, (void *)ds, durUpdateEn, rtsctsRate, 0, series, nseries, flags, 0); } /* chaintxdesc */ HAL_BOOL ar9300_freebsd_chain_tx_desc(struct ath_hal *ah, struct ath_desc *ds, HAL_DMA_ADDR *bufLenList, uint32_t *segLenList, u_int pktLen, u_int hdrLen, HAL_PKT_TYPE type, u_int keyIx, HAL_CIPHER cipher, uint8_t numDelims, HAL_BOOL firstSeg, HAL_BOOL lastSeg, HAL_BOOL lastAggr) { ath_hal_printf(ah, "%s: called\n", __func__); return AH_FALSE; } /* setupfirsttxdesc */ HAL_BOOL ar9300_freebsd_setup_first_tx_desc(struct ath_hal *ah, struct ath_desc *ds, u_int aggrLen, u_int flags, u_int txPower, u_int txRate0, u_int txTries0, u_int antMode, u_int rtsctsRate, u_int rtsctsDuration) { ath_hal_printf(ah, "%s: called\n", __func__); return AH_FALSE; } /* setuplasttxdesc */ /* * This gets called but for now let's not log anything; * it's only used to update the rate control information. */ HAL_BOOL ar9300_freebsd_setup_last_tx_desc(struct ath_hal *ah, struct ath_desc *ds, const struct ath_desc *ds0) { // ath_hal_printf(ah, "%s: called\n", __func__); return AH_FALSE; } void ar9300_freebsd_setup_11n_desc(struct ath_hal *ah, void *ds, u_int pktLen, HAL_PKT_TYPE type, u_int txPower, u_int keyIx, u_int flags) { ath_hal_printf(ah, "%s: called\n", __func__); #if 0 struct ath_hal_9300 *ahp = AH9300(ah); HAL_KEY_TYPE keyType = 0; /* XXX No padding */ if (keyIx != HAL_TXKEYIX_INVALID) keyType = ahp->ah_keytype[keyIx]; /* XXX bounds check keyix */ ar9300_set_11n_tx_desc(ah, ds, pktLen, type, txPower, keyIx, keyType, flags); #endif } HAL_STATUS ar9300_freebsd_proc_tx_desc(struct ath_hal *ah, struct ath_desc *ds, struct ath_tx_status *ts) { return ar9300_proc_tx_desc(ah, ts); } void ar9300_freebsd_beacon_init(struct ath_hal *ah, uint32_t next_beacon, uint32_t beacon_period) { ar9300_beacon_init(ah, next_beacon, beacon_period, 0, AH_PRIVATE(ah)->ah_opmode); } HAL_BOOL ar9300_freebsd_get_mib_cycle_counts(struct ath_hal *ah, HAL_SURVEY_SAMPLE *hs) { return (AH_FALSE); } HAL_BOOL ar9300_freebsd_get_dfs_default_thresh(struct ath_hal *ah, HAL_PHYERR_PARAM *pe) { /* XXX not yet */ return (AH_FALSE); } /* * Clear multicast filter by index - from FreeBSD ar5212_recv.c */ static HAL_BOOL ar9300ClrMulticastFilterIndex(struct ath_hal *ah, uint32_t ix) { uint32_t val; if (ix >= 64) return (AH_FALSE); if (ix >= 32) { val = OS_REG_READ(ah, AR_MCAST_FIL1); OS_REG_WRITE(ah, AR_MCAST_FIL1, (val &~ (1<<(ix-32)))); } else { val = OS_REG_READ(ah, AR_MCAST_FIL0); OS_REG_WRITE(ah, AR_MCAST_FIL0, (val &~ (1<= 64) return (AH_FALSE); if (ix >= 32) { val = OS_REG_READ(ah, AR_MCAST_FIL1); OS_REG_WRITE(ah, AR_MCAST_FIL1, (val | (1<<(ix-32)))); } else { val = OS_REG_READ(ah, AR_MCAST_FIL0); OS_REG_WRITE(ah, AR_MCAST_FIL0, (val | (1<bt_nexttbtt)); OS_REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextdba)); OS_REG_WRITE(ah, AR_NEXT_SWBA, ONE_EIGHTH_TU_TO_USEC(bt->bt_nextswba)); OS_REG_WRITE(ah, AR_NEXT_NDP_TIMER, TU_TO_USEC(bt->bt_nextatim)); bperiod = TU_TO_USEC(bt->bt_intval & HAL_BEACON_PERIOD); /* XXX TODO! */ // ahp->ah_beaconInterval = bt->bt_intval & HAL_BEACON_PERIOD; OS_REG_WRITE(ah, AR_BEACON_PERIOD, bperiod); OS_REG_WRITE(ah, AR_DMA_BEACON_PERIOD, bperiod); OS_REG_WRITE(ah, AR_SWBA_PERIOD, bperiod); OS_REG_WRITE(ah, AR_NDP_PERIOD, bperiod); /* * Reset TSF if required. */ if (bt->bt_intval & HAL_BEACON_RESET_TSF) ar9300_reset_tsf(ah); /* enable timers */ /* NB: flags == 0 handled specially for backwards compatibility */ OS_REG_SET_BIT(ah, AR_TIMER_MODE, bt->bt_flags != 0 ? bt->bt_flags : AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN); } /* * RF attach stubs */ static HAL_BOOL rf9330_attach(struct ath_hal *ah, HAL_STATUS *status) { (*status) = HAL_EINVAL; return (AH_FALSE); } static HAL_BOOL rf9330_probe(struct ath_hal *ah) { return (AH_FALSE); } AH_RF(RF9330, rf9330_probe, rf9330_attach); Index: head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c =================================================================== --- head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c (revision 280828) +++ head/sys/contrib/dev/ath/ath_hal/ar9300/ar9300_reset.c (revision 280829) @@ -1,6404 +1,6409 @@ /* * Copyright (c) 2013 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "opt_ah.h" #include "ah.h" #include "ah_internal.h" #include "ah_devid.h" #include "ah_desc.h" #include "ar9300.h" #include "ar9300reg.h" #include "ar9300phy.h" #include "ar9300desc.h" #define FIX_NOISE_FLOOR 1 /* Additional Time delay to wait after activiting the Base band */ #define BASE_ACTIVATE_DELAY 100 /* usec */ #define RTC_PLL_SETTLE_DELAY 100 /* usec */ #define COEF_SCALE_S 24 #define HT40_CHANNEL_CENTER_SHIFT 10 /* MHz */ #define DELPT 32 /* XXX Duplicates! (in ar9300desc.h) */ #if 0 extern HAL_BOOL ar9300_reset_tx_queue(struct ath_hal *ah, u_int q); extern u_int32_t ar9300_num_tx_pending(struct ath_hal *ah, u_int q); #endif #define MAX_MEASUREMENT 8 #define MAXIQCAL 3 struct coeff_t { int32_t mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; int32_t phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MAXIQCAL]; int32_t iqc_coeff[2]; int last_nmeasurement; HAL_BOOL last_cal; }; static HAL_BOOL ar9300_tx_iq_cal_hw_run(struct ath_hal *ah); static void ar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, int iqcal_idx, int max_iqcal, HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr); static void ar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, u_int32_t num_chains, struct coeff_t *coeff, HAL_BOOL is_cal_reusable); #if ATH_SUPPORT_CAL_REUSE static void ar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan); #endif static inline void ar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, int column); static inline void ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan); static inline HAL_BOOL ar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_corr); static inline void ar9300_init_user_settings(struct ath_hal *ah); #ifdef HOST_OFFLOAD /* * For usb offload solution, some USB registers must be tuned * to gain better stability/performance but these registers * might be changed while doing wlan reset so do this here */ #define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah) \ do { \ if (AR_SREV_HORNET(__ah) || AR_SREV_WASP(__ah)) { \ volatile u_int32_t *usb_ctrl_r1 = (u_int32_t *) 0xb8116c84; \ volatile u_int32_t *usb_ctrl_r2 = (u_int32_t *) 0xb8116c88; \ *usb_ctrl_r1 = (*usb_ctrl_r1 & 0xffefffff); \ *usb_ctrl_r2 = (*usb_ctrl_r2 & 0xfc1fffff) | (1 << 21) | (3 << 22); \ } \ } while (0) #else #define WAR_USB_DISABLE_PLL_LOCK_DETECT(__ah) #endif static inline void ar9300_attach_hw_platform(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); ahp->ah_hwp = HAL_TRUE_CHIP; return; } /* Adjust various register settings based on half/quarter rate clock setting. * This includes: +USEC, TX/RX latency, * + IFS params: slot, eifs, misc etc. * SIFS stays the same. */ static void ar9300_set_ifs_timing(struct ath_hal *ah, struct ieee80211_channel *chan) { u_int32_t tx_lat, rx_lat, usec, slot, regval, eifs; regval = OS_REG_READ(ah, AR_USEC); regval &= ~(AR_USEC_RX_LATENCY | AR_USEC_TX_LATENCY | AR_USEC_USEC); if (IEEE80211_IS_CHAN_HALF(chan)) { /* half rates */ slot = ar9300_mac_to_clks(ah, AR_SLOT_HALF); eifs = ar9300_mac_to_clks(ah, AR_EIFS_HALF); if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */ rx_lat = SM(AR_RX_LATENCY_HALF_FAST_CLOCK, AR_USEC_RX_LATENCY); tx_lat = SM(AR_TX_LATENCY_HALF_FAST_CLOCK, AR_USEC_TX_LATENCY); usec = SM(AR_USEC_HALF_FAST_CLOCK, AR_USEC_USEC); } else { rx_lat = SM(AR_RX_LATENCY_HALF, AR_USEC_RX_LATENCY); tx_lat = SM(AR_TX_LATENCY_HALF, AR_USEC_TX_LATENCY); usec = SM(AR_USEC_HALF, AR_USEC_USEC); } } else { /* quarter rate */ slot = ar9300_mac_to_clks(ah, AR_SLOT_QUARTER); eifs = ar9300_mac_to_clks(ah, AR_EIFS_QUARTER); if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { /* fast clock */ rx_lat = SM(AR_RX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_RX_LATENCY); tx_lat = SM(AR_TX_LATENCY_QUARTER_FAST_CLOCK, AR_USEC_TX_LATENCY); usec = SM(AR_USEC_QUARTER_FAST_CLOCK, AR_USEC_USEC); } else { rx_lat = SM(AR_RX_LATENCY_QUARTER, AR_USEC_RX_LATENCY); tx_lat = SM(AR_TX_LATENCY_QUARTER, AR_USEC_TX_LATENCY); usec = SM(AR_USEC_QUARTER, AR_USEC_USEC); } } OS_REG_WRITE(ah, AR_USEC, (usec | regval | tx_lat | rx_lat)); OS_REG_WRITE(ah, AR_D_GBL_IFS_SLOT, slot); OS_REG_WRITE(ah, AR_D_GBL_IFS_EIFS, eifs); } /* * This inline function configures the chip either * to encrypt/decrypt management frames or pass thru */ static inline void ar9300_init_mfp(struct ath_hal * ah) { u_int32_t mfpcap, mfp_qos; ath_hal_getcapability(ah, HAL_CAP_MFP, 0, &mfpcap); if (mfpcap == HAL_MFP_QOSDATA) { /* Treat like legacy hardware. Do not touch the MFP registers. */ HALDEBUG(ah, HAL_DEBUG_RESET, "%s forced to use QOSDATA\n", __func__); return; } /* MFP support (Sowl 1.0 or greater) */ if (mfpcap == HAL_MFP_HW_CRYPTO) { /* configure hardware MFP support */ HALDEBUG(ah, HAL_DEBUG_RESET, "%s using HW crypto\n", __func__); OS_REG_RMW_FIELD(ah, AR_AES_MUTE_MASK1, AR_AES_MUTE_MASK1_FC_MGMT, AR_AES_MUTE_MASK1_FC_MGMT_MFP); OS_REG_RMW(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE, AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT); /* * Mask used to construct AAD for CCMP-AES * Cisco spec defined bits 0-3 as mask * IEEE802.11w defined as bit 4. */ if (ath_hal_get_mfp_qos(ah)) { mfp_qos = AR_MFP_QOS_MASK_IEEE; } else { mfp_qos = AR_MFP_QOS_MASK_CISCO; } OS_REG_RMW_FIELD(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_MGMT_QOS, mfp_qos); } else if (mfpcap == HAL_MFP_PASSTHRU) { /* Disable en/decrypt by hardware */ HALDEBUG(ah, HAL_DEBUG_RESET, "%s using passthru\n", __func__); OS_REG_RMW(ah, AR_PCU_MISC_MODE2, AR_PCU_MISC_MODE2_NO_CRYPTO_FOR_NON_DATA_PKT, AR_PCU_MISC_MODE2_MGMT_CRYPTO_ENABLE); } } void ar9300_get_channel_centers(struct ath_hal *ah, const struct ieee80211_channel *chan, CHAN_CENTERS *centers) { int8_t extoff; struct ath_hal_9300 *ahp = AH9300(ah); HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); if (!IEEE80211_IS_CHAN_HT40(chan)) { centers->ctl_center = centers->ext_center = centers->synth_center = ichan->channel; return; } HALASSERT(IEEE80211_IS_CHAN_HT40(chan)); /* * In 20/40 phy mode, the center frequency is * "between" the primary and extension channels. */ if (IEEE80211_IS_CHAN_HT40U(chan)) { centers->synth_center = ichan->channel + HT40_CHANNEL_CENTER_SHIFT; extoff = 1; } else { centers->synth_center = ichan->channel - HT40_CHANNEL_CENTER_SHIFT; extoff = -1; } centers->ctl_center = centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); centers->ext_center = centers->synth_center + (extoff * ((ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_20) ? HT40_CHANNEL_CENTER_SHIFT : 15)); } /* * Read the noise-floor values from the HW. * Specifically, read the minimum clear-channel assessment value for * each chain, for both the control and extension channels. * (The received power level during clear-channel periods is the * noise floor.) * These noise floor values computed by the HW will be stored in the * NF history buffer. * The HW sometimes produces bogus NF values. To avoid using these * bogus values, the NF data is (a) range-limited, and (b) filtered. * However, this data-processing is done when reading the NF values * out of the history buffer. The history buffer stores the raw values. * This allows the NF history buffer to be used to check for interference. * A single high NF reading might be a bogus HW value, but if the NF * readings are consistently high, it must be due to interference. * This is the purpose of storing raw NF values in the history buffer, * rather than processed values. By looking at a history of NF values * that have not been range-limited, we can check if they are consistently * high (due to interference). */ #define AH_NF_SIGN_EXTEND(nf) \ ((nf) & 0x100) ? \ 0 - (((nf) ^ 0x1ff) + 1) : \ (nf) void ar9300_upload_noise_floor(struct ath_hal *ah, int is_2g, int16_t nfarray[HAL_NUM_NF_READINGS]) { int16_t nf; int chan, chain; u_int32_t regs[HAL_NUM_NF_READINGS] = { /* control channel */ AR_PHY_CCA_0, /* chain 0 */ AR_PHY_CCA_1, /* chain 1 */ AR_PHY_CCA_2, /* chain 2 */ /* extension channel */ AR_PHY_EXT_CCA, /* chain 0 */ AR_PHY_EXT_CCA_1, /* chain 1 */ AR_PHY_EXT_CCA_2, /* chain 2 */ }; u_int8_t chainmask; /* * Within a given channel (ctl vs. ext), the CH0, CH1, and CH2 * masks and shifts are the same, though they differ for the * control vs. extension channels. */ u_int32_t masks[2] = { AR_PHY_MINCCA_PWR, /* control channel */ AR_PHY_EXT_MINCCA_PWR, /* extention channel */ }; u_int8_t shifts[2] = { AR_PHY_MINCCA_PWR_S, /* control channel */ AR_PHY_EXT_MINCCA_PWR_S, /* extention channel */ }; /* * Force NF calibration for all chains. */ if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { chainmask = 0x01; } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { chainmask = 0x03; } else { chainmask = 0x07; } for (chan = 0; chan < 2 /*ctl,ext*/; chan++) { for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { int i; if (!((chainmask >> chain) & 0x1)) { continue; } i = chan * AR9300_MAX_CHAINS + chain; nf = (OS_REG_READ(ah, regs[i]) & masks[chan]) >> shifts[chan]; nfarray[i] = AH_NF_SIGN_EXTEND(nf); } } } /* ar9300_get_min_cca_pwr - * Used by the scan function for a quick read of the noise floor. * This is used to detect presence of CW interference such as video bridge. * The noise floor is assumed to have been already started during reset * called during channel change. The function checks if the noise floor * reading is done. In case it has been done, it reads the noise floor value. * If the noise floor calibration has not been finished, it assumes this is * due to presence of CW interference an returns a high value for noise floor, * derived from the CW interference threshold + margin fudge factor. */ #define BAD_SCAN_NF_MARGIN (30) int16_t ar9300_get_min_cca_pwr(struct ath_hal *ah) { int16_t nf; // struct ath_hal_private *ahpriv = AH_PRIVATE(ah); if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0) { nf = MS(OS_REG_READ(ah, AR_PHY_CCA_0), AR9280_PHY_MINCCA_PWR); if (nf & 0x100) { nf = 0 - ((nf ^ 0x1ff) + 1); } } else { /* NF calibration is not done, assume CW interference */ nf = AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta + BAD_SCAN_NF_MARGIN; } return nf; } /* * Noise Floor values for all chains. * Most recently updated values from the NF history buffer are used. */ void ar9300_chain_noise_floor(struct ath_hal *ah, int16_t *nf_buf, struct ieee80211_channel *chan, int is_scan) { struct ath_hal_9300 *ahp = AH9300(ah); int i, nf_hist_len, recent_nf_index = 0; HAL_NFCAL_HIST_FULL *h; u_int8_t rx_chainmask = ahp->ah_rx_chainmask | (ahp->ah_rx_chainmask << 3); HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); HALASSERT(ichan); #ifdef ATH_NF_PER_CHAN /* Fill 0 if valid internal channel is not found */ if (ichan == AH_NULL) { OS_MEMZERO(nf_buf, sizeof(nf_buf[0])*HAL_NUM_NF_READINGS); return; } h = &ichan->nf_cal_hist; nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; #else /* * If a scan is not in progress, then the most recent value goes * into ahpriv->nf_cal_hist. If a scan is in progress, then * the most recent value goes into ichan->nf_cal_hist. * Thus, return the value from ahpriv->nf_cal_hist if there's * no scan, and if the specified channel is the current channel. * Otherwise, return the noise floor from ichan->nf_cal_hist. */ if ((!is_scan) && chan == AH_PRIVATE(ah)->ah_curchan) { h = &AH_PRIVATE(ah)->nf_cal_hist; nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; } else { /* Fill 0 if valid internal channel is not found */ if (ichan == AH_NULL) { OS_MEMZERO(nf_buf, sizeof(nf_buf[0])*HAL_NUM_NF_READINGS); return; } /* * It is okay to treat a HAL_NFCAL_HIST_SMALL struct as if it were a * HAL_NFCAL_HIST_FULL struct, as long as only the index 0 of the * nf_cal_buffer is used (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]) */ h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; } #endif /* Get most recently updated values from nf cal history buffer */ recent_nf_index = (h->base.curr_index) ? h->base.curr_index - 1 : nf_hist_len - 1; for (i = 0; i < HAL_NUM_NF_READINGS; i++) { /* Fill 0 for unsupported chains */ if (!(rx_chainmask & (1 << i))) { nf_buf[i] = 0; continue; } nf_buf[i] = h->nf_cal_buffer[recent_nf_index][i]; } } /* * Return the current NF value in register. * If the current NF cal is not completed, return 0. */ int16_t ar9300_get_nf_from_reg(struct ath_hal *ah, struct ieee80211_channel *chan, int wait_time) { int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; int is_2g = 0; HAL_CHANNEL_INTERNAL *ichan = NULL; ichan = ath_hal_checkchannel(ah, chan); if (ichan == NULL) return (0); if (wait_time <= 0) { return 0; } if (!ath_hal_waitfor(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF, 0, wait_time)) { ath_hal_printf(ah, "%s: NF cal is not complete in %dus", __func__, wait_time); return 0; } is_2g = !! (IS_CHAN_2GHZ(ichan)); ar9300_upload_noise_floor(ah, is_2g, nfarray); return nfarray[0]; } /* * Pick up the medium one in the noise floor buffer and update the * corresponding range for valid noise floor values */ static int16_t ar9300_get_nf_hist_mid(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, int reading, int hist_len) { int16_t nfval; int16_t sort[HAL_NF_CAL_HIST_LEN_FULL]; /* upper bound for hist_len */ int i, j; for (i = 0; i < hist_len; i++) { sort[i] = h->nf_cal_buffer[i][reading]; HALDEBUG(ah, HAL_DEBUG_NFCAL, "nf_cal_buffer[%d][%d] = %d\n", i, reading, (int)sort[i]); } for (i = 0; i < hist_len - 1; i++) { for (j = 1; j < hist_len - i; j++) { if (sort[j] > sort[j - 1]) { nfval = sort[j]; sort[j] = sort[j - 1]; sort[j - 1] = nfval; } } } nfval = sort[(hist_len - 1) >> 1]; return nfval; } static int16_t ar9300_limit_nf_range(struct ath_hal *ah, int16_t nf) { if (nf < AH9300(ah)->nfp->min) { return AH9300(ah)->nfp->nominal; } else if (nf > AH9300(ah)->nfp->max) { return AH9300(ah)->nfp->max; } return nf; } #ifndef ATH_NF_PER_CHAN inline static void ar9300_reset_nf_hist_buff(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) { HAL_CHAN_NFCAL_HIST *h = &ichan->nf_cal_hist; HAL_NFCAL_HIST_FULL *home = &AH_PRIVATE(ah)->nf_cal_hist; int i; /* * Copy the value for the channel in question into the home-channel * NF history buffer. The channel NF is probably a value filled in by * a prior background channel scan, but if no scan has been done then * it is the nominal noise floor filled in by ath_hal_init_NF_buffer * for this chip and the channel's band. * Replicate this channel NF into all entries of the home-channel NF * history buffer. * If the channel NF was filled in by a channel scan, it has not had * bounds limits applied to it yet - do so now. It is important to * apply bounds limits to the priv_nf value that gets loaded into the * WLAN chip's min_cca_pwr register field. It is also necessary to * apply bounds limits to the nf_cal_buffer[] elements. Since we are * replicating a single NF reading into all nf_cal_buffer elements, * if the single reading were above the CW_INT threshold, the CW_INT * check in ar9300_get_nf would immediately conclude that CW interference * is present, even though we're not supposed to set CW_INT unless * NF values are _consistently_ above the CW_INT threshold. * Applying the bounds limits to the nf_cal_buffer contents fixes this * problem. */ for (i = 0; i < HAL_NUM_NF_READINGS; i ++) { int j; int16_t nf; /* * No need to set curr_index, since it already has a value in * the range [0..HAL_NF_CAL_HIST_LEN_FULL), and all nf_cal_buffer * values will be the same. */ nf = ar9300_limit_nf_range(ah, h->nf_cal_buffer[0][i]); for (j = 0; j < HAL_NF_CAL_HIST_LEN_FULL; j++) { home->nf_cal_buffer[j][i] = nf; } AH_PRIVATE(ah)->nf_cal_hist.base.priv_nf[i] = nf; } } #endif /* * Update the noise floor buffer as a ring buffer */ static int16_t ar9300_update_nf_hist_buff(struct ath_hal *ah, HAL_NFCAL_HIST_FULL *h, int16_t *nfarray, int hist_len) { int i, nr; int16_t nf_no_lim_chain0; nf_no_lim_chain0 = ar9300_get_nf_hist_mid(ah, h, 0, hist_len); HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] BEFORE\n", __func__, __LINE__); for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) { for (i = 0; i < HAL_NUM_NF_READINGS; i++) { HALDEBUG(ah, HAL_DEBUG_NFCAL, "nf_cal_buffer[%d][%d] = %d\n", nr, i, (int)h->nf_cal_buffer[nr][i]); } } for (i = 0; i < HAL_NUM_NF_READINGS; i++) { h->nf_cal_buffer[h->base.curr_index][i] = nfarray[i]; h->base.priv_nf[i] = ar9300_limit_nf_range( ah, ar9300_get_nf_hist_mid(ah, h, i, hist_len)); } HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] AFTER\n", __func__, __LINE__); for (nr = 0; nr < HAL_NF_CAL_HIST_LEN_FULL; nr++) { for (i = 0; i < HAL_NUM_NF_READINGS; i++) { HALDEBUG(ah, HAL_DEBUG_NFCAL, "nf_cal_buffer[%d][%d] = %d\n", nr, i, (int)h->nf_cal_buffer[nr][i]); } } if (++h->base.curr_index >= hist_len) { h->base.curr_index = 0; } return nf_no_lim_chain0; } #ifdef UNUSED static HAL_BOOL get_noise_floor_thresh(struct ath_hal *ah, const HAL_CHANNEL_INTERNAL *chan, int16_t *nft) { struct ath_hal_9300 *ahp = AH9300(ah); switch (chan->channel_flags & CHANNEL_ALL_NOTURBO) { case CHANNEL_A: case CHANNEL_A_HT20: case CHANNEL_A_HT40PLUS: case CHANNEL_A_HT40MINUS: *nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_5); break; case CHANNEL_B: case CHANNEL_G: case CHANNEL_G_HT20: case CHANNEL_G_HT40PLUS: case CHANNEL_G_HT40MINUS: *nft = (int8_t)ar9300_eeprom_get(ahp, EEP_NFTHRESH_2); break; default: HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel flags 0x%x\n", __func__, chan->channel_flags); return AH_FALSE; } return AH_TRUE; } #endif /* * Read the NF and check it against the noise floor threshhold */ #define IS(_c, _f) (((_c)->channel_flags & _f) || 0) static int ar9300_store_new_nf(struct ath_hal *ah, struct ieee80211_channel *chan, int is_scan) { // struct ath_hal_private *ahpriv = AH_PRIVATE(ah); int nf_hist_len; int16_t nf_no_lim; int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; HAL_NFCAL_HIST_FULL *h; int is_2g = 0; HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); struct ath_hal_9300 *ahp = AH9300(ah); if (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { u_int32_t tsf32, nf_cal_dur_tsf; /* * The reason the NF calibration did not complete may just be that * not enough time has passed since the NF calibration was started, * because under certain conditions (when first moving to a new * channel) the NF calibration may be checked very repeatedly. * Or, there may be CW interference keeping the NF calibration * from completing. Check the delta time between when the NF * calibration was started and now to see whether the NF calibration * should have already completed (but hasn't, probably due to CW * interference), or hasn't had enough time to finish yet. */ /* * AH_NF_CAL_DUR_MAX_TSF - A conservative maximum time that the * HW should need to finish a NF calibration. If the HW * does not complete a NF calibration within this time period, * there must be a problem - probably CW interference. * AH_NF_CAL_PERIOD_MAX_TSF - A conservative maximum time between * check of the HW's NF calibration being finished. * If the difference between the current TSF and the TSF * recorded when the NF calibration started is larger than this * value, the TSF must have been reset. * In general, we expect the TSF to only be reset during * regular operation for STAs, not for APs. However, an * AP's TSF could be reset when joining an IBSS. * There's an outside chance that this could result in the * CW_INT flag being erroneously set, if the TSF adjustment * is smaller than AH_NF_CAL_PERIOD_MAX_TSF but larger than * AH_NF_CAL_DUR_TSF. However, even if this does happen, * it shouldn't matter, as the IBSS case shouldn't be * concerned about CW_INT. */ /* AH_NF_CAL_DUR_TSF - 90 sec in usec units */ #define AH_NF_CAL_DUR_TSF (90 * 1000 * 1000) /* AH_NF_CAL_PERIOD_MAX_TSF - 180 sec in usec units */ #define AH_NF_CAL_PERIOD_MAX_TSF (180 * 1000 * 1000) /* wraparound handled by using unsigned values */ tsf32 = ar9300_get_tsf32(ah); nf_cal_dur_tsf = tsf32 - AH9300(ah)->nf_tsf32; if (nf_cal_dur_tsf > AH_NF_CAL_PERIOD_MAX_TSF) { /* * The TSF must have gotten reset during the NF cal - * just reset the NF TSF timestamp, so the next time * this function is called, the timestamp comparison * will be valid. */ AH9300(ah)->nf_tsf32 = tsf32; } else if (nf_cal_dur_tsf > AH_NF_CAL_DUR_TSF) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: NF did not complete in calibration window\n", __func__); /* the NF incompletion is probably due to CW interference */ chan->ic_state |= IEEE80211_CHANSTATE_CWINT; } return 0; /* HW's NF measurement not finished */ } HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s[%d] chan %d\n", __func__, __LINE__, ichan->channel); is_2g = !! IS_CHAN_2GHZ(ichan); ar9300_upload_noise_floor(ah, is_2g, nfarray); /* Update the NF buffer for each chain masked by chainmask */ #ifdef ATH_NF_PER_CHAN h = &ichan->nf_cal_hist; nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; #else if (is_scan) { /* * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct * rather than a HAL_NFCAL_HIST_FULL struct. * As long as we only use the first history element of nf_cal_buffer * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably. */ h = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; } else { h = &AH_PRIVATE(ah)->nf_cal_hist; nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; } #endif /* * nf_no_lim = median value from NF history buffer without bounds limits, * priv_nf = median value from NF history buffer with bounds limits. */ nf_no_lim = ar9300_update_nf_hist_buff(ah, h, nfarray, nf_hist_len); ichan->rawNoiseFloor = h->base.priv_nf[0]; /* check if there is interference */ // ichan->channel_flags &= (~CHANNEL_CW_INT); /* * Use AR9300_EMULATION to check for emulation purpose as PCIE Device ID * 0xABCD is recognized as valid Osprey as WAR in some EVs. */ if (nf_no_lim > ahp->nfp->nominal + ahp->nf_cw_int_delta) { /* * Since this CW interference check is being applied to the * median element of the NF history buffer, this indicates that * the CW interference is persistent. A single high NF reading * will not show up in the median, and thus will not cause the * CW_INT flag to be set. */ HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s: NF Cal: CW interferer detected through NF: %d\n", __func__, nf_no_lim); chan->ic_state |= IEEE80211_CHANSTATE_CWINT; } return 1; /* HW's NF measurement finished */ } #undef IS static inline void ar9300_get_delta_slope_values(struct ath_hal *ah, u_int32_t coef_scaled, u_int32_t *coef_mantissa, u_int32_t *coef_exponent) { u_int32_t coef_exp, coef_man; /* * ALGO -> coef_exp = 14-floor(log2(coef)); * floor(log2(x)) is the highest set bit position */ for (coef_exp = 31; coef_exp > 0; coef_exp--) { if ((coef_scaled >> coef_exp) & 0x1) { break; } } /* A coef_exp of 0 is a legal bit position but an unexpected coef_exp */ HALASSERT(coef_exp); coef_exp = 14 - (coef_exp - COEF_SCALE_S); /* * ALGO -> coef_man = floor(coef* 2^coef_exp+0.5); * The coefficient is already shifted up for scaling */ coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); *coef_exponent = coef_exp - 16; } #define MAX_ANALOG_START 319 /* XXX */ /* * Delta slope coefficient computation. * Required for OFDM operation. */ static void ar9300_set_delta_slope(struct ath_hal *ah, struct ieee80211_channel *chan) { u_int32_t coef_scaled, ds_coef_exp, ds_coef_man; u_int32_t fclk = COEFF; /* clock * 2.5 */ u_int32_t clock_mhz_scaled = 0x1000000 * fclk; CHAN_CENTERS centers; /* * half and quarter rate can divide the scaled clock by 2 or 4 * scale for selected channel bandwidth */ if (IEEE80211_IS_CHAN_HALF(chan)) { clock_mhz_scaled = clock_mhz_scaled >> 1; } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { clock_mhz_scaled = clock_mhz_scaled >> 2; } /* * ALGO -> coef = 1e8/fcarrier*fclock/40; * scaled coef to provide precision for this floating calculation */ ar9300_get_channel_centers(ah, chan, ¢ers); coef_scaled = clock_mhz_scaled / centers.synth_center; ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_MAN, ds_coef_man); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING3, AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); /* * For Short GI, * scaled coeff is 9/10 that of normal coeff */ coef_scaled = (9 * coef_scaled) / 10; ar9300_get_delta_slope_values(ah, coef_scaled, &ds_coef_man, &ds_coef_exp); /* for short gi */ OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_MAN, ds_coef_man); OS_REG_RMW_FIELD(ah, AR_PHY_SGI_DELTA, AR_PHY_SGI_DSC_EXP, ds_coef_exp); } #define IS(_c, _f) (IEEE80211_IS_ ## _f(_c)) /* * XXX FreeBSD: This should be turned into something generic in ath_hal! */ HAL_CHANNEL_INTERNAL * ar9300_check_chan(struct ath_hal *ah, const struct ieee80211_channel *chan) { if (chan == NULL) { return AH_NULL; } if ((IS(chan, CHAN_2GHZ) ^ IS(chan, CHAN_5GHZ)) == 0) { HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; not marked as 2GHz or 5GHz\n", __func__, chan->ic_freq , chan->ic_flags); return AH_NULL; } /* * FreeBSD sets multiple flags, so this will fail. */ #if 0 if ((IS(chan, CHAN_OFDM) ^ IS(chan, CHAN_CCK) ^ IS(chan, CHAN_DYN) ^ IS(chan, CHAN_HT20) ^ IS(chan, CHAN_HT40U) ^ IS(chan, CHAN_HT40D)) == 0) { HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; not marked as " "OFDM or CCK or DYN or HT20 or HT40PLUS or HT40MINUS\n", __func__, chan->ic_freq , chan->ic_flags); return AH_NULL; } #endif return (ath_hal_checkchannel(ah, chan)); } #undef IS static void ar9300_set_11n_regs(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_HT_MACMODE macmode) { u_int32_t phymode; // struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t enable_dac_fifo; /* XXX */ enable_dac_fifo = OS_REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO; /* Enable 11n HT, 20 MHz */ phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 | AR_PHY_GC_SHORT_GI_40 | enable_dac_fifo; /* Configure baseband for dynamic 20/40 operation */ if (IEEE80211_IS_CHAN_HT40(chan)) { phymode |= AR_PHY_GC_DYN2040_EN; /* Configure control (primary) channel at +-10MHz */ if (IEEE80211_IS_CHAN_HT40U(chan)) { phymode |= AR_PHY_GC_DYN2040_PRI_CH; } #if 0 /* Configure 20/25 spacing */ if (ahp->ah_ext_prot_spacing == HAL_HT_EXTPROTSPACING_25) { phymode |= AR_PHY_GC_DYN2040_EXT_CH; } #endif } /* make sure we preserve INI settings */ phymode |= OS_REG_READ(ah, AR_PHY_GEN_CTRL); /* EV 62881/64991 - turn off Green Field detection for Maverick STA beta */ phymode &= ~AR_PHY_GC_GF_DETECT_EN; OS_REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode); /* Set IFS timing for half/quarter rates */ if (IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan)) { u_int32_t modeselect = OS_REG_READ(ah, AR_PHY_MODE); if (IEEE80211_IS_CHAN_HALF(chan)) { modeselect |= AR_PHY_MS_HALF_RATE; } else if (IEEE80211_IS_CHAN_QUARTER(chan)) { modeselect |= AR_PHY_MS_QUARTER_RATE; } OS_REG_WRITE(ah, AR_PHY_MODE, modeselect); ar9300_set_ifs_timing(ah, chan); OS_REG_RMW_FIELD( ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW, 0x3); } /* Configure MAC for 20/40 operation */ ar9300_set_11n_mac2040(ah, macmode); /* global transmit timeout (25 TUs default)*/ /* XXX - put this elsewhere??? */ OS_REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); /* carrier sense timeout */ OS_REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); } /* * Spur mitigation for MRC CCK */ static void ar9300_spur_mitigate_mrc_cck(struct ath_hal *ah, struct ieee80211_channel *chan) { int i; /* spur_freq_for_osprey - hardcoded by Systems team for now. */ u_int32_t spur_freq_for_osprey[4] = { 2420, 2440, 2464, 2480 }; u_int32_t spur_freq_for_jupiter[2] = { 2440, 2464}; int cur_bb_spur, negative = 0, cck_spur_freq; u_int8_t* spur_fbin_ptr = NULL; int synth_freq; int range = 10; int max_spurcounts = OSPREY_EEPROM_MODAL_SPURS; HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); /* * Need to verify range +/- 10 MHz in control channel, otherwise spur * is out-of-band and can be ignored. */ if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { spur_fbin_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1); if (spur_fbin_ptr[0] == 0) { return; /* No spur in the mode */ } if (IEEE80211_IS_CHAN_HT40(chan)) { range = 19; if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0) { synth_freq = ichan->channel + 10; } else { synth_freq = ichan->channel - 10; } } else { range = 10; synth_freq = ichan->channel; } } else if(AR_SREV_JUPITER(ah)) { range = 5; max_spurcounts = 2; /* Hardcoded by Jupiter Systems team for now. */ synth_freq = ichan->channel; } else { range = 10; max_spurcounts = 4; /* Hardcoded by Osprey Systems team for now. */ synth_freq = ichan->channel; } for (i = 0; i < max_spurcounts; i++) { negative = 0; if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i], HAL_FREQ_BAND_2GHZ) - synth_freq; } else if(AR_SREV_JUPITER(ah)) { cur_bb_spur = spur_freq_for_jupiter[i] - synth_freq; } else { cur_bb_spur = spur_freq_for_osprey[i] - synth_freq; } if (cur_bb_spur < 0) { negative = 1; cur_bb_spur = -cur_bb_spur; } if (cur_bb_spur < range) { cck_spur_freq = (int)((cur_bb_spur << 19) / 11); if (negative == 1) { cck_spur_freq = -cck_spur_freq; } cck_spur_freq = cck_spur_freq & 0xfffff; /*OS_REG_WRITE_field(ah, BB_agc_control.ycok_max, 0x7);*/ OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x7); /*OS_REG_WRITE_field(ah, BB_cck_spur_mit.spur_rssi_thr, 0x7f);*/ OS_REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_RSSI_THR, 0x7f); /*OS_REG_WRITE(ah, BB_cck_spur_mit.spur_filter_type, 0x2);*/ OS_REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_SPUR_FILTER_TYPE, 0x2); /*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x1);*/ OS_REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x1); /*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, cck_spur_freq);*/ OS_REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, cck_spur_freq); return; } } /*OS_REG_WRITE(ah, BB_agc_control.ycok_max, 0x5);*/ OS_REG_RMW_FIELD(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_YCOK_MAX, 0x5); /*OS_REG_WRITE(ah, BB_cck_spur_mit.use_cck_spur_mit, 0x0);*/ OS_REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_USE_CCK_SPUR_MIT, 0x0); /*OS_REG_WRITE(ah, BB_cck_spur_mit.cck_spur_freq, 0x0);*/ OS_REG_RMW_FIELD(ah, AR_PHY_CCK_SPUR_MIT, AR_PHY_CCK_SPUR_MIT_CCK_SPUR_FREQ, 0x0); } /* Spur mitigation for OFDM */ static void ar9300_spur_mitigate_ofdm(struct ath_hal *ah, struct ieee80211_channel *chan) { int synth_freq; int range = 10; int freq_offset = 0; int spur_freq_sd = 0; int spur_subchannel_sd = 0; int spur_delta_phase = 0; int mask_index = 0; int i; int mode; u_int8_t* spur_chans_ptr; struct ath_hal_9300 *ahp; ahp = AH9300(ah); HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); if (IS_CHAN_5GHZ(ichan)) { spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 0); mode = 0; } else { spur_chans_ptr = ar9300_eeprom_get_spur_chans_ptr(ah, 1); mode = 1; } if (IEEE80211_IS_CHAN_HT40(chan)) { range = 19; if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0) { synth_freq = ichan->channel - 10; } else { synth_freq = ichan->channel + 10; } } else { range = 10; synth_freq = ichan->channel; } /* Clean all spur register fields */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, 0); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE, 0); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, 0); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 0); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 0); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0); OS_REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, 0); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, 0); OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, 0); OS_REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0); OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0); i = 0; while (spur_chans_ptr[i] && i < 5) { freq_offset = FBIN2FREQ(spur_chans_ptr[i], mode) - synth_freq; if (abs(freq_offset) < range) { /* printf( "Spur Mitigation for OFDM: Synth Frequency = %d, " "Spur Frequency = %d\n", synth_freq, FBIN2FREQ(spur_chans_ptr[i], mode)); */ if (IEEE80211_IS_CHAN_HT40(chan)) { if (freq_offset < 0) { if (OS_REG_READ_FIELD( ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0) { spur_subchannel_sd = 1; } else { spur_subchannel_sd = 0; } spur_freq_sd = ((freq_offset + 10) << 9) / 11; } else { if (OS_REG_READ_FIELD(ah, AR_PHY_GEN_CTRL, AR_PHY_GC_DYN2040_PRI_CH) == 0x0) { spur_subchannel_sd = 0; } else { spur_subchannel_sd = 1; } spur_freq_sd = ((freq_offset - 10) << 9) / 11; } spur_delta_phase = (freq_offset << 17) / 5; } else { spur_subchannel_sd = 0; spur_freq_sd = (freq_offset << 9) / 11; spur_delta_phase = (freq_offset << 18) / 5; } spur_freq_sd = spur_freq_sd & 0x3ff; spur_delta_phase = spur_delta_phase & 0xfffff; /* printf( "spur_subchannel_sd = %d, spur_freq_sd = 0x%x, " "spur_delta_phase = 0x%x\n", spur_subchannel_sd, spur_freq_sd, spur_delta_phase); */ /* OFDM Spur mitigation */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_FILTER, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_FREQ_SD, spur_freq_sd); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_SPUR_DELTA_PHASE, spur_delta_phase); OS_REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, AR_PHY_SFCORR_EXT_SPUR_SUBCHANNEL_SD, spur_subchannel_sd); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_AGC, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING11, AR_PHY_TIMING11_USE_SPUR_FILTER_IN_SELFCOR, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_SPUR_RSSI, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH, 34); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_EN_VIT_SPUR_RSSI, 1); /* * Do not subtract spur power from noise floor for wasp. * This causes the maximum client test (on Veriwave) to fail * when run on spur channel (2464 MHz). * Refer to ev#82746 and ev#82744. */ if (!AR_SREV_WASP(ah) && (OS_REG_READ_FIELD(ah, AR_PHY_MODE, AR_PHY_MODE_DYNAMIC) == 0x1)) { OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_NF_RSSI_SPUR_MIT, 1); } mask_index = (freq_offset << 4) / 5; if (mask_index < 0) { mask_index = mask_index - 1; } mask_index = mask_index & 0x7f; /*printf("Bin 0x%x\n", mask_index);*/ OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_ENABLE_MASK_PPM, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_PILOT_MASK, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_ENABLE_CHAN_MASK, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_IDX_A, mask_index); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_IDX_A, mask_index); OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_IDX_A, mask_index); OS_REG_RMW_FIELD(ah, AR_PHY_PILOT_SPUR_MASK, AR_PHY_PILOT_SPUR_MASK_CF_PILOT_MASK_A, 0xc); OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_SPUR_MASK, AR_PHY_CHAN_SPUR_MASK_CF_CHAN_MASK_A, 0xc); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_MASK_A, AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A, 0xa0); OS_REG_RMW_FIELD(ah, AR_PHY_SPUR_REG, AR_PHY_SPUR_REG_MASK_RATE_CNTL, 0xff); /* printf("BB_timing_control_4 = 0x%x\n", OS_REG_READ(ah, AR_PHY_TIMING4)); printf("BB_timing_control_11 = 0x%x\n", OS_REG_READ(ah, AR_PHY_TIMING11)); printf("BB_ext_chan_scorr_thr = 0x%x\n", OS_REG_READ(ah, AR_PHY_SFCORR_EXT)); printf("BB_spur_mask_controls = 0x%x\n", OS_REG_READ(ah, AR_PHY_SPUR_REG)); printf("BB_pilot_spur_mask = 0x%x\n", OS_REG_READ(ah, AR_PHY_PILOT_SPUR_MASK)); printf("BB_chan_spur_mask = 0x%x\n", OS_REG_READ(ah, AR_PHY_CHAN_SPUR_MASK)); printf("BB_vit_spur_mask_A = 0x%x\n", OS_REG_READ(ah, AR_PHY_SPUR_MASK_A)); */ break; } i++; } } /* * Convert to baseband spur frequency given input channel frequency * and compute register settings below. */ static void ar9300_spur_mitigate(struct ath_hal *ah, struct ieee80211_channel *chan) { ar9300_spur_mitigate_ofdm(ah, chan); ar9300_spur_mitigate_mrc_cck(ah, chan); } /************************************************************** * ar9300_channel_change * Assumes caller wants to change channel, and not reset. */ static inline HAL_BOOL ar9300_channel_change(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode) { u_int32_t synth_delay, qnum; struct ath_hal_9300 *ahp = AH9300(ah); /* TX must be stopped by now */ for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ar9300_num_tx_pending(ah, qnum)) { HALDEBUG(ah, HAL_DEBUG_QUEUE, "%s: Transmit frames pending on queue %d\n", __func__, qnum); HALASSERT(0); return AH_FALSE; } } /* * Kill last Baseband Rx Frame - Request analog bus grant */ OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath_hal_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) { HALDEBUG(ah, HAL_DEBUG_PHYIO, "%s: Could not kill baseband RX\n", __func__); return AH_FALSE; } /* Setup 11n MAC/Phy mode registers */ ar9300_set_11n_regs(ah, chan, macmode); /* * Change the synth */ if (!ahp->ah_rf_hal.set_channel(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: failed to set channel\n", __func__); return AH_FALSE; } /* * Some registers get reinitialized during ATH_INI_POST INI programming. */ ar9300_init_user_settings(ah); /* * Setup the transmit power values. * * After the public to private hal channel mapping, ichan contains the * valid regulatory power value. * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan. */ if (ar9300_eeprom_set_transmit_power( ah, &ahp->ah_eeprom, chan, ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), ath_hal_get_twice_max_regpower(AH_PRIVATE(ah), ichan, chan), AH_MIN(MAX_RATE_POWER, AH_PRIVATE(ah)->ah_powerLimit)) != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: error init'ing transmit power\n", __func__); return AH_FALSE; } /* * Release the RFBus Grant. */ OS_REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0); /* * Write spur immunity and delta slope for OFDM enabled modes (A, G, Turbo) */ if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) { ar9300_set_delta_slope(ah, chan); } else { /* Set to Ini default */ OS_REG_WRITE(ah, AR_PHY_TIMING3, 0x9c0a9f6b); OS_REG_WRITE(ah, AR_PHY_SGI_DELTA, 0x00046384); } ar9300_spur_mitigate(ah, chan); /* * Wait for the frequency synth to settle (synth goes on via PHY_ACTIVE_EN). * Read the phy active delay register. Value is in 100ns increments. */ synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IEEE80211_IS_CHAN_CCK(chan)) { synth_delay = (4 * synth_delay) / 22; } else { synth_delay /= 10; } OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY); /* * Do calibration. */ return AH_TRUE; } void ar9300_set_operating_mode(struct ath_hal *ah, int opmode) { u_int32_t val; val = OS_REG_READ(ah, AR_STA_ID1); val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); switch (opmode) { case HAL_M_HOSTAP: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP | AR_STA_ID1_KSRCH_MODE); OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; case HAL_M_IBSS: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC | AR_STA_ID1_KSRCH_MODE); OS_REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; case HAL_M_STA: case HAL_M_MONITOR: OS_REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); break; } } /* XXX need the logic for Osprey */ void ar9300_init_pll(struct ath_hal *ah, struct ieee80211_channel *chan) { u_int32_t pll; u_int8_t clk_25mhz = AH9300(ah)->clk_25mhz; HAL_CHANNEL_INTERNAL *ichan = NULL; if (chan) ichan = ath_hal_checkchannel(ah, chan); if (AR_SREV_HORNET(ah)) { if (clk_25mhz) { /* Hornet uses PLL_CONTROL_2. Xtal is 25MHz for Hornet. * REFDIV set to 0x1. * $xtal_freq = 25; * $PLL2_div = (704/$xtal_freq); # 176 * 4 = 704. * MAC and BB run at 176 MHz. * $PLL2_divint = int($PLL2_div); * $PLL2_divfrac = $PLL2_div - $PLL2_divint; * $PLL2_divfrac = int($PLL2_divfrac * 0x4000); # 2^14 * $PLL2_Val = ($PLL2_divint & 0x3f) << 19 | (0x1) << 14 | * $PLL2_divfrac & 0x3fff; * Therefore, $PLL2_Val = 0xe04a3d */ #define DPLL2_KD_VAL 0x1D #define DPLL2_KI_VAL 0x06 #define DPLL3_PHASE_SHIFT_VAL 0x1 /* Rewrite DDR PLL2 and PLL3 */ /* program DDR PLL ki and kd value, ki=0x6, kd=0x1d */ OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x18e82f01); /* program DDR PLL phase_shift to 0x1 */ OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3, AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); OS_DELAY(1000); /* program refdiv, nint, frac to RTC register */ OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0xe04a3d); /* program BB PLL ki and kd value, ki=0x6, kd=0x1d */ OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL); /* program BB PLL phase_shift to 0x1 */ OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); } else { /* 40MHz */ #undef DPLL2_KD_VAL #undef DPLL2_KI_VAL #define DPLL2_KD_VAL 0x3D #define DPLL2_KI_VAL 0x06 /* Rewrite DDR PLL2 and PLL3 */ /* program DDR PLL ki and kd value, ki=0x6, kd=0x3d */ OS_REG_WRITE(ah, AR_HORNET_CH0_DDR_DPLL2, 0x19e82f01); /* program DDR PLL phase_shift to 0x1 */ OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_DDR_DPLL3, AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); OS_DELAY(1000); /* program refdiv, nint, frac to RTC register */ OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666); /* program BB PLL ki and kd value, ki=0x6, kd=0x3d */ OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_KD, DPLL2_KD_VAL); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_KI, DPLL2_KI_VAL); /* program BB PLL phase_shift to 0x1 */ OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, AR_PHY_BB_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL); } OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); OS_DELAY(1000); } else if (AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_PLL_PWD, 0x1); /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */ OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_KD, 0x40); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_KI, 0x4); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, AR_PHY_BB_DPLL1_REFDIV, 0x5); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, AR_PHY_BB_DPLL1_NINI, 0x58); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL1, AR_PHY_BB_DPLL1_NFRAC, 0x0); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_OUTDIV, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_LOCAL_PLL, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_EN_NEGTRIG, 0x1); /* program BB PLL phase_shift to 0x6 */ OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL3, AR_PHY_BB_DPLL3_PHASE_SHIFT, 0x6); OS_REG_RMW_FIELD(ah, AR_PHY_BB_DPLL2, AR_PHY_BB_DPLL2_PLL_PWD, 0x0); OS_DELAY(1000); OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); OS_DELAY(1000); } else if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { #define SRIF_PLL 1 u_int32_t regdata, pll2_divint, pll2_divfrac; #ifndef SRIF_PLL u_int32_t pll2_clkmode; #endif #ifdef SRIF_PLL u_int32_t refdiv; #endif if (clk_25mhz) { #ifndef SRIF_PLL pll2_divint = 0x1c; pll2_divfrac = 0xa3d7; #else pll2_divint = 0x54; pll2_divfrac = 0x1eb85; refdiv = 3; #endif } else { #ifndef SRIF_PLL pll2_divint = 0x11; pll2_divfrac = 0x26666; #else if (AR_SREV_WASP(ah)) { pll2_divint = 88; pll2_divfrac = 0; refdiv = 5; } else { pll2_divint = 0x11; pll2_divfrac = 0x26666; refdiv = 1; } #endif } #ifndef SRIF_PLL pll2_clkmode = 0x3d; #endif /* PLL programming through SRIF Local Mode */ OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); /* Bypass mode */ OS_DELAY(1000); do { regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); regdata = regdata | (0x1 << 16); OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 1 */ OS_DELAY(100); /* override int, frac, refdiv */ #ifndef SRIF_PLL OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL, ((1 << 27) | (pll2_divint << 18) | pll2_divfrac)); #else OS_REG_WRITE(ah, AR_PHY_PLL_CONTROL, ((refdiv << 27) | (pll2_divint << 18) | pll2_divfrac)); #endif OS_DELAY(100); regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); #ifndef SRIF_PLL regdata = (regdata & 0x80071fff) | (0x1 << 30) | (0x1 << 13) | (0x6 << 26) | (pll2_clkmode << 19); #else if (AR_SREV_WASP(ah)) { regdata = (regdata & 0x80071fff) | (0x1 << 30) | (0x1 << 13) | (0x4 << 26) | (0x18 << 19); } else { regdata = (regdata & 0x80071fff) | (0x3 << 30) | (0x1 << 13) | (0x4 << 26) | (0x60 << 19); } #endif /* Ki, Kd, Local PLL, Outdiv */ OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); regdata = OS_REG_READ(ah, AR_PHY_PLL_MODE); regdata = (regdata & 0xfffeffff); OS_REG_WRITE(ah, AR_PHY_PLL_MODE, regdata); /* PWD_PLL set to 0 */ OS_DELAY(1000); if (AR_SREV_WASP(ah)) { /* clear do measure */ regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); regdata &= ~(1 << 30); OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); OS_DELAY(100); /* set do measure */ regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); regdata |= (1 << 30); OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); /* wait for measure done */ do { regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL4); } while ((regdata & (1 << 3)) == 0); /* clear do measure */ regdata = OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3); regdata &= ~(1 << 30); OS_REG_WRITE(ah, AR_PHY_PLL_BB_DPLL3, regdata); /* get measure sqsum dvc */ regdata = (OS_REG_READ(ah, AR_PHY_PLL_BB_DPLL3) & 0x007FFFF8) >> 3; } else { break; } } while (regdata >= 0x40000); /* Remove from Bypass mode */ OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c); OS_DELAY(1000); } else { pll = SM(0x5, AR_RTC_PLL_REFDIV); /* Supposedly not needed on Osprey */ #if 0 if (chan && IS_CHAN_HALF_RATE(chan)) { pll |= SM(0x1, AR_RTC_PLL_CLKSEL); } else if (chan && IS_CHAN_QUARTER_RATE(chan)) { pll |= SM(0x2, AR_RTC_PLL_CLKSEL); } #endif if (ichan && IS_CHAN_5GHZ(ichan)) { pll |= SM(0x28, AR_RTC_PLL_DIV); /* * When doing fast clock, set PLL to 0x142c */ if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { pll = 0x142c; } } else { pll |= SM(0x2c, AR_RTC_PLL_DIV); } OS_REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); } /* TODO: * For multi-band owl, switch between bands by reiniting the PLL. */ OS_DELAY(RTC_PLL_SETTLE_DELAY); OS_REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK | AR_RTC_PCIE_RST_PWDN_EN); if (AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { if (clk_25mhz) { OS_REG_WRITE(ah, AR_RTC_DERIVED_RTC_CLK, (0x17c << 1)); /* 32KHz sleep clk */ OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae); } else { OS_REG_WRITE(ah, AR_RTC_DERIVED_RTC_CLK, (0x261 << 1)); /* 32KHz sleep clk */ OS_REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400); OS_REG_WRITE(ah, AR_SLP32_INC, 0x0001e800); } OS_DELAY(100); } } static inline HAL_BOOL ar9300_set_reset(struct ath_hal *ah, int type) { u_int32_t rst_flags; u_int32_t tmp_reg; struct ath_hal_9300 *ahp = AH9300(ah); HALASSERT(type == HAL_RESET_WARM || type == HAL_RESET_COLD); /* * RTC Force wake should be done before resetting the MAC. * MDK/ART does it that way. */ OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); /* Reset AHB */ /* Bug26871 */ tmp_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE)); if (AR_SREV_WASP(ah)) { if (tmp_reg & (AR9340_INTR_SYNC_LOCAL_TIMEOUT)) { OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); } } else { if (tmp_reg & (AR9300_INTR_SYNC_LOCAL_TIMEOUT | AR9300_INTR_SYNC_RADM_CPL_TIMEOUT)) { OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), 0); OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_HOSTIF); } else { /* NO AR_RC_AHB in Osprey */ /*OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), AR_RC_AHB);*/ } } rst_flags = AR_RTC_RC_MAC_WARM; if (type == HAL_RESET_COLD) { rst_flags |= AR_RTC_RC_MAC_COLD; } #ifdef AH_SUPPORT_HORNET /* Hornet WAR: trigger SoC to reset WMAC if ... * (1) doing cold reset. Ref: EV 69254 * (2) beacon pending. Ref: EV 70983 */ if (AR_SREV_HORNET(ah) && (ar9300_num_tx_pending( ah, AH_PRIVATE(ah)->ah_caps.halTotalQueues - 1) != 0 || type == HAL_RESET_COLD)) { u_int32_t time_out; #define AR_SOC_RST_RESET 0xB806001C #define AR_SOC_BOOT_STRAP 0xB80600AC #define AR_SOC_WLAN_RST 0x00000800 /* WLAN reset */ #define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Hornet SoC reset WMAC.\n", __func__); REG_WRITE(AR_SOC_RST_RESET, REG_READ(AR_SOC_RST_RESET) | AR_SOC_WLAN_RST); REG_WRITE(AR_SOC_RST_RESET, REG_READ(AR_SOC_RST_RESET) & (~AR_SOC_WLAN_RST)); time_out = 0; while (1) { tmp_reg = REG_READ(AR_SOC_BOOT_STRAP); if ((tmp_reg & 0x10) == 0) { break; } if (time_out > 20) { break; } OS_DELAY(10000); time_out++; } OS_REG_WRITE(ah, AR_RTC_RESET, 1); #undef REG_READ #undef REG_WRITE #undef AR_SOC_WLAN_RST #undef AR_SOC_RST_RESET #undef AR_SOC_BOOT_STRAP } #endif /* AH_SUPPORT_HORNET */ #ifdef AH_SUPPORT_SCORPION if (AR_SREV_SCORPION(ah)) { #define DDR_CTL_CONFIG_ADDRESS 0xb8000000 #define DDR_CTL_CONFIG_OFFSET 0x0108 #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MSB 29 #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB 21 #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK 0x3fe00000 #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(x) (((x) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) >> DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) #define DDR_CTL_CONFIG_CLIENT_ACTIVITY_SET(x) (((x) << DDR_CTL_CONFIG_CLIENT_ACTIVITY_LSB) & DDR_CTL_CONFIG_CLIENT_ACTIVITY_MASK) #define MAC_DMA_CFG_ADDRESS 0xb8100000 #define MAC_DMA_CFG_OFFSET 0x0014 #define MAC_DMA_CFG_HALT_REQ_MSB 11 #define MAC_DMA_CFG_HALT_REQ_LSB 11 #define MAC_DMA_CFG_HALT_REQ_MASK 0x00000800 #define MAC_DMA_CFG_HALT_REQ_GET(x) (((x) & MAC_DMA_CFG_HALT_REQ_MASK) >> MAC_DMA_CFG_HALT_REQ_LSB) #define MAC_DMA_CFG_HALT_REQ_SET(x) (((x) << MAC_DMA_CFG_HALT_REQ_LSB) & MAC_DMA_CFG_HALT_REQ_MASK) #define MAC_DMA_CFG_HALT_ACK_MSB 12 #define MAC_DMA_CFG_HALT_ACK_LSB 12 #define MAC_DMA_CFG_HALT_ACK_MASK 0x00001000 #define MAC_DMA_CFG_HALT_ACK_GET(x) (((x) & MAC_DMA_CFG_HALT_ACK_MASK) >> MAC_DMA_CFG_HALT_ACK_LSB) #define MAC_DMA_CFG_HALT_ACK_SET(x) (((x) << MAC_DMA_CFG_HALT_ACK_LSB) & MAC_DMA_CFG_HALT_ACK_MASK) #define RST_RESET 0xB806001c #define RTC_RESET (1<<27) #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) #define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); #define DDR_REG_READ(_ah, _reg) \ *((volatile u_int32_t *)( DDR_CTL_CONFIG_ADDRESS + (_reg))) #define DDR_REG_WRITE(_ah, _reg, _val) \ *((volatile u_int32_t *)(DDR_CTL_CONFIG_ADDRESS + (_reg))) = (_val) OS_REG_WRITE(ah,MAC_DMA_CFG_OFFSET, (OS_REG_READ(ah,MAC_DMA_CFG_OFFSET) & ~MAC_DMA_CFG_HALT_REQ_MASK) | MAC_DMA_CFG_HALT_REQ_SET(1)); { int count; u_int32_t data; count = 0; while (!MAC_DMA_CFG_HALT_ACK_GET(OS_REG_READ(ah, MAC_DMA_CFG_OFFSET) )) { count++; if (count > 10) { ath_hal_printf(ah, "Halt ACK timeout\n"); break; } OS_DELAY(10); } data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET); ath_hal_printf(ah, "check DDR Activity - HIGH\n"); count = 0; while (DDR_CTL_CONFIG_CLIENT_ACTIVITY_GET(data)) { // AVE_DEBUG(0,"DDR Activity - HIGH\n"); ath_hal_printf(ah, "DDR Activity - HIGH\n"); count++; OS_DELAY(10); data = DDR_REG_READ(ah,DDR_CTL_CONFIG_OFFSET); if (count > 10) { ath_hal_printf(ah, "DDR Activity timeout\n"); break; } } } { //Force RTC reset REG_WRITE(RST_RESET, (REG_READ(RST_RESET) | RTC_RESET)); OS_DELAY(10); REG_WRITE(RST_RESET, (REG_READ(RST_RESET) & ~RTC_RESET)); OS_DELAY(10); OS_REG_WRITE(ah, AR_RTC_RESET, 0); OS_DELAY(10); OS_REG_WRITE(ah, AR_RTC_RESET, 1); OS_DELAY(10); ath_hal_printf(ah,"%s: Scorpion SoC RTC reset done.\n", __func__); } #undef REG_READ #undef REG_WRITE } #endif /* AH_SUPPORT_SCORPION */ /* * Set Mac(BB,Phy) Warm Reset */ OS_REG_WRITE(ah, AR_RTC_RC, rst_flags); OS_DELAY(50); /* XXX 50 usec */ /* * Clear resets and force wakeup */ OS_REG_WRITE(ah, AR_RTC_RC, 0); if (!ath_hal_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: RTC stuck in MAC reset\n", __FUNCTION__); HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: AR_RTC_RC = 0x%x\n", __func__, OS_REG_READ(ah, AR_RTC_RC)); return AH_FALSE; } /* Clear AHB reset */ OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_RC), 0); ar9300_attach_hw_platform(ah); ahp->ah_chip_reset_done = 1; return AH_TRUE; } static inline HAL_BOOL ar9300_set_reset_power_on(struct ath_hal *ah) { /* Force wake */ OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); /* * RTC reset and clear. Some delay in between is needed * to give the chip time to settle. */ OS_REG_WRITE(ah, AR_RTC_RESET, 0); OS_DELAY(2); OS_REG_WRITE(ah, AR_RTC_RESET, 1); /* * Poll till RTC is ON */ if (!ath_hal_wait(ah, AR_RTC_STATUS, AR_RTC_STATUS_M, AR_RTC_STATUS_ON)) { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s: RTC not waking up for %d\n", __FUNCTION__, 1000); return AH_FALSE; } /* * Read Revisions from Chip right after RTC is on for the first time. * This helps us detect the chip type early and initialize it accordingly. */ ar9300_read_revisions(ah); /* * Warm reset if we aren't really powering on, * just restarting the driver. */ return ar9300_set_reset(ah, HAL_RESET_WARM); } /* * Write the given reset bit mask into the reset register */ HAL_BOOL ar9300_set_reset_reg(struct ath_hal *ah, u_int32_t type) { HAL_BOOL ret = AH_FALSE; /* * Set force wake */ OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_WA), AH9300(ah)->ah_wa_reg_val); OS_DELAY(10); /* delay to allow AR_WA reg write to kick in */ OS_REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); switch (type) { case HAL_RESET_POWER_ON: ret = ar9300_set_reset_power_on(ah); break; case HAL_RESET_WARM: case HAL_RESET_COLD: ret = ar9300_set_reset(ah, type); break; default: break; } #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { OS_REG_WRITE(ah, AR_RTC_KEEP_AWAKE, 0x2); } #endif return ret; } /* * Places the PHY and Radio chips into reset. A full reset * must be called to leave this state. The PCI/MAC/PCU are * not placed into reset as we must receive interrupt to * re-enable the hardware. */ HAL_BOOL ar9300_phy_disable(struct ath_hal *ah) { if (!ar9300_set_reset_reg(ah, HAL_RESET_WARM)) { return AH_FALSE; } #ifdef ATH_SUPPORT_LED #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) #define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); #define ATH_GPIO_OE 0xB8040000 #define ATH_GPIO_OUT 0xB8040008 /* GPIO Ouput Value reg.*/ if (AR_SREV_WASP(ah)) { if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13))); } else { REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12))); } } else if (AR_SREV_SCORPION(ah)) { if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 13))); } else { REG_WRITE(ATH_GPIO_OE, (REG_READ(ATH_GPIO_OE) | (0x1 << 12))); } /* Turn off JMPST led */ REG_WRITE(ATH_GPIO_OUT, (REG_READ(ATH_GPIO_OUT) | (0x1 << 15))); } #undef REG_READ #undef REG_WRITE #endif if ( AR_SREV_OSPREY(ah) ) { OS_REG_RMW(ah, AR_HOSTIF_REG(ah, AR_GPIO_OUTPUT_MUX1), 0x0, 0x1f); } ar9300_init_pll(ah, AH_NULL); return AH_TRUE; } /* * Places all of hardware into reset */ HAL_BOOL ar9300_disable(struct ath_hal *ah) { if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { return AH_FALSE; } if (!ar9300_set_reset_reg(ah, HAL_RESET_COLD)) { return AH_FALSE; } ar9300_init_pll(ah, AH_NULL); return AH_TRUE; } /* * TODO: Only write the PLL if we're changing to or from CCK mode * * WARNING: The order of the PLL and mode registers must be correct. */ static inline void ar9300_set_rf_mode(struct ath_hal *ah, struct ieee80211_channel *chan) { u_int32_t rf_mode = 0; if (chan == AH_NULL) { return; } switch (AH9300(ah)->ah_hwp) { case HAL_TRUE_CHIP: rf_mode |= (IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_G(chan)) ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; break; default: HALASSERT(0); break; } /* Phy mode bits for 5GHz channels requiring Fast Clock */ if ( IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { rf_mode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); } OS_REG_WRITE(ah, AR_PHY_MODE, rf_mode); } /* * Places the hardware into reset and then pulls it out of reset */ HAL_BOOL ar9300_chip_reset(struct ath_hal *ah, struct ieee80211_channel *chan) { struct ath_hal_9300 *ahp = AH9300(ah); int type = HAL_RESET_WARM; OS_MARK(ah, AH_MARK_CHIPRESET, chan ? chan->ic_freq : 0); /* * Warm reset is optimistic. * * If the TX/RX DMA engines aren't shut down (eg, they're * wedged) then we're better off doing a full cold reset * to try and shake that condition. */ if (ahp->ah_chip_full_sleep || (ah->ah_config.ah_force_full_reset == 1) || OS_REG_READ(ah, AR_Q_TXE) || (OS_REG_READ(ah, AR_CR) & AR_CR_RXE)) { type = HAL_RESET_COLD; } if (!ar9300_set_reset_reg(ah, type)) { return AH_FALSE; } /* Bring out of sleep mode (AGAIN) */ if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { return AH_FALSE; } ahp->ah_chip_full_sleep = AH_FALSE; if (AR_SREV_HORNET(ah)) { ar9300_internal_regulator_apply(ah); } ar9300_init_pll(ah, chan); /* * Perform warm reset before the mode/PLL/turbo registers * are changed in order to deactivate the radio. Mode changes * with an active radio can result in corrupted shifts to the * radio device. */ ar9300_set_rf_mode(ah, chan); return AH_TRUE; } /* ar9300_setup_calibration * Setup HW to collect samples used for current cal */ inline static void ar9300_setup_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal) { /* Select calibration to run */ switch (curr_cal->cal_data->cal_type) { case IQ_MISMATCH_CAL: /* Start calibration w/ 2^(INIT_IQCAL_LOG_COUNT_MAX+1) samples */ OS_REG_RMW_FIELD(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_IQCAL_LOG_COUNT_MAX, curr_cal->cal_data->cal_count_max); OS_REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: starting IQ Mismatch Calibration\n", __func__); /* Kick-off cal */ OS_REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); break; case TEMP_COMP_CAL: if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1); OS_REG_RMW_FIELD(ah, AR_HORNET_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); } else if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_LOCAL, 1); OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM_JUPITER, AR_PHY_65NM_CH0_THERM_START, 1); } else { OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_LOCAL, 1); OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_THERM, AR_PHY_65NM_CH0_THERM_START, 1); } HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: starting Temperature Compensation Calibration\n", __func__); break; default: HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s called with incorrect calibration type.\n", __func__); } } /* ar9300_reset_calibration * Initialize shared data structures and prepare a cal to be run. */ inline static void ar9300_reset_calibration(struct ath_hal *ah, HAL_CAL_LIST *curr_cal) { struct ath_hal_9300 *ahp = AH9300(ah); int i; /* Setup HW for new calibration */ ar9300_setup_calibration(ah, curr_cal); /* Change SW state to RUNNING for this calibration */ curr_cal->cal_state = CAL_RUNNING; /* Reset data structures shared between different calibrations */ for (i = 0; i < AR9300_MAX_CHAINS; i++) { ahp->ah_meas0.sign[i] = 0; ahp->ah_meas1.sign[i] = 0; ahp->ah_meas2.sign[i] = 0; ahp->ah_meas3.sign[i] = 0; } ahp->ah_cal_samples = 0; } #ifdef XXX_UNUSED_FUNCTION /* * Find out which of the RX chains are enabled */ static u_int32_t ar9300_get_rx_chain_mask(struct ath_hal *ah) { u_int32_t ret_val = OS_REG_READ(ah, AR_PHY_RX_CHAINMASK); /* The bits [2:0] indicate the rx chain mask and are to be * interpreted as follows: * 00x => Only chain 0 is enabled * 01x => Chain 1 and 0 enabled * 1xx => Chain 2,1 and 0 enabled */ return (ret_val & 0x7); } #endif static void ar9300_get_nf_hist_base(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *chan, int is_scan, int16_t nf[]) { HAL_NFCAL_BASE *h_base; #ifdef ATH_NF_PER_CHAN h_base = &chan->nf_cal_hist.base; #else if (is_scan) { /* * The channel we are currently on is not the home channel, * so we shouldn't use the home channel NF buffer's values on * this channel. Instead, use the NF single value already * read for this channel. (Or, if we haven't read the NF for * this channel yet, the SW default for this chip/band will * be used.) */ h_base = &chan->nf_cal_hist.base; } else { /* use the home channel NF info */ h_base = &AH_PRIVATE(ah)->nf_cal_hist.base; } #endif OS_MEMCPY(nf, h_base->priv_nf, sizeof(h_base->priv_nf)); } HAL_BOOL ar9300_load_nf(struct ath_hal *ah, int16_t nf[]) { int i, j; int32_t val; /* XXX where are EXT regs defined */ const u_int32_t ar9300_cca_regs[] = { AR_PHY_CCA_0, AR_PHY_CCA_1, AR_PHY_CCA_2, AR_PHY_EXT_CCA, AR_PHY_EXT_CCA_1, AR_PHY_EXT_CCA_2, }; u_int8_t chainmask; /* * Force NF calibration for all chains, otherwise Vista station * would conduct a bad performance */ if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { chainmask = 0x9; } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { chainmask = 0x1b; } else { chainmask = 0x3F; } /* * Write filtered NF values into max_cca_pwr register parameter * so we can load below. */ for (i = 0; i < HAL_NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { val = OS_REG_READ(ah, ar9300_cca_regs[i]); val &= 0xFFFFFE00; val |= (((u_int32_t)(nf[i]) << 1) & 0x1ff); OS_REG_WRITE(ah, ar9300_cca_regs[i], val); } } HALDEBUG(ah, HAL_DEBUG_NFCAL, "%s: load %d %d %d %d %d %d\n", __func__, nf[0], nf[1], nf[2], nf[3], nf[4], nf[5]); /* * Load software filtered NF value into baseband internal min_cca_pwr * variable. */ OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); OS_REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); /* Wait for load to complete, should be fast, a few 10s of us. */ /* Changed the max delay 250us back to 10000us, since 250us often * results in NF load timeout and causes deaf condition * during stress testing 12/12/2009 */ for (j = 0; j < 10000; j++) { if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){ break; } OS_DELAY(10); } if (j == 10000) { /* * We timed out waiting for the noisefloor to load, probably * due to an in-progress rx. Simply return here and allow * the load plenty of time to complete before the next * calibration interval. We need to avoid trying to load -50 * (which happens below) while the previous load is still in * progress as this can cause rx deafness (see EV 66368,62830). * Instead by returning here, the baseband nf cal will * just be capped by our present noisefloor until the next * calibration timer. */ HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "%s: *** TIMEOUT while waiting for nf to load: " "AR_PHY_AGC_CONTROL=0x%x ***\n", __func__, OS_REG_READ(ah, AR_PHY_AGC_CONTROL)); return AH_FALSE; } /* * Restore max_cca_power register parameter again so that we're not capped * by the median we just loaded. This will be initial (and max) value * of next noise floor calibration the baseband does. */ for (i = 0; i < HAL_NUM_NF_READINGS; i++) { if (chainmask & (1 << i)) { val = OS_REG_READ(ah, ar9300_cca_regs[i]); val &= 0xFFFFFE00; val |= (((u_int32_t)(-50) << 1) & 0x1ff); OS_REG_WRITE(ah, ar9300_cca_regs[i], val); } } return AH_TRUE; } /* ar9300_per_calibration * Generic calibration routine. * Recalibrate the lower PHY chips to account for temperature/environment * changes. */ inline static void ar9300_per_calibration(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, u_int8_t rxchainmask, HAL_CAL_LIST *curr_cal, HAL_BOOL *is_cal_done) { struct ath_hal_9300 *ahp = AH9300(ah); /* Cal is assumed not done until explicitly set below */ *is_cal_done = AH_FALSE; /* Calibration in progress. */ if (curr_cal->cal_state == CAL_RUNNING) { /* Check to see if it has finished. */ if (!(OS_REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { int i, num_chains = 0; for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (rxchainmask & (1 << i)) { num_chains++; } } /* * Accumulate cal measures for active chains */ curr_cal->cal_data->cal_collect(ah, num_chains); ahp->ah_cal_samples++; if (ahp->ah_cal_samples >= curr_cal->cal_data->cal_num_samples) { /* * Process accumulated data */ curr_cal->cal_data->cal_post_proc(ah, num_chains); /* Calibration has finished. */ ichan->calValid |= curr_cal->cal_data->cal_type; curr_cal->cal_state = CAL_DONE; *is_cal_done = AH_TRUE; } else { /* Set-up collection of another sub-sample until we * get desired number */ ar9300_setup_calibration(ah, curr_cal); } } } else if (!(ichan->calValid & curr_cal->cal_data->cal_type)) { /* If current cal is marked invalid in channel, kick it off */ ar9300_reset_calibration(ah, curr_cal); } } static void ar9300_start_nf_cal(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF); OS_REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); AH9300(ah)->nf_tsf32 = ar9300_get_tsf32(ah); /* * We are reading the NF values before we start the NF operation, because * of that we are getting very high values like -45. * This triggers the CW_INT detected and EACS module triggers the channel change * chip_reset_done value is used to fix this issue. * chip_reset_flag is set during the RTC reset. * chip_reset_flag is cleared during the starting NF operation. * if flag is set we will clear the flag and will not read the NF values. */ ahp->ah_chip_reset_done = 0; } /* ar9300_calibration * Wrapper for a more generic Calibration routine. Primarily to abstract to * upper layers whether there is 1 or more calibrations to be run. */ HAL_BOOL ar9300_calibration(struct ath_hal *ah, struct ieee80211_channel *chan, u_int8_t rxchainmask, HAL_BOOL do_nf_cal, HAL_BOOL *is_cal_done, int is_scan, u_int32_t *sched_cals) { struct ath_hal_9300 *ahp = AH9300(ah); HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr; HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); int16_t nf_buf[HAL_NUM_NF_READINGS]; *is_cal_done = AH_TRUE; /* XXX: For initial wasp bringup - disable periodic calibration */ /* Invalid channel check */ if (ichan == AH_NULL) { HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); return AH_FALSE; } HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Entering, Doing NF Cal = %d\n", __func__, do_nf_cal); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 0 Rx IQ Cal Correction 0x%08x\n", __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); if (!AR_SREV_HORNET(ah) && !AR_SREV_POSEIDON(ah) && !AR_SREV_APHRODITE(ah)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 1 Rx IQ Cal Correction 0x%08x\n", __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B1)); if (!AR_SREV_WASP(ah) && !AR_SREV_JUPITER(ah)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Chain 2 Rx IQ Cal Correction 0x%08x\n", __func__, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B2)); } } OS_MARK(ah, AH_MARK_PERCAL, chan->ic_freq); /* For given calibration: * 1. Call generic cal routine * 2. When this cal is done (is_cal_done) if we have more cals waiting * (eg after reset), mask this to upper layers by not propagating * is_cal_done if it is set to TRUE. * Instead, change is_cal_done to FALSE and setup the waiting cal(s) * to be run. */ if (curr_cal && (curr_cal->cal_data->cal_type & *sched_cals) && (curr_cal->cal_state == CAL_RUNNING || curr_cal->cal_state == CAL_WAITING)) { ar9300_per_calibration(ah, ichan, rxchainmask, curr_cal, is_cal_done); if (*is_cal_done == AH_TRUE) { ahp->ah_cal_list_curr = curr_cal = curr_cal->cal_next; if (curr_cal && curr_cal->cal_state == CAL_WAITING) { *is_cal_done = AH_FALSE; ar9300_reset_calibration(ah, curr_cal); } else { *sched_cals &= ~IQ_MISMATCH_CAL; } } } /* Do NF cal only at longer intervals */ if (do_nf_cal) { int nf_done; /* Get the value from the previous NF cal and update history buffer */ nf_done = ar9300_store_new_nf(ah, chan, is_scan); #if 0 if (ichan->channel_flags & CHANNEL_CW_INT) { chan->channel_flags |= CHANNEL_CW_INT; } #endif chan->ic_state &= ~IEEE80211_CHANSTATE_CWINT; if (nf_done) { /* * Load the NF from history buffer of the current channel. * NF is slow time-variant, so it is OK to use a historical value. */ ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); ar9300_load_nf(ah, nf_buf); /* start NF calibration, without updating BB NF register*/ ar9300_start_nf_cal(ah); } } return AH_TRUE; } /* ar9300_iq_cal_collect * Collect data from HW to later perform IQ Mismatch Calibration */ void ar9300_iq_cal_collect(struct ath_hal *ah, u_int8_t num_chains) { struct ath_hal_9300 *ahp = AH9300(ah); int i; /* * Accumulate IQ cal measures for active chains */ for (i = 0; i < num_chains; i++) { ahp->ah_total_power_meas_i[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); ahp->ah_total_power_meas_q[i] = OS_REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); ahp->ah_total_iq_corr_meas[i] = (int32_t) OS_REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%d: Chn %d " "Reg Offset(0x%04x)pmi=0x%08x; " "Reg Offset(0x%04x)pmq=0x%08x; " "Reg Offset (0x%04x)iqcm=0x%08x;\n", ahp->ah_cal_samples, i, (unsigned) AR_PHY_CAL_MEAS_0(i), ahp->ah_total_power_meas_i[i], (unsigned) AR_PHY_CAL_MEAS_1(i), ahp->ah_total_power_meas_q[i], (unsigned) AR_PHY_CAL_MEAS_2(i), ahp->ah_total_iq_corr_meas[i]); } } /* ar9300_iq_calibration * Use HW data to perform IQ Mismatch Calibration */ void ar9300_iq_calibration(struct ath_hal *ah, u_int8_t num_chains) { struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t power_meas_q, power_meas_i, iq_corr_meas; u_int32_t q_coff_denom, i_coff_denom; int32_t q_coff, i_coff; int iq_corr_neg, i; HAL_CHANNEL_INTERNAL *ichan; static const u_int32_t offset_array[3] = { AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B1, AR_PHY_RX_IQCAL_CORR_B2, }; ichan = ath_hal_checkchannel(ah, AH_PRIVATE(ah)->ah_curchan); for (i = 0; i < num_chains; i++) { power_meas_i = ahp->ah_total_power_meas_i[i]; power_meas_q = ahp->ah_total_power_meas_q[i]; iq_corr_meas = ahp->ah_total_iq_corr_meas[i]; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Starting IQ Cal and Correction for Chain %d\n", i); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Orignal: Chn %diq_corr_meas = 0x%08x\n", i, ahp->ah_total_iq_corr_meas[i]); iq_corr_neg = 0; /* iq_corr_meas is always negative. */ if (iq_corr_meas > 0x80000000) { iq_corr_meas = (0xffffffff - iq_corr_meas) + 1; iq_corr_neg = 1; } HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Chn %d pwr_meas_i = 0x%08x\n", i, power_meas_i); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Chn %d pwr_meas_q = 0x%08x\n", i, power_meas_q); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "iq_corr_neg is 0x%08x\n", iq_corr_neg); i_coff_denom = (power_meas_i / 2 + power_meas_q / 2) / 256; q_coff_denom = power_meas_q / 64; /* Protect against divide-by-0 */ if ((i_coff_denom != 0) && (q_coff_denom != 0)) { /* IQ corr_meas is already negated if iqcorr_neg == 1 */ i_coff = iq_corr_meas / i_coff_denom; q_coff = power_meas_i / q_coff_denom - 64; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Chn %d i_coff = 0x%08x\n", i, i_coff); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Chn %d q_coff = 0x%08x\n", i, q_coff); /* Force bounds on i_coff */ if (i_coff >= 63) { i_coff = 63; } else if (i_coff <= -63) { i_coff = -63; } /* Negate i_coff if iq_corr_neg == 0 */ if (iq_corr_neg == 0x0) { i_coff = -i_coff; } /* Force bounds on q_coff */ if (q_coff >= 63) { q_coff = 63; } else if (q_coff <= -63) { q_coff = -63; } i_coff = i_coff & 0x7f; q_coff = q_coff & 0x7f; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Chn %d : i_coff = 0x%x q_coff = 0x%x\n", i, i_coff, q_coff); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Register offset (0x%04x) before update = 0x%x\n", offset_array[i], OS_REG_READ(ah, offset_array[i])); OS_REG_RMW_FIELD(ah, offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff); OS_REG_RMW_FIELD(ah, offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff); /* store the RX cal results */ if (ichan != NULL) { ahp->ah_rx_cal_corr[i] = OS_REG_READ(ah, offset_array[i]) & 0x7fff; ahp->ah_rx_cal_complete = AH_TRUE; ahp->ah_rx_cal_chan = ichan->channel; // ahp->ah_rx_cal_chan_flag = ichan->channel_flags &~ CHANNEL_PASSIVE; ahp->ah_rx_cal_chan_flag = 0; /* XXX */ } else { /* XXX? Is this what I should do? */ ahp->ah_rx_cal_complete = AH_FALSE; } HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Register offset (0x%04x) QI COFF (bitfields 0x%08x) " "after update = 0x%x\n", offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, OS_REG_READ(ah, offset_array[i])); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Register offset (0x%04x) QQ COFF (bitfields 0x%08x) " "after update = 0x%x\n", offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, OS_REG_READ(ah, offset_array[i])); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "IQ Cal and Correction done for Chain %d\n", i); } } OS_REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "IQ Cal and Correction (offset 0x%04x) enabled " "(bit position 0x%08x). New Value 0x%08x\n", (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); } /* * When coming back from offchan, we do not perform RX IQ Cal. * But the chip reset will clear all previous results * We store the previous results and restore here. */ static void ar9300_rx_iq_cal_restore(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t i_coff, q_coff; HAL_BOOL is_restore = AH_FALSE; int i; static const u_int32_t offset_array[3] = { AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B1, AR_PHY_RX_IQCAL_CORR_B2, }; for (i=0; iah_rx_cal_corr[i]) { i_coff = (ahp->ah_rx_cal_corr[i] & AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF) >> AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF_S; q_coff = (ahp->ah_rx_cal_corr[i] & AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF) >> AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF_S; OS_REG_RMW_FIELD(ah, offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_I_COFF, i_coff); OS_REG_RMW_FIELD(ah, offset_array[i], AR_PHY_RX_IQCAL_CORR_IQCORR_Q_Q_COFF, q_coff); is_restore = AH_TRUE; } } if (is_restore) OS_REG_SET_BIT(ah, AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: IQ Cal and Correction (offset 0x%04x) enabled " "(bit position 0x%08x). New Value 0x%08x\n", __func__, (unsigned) (AR_PHY_RX_IQCAL_CORR_B0), AR_PHY_RX_IQCAL_CORR_IQCORR_ENABLE, OS_REG_READ(ah, AR_PHY_RX_IQCAL_CORR_B0)); } /* * Set a limit on the overall output power. Used for dynamic * transmit power control and the like. * * NB: limit is in units of 0.5 dbM. */ HAL_BOOL ar9300_set_tx_power_limit(struct ath_hal *ah, u_int32_t limit, u_int16_t extra_txpow, u_int16_t tpc_in_db) { struct ath_hal_9300 *ahp = AH9300(ah); struct ath_hal_private *ahpriv = AH_PRIVATE(ah); const struct ieee80211_channel *chan = ahpriv->ah_curchan; HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); if (NULL == chan) { return AH_FALSE; } ahpriv->ah_powerLimit = AH_MIN(limit, MAX_RATE_POWER); ahpriv->ah_extraTxPow = extra_txpow; if(chan == NULL) { return AH_FALSE; } if (ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan, ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), ath_hal_get_twice_max_regpower(ahpriv, ichan, chan), AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)) != HAL_OK) { return AH_FALSE; } return AH_TRUE; } /* * Exported call to check for a recent gain reading and return * the current state of the thermal calibration gain engine. */ HAL_RFGAIN ar9300_get_rfgain(struct ath_hal *ah) { return HAL_RFGAIN_INACTIVE; } #define HAL_GREEN_AP_RX_MASK 0x1 static inline void ar9300_init_chain_masks(struct ath_hal *ah, int rx_chainmask, int tx_chainmask) { if (AH9300(ah)->green_ap_ps_on) { rx_chainmask = HAL_GREEN_AP_RX_MASK; } if (rx_chainmask == 0x5) { OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); } OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); /* * Adaptive Power Management: * Some 3 stream chips exceed the PCIe power requirements. * This workaround will reduce power consumption by using 2 tx chains * for 1 and 2 stream rates (5 GHz only). * * Set the self gen mask to 2 tx chains when APM is enabled. * */ if (AH_PRIVATE(ah)->ah_caps.halApmEnable && (tx_chainmask == 0x7)) { OS_REG_WRITE(ah, AR_SELFGEN_MASK, 0x3); } else { OS_REG_WRITE(ah, AR_SELFGEN_MASK, tx_chainmask); } if (tx_chainmask == 0x5) { OS_REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP, AR_PHY_SWAP_ALT_CHAIN); } } /* * Override INI values with chip specific configuration. */ static inline void ar9300_override_ini(struct ath_hal *ah, struct ieee80211_channel *chan) { u_int32_t val; HAL_CAPABILITIES *p_cap = &AH_PRIVATE(ah)->ah_caps; /* * Set the RX_ABORT and RX_DIS and clear it only after * RXE is set for MAC. This prevents frames with * corrupted descriptor status. */ OS_REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); /* * For Merlin and above, there is a new feature that allows Multicast * search based on both MAC Address and Key ID. * By default, this feature is enabled. * But since the driver is not using this feature, we switch it off; * otherwise multicast search based on MAC addr only will fail. */ val = OS_REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE); OS_REG_WRITE(ah, AR_PCU_MISC_MODE2, val | AR_BUG_58603_FIX_ENABLE | AR_AGG_WEP_ENABLE); /* Osprey revision specific configuration */ /* Osprey 2.0+ - if SW RAC support is disabled, must also disable * the Osprey 2.0 hardware RAC fix. */ if (p_cap->halIsrRacSupport == AH_FALSE) { OS_REG_CLR_BIT(ah, AR_CFG, AR_CFG_MISSING_TX_INTR_FIX_ENABLE); } /* try to enable old pal if it is needed for h/w green tx */ ar9300_hwgreentx_set_pal_spare(ah, 1); } static inline void ar9300_prog_ini(struct ath_hal *ah, struct ar9300_ini_array *ini_arr, int column) { int i, reg_writes = 0; /* New INI format: Array may be undefined (pre, core, post arrays) */ if (ini_arr->ia_array == NULL) { return; } /* * New INI format: Pre, core, and post arrays for a given subsystem may be * modal (> 2 columns) or non-modal (2 columns). * Determine if the array is non-modal and force the column to 1. */ if (column >= ini_arr->ia_columns) { column = 1; } for (i = 0; i < ini_arr->ia_rows; i++) { u_int32_t reg = INI_RA(ini_arr, i, 0); u_int32_t val = INI_RA(ini_arr, i, column); /* ** Determine if this is a shift register value ** (reg >= 0x16000 && reg < 0x17000 for Osprey) , ** and insert the configured delay if so. ** -this delay is not required for Osprey (EV#71410) */ OS_REG_WRITE(ah, reg, val); WAR_6773(reg_writes); } } static inline HAL_STATUS ar9300_process_ini(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_CHANNEL_INTERNAL *ichan, HAL_HT_MACMODE macmode) { int reg_writes = 0; struct ath_hal_9300 *ahp = AH9300(ah); u_int modes_index, modes_txgaintable_index = 0; int i; HAL_STATUS status; struct ath_hal_private *ahpriv = AH_PRIVATE(ah); /* Setup the indices for the next set of register array writes */ /* TODO: * If the channel marker is indicative of the current mode rather * than capability, we do not need to check the phy mode below. */ #if 0 switch (chan->channel_flags & CHANNEL_ALL) { case CHANNEL_A: case CHANNEL_A_HT20: if (AR_SREV_SCORPION(ah)){ if (chan->channel <= 5350){ modes_txgaintable_index = 1; }else if ((chan->channel > 5350) && (chan->channel <= 5600)){ modes_txgaintable_index = 3; }else if (chan->channel > 5600){ modes_txgaintable_index = 5; } } modes_index = 1; break; case CHANNEL_A_HT40PLUS: case CHANNEL_A_HT40MINUS: if (AR_SREV_SCORPION(ah)){ if (chan->channel <= 5350){ modes_txgaintable_index = 2; }else if ((chan->channel > 5350) && (chan->channel <= 5600)){ modes_txgaintable_index = 4; }else if (chan->channel > 5600){ modes_txgaintable_index = 6; } } modes_index = 2; break; case CHANNEL_PUREG: case CHANNEL_G_HT20: case CHANNEL_B: if (AR_SREV_SCORPION(ah)){ modes_txgaintable_index = 8; } modes_index = 4; break; case CHANNEL_G_HT40PLUS: case CHANNEL_G_HT40MINUS: if (AR_SREV_SCORPION(ah)){ modes_txgaintable_index = 7; } modes_index = 3; break; case CHANNEL_108G: modes_index = 5; break; default: HALASSERT(0); return HAL_EINVAL; } #endif /* FreeBSD */ if (IS_CHAN_5GHZ(ichan)) { if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) { if (AR_SREV_SCORPION(ah)){ if (ichan->channel <= 5350){ modes_txgaintable_index = 2; }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){ modes_txgaintable_index = 4; }else if (ichan->channel > 5600){ modes_txgaintable_index = 6; } } modes_index = 2; } else if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_HT20(chan)) { if (AR_SREV_SCORPION(ah)){ if (ichan->channel <= 5350){ modes_txgaintable_index = 1; }else if ((ichan->channel > 5350) && (ichan->channel <= 5600)){ modes_txgaintable_index = 3; }else if (ichan->channel > 5600){ modes_txgaintable_index = 5; } } modes_index = 1; } else return HAL_EINVAL; } else if (IS_CHAN_2GHZ(ichan)) { if (IEEE80211_IS_CHAN_108G(chan)) { modes_index = 5; } else if (IEEE80211_IS_CHAN_HT40U(chan) || IEEE80211_IS_CHAN_HT40D(chan)) { if (AR_SREV_SCORPION(ah)){ modes_txgaintable_index = 7; } modes_index = 3; } else if (IEEE80211_IS_CHAN_HT20(chan) || IEEE80211_IS_CHAN_G(chan) || IEEE80211_IS_CHAN_B(chan) || IEEE80211_IS_CHAN_PUREG(chan)) { if (AR_SREV_SCORPION(ah)){ modes_txgaintable_index = 8; } modes_index = 4; } else return HAL_EINVAL; } else return HAL_EINVAL; #if 0 /* Set correct Baseband to analog shift setting to access analog chips. */ OS_REG_WRITE(ah, AR_PHY(0), 0x00000007); #endif HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: " "Skipping OS-REG-WRITE(ah, AR-PHY(0), 0x00000007)\n"); HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: no ADDac programming\n"); /* * Osprey 2.0+ - new INI format. * Each subsystem has a pre, core, and post array. */ for (i = 0; i < ATH_INI_NUM_SPLIT; i++) { ar9300_prog_ini(ah, &ahp->ah_ini_soc[i], modes_index); ar9300_prog_ini(ah, &ahp->ah_ini_mac[i], modes_index); ar9300_prog_ini(ah, &ahp->ah_ini_bb[i], modes_index); ar9300_prog_ini(ah, &ahp->ah_ini_radio[i], modes_index); if ((i == ATH_INI_POST) && (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah))) { ar9300_prog_ini(ah, &ahp->ah_ini_radio_post_sys2ant, modes_index); } } if (!(AR_SREV_SOC(ah))) { /* Doubler issue : Some board doesn't work well with MCS15. Turn off doubler after freq locking is complete*/ //ath_hal_printf(ah, "%s[%d] ==== before reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ //ath_hal_printf(ah, "%s[%d] ==== after reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S, 0); /*Set synthon, synthover */ OS_DELAY(200); //ath_hal_printf(ah, "%s[%d] ==== before reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK); /* clr synthon */ //ath_hal_printf(ah, "%s[%d] ==== after reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); OS_DELAY(1); //ath_hal_printf(ah, "%s[%d] ==== before reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX2, AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK, 1); /* set synthon */ //ath_hal_printf(ah, "%s[%d] ==== after reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); OS_DELAY(200); //ath_hal_printf(ah, "%s[%d] ==== before reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_SYNTH12, OS_REG_READ(ah, AR_PHY_65NM_CH0_SYNTH12)); OS_REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_SYNTH12, AR_PHY_65NM_CH0_SYNTH12_VREFMUL3, 0xf); //OS_REG_CLR_BIT(ah, AR_PHY_65NM_CH0_SYNTH12, 1<< 16); /* clr charge pump */ //ath_hal_printf(ah, "%s[%d] ==== After reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_SYNTH12, OS_REG_READ(ah, AR_PHY_65NM_CH0_SYNTH12)); OS_REG_RMW(ah, AR_PHY_65NM_CH0_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ OS_REG_RMW(ah, AR_PHY_65NM_CH1_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ OS_REG_RMW(ah, AR_PHY_65NM_CH2_RXTX2, 0, 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK_S | 1 << AR_PHY_65NM_CH0_RXTX2_SYNTHOVR_MASK_S); /*Clr synthon, synthover */ //ath_hal_printf(ah, "%s[%d] ==== after reg[0x%08x] = 0x%08x\n", __func__, __LINE__, AR_PHY_65NM_CH0_RXTX2, OS_REG_READ(ah, AR_PHY_65NM_CH0_RXTX2)); } /* Write rxgain Array Parameters */ REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain, 1, reg_writes); HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain programming\n"); if (AR_SREV_SCORPION(ah)) { /* Write rxgain bounds Array */ REG_WRITE_ARRAY(&ahp->ah_ini_modes_rxgain_bounds, modes_index, reg_writes); HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Rx Gain table bounds programming\n"); } /* UB124 xLNA settings */ if (AR_SREV_WASP(ah) && ar9300_rx_gain_index_get(ah) == 2) { #define REG_WRITE(_reg,_val) *((volatile u_int32_t *)(_reg)) = (_val); #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) u_int32_t val; /* B8040000: bit[0]=0, bit[3]=0; */ val = REG_READ(0xB8040000); val &= 0xfffffff6; REG_WRITE(0xB8040000, val); /* B804002c: bit[31:24]=0x2e; bit[7:0]=0x2f; */ val = REG_READ(0xB804002c); val &= 0x00ffff00; val |= 0x2e00002f; REG_WRITE(0xB804002c, val); /* B804006c: bit[1]=1; */ val = REG_READ(0xB804006c); val |= 0x2; REG_WRITE(0xB804006c, val); #undef REG_READ #undef REG_WRITE } /* Write txgain Array Parameters */ if (AR_SREV_SCORPION(ah)) { REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_txgaintable_index, reg_writes); }else{ REG_WRITE_ARRAY(&ahp->ah_ini_modes_txgain, modes_index, reg_writes); } HALDEBUG(ah, HAL_DEBUG_RESET, "ar9300_process_ini: Tx Gain programming\n"); /* For 5GHz channels requiring Fast Clock, apply different modal values */ if (IS_5GHZ_FAST_CLOCK_EN(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Fast clock enabled, use special ini values\n", __func__); REG_WRITE_ARRAY(&ahp->ah_ini_modes_additional, modes_index, reg_writes); } if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: use xtal ini for AH9300(ah)->clk_25mhz: %d\n", __func__, AH9300(ah)->clk_25mhz); REG_WRITE_ARRAY( &ahp->ah_ini_modes_additional, 1/*modes_index*/, reg_writes); } if (AR_SREV_WASP(ah) && (AH9300(ah)->clk_25mhz == 0)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Apply 40MHz ini settings\n", __func__); REG_WRITE_ARRAY( &ahp->ah_ini_modes_additional_40mhz, 1/*modesIndex*/, reg_writes); } /* Handle Japan Channel 14 channel spreading */ if (2484 == ichan->channel) { ar9300_prog_ini(ah, &ahp->ah_ini_japan2484, 1); } #if 0 if (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah)) { ar9300_prog_ini(ah, &ahp->ah_ini_BTCOEX_MAX_TXPWR, 1); } #endif /* Override INI with chip specific configuration */ ar9300_override_ini(ah, chan); /* Setup 11n MAC/Phy mode registers */ ar9300_set_11n_regs(ah, chan, macmode); /* * Moved ar9300_init_chain_masks() here to ensure the swap bit is set before * the pdadc table is written. Swap must occur before any radio dependent * replicated register access. The pdadc curve addressing in particular * depends on the consistent setting of the swap bit. */ ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask); /* * Setup the transmit power values. * * After the public to private hal channel mapping, ichan contains the * valid regulatory power value. * ath_hal_getctl and ath_hal_getantennaallowed look up ichan from chan. */ status = ar9300_eeprom_set_transmit_power(ah, &ahp->ah_eeprom, chan, ath_hal_getctl(ah, chan), ath_hal_getantennaallowed(ah, chan), ath_hal_get_twice_max_regpower(ahpriv, ichan, chan), AH_MIN(MAX_RATE_POWER, ahpriv->ah_powerLimit)); if (status != HAL_OK) { HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: error init'ing transmit power\n", __func__); return HAL_EIO; } return HAL_OK; #undef N } /* ar9300_is_cal_supp * Determine if calibration is supported by device and channel flags */ inline static HAL_BOOL ar9300_is_cal_supp(struct ath_hal *ah, const struct ieee80211_channel *chan, HAL_CAL_TYPES cal_type) { struct ath_hal_9300 *ahp = AH9300(ah); HAL_BOOL retval = AH_FALSE; switch (cal_type & ahp->ah_supp_cals) { case IQ_MISMATCH_CAL: /* Run IQ Mismatch for non-CCK only */ if (!IEEE80211_IS_CHAN_B(chan)) { retval = AH_TRUE; } break; case TEMP_COMP_CAL: retval = AH_TRUE; break; } return retval; } #if 0 /* ar9285_pa_cal * PA Calibration for Kite 1.1 and later versions of Kite. * - from system's team. */ static inline void ar9285_pa_cal(struct ath_hal *ah) { u_int32_t reg_val; int i, lo_gn, offs_6_1, offs_0; u_int8_t reflo; u_int32_t phy_test2_reg_val, phy_adc_ctl_reg_val; u_int32_t an_top2_reg_val, phy_tst_dac_reg_val; /* Kite 1.1 WAR for Bug 35666 * Increase the LDO value to 1.28V before accessing analog Reg */ if (AR_SREV_KITE_11(ah)) { OS_REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14) ); } an_top2_reg_val = OS_REG_READ(ah, AR9285_AN_TOP2); /* set pdv2i pdrxtxbb */ reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1); reg_val |= ((0x1 << 5) | (0x1 << 7)); OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val); /* clear pwddb */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G7); reg_val &= 0xfffffffd; OS_REG_WRITE(ah, AR9285_AN_RF2G7, reg_val); /* clear enpacal */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); reg_val &= 0xfffff7ff; OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); /* set offcal */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2); reg_val |= (0x1 << 12); OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val); /* set pdpadrv1=pdpadrv2=pdpaout=1 */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); reg_val |= (0x7 << 23); OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); /* Read back reflo, increase it by 1 and write it. */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); reflo = ((reg_val >> 26) & 0x7); if (reflo < 0x7) { reflo++; } reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26)); OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); reflo = ((reg_val >> 26) & 0x7); /* use TX single carrier to transmit * dac const * reg. 15 */ phy_tst_dac_reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST); OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, ((0x7ff << 11) | 0x7ff)); reg_val = OS_REG_READ(ah, AR_PHY_TSTDAC_CONST); /* source is dac const * reg. 2 */ phy_test2_reg_val = OS_REG_READ(ah, AR_PHY_TEST2); OS_REG_WRITE(ah, AR_PHY_TEST2, ((0x1 << 7) | (0x1 << 1))); reg_val = OS_REG_READ(ah, AR_PHY_TEST2); /* set dac on * reg. 11 */ phy_adc_ctl_reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL); OS_REG_WRITE(ah, AR_PHY_ADC_CTL, 0x80008000); reg_val = OS_REG_READ(ah, AR_PHY_ADC_CTL); OS_REG_WRITE(ah, AR9285_AN_TOP2, (0x1 << 27) | (0x1 << 17) | (0x1 << 16) | (0x1 << 14) | (0x1 << 12) | (0x1 << 11) | (0x1 << 7) | (0x1 << 5)); OS_DELAY(10); /* 10 usec */ /* clear off[6:0] */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); reg_val &= 0xfc0fffff; OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); reg_val &= 0xfdffffff; OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); offs_6_1 = 0; for (i = 6; i > 0; i--) { /* sef off[$k]==1 */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); reg_val &= 0xfc0fffff; reg_val = reg_val | (0x1 << (19 + i)) | ((offs_6_1) << 20); OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); lo_gn = (OS_REG_READ(ah, AR9285_AN_RF2G9)) & 0x1; offs_6_1 = offs_6_1 | (lo_gn << (i - 1)); } reg_val = OS_REG_READ(ah, AR9285_AN_RF2G6); reg_val &= 0xfc0fffff; reg_val = reg_val | ((offs_6_1 - 1) << 20); OS_REG_WRITE(ah, AR9285_AN_RF2G6, reg_val); /* set off_0=1; */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); reg_val &= 0xfdffffff; reg_val = reg_val | (0x1 << 25); OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); lo_gn = OS_REG_READ(ah, AR9285_AN_RF2G9) & 0x1; offs_0 = lo_gn; reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); reg_val &= 0xfdffffff; reg_val = reg_val | (offs_0 << 25); OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); /* clear pdv2i */ reg_val = OS_REG_READ(ah, AR9285_AN_RXTXBB1); reg_val &= 0xffffff5f; OS_REG_WRITE(ah, AR9285_AN_RXTXBB1, reg_val); /* set enpacal */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); reg_val |= (0x1 << 11); OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); /* clear offcal */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G2); reg_val &= 0xffffefff; OS_REG_WRITE(ah, AR9285_AN_RF2G2, reg_val); /* set pdpadrv1=pdpadrv2=pdpaout=0 */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G1); reg_val &= 0xfc7fffff; OS_REG_WRITE(ah, AR9285_AN_RF2G1, reg_val); /* Read back reflo, decrease it by 1 and write it. */ reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); reflo = (reg_val >> 26) & 0x7; if (reflo) { reflo--; } reg_val = ((reg_val & 0xe3ffffff) | (reflo << 26)); OS_REG_WRITE(ah, AR9285_AN_RF2G3, reg_val); reg_val = OS_REG_READ(ah, AR9285_AN_RF2G3); reflo = (reg_val >> 26) & 0x7; /* write back registers */ OS_REG_WRITE(ah, AR_PHY_TSTDAC_CONST, phy_tst_dac_reg_val); OS_REG_WRITE(ah, AR_PHY_TEST2, phy_test2_reg_val); OS_REG_WRITE(ah, AR_PHY_ADC_CTL, phy_adc_ctl_reg_val); OS_REG_WRITE(ah, AR9285_AN_TOP2, an_top2_reg_val); /* Kite 1.1 WAR for Bug 35666 * Decrease the LDO value back to 1.20V */ if (AR_SREV_KITE_11(ah)) { OS_REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); } } #endif /* ar9300_run_init_cals * Runs non-periodic calibrations */ inline static HAL_BOOL ar9300_run_init_cals(struct ath_hal *ah, int init_cal_count) { struct ath_hal_9300 *ahp = AH9300(ah); HAL_CHANNEL_INTERNAL ichan; /* bogus */ HAL_BOOL is_cal_done; HAL_CAL_LIST *curr_cal; const HAL_PERCAL_DATA *cal_data; int i; curr_cal = ahp->ah_cal_list_curr; if (curr_cal == AH_NULL) { return AH_FALSE; } cal_data = curr_cal->cal_data; ichan.calValid = 0; for (i = 0; i < init_cal_count; i++) { /* Reset this Cal */ ar9300_reset_calibration(ah, curr_cal); /* Poll for offset calibration complete */ if (!ath_hal_wait( ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Cal %d failed to complete in 100ms.\n", __func__, curr_cal->cal_data->cal_type); /* Re-initialize list pointers for periodic cals */ ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; return AH_FALSE; } /* Run this cal */ ar9300_per_calibration( ah, &ichan, ahp->ah_rx_chainmask, curr_cal, &is_cal_done); if (is_cal_done == AH_FALSE) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Not able to run Init Cal %d.\n", __func__, curr_cal->cal_data->cal_type); } if (curr_cal->cal_next) { curr_cal = curr_cal->cal_next; } } /* Re-initialize list pointers for periodic cals */ ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; return AH_TRUE; } #if 0 static void ar9300_tx_carrier_leak_war(struct ath_hal *ah) { unsigned long tx_gain_table_max; unsigned long reg_bb_cl_map_0_b0 = 0xffffffff; unsigned long reg_bb_cl_map_1_b0 = 0xffffffff; unsigned long reg_bb_cl_map_2_b0 = 0xffffffff; unsigned long reg_bb_cl_map_3_b0 = 0xffffffff; unsigned long tx_gain, cal_run = 0; unsigned long cal_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; unsigned long cal_gain_index[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; unsigned long new_gain[AR_PHY_TPC_7_TX_GAIN_TABLE_MAX + 1]; int i, j; OS_MEMSET(new_gain, 0, sizeof(new_gain)); /*printf(" Running TxCarrierLeakWAR\n");*/ /* process tx gain table, we use cl_map_hw_gen=0. */ OS_REG_RMW_FIELD(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_MAP_HW_GEN, 0); //the table we used is txbb_gc[2:0], 1dB[2:1]. tx_gain_table_max = OS_REG_READ_FIELD(ah, AR_PHY_TPC_7, AR_PHY_TPC_7_TX_GAIN_TABLE_MAX); for (i = 0; i <= tx_gain_table_max; i++) { tx_gain = OS_REG_READ(ah, AR_PHY_TXGAIN_TAB(1) + i * 4); cal_gain[i] = (((tx_gain >> 5)& 0x7) << 2) | (((tx_gain >> 1) & 0x3) << 0); if (i == 0) { cal_gain_index[i] = cal_run; new_gain[i] = 1; cal_run++; } else { new_gain[i] = 1; for (j = 0; j < i; j++) { /* printf("i=%d, j=%d cal_gain[$i]=0x%04x\n", i, j, cal_gain[i]); */ if (new_gain[i]) { if ((cal_gain[i] != cal_gain[j])) { new_gain[i] = 1; } else { /* if old gain found, use old cal_run value. */ new_gain[i] = 0; cal_gain_index[i] = cal_gain_index[j]; } } } /* if new gain found, increase cal_run */ if (new_gain[i] == 1) { cal_gain_index[i] = cal_run; cal_run++; } } reg_bb_cl_map_0_b0 = (reg_bb_cl_map_0_b0 & ~(0x1 << i)) | ((cal_gain_index[i] >> 0 & 0x1) << i); reg_bb_cl_map_1_b0 = (reg_bb_cl_map_1_b0 & ~(0x1 << i)) | ((cal_gain_index[i] >> 1 & 0x1) << i); reg_bb_cl_map_2_b0 = (reg_bb_cl_map_2_b0 & ~(0x1 << i)) | ((cal_gain_index[i] >> 2 & 0x1) << i); reg_bb_cl_map_3_b0 = (reg_bb_cl_map_3_b0 & ~(0x1 << i)) | ((cal_gain_index[i] >> 3 & 0x1) << i); /* printf("i=%2d, cal_gain[$i]= 0x%04x, cal_run= %d, " "cal_gain_index[i]=%d, new_gain[i] = %d\n", i, cal_gain[i], cal_run, cal_gain_index[i], new_gain[i]); */ } OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B0, reg_bb_cl_map_0_b0); OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B0, reg_bb_cl_map_1_b0); OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B0, reg_bb_cl_map_2_b0); OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B0, reg_bb_cl_map_3_b0); if (AR_SREV_WASP(ah)) { OS_REG_WRITE(ah, AR_PHY_CL_MAP_0_B1, reg_bb_cl_map_0_b0); OS_REG_WRITE(ah, AR_PHY_CL_MAP_1_B1, reg_bb_cl_map_1_b0); OS_REG_WRITE(ah, AR_PHY_CL_MAP_2_B1, reg_bb_cl_map_2_b0); OS_REG_WRITE(ah, AR_PHY_CL_MAP_3_B1, reg_bb_cl_map_3_b0); } } #endif static inline void ar9300_invalidate_saved_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) { #if ATH_SUPPORT_CAL_REUSE if (AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse & ATH_CAL_REUSE_REDO_IN_FULL_RESET) { ichan->one_time_txiqcal_done = AH_FALSE; ichan->one_time_txclcal_done = AH_FALSE; } #endif } static inline HAL_BOOL ar9300_restore_rtt_cals(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) { HAL_BOOL restore_status = AH_FALSE; return restore_status; } /* ar9300_init_cal * Initialize Calibration infrastructure */ static inline HAL_BOOL ar9300_init_cal_internal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_CHANNEL_INTERNAL *ichan, HAL_BOOL enable_rtt, HAL_BOOL do_rtt_cal, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr) { struct ath_hal_9300 *ahp = AH9300(ah); HAL_BOOL txiqcal_success_flag = AH_FALSE; HAL_BOOL cal_done = AH_FALSE; int iqcal_idx = 0; HAL_BOOL do_sep_iq_cal = AH_FALSE; HAL_BOOL do_agc_cal = do_rtt_cal; HAL_BOOL is_cal_reusable = AH_TRUE; #if ATH_SUPPORT_CAL_REUSE HAL_BOOL cal_reuse_enable = AH_PRIVATE(ah)->ah_config.ath_hal_cal_reuse & ATH_CAL_REUSE_ENABLE; HAL_BOOL clc_success = AH_FALSE; int32_t ch_idx, j, cl_tab_reg; u_int32_t BB_cl_tab_entry = MAX_BB_CL_TABLE_ENTRY; u_int32_t BB_cl_tab_b[AR9300_MAX_CHAINS] = { AR_PHY_CL_TAB_0, AR_PHY_CL_TAB_1, AR_PHY_CL_TAB_2 }; #endif if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah) || AR_SREV_APHRODITE(ah)) { /* Hornet: 1 x 1 */ ahp->ah_rx_cal_chainmask = 0x1; ahp->ah_tx_cal_chainmask = 0x1; } else if (AR_SREV_WASP(ah) || AR_SREV_JUPITER(ah)) { /* Wasp/Jupiter: 2 x 2 */ ahp->ah_rx_cal_chainmask = 0x3; ahp->ah_tx_cal_chainmask = 0x3; } else { /* * Osprey needs to be configured for the correct chain mode * before running AGC/TxIQ cals. */ if (ahp->ah_enterprise_mode & AR_ENT_OTP_CHAIN2_DISABLE) { /* chain 2 disabled - 2 chain mode */ ahp->ah_rx_cal_chainmask = 0x3; ahp->ah_tx_cal_chainmask = 0x3; } else { ahp->ah_rx_cal_chainmask = 0x7; ahp->ah_tx_cal_chainmask = 0x7; } } ar9300_init_chain_masks(ah, ahp->ah_rx_cal_chainmask, ahp->ah_tx_cal_chainmask); if (ahp->tx_cl_cal_enable) { #if ATH_SUPPORT_CAL_REUSE /* disable Carrie Leak or set do_agc_cal accordingly */ if (cal_reuse_enable && ichan->one_time_txclcal_done) { OS_REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); } else #endif /* ATH_SUPPORT_CAL_REUSE */ { OS_REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE); do_agc_cal = AH_TRUE; } } /* Do Tx IQ Calibration here for osprey hornet and wasp */ /* XXX: For initial wasp bringup - check and enable this */ /* EV 74233: Tx IQ fails to complete for half/quarter rates */ if (!(IEEE80211_IS_CHAN_HALF(chan) || IEEE80211_IS_CHAN_QUARTER(chan))) { if (ahp->tx_iq_cal_enable) { /* this should be eventually moved to INI file */ OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1(ah), AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT); /* * For poseidon and later chips, * Tx IQ cal HW run will be a part of AGC calibration */ if (ahp->tx_iq_cal_during_agc_cal) { /* * txiqcal_success_flag always set to 1 to run * ar9300_tx_iq_cal_post_proc * if following AGC cal passes */ #if ATH_SUPPORT_CAL_REUSE if (!cal_reuse_enable || !ichan->one_time_txiqcal_done) { txiqcal_success_flag = AH_TRUE; OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) | AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); } else { OS_REG_WRITE(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), OS_REG_READ(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah)) & (~AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)); } #else if (OS_REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL)){ if (apply_last_iqcorr == AH_TRUE) { OS_REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); txiqcal_success_flag = AH_FALSE; } else { txiqcal_success_flag = AH_TRUE; } }else{ txiqcal_success_flag = AH_FALSE; } #endif if (txiqcal_success_flag) { do_agc_cal = AH_TRUE; } } else #if ATH_SUPPORT_CAL_REUSE if (!cal_reuse_enable || !ichan->one_time_txiqcal_done) #endif { do_sep_iq_cal = AH_TRUE; do_agc_cal = AH_TRUE; } } } #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport && IS_CHAN_2GHZ(ichan) && (ahp->ah_mci_bt_state == MCI_BT_AWAKE) && do_agc_cal && !(ah->ah_config.ath_hal_mci_config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) { u_int32_t payload[4] = {0, 0, 0, 0}; /* Send CAL_REQ only when BT is AWAKE. */ HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_REQ 0x%X\n", __func__, ahp->ah_mci_wlan_cal_seq); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_REQ); payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_seq++; ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); /* Wait BT_CAL_GRANT for 50ms */ HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Wait for BT_CAL_GRANT\n", __func__); if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_GRANT, 0, 50000)) { HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Got BT_CAL_GRANT.\n", __func__); } else { is_cal_reusable = AH_FALSE; HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: BT is not responding.\n", __func__); } } #endif /* ATH_SUPPORT_MCI */ if (do_sep_iq_cal) { /* enable Tx IQ Calibration HW for osprey/hornet/wasp */ txiqcal_success_flag = ar9300_tx_iq_cal_hw_run(ah); OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); OS_DELAY(5); OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); } #if 0 if (AR_SREV_HORNET(ah) || AR_SREV_POSEIDON(ah)) { ar9300_tx_carrier_leak_war(ah); } #endif /* * Calibrate the AGC * * Tx IQ cal is a part of AGC cal for Jupiter/Poseidon, etc. * please enable the bit of txiqcal_control_0[31] in INI file * for Jupiter/Poseidon/etc. */ if(!AR_SREV_SCORPION(ah)) { if (do_agc_cal || !skip_if_none) { OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); /* Poll for offset calibration complete */ cal_done = ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0); if (!cal_done) { HALDEBUG(ah, HAL_DEBUG_FCS_RTT, "(FCS) CAL NOT DONE!!! - %d\n", ichan->channel); } } else { cal_done = AH_TRUE; } /* * Tx IQ cal post-processing in SW * This part of code should be common to all chips, * no chip specific code for Jupiter/Posdeion except for register names. */ if (txiqcal_success_flag) { ar9300_tx_iq_cal_post_proc(ah,ichan, 1, 1,is_cal_reusable, AH_FALSE); } } else { if (!txiqcal_success_flag) { OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); if (!ath_hal_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: offset calibration failed to complete in 1ms; " "noisy environment?\n", __func__); return AH_FALSE; } if (apply_last_iqcorr == AH_TRUE) { ar9300_tx_iq_cal_post_proc(ah, ichan, 0, 0, is_cal_reusable, AH_TRUE); } } else { for (iqcal_idx=0;iqcal_idxah_caps.halMciSupport && IS_CHAN_2GHZ(ichan) && (ahp->ah_mci_bt_state == MCI_BT_AWAKE) && do_agc_cal && !(ah->ah_config.ath_hal_mci_config & ATH_MCI_CONFIG_DISABLE_MCI_CAL)) { u_int32_t payload[4] = {0, 0, 0, 0}; HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_DONE 0x%X\n", __func__, ahp->ah_mci_wlan_cal_done); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); payload[MCI_GPM_WLAN_CAL_W_SEQUENCE] = ahp->ah_mci_wlan_cal_done++; ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); } #endif /* ATH_SUPPORT_MCI */ if (!cal_done && !AR_SREV_SCORPION(ah) ) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: offset calibration failed to complete in 1ms; " "noisy environment?\n", __func__); return AH_FALSE; } #if 0 /* Beacon stuck fix, refer to EV 120056 */ if(IS_CHAN_2GHZ(chan) && AR_SREV_SCORPION(ah)) OS_REG_WRITE(ah, AR_PHY_TIMING5, OS_REG_READ(ah,AR_PHY_TIMING5) & ~AR_PHY_TIMING5_CYCPWR_THR1_ENABLE); #endif #if 0 /* Do PA Calibration */ if (AR_SREV_KITE(ah) && AR_SREV_KITE_11_OR_LATER(ah)) { ar9285_pa_cal(ah); } #endif #if ATH_SUPPORT_CAL_REUSE if (ichan->one_time_txiqcal_done) { ar9300_tx_iq_cal_apply(ah, ichan); HALDEBUG(ah, HAL_DEBUG_FCS_RTT, "(FCS) TXIQCAL applied - %d\n", ichan->channel); } #endif /* ATH_SUPPORT_CAL_REUSE */ #if ATH_SUPPORT_CAL_REUSE if (cal_reuse_enable && ahp->tx_cl_cal_enable) { clc_success = (OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_CLC_SUCCESS) ? 1 : 0; if (ichan->one_time_txclcal_done) { /* reapply CL cal results */ for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { continue; } cl_tab_reg = BB_cl_tab_b[ch_idx]; for (j = 0; j < BB_cl_tab_entry; j++) { OS_REG_WRITE(ah, cl_tab_reg, ichan->tx_clcal[ch_idx][j]); cl_tab_reg += 4;; } } HALDEBUG(ah, HAL_DEBUG_FCS_RTT, "(FCS) TX CL CAL applied - %d\n", ichan->channel); } else if (is_cal_reusable && clc_success) { /* save CL cal results */ for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { continue; } cl_tab_reg = BB_cl_tab_b[ch_idx]; for (j = 0; j < BB_cl_tab_entry; j++) { ichan->tx_clcal[ch_idx][j] = OS_REG_READ(ah, cl_tab_reg); cl_tab_reg += 4; } } ichan->one_time_txclcal_done = AH_TRUE; HALDEBUG(ah, HAL_DEBUG_FCS_RTT, "(FCS) TX CL CAL saved - %d\n", ichan->channel); } } #endif /* ATH_SUPPORT_CAL_REUSE */ /* Revert chainmasks to their original values before NF cal */ ar9300_init_chain_masks(ah, ahp->ah_rx_chainmask, ahp->ah_tx_chainmask); #if !FIX_NOISE_FLOOR /* * Do NF calibration after DC offset and other CALs. * Per system engineers, noise floor value can sometimes be 20 dB * higher than normal value if DC offset and noise floor cal are * triggered at the same time. */ OS_REG_WRITE(ah, AR_PHY_AGC_CONTROL, OS_REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF); #endif /* Initialize list pointers */ ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = AH_NULL; /* * Enable IQ, ADC Gain, ADC DC Offset Cals */ /* Setup all non-periodic, init time only calibrations */ /* XXX: Init DC Offset not working yet */ #ifdef not_yet if (AH_TRUE == ar9300_is_cal_supp(ah, chan, ADC_DC_INIT_CAL)) { INIT_CAL(&ahp->ah_adc_dc_cal_init_data); INSERT_CAL(ahp, &ahp->ah_adc_dc_cal_init_data); } /* Initialize current pointer to first element in list */ ahp->ah_cal_list_curr = ahp->ah_cal_list; if (ahp->ah_cal_list_curr) { if (ar9300_run_init_cals(ah, 0) == AH_FALSE) { return AH_FALSE; } } #endif /* end - Init time calibrations */ /* Do not do RX cal in case of offchan, or cal data already exists on same channel*/ if (ahp->ah_skip_rx_iq_cal) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Skip RX IQ Cal\n"); return AH_TRUE; } /* If Cals are supported, add them to list via INIT/INSERT_CAL */ if (AH_TRUE == ar9300_is_cal_supp(ah, chan, IQ_MISMATCH_CAL)) { INIT_CAL(&ahp->ah_iq_cal_data); INSERT_CAL(ahp, &ahp->ah_iq_cal_data); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: enabling IQ Calibration.\n", __func__); } if (AH_TRUE == ar9300_is_cal_supp(ah, chan, TEMP_COMP_CAL)) { INIT_CAL(&ahp->ah_temp_comp_cal_data); INSERT_CAL(ahp, &ahp->ah_temp_comp_cal_data); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: enabling Temperature Compensation Calibration.\n", __func__); } /* Initialize current pointer to first element in list */ ahp->ah_cal_list_curr = ahp->ah_cal_list; /* Reset state within current cal */ if (ahp->ah_cal_list_curr) { ar9300_reset_calibration(ah, ahp->ah_cal_list_curr); } /* Mark all calibrations on this channel as being invalid */ ichan->calValid = 0; return AH_TRUE; } static inline HAL_BOOL ar9300_init_cal(struct ath_hal *ah, struct ieee80211_channel *chan, HAL_BOOL skip_if_none, HAL_BOOL apply_last_iqcorr) { HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); HAL_BOOL do_rtt_cal = AH_TRUE; HAL_BOOL enable_rtt = AH_FALSE; HALASSERT(ichan); return ar9300_init_cal_internal(ah, chan, ichan, enable_rtt, do_rtt_cal, skip_if_none, apply_last_iqcorr); } /* ar9300_reset_cal_valid * Entry point for upper layers to restart current cal. * Reset the calibration valid bit in channel. */ void ar9300_reset_cal_valid(struct ath_hal *ah, const struct ieee80211_channel *chan, HAL_BOOL *is_cal_done, u_int32_t cal_type) { struct ath_hal_9300 *ahp = AH9300(ah); HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); HAL_CAL_LIST *curr_cal = ahp->ah_cal_list_curr; *is_cal_done = AH_TRUE; if (curr_cal == AH_NULL) { return; } if (ichan == AH_NULL) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); return; } if (!(cal_type & IQ_MISMATCH_CAL)) { *is_cal_done = AH_FALSE; return; } /* Expected that this calibration has run before, post-reset. * Current state should be done */ if (curr_cal->cal_state != CAL_DONE) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Calibration state incorrect, %d\n", __func__, curr_cal->cal_state); return; } /* Verify Cal is supported on this channel */ if (ar9300_is_cal_supp(ah, chan, curr_cal->cal_data->cal_type) == AH_FALSE) { return; } HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Resetting Cal %d state for channel %u/0x%x\n", __func__, curr_cal->cal_data->cal_type, chan->ic_freq, chan->ic_flags); /* Disable cal validity in channel */ ichan->calValid &= ~curr_cal->cal_data->cal_type; curr_cal->cal_state = CAL_WAITING; /* Indicate to upper layers that we need polling */ *is_cal_done = AH_FALSE; } static inline void ar9300_set_dma(struct ath_hal *ah) { u_int32_t regval; struct ath_hal_9300 *ahp = AH9300(ah); struct ath_hal_private *ahpriv = AH_PRIVATE(ah); HAL_CAPABILITIES *pCap = &ahpriv->ah_caps; #if 0 /* * set AHB_MODE not to do cacheline prefetches */ regval = OS_REG_READ(ah, AR_AHB_MODE); OS_REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); #endif /* * let mac dma reads be in 128 byte chunks */ regval = OS_REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; OS_REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); /* * Restore TX Trigger Level to its pre-reset value. * The initial value depends on whether aggregation is enabled, and is * adjusted whenever underruns are detected. */ /* OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, AH_PRIVATE(ah)->ah_tx_trig_level); */ /* * Osprey 1.0 bug (EV 61936). Don't change trigger level from .ini default. * Osprey 2.0 - hardware recommends using the default INI settings. */ #if 0 OS_REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, 0x3f); #endif /* * let mac dma writes be in 128 byte chunks */ regval = OS_REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; OS_REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); /* * Setup receive FIFO threshold to hold off TX activities */ OS_REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); /* * reduce the number of usable entries in PCU TXBUF to avoid * wrap around bugs. (bug 20428) */ if (AR_SREV_WASP(ah) && (AH_PRIVATE((ah))->ah_macRev > AR_SREV_REVISION_WASP_12)) { /* Wasp 1.3 fix for EV#85395 requires usable entries * to be set to 0x500 */ OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, 0x500); } else { OS_REG_WRITE(ah, AR_PCU_TXBUF_CTRL, AR_PCU_TXBUF_CTRL_USABLE_SIZE); } /* * Enable HPQ for UAPSD */ if (pCap->halHwUapsdTrig == AH_TRUE) { /* Only enable this if HAL capabilities says it is OK */ if (AH_PRIVATE(ah)->ah_opmode == HAL_M_HOSTAP) { OS_REG_WRITE(ah, AR_HP_Q_CONTROL, AR_HPQ_ENABLE | AR_HPQ_UAPSD | AR_HPQ_UAPSD_TRIGGER_EN); } } else { /* use default value from ini file - which disable HPQ queue usage */ } /* * set the transmit status ring */ ar9300_reset_tx_status_ring(ah); /* * set rxbp threshold. Must be non-zero for RX_EOL to occur. * For Osprey 2.0+, keep the original thresholds * otherwise performance is lost due to excessive RX EOL interrupts. */ OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_HP, 0x1); OS_REG_RMW_FIELD(ah, AR_RXBP_THRESH, AR_RXBP_THRESH_LP, 0x1); /* * set receive buffer size. */ if (ahp->rx_buf_size) { OS_REG_WRITE(ah, AR_DATABUF, ahp->rx_buf_size); } } static inline void ar9300_init_bb(struct ath_hal *ah, struct ieee80211_channel *chan) { u_int32_t synth_delay; /* * Wait for the frequency synth to settle (synth goes on * via AR_PHY_ACTIVE_EN). Read the phy active delay register. * Value is in 100ns increments. */ synth_delay = OS_REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; if (IEEE80211_IS_CHAN_CCK(chan)) { synth_delay = (4 * synth_delay) / 22; } else { synth_delay /= 10; } /* Activate the PHY (includes baseband activate + synthesizer on) */ OS_REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); /* * There is an issue if the AP starts the calibration before * the base band timeout completes. This could result in the * rx_clear AH_FALSE triggering. As a workaround we add delay an * extra BASE_ACTIVATE_DELAY usecs to ensure this condition * does not happen. */ OS_DELAY(synth_delay + BASE_ACTIVATE_DELAY); } static inline void ar9300_init_interrupt_masks(struct ath_hal *ah, HAL_OPMODE opmode) { struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t msi_cfg = 0; u_int32_t sync_en_def = AR9300_INTR_SYNC_DEFAULT; /* * Setup interrupt handling. Note that ar9300_reset_tx_queue * manipulates the secondary IMR's as queues are enabled * and disabled. This is done with RMW ops to insure the * settings we make here are preserved. */ ahp->ah_mask_reg = AR_IMR_TXERR | AR_IMR_TXURN | AR_IMR_RXERR | AR_IMR_RXORN | AR_IMR_BCNMISC; if (ahp->ah_intr_mitigation_rx) { /* enable interrupt mitigation for rx */ ahp->ah_mask_reg |= AR_IMR_RXINTM | AR_IMR_RXMINTR | AR_IMR_RXOK_HP; msi_cfg |= AR_INTCFG_MSI_RXINTM | AR_INTCFG_MSI_RXMINTR; } else { ahp->ah_mask_reg |= AR_IMR_RXOK_LP | AR_IMR_RXOK_HP; msi_cfg |= AR_INTCFG_MSI_RXOK; } if (ahp->ah_intr_mitigation_tx) { /* enable interrupt mitigation for tx */ ahp->ah_mask_reg |= AR_IMR_TXINTM | AR_IMR_TXMINTR; msi_cfg |= AR_INTCFG_MSI_TXINTM | AR_INTCFG_MSI_TXMINTR; } else { ahp->ah_mask_reg |= AR_IMR_TXOK; msi_cfg |= AR_INTCFG_MSI_TXOK; } if (opmode == HAL_M_HOSTAP) { ahp->ah_mask_reg |= AR_IMR_MIB; } OS_REG_WRITE(ah, AR_IMR, ahp->ah_mask_reg); OS_REG_WRITE(ah, AR_IMR_S2, OS_REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); ahp->ah_mask2Reg = OS_REG_READ(ah, AR_IMR_S2); if (ah->ah_config.ath_hal_enable_msi) { /* Cache MSI register value */ ahp->ah_msi_reg = OS_REG_READ(ah, AR_HOSTIF_REG(ah, AR_PCIE_MSI)); ahp->ah_msi_reg |= AR_PCIE_MSI_HW_DBI_WR_EN; if (AR_SREV_POSEIDON(ah)) { ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR_MSI_64; } else { ahp->ah_msi_reg &= AR_PCIE_MSI_HW_INT_PENDING_ADDR; } /* Program MSI configuration */ OS_REG_WRITE(ah, AR_INTCFG, msi_cfg); } /* * debug - enable to see all synchronous interrupts status */ /* Clear any pending sync cause interrupts */ OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_CAUSE), 0xFFFFFFFF); /* Allow host interface sync interrupt sources to set cause bit */ if (AR_SREV_POSEIDON(ah)) { sync_en_def = AR9300_INTR_SYNC_DEF_NO_HOST1_PERR; } else if (AR_SREV_WASP(ah)) { sync_en_def = AR9340_INTR_SYNC_DEFAULT; } OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_ENABLE), sync_en_def); /* _Disable_ host interface sync interrupt when cause bits set */ OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_SYNC_MASK), 0); OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_ENABLE), 0); OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_ASYNC_MASK), 0); OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_ENABLE), 0); OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_INTR_PRIO_SYNC_MASK), 0); } static inline void ar9300_init_qos(struct ath_hal *ah) { OS_REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); /* XXX magic */ OS_REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); /* XXX magic */ /* Turn on NOACK Support for QoS packets */ OS_REG_WRITE(ah, AR_QOS_NO_ACK, SM(2, AR_QOS_NO_ACK_TWO_BIT) | SM(5, AR_QOS_NO_ACK_BIT_OFF) | SM(0, AR_QOS_NO_ACK_BYTE_OFF)); /* * initialize TXOP for all TIDs */ OS_REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); OS_REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); OS_REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); OS_REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); OS_REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); } static inline void ar9300_init_user_settings(struct ath_hal *ah) { struct ath_hal_9300 *ahp = AH9300(ah); /* Restore user-specified settings */ HALDEBUG(ah, HAL_DEBUG_RESET, "--AP %s ahp->ah_misc_mode 0x%x\n", __func__, ahp->ah_misc_mode); if (ahp->ah_misc_mode != 0) { OS_REG_WRITE(ah, AR_PCU_MISC, OS_REG_READ(ah, AR_PCU_MISC) | ahp->ah_misc_mode); } if (ahp->ah_get_plcp_hdr) { OS_REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_SEL_EVM); } if (ahp->ah_slot_time != (u_int) -1) { ar9300_set_slot_time(ah, ahp->ah_slot_time); } if (ahp->ah_ack_timeout != (u_int) -1) { ar9300_set_ack_timeout(ah, ahp->ah_ack_timeout); } if (AH_PRIVATE(ah)->ah_diagreg != 0) { OS_REG_SET_BIT(ah, AR_DIAG_SW, AH_PRIVATE(ah)->ah_diagreg); } if (ahp->ah_beacon_rssi_threshold != 0) { ar9300_set_hw_beacon_rssi_threshold(ah, ahp->ah_beacon_rssi_threshold); } #ifdef ATH_SUPPORT_DFS if (ahp->ah_cac_quiet_enabled) { ar9300_cac_tx_quiet(ah, 1); } #endif /* ATH_SUPPORT_DFS */ } int ar9300_get_spur_info(struct ath_hal * ah, int *enable, int len, u_int16_t *freq) { // struct ath_hal_private *ap = AH_PRIVATE(ah); int i, j; for (i = 0; i < len; i++) { freq[i] = 0; } *enable = ah->ah_config.ath_hal_spur_mode; for (i = 0, j = 0; i < AR_EEPROM_MODAL_SPURS; i++) { if (AH9300(ah)->ath_hal_spur_chans[i][0] != AR_NO_SPUR) { freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][0]; HALDEBUG(ah, HAL_DEBUG_ANI, "1. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][0]); } if (AH9300(ah)->ath_hal_spur_chans[i][1] != AR_NO_SPUR) { freq[j++] = AH9300(ah)->ath_hal_spur_chans[i][1]; HALDEBUG(ah, HAL_DEBUG_ANI, "2. get spur %d\n", AH9300(ah)->ath_hal_spur_chans[i][1]); } } return 0; } #define ATH_HAL_2GHZ_FREQ_MIN 20000 #define ATH_HAL_2GHZ_FREQ_MAX 29999 #define ATH_HAL_5GHZ_FREQ_MIN 50000 #define ATH_HAL_5GHZ_FREQ_MAX 59999 #if 0 int ar9300_set_spur_info(struct ath_hal * ah, int enable, int len, u_int16_t *freq) { struct ath_hal_private *ap = AH_PRIVATE(ah); int i, j, k; ap->ah_config.ath_hal_spur_mode = enable; if (ap->ah_config.ath_hal_spur_mode == SPUR_ENABLE_IOCTL) { for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { AH9300(ah)->ath_hal_spur_chans[i][0] = AR_NO_SPUR; AH9300(ah)->ath_hal_spur_chans[i][1] = AR_NO_SPUR; } for (i = 0, j = 0, k = 0; i < len; i++) { if (freq[i] > ATH_HAL_2GHZ_FREQ_MIN && freq[i] < ATH_HAL_2GHZ_FREQ_MAX) { /* 2GHz Spur */ if (j < AR_EEPROM_MODAL_SPURS) { AH9300(ah)->ath_hal_spur_chans[j++][1] = freq[i]; HALDEBUG(ah, HAL_DEBUG_ANI, "1 set spur %d\n", freq[i]); } } else if (freq[i] > ATH_HAL_5GHZ_FREQ_MIN && freq[i] < ATH_HAL_5GHZ_FREQ_MAX) { /* 5Ghz Spur */ if (k < AR_EEPROM_MODAL_SPURS) { AH9300(ah)->ath_hal_spur_chans[k++][0] = freq[i]; HALDEBUG(ah, HAL_DEBUG_ANI, "2 set spur %d\n", freq[i]); } } } } return 0; } #endif #define ar9300_check_op_mode(_opmode) \ ((_opmode == HAL_M_STA) || (_opmode == HAL_M_IBSS) ||\ (_opmode == HAL_M_HOSTAP) || (_opmode == HAL_M_MONITOR)) #ifndef ATH_NF_PER_CHAN /* * To fixed first reset noise floor value not correct issue * For ART need it to fixed low rate sens too low issue */ static int First_NFCal(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, int is_scan, struct ieee80211_channel *chan) { HAL_NFCAL_HIST_FULL *nfh; int i, j, k; int16_t nfarray[HAL_NUM_NF_READINGS] = {0}; int is_2g = 0; int nf_hist_len; int stats = 0; int16_t nf_buf[HAL_NUM_NF_READINGS]; #define IS(_c, _f) (((_c)->channel_flags & _f) || 0) if ((!is_scan) && chan->ic_freq == AH_PRIVATE(ah)->ah_curchan->ic_freq) { nfh = &AH_PRIVATE(ah)->nf_cal_hist; } else { nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; } ar9300_start_nf_cal(ah); for (j = 0; j < 10000; j++) { if ((OS_REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) == 0){ break; } OS_DELAY(10); } if (j < 10000) { is_2g = IEEE80211_IS_CHAN_2GHZ(chan); ar9300_upload_noise_floor(ah, is_2g, nfarray); if (is_scan) { /* * This channel's NF cal info is just a HAL_NFCAL_HIST_SMALL struct * rather than a HAL_NFCAL_HIST_FULL struct. * As long as we only use the first history element of nf_cal_buffer * (nf_cal_buffer[0][0:HAL_NUM_NF_READINGS-1]), we can use * HAL_NFCAL_HIST_SMALL and HAL_NFCAL_HIST_FULL interchangeably. */ nfh = (HAL_NFCAL_HIST_FULL *) &ichan->nf_cal_hist; nf_hist_len = HAL_NF_CAL_HIST_LEN_SMALL; } else { nfh = &AH_PRIVATE(ah)->nf_cal_hist; nf_hist_len = HAL_NF_CAL_HIST_LEN_FULL; } for (i = 0; i < HAL_NUM_NF_READINGS; i ++) { for (k = 0; k < HAL_NF_CAL_HIST_LEN_FULL; k++) { nfh->nf_cal_buffer[k][i] = nfarray[i]; } nfh->base.priv_nf[i] = ar9300_limit_nf_range(ah, ar9300_get_nf_hist_mid(ah, nfh, i, nf_hist_len)); } //ar9300StoreNewNf(ah, ichan, is_scan); /* * See if the NF value from the old channel should be * retained when switching to a new channel. * TBD: this may need to be changed, as it wipes out the * purpose of saving NF values for each channel. */ for (i = 0; i < HAL_NUM_NF_READINGS; i++) { if (IEEE80211_IS_CHAN_2GHZ(chan)) { if (nfh->nf_cal_buffer[0][i] < AR_PHY_CCA_MAX_GOOD_VAL_OSPREY_2GHZ) { ichan->nf_cal_hist.nf_cal_buffer[0][i] = AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; } } else { if (AR_SREV_AR9580(ah)) { if (nfh->nf_cal_buffer[0][i] < AR_PHY_CCA_NOM_VAL_PEACOCK_5GHZ) { ichan->nf_cal_hist.nf_cal_buffer[0][i] = AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; } } else { if (nfh->nf_cal_buffer[0][i] < AR_PHY_CCA_NOM_VAL_OSPREY_5GHZ) { ichan->nf_cal_hist.nf_cal_buffer[0][i] = AH_PRIVATE(ah)->nf_cal_hist.nf_cal_buffer[0][i]; } } } } /* * Copy the channel's NF buffer, which may have been modified * just above here, to the full NF history buffer. */ ar9300_reset_nf_hist_buff(ah, ichan); ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); ar9300_load_nf(ah, nf_buf); stats = 0; } else { stats = 1; } #undef IS return stats; } #endif /* * Places the device in and out of reset and then places sane * values in the registers based on EEPROM config, initialization * vectors (as determined by the mode), and station configuration * * b_channel_change is used to preserve DMA/PCU registers across * a HW Reset during channel change. */ HAL_BOOL ar9300_reset(struct ath_hal *ah, HAL_OPMODE opmode, struct ieee80211_channel *chan, HAL_HT_MACMODE macmode, u_int8_t txchainmask, u_int8_t rxchainmask, HAL_HT_EXTPROTSPACING extprotspacing, HAL_BOOL b_channel_change, HAL_STATUS *status, int is_scan) { #define FAIL(_code) do { ecode = _code; goto bad; } while (0) u_int32_t save_led_state; struct ath_hal_9300 *ahp = AH9300(ah); struct ath_hal_private *ap = AH_PRIVATE(ah); HAL_CHANNEL_INTERNAL *ichan; //const struct ieee80211_channel *curchan = ap->ah_curchan; #if ATH_SUPPORT_MCI HAL_BOOL save_full_sleep = ahp->ah_chip_full_sleep; #endif u_int32_t save_def_antenna; u_int32_t mac_sta_id1; HAL_STATUS ecode; int i, rx_chainmask; int nf_hist_buff_reset = 0; int16_t nf_buf[HAL_NUM_NF_READINGS]; #ifdef ATH_FORCE_PPM u_int32_t save_force_val, tmp_reg; #endif HAL_BOOL stopped, cal_ret; HAL_BOOL apply_last_iqcorr = AH_FALSE; if (OS_REG_READ(ah, AR_IER) == AR_IER_ENABLE) { HALDEBUG(AH_NULL, HAL_DEBUG_UNMASKABLE, "** Reset called with WLAN " "interrupt enabled %08x **\n", ar9300_get_interrupts(ah)); } /* * Set the status to "ok" by default to cover the cases * where we return AH_FALSE without going to "bad" */ HALASSERT(status); *status = HAL_OK; if ((ah->ah_config.ath_hal_sta_update_tx_pwr_enable)) { AH9300(ah)->green_tx_status = HAL_RSSI_TX_POWER_NONE; } #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport && (AR_SREV_JUPITER_20(ah) || AR_SREV_APHRODITE(ah))) { ar9300_mci_2g5g_changed(ah, IEEE80211_IS_CHAN_2GHZ(chan)); } #endif ahp->ah_ext_prot_spacing = extprotspacing; ahp->ah_tx_chainmask = txchainmask & ap->ah_caps.halTxChainMask; ahp->ah_rx_chainmask = rxchainmask & ap->ah_caps.halRxChainMask; ahp->ah_tx_cal_chainmask = ap->ah_caps.halTxChainMask; ahp->ah_rx_cal_chainmask = ap->ah_caps.halRxChainMask; /* * Keep the previous optinal txchainmask value */ HALASSERT(ar9300_check_op_mode(opmode)); OS_MARK(ah, AH_MARK_RESET, b_channel_change); /* * Map public channel to private. */ ichan = ar9300_check_chan(ah, chan); if (ichan == AH_NULL) { HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); FAIL(HAL_EINVAL); } ichan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */ #if 0 chan->paprd_table_write_done = 0; /* Clear PAPRD table write flag */ #endif if (ar9300_get_power_mode(ah) != HAL_PM_FULL_SLEEP) { /* Need to stop RX DMA before reset otherwise chip might hang */ stopped = ar9300_set_rx_abort(ah, AH_TRUE); /* abort and disable PCU */ ar9300_set_rx_filter(ah, 0); stopped &= ar9300_stop_dma_receive(ah, 0); /* stop and disable RX DMA */ if (!stopped) { /* * During the transition from full sleep to reset, * recv DMA regs are not available to be read */ HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s[%d]: ar9300_stop_dma_receive failed\n", __func__, __LINE__); b_channel_change = AH_FALSE; } } else { HALDEBUG(ah, HAL_DEBUG_UNMASKABLE, "%s[%d]: Chip is already in full sleep\n", __func__, __LINE__); } #if ATH_SUPPORT_MCI if ((AH_PRIVATE(ah)->ah_caps.halMciSupport) && (ahp->ah_mci_bt_state == MCI_BT_CAL_START)) { u_int32_t payload[4] = {0, 0, 0, 0}; HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Stop rx for BT cal.\n", __func__); ahp->ah_mci_bt_state = MCI_BT_CAL; /* * MCIFIX: disable mci interrupt here. This is to avoid SW_MSG_DONE or * RX_MSG bits to trigger MCI_INT and lead to mci_intr reentry. */ ar9300_mci_disable_interrupt(ah); HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Send WLAN_CAL_GRANT\n", __func__); MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_GRANT); ar9300_mci_send_message(ah, MCI_GPM, 0, payload, 16, AH_TRUE, AH_FALSE); /* Wait BT calibration to be completed for 25ms */ HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: BT is calibrating.\n", __func__); if (ar9300_mci_wait_for_gpm(ah, MCI_GPM_BT_CAL_DONE, 0, 25000)) { HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Got BT_CAL_DONE.\n", __func__); } else { HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: ### BT cal takes too long. Force bt_state to be bt_awake.\n", __func__); } ahp->ah_mci_bt_state = MCI_BT_AWAKE; /* MCIFIX: enable mci interrupt here */ ar9300_mci_enable_interrupt(ah); return AH_TRUE; } #endif /* Bring out of sleep mode */ if (!ar9300_set_power_mode(ah, HAL_PM_AWAKE, AH_TRUE)) { *status = HAL_INV_PMODE; return AH_FALSE; } /* Check the Rx mitigation config again, it might have changed * during attach in ath_vap_attach. */ if (ah->ah_config.ath_hal_intr_mitigation_rx != 0) { ahp->ah_intr_mitigation_rx = AH_TRUE; } else { ahp->ah_intr_mitigation_rx = AH_FALSE; } /* * XXX TODO FreeBSD: * * This is painful because we don't have a non-const channel pointer * at this stage. * * Make sure this gets fixed! */ #if 0 /* Get the value from the previous NF cal and update history buffer */ if (curchan && (ahp->ah_chip_full_sleep != AH_TRUE)) { if(ahp->ah_chip_reset_done){ ahp->ah_chip_reset_done = 0; } else { /* * is_scan controls updating NF for home channel or off channel. * Home -> Off, update home channel * Off -> Home, update off channel * Home -> Home, uppdate home channel */ if (ap->ah_curchan->channel != chan->channel) ar9300_store_new_nf(ah, curchan, !is_scan); else ar9300_store_new_nf(ah, curchan, is_scan); } } #endif /* * Account for the effect of being in either the 2 GHz or 5 GHz band * on the nominal, max allowable, and min allowable noise floor values. */ AH9300(ah)->nfp = IS_CHAN_2GHZ(ichan) ? &ahp->nf_2GHz : &ahp->nf_5GHz; /* * XXX FreeBSD For now, don't apply the last IQ correction. * * This should be done when scorpion is enabled on FreeBSD; just be * sure to fix this channel match code so it uses net80211 flags * instead. */ #if 0 if (AR_SREV_SCORPION(ah) && curchan && (chan->channel == curchan->channel) && ((chan->channel_flags & (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER)) == (curchan->channel_flags & (CHANNEL_ALL | CHANNEL_HALF | CHANNEL_QUARTER)))) { apply_last_iqcorr = AH_TRUE; } #endif apply_last_iqcorr = AH_FALSE; #ifndef ATH_NF_PER_CHAN /* * If there's only one full-size home-channel NF history buffer * rather than a full-size NF history buffer per channel, decide * whether to (re)initialize the home-channel NF buffer. * If this is just a channel change for a scan, or if the channel * is not being changed, don't mess up the home channel NF history * buffer with NF values from this scanned channel. If we're * changing the home channel to a new channel, reset the home-channel * NF history buffer with the most accurate NF known for the new channel. */ if (!is_scan && (!ap->ah_curchan || ap->ah_curchan->ic_freq != chan->ic_freq)) // || // ap->ah_curchan->channel_flags != chan->channel_flags)) { nf_hist_buff_reset = 1; ar9300_reset_nf_hist_buff(ah, ichan); } #endif /* * In case of * - offchan scan, or * - same channel and RX IQ Cal already available * disable RX IQ Cal. */ if (is_scan) { ahp->ah_skip_rx_iq_cal = AH_TRUE; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Skip RX IQ Cal due to scanning\n"); } else { #if 0 /* XXX FreeBSD: always just do the RX IQ cal */ /* XXX I think it's just going to speed things up; I don't think it's to avoid chan bugs */ if (ahp->ah_rx_cal_complete && ahp->ah_rx_cal_chan == ichan->channel && ahp->ah_rx_cal_chan_flag == chan->channel_flags) { ahp->ah_skip_rx_iq_cal = AH_TRUE; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "Skip RX IQ Cal due to same channel with completed RX IQ Cal\n"); } else #endif ahp->ah_skip_rx_iq_cal = AH_FALSE; } - + + /* FreeBSD: clear the channel survey data */ + ath_hal_survey_clear(ah); + /* * Fast channel change (Change synthesizer based on channel freq * without resetting chip) * Don't do it when * - Flag is not set * - Chip is just coming out of full sleep * - Channel to be set is same as current channel * - Channel flags are different, like when moving from 2GHz to 5GHz * channels * - Merlin: Switching in/out of fast clock enabled channels * (not currently coded, since fast clock is enabled * across the 5GHz band * and we already do a full reset when switching in/out * of 5GHz channels) */ #if 0 if (b_channel_change && (ahp->ah_chip_full_sleep != AH_TRUE) && (AH_PRIVATE(ah)->ah_curchan != AH_NULL) && ((chan->channel != AH_PRIVATE(ah)->ah_curchan->channel) && (((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & chan->channel_flags) == ((CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) & AH_PRIVATE(ah)->ah_curchan->channel_flags)))) { if (ar9300_channel_change(ah, chan, ichan, macmode)) { chan->channel_flags = ichan->channel_flags; chan->priv_flags = ichan->priv_flags; AH_PRIVATE(ah)->ah_curchan->ah_channel_time = 0; AH_PRIVATE(ah)->ah_curchan->ah_tsf_last = ar9300_get_tsf64(ah); /* * Load the NF from history buffer of the current channel. * NF is slow time-variant, so it is OK to use a historical value. */ ar9300_get_nf_hist_base(ah, AH_PRIVATE(ah)->ah_curchan, is_scan, nf_buf); ar9300_load_nf(ah, nf_buf); /* start NF calibration, without updating BB NF register*/ ar9300_start_nf_cal(ah); /* * If channel_change completed and DMA was stopped * successfully - skip the rest of reset */ if (AH9300(ah)->ah_dma_stuck != AH_TRUE) { WAR_USB_DISABLE_PLL_LOCK_DETECT(ah); #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { ar9300_mci_2g5g_switch(ah, AH_TRUE); } #endif return HAL_OK; } } } #endif /* #if 0 */ #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { ar9300_mci_disable_interrupt(ah); if (ahp->ah_mci_ready && !save_full_sleep) { ar9300_mci_mute_bt(ah); OS_DELAY(20); OS_REG_WRITE(ah, AR_BTCOEX_CTRL, 0); } ahp->ah_mci_bt_state = MCI_BT_SLEEP; ahp->ah_mci_ready = AH_FALSE; } #endif AH9300(ah)->ah_dma_stuck = AH_FALSE; #ifdef ATH_FORCE_PPM /* Preserve force ppm state */ save_force_val = OS_REG_READ(ah, AR_PHY_TIMING2) & (AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL); #endif /* * Preserve the antenna on a channel change */ save_def_antenna = OS_REG_READ(ah, AR_DEF_ANTENNA); if (0 == ahp->ah_smartantenna_enable ) { if (save_def_antenna == 0) { save_def_antenna = 1; } } /* Save hardware flag before chip reset clears the register */ mac_sta_id1 = OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B; /* Save led state from pci config register */ save_led_state = OS_REG_READ(ah, AR_CFG_LED) & (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | AR_CFG_LED_BLINK_THRESH_SEL | AR_CFG_LED_BLINK_SLOW); /* Mark PHY inactive prior to reset, to be undone in ar9300_init_bb () */ ar9300_mark_phy_inactive(ah); if (!ar9300_chip_reset(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: chip reset failed\n", __func__); FAIL(HAL_EIO); } OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); /* Disable JTAG */ OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_GPIO_INPUT_EN_VAL), AR_GPIO_JTAG_DISABLE); /* * Note that ar9300_init_chain_masks() is called from within * ar9300_process_ini() to ensure the swap bit is set before * the pdadc table is written. */ ecode = ar9300_process_ini(ah, chan, ichan, macmode); if (ecode != HAL_OK) { goto bad; } ahp->ah_immunity_on = AH_FALSE; if (AR_SREV_JUPITER(ah) || AR_SREV_APHRODITE(ah)) { ahp->tx_iq_cal_enable = OS_REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_0(ah), AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL) ? 1 : 0; } ahp->tx_cl_cal_enable = (OS_REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) ? 1 : 0; /* For devices with full HW RIFS Rx support (Sowl/Howl/Merlin, etc), * restore register settings from prior to reset. */ if ((AH_PRIVATE(ah)->ah_curchan != AH_NULL) && (ar9300_get_capability(ah, HAL_CAP_LDPCWAR, 0, AH_NULL) == HAL_OK)) { /* Re-program RIFS Rx policy after reset */ ar9300_set_rifs_delay(ah, ahp->ah_rifs_enabled); } #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport) { ar9300_mci_reset(ah, AH_FALSE, IS_CHAN_2GHZ(ichan), save_full_sleep); } #endif /* Initialize Management Frame Protection */ ar9300_init_mfp(ah); ahp->ah_immunity_vals[0] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M1_THRESH_LOW); ahp->ah_immunity_vals[1] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2_THRESH_LOW); ahp->ah_immunity_vals[2] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M1_THRESH); ahp->ah_immunity_vals[3] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2_THRESH); ahp->ah_immunity_vals[4] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR, AR_PHY_SFCORR_M2COUNT_THR); ahp->ah_immunity_vals[5] = OS_REG_READ_FIELD(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW); /* Write delta slope for OFDM enabled modes (A, G, Turbo) */ if (IEEE80211_IS_CHAN_OFDM(chan) || IEEE80211_IS_CHAN_HT(chan)) { ar9300_set_delta_slope(ah, chan); } ar9300_spur_mitigate(ah, chan); if (!ar9300_eeprom_set_board_values(ah, chan)) { HALDEBUG(ah, HAL_DEBUG_EEPROM, "%s: error setting board options\n", __func__); FAIL(HAL_EIO); } #ifdef ATH_HAL_WAR_REG16284_APH128 /* temp work around, will be removed. */ if (AR_SREV_WASP(ah)) { OS_REG_WRITE(ah, 0x16284, 0x1553e000); } #endif OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); OS_REG_WRITE(ah, AR_STA_ID0, LE_READ_4(ahp->ah_macaddr)); OS_REG_WRITE(ah, AR_STA_ID1, LE_READ_2(ahp->ah_macaddr + 4) | mac_sta_id1 | AR_STA_ID1_RTS_USE_DEF | (ah->ah_config.ath_hal_6mb_ack ? AR_STA_ID1_ACKCTS_6MB : 0) | ahp->ah_sta_id1_defaults ); ar9300_set_operating_mode(ah, opmode); /* Set Venice BSSID mask according to current state */ OS_REG_WRITE(ah, AR_BSSMSKL, LE_READ_4(ahp->ah_bssid_mask)); OS_REG_WRITE(ah, AR_BSSMSKU, LE_READ_2(ahp->ah_bssid_mask + 4)); /* Restore previous antenna */ OS_REG_WRITE(ah, AR_DEF_ANTENNA, save_def_antenna); #ifdef ATH_FORCE_PPM /* Restore force ppm state */ tmp_reg = OS_REG_READ(ah, AR_PHY_TIMING2) & ~(AR_PHY_TIMING2_USE_FORCE | AR_PHY_TIMING2_FORCE_VAL); OS_REG_WRITE(ah, AR_PHY_TIMING2, tmp_reg | save_force_val); #endif /* then our BSSID and assocID */ OS_REG_WRITE(ah, AR_BSS_ID0, LE_READ_4(ahp->ah_bssid)); OS_REG_WRITE(ah, AR_BSS_ID1, LE_READ_2(ahp->ah_bssid + 4) | ((ahp->ah_assoc_id & 0x3fff) << AR_BSS_ID1_AID_S)); OS_REG_WRITE(ah, AR_ISR, ~0); /* cleared on write */ OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, INIT_RSSI_THR); /* HW beacon processing */ /* * XXX what happens if I just leave filter_interval=0? * it stays disabled? */ OS_REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_BCN_WEIGHT, INIT_RSSI_BEACON_WEIGHT); OS_REG_SET_BIT(ah, AR_HWBCNPROC1, AR_HWBCNPROC1_CRC_ENABLE | AR_HWBCNPROC1_EXCLUDE_TIM_ELM); if (ah->ah_config.ath_hal_beacon_filter_interval) { OS_REG_RMW_FIELD(ah, AR_HWBCNPROC2, AR_HWBCNPROC2_FILTER_INTERVAL, ah->ah_config.ath_hal_beacon_filter_interval); OS_REG_SET_BIT(ah, AR_HWBCNPROC2, AR_HWBCNPROC2_FILTER_INTERVAL_ENABLE); } /* * Set Channel now modifies bank 6 parameters for FOWL workaround * to force rf_pwd_icsyndiv bias current as function of synth * frequency.Thus must be called after ar9300_process_ini() to ensure * analog register cache is valid. */ if (!ahp->ah_rf_hal.set_channel(ah, chan)) { FAIL(HAL_EIO); } OS_MARK(ah, AH_MARK_RESET_LINE, __LINE__); /* Set 1:1 QCU to DCU mapping for all queues */ for (i = 0; i < AR_NUM_DCU; i++) { OS_REG_WRITE(ah, AR_DQCUMASK(i), 1 << i); } ahp->ah_intr_txqs = 0; for (i = 0; i < AH_PRIVATE(ah)->ah_caps.halTotalQueues; i++) { ar9300_reset_tx_queue(ah, i); } ar9300_init_interrupt_masks(ah, opmode); /* Reset ier reference count to disabled */ // OS_ATOMIC_SET(&ahp->ah_ier_ref_count, 1); if (ath_hal_isrfkillenabled(ah)) { ar9300_enable_rf_kill(ah); } /* must be called AFTER ini is processed */ ar9300_ani_init_defaults(ah, macmode); ar9300_init_qos(ah); ar9300_init_user_settings(ah); AH_PRIVATE(ah)->ah_opmode = opmode; /* record operating mode */ OS_MARK(ah, AH_MARK_RESET_DONE, 0); /* * disable seq number generation in hw */ OS_REG_WRITE(ah, AR_STA_ID1, OS_REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM); ar9300_set_dma(ah); /* * program OBS bus to see MAC interrupts */ #if ATH_SUPPORT_MCI if (!AH_PRIVATE(ah)->ah_caps.halMciSupport) { OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8); } #else OS_REG_WRITE(ah, AR_HOSTIF_REG(ah, AR_OBS), 8); #endif /* enabling AR_GTTM_IGNORE_IDLE in GTTM register so that GTT timer will not increment if the channel idle indicates the air is busy or NAV is still counting down */ OS_REG_WRITE(ah, AR_GTTM, AR_GTTM_IGNORE_IDLE); /* * GTT debug mode setting */ /* OS_REG_WRITE(ah, 0x64, 0x00320000); OS_REG_WRITE(ah, 0x68, 7); OS_REG_WRITE(ah, 0x4080, 0xC); */ /* * Disable general interrupt mitigation by setting MIRT = 0x0 * Rx and tx interrupt mitigation are conditionally enabled below. */ OS_REG_WRITE(ah, AR_MIRT, 0); if (ahp->ah_intr_mitigation_rx) { /* * Enable Interrupt Mitigation for Rx. * If no build-specific limits for the rx interrupt mitigation * timer have been specified, use conservative defaults. */ #ifndef AH_RIMT_VAL_LAST #define AH_RIMT_LAST_MICROSEC 500 #endif #ifndef AH_RIMT_VAL_FIRST #define AH_RIMT_FIRST_MICROSEC 2000 #endif #ifndef HOST_OFFLOAD OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, AH_RIMT_LAST_MICROSEC); OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, AH_RIMT_FIRST_MICROSEC); #else /* lower mitigation level to reduce latency for offload arch. */ OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, (AH_RIMT_LAST_MICROSEC >> 2)); OS_REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_FIRST, (AH_RIMT_FIRST_MICROSEC >> 2)); #endif } if (ahp->ah_intr_mitigation_tx) { /* * Enable Interrupt Mitigation for Tx. * If no build-specific limits for the tx interrupt mitigation * timer have been specified, use the values preferred for * the carrier group's products. */ #ifndef AH_TIMT_LAST #define AH_TIMT_LAST_MICROSEC 300 #endif #ifndef AH_TIMT_FIRST #define AH_TIMT_FIRST_MICROSEC 750 #endif OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_LAST, AH_TIMT_LAST_MICROSEC); OS_REG_RMW_FIELD(ah, AR_TIMT, AR_TIMT_FIRST, AH_TIMT_FIRST_MICROSEC); } rx_chainmask = ahp->ah_rx_chainmask; OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); ar9300_init_bb(ah, chan); /* BB Step 7: Calibration */ /* * Only kick off calibration not on offchan. * If coming back from offchan, restore prevous Cal results * since chip reset will clear existings. */ if (!ahp->ah_skip_rx_iq_cal) { int i; /* clear existing RX cal data */ for (i=0; iah_rx_cal_corr[i] = 0; ahp->ah_rx_cal_complete = AH_FALSE; // ahp->ah_rx_cal_chan = chan->channel; // ahp->ah_rx_cal_chan_flag = ichan->channel_flags; ahp->ah_rx_cal_chan = 0; ahp->ah_rx_cal_chan_flag = 0; /* XXX FreeBSD */ } ar9300_invalidate_saved_cals(ah, ichan); cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { if (IS_CHAN_2GHZ(ichan) && (ahp->ah_mci_bt_state == MCI_BT_SLEEP)) { if (ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET) || ar9300_mci_check_int(ah, AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE)) { /* * BT is sleeping. Check if BT wakes up duing WLAN * calibration. If BT wakes up during WLAN calibration, need * to go through all message exchanges again and recal. */ HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) ### %s: BT wakes up during WLAN calibration.\n", __func__); OS_REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET | AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE); HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) send REMOTE_RESET\n"); ar9300_mci_remote_reset(ah, AH_TRUE); ar9300_mci_send_sys_waking(ah, AH_TRUE); OS_DELAY(1); if (IS_CHAN_2GHZ(ichan)) { ar9300_mci_send_lna_transfer(ah, AH_TRUE); } ahp->ah_mci_bt_state = MCI_BT_AWAKE; /* Redo calibration */ HALDEBUG(ah, HAL_DEBUG_BT_COEX, "(MCI) %s: Re-calibrate.\n", __func__); ar9300_invalidate_saved_cals(ah, ichan); cal_ret = ar9300_init_cal(ah, chan, AH_FALSE, apply_last_iqcorr); } } ar9300_mci_enable_interrupt(ah); } #endif if (!cal_ret) { HALDEBUG(ah, HAL_DEBUG_RESET, "%s: Init Cal Failed\n", __func__); FAIL(HAL_ESELFTEST); } ar9300_init_txbf(ah); #if 0 /* * WAR for owl 1.0 - restore chain mask for 2-chain cfgs after cal */ rx_chainmask = ahp->ah_rx_chainmask; if ((rx_chainmask == 0x5) || (rx_chainmask == 0x3)) { OS_REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); OS_REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); } #endif /* Restore previous led state */ OS_REG_WRITE(ah, AR_CFG_LED, save_led_state | AR_CFG_SCLK_32KHZ); #if ATH_BT_COEX if (ahp->ah_bt_coex_config_type != HAL_BT_COEX_CFG_NONE) { ar9300_init_bt_coex(ah); #if ATH_SUPPORT_MCI if (AH_PRIVATE(ah)->ah_caps.halMciSupport && ahp->ah_mci_ready) { /* Check BT state again to make sure it's not changed. */ ar9300_mci_sync_bt_state(ah); ar9300_mci_2g5g_switch(ah, AH_TRUE); if ((ahp->ah_mci_bt_state == MCI_BT_AWAKE) && (ahp->ah_mci_query_bt == AH_TRUE)) { ahp->ah_mci_need_flush_btinfo = AH_TRUE; } } #endif } #endif /* Start TSF2 for generic timer 8-15. */ ar9300_start_tsf2(ah); /* MIMO Power save setting */ if (ar9300_get_capability(ah, HAL_CAP_DYNAMIC_SMPS, 0, AH_NULL) == HAL_OK) { ar9300_set_sm_power_mode(ah, ahp->ah_sm_power_mode); } /* * For big endian systems turn on swapping for descriptors */ #if AH_BYTE_ORDER == AH_BIG_ENDIAN if (AR_SREV_HORNET(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { OS_REG_RMW(ah, AR_CFG, AR_CFG_SWTB | AR_CFG_SWRB, 0); } else { ar9300_init_cfg_reg(ah); } #endif if ( AR_SREV_OSPREY(ah) || AR_SREV_WASP(ah) || AR_SREV_SCORPION(ah)) { OS_REG_RMW(ah, AR_CFG_LED, AR_CFG_LED_ASSOC_CTL, AR_CFG_LED_ASSOC_CTL); } #if !(defined(ART_BUILD)) && defined(ATH_SUPPORT_LED) #define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val); #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) #define ATH_GPIO_OUT_FUNCTION3 0xB8040038 #define ATH_GPIO_OE 0xB8040000 if ( AR_SREV_WASP(ah)) { if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x33 << 8) ); REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) ))); } else { /* Disable 2G WLAN LED. During ath_open, reset function is called even before channel is set. So 2GHz is taken as default and it also blinks. Hence to avoid both from blinking, disable 2G led while in 5G mode */ REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) | (1 << 13) )); REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x33) ); REG_WRITE(ATH_GPIO_OE, ( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) ))); } } else if (AR_SREV_SCORPION(ah)) { if (IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan))) { REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff << 8))) | (0x2F << 8) ); REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 13) )) | (0x1 << 12))); } else if (IS_CHAN_5GHZ((AH_PRIVATE(ah)->ah_curchan))) { REG_WRITE(ATH_GPIO_OUT_FUNCTION3, ( REG_READ(ATH_GPIO_OUT_FUNCTION3) & (~(0xff))) | (0x2F) ); REG_WRITE(ATH_GPIO_OE, (( REG_READ(ATH_GPIO_OE) & (~(0x1 << 12) )) | (0x1 << 13))); } } #undef REG_READ #undef REG_WRITE #endif /* XXX FreeBSD What's this? -adrian */ #if 0 chan->channel_flags = ichan->channel_flags; chan->priv_flags = ichan->priv_flags; #endif #if FIX_NOISE_FLOOR /* XXX FreeBSD is ichan appropariate? It was curchan.. */ ar9300_get_nf_hist_base(ah, ichan, is_scan, nf_buf); ar9300_load_nf(ah, nf_buf); if (nf_hist_buff_reset == 1) { nf_hist_buff_reset = 0; #ifndef ATH_NF_PER_CHAN if (First_NFCal(ah, ichan, is_scan, chan)){ if (ahp->ah_skip_rx_iq_cal && !is_scan) { /* restore RX Cal result if existing */ ar9300_rx_iq_cal_restore(ah); ahp->ah_skip_rx_iq_cal = AH_FALSE; } } #endif /* ATH_NF_PER_CHAN */ } else{ ar9300_start_nf_cal(ah); } #endif #ifdef AH_SUPPORT_AR9300 /* BB Panic Watchdog */ if (ar9300_get_capability(ah, HAL_CAP_BB_PANIC_WATCHDOG, 0, AH_NULL) == HAL_OK) { ar9300_config_bb_panic_watchdog(ah); } #endif /* While receiving unsupported rate frame receive state machine * gets into a state 0xb and if phy_restart happens when rx * state machine is in 0xb state, BB would go hang, if we * see 0xb state after first bb panic, make sure that we * disable the phy_restart. * * There may be multiple panics, make sure that we always do * this if we see this panic at least once. This is required * because reset seems to be writing from INI file. */ if ((ar9300_get_capability(ah, HAL_CAP_PHYRESTART_CLR_WAR, 0, AH_NULL) == HAL_OK) && (((MS((AH9300(ah)->ah_bb_panic_last_status), AR_PHY_BB_WD_RX_OFDM_SM)) == 0xb) || AH9300(ah)->ah_phyrestart_disabled) ) { ar9300_disable_phy_restart(ah, 1); } ahp->ah_radar1 = MS(OS_REG_READ(ah, AR_PHY_RADAR_1), AR_PHY_RADAR_1_CF_BIN_THRESH); ahp->ah_dc_offset = MS(OS_REG_READ(ah, AR_PHY_TIMING2), AR_PHY_TIMING2_DC_OFFSET); ahp->ah_disable_cck = MS(OS_REG_READ(ah, AR_PHY_MODE), AR_PHY_MODE_DISABLE_CCK); if (AH9300(ah)->ah_enable_keysearch_always) { ar9300_enable_keysearch_always(ah, 1); } #if ATH_LOW_POWER_ENABLE #define REG_WRITE(_reg, _val) *((volatile u_int32_t *)(_reg)) = (_val) #define REG_READ(_reg) *((volatile u_int32_t *)(_reg)) if (AR_SREV_OSPREY(ah)) { REG_WRITE(0xb4000080, REG_READ(0xb4000080) | 3); OS_REG_WRITE(ah, AR_RTC_RESET, 1); OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_PCIE_PM_CTRL), AR_PCIE_PM_CTRL_ENA); OS_REG_SET_BIT(ah, AR_HOSTIF_REG(ah, AR_SPARE), 0xffffffff); } #undef REG_READ #undef REG_WRITE #endif /* ATH_LOW_POWER_ENABLE */ WAR_USB_DISABLE_PLL_LOCK_DETECT(ah); /* H/W Green TX */ ar9300_control_signals_for_green_tx_mode(ah); /* Smart Antenna, only for 5GHz on Scropion */ if (IEEE80211_IS_CHAN_2GHZ((AH_PRIVATE(ah)->ah_curchan)) && AR_SREV_SCORPION(ah)) { ahp->ah_smartantenna_enable = 0; } ar9300_set_smart_antenna(ah, ahp->ah_smartantenna_enable); if (ahp->ah_skip_rx_iq_cal && !is_scan) { /* restore RX Cal result if existing */ ar9300_rx_iq_cal_restore(ah); ahp->ah_skip_rx_iq_cal = AH_FALSE; } return AH_TRUE; bad: OS_MARK(ah, AH_MARK_RESET_DONE, ecode); *status = ecode; if (ahp->ah_skip_rx_iq_cal && !is_scan) { /* restore RX Cal result if existing */ ar9300_rx_iq_cal_restore(ah); ahp->ah_skip_rx_iq_cal = AH_FALSE; } return AH_FALSE; #undef FAIL } void ar9300_green_ap_ps_on_off( struct ath_hal *ah, u_int16_t on_off) { /* Set/reset the ps flag */ AH9300(ah)->green_ap_ps_on = !!on_off; } /* * This function returns 1, where it is possible to do * single-chain power save. */ u_int16_t ar9300_is_single_ant_power_save_possible(struct ath_hal *ah) { return AH_TRUE; } /* To avoid compilation warnings. Functions not used when EMULATION. */ /* * ar9300_find_mag_approx() */ static int32_t ar9300_find_mag_approx(struct ath_hal *ah, int32_t in_re, int32_t in_im) { int32_t abs_i = abs(in_re); int32_t abs_q = abs(in_im); int32_t max_abs, min_abs; if (abs_i > abs_q) { max_abs = abs_i; min_abs = abs_q; } else { max_abs = abs_q; min_abs = abs_i; } return (max_abs - (max_abs / 32) + (min_abs / 8) + (min_abs / 4)); } /* * ar9300_solve_iq_cal() * solve 4x4 linear equation used in loopback iq cal. */ static HAL_BOOL ar9300_solve_iq_cal( struct ath_hal *ah, int32_t sin_2phi_1, int32_t cos_2phi_1, int32_t sin_2phi_2, int32_t cos_2phi_2, int32_t mag_a0_d0, int32_t phs_a0_d0, int32_t mag_a1_d0, int32_t phs_a1_d0, int32_t solved_eq[]) { int32_t f1 = cos_2phi_1 - cos_2phi_2; int32_t f3 = sin_2phi_1 - sin_2phi_2; int32_t f2; int32_t mag_tx, phs_tx, mag_rx, phs_rx; const int32_t result_shift = 1 << 15; f2 = (((int64_t)f1 * (int64_t)f1) / result_shift) + (((int64_t)f3 * (int64_t)f3) / result_shift); if (0 == f2) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d).\n", __func__, __LINE__); return AH_FALSE; } /* magnitude mismatch, tx */ mag_tx = f1 * (mag_a0_d0 - mag_a1_d0) + f3 * (phs_a0_d0 - phs_a1_d0); /* phase mismatch, tx */ phs_tx = f3 * (-mag_a0_d0 + mag_a1_d0) + f1 * (phs_a0_d0 - phs_a1_d0); mag_tx = (mag_tx / f2); phs_tx = (phs_tx / f2); /* magnitude mismatch, rx */ mag_rx = mag_a0_d0 - (cos_2phi_1 * mag_tx + sin_2phi_1 * phs_tx) / result_shift; /* phase mismatch, rx */ phs_rx = phs_a0_d0 + (sin_2phi_1 * mag_tx - cos_2phi_1 * phs_tx) / result_shift; solved_eq[0] = mag_tx; solved_eq[1] = phs_tx; solved_eq[2] = mag_rx; solved_eq[3] = phs_rx; return AH_TRUE; } /* * ar9300_calc_iq_corr() */ static HAL_BOOL ar9300_calc_iq_corr(struct ath_hal *ah, int32_t chain_idx, const int32_t iq_res[], int32_t iqc_coeff[]) { int32_t i2_m_q2_a0_d0, i2_p_q2_a0_d0, iq_corr_a0_d0; int32_t i2_m_q2_a0_d1, i2_p_q2_a0_d1, iq_corr_a0_d1; int32_t i2_m_q2_a1_d0, i2_p_q2_a1_d0, iq_corr_a1_d0; int32_t i2_m_q2_a1_d1, i2_p_q2_a1_d1, iq_corr_a1_d1; int32_t mag_a0_d0, mag_a1_d0, mag_a0_d1, mag_a1_d1; int32_t phs_a0_d0, phs_a1_d0, phs_a0_d1, phs_a1_d1; int32_t sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2; int32_t mag_tx, phs_tx, mag_rx, phs_rx; int32_t solved_eq[4], mag_corr_tx, phs_corr_tx, mag_corr_rx, phs_corr_rx; int32_t q_q_coff, q_i_coff; const int32_t res_scale = 1 << 15; const int32_t delpt_shift = 1 << 8; int32_t mag1, mag2; i2_m_q2_a0_d0 = iq_res[0] & 0xfff; i2_p_q2_a0_d0 = (iq_res[0] >> 12) & 0xfff; iq_corr_a0_d0 = ((iq_res[0] >> 24) & 0xff) + ((iq_res[1] & 0xf) << 8); if (i2_m_q2_a0_d0 > 0x800) { i2_m_q2_a0_d0 = -((0xfff - i2_m_q2_a0_d0) + 1); } if (iq_corr_a0_d0 > 0x800) { iq_corr_a0_d0 = -((0xfff - iq_corr_a0_d0) + 1); } i2_m_q2_a0_d1 = (iq_res[1] >> 4) & 0xfff; i2_p_q2_a0_d1 = (iq_res[2] & 0xfff); iq_corr_a0_d1 = (iq_res[2] >> 12) & 0xfff; if (i2_m_q2_a0_d1 > 0x800) { i2_m_q2_a0_d1 = -((0xfff - i2_m_q2_a0_d1) + 1); } if (iq_corr_a0_d1 > 0x800) { iq_corr_a0_d1 = -((0xfff - iq_corr_a0_d1) + 1); } i2_m_q2_a1_d0 = ((iq_res[2] >> 24) & 0xff) + ((iq_res[3] & 0xf) << 8); i2_p_q2_a1_d0 = (iq_res[3] >> 4) & 0xfff; iq_corr_a1_d0 = iq_res[4] & 0xfff; if (i2_m_q2_a1_d0 > 0x800) { i2_m_q2_a1_d0 = -((0xfff - i2_m_q2_a1_d0) + 1); } if (iq_corr_a1_d0 > 0x800) { iq_corr_a1_d0 = -((0xfff - iq_corr_a1_d0) + 1); } i2_m_q2_a1_d1 = (iq_res[4] >> 12) & 0xfff; i2_p_q2_a1_d1 = ((iq_res[4] >> 24) & 0xff) + ((iq_res[5] & 0xf) << 8); iq_corr_a1_d1 = (iq_res[5] >> 4) & 0xfff; if (i2_m_q2_a1_d1 > 0x800) { i2_m_q2_a1_d1 = -((0xfff - i2_m_q2_a1_d1) + 1); } if (iq_corr_a1_d1 > 0x800) { iq_corr_a1_d1 = -((0xfff - iq_corr_a1_d1) + 1); } if ((i2_p_q2_a0_d0 == 0) || (i2_p_q2_a0_d1 == 0) || (i2_p_q2_a1_d0 == 0) || (i2_p_q2_a1_d1 == 0)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d):\na0_d0=%d\na0_d1=%d\na2_d0=%d\na1_d1=%d\n", __func__, __LINE__, i2_p_q2_a0_d0, i2_p_q2_a0_d1, i2_p_q2_a1_d0, i2_p_q2_a1_d1); return AH_FALSE; } if ((i2_p_q2_a0_d0 <= 1024) || (i2_p_q2_a0_d0 > 2047) || (i2_p_q2_a1_d0 < 0) || (i2_p_q2_a1_d1 < 0) || (i2_p_q2_a0_d0 <= i2_m_q2_a0_d0) || (i2_p_q2_a0_d0 <= iq_corr_a0_d0) || (i2_p_q2_a0_d1 <= i2_m_q2_a0_d1) || (i2_p_q2_a0_d1 <= iq_corr_a0_d1) || (i2_p_q2_a1_d0 <= i2_m_q2_a1_d0) || (i2_p_q2_a1_d0 <= iq_corr_a1_d0) || (i2_p_q2_a1_d1 <= i2_m_q2_a1_d1) || (i2_p_q2_a1_d1 <= iq_corr_a1_d1)) { return AH_FALSE; } mag_a0_d0 = (i2_m_q2_a0_d0 * res_scale) / i2_p_q2_a0_d0; phs_a0_d0 = (iq_corr_a0_d0 * res_scale) / i2_p_q2_a0_d0; mag_a0_d1 = (i2_m_q2_a0_d1 * res_scale) / i2_p_q2_a0_d1; phs_a0_d1 = (iq_corr_a0_d1 * res_scale) / i2_p_q2_a0_d1; mag_a1_d0 = (i2_m_q2_a1_d0 * res_scale) / i2_p_q2_a1_d0; phs_a1_d0 = (iq_corr_a1_d0 * res_scale) / i2_p_q2_a1_d0; mag_a1_d1 = (i2_m_q2_a1_d1 * res_scale) / i2_p_q2_a1_d1; phs_a1_d1 = (iq_corr_a1_d1 * res_scale) / i2_p_q2_a1_d1; /* without analog phase shift */ sin_2phi_1 = (((mag_a0_d0 - mag_a0_d1) * delpt_shift) / DELPT); /* without analog phase shift */ cos_2phi_1 = (((phs_a0_d1 - phs_a0_d0) * delpt_shift) / DELPT); /* with analog phase shift */ sin_2phi_2 = (((mag_a1_d0 - mag_a1_d1) * delpt_shift) / DELPT); /* with analog phase shift */ cos_2phi_2 = (((phs_a1_d1 - phs_a1_d0) * delpt_shift) / DELPT); /* force sin^2 + cos^2 = 1; */ /* find magnitude by approximation */ mag1 = ar9300_find_mag_approx(ah, cos_2phi_1, sin_2phi_1); mag2 = ar9300_find_mag_approx(ah, cos_2phi_2, sin_2phi_2); if ((mag1 == 0) || (mag2 == 0)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d): mag1=%d, mag2=%d\n", __func__, __LINE__, mag1, mag2); return AH_FALSE; } /* normalization sin and cos by mag */ sin_2phi_1 = (sin_2phi_1 * res_scale / mag1); cos_2phi_1 = (cos_2phi_1 * res_scale / mag1); sin_2phi_2 = (sin_2phi_2 * res_scale / mag2); cos_2phi_2 = (cos_2phi_2 * res_scale / mag2); /* calculate IQ mismatch */ if (AH_FALSE == ar9300_solve_iq_cal(ah, sin_2phi_1, cos_2phi_1, sin_2phi_2, cos_2phi_2, mag_a0_d0, phs_a0_d0, mag_a1_d0, phs_a1_d0, solved_eq)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Call to ar9300_solve_iq_cal failed.\n", __func__); return AH_FALSE; } mag_tx = solved_eq[0]; phs_tx = solved_eq[1]; mag_rx = solved_eq[2]; phs_rx = solved_eq[3]; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: chain %d: mag mismatch=%d phase mismatch=%d\n", __func__, chain_idx, mag_tx / res_scale, phs_tx / res_scale); if (res_scale == mag_tx) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d): mag_tx=%d, res_scale=%d\n", __func__, __LINE__, mag_tx, res_scale); return AH_FALSE; } /* calculate and quantize Tx IQ correction factor */ mag_corr_tx = (mag_tx * res_scale) / (res_scale - mag_tx); phs_corr_tx = -phs_tx; q_q_coff = (mag_corr_tx * 128 / res_scale); q_i_coff = (phs_corr_tx * 256 / res_scale); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: tx chain %d: mag corr=%d phase corr=%d\n", __func__, chain_idx, q_q_coff, q_i_coff); if (q_i_coff < -63) { q_i_coff = -63; } if (q_i_coff > 63) { q_i_coff = 63; } if (q_q_coff < -63) { q_q_coff = -63; } if (q_q_coff > 63) { q_q_coff = 63; } iqc_coeff[0] = (q_q_coff * 128) + (0x7f & q_i_coff); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: tx chain %d: iq corr coeff=%x\n", __func__, chain_idx, iqc_coeff[0]); if (-mag_rx == res_scale) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Divide by 0(%d): mag_rx=%d, res_scale=%d\n", __func__, __LINE__, mag_rx, res_scale); return AH_FALSE; } /* calculate and quantize Rx IQ correction factors */ mag_corr_rx = (-mag_rx * res_scale) / (res_scale + mag_rx); phs_corr_rx = -phs_rx; q_q_coff = (mag_corr_rx * 128 / res_scale); q_i_coff = (phs_corr_rx * 256 / res_scale); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: rx chain %d: mag corr=%d phase corr=%d\n", __func__, chain_idx, q_q_coff, q_i_coff); if (q_i_coff < -63) { q_i_coff = -63; } if (q_i_coff > 63) { q_i_coff = 63; } if (q_q_coff < -63) { q_q_coff = -63; } if (q_q_coff > 63) { q_q_coff = 63; } iqc_coeff[1] = (q_q_coff * 128) + (0x7f & q_i_coff); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: rx chain %d: iq corr coeff=%x\n", __func__, chain_idx, iqc_coeff[1]); return AH_TRUE; } #define MAX_MAG_DELTA 11 //maximum magnitude mismatch delta across gains #define MAX_PHS_DELTA 10 //maximum phase mismatch delta across gains #define ABS(x) ((x) >= 0 ? (x) : (-(x))) u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, }; static void ar9300_tx_iq_cal_outlier_detection(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan, u_int32_t num_chains, struct coeff_t *coeff, HAL_BOOL is_cal_reusable) { int nmeasurement, ch_idx, im; int32_t magnitude, phase; int32_t magnitude_max, phase_max; int32_t magnitude_min, phase_min; int32_t magnitude_max_idx, phase_max_idx; int32_t magnitude_min_idx, phase_min_idx; int32_t magnitude_avg, phase_avg; int32_t outlier_mag_idx = 0; int32_t outlier_phs_idx = 0; if (AR_SREV_POSEIDON(ah)) { HALASSERT(num_chains == 0x1); tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; } for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { nmeasurement = OS_REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); if (nmeasurement > MAX_MEASUREMENT) { nmeasurement = MAX_MEASUREMENT; } if (!AR_SREV_SCORPION(ah)) { /* * reset max/min variable to min/max values so that * we always start with 1st calibrated gain value */ magnitude_max = -64; phase_max = -64; magnitude_min = 63; phase_min = 63; magnitude_avg = 0; phase_avg = 0; magnitude_max_idx = 0; magnitude_min_idx = 0; phase_max_idx = 0; phase_min_idx = 0; /* detect outlier only if nmeasurement > 1 */ if (nmeasurement > 1) { /* printf("----------- start outlier detection -----------\n"); */ /* * find max/min and phase/mag mismatch across all calibrated gains */ for (im = 0; im < nmeasurement; im++) { magnitude = coeff->mag_coeff[ch_idx][im][0]; phase = coeff->phs_coeff[ch_idx][im][0]; magnitude_avg = magnitude_avg + magnitude; phase_avg = phase_avg + phase; if (magnitude > magnitude_max) { magnitude_max = magnitude; magnitude_max_idx = im; } if (magnitude < magnitude_min) { magnitude_min = magnitude; magnitude_min_idx = im; } if (phase > phase_max) { phase_max = phase; phase_max_idx = im; } if (phase < phase_min) { phase_min = phase; phase_min_idx = im; } } /* find average (exclude max abs value) */ for (im = 0; im < nmeasurement; im++) { magnitude = coeff->mag_coeff[ch_idx][im][0]; phase = coeff->phs_coeff[ch_idx][im][0]; if ((ABS(magnitude) < ABS(magnitude_max)) || (ABS(magnitude) < ABS(magnitude_min))) { magnitude_avg = magnitude_avg + magnitude; } if ((ABS(phase) < ABS(phase_max)) || (ABS(phase) < ABS(phase_min))) { phase_avg = phase_avg + phase; } } magnitude_avg = magnitude_avg / (nmeasurement - 1); phase_avg = phase_avg / (nmeasurement - 1); /* detect magnitude outlier */ if (ABS(magnitude_max - magnitude_min) > MAX_MAG_DELTA) { if (ABS(magnitude_max - magnitude_avg) > ABS(magnitude_min - magnitude_avg)) { /* max is outlier, force to avg */ outlier_mag_idx = magnitude_max_idx; } else { /* min is outlier, force to avg */ outlier_mag_idx = magnitude_min_idx; } coeff->mag_coeff[ch_idx][outlier_mag_idx][0] = magnitude_avg; coeff->phs_coeff[ch_idx][outlier_mag_idx][0] = phase_avg; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "[ch%d][outlier mag gain%d]:: " "mag_avg = %d (/128), phase_avg = %d (/256)\n", ch_idx, outlier_mag_idx, magnitude_avg, phase_avg); } /* detect phase outlier */ if (ABS(phase_max - phase_min) > MAX_PHS_DELTA) { if (ABS(phase_max-phase_avg) > ABS(phase_min - phase_avg)) { /* max is outlier, force to avg */ outlier_phs_idx = phase_max_idx; } else{ /* min is outlier, force to avg */ outlier_phs_idx = phase_min_idx; } coeff->mag_coeff[ch_idx][outlier_phs_idx][0] = magnitude_avg; coeff->phs_coeff[ch_idx][outlier_phs_idx][0] = phase_avg; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "[ch%d][outlier phs gain%d]:: " "mag_avg = %d (/128), phase_avg = %d (/256)\n", ch_idx, outlier_phs_idx, magnitude_avg, phase_avg); } } } /*printf("------------ after outlier detection -------------\n");*/ for (im = 0; im < nmeasurement; im++) { magnitude = coeff->mag_coeff[ch_idx][im][0]; phase = coeff->phs_coeff[ch_idx][im][0]; #if 0 printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n", ch_idx, im, magnitude, phase); #endif coeff->iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7); if ((im % 2) == 0) { OS_REG_RMW_FIELD(ah, tx_corr_coeff[im][ch_idx], AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, coeff->iqc_coeff[0]); } else { OS_REG_RMW_FIELD(ah, tx_corr_coeff[im][ch_idx], AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, coeff->iqc_coeff[0]); } #if ATH_SUPPORT_CAL_REUSE ichan->tx_corr_coeff[im][ch_idx] = coeff->iqc_coeff[0]; #endif } #if ATH_SUPPORT_CAL_REUSE ichan->num_measures[ch_idx] = nmeasurement; #endif } OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); #if ATH_SUPPORT_CAL_REUSE if (is_cal_reusable) { ichan->one_time_txiqcal_done = AH_TRUE; HALDEBUG(ah, HAL_DEBUG_FCS_RTT, "(FCS) TXIQCAL saved - %d\n", ichan->channel); } #endif } #if ATH_SUPPORT_CAL_REUSE static void ar9300_tx_iq_cal_apply(struct ath_hal *ah, HAL_CHANNEL_INTERNAL *ichan) { struct ath_hal_9300 *ahp = AH9300(ah); int nmeasurement, ch_idx, im; u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, }; if (AR_SREV_POSEIDON(ah)) { HALASSERT(ahp->ah_tx_cal_chainmask == 0x1); tx_corr_coeff[0][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; tx_corr_coeff[1][0] = AR_PHY_TX_IQCAL_CORR_COEFF_01_B0_POSEIDON; tx_corr_coeff[2][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; tx_corr_coeff[3][0] = AR_PHY_TX_IQCAL_CORR_COEFF_23_B0_POSEIDON; tx_corr_coeff[4][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; tx_corr_coeff[5][0] = AR_PHY_TX_IQCAL_CORR_COEFF_45_B0_POSEIDON; tx_corr_coeff[6][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; tx_corr_coeff[7][0] = AR_PHY_TX_IQCAL_CORR_COEFF_67_B0_POSEIDON; } for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { if ((ahp->ah_tx_cal_chainmask & (1 << ch_idx)) == 0) { continue; } nmeasurement = ichan->num_measures[ch_idx]; for (im = 0; im < nmeasurement; im++) { if ((im % 2) == 0) { OS_REG_RMW_FIELD(ah, tx_corr_coeff[im][ch_idx], AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, ichan->tx_corr_coeff[im][ch_idx]); } else { OS_REG_RMW_FIELD(ah, tx_corr_coeff[im][ch_idx], AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, ichan->tx_corr_coeff[im][ch_idx]); } } } OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); OS_REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0, AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); } #endif /* * ar9300_tx_iq_cal_hw_run is only needed for osprey/wasp/hornet * It is not needed for jupiter/poseidon. */ HAL_BOOL ar9300_tx_iq_cal_hw_run(struct ath_hal *ah) { int is_tx_gain_forced; is_tx_gain_forced = OS_REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE); if (is_tx_gain_forced) { /*printf("Tx gain can not be forced during tx I/Q cal!\n");*/ OS_REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN, AR_PHY_TXGAIN_FORCE, 0); } /* enable tx IQ cal */ OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, AR_PHY_TX_IQCAL_START_DO_CAL); if (!ath_hal_wait(ah, AR_PHY_TX_IQCAL_START(ah), AR_PHY_TX_IQCAL_START_DO_CAL, 0)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Tx IQ Cal is never completed.\n", __func__); return AH_FALSE; } return AH_TRUE; } static void ar9300_tx_iq_cal_post_proc(struct ath_hal *ah,HAL_CHANNEL_INTERNAL *ichan, int iqcal_idx, int max_iqcal,HAL_BOOL is_cal_reusable, HAL_BOOL apply_last_corr) { int nmeasurement=0, im, ix, iy, temp; struct ath_hal_9300 *ahp = AH9300(ah); u_int32_t txiqcal_status[AR9300_MAX_CHAINS] = { AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_TX_IQCAL_STATUS_B1, AR_PHY_TX_IQCAL_STATUS_B2, }; const u_int32_t chan_info_tab[] = { AR_PHY_CHAN_INFO_TAB_0, AR_PHY_CHAN_INFO_TAB_1, AR_PHY_CHAN_INFO_TAB_2, }; int32_t iq_res[6]; int32_t ch_idx, j; u_int32_t num_chains = 0; static struct coeff_t coeff; txiqcal_status[0] = AR_PHY_TX_IQCAL_STATUS_B0(ah); for (ch_idx = 0; ch_idx < AR9300_MAX_CHAINS; ch_idx++) { if (ahp->ah_tx_chainmask & (1 << ch_idx)) { num_chains++; } } if (apply_last_corr) { if (coeff.last_cal == AH_TRUE) { int32_t magnitude, phase; int ch_idx, im; u_int32_t tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS] = { { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_01_B0, AR_PHY_TX_IQCAL_CORR_COEFF_01_B1, AR_PHY_TX_IQCAL_CORR_COEFF_01_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_23_B0, AR_PHY_TX_IQCAL_CORR_COEFF_23_B1, AR_PHY_TX_IQCAL_CORR_COEFF_23_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_45_B0, AR_PHY_TX_IQCAL_CORR_COEFF_45_B1, AR_PHY_TX_IQCAL_CORR_COEFF_45_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, { AR_PHY_TX_IQCAL_CORR_COEFF_67_B0, AR_PHY_TX_IQCAL_CORR_COEFF_67_B1, AR_PHY_TX_IQCAL_CORR_COEFF_67_B2}, }; for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { for (im = 0; im < coeff.last_nmeasurement; im++) { magnitude = coeff.mag_coeff[ch_idx][im][0]; phase = coeff.phs_coeff[ch_idx][im][0]; #if 0 printf("[ch%d][gain%d]:: mag = %d (/128), phase = %d (/256)\n", ch_idx, im, magnitude, phase); #endif coeff.iqc_coeff[0] = (phase & 0x7f) | ((magnitude & 0x7f) << 7); if ((im % 2) == 0) { OS_REG_RMW_FIELD(ah, tx_corr_coeff[im][ch_idx], AR_PHY_TX_IQCAL_CORR_COEFF_00_COEFF_TABLE, coeff.iqc_coeff[0]); } else { OS_REG_RMW_FIELD(ah, tx_corr_coeff[im][ch_idx], AR_PHY_TX_IQCAL_CORR_COEFF_01_COEFF_TABLE, coeff.iqc_coeff[0]); } } } OS_REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3, AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x1); } return; } for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { nmeasurement = OS_REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0(ah), AR_PHY_CALIBRATED_GAINS_0); if (nmeasurement > MAX_MEASUREMENT) { nmeasurement = MAX_MEASUREMENT; } for (im = 0; im < nmeasurement; im++) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Doing Tx IQ Cal for chain %d.\n", __func__, ch_idx); if (OS_REG_READ(ah, txiqcal_status[ch_idx]) & AR_PHY_TX_IQCAL_STATUS_FAILED) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Tx IQ Cal failed for chain %d.\n", __func__, ch_idx); goto TX_IQ_CAL_FAILED_; } for (j = 0; j < 3; j++) { u_int32_t idx = 2 * j; /* 3 registers for each calibration result */ u_int32_t offset = 4 * (3 * im + j); OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, AR_PHY_CHAN_INFO_TAB_S2_READ, 0); /* 32 bits */ iq_res[idx] = OS_REG_READ(ah, chan_info_tab[ch_idx] + offset); OS_REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY, AR_PHY_CHAN_INFO_TAB_S2_READ, 1); /* 16 bits */ iq_res[idx + 1] = 0xffff & OS_REG_READ(ah, chan_info_tab[ch_idx] + offset); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n", __func__, idx, iq_res[idx], idx + 1, iq_res[idx + 1]); } if (AH_FALSE == ar9300_calc_iq_corr( ah, ch_idx, iq_res, coeff.iqc_coeff)) { HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "%s: Failed in calculation of IQ correction.\n", __func__); goto TX_IQ_CAL_FAILED_; } coeff.phs_coeff[ch_idx][im][iqcal_idx-1] = coeff.iqc_coeff[0] & 0x7f; coeff.mag_coeff[ch_idx][im][iqcal_idx-1] = (coeff.iqc_coeff[0] >> 7) & 0x7f; if (coeff.mag_coeff[ch_idx][im][iqcal_idx-1] > 63) { coeff.mag_coeff[ch_idx][im][iqcal_idx-1] -= 128; } if (coeff.phs_coeff[ch_idx][im][iqcal_idx-1] > 63) { coeff.phs_coeff[ch_idx][im][iqcal_idx-1] -= 128; } #if 0 ath_hal_printf(ah, "IQCAL::[ch%d][gain%d]:: mag = %d phase = %d \n", ch_idx, im, coeff.mag_coeff[ch_idx][im][iqcal_idx-1], coeff.phs_coeff[ch_idx][im][iqcal_idx-1]); #endif } } //last iteration; calculate mag and phs if (iqcal_idx == max_iqcal) { if (max_iqcal>1) { for (ch_idx = 0; ch_idx < num_chains; ch_idx++) { for (im = 0; im < nmeasurement; im++) { //sort mag and phs for( ix=0;ixah_phyrestart_disabled = 1; } else { val |= AR_PHY_RESTART_ENA; AH9300(ah)->ah_phyrestart_disabled = 0; } OS_REG_WRITE(ah, AR_PHY_RESTART, val); val = OS_REG_READ(ah, AR_PHY_RESTART); } HAL_BOOL ar9300_interference_is_present(struct ath_hal *ah) { int i; struct ath_hal_private *ahpriv = AH_PRIVATE(ah); const struct ieee80211_channel *chan = ahpriv->ah_curchan; HAL_CHANNEL_INTERNAL *ichan = ath_hal_checkchannel(ah, chan); if (ichan == NULL) { ath_hal_printf(ah, "%s: called with ichan=NULL\n", __func__); return AH_FALSE; } /* This function is called after a stuck beacon, if EACS is enabled. * If CW interference is severe, then HW goes into a loop of continuous * stuck beacons and resets. On reset the NF cal history is cleared. * So the median value of the history cannot be used - * hence check if any value (Chain 0/Primary Channel) * is outside the bounds. */ HAL_NFCAL_HIST_FULL *h = AH_HOME_CHAN_NFCAL_HIST(ah, ichan); for (i = 0; i < HAL_NF_CAL_HIST_LEN_FULL; i++) { if (h->nf_cal_buffer[i][0] > AH9300(ah)->nfp->nominal + AH9300(ah)->nf_cw_int_delta) { return AH_TRUE; } } return AH_FALSE; } #if ATH_SUPPORT_CRDC void ar9300_crdc_rx_notify(struct ath_hal *ah, struct ath_rx_status *rxs) { struct ath_hal_private *ahpriv = AH_PRIVATE(ah); int rssi_index; if ((!AR_SREV_WASP(ah)) || (!ahpriv->ah_config.ath_hal_crdc_enable)) { return; } if (rxs->rs_isaggr && rxs->rs_moreaggr) { return; } if ((rxs->rs_rssi_ctl0 >= HAL_RSSI_BAD) || (rxs->rs_rssi_ctl1 >= HAL_RSSI_BAD)) { return; } rssi_index = ah->ah_crdc_rssi_ptr % HAL_MAX_CRDC_RSSI_SAMPLE; ah->ah_crdc_rssi_sample[0][rssi_index] = rxs->rs_rssi_ctl0; ah->ah_crdc_rssi_sample[1][rssi_index] = rxs->rs_rssi_ctl1; ah->ah_crdc_rssi_ptr++; } static int ar9300_crdc_avg_rssi(struct ath_hal *ah, int chain) { int crdc_rssi_sum = 0; int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr, i; struct ath_hal_private *ahpriv = AH_PRIVATE(ah); int crdc_window = ahpriv->ah_config.ath_hal_crdc_window; if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) { crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE; } for (i = 1; i <= crdc_window; i++) { crdc_rssi_sum += ah->ah_crdc_rssi_sample[chain] [(crdc_rssi_ptr - i) % HAL_MAX_CRDC_RSSI_SAMPLE]; } return crdc_rssi_sum / crdc_window; } static void ar9300_crdc_activate(struct ath_hal *ah, int rssi_diff, int enable) { int val, orig_val; struct ath_hal_private *ahpriv = AH_PRIVATE(ah); int crdc_numerator = ahpriv->ah_config.ath_hal_crdc_numerator; int crdc_denominator = ahpriv->ah_config.ath_hal_crdc_denominator; int c = (rssi_diff * crdc_numerator) / crdc_denominator; val = orig_val = OS_REG_READ(ah, AR_PHY_MULTICHAIN_CTRL); val &= 0xffffff00; if (enable) { val |= 0x1; val |= ((c << 1) & 0xff); } OS_REG_WRITE(ah, AR_PHY_MULTICHAIN_CTRL, val); HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "diff: %02d comp: %02d reg: %08x %08x\n", rssi_diff, c, orig_val, val); } void ar9300_chain_rssi_diff_compensation(struct ath_hal *ah) { struct ath_hal_private *ahpriv = AH_PRIVATE(ah); int crdc_window = ahpriv->ah_config.ath_hal_crdc_window; int crdc_rssi_ptr = ah->ah_crdc_rssi_ptr; int crdc_rssi_thresh = ahpriv->ah_config.ath_hal_crdc_rssithresh; int crdc_diff_thresh = ahpriv->ah_config.ath_hal_crdc_diffthresh; int avg_rssi[2], avg_rssi_diff; if ((!AR_SREV_WASP(ah)) || (!ahpriv->ah_config.ath_hal_crdc_enable)) { if (ah->ah_crdc_rssi_ptr) { ar9300_crdc_activate(ah, 0, 0); ah->ah_crdc_rssi_ptr = 0; } return; } if (crdc_window > HAL_MAX_CRDC_RSSI_SAMPLE) { crdc_window = HAL_MAX_CRDC_RSSI_SAMPLE; } if (crdc_rssi_ptr < crdc_window) { return; } avg_rssi[0] = ar9300_crdc_avg_rssi(ah, 0); avg_rssi[1] = ar9300_crdc_avg_rssi(ah, 1); avg_rssi_diff = avg_rssi[1] - avg_rssi[0]; HALDEBUG(ah, HAL_DEBUG_CALIBRATE, "crdc: avg: %02d %02d ", avg_rssi[0], avg_rssi[1]); if ((avg_rssi[0] < crdc_rssi_thresh) && (avg_rssi[1] < crdc_rssi_thresh)) { ar9300_crdc_activate(ah, 0, 0); } else { if (ABS(avg_rssi_diff) >= crdc_diff_thresh) { ar9300_crdc_activate(ah, avg_rssi_diff, 1); } else { ar9300_crdc_activate(ah, 0, 1); } } } #endif #if ATH_ANT_DIV_COMB HAL_BOOL ar9300_ant_ctrl_set_lna_div_use_bt_ant(struct ath_hal *ah, HAL_BOOL enable, const struct ieee80211_channel *chan) { u_int32_t value; u_int32_t regval; struct ath_hal_9300 *ahp = AH9300(ah); HAL_CHANNEL_INTERNAL *ichan; struct ath_hal_private *ahpriv = AH_PRIVATE(ah); HAL_CAPABILITIES *pcap = &ahpriv->ah_caps; if (AR_SREV_POSEIDON(ah)) { // Make sure this scheme is only used for WB225(Astra) ahp->ah_lna_div_use_bt_ant_enable = enable; ichan = ar9300_check_chan(ah, chan); if ( ichan == AH_NULL ) { HALDEBUG(ah, HAL_DEBUG_CHANNEL, "%s: invalid channel %u/0x%x; no mapping\n", __func__, chan->ic_freq, chan->ic_flags); return AH_FALSE; } if ( enable == TRUE ) { pcap->halAntDivCombSupport = TRUE; } else { pcap->halAntDivCombSupport = pcap->halAntDivCombSupportOrg; } #define AR_SWITCH_TABLE_COM2_ALL (0xffffff) #define AR_SWITCH_TABLE_COM2_ALL_S (0) value = ar9300_ant_ctrl_common2_get(ah, IS_CHAN_2GHZ(ichan)); if ( enable == TRUE ) { value &= ~AR_SWITCH_TABLE_COM2_ALL; value |= ah->ah_config.ath_hal_ant_ctrl_comm2g_switch_enable; } HALDEBUG(ah, HAL_DEBUG_RESET, "%s: com2=0x%08x\n", __func__, value); OS_REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value); value = ar9300_eeprom_get(ahp, EEP_ANTDIV_control); /* main_lnaconf, alt_lnaconf, main_tb, alt_tb */ regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); regval &= (~ANT_DIV_CONTROL_ALL); /* clear bit 25~30 */ regval |= (value & 0x3f) << ANT_DIV_CONTROL_ALL_S; /* enable_lnadiv */ regval &= (~MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__MASK); regval |= ((value >> 6) & 0x1) << MULTICHAIN_GAIN_CTRL__ENABLE_ANT_DIV_LNADIV__SHIFT; if ( enable == TRUE ) { regval |= ANT_DIV_ENABLE; } OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); /* enable fast_div */ regval = OS_REG_READ(ah, AR_PHY_CCK_DETECT); regval &= (~BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__MASK); regval |= ((value >> 7) & 0x1) << BBB_SIG_DETECT__ENABLE_ANT_FAST_DIV__SHIFT; if ( enable == TRUE ) { regval |= FAST_DIV_ENABLE; } OS_REG_WRITE(ah, AR_PHY_CCK_DETECT, regval); if ( AR_SREV_POSEIDON_11_OR_LATER(ah) ) { if (pcap->halAntDivCombSupport) { /* If support DivComb, set MAIN to LNA1 and ALT to LNA2 at the first beginning */ regval = OS_REG_READ(ah, AR_PHY_MC_GAIN_CTRL); /* clear bit 25~30 main_lnaconf, alt_lnaconf, main_tb, alt_tb */ regval &= (~(MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__MASK | MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__MASK | MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_GAINTB__MASK | MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_GAINTB__MASK)); regval |= (HAL_ANT_DIV_COMB_LNA1 << MULTICHAIN_GAIN_CTRL__ANT_DIV_MAIN_LNACONF__SHIFT); regval |= (HAL_ANT_DIV_COMB_LNA2 << MULTICHAIN_GAIN_CTRL__ANT_DIV_ALT_LNACONF__SHIFT); OS_REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval); } } return AH_TRUE; } else { return AH_TRUE; } + + /* XXX TODO: Add AR9565 support? */ } #endif /* ATH_ANT_DIV_COMB */