2012-06-08 17:38:13

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 1/9] ath9k: choose legacy rate as last rate of MRR series

Choose legacy rate as the last rate of Multi Rate Retry series
if and only if the last selected rate is MCS and having higher
PER rate. The current code fills a legacy rate as last one even
though the previous rates in the series are having good PER value.
This could limit the aggregation that affects the uplink performance.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/rc.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 92a6c0a..e034add 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -770,7 +770,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
struct ieee80211_tx_rate *rates = tx_info->control.rates;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
__le16 fc = hdr->frame_control;
- u8 try_per_rate, i = 0, rix, high_rix;
+ u8 try_per_rate, i = 0, rix;
int is_probe = 0;

if (rate_control_send_low(sta, priv_sta, txrc))
@@ -791,7 +791,6 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
rate_table = ath_rc_priv->rate_table;
rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
&is_probe, false);
- high_rix = rix;

/*
* If we're in HT mode and both us and our peer supports LDPC.
@@ -839,16 +838,16 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
try_per_rate = 8;

/*
- * Use a legacy rate as last retry to ensure that the frame
- * is tried in both MCS and legacy rates.
+ * If the last rate in the rate series is MCS and has
+ * more than 80% of per thresh, then use a legacy rate
+ * as last retry to ensure that the frame is tried in both
+ * MCS and legacy rate.
*/
- if ((rates[2].flags & IEEE80211_TX_RC_MCS) &&
- (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) ||
- (ath_rc_priv->per[high_rix] > 45)))
+ ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
+ if (WLAN_RC_PHY_HT(rate_table->info[rix].phy) &&
+ (ath_rc_priv->per[rix] > 45))
rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
&is_probe, true);
- else
- ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);

/* All other rates in the series have RTS enabled */
ath_rc_rate_set_series(rate_table, &rates[i], txrc,
--
1.7.10.3



2012-06-08 17:39:07

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 9/9] ath9k: keep btcoex period in milliseconds

btcoex periord is converted into micro seconds during initialization
and converted back to milli seconds while starting timer. As MCI code
handles btcoex period in msec, lets keep the btcoex timer in msec and
convert them into other form whenever needed.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/gpio.c | 8 ++++----
drivers/net/wireless/ath/ath9k/mci.c | 3 +--
2 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index af6d273..00ff5ab 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -232,7 +232,7 @@ static void ath_btcoex_period_timer(unsigned long data)
}

ath9k_ps_restore(sc);
- timer_period = btcoex->btcoex_period / 1000;
+ timer_period = btcoex->btcoex_period;
mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period));
}

@@ -267,10 +267,10 @@ static int ath_init_btcoex_timer(struct ath_softc *sc)
{
struct ath_btcoex *btcoex = &sc->btcoex;

- btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000;
- btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
+ btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
+ btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 *
btcoex->btcoex_period / 100;
- btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
+ btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 *
btcoex->btcoex_period / 100;

setup_timer(&btcoex->period_timer, ath_btcoex_period_timer,
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 2ea5e93..92d61cc 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -182,8 +182,7 @@ skip_tuning:
if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;

- btcoex->btcoex_period *= 1000;
- btcoex->btcoex_no_stomp = btcoex->btcoex_period *
+ btcoex->btcoex_no_stomp = btcoex->btcoex_period * 1000 *
(100 - btcoex->duty_cycle) / 100;

ath9k_hw_btcoex_enable(sc->sc_ah);
--
1.7.10.3


2012-06-08 17:38:41

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 6/9] ath9k_hw: program OBS register only when MCI is disabled

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index c3bb4a3..6a4ac60 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1915,7 +1915,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,

ath9k_hw_set_dma(ah);

- REG_WRITE(ah, AR_OBS, 8);
+ if (!ath9k_hw_mci_is_enabled(ah))
+ REG_WRITE(ah, AR_OBS, 8);

if (ah->config.rx_intr_mitigation) {
REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500);
--
1.7.10.3


2012-06-08 17:38:16

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 3/9] ath9k_hw: Fix AR9462 power consumption on idle associated

The HW statemachine is sometimes found stuck in the state
WL_LNA_CTRL_DISABLE when BT is in sleep, which will cause
TX_HOLD always asserted and resmgr stuck in PENDING_TX state

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 45e6700..db3dfc9 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2086,8 +2086,9 @@ static void ath9k_set_power_network_sleep(struct ath_hw *ah)

