Handle the newer-style bluetooth message format from the (at least)

Centrino 2230 firmware.

This fixes the general statistics block to be actually valid.

I've verified this by contrasting the output of iwnstats before and
after the change.  The general block is now correct.

Tested:

* Intel 5100 (old format stats message)
* Intel 2230 (new format stats message)
This commit is contained in:
Adrian Chadd 2014-03-04 08:01:56 +00:00
parent cd29d6dd3b
commit 26bb40d804

View File

@ -685,6 +685,13 @@ iwn_attach(device_t dev)
goto fail;
}
#if 0
device_printf(sc->sc_dev, "%s: rx_stats=%d, rx_stats_bt=%d\n",
__func__,
sizeof(struct iwn_stats),
sizeof(struct iwn_stats_bt));
#endif
if (bootverbose)
ieee80211_announce(ic);
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
@ -3143,11 +3150,62 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc,
static void
iwn_stats_update(struct iwn_softc *sc, struct iwn_calib_state *calib,
struct iwn_stats *stats)
struct iwn_stats *stats, int len)
{
struct iwn_stats_bt *stats_bt;
struct iwn_stats *lstats;
/* XXX lock assert */
memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats));
/*
* First - check whether the length is the bluetooth or normal.
*
* If it's normal - just copy it and bump out.
* Otherwise we have to convert things.
*/
if (len == sizeof(struct iwn_stats) + 4) {
memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats));
sc->last_stat_valid = 1;
return;
}
/*
* If it's not the bluetooth size - log, then just copy.
*/
if (len != sizeof(struct iwn_stats_bt) + 4) {
DPRINTF(sc, IWN_DEBUG_STATS,
"%s: size of rx statistics (%d) not an expected size!\n",
__func__,
len);
memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats));
sc->last_stat_valid = 1;
return;
}
/*
* Ok. Time to copy.
*/
stats_bt = (struct iwn_stats_bt *) stats;
lstats = &sc->last_stat;
/* flags */
lstats->flags = stats_bt->flags;
/* rx_bt */
memcpy(&lstats->rx.ofdm, &stats_bt->rx_bt.ofdm,
sizeof(struct iwn_rx_phy_stats));
memcpy(&lstats->rx.cck, &stats_bt->rx_bt.cck,
sizeof(struct iwn_rx_phy_stats));
memcpy(&lstats->rx.general, &stats_bt->rx_bt.general_bt.common,
sizeof(struct iwn_rx_general_stats));
memcpy(&lstats->rx.ht, &stats_bt->rx_bt.ht,
sizeof(struct iwn_rx_ht_phy_stats));
/* tx */
memcpy(&lstats->tx, &stats_bt->tx,
sizeof(struct iwn_tx_stats));
/* general */
memcpy(&lstats->general, &stats_bt->general,
sizeof(struct iwn_general_stats));
/* XXX TODO: Squirrel away the extra bluetooth stats somewhere */
sc->last_stat_valid = 1;
}
@ -3165,6 +3223,7 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc,
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
struct iwn_calib_state *calib = &sc->calib;
struct iwn_stats *stats = (struct iwn_stats *)(desc + 1);
struct iwn_stats *lstats;
int temp;
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
@ -3179,15 +3238,26 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc,
bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: received statistics, cmd %d\n",
__func__, desc->type);
DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_STATS,
"%s: received statistics, cmd %d, len %d\n",
__func__, desc->type, le16toh(desc->len));
sc->calib_cnt = 0; /* Reset TX power calibration timeout. */
/* Collect/track general statistics for reporting */
iwn_stats_update(sc, calib, stats);
/*
* Collect/track general statistics for reporting.
*
* This takes care of ensuring that the bluetooth sized message
* will be correctly converted to the legacy sized message.
*/
iwn_stats_update(sc, calib, stats, le16toh(desc->len));
/*
* And now, let's take a reference of it to use!
*/
lstats = &sc->last_stat;
/* Test if temperature has changed. */
if (stats->general.temp != sc->rawtemp) {
if (lstats->general.temp != sc->rawtemp) {
/* Convert "raw" temperature to degC. */
sc->rawtemp = stats->general.temp;
temp = ops->get_temperature(sc);
@ -3202,25 +3272,25 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc,
if (desc->type != IWN_BEACON_STATISTICS)
return; /* Reply to a statistics request. */
sc->noise = iwn_get_noise(&stats->rx.general);
sc->noise = iwn_get_noise(&lstats->rx.general);
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: noise %d\n", __func__, sc->noise);
/* Test that RSSI and noise are present in stats report. */
if (le32toh(stats->rx.general.flags) != 1) {
if (le32toh(lstats->rx.general.flags) != 1) {
DPRINTF(sc, IWN_DEBUG_ANY, "%s\n",
"received statistics without RSSI");
return;
}
if (calib->state == IWN_CALIB_STATE_ASSOC)
iwn_collect_noise(sc, &stats->rx.general);
iwn_collect_noise(sc, &lstats->rx.general);
else if (calib->state == IWN_CALIB_STATE_RUN) {
iwn_tune_sensitivity(sc, &stats->rx);
iwn_tune_sensitivity(sc, &lstats->rx);
/*
* XXX TODO: Only run the RX recovery if we're associated!
*/
iwn_check_rx_recovery(sc, stats);
iwn_save_stats_counters(sc, stats);
iwn_check_rx_recovery(sc, lstats);
iwn_save_stats_counters(sc, lstats);
}
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);