static inline void
ar9300_init_rate_txpower_cck(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
                         u_int8_t rates_array[], u_int8_t chainmask)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    /*
     * Pick the lower of the long-preamble txpower, and short-preamble tx power.
     * Unfortunately, the rate table doesn't have separate entries for these!.
     */
    switch (chainmask) {
    case OSPREY_1_CHAINMASK:
        ahp->txpower[0][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
        ahp->txpower[1][0] = rates_array[ALL_TARGET_LEGACY_1L_5L];
        ahp->txpower[2][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
                                  rates_array[ALL_TARGET_LEGACY_5S]);
        ahp->txpower[3][0] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
                                      rates_array[ALL_TARGET_LEGACY_11S]);
        break;
    case OSPREY_2LOHI_CHAINMASK:
    case OSPREY_2LOMID_CHAINMASK:
        ahp->txpower[0][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
        ahp->txpower[1][1] = rates_array[ALL_TARGET_LEGACY_1L_5L];
        ahp->txpower[2][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
                                  rates_array[ALL_TARGET_LEGACY_5S]);
        ahp->txpower[3][1] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
                                  rates_array[ALL_TARGET_LEGACY_11S]);
        break;
    case OSPREY_3_CHAINMASK:
        ahp->txpower[0][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
        ahp->txpower[1][2] = rates_array[ALL_TARGET_LEGACY_1L_5L];
        ahp->txpower[2][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_1L_5L],
                                   rates_array[ALL_TARGET_LEGACY_5S]);
        ahp->txpower[3][2] = AH_MIN(rates_array[ALL_TARGET_LEGACY_11L],
                                       rates_array[ALL_TARGET_LEGACY_11S]);
        break;
    default:
        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                 __func__, chainmask);
        break;
    }
}
Beispiel #2
0
/*
 * Sets the transmit power in the baseband for the given
 * operating channel and mode.
 */