static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
{
- u32 val;
+ u32 val, btcoex_ctrl2, diag_sw;
int i;
+ u8 lna_ctrl, bt_sleep;

/* Set Bits 14 and 17 of AR_WA before powering on the chip. */
if (AR_SREV_9300_20_OR_LATER(ah)) {
@@ -2111,6 +2112,37 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
AR_RTC_FORCE_WAKE_EN);
udelay(50);

+ if (!AR_SREV_9462_20(ah))
+ goto skip_btcoex;
+
+ for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+ btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2);
+ if (btcoex_ctrl2 != 0xdeadbeef)
+ break;
+ udelay(AH_TIME_QUANTUM);
+ }
+ REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23)));
+
+ for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
+ diag_sw = REG_READ(ah, AR_DIAG_SW);
+ if (diag_sw != 0xdeadbeef)
+ break;
+ udelay(AH_TIME_QUANTUM);
+ }
+ REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18)));
+ lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3;
+ bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP;
+
+ REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2);
+ REG_WRITE(ah, AR_DIAG_SW, diag_sw);
+
+ if (bt_sleep && (lna_ctrl == 2)) {
+ REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1);
+ REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1);
+ udelay(50);
+ }
+
+skip_btcoex:
for (i = POWER_UP_TIME / 50; i > 0; i--) {
val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
if (val == AR_RTC_STATUS_ON)
--
1.7.10.3


2012-06-08 17:38:06

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 2/9] ath9k: restore power state on set channel failure

Not doing so, could cause imbalance in powersave count.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/main.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index c0f478b..e655f2a 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1258,6 +1258,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
ath_err(common, "Unable to set channel\n");
mutex_unlock(&sc->mutex);
+ ath9k_ps_restore(sc);
return -EINVAL;
}

--
1.7.10.3


2012-06-08 17:38:36

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 5/9] ath9k_hw: fix incorrect LNA register settings

After a full reset, mci_reset will put LNA update to the setting
for 2G mode. Those registers need to be forced to update when
the channel is in 5G.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_mci.c | 24 +++++++++---------------
drivers/net/wireless/ath/ath9k/ar9003_mci.h | 2 +-
drivers/net/wireless/ath/ath9k/hw.c | 2 +-
3 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index 96a8a5f..5097ed8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -1013,38 +1013,32 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header,
}
}

-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done)
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
{
struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;

- if (!mci->update_2g5g)
+ if (!mci->update_2g5g && !force)
return;

if (mci->is_2g) {
ar9003_mci_send_2g5g_status(ah, true);
- ar9003_mci_send_lna_transfer(ah, true);
- udelay(5);

- REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
+ REG_SET_BIT(ah, AR_MCI_TX_CTRL,
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
REG_CLR_BIT(ah, AR_PHY_GLB_CONTROL,
AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);

if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
- REG_SET_BIT(ah, AR_BTCOEX_CTRL,
- AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);
+ ar9003_mci_osla_setup(ah, true);
} else {
- ar9003_mci_send_lna_take(ah, true);
- udelay(5);
-
REG_SET_BIT(ah, AR_MCI_TX_CTRL,
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
REG_SET_BIT(ah, AR_PHY_GLB_CONTROL,
AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
- REG_CLR_BIT(ah, AR_BTCOEX_CTRL,
- AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN);

- ar9003_mci_send_2g5g_status(ah, true);
+ ar9003_mci_osla_setup(ah, false);
+ if (!force)
+ ar9003_mci_send_2g5g_status(ah, true);
}
}

@@ -1313,7 +1307,7 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
if (mci->unhalt_bt_gpm)
ar9003_mci_send_coex_halt_bt_gpm(ah, false, true);

- ar9003_mci_2g5g_switch(ah, true);
+ ar9003_mci_2g5g_switch(ah, false);
break;
case MCI_STATE_SET_BT_CAL_START:
mci->bt_state = MCI_BT_CAL_START;
@@ -1394,7 +1388,7 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
mci->query_bt = true;
mci->need_flush_btinfo = true;
ar9003_mci_send_coex_wlan_channels(ah, true);
- ar9003_mci_2g5g_switch(ah, true);
+ ar9003_mci_2g5g_switch(ah, false);
break;
case MCI_STATE_NEED_FTP_STOMP:
value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
index b36c885..8ab082e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
@@ -278,7 +278,7 @@ void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep);
void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable);
void ar9003_mci_init_cal_done(struct ath_hw *ah);
void ar9003_mci_set_full_sleep(struct ath_hw *ah);
-void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done);
+void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force);
void ar9003_mci_check_bt(struct ath_hw *ah);
bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan);
int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index e3ccb45..c3bb4a3 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1711,7 +1711,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
ath9k_hw_start_nfcal(ah, true);

