urtwn: add temperature calibration

Redo LC calibration if temperature changed significantly since last
calibration.

Tested with RTL8188EU/RTL8188CUS in STA mode.

Reviewed by:	kevlo
Approved by:	adrian (mentor)
Obtained from:	NetBSD (mostly)
Differential Revision:	https://reviews.freebsd.org/D4966
This commit is contained in:
Andriy Voskoboinyk 2016-01-20 23:55:39 +00:00
parent 17182b1351
commit 218592ceed
3 changed files with 106 additions and 5 deletions

View File

@ -286,6 +286,9 @@ static void urtwn_ibss_recv_mgmt(struct ieee80211_node *,
const struct ieee80211_rx_stats *, int, int);
static int urtwn_newstate(struct ieee80211vap *,
enum ieee80211_state, int);
static void urtwn_calib_to(void *);
static void urtwn_calib_cb(struct urtwn_softc *,
union sec_param *);
static void urtwn_watchdog(void *);
static void urtwn_update_avgrssi(struct urtwn_softc *, int, int8_t);
static int8_t urtwn_get_rssi(struct urtwn_softc *, int, void *);
@ -353,6 +356,7 @@ static void urtwn_set_chan(struct urtwn_softc *,
struct ieee80211_channel *);
static void urtwn_iq_calib(struct urtwn_softc *);
static void urtwn_lc_calib(struct urtwn_softc *);
static void urtwn_temp_calib(struct urtwn_softc *);
static int urtwn_init(struct urtwn_softc *);
static void urtwn_stop(struct urtwn_softc *);
static void urtwn_abort_xfers(struct urtwn_softc *);
@ -481,6 +485,7 @@ urtwn_attach(device_t self)
MTX_NETWORK_LOCK, MTX_DEF);
URTWN_CMDQ_LOCK_INIT(sc);
URTWN_NT_LOCK_INIT(sc);
callout_init(&sc->sc_calib_to, 0);
callout_init(&sc->sc_watchdog_ch, 0);
mbufq_init(&sc->sc_snd, ifqmaxlen);
@ -626,6 +631,7 @@ urtwn_detach(device_t self)
urtwn_stop(sc);
callout_drain(&sc->sc_watchdog_ch);
callout_drain(&sc->sc_calib_to);
/* stop all USB transfers */
usbd_transfer_unsetup(sc->sc_xfer, URTWN_N_TRANSFER);
@ -2313,6 +2319,9 @@ urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
callout_stop(&sc->sc_watchdog_ch);
if (ostate == IEEE80211_S_RUN) {
/* Stop calibration. */
callout_stop(&sc->sc_calib_to);
/* Turn link LED off. */
urtwn_set_led(sc, URTWN_LED_LINK, 0);
@ -2450,8 +2459,10 @@ urtwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
sc->avg_pwdb = -1; /* Reset average RSSI. */
/* Reset temperature calibration state machine. */
sc->thcal_state = 0;
sc->sc_flags &= ~URTWN_TEMP_MEASURED;
sc->thcal_lctemp = 0;
/* Start periodic calibration. */
callout_reset(&sc->sc_calib_to, 2*hz, urtwn_calib_to, sc);
end_run:
ieee80211_free_node(ni);
@ -2465,6 +2476,25 @@ end_run:
return (error != 0 ? error : uvp->newstate(vap, nstate, arg));
}
static void
urtwn_calib_to(void *arg)
{
struct urtwn_softc *sc = arg;
/* Do it in a process context. */
urtwn_cmd_sleepable(sc, NULL, 0, urtwn_calib_cb);
}
static void
urtwn_calib_cb(struct urtwn_softc *sc, union sec_param *data)
{
/* Do temperature compensation. */
urtwn_temp_calib(sc);
if ((urtwn_read_1(sc, R92C_MSR) & R92C_MSR_MASK) != R92C_MSR_NOLINK)
callout_reset(&sc->sc_calib_to, 2*hz, urtwn_calib_to, sc);
}
static void
urtwn_watchdog(void *arg)
{
@ -4557,6 +4587,64 @@ urtwn_lc_calib(struct urtwn_softc *sc)
}
}
static void
urtwn_temp_calib(struct urtwn_softc *sc)
{
uint8_t temp;
URTWN_ASSERT_LOCKED(sc);
if (!(sc->sc_flags & URTWN_TEMP_MEASURED)) {
/* Start measuring temperature. */
URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP,
"%s: start measuring temperature\n", __func__);
if (sc->chip & URTWN_CHIP_88E) {
urtwn_rf_write(sc, 0, R88E_RF_T_METER,
R88E_RF_T_METER_START);
} else {
urtwn_rf_write(sc, 0, R92C_RF_T_METER,
R92C_RF_T_METER_START);
}
sc->sc_flags |= URTWN_TEMP_MEASURED;
return;
}
sc->sc_flags &= ~URTWN_TEMP_MEASURED;
/* Read measured temperature. */
if (sc->chip & URTWN_CHIP_88E) {
temp = MS(urtwn_rf_read(sc, 0, R88E_RF_T_METER),
R88E_RF_T_METER_VAL);
} else {
temp = MS(urtwn_rf_read(sc, 0, R92C_RF_T_METER),
R92C_RF_T_METER_VAL);
}
if (temp == 0) { /* Read failed, skip. */
URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP,
"%s: temperature read failed, skipping\n", __func__);
return;
}
URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP,
"%s: temperature: previous %u, current %u\n",
__func__, sc->thcal_lctemp, temp);
/*
* Redo LC calibration if temperature changed significantly since
* last calibration.
*/
if (sc->thcal_lctemp == 0) {
/* First LC calibration is performed in urtwn_init(). */
sc->thcal_lctemp = temp;
} else if (abs(temp - sc->thcal_lctemp) > 1) {
URTWN_DPRINTF(sc, URTWN_DEBUG_TEMP,
"%s: LC calib triggered by temp: %u -> %u\n",
__func__, sc->thcal_lctemp, temp);
urtwn_lc_calib(sc);
/* Record temperature of last LC calibration. */
sc->thcal_lctemp = temp;
}
}
static int
urtwn_init(struct urtwn_softc *sc)
{
@ -4804,7 +4892,8 @@ urtwn_stop(struct urtwn_softc *sc)
return;
}
sc->sc_flags &= ~URTWN_RUNNING;
sc->sc_flags &= ~(URTWN_RUNNING | URTWN_TEMP_MEASURED);
sc->thcal_lctemp = 0;
callout_stop(&sc->sc_watchdog_ch);
urtwn_abort_xfers(sc);

