2013-12-17 18:11:49

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 0/4] ath9k patches

From: Sujith Manoharan <[email protected]>

This series has a few RTC fixes. There are still two missing pieces:

* When a cold reset is performed, AR9100 requires the AHB/WMAC interface
to be reset.
* AR955x requires an SoC RTC reset.

Both have to be done via the external_reset() platform interface.

Sujith Manoharan (4):
ath9k: Remove ath9k_hw_gettsf32()
ath9k: Add a delay between RTC reset/clear for AR9003
ath9k: Fix RTC reset delay
ath9k: Fix AR9330 external reset

drivers/net/wireless/ath/ath9k/ar9003_mci.c | 2 +-
drivers/net/wireless/ath/ath9k/hw.c | 86 ++++++++++++++---------------
drivers/net/wireless/ath/ath9k/hw.h | 2 +-
drivers/net/wireless/ath/ath9k/init.c | 3 +-
4 files changed, 45 insertions(+), 48 deletions(-)

--
1.8.5.1



2013-12-17 18:11:51

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 2/4] ath9k: Add a delay between RTC reset/clear for AR9003

From: Sujith Manoharan <[email protected]>

The small delay that is present between a RTC reset/clear
operation is required for the chip to settle and this is
needed for all chips, not just the AR9002 family.

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

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 40cc64b..f58868c 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1399,8 +1399,7 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)

REGWRITE_BUFFER_FLUSH(ah);

- if (!AR_SREV_9300_20_OR_LATER(ah))
- udelay(2);
+ udelay(2);

if (!AR_SREV_9100(ah) && !AR_SREV_9300_20_OR_LATER(ah))
REG_WRITE(ah, AR_RC, 0);
--
1.8.5.1


2013-12-18 03:04:14

by Sujith Manoharan

[permalink] [raw]
Subject: Re: [PATCH 4/4] ath9k: Fix AR9330 external reset

Felix Fietkau wrote:
> In my tests, the external reset helped with getting Tx DMA un-stuck as
> well, even if no beacons are enabled. I think we should keep the tx
> pending check.

Maybe this check is unnecessary altogether ? If we are doing a full cold reset,
the SoC probably needs to be reset as well, so why check for pending frames
at all ?

Sujith


2013-12-17 20:44:56

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH 4/4] ath9k: Fix AR9330 external reset

On 2013-12-17 19:06, Sujith Manoharan wrote:
> From: Sujith Manoharan <[email protected]>
>
> The external SoC reset for AR9330 is required only when a
> beacon stuck is seen, so do not check all the TX queues
> for pending frames.
In my tests, the external reset helped with getting Tx DMA un-stuck as
well, even if no beacons are enabled. I think we should keep the tx
pending check.

- Felix

2013-12-17 18:11:47

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 1/4] ath9k: Remove ath9k_hw_gettsf32()

From: Sujith Manoharan <[email protected]>

It is unnecessary and the value is just a simple,
direct register read.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/ar9003_mci.c | 2 +-
drivers/net/wireless/ath/ath9k/hw.c | 10 ----------
drivers/net/wireless/ath/ath9k/hw.h | 1 -
3 files changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
index 7b94a6c..e9cf1de 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c
@@ -1263,7 +1263,7 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type)
ar9003_mci_send_coex_bt_status_query(ah, true, query_type);
break;
case MCI_STATE_RECOVER_RX:
- tsf = ath9k_hw_gettsf32(ah);
+ tsf = REG_READ(ah, AR_TSF_L32);
if ((tsf - mci->last_recovery) <= MCI_RECOVERY_DUR_TSF) {
ath_dbg(ath9k_hw_common(ah), MCI,
"(MCI) ignore Rx recovery\n");
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 4797cb2..40cc64b 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2973,12 +2973,6 @@ static const struct ath_gen_timer_configuration gen_tmr_configuration[] =

/* HW generic timer primitives */

-u32 ath9k_hw_gettsf32(struct ath_hw *ah)
-{
- return REG_READ(ah, AR_TSF_L32);
-}
-EXPORT_SYMBOL(ath9k_hw_gettsf32);
-
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),
void (*overflow)(void *),
@@ -3137,10 +3131,6 @@ void ath_gen_timer_isr(struct ath_hw *ah)
}
EXPORT_SYMBOL(ath_gen_timer_isr);

-/********/
-/* HTC */
-/********/
-
static struct {
u32 version;
const char * name;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 54932d8..ba0059f 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -978,7 +978,6 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test);
void ath9k_hw_setopmode(struct ath_hw *ah);
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
void ath9k_hw_write_associd(struct ath_hw *ah);
-u32 ath9k_hw_gettsf32(struct ath_hw *ah);
u64 ath9k_hw_gettsf64(struct ath_hw *ah);
void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64);
void ath9k_hw_reset_tsf(struct ath_hw *ah);
--
1.8.5.1


