linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] ath9k_hw: Add capability flag for Antenna diversity and combining feature
@ 2010-07-29 12:56 Vasanthakumar Thiagarajan
  2010-07-29 12:56 ` [PATCH 2/3] ath9k_hw: Add functions to get/set antenna diversity configuration Vasanthakumar Thiagarajan
  2010-07-29 12:56 ` [PATCH 3/3] ath9k: Implement an algorithm for Antenna diversity and combining Vasanthakumar Thiagarajan
  0 siblings, 2 replies; 6+ messages in thread
From: Vasanthakumar Thiagarajan @ 2010-07-29 12:56 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This is enabled only for ar9285.

Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
---
 drivers/net/wireless/ath/ath9k/eeprom.h    |    2 ++
 drivers/net/wireless/ath/ath9k/eeprom_4k.c |    4 ++++
 drivers/net/wireless/ath/ath9k/hw.c        |    9 +++++++++
 drivers/net/wireless/ath/ath9k/hw.h        |    1 +
 4 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 8750c55..b2223a6 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -265,6 +265,8 @@ enum eeprom_param {
 	EEP_INTERNAL_REGULATOR,
 	EEP_SWREG,
 	EEP_PAPRD,
+	EEP_MODAL_VER,
+	EEP_ANT_DIV_CTL1,
 };
 
 enum ar5416_rates {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 9cccd12..2e1397b 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -213,6 +213,10 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
 		return 0;
 	case EEP_PWR_TABLE_OFFSET:
 		return AR5416_PWR_TABLE_OFFSET_DB;
+	case EEP_MODAL_VER:
+		return pModal->version;
+	case EEP_ANT_DIV_CTL1:
+		return pModal->antdiv_ctl1;
 	default:
 		return 0;
 	}
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 2f83f97..d9e9344 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2052,6 +2052,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
 	u16 capField = 0, eeval;
+	u8 ant_div_ctl1;
 
 	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
 	regulatory->current_rd = eeval;
@@ -2276,6 +2277,14 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 	if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah))
 		pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
 
+	if (AR_SREV_9285(ah))
+		if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) {
+			ant_div_ctl1 =
+				ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+			if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
+				pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
+		}
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 2d30efc..3f19148 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -204,6 +204,7 @@ enum ath9k_hw_caps {
 	ATH9K_HW_CAP_FASTCLOCK			= BIT(20),
 	ATH9K_HW_CAP_SGI_20			= BIT(21),
 	ATH9K_HW_CAP_PAPRD			= BIT(22),
+	ATH9K_HW_CAP_ANT_DIV_COMB		= BIT(23),
 };
 
 struct ath9k_hw_capabilities {
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] ath9k_hw: Add functions to get/set antenna diversity configuration
  2010-07-29 12:56 [PATCH 1/3] ath9k_hw: Add capability flag for Antenna diversity and combining feature Vasanthakumar Thiagarajan
@ 2010-07-29 12:56 ` Vasanthakumar Thiagarajan
  2010-07-29 12:56 ` [PATCH 3/3] ath9k: Implement an algorithm for Antenna diversity and combining Vasanthakumar Thiagarajan
  1 sibling, 0 replies; 6+ messages in thread
From: Vasanthakumar Thiagarajan @ 2010-07-29 12:56 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
---
 drivers/net/wireless/ath/ath9k/ar9002_phy.c |   39 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/ar9002_phy.h |    2 +
 drivers/net/wireless/ath/ath9k/hw-ops.h     |   14 +++++++++
 drivers/net/wireless/ath/ath9k/hw.h         |   10 +++++++
 4 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 4922b8d..f12aab2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -513,9 +513,43 @@ static void ar9002_hw_set_nf_limits(struct ath_hw *ah)
 	}
 }
 