if (ath9k_hw_mci_is_enabled(ah))
- ar9003_mci_2g5g_switch(ah, true);
+ ar9003_mci_2g5g_switch(ah, false);

if (AR_SREV_9271(ah))
ar9002_hw_load_ani_reg(ah, chan);
--
1.7.10.3


2012-06-09 00:03:41

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 3/9] ath9k_hw: Fix AR9462 power consumption on idle associated

Rajkumar Manoharan wrote:
> + if (!AR_SREV_9462_20(ah))
> + goto skip_btcoex;
> +
> + for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
> + btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2);
> + if (btcoex_ctrl2 != 0xdeadbeef)
> + break;
> + udelay(AH_TIME_QUANTUM);
> + }
> + REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23)));
> +
> + for (i = 0; i < AH_WAIT_TIMEOUT; i++) {
> + diag_sw = REG_READ(ah, AR_DIAG_SW);
> + if (diag_sw != 0xdeadbeef)
> + break;
> + udelay(AH_TIME_QUANTUM);
> + }
> + REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18)));
> + lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3;
> + bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP;
> +
> + REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2);
> + REG_WRITE(ah, AR_DIAG_SW, diag_sw);
> +
> + if (bt_sleep && (lna_ctrl == 2)) {
> + REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1);
> + REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1);
> + udelay(50);
> + }
> +
> +skip_btcoex:

It would be cleaner to use a helper function for this and also check
whether MCI/BTCOEX is actually enabled.

Sujith

2012-06-09 00:06:12

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 7/9] ath9k_hw: process MCI interrupts only when btcoex is enabled

Rajkumar Manoharan wrote:
> let us process MCI interrupts only when BTCOEX is enabled to avoid
> processing bogus interrupts.
>
> Signed-off-by: Rajkumar Manoharan <[email protected]>
> ---
> drivers/net/wireless/ath/ath9k/ar9003_mac.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
> index d9e0824..1c0621d 100644
> --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
> +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
> @@ -302,7 +302,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
> ar9003_hw_bb_watchdog_read(ah);
> }
>
> - if (async_cause & AR_INTR_ASYNC_MASK_MCI)
> + if ((async_cause & AR_INTR_ASYNC_MASK_MCI) &&
> + ath9k_hw_mci_is_enabled(ah))
> ar9003_mci_get_isr(ah, masked);

I don't see how AR_INTR_ASYNC_MASK_MCI would be generated when
MCI is disabled ? So the check needs to be one level up.

Sujith

2012-06-08 17:38:48

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 7/9] ath9k_hw: process MCI interrupts only when btcoex is enabled

let us process MCI interrupts only when BTCOEX is enabled to avoid
processing bogus interrupts.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_mac.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index d9e0824..1c0621d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -302,7 +302,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
ar9003_hw_bb_watchdog_read(ah);
}

- if (async_cause & AR_INTR_ASYNC_MASK_MCI)
+ if ((async_cause & AR_INTR_ASYNC_MASK_MCI) &&
+ ath9k_hw_mci_is_enabled(ah))
ar9003_mci_get_isr(ah, masked);

if (sync_cause) {
--
1.7.10.3


2012-06-08 17:39:00

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 8/9] ath9k: simplify btcoex profile management

This patch simplifies profile management utility functions.

* Separate find_profile from add/del functions
* Return correct values when the profile list is empty or
profile is ot found
* flush the profiles when there are entries in the list

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/mci.c | 48 +++++++++++++++++-----------------
1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 49137f4..2ea5e93 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -28,11 +28,14 @@ ath_mci_find_profile(struct ath_mci_profile *mci,
{
struct ath_mci_profile_info *entry;

+ if (list_empty(&mci->info))
+ return NULL;
+
list_for_each_entry(entry, &mci->info, list) {
if (entry->conn_handle == info->conn_handle)
- break;
+ return entry;
}
- return entry;
+ return NULL;
}

static bool ath_mci_add_profile(struct ath_common *common,
@@ -49,31 +52,21 @@ static bool ath_mci_add_profile(struct ath_common *common,
(info->type != MCI_GPM_COEX_PROFILE_VOICE))
return false;

- entry = ath_mci_find_profile(mci, info);
-
- if (entry) {
- memcpy(entry, info, 10);
- } else {
- entry = kzalloc(sizeof(*entry), GFP_KERNEL);
- if (!entry)
- return false;
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return false;

- memcpy(entry, info, 10);
- INC_PROF(mci, info);
- list_add_tail(&info->list, &mci->info);
- }
+ memcpy(entry, info, 10);
+ INC_PROF(mci, info);
+ list_add_tail(&entry->list, &mci->info);

return true;
}

static void ath_mci_del_profile(struct ath_common *common,
struct ath_mci_profile *mci,
- struct ath_mci_profile_info *info)
+ struct ath_mci_profile_info *entry)
{
- struct ath_mci_profile_info *entry;
-
- entry = ath_mci_find_profile(mci, info);
-
if (!entry)
return;

@@ -86,12 +79,16 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci)
{
struct ath_mci_profile_info *info, *tinfo;

+ mci->aggr_limit = 0;
+
+ if (list_empty(&mci->info))
+ return;
+
list_for_each_entry_safe(info, tinfo, &mci->info, list) {
list_del(&info->list);
DEC_PROF(mci, info);
kfree(info);
}
- mci->aggr_limit = 0;
}

