Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2255679 authored by David S. Miller's avatar David S. Miller
Browse files
parents 4b030d42 a24d52f3
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -1087,7 +1087,6 @@ F: drivers/net/wireless/ath/ath5k/
ATHEROS ATH9K WIRELESS DRIVER
ATHEROS ATH9K WIRELESS DRIVER
M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
M:	"Luis R. Rodriguez" <lrodriguez@atheros.com>
M:	Jouni Malinen <jmalinen@atheros.com>
M:	Jouni Malinen <jmalinen@atheros.com>
M:	Sujith Manoharan <Sujith.Manoharan@atheros.com>
M:	Vasanthakumar Thiagarajan <vasanth@atheros.com>
M:	Vasanthakumar Thiagarajan <vasanth@atheros.com>
M:	Senthil Balasubramanian <senthilkumar@atheros.com>
M:	Senthil Balasubramanian <senthilkumar@atheros.com>
L:	linux-wireless@vger.kernel.org
L:	linux-wireless@vger.kernel.org
+27 −16
Original line number Original line Diff line number Diff line
@@ -63,6 +63,7 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
				      u8 rxchainmask,
				      u8 rxchainmask,
				      struct ath9k_cal_list *currCal)
				      struct ath9k_cal_list *currCal)
{
{
	struct ath9k_hw_cal_data *caldata = ah->caldata;
	bool iscaldone = false;
	bool iscaldone = false;


	if (currCal->calState == CAL_RUNNING) {
	if (currCal->calState == CAL_RUNNING) {
@@ -81,14 +82,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
				}
				}


				currCal->calData->calPostProc(ah, numChains);
				currCal->calData->calPostProc(ah, numChains);
				ichan->CalValid |= currCal->calData->calType;
				caldata->CalValid |= currCal->calData->calType;
				currCal->calState = CAL_DONE;
				currCal->calState = CAL_DONE;
				iscaldone = true;
				iscaldone = true;
			} else {
			} else {
				ar9002_hw_setup_calibration(ah, currCal);
				ar9002_hw_setup_calibration(ah, currCal);
			}
			}
		}
		}
	} else if (!(ichan->CalValid & currCal->calData->calType)) {
	} else if (!(caldata->CalValid & currCal->calData->calType)) {
		ath9k_hw_reset_calibration(ah, currCal);
		ath9k_hw_reset_calibration(ah, currCal);
	}
	}