+static void ar9002_hw_ant_div_comb_conf_get(struct ath_hw *ah,
+					    struct ath_hw_antcomb_conf *antconf)
+{
+	u32 regval;
+
+	regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+	antconf->main_lna_conf = (regval & AR_PHY_9285_ANT_DIV_MAIN_LNACONF) >>
+				  AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S;
+	antconf->alt_lna_conf = (regval & AR_PHY_9285_ANT_DIV_ALT_LNACONF) >>
+				 AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
+	antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
+				  AR_PHY_9285_FAST_DIV_BIAS_S;
+}
+
+static void ar9002_hw_ant_div_comb_conf_set(struct ath_hw *ah,
+					    struct ath_hw_antcomb_conf *antconf)
+{
+	u32 regval;
+
+	regval = REG_READ(ah, AR_PHY_MULTICHAIN_GAIN_CTL);
+	regval &= ~(AR_PHY_9285_ANT_DIV_MAIN_LNACONF |
+		    AR_PHY_9285_ANT_DIV_ALT_LNACONF |
+		    AR_PHY_9285_FAST_DIV_BIAS);
+	regval |= ((antconf->main_lna_conf << AR_PHY_9285_ANT_DIV_MAIN_LNACONF_S)
+		   & AR_PHY_9285_ANT_DIV_MAIN_LNACONF);
+	regval |= ((antconf->alt_lna_conf << AR_PHY_9285_ANT_DIV_ALT_LNACONF_S)
+		   & AR_PHY_9285_ANT_DIV_ALT_LNACONF);
+	regval |= ((antconf->fast_div_bias << AR_PHY_9285_FAST_DIV_BIAS_S)
+		   & AR_PHY_9285_FAST_DIV_BIAS);
+
+	REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
+}
+
 void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
 {
 	struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+	struct ath_hw_ops *ops = ath9k_hw_ops(ah);
 
 	priv_ops->set_rf_regs = NULL;
 	priv_ops->rf_alloc_ext_banks = NULL;
@@ -526,5 +560,10 @@ void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
 	priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
 	priv_ops->do_getnf = ar9002_hw_do_getnf;
 
+	if (AR_SREV_9285(ah)) {
+		ops->ant_div_comb_conf_get = ar9002_hw_ant_div_comb_conf_get;
+		ops->ant_div_comb_conf_set = ar9002_hw_ant_div_comb_conf_set;
+	}
+
 	ar9002_hw_set_nf_limits(ah);
 }
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.h b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
index c5151a4..37663db 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
@@ -302,6 +302,8 @@
 #define AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE 0x80000000
 
 #define AR_PHY_MULTICHAIN_GAIN_CTL          0x99ac
+#define AR_PHY_9285_FAST_DIV_BIAS	    0x00007E00
+#define AR_PHY_9285_FAST_DIV_BIAS_S	    9
 #define AR_PHY_9285_ANT_DIV_CTL_ALL         0x7f000000
 #define AR_PHY_9285_ANT_DIV_CTL             0x01000000
 #define AR_PHY_9285_ANT_DIV_CTL_S           24
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index ffecbad..7d84b7f 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -139,6 +139,20 @@ static inline void ath9k_hw_ani_monitor(struct ath_hw *ah,
 	ath9k_hw_ops(ah)->ani_monitor(ah, chan);
 }
 
+static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+					struct ath_hw_antcomb_conf *antconf)
+{
+	if (ath9k_hw_ops(ah)->ant_div_comb_conf_get)
+		ath9k_hw_ops(ah)->ant_div_comb_conf_get(ah, antconf);
+}
+
+static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+					struct ath_hw_antcomb_conf *antconf)
+{
+	if (ath9k_hw_ops(ah)->ant_div_comb_conf_set)
+		ath9k_hw_ops(ah)->ant_div_comb_conf_set(ah, antconf);
+}
+
 /* Private hardware call ops */
 
 /* PHY ops */
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 3f19148..4663557 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -489,6 +489,12 @@ struct ath_gen_timer_table {
 	} timer_mask;
 };
 