static HAL_BOOL
setRateTable(struct ath_hal *ah, const struct ieee80211_channel *chan, 
		   int16_t tpcScaleReduction, int16_t powerLimit,
                   int16_t *pMinPower, int16_t *pMaxPower)
{
	u_int16_t ratesArray[16];
	u_int16_t *rpow = ratesArray;
	u_int16_t twiceMaxRDPower, twiceMaxEdgePower, twiceMaxEdgePowerCck;
	int8_t twiceAntennaGain, twiceAntennaReduction;
	TRGT_POWER_INFO targetPowerOfdm, targetPowerCck;
	RD_EDGES_POWER *rep;
	int16_t scaledPower;
	u_int8_t cfgCtl;

	twiceMaxRDPower = chan->ic_maxregpower * 2;
	*pMaxPower = -MAX_RATE_POWER;
	*pMinPower = MAX_RATE_POWER;

	/* Get conformance test limit maximum for this channel */
	cfgCtl = ath_hal_getctl(ah, chan);
	rep = findEdgePower(ah, cfgCtl);
	if (rep != AH_NULL)
		twiceMaxEdgePower = ar5212GetMaxEdgePower(chan->ic_freq, rep);
	else
		twiceMaxEdgePower = MAX_RATE_POWER;

	if (IEEE80211_IS_CHAN_G(chan)) {
		/* Check for a CCK CTL for 11G CCK powers */
		cfgCtl = (cfgCtl & 0xFC) | 0x01;
		rep = findEdgePower(ah, cfgCtl);
		if (rep != AH_NULL)
			twiceMaxEdgePowerCck = ar5212GetMaxEdgePower(chan->ic_freq, rep);
		else
			twiceMaxEdgePowerCck = MAX_RATE_POWER;
	} else {
		/* Set the 11B cck edge power to the one found before */
		twiceMaxEdgePowerCck = twiceMaxEdgePower;
	}

	/* Get Antenna Gain reduction */
	if (IEEE80211_IS_CHAN_5GHZ(chan)) {
		twiceAntennaGain = antennaGainMax[0];
	} else {
		twiceAntennaGain = antennaGainMax[1];
	}
	twiceAntennaReduction =
		ath_hal_getantennareduction(ah, chan, twiceAntennaGain);

	if (IEEE80211_IS_CHAN_OFDM(chan)) {
		/* Get final OFDM target powers */
		if (IEEE80211_IS_CHAN_G(chan)) { 
			/* TODO - add Turbo 2.4 to this mode check */
			ar5212GetTargetPowers(ah, chan, trgtPwr_11g,
				numTargetPwr_11g, &targetPowerOfdm);
		} else {
			ar5212GetTargetPowers(ah, chan, trgtPwr_11a,
				numTargetPwr_11a, &targetPowerOfdm);
		}

		/* Get Maximum OFDM power */
		/* Minimum of target and edge powers */
		scaledPower = AH_MIN(twiceMaxEdgePower,
				twiceMaxRDPower - twiceAntennaReduction);

		/*
		 * If turbo is set, reduce power to keep power
		 * consumption under 2 Watts.  Note that we always do
		 * this unless specially configured.  Then we limit
		 * power only for non-AP operation.
		 */
		if (IEEE80211_IS_CHAN_TURBO(chan)
#ifdef AH_ENABLE_AP_SUPPORT
		    && AH_PRIVATE(ah)->ah_opmode != HAL_M_HOSTAP
#endif
		) {
			/*
			 * If turbo is set, reduce power to keep power
			 * consumption under 2 Watts
			 */
			if (eeversion >= AR_EEPROM_VER3_1)
				scaledPower = AH_MIN(scaledPower,
					turbo2WMaxPower5);
			/*
			 * EEPROM version 4.0 added an additional
			 * constraint on 2.4GHz channels.
			 */
			if (eeversion >= AR_EEPROM_VER4_0 &&
			    IEEE80211_IS_CHAN_2GHZ(chan))
				scaledPower = AH_MIN(scaledPower,
					turbo2WMaxPower2);
		}
		/* Reduce power by max regulatory domain allowed restrictions */
		scaledPower -= (tpcScaleReduction * 2);
		scaledPower = (scaledPower < 0) ? 0 : scaledPower;
		scaledPower = AH_MIN(scaledPower, powerLimit);

		scaledPower = AH_MIN(scaledPower, targetPowerOfdm.twicePwr6_24);

		/* Set OFDM rates 9, 12, 18, 24, 36, 48, 54, XR */
		rpow[0] = rpow[1] = rpow[2] = rpow[3] = rpow[4] = scaledPower;
		rpow[5] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr36);
		rpow[6] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr48);
		rpow[7] = AH_MIN(rpow[0], targetPowerOfdm.twicePwr54);

#ifdef notyet
		if (eeversion >= AR_EEPROM_VER4_0) {
			/* Setup XR target power from EEPROM */
			rpow[15] = AH_MIN(scaledPower, IS_CHAN_2GHZ(chan) ?
				xrTargetPower2 : xrTargetPower5);
		} else {
			/* XR uses 6mb power */
			rpow[15] = rpow[0];
		}
#else
		rpow[15] = rpow[0];
#endif

		*pMinPower = rpow[7];
		*pMaxPower = rpow[0];

#if 0
		ahp->ah_ofdmTxPower = rpow[0];