@@ -686,8 +687,13 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
{
{
	bool iscaldone = true;
	bool iscaldone = true;
	struct ath9k_cal_list *currCal = ah->cal_list_curr;
	struct ath9k_cal_list *currCal = ah->cal_list_curr;
	bool nfcal, nfcal_pending = false;


	if (currCal &&
	nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
	if (ah->caldata)
		nfcal_pending = ah->caldata->nfcal_pending;

	if (currCal && !nfcal &&
	    (currCal->calState == CAL_RUNNING ||
	    (currCal->calState == CAL_RUNNING ||
	     currCal->calState == CAL_WAITING)) {
	     currCal->calState == CAL_WAITING)) {
		iscaldone = ar9002_hw_per_calibration(ah, chan,
		iscaldone = ar9002_hw_per_calibration(ah, chan,
@@ -703,7 +709,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
	}
	}


	/* Do NF cal only at longer intervals */
	/* Do NF cal only at longer intervals */
	if (longcal) {
	if (longcal || nfcal_pending) {
		/* Do periodic PAOffset Cal */
		/* Do periodic PAOffset Cal */
		ar9002_hw_pa_cal(ah, false);
		ar9002_hw_pa_cal(ah, false);
		ar9002_hw_olc_temp_compensation(ah);
		ar9002_hw_olc_temp_compensation(ah);
@@ -712,16 +718,18 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
		 * Get the value from the previous NF cal and update
		 * Get the value from the previous NF cal and update
		 * history buffer.
		 * history buffer.
		 */
		 */
		ath9k_hw_getnf(ah, chan);
		if (ath9k_hw_getnf(ah, chan)) {

			/*
			/*
		 * Load the NF from history buffer of the current channel.
			 * Load the NF from history buffer of the current
		 * NF is slow time-variant, so it is OK to use a historical
			 * channel.
		 * value.
			 * NF is slow time-variant, so it is OK to use a
			 * historical value.
			 */
			 */
			ath9k_hw_loadnf(ah, ah->curchan);
			ath9k_hw_loadnf(ah, ah->curchan);
		}


		ath9k_hw_start_nfcal(ah);
		if (longcal)
			ath9k_hw_start_nfcal(ah, false);
	}
	}


	return iscaldone;
	return iscaldone;
@@ -869,8 +877,10 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
	ar9002_hw_pa_cal(ah, true);
	ar9002_hw_pa_cal(ah, true);


	/* Do NF Calibration after DC offset and other calibrations */
	/* Do NF Calibration after DC offset and other calibrations */
	REG_WRITE(ah, AR_PHY_AGC_CONTROL,
	ath9k_hw_start_nfcal(ah, true);
		  REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_NF);

	if (ah->caldata)
		ah->caldata->nfcal_pending = true;


	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;


@@ -901,7 +911,8 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
			ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
	}
	}


	chan->CalValid = 0;
	if (ah->caldata)
		ah->caldata->CalValid = 0;


	return true;
	return true;
}
}
+14 −4
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
				      u8 rxchainmask,
				      u8 rxchainmask,
				      struct ath9k_cal_list *currCal)
				      struct ath9k_cal_list *currCal)
{
{
	struct ath9k_hw_cal_data *caldata = ah->caldata;
	/* Cal is assumed not done until explicitly set below */
	/* Cal is assumed not done until explicitly set below */
	bool iscaldone = false;
	bool iscaldone = false;


@@ -95,7 +96,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
				currCal->calData->calPostProc(ah, numChains);
				currCal->calData->calPostProc(ah, numChains);


				/* Calibration has finished. */
				/* Calibration has finished. */
				ichan->CalValid |= currCal->calData->calType;
				caldata->CalValid |= currCal->calData->calType;
				currCal->calState = CAL_DONE;
				currCal->calState = CAL_DONE;
				iscaldone = true;
				iscaldone = true;
			} else {
			} else {
@@ -106,7 +107,7 @@ static bool ar9003_hw_per_calibration(struct ath_hw *ah,
			ar9003_hw_setup_calibration(ah, currCal);
			ar9003_hw_setup_calibration(ah, currCal);
			}
			}
		}
		}
	} else if (!(ichan->CalValid & currCal->calData->calType)) {
	} else if (!(caldata->CalValid & currCal->calData->calType)) {
		/* If current cal is marked invalid in channel, kick it off */
		/* If current cal is marked invalid in channel, kick it off */
		ath9k_hw_reset_calibration(ah, currCal);
		ath9k_hw_reset_calibration(ah, currCal);
	}
	}
@@ -148,6 +149,12 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah,


	/* Do NF cal only at longer intervals */
	/* Do NF cal only at longer intervals */
	if (longcal) {
	if (longcal) {
		/*
		 * Get the value from the previous NF cal and update
		 * history buffer.
		 */
		ath9k_hw_getnf(ah, chan);

		/*
		/*
		 * Load the NF from history buffer of the current channel.
		 * Load the NF from history buffer of the current channel.
		 * NF is slow time-variant, so it is OK to use a historical
		 * NF is slow time-variant, so it is OK to use a historical
@@ -156,7 +163,7 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah,
		ath9k_hw_loadnf(ah, ah->curchan);
		ath9k_hw_loadnf(ah, ah->curchan);


		/* start NF calibration, without updating BB NF register */
		/* start NF calibration, without updating BB NF register */
		ath9k_hw_start_nfcal(ah);
		ath9k_hw_start_nfcal(ah, false);
	}
	}


	return iscaldone;
	return iscaldone;
@@ -762,6 +769,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
	/* Revert chainmasks to their original values before NF cal */
	/* Revert chainmasks to their original values before NF cal */
	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
	ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);


	ath9k_hw_start_nfcal(ah, true);

	/* Initialize list pointers */
	/* Initialize list pointers */
	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
	ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;


@@ -785,7 +794,8 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
	if (ah->cal_list_curr)
	if (ah->cal_list_curr)
		ath9k_hw_reset_calibration(ah, ah->cal_list_curr);
		ath9k_hw_reset_calibration(ah, ah->cal_list_curr);


	chan->CalValid = 0;
	if (ah->caldata)
		ah->caldata->CalValid = 0;


	return true;
	return true;
}
}
+381 −7
Original line number Original line Diff line number Diff line
@@ -41,6 +41,20 @@
#define LE16(x) __constant_cpu_to_le16(x)
#define LE16(x) __constant_cpu_to_le16(x)
#define LE32(x) __constant_cpu_to_le32(x)
#define LE32(x) __constant_cpu_to_le32(x)