2013-12-18 04:16:54

by Sujith Manoharan

[permalink] [raw]
Subject: Re: [PATCH 4/4] ath9k: Fix AR9330 external reset

Sujith Manoharan wrote:
> Maybe this check is unnecessary altogether ? If we are doing a full cold reset,
> the SoC probably needs to be reset as well, so why check for pending frames
> at all ?

For warm reset, this could be required, so we can probably retain the check
for pending TX frames.

Sujith

2013-12-17 18:11:51

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 4/4] ath9k: Fix AR9330 external reset

From: Sujith Manoharan <[email protected]>

The external SoC reset for AR9330 is required only when a
beacon stuck is seen, so do not check all the TX queues
for pending frames.

Signed-off-by: Sujith Manoharan <[email protected]>
---
drivers/net/wireless/ath/ath9k/hw.c | 66 ++++++++++++++++++-----------------
drivers/net/wireless/ath/ath9k/hw.h | 1 +
drivers/net/wireless/ath/ath9k/init.c | 3 +-
3 files changed, 37 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 2a511c6..29125c2 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1272,6 +1272,38 @@ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
*coef_exponent = coef_exp - 16;
}

+/* AR9330 WAR:
+ * call external reset function to reset WMAC if:
+ * - doing a cold reset
+ * - we have pending frames in the beacon queue
+ */
+static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type)
+{
+ int npend = 0;
+
+ npend = ath9k_hw_numtxpending(ah, ah->beaconq);
+
+ if (ah->external_reset &&
+ (npend || type == ATH9K_RESET_COLD)) {
+ int reset_err = 0;
+
+ ath_dbg(ath9k_hw_common(ah), RESET,
+ "reset MAC via external reset\n");
+
+ reset_err = ah->external_reset();
+ if (reset_err) {
+ ath_err(ath9k_hw_common(ah),
+ "External reset failed, err=%d\n",
+ reset_err);
+ return false;
+ }
+
+ REG_WRITE(ah, AR_RTC_RESET, 1);
+ }
+
+ return true;
+}
+
static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
{
u32 rst_flags;
@@ -1322,38 +1354,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
}

if (AR_SREV_9330(ah)) {
- int npend = 0;
- int i;
-
- /* AR9330 WAR:
- * call external reset function to reset WMAC if:
- * - doing a cold reset
- * - we have pending frames in the TX queues
- */
-
- for (i = 0; i < AR_NUM_QCU; i++) {
- npend = ath9k_hw_numtxpending(ah, i);
- if (npend)
- break;
- }
-
- if (ah->external_reset &&
- (npend || type == ATH9K_RESET_COLD)) {
- int reset_err = 0;
-
- ath_dbg(ath9k_hw_common(ah), RESET,
- "reset MAC via external reset\n");
-
- reset_err = ah->external_reset();
- if (reset_err) {
- ath_err(ath9k_hw_common(ah),
- "External reset failed, err=%d\n",
- reset_err);
- return false;
- }
-
- REG_WRITE(ah, AR_RTC_RESET, 1);
- }
+ if (!ath9k_hw_ar9330_reset_war(ah, type))
+ return false;
}

if (ath9k_hw_mci_is_enabled(ah))
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index ba0059f..def98b4 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -753,6 +753,7 @@ struct ath_hw {
struct ath9k_pacal_info pacal_info;
struct ar5416Stats stats;
struct ath9k_tx_queue_info txq[ATH9K_NUM_TX_QUEUES];
+ int beaconq;

enum ath9k_int imask;
u32 imrs2_reg;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index ea67c01..dff1e96 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -469,8 +469,9 @@ static int ath9k_init_queues(struct ath_softc *sc)
int i = 0;

sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
- sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
+ sc->sc_ah->beaconq = sc->beacon.beaconq;

+ sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
ath_cabq_update(sc);

sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0);
--
1.8.5.1


2013-12-17 18:11:51

by Sujith Manoharan

[permalink] [raw]
Subject: [PATCH 3/4] ath9k: Fix RTC reset delay

From: Sujith Manoharan <[email protected]>

The delay that is required after issuing a RTC reset
varies for each chip. Handle this properly.

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

diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index f58868c..2a511c6 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1363,7 +1363,12 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)

REGWRITE_BUFFER_FLUSH(ah);

- udelay(50);
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ udelay(50);
+ else if (AR_SREV_9100(ah))
+ udelay(10000);
+ else
+ udelay(100);

REG_WRITE(ah, AR_RTC_RC, 0);
if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
--
1.8.5.1