From 56d11693f21ce78aa64975442e893ee37fd8ad0e Mon Sep 17 00:00:00 2001 From: stsp Date: Sun, 10 May 2015 19:40:56 +0000 Subject: [PATCH] Fix urtwn(4) 11b performance for RTL8188EU devices. With 11b APs the firmware retries excessively unless we force it into 11b-only mode instead of mixed b/g. Perhaps a firmware bug, perhaps a bug in our code elsewhere. For now, this makes it work. ok kettenis --- sys/dev/usb/if_urtwn.c | 61 +++++++++++++++++++++++++++++++++------ sys/dev/usb/if_urtwnreg.h | 5 ++-- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/sys/dev/usb/if_urtwn.c b/sys/dev/usb/if_urtwn.c index 65f9e4c1ad6..81f811c36a6 100644 --- a/sys/dev/usb/if_urtwn.c +++ b/sys/dev/usb/if_urtwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_urtwn.c,v 1.45 2015/05/10 15:10:46 stsp Exp $ */ +/* $OpenBSD: if_urtwn.c,v 1.46 2015/05/10 19:40:56 stsp Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini @@ -184,6 +184,10 @@ void urtwn_read_rom(struct urtwn_softc *); void urtwn_r88e_read_rom(struct urtwn_softc *); int urtwn_media_change(struct ifnet *); int urtwn_ra_init(struct urtwn_softc *); +int urtwn_r92c_ra_init(struct urtwn_softc *, u_int8_t, u_int32_t, + int, uint32_t, int); +int urtwn_r88e_ra_init(struct urtwn_softc *, u_int8_t, u_int32_t, + int, uint32_t, int); void urtwn_tsf_sync_enable(struct urtwn_softc *); void urtwn_set_led(struct urtwn_softc *, int, int); void urtwn_calib_to(void *); @@ -1083,7 +1087,6 @@ urtwn_ra_init(struct urtwn_softc *sc) struct ieee80211com *ic = &sc->sc_ic; struct ieee80211_node *ni = ic->ic_bss; struct ieee80211_rateset *rs = &ni->ni_rates; - struct r92c_fw_cmd_macid_cfg cmd; uint32_t rates, basicrates; uint8_t mode; int maxrate, maxbasicrate, error, i, j; @@ -1114,6 +1117,24 @@ urtwn_ra_init(struct urtwn_softc *sc) DPRINTF(("mode=0x%x rates=0x%08x, basicrates=0x%08x\n", mode, rates, basicrates)); + if (sc->chip & URTWN_CHIP_88E) + error = urtwn_r88e_ra_init(sc, mode, rates, maxrate, + basicrates, maxbasicrate); + else + error = urtwn_r92c_ra_init(sc, mode, rates, maxrate, + basicrates, maxbasicrate); + + /* Indicate highest supported rate. */ + ni->ni_txrate = rs->rs_nrates - 1; + return (error); +} + +int urtwn_r92c_ra_init(struct urtwn_softc *sc, u_int8_t mode, u_int32_t rates, + int maxrate, uint32_t basicrates, int maxbasicrate) +{ + struct r92c_fw_cmd_macid_cfg cmd; + int error; + /* Set rates mask for group addressed frames. */ cmd.macid = URTWN_MACID_BC | URTWN_MACID_VALID; cmd.mask = htole32(mode << 28 | basicrates); @@ -1142,8 +1163,28 @@ urtwn_ra_init(struct urtwn_softc *sc) urtwn_write_1(sc, R92C_INIDATA_RATE_SEL(URTWN_MACID_BSS), maxrate); - /* Indicate highest supported rate. */ - ni->ni_txrate = rs->rs_nrates - 1; + return (0); +} + +int +urtwn_r88e_ra_init(struct urtwn_softc *sc, u_int8_t mode, u_int32_t rates, + int maxrate, uint32_t basicrates, int maxbasicrate) +{ + u_int32_t reg; + + urtwn_write_1(sc, R92C_INIRTS_RATE_SEL, maxbasicrate); + + reg = urtwn_read_4(sc, R92C_RRSR); + reg = RW(reg, R92C_RRSR_RATE_BITMAP, rates); + urtwn_write_4(sc, R92C_RRSR, reg); + + /* + * Workaround for performance problems with firmware rate adaptation: + * If the AP only supports 11b rates, disable mixed B/G mode. + */ + if (mode != R92C_RAID_11B && maxrate <= 3 /* 11M */) + sc->sc_flags |= URTWN_FLAG_FORCE_RAID_11B; + return (0); } @@ -1312,6 +1353,9 @@ urtwn_newstate_cb(struct urtwn_softc *sc, void *arg) urtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317); urtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320); urtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444); + + /* Disable 11b-only AP workaround (see urtwn_r88e_ra_init). */ + sc->sc_flags &= ~URTWN_FLAG_FORCE_RAID_11B; } switch (cmd->state) { case IEEE80211_S_INIT: @@ -1417,10 +1461,8 @@ urtwn_newstate_cb(struct urtwn_softc *sc, void *arg) urtwn_write_1(sc, R92C_T2T_SIFS + 1, 10); /* Intialize rate adaptation. */ - if (sc->chip & URTWN_CHIP_88E) - ni->ni_txrate = ni->ni_rates.rs_nrates-1; - else - urtwn_ra_init(sc); + urtwn_ra_init(sc); + /* Turn link LED on. */ urtwn_set_led(sc, URTWN_LED_LINK, 1); @@ -1981,7 +2023,8 @@ urtwn_tx(struct urtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) #endif if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && type == IEEE80211_FC0_TYPE_DATA) { - if (ic->ic_curmode == IEEE80211_MODE_11B) + if (ic->ic_curmode == IEEE80211_MODE_11B || + (sc->sc_flags & URTWN_FLAG_FORCE_RAID_11B)) raid = R92C_RAID_11B; else raid = R92C_RAID_11BG; diff --git a/sys/dev/usb/if_urtwnreg.h b/sys/dev/usb/if_urtwnreg.h index edbad3d898c..8d46a6e6a51 100644 --- a/sys/dev/usb/if_urtwnreg.h +++ b/sys/dev/usb/if_urtwnreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_urtwnreg.h,v 1.5 2015/05/04 11:46:29 stsp Exp $ */ +/* $OpenBSD: if_urtwnreg.h,v 1.6 2015/05/10 19:40:56 stsp Exp $ */ /*- * Copyright (c) 2010 Damien Bergamini @@ -1153,7 +1153,8 @@ struct urtwn_softc { struct usbd_pipe *tx_pipe[R92C_MAX_EPOUT]; int ac2idx[EDCA_NUM_AC]; u_int sc_flags; -#define URTWN_FLAG_CCK_HIPWR 0x01 +#define URTWN_FLAG_CCK_HIPWR 0x01 +#define URTWN_FLAG_FORCE_RAID_11B 0x02 u_int chip; #define URTWN_CHIP_92C 0x01 -- 2.20.1