/* Local defines to distinguish between extension and control CTL's */
#define EXT_ADDITIVE (0x8000)
#define CTL_11A_EXT (CTL_11A | EXT_ADDITIVE)
#define CTL_11G_EXT (CTL_11G | EXT_ADDITIVE)
#define CTL_11B_EXT (CTL_11B | EXT_ADDITIVE)
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN   9  /* 10*log10(3)*2 */
#define PWRINCR_3_TO_1_CHAIN      9             /* 10*log(3)*2 */
#define PWRINCR_3_TO_2_CHAIN      3             /* floor(10*log(3/2)*2) */
#define PWRINCR_2_TO_1_CHAIN      6             /* 10*log(2)*2 */

#define SUB_NUM_CTL_MODES_AT_5G_40 2    /* excluding HT40, EXT-OFDM */
#define SUB_NUM_CTL_MODES_AT_2G_40 3    /* excluding HT40, EXT-OFDM, EXT-CCK */

static const struct ar9300_eeprom ar9300_default = {
static const struct ar9300_eeprom ar9300_default = {
	.eepromVersion = 2,
	.eepromVersion = 2,
	.templateVersion = 2,
	.templateVersion = 2,
@@ -609,6 +623,14 @@ static const struct ar9300_eeprom ar9300_default = {
	 }
	 }
};
};


static u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
{
	if (fbin == AR9300_BCHAN_UNUSED)
		return fbin;

	return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
}

static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah)
static int ath9k_hw_ar9300_check_eeprom(struct ath_hw *ah)
{
{
	return 0;
	return 0;
@@ -1417,9 +1439,9 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
#undef POW_SM
#undef POW_SM
}
}


static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq)
static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq,
					      u8 *targetPowerValT2)
{
{
	u8 targetPowerValT2[ar9300RateSize];
	/* XXX: hard code for now, need to get from eeprom struct */
	/* XXX: hard code for now, need to get from eeprom struct */
	u8 ht40PowerIncForPdadc = 0;
	u8 ht40PowerIncForPdadc = 0;
	bool is2GHz = false;
	bool is2GHz = false;
@@ -1553,9 +1575,6 @@ static void ar9003_hw_set_target_power_eeprom(struct ath_hw *ah, u16 freq)
			  "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
			  "TPC[%02d] 0x%08x\n", i, targetPowerValT2[i]);
		i++;
		i++;
	}
	}

	/* Write target power array to registers */
	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);
}
}


static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
static int ar9003_hw_cal_pier_get(struct ath_hw *ah,
@@ -1799,14 +1818,369 @@ static int ar9003_hw_calibration_apply(struct ath_hw *ah, int frequency)
	return 0;
	return 0;
}
}


static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep,
					   int idx,
					   int edge,
					   bool is2GHz)
{
	struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G;
	struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;

	if (is2GHz)
		return ctl_2g[idx].ctlEdges[edge].tPower;
	else
		return ctl_5g[idx].ctlEdges[edge].tPower;
}

static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
					     int idx,
					     unsigned int edge,
					     u16 freq,
					     bool is2GHz)
{
	struct cal_ctl_data_2g *ctl_2g = eep->ctlPowerData_2G;
	struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;

	u8 *ctl_freqbin = is2GHz ?
		&eep->ctl_freqbin_2G[idx][0] :
		&eep->ctl_freqbin_5G[idx][0];

	if (is2GHz) {
		if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq &&
		    ctl_2g[idx].ctlEdges[edge - 1].flag)
			return ctl_2g[idx].ctlEdges[edge - 1].tPower;
	} else {
		if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq &&
		    ctl_5g[idx].ctlEdges[edge - 1].flag)
			return ctl_5g[idx].ctlEdges[edge - 1].tPower;
	}

	return AR9300_MAX_RATE_POWER;
}

/*
 * Find the maximum conformance test limit for the given channel and CTL info
 */
