ath9k: add calibration timeout for AR9002
authorSergey Ryazanov <ryazanov.s.a@gmail.com>
Fri, 24 Apr 2020 00:49:23 +0000 (03:49 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 28 Apr 2020 09:07:21 +0000 (12:07 +0300)
ADC & I/Q calibrations could take infinite time to comple, since they
depend on received frames. In particular the I/Q mismatch calibration
requires receiving of OFDM frames for completion. But in the 2.4GHz
band, a station could receive only CCK frames for a very long time.

And while we wait for the completion of one of the mentioned
calibrations, the NF calibration is blocked. Moreover, in some
environments, I/Q calibration is unable to complete until a correct
noise calibration will be performed due to AGC behaviour.

In order to avoid delaying NF calibration on forever, limit the maximum
duration of ADCs & I/Q calibrations. If the calibration is not completed
within the maximum time, it will be interrupted and a next calibration
will be performed. The code that selects the next calibration has been
reworked to the loop so incompleted calibration will be respinned later.

Ð\90 maximum calibration time of 30 seconds was selected to give the
calibration enough time to complete and to not interfere with the long
(NF) calibration.

Run tested with AR9220.

Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200424004923.17129-7-ryazanov.s.a@gmail.com
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/hw.h

index 68188f500949e9b7905b97eb2d81d8efbf1511ef..fd53b5f9e9b54d8024db71b290908c518cf30cec 100644 (file)
@@ -19,6 +19,8 @@
 #include "ar9002_phy.h"
 
 #define AR9285_CLCAL_REDO_THRESH    1
+/* AGC & I/Q calibrations time limit, ms */
+#define AR9002_CAL_MAX_TIME            30000
 
 enum ar9002_cal_types {
        ADC_GAIN_CAL = BIT(0),
@@ -104,6 +106,14 @@ static bool ar9002_hw_per_calibration(struct ath_hw *ah,
                        } else {
                                ar9002_hw_setup_calibration(ah, currCal);
                        }
+               } else if (time_after(jiffies, ah->cal_start_time +
+                                     msecs_to_jiffies(AR9002_CAL_MAX_TIME))) {
+                       REG_CLR_BIT(ah, AR_PHY_TIMING_CTRL4(0),
+                                   AR_PHY_TIMING_CTRL4_DO_CAL);
+                       ath_dbg(ath9k_hw_common(ah), CALIBRATE,
+                               "calibration timeout\n");
+                       currCal->calState = CAL_WAITING;        /* Try later */
+                       iscaldone = true;
                }
        } else if (!(caldata->CalValid & currCal->calData->calType)) {
                ath9k_hw_reset_calibration(ah, currCal);
@@ -679,8 +689,19 @@ static int ar9002_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
                if (!ar9002_hw_per_calibration(ah, chan, rxchainmask, currCal))
                        return 0;
 
-               ah->cal_list_curr = currCal = currCal->calNext;
-               percal_pending = currCal->calState == CAL_WAITING;
+               /* Looking for next waiting calibration if any */
+               for (currCal = currCal->calNext; currCal != ah->cal_list_curr;
+                    currCal = currCal->calNext) {
+                       if (currCal->calState == CAL_WAITING)
+                               break;
+               }
+               if (currCal->calState == CAL_WAITING) {
+                       percal_pending = true;
+                       ah->cal_list_curr = currCal;
+               } else {
+                       percal_pending = false;
+                       ah->cal_list_curr = ah->cal_list;
+               }
        }
 
        /* Do not start a next calibration if the longcal is in action */
index 2ac3eefd38513f7544b83ab1ec957e1ab12269ac..0422a33395b773fd2d9c91c181711f763ae3d9f9 100644 (file)
@@ -176,6 +176,7 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
 
        ath9k_hw_setup_calibration(ah, currCal);
 
+       ah->cal_start_time = jiffies;
        currCal->calState = CAL_RUNNING;
 
        for (i = 0; i < AR5416_MAX_CHAINS; i++) {
index c99f3c77c823246597c94cf77242ec3c18514bd7..023599e10dd51812e0c904a3bb41be2530bf1770 100644 (file)
@@ -834,6 +834,7 @@ struct ath_hw {
 
        /* Calibration */
        u32 supp_cals;
+       unsigned long cal_start_time;
        struct ath9k_cal_list iq_caldata;
        struct ath9k_cal_list adcgain_caldata;
        struct ath9k_cal_list adcdc_caldata;