/**
 * 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;
}
Exemple #4
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;
}
Exemple #5
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);
}
Exemple #6
0
/**
 * 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);
}
Exemple #7
0
/**
 * 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;
}
Exemple #8
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);
}
Exemple #9
0
/**
 * 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;
}
Exemple #12
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;
	}
Exemple #13
0
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;
	}
Exemple #14
0
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;
}
Exemple #16
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;
	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;
	}