This diff completes noisefloor calibration code in our athn(4) driver.
Update default/min/max noisefloor values to those used by Linux.

Tested on AR9280 on 2GHz and 5Ghz. Further tests are appreciated.

Index: ar5008.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar5008.c,v
retrieving revision 1.46
diff -u -p -r1.46 ar5008.c
--- ar5008.c    28 Nov 2017 04:35:39 -0000      1.46
+++ ar5008.c    31 Jan 2019 13:39:55 -0000
@@ -98,9 +98,9 @@ void  ar5008_init_chains(struct athn_soft
 void   ar5008_set_rxchains(struct athn_softc *);
 void   ar5008_read_noisefloor(struct athn_softc *, int16_t *, int16_t *);
 void   ar5008_write_noisefloor(struct athn_softc *, int16_t *, int16_t *);
-void   ar5008_get_noisefloor(struct athn_softc *, struct ieee80211_channel *);
+int    ar5008_get_noisefloor(struct athn_softc *);
+void   ar5008_apply_noisefloor(struct athn_softc *);
 void   ar5008_bb_load_noisefloor(struct athn_softc *);
-void   ar5008_noisefloor_calib(struct athn_softc *);
 void   ar5008_do_noisefloor_calib(struct athn_softc *);
 void   ar5008_do_calib(struct athn_softc *);
 void   ar5008_next_calib(struct athn_softc *);
@@ -176,6 +176,8 @@ ar5008_attach(struct athn_softc *sc)
        ops->disable_phy = ar5008_disable_phy;
        ops->set_rxchains = ar5008_set_rxchains;
        ops->noisefloor_calib = ar5008_do_noisefloor_calib;
+       ops->get_noisefloor = ar5008_get_noisefloor;
+       ops->apply_noisefloor = ar5008_apply_noisefloor;
        ops->do_calib = ar5008_do_calib;
        ops->next_calib = ar5008_next_calib;
        ops->hw_init = ar5008_hw_init;
@@ -1876,15 +1878,15 @@ ar5008_write_noisefloor(struct athn_soft
        AR_WRITE_BARRIER(sc);
 }
 
-void
-ar5008_get_noisefloor(struct athn_softc *sc, struct ieee80211_channel *c)
+int
+ar5008_get_noisefloor(struct athn_softc *sc)
 {
        int16_t nf[AR_MAX_CHAINS], nf_ext[AR_MAX_CHAINS];
        int i;
 
        if (AR_READ(sc, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
                /* Noisefloor calibration not finished. */
-               return;
+               return 0;
        }
        /* Noisefloor calibration is finished. */
        ar5008_read_noisefloor(sc, nf, nf_ext);
@@ -1896,6 +1898,7 @@ ar5008_get_noisefloor(struct athn_softc 
        }
        if (++sc->nf_hist_cur >= ATHN_NF_CAL_HIST_MAX)
                sc->nf_hist_cur = 0;
+       return 1;
 }
 
 void
@@ -1926,24 +1929,44 @@ ar5008_bb_load_noisefloor(struct athn_so
                return;
        }
 
-       /* Restore noisefloor values to initial (max) values. */
+       /*
+        * Restore noisefloor values to initial (max) values. These will
+        * be used as initial values during the next NF calibration.
+        */
        for (i = 0; i < AR_MAX_CHAINS; i++)
                nf[i] = nf_ext[i] = AR_DEFAULT_NOISE_FLOOR;
        ar5008_write_noisefloor(sc, nf, nf_ext);
 }
 
 void
-ar5008_noisefloor_calib(struct athn_softc *sc)
+ar5008_apply_noisefloor(struct athn_softc *sc)
 {
-       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
-       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
-       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
-       AR_WRITE_BARRIER(sc);
+       uint32_t agc_nfcal;
+
+       agc_nfcal = AR_READ(sc, AR_PHY_AGC_CONTROL) &
+           (AR_PHY_AGC_CONTROL_NF | AR_PHY_AGC_CONTROL_ENABLE_NF |
+           AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+
+       if (agc_nfcal & AR_PHY_AGC_CONTROL_NF) {
+               /* Pause running NF calibration while values are updated. */
+               AR_CLRBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+               AR_WRITE_BARRIER(sc);
+       }
+
+       ar5008_bb_load_noisefloor(sc);
+
+       if (agc_nfcal & AR_PHY_AGC_CONTROL_NF) {
+               /* Restart interrupted NF calibration. */
+               AR_SETBITS(sc, AR_PHY_AGC_CONTROL, agc_nfcal);
+               AR_WRITE_BARRIER(sc);
+       }
 }
 
 void
 ar5008_do_noisefloor_calib(struct athn_softc *sc)
 {
+       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
+       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
        AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
        AR_WRITE_BARRIER(sc);
 }
Index: ar5416.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar5416.c,v
retrieving revision 1.20
diff -u -p -r1.20 ar5416.c
--- ar5416.c    12 Jan 2017 16:32:28 -0000      1.20
+++ ar5416.c    31 Jan 2019 12:13:37 -0000
@@ -112,7 +112,6 @@ ar5416_attach(struct athn_softc *sc)
 {
        sc->eep_base = AR5416_EEP_START_LOC;
        sc->eep_size = sizeof(struct ar5416_eeprom);
-       sc->def_nf = AR5416_PHY_CCA_MAX_GOOD_VALUE;
        sc->ngpiopins = 14;
        sc->led_pin = 1;
        sc->workaround = AR5416_WA_DEFAULT;
@@ -123,6 +122,10 @@ ar5416_attach(struct athn_softc *sc)
        sc->ops.set_synth = ar5416_set_synth;
        sc->ops.spur_mitigate = ar5416_spur_mitigate;
        sc->ops.get_spur_chans = ar5416_get_spur_chans;
+       sc->cca_min_2g = AR5416_PHY_CCA_MIN_GOOD_VAL_2GHZ;
+       sc->cca_max_2g = AR5416_PHY_CCA_MAX_GOOD_VAL_2GHZ;
+       sc->cca_min_5g = AR5416_PHY_CCA_MIN_GOOD_VAL_5GHZ;
+       sc->cca_max_5g = AR5416_PHY_CCA_MAX_GOOD_VAL_5GHZ;
        if (AR_SREV_9160_10_OR_LATER(sc))
                sc->ini = &ar9160_ini;
        else
Index: ar5416reg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar5416reg.h,v
retrieving revision 1.6
diff -u -p -r1.6 ar5416reg.h
--- ar5416reg.h 5 Jan 2016 18:41:15 -0000       1.6
+++ ar5416reg.h 31 Jan 2019 12:14:47 -0000
@@ -19,7 +19,10 @@
 
 #define AR5416_MAX_CHAINS      3
 
-#define AR5416_PHY_CCA_MAX_GOOD_VALUE  ( -85)
+#define AR5416_PHY_CCA_MIN_GOOD_VAL_2GHZ       (-100)
+#define AR5416_PHY_CCA_MIN_GOOD_VAL_5GHZ       (-110)
+#define AR5416_PHY_CCA_MAX_GOOD_VAL_2GHZ       (-80)
+#define AR5416_PHY_CCA_MAX_GOOD_VAL_5GHZ       (-90)
 
 /*
  * ROM layout used by AR5416, AR9160 and AR9280.
Index: ar9003.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar9003.c,v
retrieving revision 1.46
diff -u -p -r1.46 ar9003.c
--- ar9003.c    19 May 2017 11:42:48 -0000      1.46
+++ ar9003.c    31 Jan 2019 13:58:47 -0000
@@ -105,9 +105,9 @@ void        ar9003_init_chains(struct athn_soft
 void   ar9003_set_rxchains(struct athn_softc *);
 void   ar9003_read_noisefloor(struct athn_softc *, int16_t *, int16_t *);
 void   ar9003_write_noisefloor(struct athn_softc *, int16_t *, int16_t *);
-void   ar9003_get_noisefloor(struct athn_softc *, struct ieee80211_channel *);
+int    ar9003_get_noisefloor(struct athn_softc *);
+void   ar9003_apply_noisefloor(struct athn_softc *);
 void   ar9003_bb_load_noisefloor(struct athn_softc *);
-void   ar9300_noisefloor_calib(struct athn_softc *);
 void   ar9003_do_noisefloor_calib(struct athn_softc *);
 int    ar9003_init_calib(struct athn_softc *);
 void   ar9003_do_calib(struct athn_softc *);
@@ -185,6 +185,8 @@ ar9003_attach(struct athn_softc *sc)
        ops->disable_phy = ar9003_disable_phy;
        ops->set_rxchains = ar9003_set_rxchains;
        ops->noisefloor_calib = ar9003_do_noisefloor_calib;
+       ops->get_noisefloor = ar9003_get_noisefloor;
+       ops->apply_noisefloor = ar9003_apply_noisefloor;
        ops->do_calib = ar9003_do_calib;
        ops->next_calib = ar9003_next_calib;
        ops->hw_init = ar9003_hw_init;
@@ -1976,43 +1978,27 @@ ar9003_write_noisefloor(struct athn_soft
        AR_WRITE_BARRIER(sc);
 }
 
-void
-ar9003_get_noisefloor(struct athn_softc *sc, struct ieee80211_channel *c)
+int
+ar9003_get_noisefloor(struct athn_softc *sc)
 {
        int16_t nf[AR_MAX_CHAINS], nf_ext[AR_MAX_CHAINS];
-       int16_t min, max;
        int i;
 
        if (AR_READ(sc, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) {
                /* Noisefloor calibration not finished. */
-               return;
+               return 0;
        }
        /* Noisefloor calibration is finished. */
        ar9003_read_noisefloor(sc, nf, nf_ext);
 
-       if (IEEE80211_IS_CHAN_2GHZ(c)) {
-               min = sc->cca_min_2g;
-               max = sc->cca_max_2g;
-       } else {
-               min = sc->cca_min_5g;
-               max = sc->cca_max_5g;
-       }
        /* Update noisefloor history. */
        for (i = 0; i < sc->nrxchains; i++) {
-               if (nf[i] < min)
-                       nf[i] = min;
-               else if (nf[i] > max)
-                       nf[i] = max;
-               if (nf_ext[i] < min)
-                       nf_ext[i] = min;
-               else if (nf_ext[i] > max)
-                       nf_ext[i] = max;
-
                sc->nf_hist[sc->nf_hist_cur].nf[i] = nf[i];
                sc->nf_hist[sc->nf_hist_cur].nf_ext[i] = nf_ext[i];
        }
        if (++sc->nf_hist_cur >= ATHN_NF_CAL_HIST_MAX)
                sc->nf_hist_cur = 0;
+       return 1;
 }
 
 void
@@ -2050,17 +2036,36 @@ ar9003_bb_load_noisefloor(struct athn_so
 }
 
 void
-ar9300_noisefloor_calib(struct athn_softc *sc)
+ar9003_apply_noisefloor(struct athn_softc *sc)
 {
-       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
-       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
-       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+       uint32_t agc_nfcal;
+
+       agc_nfcal = AR_READ(sc, AR_PHY_AGC_CONTROL) &
+           (AR_PHY_AGC_CONTROL_NF | AR_PHY_AGC_CONTROL_ENABLE_NF |
+           AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
+
+       if (agc_nfcal & AR_PHY_AGC_CONTROL_NF) {
+               /* Pause running NF calibration while values are updated. */
+               AR_CLRBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+               AR_WRITE_BARRIER(sc);
+       }
+
+       ar9003_bb_load_noisefloor(sc);
+
+       if (agc_nfcal & AR_PHY_AGC_CONTROL_NF) {
+               /* Restart interrupted NF calibration. */
+               AR_SETBITS(sc, AR_PHY_AGC_CONTROL, agc_nfcal);
+               AR_WRITE_BARRIER(sc);
+       }
 }
 
 void
 ar9003_do_noisefloor_calib(struct athn_softc *sc)
 {
+       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_ENABLE_NF);
+       AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
        AR_SETBITS(sc, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
+       AR_WRITE_BARRIER(sc);
 }
 
 int
Index: ar9280.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar9280.c,v
retrieving revision 1.26
diff -u -p -r1.26 ar9280.c
--- ar9280.c    12 Jan 2017 16:32:28 -0000      1.26
+++ ar9280.c    31 Jan 2019 12:46:31 -0000
@@ -93,7 +93,6 @@ ar9280_attach(struct athn_softc *sc)
 {
        sc->eep_base = AR5416_EEP_START_LOC;
        sc->eep_size = sizeof(struct ar5416_eeprom);
-       sc->def_nf = AR9280_PHY_CCA_MAX_GOOD_VALUE;
        sc->ngpiopins = (sc->flags & ATHN_FLAG_USB) ? 16 : 10;
        sc->led_pin = 1;
        sc->workaround = AR9280_WA_DEFAULT;
@@ -106,6 +105,10 @@ ar9280_attach(struct athn_softc *sc)
        sc->ops.get_spur_chans = ar5416_get_spur_chans;
        sc->ops.olpc_init = ar9280_olpc_init;
        sc->ops.olpc_temp_compensation = ar9280_olpc_temp_compensation;
+       sc->cca_min_2g = AR9280_PHY_CCA_MIN_GOOD_VAL_2GHZ;
+       sc->cca_max_2g = AR9280_PHY_CCA_MAX_GOOD_VAL_2GHZ;
+       sc->cca_min_5g = AR9280_PHY_CCA_MIN_GOOD_VAL_5GHZ;
+       sc->cca_max_5g = AR9280_PHY_CCA_MAX_GOOD_VAL_5GHZ;
        sc->ini = &ar9280_2_0_ini;
        sc->serdes = &ar9280_2_0_serdes;
 
Index: ar9280reg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar9280reg.h,v
retrieving revision 1.7
diff -u -p -r1.7 ar9280reg.h
--- ar9280reg.h 5 Jan 2016 18:41:15 -0000       1.7
+++ ar9280reg.h 31 Jan 2019 12:14:27 -0000
@@ -20,7 +20,11 @@
 #define AR9280_MAX_CHAINS      2
 
 #define AR9280_PD_GAIN_BOUNDARY_DEFAULT        56
-#define AR9280_PHY_CCA_MAX_GOOD_VALUE  (-112)
+
+#define AR9280_PHY_CCA_MIN_GOOD_VAL_2GHZ       (-127)
+#define AR9280_PHY_CCA_MIN_GOOD_VAL_5GHZ       (-122)
+#define AR9280_PHY_CCA_MAX_GOOD_VAL_2GHZ       (-97)
+#define AR9280_PHY_CCA_MAX_GOOD_VAL_5GHZ       (-102)
 
 #define AR9280_PHY_SYNTH_CONTROL       0x9874
 
Index: ar9285.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar9285.c,v
retrieving revision 1.27
diff -u -p -r1.27 ar9285.c
--- ar9285.c    12 Jan 2017 16:32:28 -0000      1.27
+++ ar9285.c    31 Jan 2019 12:29:54 -0000
@@ -104,7 +104,6 @@ ar9285_attach(struct athn_softc *sc)
 {
        sc->eep_base = AR9285_EEP_START_LOC;
        sc->eep_size = sizeof(struct ar9285_eeprom);
-       sc->def_nf = AR9285_PHY_CCA_MAX_GOOD_VALUE;
        sc->ngpiopins = (sc->flags & ATHN_FLAG_USB) ? 16 : 12;
        sc->led_pin = (sc->flags & ATHN_FLAG_USB) ? 15 : 1;
        sc->workaround = AR9285_WA_DEFAULT;
@@ -115,6 +114,16 @@ ar9285_attach(struct athn_softc *sc)
        sc->ops.set_synth = ar9280_set_synth;
        sc->ops.spur_mitigate = ar9280_spur_mitigate;
        sc->ops.get_spur_chans = ar9285_get_spur_chans;
+#if NATHN_USB > 0
+       if (AR_SREV_9271(sc)) {
+               sc->cca_min_2g = AR9271_PHY_CCA_MIN_GOOD_VAL_2GHZ;
+               sc->cca_max_2g = AR9271_PHY_CCA_MAX_GOOD_VAL_2GHZ;
+       } else
+#endif
+       {
+               sc->cca_min_2g = AR9285_PHY_CCA_MIN_GOOD_VAL_2GHZ;
+               sc->cca_max_2g = AR9285_PHY_CCA_MAX_GOOD_VAL_2GHZ;
+       }
 #if NATHN_USB > 0
        if (AR_SREV_9271(sc))
                sc->ini = &ar9271_ini;
Index: ar9285reg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar9285reg.h,v
retrieving revision 1.8
diff -u -p -r1.8 ar9285reg.h
--- ar9285reg.h 5 Jan 2016 18:41:15 -0000       1.8
+++ ar9285reg.h 31 Jan 2019 12:14:09 -0000
@@ -19,7 +19,10 @@
 
 #define AR9285_MAX_CHAINS      1
 
-#define AR9285_PHY_CCA_MAX_GOOD_VALUE  (-118)
+#define AR9285_PHY_CCA_MIN_GOOD_VAL_2GHZ       (-127)
+#define AR9285_PHY_CCA_MAX_GOOD_VAL_2GHZ       (-108)
+#define AR9271_PHY_CCA_MIN_GOOD_VAL_2GHZ       (-127)
+#define AR9271_PHY_CCA_MAX_GOOD_VAL_2GHZ       (-116)
 
 #define AR9285_CL_CAL_REDO_THRESH      1
 
Index: ar9287.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar9287.c,v
retrieving revision 1.25
diff -u -p -r1.25 ar9287.c
--- ar9287.c    12 Jan 2017 16:32:28 -0000      1.25
+++ ar9287.c    31 Jan 2019 12:30:04 -0000
@@ -102,7 +102,6 @@ ar9287_attach(struct athn_softc *sc)
 {
        sc->eep_base = AR9287_EEP_START_LOC;
        sc->eep_size = sizeof(struct ar9287_eeprom);
-       sc->def_nf = AR9287_PHY_CCA_MAX_GOOD_VALUE;
        sc->ngpiopins = (sc->flags & ATHN_FLAG_USB) ? 16 : 11;
        sc->led_pin = 8;
        sc->workaround = AR9285_WA_DEFAULT;
@@ -115,6 +114,8 @@ ar9287_attach(struct athn_softc *sc)
        sc->ops.get_spur_chans = ar9287_get_spur_chans;
        sc->ops.olpc_init = ar9287_olpc_init;
        sc->ops.olpc_temp_compensation = ar9287_olpc_temp_compensation;
+       sc->cca_min_2g = AR9287_PHY_CCA_MIN_GOOD_VAL_2GHZ;
+       sc->cca_max_2g = AR9287_PHY_CCA_MAX_GOOD_VAL_2GHZ;
        sc->ini = &ar9287_1_1_ini;
        sc->serdes = &ar9280_2_0_serdes;
 
Index: ar9287reg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/ar9287reg.h,v
retrieving revision 1.4
diff -u -p -r1.4 ar9287reg.h
--- ar9287reg.h 5 Jan 2016 18:41:15 -0000       1.4
+++ ar9287reg.h 31 Jan 2019 12:14:04 -0000
@@ -19,7 +19,8 @@
 
 #define AR9287_MAX_CHAINS      2
 
-#define AR9287_PHY_CCA_MAX_GOOD_VALUE  (-118)
+#define AR9287_PHY_CCA_MIN_GOOD_VAL_2GHZ       (-127)
+#define AR9287_PHY_CCA_MAX_GOOD_VAL_2GHZ       (-97)
 
 /*
  * Analog registers.
Index: athn.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/athn.c,v
retrieving revision 1.100
diff -u -p -r1.100 athn.c
--- athn.c      31 Jan 2019 11:38:52 -0000      1.100
+++ athn.c      31 Jan 2019 14:27:55 -0000
@@ -95,6 +95,10 @@ int          athn_set_key(struct ieee80211com *,
 void           athn_delete_key(struct ieee80211com *, struct ieee80211_node *,
                    struct ieee80211_key *);
 void           athn_iter_calib(void *, struct ieee80211_node *);
+int            athn_cap_noisefloor(struct athn_softc *, int);
+int            athn_nf_hist_mid(int *, int);
+void           athn_filter_noisefloor(struct athn_softc *);
+void           athn_start_noisefloor_calib(struct athn_softc *, int);
 void           athn_calib_to(void *);
 int            athn_init_calib(struct athn_softc *,
                    struct ieee80211_channel *, struct ieee80211_channel *);
@@ -890,7 +894,7 @@ athn_set_chan(struct athn_softc *sc, str
                ops->set_delta_slope(sc, c, extc);
 
        ops->spur_mitigate(sc, c, extc);
-       /* XXX Load noisefloor values and start calibration. */
+       athn_start_noisefloor_calib(sc, 1);
 
        return (0);
 }
@@ -1236,6 +1240,94 @@ athn_iter_calib(void *arg, struct ieee80
                ieee80211_amrr_choose(&sc->amrr, ni, &an->amn);
 }
 
+int
+athn_cap_noisefloor(struct athn_softc *sc, int nf)
+{
+       int16_t min, max;
+
+       if (nf == 0 || nf == -1) /* invalid measurement */
+               return AR_DEFAULT_NOISE_FLOOR;
+
+       if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) {
+               min = sc->cca_min_2g;
+               max = sc->cca_max_2g;
+       } else {
+               min = sc->cca_min_5g;
+               max = sc->cca_max_5g;
+       }
+
+       if (nf < min)
+               return min;
+       if (nf > max)
+               return max;
+
+       return nf;
+}
+
+int
+athn_nf_hist_mid(int *nf_vals, int nvalid)
+{
+       int nf_sorted[ATHN_NF_CAL_HIST_MAX];
+       int i, j, nf;
+
+       if (nvalid <= 1)
+               return nf_vals[0];
+
+       for (i = 0; i < nvalid; i++)
+               nf_sorted[i] = nf_vals[i];
+
+       for (i = 0; i < nvalid; i++) {
+               for (j = 1; j < nvalid - i; j++) {
+                       if (nf_sorted[j] > nf_sorted[j - 1]) {
+                               nf = nf_sorted[j];
+                               nf_sorted[j] = nf_sorted[j - 1];
+                               nf_sorted[j - 1] = nf;
+                       }
+               }
+       }
+
+       return nf_sorted[nvalid / 2];
+}
+
+void
+athn_filter_noisefloor(struct athn_softc *sc)
+{
+       int nf_vals[ATHN_NF_CAL_HIST_MAX];
+       int nf_ext_vals[ATHN_NF_CAL_HIST_MAX];
+       int i, cur, n;
+
+       for (i = 0; i < sc->ntxchains; i++) {
+               if (sc->nf_hist_cur > 0)
+                       cur = sc->nf_hist_cur - 1;
+               else
+                       cur = ATHN_NF_CAL_HIST_MAX - 1;
+               for (n = 0; n < sc->nf_hist_nvalid; n++) {
+                       nf_vals[n] = sc->nf_hist[cur].nf[i];
+                       nf_ext_vals[n] = sc->nf_hist[cur].nf_ext[i];
+                       if (++cur >= ATHN_NF_CAL_HIST_MAX)
+                               cur = 0;
+               }
+               sc->nf_priv[i] = athn_cap_noisefloor(sc,
+                   athn_nf_hist_mid(nf_vals, sc->nf_hist_nvalid));
+               sc->nf_ext_priv[i] = athn_cap_noisefloor(sc,
+                   athn_nf_hist_mid(nf_ext_vals, sc->nf_hist_nvalid));
+       }
+}
+
+void
+athn_start_noisefloor_calib(struct athn_softc *sc, int reset_history)
+{
+       extern int ticks;
+
+       if (reset_history)
+               sc->nf_hist_nvalid = 0;
+
+       sc->nf_calib_pending = 1;
+       sc->nf_calib_ticks = ticks;
+
+       sc->ops.noisefloor_calib(sc);
+}
+
 void
 athn_calib_to(void *arg)
 {
@@ -1258,6 +1350,17 @@ athn_calib_to(void *arg)
                        ar9285_pa_calib(sc);
        }
 
+       /* Do periodic (every 4 minutes) NF calibration. */
+       if (sc->nf_calib_pending && ops->get_noisefloor(sc)) {
+               if (sc->nf_hist_nvalid < ATHN_NF_CAL_HIST_MAX)
+                       sc->nf_hist_nvalid++;
+               athn_filter_noisefloor(sc);
+               ops->apply_noisefloor(sc);
+               sc->nf_calib_pending = 0;
+       }
+       if (ticks - (sc->nf_calib_ticks + 240 * hz) >= 0)
+               athn_start_noisefloor_calib(sc, 0);
+
        /* Do periodic (every 30 seconds) temperature compensation. */
        if ((sc->flags & ATHN_FLAG_OLPC) &&
            ticks >= sc->olpc_ticks + 30 * hz) {
@@ -1296,7 +1399,6 @@ int
 athn_init_calib(struct athn_softc *sc, struct ieee80211_channel *c,
     struct ieee80211_channel *extc)
 {
-       struct athn_ops *ops = &sc->ops;
        int error;
 
        if (AR_SREV_9380_10_OR_LATER(sc))
@@ -1318,9 +1420,11 @@ athn_init_calib(struct athn_softc *sc, s
                        else
                                ar9285_pa_calib(sc);
                }
-               /* Do noisefloor calibration. */
-               ops->noisefloor_calib(sc);
        }
+
+       /* Do noisefloor calibration. */
+       athn_start_noisefloor_calib(sc, 1);
+
        if (AR_SREV_9160_10_OR_LATER(sc)) {
                /* Support IQ calibration. */
                sc->sup_calib_mask = ATHN_CAL_IQ;
Index: athnreg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/athnreg.h,v
retrieving revision 1.21
diff -u -p -r1.21 athnreg.h
--- athnreg.h   28 Nov 2017 04:35:39 -0000      1.21
+++ athnreg.h   31 Jan 2019 12:36:17 -0000
@@ -1449,7 +1449,7 @@
 #define AR_CTL_2GHT40  7
 #define AR_CTL_5GHT40  8
 
-#define AR_DEFAULT_NOISE_FLOOR (-95)
+#define AR_DEFAULT_NOISE_FLOOR (-100)
 
 /*
  * Macros to access registers.
Index: athnvar.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/athnvar.h,v
retrieving revision 1.38
diff -u -p -r1.38 athnvar.h
--- athnvar.h   31 Jan 2019 11:38:52 -0000      1.38
+++ athnvar.h   31 Jan 2019 14:07:51 -0000
@@ -408,6 +408,8 @@ struct athn_ops {
        void    (*disable_phy)(struct athn_softc *);
        void    (*set_rxchains)(struct athn_softc *);
        void    (*noisefloor_calib)(struct athn_softc *);
+       int     (*get_noisefloor)(struct athn_softc *);
+       void    (*apply_noisefloor)(struct athn_softc *);
        void    (*do_calib)(struct athn_softc *);
        void    (*next_calib)(struct athn_softc *);
        void    (*hw_init)(struct athn_softc *, struct ieee80211_channel *,
@@ -550,14 +552,16 @@ struct athn_softc {
        int16_t                         cca_max_2g;
        int16_t                         cca_min_5g;
        int16_t                         cca_max_5g;
-       int16_t                         def_nf;
        struct {
                int16_t nf[AR_MAX_CHAINS];
                int16_t nf_ext[AR_MAX_CHAINS];
        }                               nf_hist[ATHN_NF_CAL_HIST_MAX];
        int                             nf_hist_cur;
+       int                             nf_hist_nvalid;
        int16_t                         nf_priv[AR_MAX_CHAINS];
        int16_t                         nf_ext_priv[AR_MAX_CHAINS];
+       int                             nf_calib_pending;
+       int                             nf_calib_ticks;
        int                             pa_calib_ticks;
 
        struct athn_calib               calib;

Reply via email to