+struct ath_hw_antcomb_conf {
+	u8 main_lna_conf;
+	u8 alt_lna_conf;
+	u8 fast_div_bias;
+};
+
 /**
  * struct ath_hw_private_ops - callbacks used internally by hardware code
  *
@@ -627,6 +633,10 @@ struct ath_hw_ops {
 
 	void (*ani_proc_mib_event)(struct ath_hw *ah);
 	void (*ani_monitor)(struct ath_hw *ah, struct ath9k_channel *chan);
+	void (*ant_div_comb_conf_get)(struct ath_hw *ah,
+				      struct ath_hw_antcomb_conf *antconf);
+	void (*ant_div_comb_conf_set)(struct ath_hw *ah,
+				      struct ath_hw_antcomb_conf *antconf);
 };
 
 struct ath_nf_limits {
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] ath9k: Implement an algorithm for Antenna diversity and combining
  2010-07-29 12:56 [PATCH 1/3] ath9k_hw: Add capability flag for Antenna diversity and combining feature Vasanthakumar Thiagarajan
  2010-07-29 12:56 ` [PATCH 2/3] ath9k_hw: Add functions to get/set antenna diversity configuration Vasanthakumar Thiagarajan
@ 2010-07-29 12:56 ` Vasanthakumar Thiagarajan
  2010-07-29 14:39   ` Luis R. Rodriguez
  1 sibling, 1 reply; 6+ messages in thread
From: Vasanthakumar Thiagarajan @ 2010-07-29 12:56 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This algorithm chooses the best main and alt lna out of
LNA1, LNA2, LNA1+LNA2 and LNA1-LNA2 to improve rx for single
chain chips(AR9285). This would greatly improve rx when there
is only one antenna is connected with AR9285.

Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
---
 drivers/net/wireless/ath/ath9k/ath9k.h |   56 ++++
 drivers/net/wireless/ath/ath9k/init.c  |    5 +
 drivers/net/wireless/ath/ath9k/recv.c  |  531 ++++++++++++++++++++++++++++++++
 3 files changed, 592 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 6e486a5..ef256c6 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -488,6 +488,60 @@ struct ath_led {
 void ath_init_leds(struct ath_softc *sc);
 void ath_deinit_leds(struct ath_softc *sc);
 
+/* Antenna diversity/combining */
+#define ATH_ANT_RX_CURRENT_SHIFT 4
+#define ATH_ANT_RX_MAIN_SHIFT 2
+#define ATH_ANT_RX_MASK 0x3
+
+#define ATH_ANT_DIV_COMB_SHORT_SCAN_INTR 50
+#define ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT 0x100
+#define ATH_ANT_DIV_COMB_MAX_PKTCOUNT 0x200
+#define ATH_ANT_DIV_COMB_INIT_COUNT 95
+#define ATH_ANT_DIV_COMB_MAX_COUNT 100
+#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
+#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
+
+#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3
+#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
+#define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
+
+enum ath9k_ant_div_comb_lna_conf {
+	ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2,
+	ATH_ANT_DIV_COMB_LNA2,
+	ATH_ANT_DIV_COMB_LNA1,
+	ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2,
+};
+
+struct ath_ant_comb {
+	u16 count;
+	u16 total_pkt_count;
+	bool scan;
+	bool scan_not_start;
+	int main_total_rssi;
+	int alt_total_rssi;
+	int alt_recv_cnt;
+	int main_recv_cnt;
+	int rssi_lna1;
+	int rssi_lna2;
+	int rssi_add;
+	int rssi_sub;
+	int rssi_first;
+	int rssi_second;
+	int rssi_third;
+	bool alt_good;
+	int quick_scan_cnt;
+	int main_conf;
+	enum ath9k_ant_div_comb_lna_conf first_quick_scan_conf;
+	enum ath9k_ant_div_comb_lna_conf second_quick_scan_conf;
+	int first_bias;
+	int second_bias;
+	bool first_ratio;
+	bool second_ratio;
+	unsigned long scan_start_time;
+};
+
 /********************/
 /* Main driver core */
 /********************/
@@ -604,6 +658,8 @@ struct ath_softc {
 	struct ath_btcoex btcoex;
 
 	struct ath_descdma txsdma;
+
+	struct ath_ant_comb ant_comb;
 };
 
 struct ath_wiphy {
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 243c177..8b4e4a6 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -531,6 +531,11 @@ static void ath9k_init_misc(struct ath_softc *sc)
 		sc->beacon.bslot[i] = NULL;
 		sc->beacon.bslot_aphy[i] = NULL;
 	}
+
+	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
+		memset(&sc->ant_comb, 0, sizeof(struct ath_ant_comb));
+		sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
+	}
 }
 
 static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index da0cfe9..711e8d2 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1073,6 +1073,534 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
 		rxs->flag &= ~RX_FLAG_DECRYPTED;
 }
 