#endif

		HALDEBUG(ah, HAL_DEBUG_ANY,
		    "%s: MaxRD: %d TurboMax: %d MaxCTL: %d "
		    "TPC_Reduction %d\n", __func__,
		    twiceMaxRDPower, turbo2WMaxPower5,
		    twiceMaxEdgePower, tpcScaleReduction * 2);
	}

	if (IEEE80211_IS_CHAN_CCK(chan)) {
		/* Get final CCK target powers */
		ar5212GetTargetPowers(ah, chan, trgtPwr_11b,
			numTargetPwr_11b, &targetPowerCck);

		/* Reduce power by max regulatory domain allowed restrictions */
		scaledPower = AH_MIN(twiceMaxEdgePowerCck,
			twiceMaxRDPower - twiceAntennaReduction);

		scaledPower -= (tpcScaleReduction * 2);
		scaledPower = (scaledPower < 0) ? 0 : scaledPower;
		scaledPower = AH_MIN(scaledPower, powerLimit);

		rpow[8] = (scaledPower < 1) ? 1 : scaledPower;

		/* Set CCK rates 2L, 2S, 5.5L, 5.5S, 11L, 11S */
		rpow[8]  = AH_MIN(scaledPower, targetPowerCck.twicePwr6_24);
		rpow[9]  = AH_MIN(scaledPower, targetPowerCck.twicePwr36);
		rpow[10] = rpow[9];
		rpow[11] = AH_MIN(scaledPower, targetPowerCck.twicePwr48);
		rpow[12] = rpow[11];
		rpow[13] = AH_MIN(scaledPower, targetPowerCck.twicePwr54);
		rpow[14] = rpow[13];

		/* Set min/max power based off OFDM values or initialization */
		if (rpow[13] < *pMinPower)
		    *pMinPower = rpow[13];
		if (rpow[9] > *pMaxPower)
		    *pMaxPower = rpow[9];

	}
#if 0
	ahp->ah_tx6PowerInHalfDbm = *pMaxPower;