static u16 ar9003_hw_get_max_edge_power(struct ar9300_eeprom *eep,
					u16 freq, int idx, bool is2GHz)
{
	u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER;
	u8 *ctl_freqbin = is2GHz ?
		&eep->ctl_freqbin_2G[idx][0] :
		&eep->ctl_freqbin_5G[idx][0];
	u16 num_edges = is2GHz ?
		AR9300_NUM_BAND_EDGES_2G : AR9300_NUM_BAND_EDGES_5G;
	unsigned int edge;

	/* Get the edge power */
	for (edge = 0;
	     (edge < num_edges) && (ctl_freqbin[edge] != AR9300_BCHAN_UNUSED);
	     edge++) {
		/*
		 * If there's an exact channel match or an inband flag set
		 * on the lower channel use the given rdEdgePower
		 */
		if (freq == ath9k_hw_fbin2freq(ctl_freqbin[edge], is2GHz)) {
			twiceMaxEdgePower =
				ar9003_hw_get_direct_edge_power(eep, idx,
								edge, is2GHz);
			break;
		} else if ((edge > 0) &&
			   (freq < ath9k_hw_fbin2freq(ctl_freqbin[edge],
						      is2GHz))) {
			twiceMaxEdgePower =
				ar9003_hw_get_indirect_edge_power(eep, idx,
								  edge, freq,
								  is2GHz);
			/*
			 * Leave loop - no more affecting edges possible in
			 * this monotonic increasing list
			 */
			break;
		}
	}
	return twiceMaxEdgePower;
}