+/* Antenna diversity and combining */
+static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
+{
+	struct ath_hw_antcomb_conf div_ant_conf;
+	struct ath_ant_comb *antcomb = &sc->ant_comb;
+	int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
+	int curr_main_set, curr_bias;
+	int main_rssi = rs->rs_rssi_ctl0;
+	int alt_rssi = rs->rs_rssi_ctl1;
+	int rx_ant_conf,  main_ant_conf;
+	bool short_scan = false;
+
+	rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
+		       ATH_ANT_RX_MASK;
+	main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
+			 ATH_ANT_RX_MASK;
+
+	/* Record packet only when alt_rssi is positive */
+	if (alt_rssi > 0) {
+		antcomb->total_pkt_count++;
+		antcomb->main_total_rssi += main_rssi;
+		antcomb->alt_total_rssi  += alt_rssi;
+		if (main_ant_conf == rx_ant_conf)
+			antcomb->main_recv_cnt++;
+		else
+			antcomb->alt_recv_cnt++;
+	}
+
+	/* Short scan check */
+	if (antcomb->scan && antcomb->alt_good) {
+		if (time_after(jiffies, antcomb->scan_start_time +
+		    msecs_to_jiffies(ATH_ANT_DIV_COMB_SHORT_SCAN_INTR)))
+			short_scan = true;
+		else
+			if (antcomb->total_pkt_count ==
+			    ATH_ANT_DIV_COMB_SHORT_SCAN_PKTCOUNT) {
+				alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+					    antcomb->total_pkt_count);
+				if (alt_ratio < ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+					short_scan = true;
+			}
+	}
+
+	if (((antcomb->total_pkt_count < ATH_ANT_DIV_COMB_MAX_PKTCOUNT) ||
+	    rs->rs_moreaggr) && !short_scan)
+		return;
+
+	if (antcomb->total_pkt_count) {
+		alt_ratio = ((antcomb->alt_recv_cnt * 100) /
+			     antcomb->total_pkt_count);
+		main_rssi_avg = (antcomb->main_total_rssi /
+				 antcomb->total_pkt_count);
+		alt_rssi_avg = (antcomb->alt_total_rssi /
+				 antcomb->total_pkt_count);
+	}
+
+
+	ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
+	curr_alt_set = div_ant_conf.alt_lna_conf;
+	curr_main_set = div_ant_conf.main_lna_conf;
+	curr_bias = div_ant_conf.fast_div_bias;
+
+	antcomb->count++;
+
+	if (antcomb->count == ATH_ANT_DIV_COMB_MAX_COUNT) {
+		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+			antcomb->alt_good = true;
+			antcomb->quick_scan_cnt = 0;
+
+			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
+				antcomb->rssi_lna2 = main_rssi_avg;
+			else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
+				antcomb->rssi_lna1 = main_rssi_avg;
+
+			switch ((curr_main_set << 4) | curr_alt_set) {
+			case (0x10): /* LNA2 A-B */
+				antcomb->main_conf =
+					ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				antcomb->first_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				antcomb->second_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1;
+				break;
+			case (0x20): /* LNA1 A-B */
+				antcomb->main_conf =
+					ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				antcomb->first_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				antcomb->second_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA2;
+				break;
+			case (0x21): /* LNA1 LNA2 */
+				antcomb->main_conf =
+					ATH_ANT_DIV_COMB_LNA2;
+				antcomb->first_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				antcomb->second_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				break;
+			case (0x12): /* LNA2 LNA1 */
+				antcomb->main_conf =
+					ATH_ANT_DIV_COMB_LNA1;
+				antcomb->first_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				antcomb->second_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				break;
+			case (0x13): /* LNA2 A+B */
+				antcomb->main_conf =
+					ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				antcomb->first_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				antcomb->second_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1;
+				break;
+			case (0x23): /* LNA1 A+B */
+				antcomb->main_conf =
+					ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				antcomb->first_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				antcomb->second_quick_scan_conf =
+					ATH_ANT_DIV_COMB_LNA2;
+				break;
+			default:
+				break;
+			}
+		} else {
+			antcomb->alt_good = false;
+		}
+
+		antcomb->count = 0;
+		antcomb->scan = true;
+		antcomb->scan_not_start = true;
+	}
+
+	if (!antcomb->scan) {
+		if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+			if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
+				/* Switch main and alt LNA */
+				div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+				div_ant_conf.alt_lna_conf  =
+						ATH_ANT_DIV_COMB_LNA1;
+			} else if (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) {
+				div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				div_ant_conf.alt_lna_conf  =
+						ATH_ANT_DIV_COMB_LNA2;
+			}
+
+			goto div_comb_done;
+		} else if ((curr_alt_set != ATH_ANT_DIV_COMB_LNA1) &&
+			   (curr_alt_set != ATH_ANT_DIV_COMB_LNA2)) {
+			/* Set alt to another LNA */
+			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2)
+				div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+			else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1)
+				div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+
+			goto div_comb_done;
+		}
+
+		if ((alt_rssi_avg < (main_rssi_avg +
+		    ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
+			goto div_comb_done;
+	}
+
+	if (!antcomb->scan_not_start) {
+		switch (curr_alt_set) {
+		case ATH_ANT_DIV_COMB_LNA2:
+			antcomb->rssi_lna2 = alt_rssi_avg;
+			antcomb->rssi_lna1 = main_rssi_avg;
+			antcomb->scan = true;
+			/* set to A+B */
+			div_ant_conf.main_lna_conf =
+				ATH_ANT_DIV_COMB_LNA1;
+			div_ant_conf.alt_lna_conf  =
+				ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+			break;
+		case ATH_ANT_DIV_COMB_LNA1:
+			antcomb->rssi_lna1 = alt_rssi_avg;
+			antcomb->rssi_lna2 = main_rssi_avg;
+			antcomb->scan = true;
+			/* set to A+B */
+			div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+			div_ant_conf.alt_lna_conf  =
+				ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+			break;
+		case ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2:
+			antcomb->rssi_add = alt_rssi_avg;
+			antcomb->scan = true;
+			/* set to A-B */
+			div_ant_conf.alt_lna_conf =
+				ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+			break;
+		case ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2:
+			antcomb->rssi_sub = alt_rssi_avg;
+			antcomb->scan = false;
+			if (antcomb->rssi_lna2 >
+			    (antcomb->rssi_lna1 +
+			    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+				/* use LNA2 as main LNA */
+				if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
+				    (antcomb->rssi_add > antcomb->rssi_sub)) {
+					/* set to A+B */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+					div_ant_conf.alt_lna_conf  =
+						ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				} else if (antcomb->rssi_sub >
+					   antcomb->rssi_lna1) {
+					/* set to A-B */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				} else {
+					/* set to LNA1 */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				}
+			} else {
+				/* use LNA1 as main LNA */
+				if ((antcomb->rssi_add > antcomb->rssi_lna2) &&
+				    (antcomb->rssi_add > antcomb->rssi_sub)) {
+					/* set to A+B */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+					div_ant_conf.alt_lna_conf  =
+						ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2;
+				} else if (antcomb->rssi_sub >
+					   antcomb->rssi_lna1) {
+					/* set to A-B */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2;
+				} else {
+					/* set to LNA2 */
+					div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	} else {
+		if (!antcomb->alt_good) {
+			antcomb->scan_not_start = false;
+			/* Set alt to another LNA */
+			if (curr_main_set == ATH_ANT_DIV_COMB_LNA2) {
+				div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+				div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+			} else if (curr_main_set == ATH_ANT_DIV_COMB_LNA1) {
+				div_ant_conf.main_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+			}
+			goto div_comb_done;
+		}
+	}
+
+	/* alt_good */
+	switch (antcomb->quick_scan_cnt) {
+	case 0:
+		/* set alt to main, and alt to first conf */
+		div_ant_conf.main_lna_conf = antcomb->main_conf;
+		div_ant_conf.alt_lna_conf = antcomb->first_quick_scan_conf;
+		break;
+	case 1:
+		/* set alt to main, and alt to first conf */
+		div_ant_conf.main_lna_conf = antcomb->main_conf;
+		div_ant_conf.alt_lna_conf = antcomb->second_quick_scan_conf;
+		antcomb->rssi_first = main_rssi_avg;
+		antcomb->rssi_second = alt_rssi_avg;
+
+		if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+			/* main is LNA1 */
+			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_LOW)) &&
+			    (antcomb->total_pkt_count > 50))
+				antcomb->first_ratio = true;
+			else
+				antcomb->first_ratio = false;
+		} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_MID)) ||
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_LOW)) &&
+			    (antcomb->total_pkt_count > 50))
+				antcomb->first_ratio = true;
+			else
+				antcomb->first_ratio = false;
+		} else {
+			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+			    (alt_rssi_avg > main_rssi_avg)) &&
+			    (antcomb->total_pkt_count > 50))
+				antcomb->first_ratio = true;
+			else
+				antcomb->first_ratio = false;
+		}
+		break;
+	case 2:
+		antcomb->alt_good = false;
+		antcomb->scan_not_start = false;
+		antcomb->scan = false;
+		antcomb->rssi_first = main_rssi_avg;
+		antcomb->rssi_third = alt_rssi_avg;
+
+		if (antcomb->second_quick_scan_conf ==
+		    ATH_ANT_DIV_COMB_LNA1)
+			antcomb->rssi_lna1 = alt_rssi_avg;
+		else if (antcomb->second_quick_scan_conf ==
+			 ATH_ANT_DIV_COMB_LNA2)
+			antcomb->rssi_lna2 = alt_rssi_avg;
+		else if (antcomb->second_quick_scan_conf ==
+			 ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2) {
+			if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2)
+				antcomb->rssi_lna2 = main_rssi_avg;
+			else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1)
+				antcomb->rssi_lna1 = main_rssi_avg;
+		}
+
+		if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
+		    ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
+			div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
+		else
+			div_ant_conf.main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
+
+		if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA1) {
+			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_LOW)) &&
+			    (antcomb->total_pkt_count > 50))
+				antcomb->second_ratio = true;
+			else
+				antcomb->second_ratio = false;
+		} else if (antcomb->main_conf == ATH_ANT_DIV_COMB_LNA2) {
+			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_MID)) ||
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_LOW)) &&
+			    (antcomb->total_pkt_count > 50))
+				antcomb->second_ratio = true;
+			else
+				antcomb->second_ratio = false;
+		} else {
+			if ((((alt_ratio >= ATH_ANT_DIV_COMB_ALT_ANT_RATIO2) &&
+			    (alt_rssi_avg > main_rssi_avg +
+			    ATH_ANT_DIV_COMB_LNA1_DELTA_HI)) ||
+			    (alt_rssi_avg > main_rssi_avg)) &&
+			    (antcomb->total_pkt_count > 50))
+				antcomb->second_ratio = true;
+			else
+				antcomb->second_ratio = false;
+		}
+
+		/* set alt to the conf with maximun ratio */
+		if (antcomb->first_ratio && antcomb->second_ratio) {
+			if (antcomb->rssi_second > antcomb->rssi_third) {
+				/* first alt*/
+				if ((antcomb->first_quick_scan_conf ==
+				    ATH_ANT_DIV_COMB_LNA1) ||
+				    (antcomb->first_quick_scan_conf ==
+				    ATH_ANT_DIV_COMB_LNA2))
+					/* Set alt LNA1 or LNA2*/
+					if (div_ant_conf.main_lna_conf ==
+					    ATH_ANT_DIV_COMB_LNA2)
+						div_ant_conf.alt_lna_conf =
+							ATH_ANT_DIV_COMB_LNA1;
+					else
+						div_ant_conf.alt_lna_conf =
+							ATH_ANT_DIV_COMB_LNA2;
+				else
+					/* Set alt to A+B or A-B */
+					div_ant_conf.alt_lna_conf =
+						antcomb->first_quick_scan_conf;
+			} else if ((antcomb->second_quick_scan_conf ==
+				   ATH_ANT_DIV_COMB_LNA1) ||
+				   (antcomb->second_quick_scan_conf ==
+				   ATH_ANT_DIV_COMB_LNA2)) {
+				/* Set alt LNA1 or LNA2 */
+				if (div_ant_conf.main_lna_conf ==
+				    ATH_ANT_DIV_COMB_LNA2)
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				else
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+			} else {
+				/* Set alt to A+B or A-B */
+				div_ant_conf.alt_lna_conf =
+					antcomb->second_quick_scan_conf;
+			}
+		} else if (antcomb->first_ratio) {
+			/* first alt */
+			if ((antcomb->first_quick_scan_conf ==
+			    ATH_ANT_DIV_COMB_LNA1) ||
+			    (antcomb->first_quick_scan_conf ==
+			    ATH_ANT_DIV_COMB_LNA2))
+				/* Set alt LNA1 or LNA2 */
+				if (div_ant_conf.main_lna_conf ==
+				    ATH_ANT_DIV_COMB_LNA2)
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				else
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+			else
+				/* Set alt to A+B or A-B */
+				div_ant_conf.alt_lna_conf =
+					antcomb->first_quick_scan_conf;
+		} else if (antcomb->second_ratio) {
+			/* second alt */
+			if ((antcomb->second_quick_scan_conf ==
+			    ATH_ANT_DIV_COMB_LNA1) ||
+			    (antcomb->second_quick_scan_conf ==
+			    ATH_ANT_DIV_COMB_LNA2))
+				/* Set alt LNA1 or LNA2 */
+				if (div_ant_conf.main_lna_conf ==
+				    ATH_ANT_DIV_COMB_LNA2)
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				else
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+			else
+				/* Set alt to A+B or A-B */
+				div_ant_conf.alt_lna_conf =
+					antcomb->second_quick_scan_conf;
+		} else {
+			/* main is largest */
+			if ((antcomb->main_conf ==
+			    ATH_ANT_DIV_COMB_LNA1) ||
+			    (antcomb->main_conf ==
+			    ATH_ANT_DIV_COMB_LNA2))
+				/* Set alt LNA1 or LNA2 */
+				if (div_ant_conf.main_lna_conf ==
+				    ATH_ANT_DIV_COMB_LNA2)
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA1;
+				else
+					div_ant_conf.alt_lna_conf =
+						ATH_ANT_DIV_COMB_LNA2;
+			else
+				/* Set alt to A+B or A-B */
+				div_ant_conf.alt_lna_conf =
+					antcomb->main_conf;
+		}
+		break;
+	default:
+		break;
+	}
+
+	antcomb->quick_scan_cnt++;
+
+div_comb_done:
+	/* Adjust the fast_div_bias based on main and alt lna conf */
+	switch ((div_ant_conf.main_lna_conf << 4) | div_ant_conf.alt_lna_conf) {
+	case (0x01): /* A-B LNA2 */
+		div_ant_conf.fast_div_bias = 0x3b;
+		break;
+	case (0x02): /* A-B LNA1 */
+		div_ant_conf.fast_div_bias = 0x3d;
+		break;
+	case (0x03): /* A-B A+B */
+		div_ant_conf.fast_div_bias = 0x1;
+		break;
+	case (0x10): /* LNA2 A-B */
+		div_ant_conf.fast_div_bias = 0x7;
+		break;
+	case (0x12): /* LNA2 LNA1 */
+		div_ant_conf.fast_div_bias = 0x2;
+		break;
+	case (0x13): /* LNA2 A+B */
+		div_ant_conf.fast_div_bias = 0x7;
+		break;
+	case (0x20): /* LNA1 A-B */
+		div_ant_conf.fast_div_bias = 0x6;
+		break;
+	case (0x21): /* LNA1 LNA2 */
+		div_ant_conf.fast_div_bias = 0x0;
+		break;
+	case (0x23): /* LNA1 A+B */
+		div_ant_conf.fast_div_bias = 0x6;
+		break;
+	case (0x30): /* A+B A-B */
+		div_ant_conf.fast_div_bias = 0x1;
+		break;
+	case (0x31): /* A+B LNA2 */
+		div_ant_conf.fast_div_bias = 0x3b;
+		break;
+	case (0x32): /* A+B LNA1 */
+		div_ant_conf.fast_div_bias = 0x3d;
+		break;
+	default:
+		break;
+	}
+
+	ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
+
+	antcomb->scan_start_time = jiffies;
+	antcomb->total_pkt_count = 0;
+	antcomb->main_total_rssi = 0;
+	antcomb->alt_total_rssi = 0;
+	antcomb->main_recv_cnt = 0;
+	antcomb->alt_recv_cnt = 0;
+}
+
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
 	struct ath_buf *bf;
