/** * ath5k_hw_post - Power On Self Test helper function * * @ah: The &struct ath5k_hw */ static int ath5k_hw_post(struct ath5k_hw *ah) { static const u32 static_pattern[4] = { 0x55555555, 0xaaaaaaaa, 0x66666666, 0x99999999 }; static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) }; int i, c; u16 cur_reg; u32 var_pattern; u32 init_val; u32 cur_val; for (c = 0; c < 2; c++) { cur_reg = regs[c]; /* Save previous value */ init_val = ath5k_hw_reg_read(ah, cur_reg); for (i = 0; i < 256; i++) { var_pattern = i << 16 | i; ath5k_hw_reg_write(ah, var_pattern, cur_reg); cur_val = ath5k_hw_reg_read(ah, cur_reg); if (cur_val != var_pattern) { ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); return -EAGAIN; } /* Found on ndiswrapper dumps */ var_pattern = 0x0039080f; ath5k_hw_reg_write(ah, var_pattern, cur_reg); } for (i = 0; i < 4; i++) { var_pattern = static_pattern[i]; ath5k_hw_reg_write(ah, var_pattern, cur_reg); cur_val = ath5k_hw_reg_read(ah, cur_reg); if (cur_val != var_pattern) { ATH5K_ERR(ah->ah_sc, "POST Failed !!!\n"); return -EAGAIN; } /* Found on ndiswrapper dumps */ var_pattern = 0x003b080f; ath5k_hw_reg_write(ah, var_pattern, cur_reg); } /* Restore previous value */ ath5k_hw_reg_write(ah, init_val, cur_reg); } return 0; }
void ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) { #if 0 static const s8 lo[] = { -52, -56, -60, -64, -70 }; static const s8 hi[] = { -18, -18, -16, -14, -12 }; static const s8 sz[] = { -34, -41, -48, -55, -62 }; static const s8 fr[] = { -70, -72, -75, -78, -80 }; #else static const s8 lo[] = { -64, -70 }; static const s8 hi[] = { -14, -12 }; static const s8 sz[] = { -55, -62 }; static const s8 fr[] = { -78, -80 }; #endif if (level < 0 || level >= ARRAY_SIZE(sz)) { ATH5K_ERR(ah, "noise immunity level %d out of range", level); return; } AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, AR5K_PHY_DESIRED_SIZE_TOT, sz[level]); AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_LO, lo[level]); AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, hi[level]); AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, fr[level]); ah->ani_state.noise_imm_level = level; ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); }
/** * ath5k_hw_setup_mrr_tx_desc() - Initialize an MRR tx control descriptor * @ah: The &struct ath5k_hw * @desc: The &struct ath5k_desc * @tx_rate1: HW idx for rate used on transmission series 1 * @tx_tries1: Max number of retransmissions for transmission series 1 * @tx_rate2: HW idx for rate used on transmission series 2 * @tx_tries2: Max number of retransmissions for transmission series 2 * @tx_rate3: HW idx for rate used on transmission series 3 * @tx_tries3: Max number of retransmissions for transmission series 3 * * Multi rate retry (MRR) tx control descriptors are available only on AR5212 * MACs, they are part of the normal 4-word tx control descriptor (see above) * but we handle them through a separate function for better abstraction. * * Returns 0 on success or -EINVAL on invalid input */ int ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, u_int tx_rate1, u_int tx_tries1, u_int tx_rate2, u_int tx_tries2, u_int tx_rate3, u_int tx_tries3) { struct ath5k_hw_4w_tx_ctl *tx_ctl; /* no mrr support for cards older than 5212 */ if (ah->ah_version < AR5K_AR5212) return 0; /* * Rates can be 0 as long as the retry count is 0 too. * A zero rate and nonzero retry count will put the HW into a mode where * it continuously sends noise on the channel, so it is important to * avoid this. */ if (unlikely((tx_rate1 == 0 && tx_tries1 != 0) || (tx_rate2 == 0 && tx_tries2 != 0) || (tx_rate3 == 0 && tx_tries3 != 0))) { ATH5K_ERR(ah, "zero rate\n"); WARN_ON(1); return -EINVAL; } if (ah->ah_version == AR5K_AR5212) { tx_ctl = &desc->ud.ds_tx5212.tx_ctl; #define _XTX_TRIES(_n) \ if (tx_tries##_n) { \ tx_ctl->tx_control_2 |= \ AR5K_REG_SM(tx_tries##_n, \ AR5K_4W_TX_DESC_CTL2_XMIT_TRIES##_n); \ tx_ctl->tx_control_3 |= \ AR5K_REG_SM(tx_rate##_n, \ AR5K_4W_TX_DESC_CTL3_XMIT_RATE##_n); \ } _XTX_TRIES(1); _XTX_TRIES(2); _XTX_TRIES(3); #undef _XTX_TRIES return 1; } return 0; }
int ath5k_sysfs_register(struct ath5k_softc *sc) { struct device *dev = sc->dev; int err; err = sysfs_create_group(&dev->kobj, &ath5k_attribute_group_ani); if (err) { ATH5K_ERR(sc, "failed to create sysfs group\n"); return err; } return 0; }
/** * ath5k_ani_set_firstep_level() - Set "firstep" level * @ah: The &struct ath5k_hw * @level: level between 0 and @ATH5K_ANI_MAX_FIRSTEP_LVL */ void ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level) { static const int val[] = { 0, 4, 8 }; if (level < 0 || level >= ARRAY_SIZE(val)) { ATH5K_ERR(ah, "firstep level %d out of range", level); return; } AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRSTEP, val[level]); ah->ani_state.firstep_level = level; ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); }
/** * ath5k_ani_set_spur_immunity_level() - Set spur immunity level * @ah: The &struct ath5k_hw * @level: level between 0 and @max_spur_level (the maximum level is dependent * on the chip revision). */ void ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level) { static const int val[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; if (level < 0 || level >= ARRAY_SIZE(val) || level > ah->ani_state.max_spur_level) { ATH5K_ERR(ah, "spur immunity level %d out of range", level); return; } AR5K_REG_WRITE_BITS(ah, AR5K_PHY_OFDM_SELFCORR, AR5K_PHY_OFDM_SELFCORR_CYPWR_THR1, val[level]); ah->ani_state.spur_level = level; ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); }
/** * ath5k_hw_init_queues() - Initialize tx queues * @ah: The &struct ath5k_hw * * Initializes all tx queues based on information on * ah->ah_txq* set by the driver */ int ath5k_hw_init_queues(struct ath5k_hw *ah) { int i, ret; /* TODO: HW Compression support for data queues */ /* TODO: Burst prefetch for data queues */ /* * Reset queues and start beacon timers at the end of the reset routine * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping * Note: If we want we can assign multiple qcus on one dcu. */ if (ah->ah_version != AR5K_AR5210) for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) { ret = ath5k_hw_reset_tx_queue(ah, i); if (ret) { ATH5K_ERR(ah, "failed to reset TX queue #%d\n", i); return ret; } } else /* No QCU/DCU on AR5210, just set tx * retry limits. We set IFS parameters * on ath5k_hw_set_ifs_intervals */ ath5k_hw_set_tx_retry_limits(ah, 0); /* Set the turbo flag when operating on 40MHz */ if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) AR5K_REG_ENABLE_BITS(ah, AR5K_DCU_GBL_IFS_MISC, AR5K_DCU_GBL_IFS_MISC_TURBO_MODE); /* If we didn't set IFS timings through * ath5k_hw_set_coverage_class make sure * we set them here */ if (!ah->ah_coverage_class) { unsigned int slot_time = ath5k_hw_get_default_slottime(ah); ath5k_hw_set_ifs_intervals(ah, slot_time); } return 0; }
/** * ath5k_ani_set_noise_immunity_level() - Set noise immunity level * @ah: The &struct ath5k_hw * @level: level between 0 and @ATH5K_ANI_MAX_NOISE_IMM_LVL */ void ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level) { /* TODO: * ANI documents suggest the following five levels to use, but the HAL * and ath9k use only the last two levels, making this * essentially an on/off option. There *may* be a reason for this (???), * so i stick with the HAL version for now... */ #if 0 static const s8 lo[] = { -52, -56, -60, -64, -70 }; static const s8 hi[] = { -18, -18, -16, -14, -12 }; static const s8 sz[] = { -34, -41, -48, -55, -62 }; static const s8 fr[] = { -70, -72, -75, -78, -80 }; #else static const s8 lo[] = { -64, -70 }; static const s8 hi[] = { -14, -12 }; static const s8 sz[] = { -55, -62 }; static const s8 fr[] = { -78, -80 }; #endif if (level < 0 || level >= ARRAY_SIZE(sz)) { ATH5K_ERR(ah, "noise immunity level %d out of range", level); return; } AR5K_REG_WRITE_BITS(ah, AR5K_PHY_DESIRED_SIZE, AR5K_PHY_DESIRED_SIZE_TOT, sz[level]); AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_LO, lo[level]); AR5K_REG_WRITE_BITS(ah, AR5K_PHY_AGCCOARSE, AR5K_PHY_AGCCOARSE_HI, hi[level]); AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SIG, AR5K_PHY_SIG_FIRPWR, fr[level]); ah->ani_state.noise_imm_level = level; ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "new level %d", level); }
/** * ath5k_ani_init() - Initialize ANI * @ah: The &struct ath5k_hw * @mode: One of enum ath5k_ani_mode * * Initialize ANI according to mode. */ void ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) { /* ANI is only possible on 5212 and newer */ if (ah->ah_version < AR5K_AR5212) return; if (mode < ATH5K_ANI_MODE_OFF || mode > ATH5K_ANI_MODE_AUTO) { ATH5K_ERR(ah, "ANI mode %d out of range", mode); return; } /* clear old state information */ memset(&ah->ani_state, 0, sizeof(ah->ani_state)); /* older hardware has more spur levels than newer */ if (ah->ah_mac_srev < AR5K_SREV_AR2414) ah->ani_state.max_spur_level = 7; else ah->ani_state.max_spur_level = 2; /* initial values for our ani parameters */ if (mode == ATH5K_ANI_MODE_OFF) { ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "ANI off\n"); } else if (mode == ATH5K_ANI_MODE_MANUAL_LOW) { ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "ANI manual low -> high sensitivity\n"); ath5k_ani_set_noise_immunity_level(ah, 0); ath5k_ani_set_spur_immunity_level(ah, 0); ath5k_ani_set_firstep_level(ah, 0); ath5k_ani_set_ofdm_weak_signal_detection(ah, true); ath5k_ani_set_cck_weak_signal_detection(ah, true); } else if (mode == ATH5K_ANI_MODE_MANUAL_HIGH) { ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "ANI manual high -> low sensitivity\n"); ath5k_ani_set_noise_immunity_level(ah, ATH5K_ANI_MAX_NOISE_IMM_LVL); ath5k_ani_set_spur_immunity_level(ah, ah->ani_state.max_spur_level); ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL); ath5k_ani_set_ofdm_weak_signal_detection(ah, false); ath5k_ani_set_cck_weak_signal_detection(ah, false); } else if (mode == ATH5K_ANI_MODE_AUTO) { ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "ANI auto\n"); ath5k_ani_set_noise_immunity_level(ah, 0); ath5k_ani_set_spur_immunity_level(ah, 0); ath5k_ani_set_firstep_level(ah, 0); ath5k_ani_set_ofdm_weak_signal_detection(ah, true); ath5k_ani_set_cck_weak_signal_detection(ah, false); } /* newer hardware has PHY error counter registers which we can use to * get OFDM and CCK error counts. older hardware has to set rxfilter and * report every single PHY error by calling ath5k_ani_phy_error_report() */ if (mode == ATH5K_ANI_MODE_AUTO) { if (ah->ah_capabilities.cap_has_phyerr_counters) ath5k_enable_phy_err_counters(ah); else ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) | AR5K_RX_FILTER_PHYERR); } else { if (ah->ah_capabilities.cap_has_phyerr_counters) ath5k_disable_phy_err_counters(ah); else ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) & ~AR5K_RX_FILTER_PHYERR); } ah->ani_state.ani_mode = mode; }
/** * ath5k_hw_setup_2word_tx_desc() - Initialize a 2-word tx control descriptor * @ah: The &struct ath5k_hw * @desc: The &struct ath5k_desc * @pkt_len: Frame length in bytes * @hdr_len: Header length in bytes (only used on AR5210) * @padsize: Any padding we've added to the frame length * @type: One of enum ath5k_pkt_type * @tx_power: Tx power in 0.5dB steps * @tx_rate0: HW idx for transmission rate * @tx_tries0: Max number of retransmissions * @key_index: Index on key table to use for encryption * @antenna_mode: Which antenna to use (0 for auto) * @flags: One of AR5K_TXDESC_* flags (desc.h) * @rtscts_rate: HW idx for RTS/CTS transmission rate * @rtscts_duration: What to put on duration field on the header of RTS/CTS * * Internal function to initialize a 2-Word TX control descriptor * found on AR5210 and AR5211 MACs chips. * * Returns 0 on success or -EINVAL on false input */ static int ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, int padsize, enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, unsigned int rtscts_duration) { u32 frame_type; struct ath5k_hw_2w_tx_ctl *tx_ctl; unsigned int frame_len; tx_ctl = &desc->ud.ds_tx5210.tx_ctl; /* * Validate input * - Zero retries don't make sense. * - A zero rate will put the HW into a mode where it continuously sends * noise on the channel, so it is important to avoid this. */ if (unlikely(tx_tries0 == 0)) { ATH5K_ERR(ah, "zero retries\n"); WARN_ON(1); return -EINVAL; } if (unlikely(tx_rate0 == 0)) { ATH5K_ERR(ah, "zero rate\n"); WARN_ON(1); return -EINVAL; } /* Clear descriptor */ memset(&desc->ud.ds_tx5210, 0, sizeof(struct ath5k_hw_5210_tx_desc)); /* Setup control descriptor */ /* Verify and set frame length */ /* remove padding we might have added before */ frame_len = pkt_len - padsize + FCS_LEN; if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; tx_ctl->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ /* NB: beacon's BufLen must be a multiple of 4 bytes */ if (type == AR5K_PKT_TYPE_BEACON) pkt_len = roundup(pkt_len, 4); if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; tx_ctl->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; /* * Verify and set header length (only 5210) */ if (ah->ah_version == AR5K_AR5210) { if (hdr_len & ~AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210) return -EINVAL; tx_ctl->tx_control_0 |= AR5K_REG_SM(hdr_len, AR5K_2W_TX_DESC_CTL0_HEADER_LEN_5210); } /*Differences between 5210-5211*/ if (ah->ah_version == AR5K_AR5210) { switch (type) { case AR5K_PKT_TYPE_BEACON: case AR5K_PKT_TYPE_PROBE_RESP: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_NO_DELAY; break; case AR5K_PKT_TYPE_PIFS: frame_type = AR5K_AR5210_TX_DESC_FRAME_TYPE_PIFS; break; default: frame_type = type; break; } tx_ctl->tx_control_0 |= AR5K_REG_SM(frame_type, AR5K_2W_TX_DESC_CTL0_FRAME_TYPE_5210) | AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE); } else { tx_ctl->tx_control_0 |= AR5K_REG_SM(tx_rate0, AR5K_2W_TX_DESC_CTL0_XMIT_RATE) | AR5K_REG_SM(antenna_mode, AR5K_2W_TX_DESC_CTL0_ANT_MODE_XMIT); tx_ctl->tx_control_1 |= AR5K_REG_SM(type, AR5K_2W_TX_DESC_CTL1_FRAME_TYPE_5211); } #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ tx_ctl->tx_control_##_c |= \ AR5K_2W_TX_DESC_CTL##_c##_##_flag; \ } #define _TX_FLAGS_5211(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ tx_ctl->tx_control_##_c |= \ AR5K_2W_TX_DESC_CTL##_c##_##_flag##_5211; \ } _TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA); if (ah->ah_version == AR5K_AR5211) { _TX_FLAGS_5211(0, VEOL); _TX_FLAGS_5211(1, NOACK); } #undef _TX_FLAGS #undef _TX_FLAGS_5211 /* * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { tx_ctl->tx_control_0 |= AR5K_2W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; tx_ctl->tx_control_1 |= AR5K_REG_SM(key_index, AR5K_2W_TX_DESC_CTL1_ENC_KEY_IDX); } /* * RTS/CTS Duration [5210 ?] */ if ((ah->ah_version == AR5K_AR5210) && (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA))) tx_ctl->tx_control_1 |= rtscts_duration & AR5K_2W_TX_DESC_CTL1_RTS_DURATION_5210; return 0; }
/** * ath5k_hw_setup_4word_tx_desc() - Initialize a 4-word tx control descriptor * @ah: The &struct ath5k_hw * @desc: The &struct ath5k_desc * @pkt_len: Frame length in bytes * @hdr_len: Header length in bytes (only used on AR5210) * @padsize: Any padding we've added to the frame length * @type: One of enum ath5k_pkt_type * @tx_power: Tx power in 0.5dB steps * @tx_rate0: HW idx for transmission rate * @tx_tries0: Max number of retransmissions * @key_index: Index on key table to use for encryption * @antenna_mode: Which antenna to use (0 for auto) * @flags: One of AR5K_TXDESC_* flags (desc.h) * @rtscts_rate: HW idx for RTS/CTS transmission rate * @rtscts_duration: What to put on duration field on the header of RTS/CTS * * Internal function to initialize a 4-Word TX control descriptor * found on AR5212 and later MACs chips. * * Returns 0 on success or -EINVAL on false input */ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, unsigned int pkt_len, unsigned int hdr_len, int padsize, enum ath5k_pkt_type type, unsigned int tx_power, unsigned int tx_rate0, unsigned int tx_tries0, unsigned int key_index, unsigned int antenna_mode, unsigned int flags, unsigned int rtscts_rate, unsigned int rtscts_duration) { struct ath5k_hw_4w_tx_ctl *tx_ctl; unsigned int frame_len; /* * Use local variables for these to reduce load/store access on * uncached memory */ u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0; tx_ctl = &desc->ud.ds_tx5212.tx_ctl; /* * Validate input * - Zero retries don't make sense. * - A zero rate will put the HW into a mode where it continuously sends * noise on the channel, so it is important to avoid this. */ if (unlikely(tx_tries0 == 0)) { ATH5K_ERR(ah, "zero retries\n"); WARN_ON(1); return -EINVAL; } if (unlikely(tx_rate0 == 0)) { ATH5K_ERR(ah, "zero rate\n"); WARN_ON(1); return -EINVAL; } tx_power += ah->ah_txpower.txp_offset; if (tx_power > AR5K_TUNE_MAX_TXPOWER) tx_power = AR5K_TUNE_MAX_TXPOWER; /* Clear descriptor status area */ memset(&desc->ud.ds_tx5212.tx_stat, 0, sizeof(desc->ud.ds_tx5212.tx_stat)); /* Setup control descriptor */ /* Verify and set frame length */ /* remove padding we might have added before */ frame_len = pkt_len - padsize + FCS_LEN; if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ /* NB: beacon's BufLen must be a multiple of 4 bytes */ if (type == AR5K_PKT_TYPE_BEACON) pkt_len = roundup(pkt_len, 4); if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT); txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE); txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0); txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0; #define _TX_FLAGS(_c, _flag) \ if (flags & AR5K_TXDESC_##_flag) { \ txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \ } _TX_FLAGS(0, CLRDMASK); _TX_FLAGS(0, VEOL); _TX_FLAGS(0, INTREQ); _TX_FLAGS(0, RTSENA); _TX_FLAGS(0, CTSENA); _TX_FLAGS(1, NOACK); #undef _TX_FLAGS /* * WEP crap */ if (key_index != AR5K_TXKEYIX_INVALID) { txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID; txctl1 |= AR5K_REG_SM(key_index, AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX); } /* * RTS/CTS */ if (flags & (AR5K_TXDESC_RTSENA | AR5K_TXDESC_CTSENA)) { if ((flags & AR5K_TXDESC_RTSENA) && (flags & AR5K_TXDESC_CTSENA)) return -EINVAL; txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION; txctl3 |= AR5K_REG_SM(rtscts_rate, AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE); } tx_ctl->tx_control_0 = txctl0; tx_ctl->tx_control_1 = txctl1; tx_ctl->tx_control_2 = txctl2; tx_ctl->tx_control_3 = txctl3; return 0; }
/* * Initialize eeprom & capabilities structs */ static int ath5k_eeprom_init_header(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; u16 val; u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX; /* * Read values from EEPROM and store them in the capability structure */ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); /* Return if we have an old EEPROM */ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) return 0; /* * Validate the checksum of the EEPROM date. There are some * devices with invalid EEPROMs. */ AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val); if (val) { eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) << AR5K_EEPROM_SIZE_ENDLOC_SHIFT; AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val); eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE; /* * Fail safe check to prevent stupid loops due * to busted EEPROMs. XXX: This value is likely too * big still, waiting on a better value. */ if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) { ATH5K_ERR(ah, "Invalid max custom EEPROM size: " "%d (0x%04x) max expected: %d (0x%04x)\n", eep_max, eep_max, 3 * AR5K_EEPROM_INFO_MAX, 3 * AR5K_EEPROM_INFO_MAX); return -EIO; } } for (cksum = 0, offset = 0; offset < eep_max; offset++) { AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); cksum ^= val; } if (cksum != AR5K_EEPROM_INFO_CKSUM) { ATH5K_ERR(ah, "Invalid EEPROM " "checksum: 0x%04x eep_max: 0x%04x (%s)\n", cksum, eep_max, eep_max == AR5K_EEPROM_INFO_MAX ? "default size" : "custom size"); return -EIO; } AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), ee_ant_gain); if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); /* XXX: Don't know which versions include these two */ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2); if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3); if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) { AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6); } } if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; }
static int ath5k_eeprom_init_header(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; int ret; u16 val; u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX; AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) return 0; AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val); if (val) { eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) << AR5K_EEPROM_SIZE_ENDLOC_SHIFT; AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val); eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE; if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) { ATH5K_ERR(ah->ah_sc, "Invalid max custom EEPROM size: " "%d (0x%04x) max expected: %d (0x%04x)\n", eep_max, eep_max, 3 * AR5K_EEPROM_INFO_MAX, 3 * AR5K_EEPROM_INFO_MAX); return -EIO; } } for (cksum = 0, offset = 0; offset < eep_max; offset++) { AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); cksum ^= val; } if (cksum != AR5K_EEPROM_INFO_CKSUM) { ATH5K_ERR(ah->ah_sc, "Invalid EEPROM " "checksum: 0x%04x eep_max: 0x%04x (%s)\n", cksum, eep_max, eep_max == AR5K_EEPROM_INFO_MAX ? "default size" : "custom size"); return -EIO; } AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), ee_ant_gain); if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2); if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3); if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) { AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6); } } if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; }
int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu) { /* * Write initial register settings */ /* For AR5212 and compatible */ if (ah->ah_version == AR5K_AR5212) { /* First set of mode-specific settings */ ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_ini_mode_start), ar5212_ini_mode_start, mode); /* * Write initial settings common for all modes */ ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start), ar5212_ini_common_start, skip_pcu); /* Second set of mode-specific settings */ switch (ah->ah_radio) { case AR5K_RF5111: ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf5111_ini_mode_end), rf5111_ini_mode_end, mode); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_common_end), rf5111_ini_common_end, skip_pcu); /* Baseband gain table */ ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain), rf5111_ini_bbgain, skip_pcu); break; case AR5K_RF5112: ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf5112_ini_mode_end), rf5112_ini_mode_end, mode); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5112_ini_common_end), rf5112_ini_common_end, skip_pcu); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, skip_pcu); break; case AR5K_RF5413: ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf5413_ini_mode_end), rf5413_ini_mode_end, mode); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5413_ini_common_end), rf5413_ini_common_end, skip_pcu); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, skip_pcu); break; case AR5K_RF2316: case AR5K_RF2413: ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf2413_ini_mode_end), rf2413_ini_mode_end, mode); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf2413_ini_common_end), rf2413_ini_common_end, skip_pcu); /* Override settings from rf2413_ini_common_end */ if (ah->ah_radio == AR5K_RF2316) { ath5k_hw_reg_write(ah, 0x00004000, AR5K_PHY_AGC); ath5k_hw_reg_write(ah, 0x081b7caa, 0xa274); } ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, skip_pcu); break; case AR5K_RF2317: ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf2413_ini_mode_end), rf2413_ini_mode_end, mode); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf2425_ini_common_end), rf2425_ini_common_end, skip_pcu); /* Override settings from rf2413_ini_mode_end */ ath5k_hw_reg_write(ah, 0x00180a65, AR5K_PHY_GAIN); /* Override settings from rf2413_ini_common_end */ ath5k_hw_reg_write(ah, 0x00004000, AR5K_PHY_AGC); AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TPC_RG5, AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP, 0xa); ath5k_hw_reg_write(ah, 0x800000a8, 0x8140); ath5k_hw_reg_write(ah, 0x000000ff, 0x9958); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, skip_pcu); break; case AR5K_RF2425: ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf2425_ini_mode_end), rf2425_ini_mode_end, mode); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf2425_ini_common_end), rf2425_ini_common_end, skip_pcu); ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, skip_pcu); break; default: return -EINVAL; } /* For AR5211 */ } else if (ah->ah_version == AR5K_AR5211) { /* AR5K_MODE_11B */ if (mode > 2) { ATH5K_ERR(ah, "unsupported channel mode: %d\n", mode); return -EINVAL; } /* Mode-specific settings */ ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5211_ini_mode), ar5211_ini_mode, mode); /* * Write initial settings common for all modes */ ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini), ar5211_ini, skip_pcu); /* AR5211 only comes with 5111 */ /* Baseband gain table */ ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain), rf5111_ini_bbgain, skip_pcu); /* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */ } else if (ah->ah_version == AR5K_AR5210) { ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini), ar5210_ini, skip_pcu); } return 0; }
void ath5k_ani_init(struct ath5k_hw *ah, enum ath5k_ani_mode mode) { if (ah->ah_version < AR5K_AR5212) return; if (mode < ATH5K_ANI_MODE_OFF || mode > ATH5K_ANI_MODE_AUTO) { ATH5K_ERR(ah, "ANI mode %d out of range", mode); return; } memset(&ah->ani_state, 0, sizeof(ah->ani_state)); if (ah->ah_mac_srev < AR5K_SREV_AR2414) ah->ani_state.max_spur_level = 7; else ah->ani_state.max_spur_level = 2; if (mode == ATH5K_ANI_MODE_OFF) { ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "ANI off\n"); } else if (mode == ATH5K_ANI_MODE_MANUAL_LOW) { ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "ANI manual low -> high sensitivity\n"); ath5k_ani_set_noise_immunity_level(ah, 0); ath5k_ani_set_spur_immunity_level(ah, 0); ath5k_ani_set_firstep_level(ah, 0); ath5k_ani_set_ofdm_weak_signal_detection(ah, true); ath5k_ani_set_cck_weak_signal_detection(ah, true); } else if (mode == ATH5K_ANI_MODE_MANUAL_HIGH) { ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "ANI manual high -> low sensitivity\n"); ath5k_ani_set_noise_immunity_level(ah, ATH5K_ANI_MAX_NOISE_IMM_LVL); ath5k_ani_set_spur_immunity_level(ah, ah->ani_state.max_spur_level); ath5k_ani_set_firstep_level(ah, ATH5K_ANI_MAX_FIRSTEP_LVL); ath5k_ani_set_ofdm_weak_signal_detection(ah, false); ath5k_ani_set_cck_weak_signal_detection(ah, false); } else if (mode == ATH5K_ANI_MODE_AUTO) { ATH5K_DBG_UNLIMIT(ah, ATH5K_DEBUG_ANI, "ANI auto\n"); ath5k_ani_set_noise_immunity_level(ah, 0); ath5k_ani_set_spur_immunity_level(ah, 0); ath5k_ani_set_firstep_level(ah, 0); ath5k_ani_set_ofdm_weak_signal_detection(ah, true); ath5k_ani_set_cck_weak_signal_detection(ah, false); } if (mode == ATH5K_ANI_MODE_AUTO) { if (ah->ah_capabilities.cap_has_phyerr_counters) ath5k_enable_phy_err_counters(ah); else ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) | AR5K_RX_FILTER_PHYERR); } else { if (ah->ah_capabilities.cap_has_phyerr_counters) ath5k_disable_phy_err_counters(ah); else ath5k_hw_set_rx_filter(ah, ath5k_hw_get_rx_filter(ah) & ~AR5K_RX_FILTER_PHYERR); } ah->ani_state.ani_mode = mode; }
/* * Initialize eeprom & capabilities structs */ static int ath5k_eeprom_init_header(struct ath5k_hw *ah) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; int ret; u16 val; /* * Read values from EEPROM and store them in the capability structure */ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); /* Return if we have an old EEPROM */ if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) return 0; #ifdef notyet /* * Validate the checksum of the EEPROM date. There are some * devices with invalid EEPROMs. */ for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); cksum ^= val; } if (cksum != AR5K_EEPROM_INFO_CKSUM) { ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); return -EIO; } #endif AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), ee_ant_gain); if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); /* XXX: Don't know which versions include these two */ AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC2, ee_misc2); if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC3, ee_misc3); if (ee->ee_version >= AR5K_EEPROM_VERSION_5_0) { AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC4, ee_misc4); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC5, ee_misc5); AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC6, ee_misc6); } } if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; }