diff --git a/sys/dev/iwx/if_iwx.c b/sys/dev/iwx/if_iwx.c --- a/sys/dev/iwx/if_iwx.c +++ b/sys/dev/iwx/if_iwx.c @@ -432,7 +432,7 @@ static int iwx_rxmq_get_signal_strength(struct iwx_softc *, struct iwx_rx_mpdu_desc *); static void iwx_rx_rx_phy_cmd(struct iwx_softc *, struct iwx_rx_packet *, struct iwx_rx_data *); -static int iwx_get_noise(const struct iwx_statistics_rx_non_phy *); +static int iwx_get_noise(struct iwx_softc *, const struct iwx_statistics_rx_non_phy *); static int iwx_rx_hwdecrypt(struct iwx_softc *, struct mbuf *, uint32_t); #if 0 int iwx_ccmp_decap(struct iwx_softc *, struct mbuf *, @@ -4208,6 +4208,17 @@ return 0; } +/* + * @brief Return a single signal strength for the given frame. + * + * The firmware communicates up an energy field which is the negative of + * the dBm value. Ie, the number is positive and it increases as the + * signal level decreases. + * + * Fetch the two values, map 0 (inactive antenna) to -256 dBm which is a + * very small number, negate a non-zero value so it's mapped into a dBm + * value, then choose the maximum value to return. + */ static int iwx_rxmq_get_signal_strength(struct iwx_softc *sc, struct iwx_rx_mpdu_desc *desc) @@ -4253,12 +4264,18 @@ } /* - * Retrieve the average noise (in dBm) among receivers. + * @brief Retrieve the average noise (in dBm) among receivers. + * + * Note: This routine calculates the noise floor sum incorrectly, as + * you can't just linearly add the logarithm based dB units together. + * + * If no noise floor is available then this routine will return -127. */ static int -iwx_get_noise(const struct iwx_statistics_rx_non_phy *stats) +iwx_get_noise(struct iwx_softc *sc, + const struct iwx_statistics_rx_non_phy *stats) { - int i, total, nbant, noise; + int i, total, nbant, noise, ret; total = nbant = noise = 0; for (i = 0; i < 3; i++) { @@ -4270,7 +4287,14 @@ } /* There should be at least one antenna but check anyway. */ - return (nbant == 0) ? -127 : (total / nbant) - 107; + if (nbant == 0) + ret = -127; + else if (total == 0) + ret = -127; + else + ret = (total / nbant) - 127; + + return (ret); } #if 0 @@ -4687,7 +4711,17 @@ /* rssi is in 1/2db units */ rxs.c_rssi = rssi * 2; - rxs.c_nf = sc->sc_noise; + + /* noise floor is in 1dB units */ + if (sc->sc_noise == -127) + /* + * For now choose /a/ default, net80211 expects nf to be passed + * in various places and older drivers fake NF values where + * needed. + */ + rxs.c_nf = -107; + else + rxs.c_nf = sc->sc_noise; if (pad) { rxs.c_pktflags |= IEEE80211_RX_F_DECRYPTED; @@ -9129,11 +9163,16 @@ break; } + /* + * TODO: is this the right struct to use? Look at what + * mvm is doing for statistics notification (eg + * iwl_mvm_handle_rx_statistics() . + */ case IWX_STATISTICS_NOTIFICATION: { struct iwx_notif_statistics *stats; SYNC_RESP_STRUCT(stats, pkt); memcpy(&sc->sc_stats, stats, sizeof(sc->sc_stats)); - sc->sc_noise = iwx_get_noise(&stats->rx.general); + sc->sc_noise = iwx_get_noise(sc, &stats->rx.general); break; }