#endif
	return AH_TRUE;
}
static inline void
ar9300_adjust_rate_txpower_cdd(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
                        HAL_BOOL is40,
                        int rt_ss_offset, int rt_ds_offset,
                        int rt_ts_offset, u_int8_t chainmask)
{

    struct ath_hal_9300 *ahp = AH9300(ah);
    int i;
    int16_t twice_array_gain, cdd_power = 0;
    u_int8_t mcs_index = 0;

    /*
     *  Adjust the upper limit for CDD factoring in the array gain .
     *  The array gain is the same as TxBF, hence reuse the same defines. 
     */
    switch (chainmask) {
    case OSPREY_1_CHAINMASK:
        cdd_power = ahp->upper_limit[0];
        break;
  
    case OSPREY_2LOHI_CHAINMASK:
    case OSPREY_2LOMID_CHAINMASK:
        twice_array_gain =
            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
            -(AR9300_TXBF_2TX_ARRAY_GAIN) :
            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
            (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
        cdd_power = ahp->upper_limit[1] + twice_array_gain;
        break;
        
    case OSPREY_3_CHAINMASK:
        twice_array_gain =
            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
            -(AR9300_TXBF_3TX_ARRAY_GAIN) :
            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
            (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
        cdd_power = ahp->upper_limit[2] + twice_array_gain;
        break;

    default:
        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
        break;
    }


    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            break;

        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            /* 2 TX/1 stream  CDD gain adjustment */
            if (ahp->txpower[i][1] > cdd_power){
                ahp->txpower[i][1] = cdd_power;
            } 
            break;
        case OSPREY_3_CHAINMASK:
            /* 3 TX/1 stream  CDD gain adjustment */
            if (ahp->txpower[i][2] > cdd_power){
                ahp->txpower[i][2] = cdd_power;
            }
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            break;
        case OSPREY_3_CHAINMASK:
        /* 3 TX/2 stream  TxBF gain adjustment */
            if (ahp->txpower[i][2] > cdd_power){
                ahp->txpower[i][2] = cdd_power;
            } 
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                 __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    return;

}
static inline void
ar9300_init_rate_txpower_stbc(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
                        HAL_BOOL is40,
                        int rt_ss_offset, int rt_ds_offset,
                        int rt_ts_offset, u_int8_t chainmask)
{

    struct ath_hal_9300 *ahp = AH9300(ah);
    int i;
    int16_t twice_array_gain, stbc_power = 0;
    u_int8_t mcs_index = 0;

    /* Upper Limit with STBC */
    switch (chainmask) {
    case OSPREY_1_CHAINMASK:
        stbc_power = ahp->upper_limit[0];
        break;
    case OSPREY_2LOHI_CHAINMASK:
    case OSPREY_2LOMID_CHAINMASK:
        stbc_power = ahp->upper_limit[1];
        break;
    case OSPREY_3_CHAINMASK:
        stbc_power = ahp->upper_limit[2];
        /* Ony FCC requires that we back off with 3 transmit chains */
        if (is_reg_dmn_fcc(ahp->reg_dmn)) {
            twice_array_gain =
                (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
                -(AR9300_STBC_3TX_ARRAY_GAIN) :
                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
                (ahp->twice_antenna_gain + AR9300_STBC_3TX_ARRAY_GAIN)), 0));
            stbc_power = ahp->upper_limit[2] + twice_array_gain;
        }
        break;

    default:
        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                 __func__, chainmask);
        break;
    }


    for (i = rt_ss_offset; i < rt_ss_offset + AR9300_NUM_HT_SS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
            /* 3 TX/1 stream  STBC gain adjustment */
            if (ahp->txpower_stbc[i][2] > stbc_power){
                ahp->txpower_stbc[i][2] = stbc_power;
            }
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    for (i = rt_ds_offset; i < rt_ds_offset + AR9300_NUM_HT_DS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
            /* 3 TX/2 stream  STBC gain adjustment */
            if (ahp->txpower_stbc[i][2] > stbc_power){
                ahp->txpower_stbc[i][2] = stbc_power;
	    } 
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    for (i = rt_ts_offset; i < rt_ts_offset + AR9300_NUM_HT_TS_RATES; i++) {
        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower_stbc[i][0] = ahp->txpower[i][0];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower_stbc[i][1] = ahp->txpower[i][1];
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower_stbc[i][2] = ahp->txpower[i][2];
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
        mcs_index++;
    }

    return;
}
static inline void
ar9300_init_rate_txpower_ofdm(struct ath_hal *ah, const HAL_RATE_TABLE *rt,
                          u_int8_t rates_array[], int rt_offset,
                          u_int8_t chainmask)
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    int16_t twice_array_gain, cdd_power = 0;
    int i, j;
    u_int8_t ofdm_rt_2_pwr_idx[8] =
    {
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_6_24,
        ALL_TARGET_LEGACY_36,
        ALL_TARGET_LEGACY_48,
        ALL_TARGET_LEGACY_54,
    };

    /*
     *  For FCC adjust the upper limit for CDD factoring in the array gain.
     *  The array gain is the same as TxBF, hence reuse the same defines. 
     */
    for (i = rt_offset; i < rt_offset + AR9300_NUM_OFDM_RATES; i++) {

        /* Get the correct OFDM rate to Power table Index */
        j = ofdm_rt_2_pwr_idx[i- rt_offset]; 

        switch (chainmask) {
        case OSPREY_1_CHAINMASK:
            ahp->txpower[i][0] = rates_array[j];
            break;
        case OSPREY_2LOHI_CHAINMASK:
        case OSPREY_2LOMID_CHAINMASK:
            ahp->txpower[i][1] = rates_array[j];
            if (is_reg_dmn_fcc(ahp->reg_dmn)){
                twice_array_gain = (ahp->twice_antenna_gain >=
                ahp->twice_antenna_reduction)?
                -(AR9300_TXBF_2TX_ARRAY_GAIN) :
                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
               (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
                cdd_power = ahp->upper_limit[1] + twice_array_gain;
                if (ahp->txpower[i][1] > cdd_power){
                    ahp->txpower[i][1] = cdd_power;
                }
            }
            break;
        case OSPREY_3_CHAINMASK:
            ahp->txpower[i][2] = rates_array[j];
            if (is_reg_dmn_fcc(ahp->reg_dmn)) {
                twice_array_gain =
                (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
                -(AR9300_TXBF_3TX_ARRAY_GAIN):
                ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
                (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
                cdd_power = ahp->upper_limit[2] + twice_array_gain;
                if (ahp->txpower[i][2] > cdd_power){
                    ahp->txpower[i][2] = cdd_power;
                }
            } 
            break;
        default:
            HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                     __func__, chainmask);
            break;
        }
    }
}
extern void
ar9300_adjust_reg_txpower_cdd(struct ath_hal *ah, 
                      u_int8_t power_per_rate[])
                      
{
    struct ath_hal_9300 *ahp = AH9300(ah);
    int16_t twice_array_gain, cdd_power = 0;
    int i;

    /*
     *  Adjust the upper limit for CDD factoring in the array gain .
     *  The array gain is the same as TxBF, hence reuse the same defines. 
     */
    switch (ahp->ah_tx_chainmask) {

    case OSPREY_1_CHAINMASK:
        cdd_power = ahp->upper_limit[0];
        break;
  
    case OSPREY_2LOHI_CHAINMASK:
    case OSPREY_2LOMID_CHAINMASK:
        twice_array_gain =
           (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
           -(AR9300_TXBF_2TX_ARRAY_GAIN) :
           ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
           (ahp->twice_antenna_gain + AR9300_TXBF_2TX_ARRAY_GAIN)), 0));
        cdd_power = ahp->upper_limit[1] + twice_array_gain;
        /* Adjust OFDM legacy rates as well */
        for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power; 
            } 
        }
            
        /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 20*/
        for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_7; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power; 
            } 
        } 

        /* 2Tx/(n-1) stream Adjust rates MCS0 through MCS 7  HT 40*/
        for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_7; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power; 
            } 
        } 
        break;
        
    case OSPREY_3_CHAINMASK:
        twice_array_gain =
            (ahp->twice_antenna_gain >= ahp->twice_antenna_reduction)?
            -(AR9300_TXBF_3TX_ARRAY_GAIN) :
            ((int16_t)AH_MIN((ahp->twice_antenna_reduction -
            (ahp->twice_antenna_gain + AR9300_TXBF_3TX_ARRAY_GAIN)), 0));
        cdd_power = ahp->upper_limit[2] + twice_array_gain;
        /* Adjust OFDM legacy rates as well */
        for (i = ALL_TARGET_LEGACY_6_24; i <= ALL_TARGET_LEGACY_54; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power; 
            } 
        }
        /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT20 */
        for (i = ALL_TARGET_HT20_0_8_16; i <= ALL_TARGET_HT20_15; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power;
            }
        }

        /* 3Tx/(n-1)streams Adjust rates MCS0 through MCS 15 HT40 */
        for (i = ALL_TARGET_HT40_0_8_16; i <= ALL_TARGET_HT40_15; i++) {
            if (power_per_rate[i] > cdd_power) {
                power_per_rate[i] = cdd_power;
            }
        }

        break;

    default:
        HALDEBUG(ah, HAL_DEBUG_POWER_MGMT, "%s: invalid chainmask 0x%x\n",
                 __func__, ahp->ah_tx_chainmask);
        break;
    }

    return;
}
HAL_STATUS
ath_hal_v4kEepromAttach(struct ath_hal *ah)
{
#define	NW(a)	(sizeof(a) / sizeof(uint16_t))
    HAL_EEPROM_v4k *ee = AH_PRIVATE(ah)->ah_eeprom;
    uint16_t *eep_data, magic;
    HAL_BOOL need_swap;
    u_int w, off, len;
    uint32_t sum;

    HALASSERT(ee == AH_NULL);
    /*
     * Don't check magic if we're supplied with an EEPROM block,
     * typically this is from Howl but it may also be from later
     * boards w/ an embedded WMAC.
     */
    if (ah->ah_eepromdata == NULL) {
        if (!ath_hal_eepromRead(ah, AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
            HALDEBUG(ah, HAL_DEBUG_ANY,
                     "%s Error reading Eeprom MAGIC\n", __func__);
            return HAL_EEREAD;
        }
    }
    HALDEBUG(ah, HAL_DEBUG_ATTACH, "%s Eeprom Magic = 0x%x\n",
             __func__, magic);
    if (magic != AR5416_EEPROM_MAGIC) {
        HALDEBUG(ah, HAL_DEBUG_ANY, "Bad magic number\n");
        return HAL_EEMAGIC;
    }

    ee = ath_hal_malloc(sizeof(HAL_EEPROM_v4k));
    if (ee == AH_NULL) {
        /* XXX message */
        return HAL_ENOMEM;
    }

    eep_data = (uint16_t *)&ee->ee_base;
    for (w = 0; w < NW(struct ar5416eeprom_4k); w++) {
        off = owl_eep_start_loc + w;	/* NB: AP71 starts at 0 */
        if (!ath_hal_eepromRead(ah, off, &eep_data[w])) {
            HALDEBUG(ah, HAL_DEBUG_ANY,
                     "%s eeprom read error at offset 0x%x\n",
                     __func__, off);
            return HAL_EEREAD;
        }
    }
    /* Convert to eeprom native eeprom endian format */
    /*
     * XXX this is likely incorrect but will do for now
     * XXX to get embedded boards working.
     */
    if (ah->ah_eepromdata == NULL && isBigEndian()) {
        for (w = 0; w < NW(struct ar5416eeprom_4k); w++)
            eep_data[w] = __bswap16(eep_data[w]);
    }

    /*
     * At this point, we're in the native eeprom endian format
     * Now, determine the eeprom endian by looking at byte 26??
     */
    need_swap = ((ee->ee_base.baseEepHeader.eepMisc & AR5416_EEPMISC_BIG_ENDIAN) != 0) ^ isBigEndian();
    if (need_swap) {
        HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM,
                 "Byte swap EEPROM contents.\n");
        len = __bswap16(ee->ee_base.baseEepHeader.length);
    } else {
        len = ee->ee_base.baseEepHeader.length;
    }
    len = AH_MIN(len, sizeof(struct ar5416eeprom_4k)) / sizeof(uint16_t);

    /* Apply the checksum, done in native eeprom format */
    /* XXX - Need to check to make sure checksum calculation is done
     * in the correct endian format.  Right now, it seems it would
     * cast the raw data to host format and do the calculation, which may
     * not be correct as the calculation may need to be done in the native
     * eeprom format
     */
    sum = 0;
    for (w = 0; w < len; w++) {
        sum ^= eep_data[w];
    }
    /* Check CRC - Attach should fail on a bad checksum */
    if (sum != 0xffff) {
        HALDEBUG(ah, HAL_DEBUG_ANY,
                 "Bad EEPROM checksum 0x%x (Len=%u)\n", sum, len);
        return HAL_EEBADSUM;
    }

    if (need_swap)
        eepromSwap(&ee->ee_base);	/* byte swap multi-byte data */

    /* swap words 0+2 so version is at the front */
    magic = eep_data[0];
    eep_data[0] = eep_data[2];
    eep_data[2] = magic;

    HALDEBUG(ah, HAL_DEBUG_ATTACH | HAL_DEBUG_EEPROM,
             "%s Eeprom Version %u.%u\n", __func__,
             owl_get_eep_ver(ee), owl_get_eep_rev(ee));

    /* NB: must be after all byte swapping */
    if (owl_get_eep_ver(ee) != AR5416_EEP_VER) {
        HALDEBUG(ah, HAL_DEBUG_ANY,
                 "Bad EEPROM version 0x%x\n", owl_get_eep_ver(ee));
        return HAL_EEBADSUM;
    }

    v4kEepromReadCTLInfo(ah, ee);		/* Get CTLs */

    AH_PRIVATE(ah)->ah_eeprom = ee;
    AH_PRIVATE(ah)->ah_eeversion = ee->ee_base.baseEepHeader.version;
    AH_PRIVATE(ah)->ah_eepromDetach = v4kEepromDetach;
    AH_PRIVATE(ah)->ah_eepromGet = v4kEepromGet;
    AH_PRIVATE(ah)->ah_eepromSet = v4kEepromSet;
    AH_PRIVATE(ah)->ah_getSpurChan = v4kEepromGetSpurChan;
    AH_PRIVATE(ah)->ah_eepromDiag = v4kEepromDiag;
    return HAL_OK;
#undef NW
}
Beispiel #8
0
void
ar5416Set11nRateScenario(struct ath_hal *ah, void *ds,
                             void *lastds,
                             u_int dur_update_en, u_int rts_cts_rate, u_int rts_cts_duration,
                             HAL_11N_RATE_SERIES series[], u_int nseries,
                             u_int flags, u_int32_t smartAntenna)