static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
@@ -229,12 +226,17 @@ static void ath_mci_process_profile(struct ath_softc *sc,
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_btcoex *btcoex = &sc->btcoex;
struct ath_mci_profile *mci = &btcoex->mci;
+ struct ath_mci_profile_info *entry = NULL;
+
+ entry = ath_mci_find_profile(mci, info);
+ if (entry)
+ memcpy(entry, info, 10);

if (info->start) {
- if (!ath_mci_add_profile(common, mci, info))
+ if (!entry && !ath_mci_add_profile(common, mci, info))
return;
} else
- ath_mci_del_profile(common, mci, info);
+ ath_mci_del_profile(common, mci, entry);

btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
mci->aggr_limit = mci->num_sco ? 6 : 0;
@@ -263,8 +265,6 @@ static void ath_mci_process_status(struct ath_softc *sc,
if (status->is_link)
return;

- memset(&info, 0, sizeof(struct ath_mci_profile_info));
-
info.conn_handle = status->conn_handle;
if (ath_mci_find_profile(mci, &info))
return;
--
1.7.10.3


2012-06-08 17:38:35

by Rajkumar Manoharan

[permalink] [raw]
Subject: [PATCH 4/9] ath9k_hw: check GPM HW write pointer before chip reset

Both "MAC Warm Reset" and "MCI Reset Rx" will reset GPM HW write_ptr.
We should check software cached write_ptr against HW write_ptr before
reset. Otherwise the pending DMA data will be lost.

Signed-off-by: Rajkumar Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_mci.c | 18 ++++++++++++++++++
drivers/net/wireless/ath/ath9k/ar9003_mci.h | 1 +
drivers/net/wireless/ath/ath9k/hw.c | 3 +++
3 files changed, 22 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index b1ced2a..96a8a5f 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -893,6 +893,9 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g,
udelay(100);
}

+ /* Check pending GPM msg before MCI Reset Rx */
+ ar9003_mci_state(ah, MCI_STATE_CHECK_GPM_OFFSET, NULL);
+
regval |= SM(1, AR_MCI_COMMAND2_RESET_RX);
REG_WRITE(ah, AR_MCI_COMMAND2, regval);
udelay(1);
@@ -1190,6 +1193,21 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data)
value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
mci->gpm_idx = value;
break;
+ case MCI_STATE_CHECK_GPM_OFFSET:
+ /*
+ * This should only be called before "MAC Warm Reset" or
+ * "MCI Reset Rx".
+ */
+ value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR);
+ if (mci->gpm_idx == value)
+ break;
+ ath_dbg(common, MCI,
+ "GPM cached write pointer mismatch %d %d\n",
+ mci->gpm_idx, value);
+ mci->query_bt = true;
+ mci->need_flush_btinfo = true;
+ mci->gpm_idx = 0;
+ break;
case MCI_STATE_NEXT_GPM_OFFSET:
case MCI_STATE_LAST_GPM_OFFSET:
/*
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
index 10282e2..b36c885 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
@@ -190,6 +190,7 @@ enum mci_bt_state {
enum mci_state_type {
MCI_STATE_ENABLE,
MCI_STATE_INIT_GPM_OFFSET,
+ MCI_STATE_CHECK_GPM_OFFSET,
MCI_STATE_NEXT_GPM_OFFSET,
MCI_STATE_LAST_GPM_OFFSET,
MCI_STATE_BT,
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index db3dfc9..e3ccb45 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1348,6 +1348,9 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
}
}

+ if (ath9k_hw_mci_is_enabled(ah))
+ ar9003_mci_state(ah, MCI_STATE_CHECK_GPM_OFFSET, NULL);
+
REG_WRITE(ah, AR_RTC_RC, rst_flags);

REGWRITE_BUFFER_FLUSH(ah);
--
1.7.10.3