@@ -1210,6 +1738,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 					      PS_WAIT_FOR_PSPOLL_DATA))))
 			ath_rx_ps(sc, skb);
 
+		if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
+			ath_ant_comb_scan(sc, &rs);
+
 		ath_rx_send_to_mac80211(hw, sc, skb, rxs);
 
 requeue:
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] ath9k: Implement an algorithm for Antenna diversity and combining
  2010-07-29 12:56 ` [PATCH 3/3] ath9k: Implement an algorithm for Antenna diversity and combining Vasanthakumar Thiagarajan
@ 2010-07-29 14:39   ` Luis R. Rodriguez
  2010-07-30  5:36     ` Vasanthakumar Thiagarajan
  0 siblings, 1 reply; 6+ messages in thread
From: Luis R. Rodriguez @ 2010-07-29 14:39 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan; +Cc: linville, linux-wireless

On Thu, Jul 29, 2010 at 5:56 AM, Vasanthakumar Thiagarajan
<vasanth@atheros.com> wrote:
> This algorithm chooses the best main and alt lna out of
> LNA1, LNA2, LNA1+LNA2 and LNA1-LNA2 to improve rx for single
> chain chips(AR9285). This would greatly improve rx when there
> is only one antenna is connected with AR9285.
>
> Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>

> diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
> index 243c177..8b4e4a6 100644
> --- a/drivers/net/wireless/ath/ath9k/init.c
> +++ b/drivers/net/wireless/ath/ath9k/init.c
> @@ -531,6 +531,11 @@ static void ath9k_init_misc(struct ath_softc *sc)
>                sc->beacon.bslot[i] = NULL;
>                sc->beacon.bslot_aphy[i] = NULL;
>        }
> +
> +       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
> +               memset(&sc->ant_comb, 0, sizeof(struct ath_ant_comb));

I do not believe this memset is required since we kzalloc()'d the ah struct.

> +               sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
> +       }
>  }
>
>  static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
> diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
> index da0cfe9..711e8d2 100644
> --- a/drivers/net/wireless/ath/ath9k/recv.c
> +++ b/drivers/net/wireless/ath/ath9k/recv.c
> @@ -1073,6 +1073,534 @@ static void ath9k_rx_skb_postprocess(struct ath_common *common,
>                rxs->flag &= ~RX_FLAG_DECRYPTED;
>  }
>
> +/* Antenna diversity and combining */
> +static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
> +{

   <-- snip -->

> +       ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);

  <-- snip -->

> +       ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);

  <-- snip -->

> +}

Wow this routine is pretty large. Could you split this up into a few
helpers which describe what they do ?
Also notice how this ended up calling ath9k_hw_antdiv_comb_conf_get()
and ath9k_hw_antdiv_comb_conf_set(), the only callers of those
routines, and this itself is done when:

> +
>  int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
>  {
>        struct ath_buf *bf;
> @@ -1210,6 +1738,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
>                                              PS_WAIT_FOR_PSPOLL_DATA))))
>                        ath_rx_ps(sc, skb);
>
> +               if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
> +                       ath_ant_comb_scan(sc, &rs);
> +
>                ath_rx_send_to_mac80211(hw, sc, skb, rxs);
>
>  requeue:

So the call currently really does not require to be abstracted away
unless we expect another 1x1 device where it will have its own set of
calls, eventually.

  Luis

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] ath9k: Implement an algorithm for Antenna diversity and combining
  2010-07-29 14:39   ` Luis R. Rodriguez