#endif
{
        struct ath_hal_private *ap = AH_PRIVATE(ah);
        struct ar5416_desc *ads = AR5416DESC(ds);
        struct ar5416_desc *last_ads = AR5416DESC(lastds);
        u_int32_t ds_ctl0;
        u_int mode;

        HALASSERT(nseries == 4);
        (void)nseries;
        (void)rts_cts_duration;   /* use H/W to calculate RTSCTSDuration */

        /*
         * Rate control settings override
         */
        ds_ctl0 = ads->ds_ctl0;
        if (flags & (HAL_TXDESC_RTSENA | HAL_TXDESC_CTSENA)) {
            if (flags & HAL_TXDESC_RTSENA) {
                ds_ctl0 &= ~AR_CTSEnable;
                ds_ctl0 |= AR_RTSEnable;
            } else {
                ds_ctl0 &= ~AR_RTSEnable;
                ds_ctl0 |= AR_CTSEnable;
            }
        } else {
            ds_ctl0 = (ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable));
        }

        mode = ath_hal_get_curmode(ah, ap->ah_curchan);
        if (ap->ah_config.ath_hal_desc_tpc) {
            int16_t txpower;

            txpower = ar5416GetRateTxPower(ah, mode, series[0].rate_index,
                                           series[0].ch_sel);

            if(series[0].tx_power_cap == 0)
            {  
                /*For short range mode, set txpower to MAX to put series[0].TxPowerCap into the descriptor*/
                txpower = HAL_TXPOWER_MAX;
            }

            ds_ctl0 &= ~AR_XmitPower0;
            if (AR_SREV_MERLIN_10_OR_LATER(ah)) {
                u_int count;
                for (count=0; count < nseries; count++) {
                    series[count].tx_power_cap -= AR5416_PWR_TABLE_OFFSET_DB * 2;
                }
            }
            ds_ctl0 |= set11nTxPower(0, AH_MIN(txpower, series[0].tx_power_cap));
        }

        ads->ds_ctl0 = ds_ctl0;

        ads->ds_ctl2 = set11nTries(series, 0)
                                 |  set11nTries(series, 1)
                                 |  set11nTries(series, 2)
                                 |  set11nTries(series, 3)
                                 |  (dur_update_en ? AR_DurUpdateEna : 0)
                                 |  SM(0, AR_BurstDur);

        ads->ds_ctl3 = set11nRate(series, 0)
                                 |  set11nRate(series, 1)
                                 |  set11nRate(series, 2)
                                 |  set11nRate(series, 3);

        ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0)
                                 |  set11nPktDurRTSCTS(series, 1);

        ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2)
                                 |  set11nPktDurRTSCTS(series, 3);

        ads->ds_ctl7 = set11nRateFlags(series, 0)
                                 |  set11nRateFlags(series, 1)
                                 |  set11nRateFlags(series, 2)
                                 |  set11nRateFlags(series, 3)
                                 | SM(rts_cts_rate, AR_RTSCTSRate);

        if (ap->ah_config.ath_hal_desc_tpc && AR_SREV_OWL_20_OR_LATER(ah)) {
            int16_t txpower;
            txpower = ar5416GetRateTxPower(
                ah, mode, series[1].rate_index, series[1].ch_sel);
            ads->ds_ctl9 =
                set11nTxPower(1, AH_MIN(txpower, series[1].tx_power_cap));
            txpower = ar5416GetRateTxPower(
                ah, mode, series[2].rate_index, series[2].ch_sel);
            ads->ds_ctl10 =
                set11nTxPower(2, AH_MIN(txpower, series[2].tx_power_cap));
            txpower = ar5416GetRateTxPower(
                ah, mode, series[3].rate_index, series[3].ch_sel);
            ads->ds_ctl11 =
                set11nTxPower(3, AH_MIN(txpower, series[3].tx_power_cap));
        }

#ifdef AH_NEED_DESC_SWAP
        last_ads->ds_ctl2 = __bswap32(ads->ds_ctl2);
        last_ads->ds_ctl3 = __bswap32(ads->ds_ctl3);
#else
        last_ads->ds_ctl2 = ads->ds_ctl2;
        last_ads->ds_ctl3 = ads->ds_ctl3;
#endif
}