static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
					       struct ath9k_channel *chan,
					       u8 *pPwrArray, u16 cfgCtl,
					       u8 twiceAntennaReduction,
					       u8 twiceMaxRegulatoryPower,
					       u16 powerLimit)
{
	struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
	struct ath_common *common = ath9k_hw_common(ah);
	struct ar9300_eeprom *pEepData = &ah->eeprom.ar9300_eep;
	u16 twiceMaxEdgePower = AR9300_MAX_RATE_POWER;
	static const u16 tpScaleReductionTable[5] = {
		0, 3, 6, 9, AR9300_MAX_RATE_POWER
	};
	int i;
	int16_t  twiceLargestAntenna;
	u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
	u16 ctlModesFor11a[] = {
		CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40
	};
	u16 ctlModesFor11g[] = {
		CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT,
		CTL_11G_EXT, CTL_2GHT40
	};
	u16 numCtlModes, *pCtlMode, ctlMode, freq;
	struct chan_centers centers;
	u8 *ctlIndex;
	u8 ctlNum;
	u16 twiceMinEdgePower;
	bool is2ghz = IS_CHAN_2GHZ(chan);

	ath9k_hw_get_channel_centers(ah, chan, &centers);

	/* Compute TxPower reduction due to Antenna Gain */
	if (is2ghz)
		twiceLargestAntenna = pEepData->modalHeader2G.antennaGain;
	else
		twiceLargestAntenna = pEepData->modalHeader5G.antennaGain;

	twiceLargestAntenna = (int16_t)min((twiceAntennaReduction) -
				twiceLargestAntenna, 0);

	/*
	 * scaledPower is the minimum of the user input power level
	 * and the regulatory allowed power level
	 */
	maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;

	if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX) {
		maxRegAllowedPower -=
			(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
	}

	scaledPower = min(powerLimit, maxRegAllowedPower);

	/*
	 * Reduce scaled Power by number of chains active to get
	 * to per chain tx power level
	 */
	switch (ar5416_get_ntxchains(ah->txchainmask)) {
	case 1:
		break;
	case 2:
		scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
		break;
	case 3:
		scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
		break;
	}

	scaledPower = max((u16)0, scaledPower);

	/*
	 * Get target powers from EEPROM - our baseline for TX Power
	 */
	if (is2ghz) {
		/* Setup for CTL modes */
		/* CTL_11B, CTL_11G, CTL_2GHT20 */
		numCtlModes =
			ARRAY_SIZE(ctlModesFor11g) -
				   SUB_NUM_CTL_MODES_AT_2G_40;
		pCtlMode = ctlModesFor11g;
		if (IS_CHAN_HT40(chan))
			/* All 2G CTL's */
			numCtlModes = ARRAY_SIZE(ctlModesFor11g);
	} else {
		/* Setup for CTL modes */
		/* CTL_11A, CTL_5GHT20 */
		numCtlModes = ARRAY_SIZE(ctlModesFor11a) -
					 SUB_NUM_CTL_MODES_AT_5G_40;
		pCtlMode = ctlModesFor11a;
		if (IS_CHAN_HT40(chan))
			/* All 5G CTL's */
			numCtlModes = ARRAY_SIZE(ctlModesFor11a);
	}

	/*
	 * For MIMO, need to apply regulatory caps individually across
	 * dynamically running modes: CCK, OFDM, HT20, HT40
	 *
	 * The outer loop walks through each possible applicable runtime mode.
	 * The inner loop walks through each ctlIndex entry in EEPROM.
	 * The ctl value is encoded as [7:4] == test group, [3:0] == test mode.
	 */
	for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
		bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
			(pCtlMode[ctlMode] == CTL_2GHT40);
		if (isHt40CtlMode)
			freq = centers.synth_center;
		else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
			freq = centers.ext_center;
		else
			freq = centers.ctl_center;

		ath_print(common, ATH_DBG_REGULATORY,
			  "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, "
			  "EXT_ADDITIVE %d\n",
			  ctlMode, numCtlModes, isHt40CtlMode,
			  (pCtlMode[ctlMode] & EXT_ADDITIVE));

		/* walk through each CTL index stored in EEPROM */
		if (is2ghz) {
			ctlIndex = pEepData->ctlIndex_2G;
			ctlNum = AR9300_NUM_CTLS_2G;
		} else {
			ctlIndex = pEepData->ctlIndex_5G;
			ctlNum = AR9300_NUM_CTLS_5G;
		}

		for (i = 0; (i < ctlNum) && ctlIndex[i]; i++) {
			ath_print(common, ATH_DBG_REGULATORY,
				  "LOOP-Ctlidx %d: cfgCtl 0x%2.2x "
				  "pCtlMode 0x%2.2x ctlIndex 0x%2.2x "
				  "chan %dn",
				  i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
				  chan->channel);

				/*
				 * compare test group from regulatory
				 * channel list with test mode from pCtlMode
				 * list
				 */
				if ((((cfgCtl & ~CTL_MODE_M) |
				       (pCtlMode[ctlMode] & CTL_MODE_M)) ==
					ctlIndex[i]) ||
				    (((cfgCtl & ~CTL_MODE_M) |
				       (pCtlMode[ctlMode] & CTL_MODE_M)) ==
				     ((ctlIndex[i] & CTL_MODE_M) |
				       SD_NO_CTL))) {
					twiceMinEdgePower =
					  ar9003_hw_get_max_edge_power(pEepData,
								       freq, i,
								       is2ghz);

					if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
						/*
						 * Find the minimum of all CTL
						 * edge powers that apply to
						 * this channel
						 */
						twiceMaxEdgePower =
							min(twiceMaxEdgePower,
							    twiceMinEdgePower);
						else {
							/* specific */
							twiceMaxEdgePower =
							  twiceMinEdgePower;
							break;
						}
				}
			}

			minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);

			ath_print(common, ATH_DBG_REGULATORY,
				  "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d "
				  "sP %d minCtlPwr %d\n",
				  ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
				  scaledPower, minCtlPower);

			/* Apply ctl mode to correct target power set */
			switch (pCtlMode[ctlMode]) {
			case CTL_11B:
				for (i = ALL_TARGET_LEGACY_1L_5L;
				     i <= ALL_TARGET_LEGACY_11S; i++)
					pPwrArray[i] =
					  (u8)min((u16)pPwrArray[i],
						  minCtlPower);
				break;
			case CTL_11A:
			case CTL_11G:
				for (i = ALL_TARGET_LEGACY_6_24;
				     i <= ALL_TARGET_LEGACY_54; i++)
					pPwrArray[i] =
					  (u8)min((u16)pPwrArray[i],
						  minCtlPower);
				break;
			case CTL_5GHT20:
			case CTL_2GHT20:
				for (i = ALL_TARGET_HT20_0_8_16;
				     i <= ALL_TARGET_HT20_21; i++)
					pPwrArray[i] =
					  (u8)min((u16)pPwrArray[i],
						  minCtlPower);
				pPwrArray[ALL_TARGET_HT20_22] =
				  (u8)min((u16)pPwrArray[ALL_TARGET_HT20_22],
					  minCtlPower);
				pPwrArray[ALL_TARGET_HT20_23] =
				  (u8)min((u16)pPwrArray[ALL_TARGET_HT20_23],
					   minCtlPower);
				break;
			case CTL_5GHT40:
			case CTL_2GHT40:
				for (i = ALL_TARGET_HT40_0_8_16;
				     i <= ALL_TARGET_HT40_23; i++)
					pPwrArray[i] =
					  (u8)min((u16)pPwrArray[i],
						  minCtlPower);
				break;
			default:
			    break;
			}
	} /* end ctl mode checking */
}