@ 2010-07-30  5:36     ` Vasanthakumar Thiagarajan
  0 siblings, 0 replies; 6+ messages in thread
From: Vasanthakumar Thiagarajan @ 2010-07-30  5:36 UTC (permalink / raw)
  To: Luis R. Rodriguez; +Cc: Vasanth Thiagarajan, linville, linux-wireless

On Thu, Jul 29, 2010 at 08:09:35PM +0530, Luis R. Rodriguez wrote:
> On Thu, Jul 29, 2010 at 5:56 AM, Vasanthakumar Thiagarajan
> <vasanth@atheros.com> wrote:
> > This algorithm chooses the best main and alt lna out of
> > LNA1, LNA2, LNA1+LNA2 and LNA1-LNA2 to improve rx for single
> > chain chips(AR9285). This would greatly improve rx when there
> > is only one antenna is connected with AR9285.
> >
> > Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
> 
> > diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
> > index 243c177..8b4e4a6 100644
> > --- a/drivers/net/wireless/ath/ath9k/init.c
> > +++ b/drivers/net/wireless/ath/ath9k/init.c
> > @@ -531,6 +531,11 @@ static void ath9k_init_misc(struct ath_softc *sc)
> >                sc->beacon.bslot[i] = NULL;
> >                sc->beacon.bslot_aphy[i] = NULL;
> >        }
> > +
> > +       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) {
> > +               memset(&sc->ant_comb, 0, sizeof(struct ath_ant_comb));
> 
> I do not believe this memset is required since we kzalloc()'d the ah struct.

that,s true. thanks.

> 
> Wow this routine is pretty large. Could you split this up into a few
> helpers which describe what they do ?

right, this one is pretty large, let me see if I can split things
up.

> Also notice how this ended up calling ath9k_hw_antdiv_comb_conf_get()
> and ath9k_hw_antdiv_comb_conf_set(), the only callers of those
> routines, and this itself is done when:
> 
> > +
> >  int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
> >  {
> >        struct ath_buf *bf;
> > @@ -1210,6 +1738,9 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
> >                                              PS_WAIT_FOR_PSPOLL_DATA))))
> >                        ath_rx_ps(sc, skb);
> >
> > +               if (ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)
> > +                       ath_ant_comb_scan(sc, &rs);
> > +
> >                ath_rx_send_to_mac80211(hw, sc, skb, rxs);
> >
> >  requeue:
> 
> So the call currently really does not require to be abstracted away
> unless we expect another 1x1 device where it will have its own set of
> calls, eventually.

hm, i actually planned not to abstract, not sure how I ended up
doing this one. I'll send the next version of this series. thanks.

Vasanth

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] ath9k_hw: Add capability flag for Antenna diversity and combining feature
@ 2010-09-02  8:34 Vasanthakumar Thiagarajan
  0 siblings, 0 replies; 6+ messages in thread
From: Vasanthakumar Thiagarajan @ 2010-09-02  8:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless

This is enabled only for ar9285.

Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
---
 drivers/net/wireless/ath/ath9k/eeprom.h    |    2 ++
 drivers/net/wireless/ath/ath9k/eeprom_4k.c |    4 ++++
 drivers/net/wireless/ath/ath9k/hw.c        |    9 +++++++++
 drivers/net/wireless/ath/ath9k/hw.h        |    1 +
 4 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 0b09db0..3216b70 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -266,6 +266,8 @@ enum eeprom_param {
 	EEP_INTERNAL_REGULATOR,
 	EEP_SWREG,
 	EEP_PAPRD,
+	EEP_MODAL_VER,
+	EEP_ANT_DIV_CTL1,
 };
 
 enum ar5416_rates {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 9cccd12..2e1397b 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -213,6 +213,10 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
 		return 0;
 	case EEP_PWR_TABLE_OFFSET:
 		return AR5416_PWR_TABLE_OFFSET_DB;
+	case EEP_MODAL_VER:
+		return pModal->version;
+	case EEP_ANT_DIV_CTL1:
+		return pModal->antdiv_ctl1;
 	default:
 		return 0;
 	}
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 3384ca1..68940a8 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2056,6 +2056,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 	struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
 
 	u16 capField = 0, eeval;
+	u8 ant_div_ctl1;
 
 	eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
 	regulatory->current_rd = eeval;
@@ -2280,6 +2281,14 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
 	if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah))
 		pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
 
+	if (AR_SREV_9285(ah))
+		if (ah->eep_ops->get_eeprom(ah, EEP_MODAL_VER) >= 3) {
+			ant_div_ctl1 =
+				ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+			if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
+				pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
+		}
+
 	return 0;
 }
 
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 1601dd4..1a0efbd 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -204,6 +204,7 @@ enum ath9k_hw_caps {
 	ATH9K_HW_CAP_FASTCLOCK			= BIT(20),
 	ATH9K_HW_CAP_SGI_20			= BIT(21),
 	ATH9K_HW_CAP_PAPRD			= BIT(22),
+	ATH9K_HW_CAP_ANT_DIV_COMB		= BIT(23),
 };
 
 struct ath9k_hw_capabilities {
-- 
1.7.0.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-09-02  8:34 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-07-29 12:56 [PATCH 1/3] ath9k_hw: Add capability flag for Antenna diversity and combining feature Vasanthakumar Thiagarajan
2010-07-29 12:56 ` [PATCH 2/3] ath9k_hw: Add functions to get/set antenna diversity configuration Vasanthakumar Thiagarajan
2010-07-29 12:56 ` [PATCH 3/3] ath9k: Implement an algorithm for Antenna diversity and combining Vasanthakumar Thiagarajan
2010-07-29 14:39   ` Luis R. Rodriguez
2010-07-30  5:36     ` Vasanthakumar Thiagarajan
2010-09-02  8:34 [PATCH 1/3] ath9k_hw: Add capability flag for Antenna diversity and combining feature Vasanthakumar Thiagarajan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).