View File

@ -813,6 +813,7 @@
#define R92C_RF_SYN_G(i) (0x25 + (i))
#define R92C_RF_RCK_OS 0x30
#define R92C_RF_TXPA_G(i) (0x31 + (i))
#define R88E_RF_T_METER 0x42
/* Bits for R92C_RF_AC. */
#define R92C_RF_AC_MODE_M 0x70000
@ -826,6 +827,16 @@
#define R88E_RF_CHNLBW_BW20 0x00c00
#define R92C_RF_CHNLBW_LCSTART 0x08000
/* Bits for R92C_RF_T_METER. */
#define R92C_RF_T_METER_START 0x60
#define R92C_RF_T_METER_VAL_M 0x1f
#define R92C_RF_T_METER_VAL_S 0
/* Bits for R88E_RF_T_METER. */
#define R88E_RF_T_METER_VAL_M 0x0fc00
#define R88E_RF_T_METER_VAL_S 10
#define R88E_RF_T_METER_START 0x30000
/*
* CAM entries.

View File

@ -156,6 +156,7 @@ struct urtwn_softc {
#define URTWN_FLAG_CCK_HIPWR 0x01
#define URTWN_DETACHED 0x02
#define URTWN_RUNNING 0x04
#define URTWN_TEMP_MEASURED 0x10
u_int chip;
#define URTWN_CHIP_92C 0x01
@ -180,8 +181,7 @@ struct urtwn_softc {
int8_t ofdm_tx_pwr_diff;
int8_t bw20_tx_pwr_diff;
int avg_pwdb;
int thcal_state;
int thcal_lctemp;
uint8_t thcal_lctemp;
int ntxchains;
int nrxchains;
int ledlink;
@ -203,7 +203,8 @@ struct urtwn_softc {
union urtwn_rom rom;
uint16_t last_rom_addr;
struct callout sc_calib_to;
struct callout sc_watchdog_ch;
struct mtx sc_mtx;
uint32_t keys_bmap;