static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
					struct ath9k_channel *chan, u16 cfgCtl,
					struct ath9k_channel *chan, u16 cfgCtl,
					u8 twiceAntennaReduction,
					u8 twiceAntennaReduction,
					u8 twiceMaxRegulatoryPower,
					u8 twiceMaxRegulatoryPower,
					u8 powerLimit)
					u8 powerLimit)
{
{
	ah->txpower_limit = powerLimit;
	struct ath_common *common = ath9k_hw_common(ah);
	ar9003_hw_set_target_power_eeprom(ah, chan->channel);
	u8 targetPowerValT2[ar9300RateSize];
	unsigned int i = 0;

	ar9003_hw_set_target_power_eeprom(ah, chan->channel, targetPowerValT2);
	ar9003_hw_set_power_per_rate_table(ah, chan,
					   targetPowerValT2, cfgCtl,
					   twiceAntennaReduction,
					   twiceMaxRegulatoryPower,
					   powerLimit);

	while (i < ar9300RateSize) {
		ath_print(common, ATH_DBG_EEPROM,
			  "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
		i++;
		ath_print(common, ATH_DBG_EEPROM,
			  "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
		i++;
		ath_print(common, ATH_DBG_EEPROM,
			  "TPC[%02d] 0x%08x ", i, targetPowerValT2[i]);
		i++;
		ath_print(common, ATH_DBG_EEPROM,
			  "TPC[%02d] 0x%08x\n\n", i, targetPowerValT2[i]);
		i++;
	}

	/* Write target power array to registers */
	ar9003_hw_tx_power_regwrite(ah, targetPowerValT2);

	/*
	 * This is the TX power we send back to driver core,
	 * and it can use to pass to userspace to display our
	 * currently configured TX power setting.
	 *
	 * Since power is rate dependent, use one of the indices
	 * from the AR9300_Rates enum to select an entry from
	 * targetPowerValT2[] to report. Currently returns the
	 * power for HT40 MCS 0, HT20 MCS 0, or OFDM 6 Mbps
	 * as CCK power is less interesting (?).
	 */
	i = ALL_TARGET_LEGACY_6_24; /* legacy */
	if (IS_CHAN_HT40(chan))
		i = ALL_TARGET_HT40_0_8_16; /* ht40 */
	else if (IS_CHAN_HT20(chan))
		i = ALL_TARGET_HT20_0_8_16; /* ht20 */

	ah->txpower_limit = targetPowerValT2[i];

	ar9003_hw_calibration_apply(ah, chan->channel);
	ar9003_hw_calibration_apply(ah, chan->channel);
}
}


+9 −8
Original line number Original line Diff line number Diff line
@@ -577,10 +577,11 @@ static bool create_pa_curve(u32 *data_L, u32 *data_U, u32 *pa_table, u16 *gain)
}
}


void ar9003_paprd_populate_single_table(struct ath_hw *ah,
void ar9003_paprd_populate_single_table(struct ath_hw *ah,
					struct ath9k_channel *chan, int chain)
					struct ath9k_hw_cal_data *caldata,
					int chain)
{
{
	u32 *paprd_table_val = chan->pa_table[chain];
	u32 *paprd_table_val = caldata->pa_table[chain];
	u32 small_signal_gain = chan->small_signal_gain[chain];
	u32 small_signal_gain = caldata->small_signal_gain[chain];
	u32 training_power;
	u32 training_power;
	u32 reg = 0;
	u32 reg = 0;
	int i;
	int i;
@@ -654,17 +655,17 @@ int ar9003_paprd_setup_gain_table(struct ath_hw *ah, int chain)
}
}
EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);
EXPORT_SYMBOL(ar9003_paprd_setup_gain_table);


int ar9003_paprd_create_curve(struct ath_hw *ah, struct ath9k_channel *chan,
int ar9003_paprd_create_curve(struct ath_hw *ah,
			      int chain)
			      struct ath9k_hw_cal_data *caldata, int chain)
{
{
	u16 *small_signal_gain = &chan->small_signal_gain[chain];
	u16 *small_signal_gain = &caldata->small_signal_gain[chain];
	u32 *pa_table = chan->pa_table[chain];
	u32 *pa_table = caldata->pa_table[chain];
	u32 *data_L, *data_U;
	u32 *data_L, *data_U;
	int i, status = 0;
	int i, status = 0;
	u32 *buf;
	u32 *buf;
	u32 reg;
	u32 reg;


	memset(chan->pa_table[chain], 0, sizeof(chan->pa_table[chain]));
	memset(caldata->pa_table[chain], 0, sizeof(caldata->pa_table[chain]));


	buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC);
	buf = kmalloc(2 * 48 * sizeof(u32), GFP_ATOMIC);
	if (!buf)
	if (!buf)
Loading