From c83aa81d394b7f1e850bf698977985c8e00e747d Mon Sep 17 00:00:00 2001
From: Cy Schubert <cy@FreeBSD.org>
Date: Mon, 9 Jan 2023 12:54:00 -0800
Subject: [PATCH] rtwn: Fix RTL8188EU & RTL8192EU cannot associate in STA mode
On some systems RTL8188EU and RTL8192EU will fail to associate in STA
mode while others it will work fine. On the systems RTL8192EU fails to
associate in STA mode, it works perfectly fine in AP mode. This points
to a USB timing issue when selecting a channel while in STA mode.
While here fix RTL8192EU power off and power on hang for the same reason.
PR: 247528
Reported by: Mc James <realmcjames@protonmail.ch>,
rkoberman@gmail.com, many
Reviewed by:
Tested by: titus@edc.ro
Approved by:
Concept by: titus@edc.ro
MFC after:
Relnotes:
Differential Revision:
---
sys/dev/rtwn/rtl8188e/r88e_reg.h | 1 +
sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c | 2 ++
sys/dev/rtwn/rtl8188e/usb/r88eu_init.c | 15 +++++++++++-
sys/dev/rtwn/rtl8192c/r92c_chan.c | 8 ++++++
sys/dev/rtwn/rtl8192c/r92c_reg.h | 2 ++
sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c | 1 +
sys/dev/rtwn/rtl8192e/r92e_chan.c | 6 +++++
sys/dev/rtwn/rtl8192e/r92e_init.c | 31 ++++++++++++++++++++++--
sys/dev/rtwn/rtl8192e/r92e_reg.h | 1 +
sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c | 1 +
sys/dev/rtwn/usb/rtwn_usb_attach.c | 5 ++++
sys/dev/rtwn/usb/rtwn_usb_reg.c | 4 +++
sys/dev/rtwn/usb/rtwn_usb_var.h | 4 +++
13 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/sys/dev/rtwn/rtl8188e/r88e_reg.h b/sys/dev/rtwn/rtl8188e/r88e_reg.h
index d9f236cddbb6..bed88c4604f6 100644
--- a/sys/dev/rtwn/rtl8188e/r88e_reg.h
+++ b/sys/dev/rtwn/rtl8188e/r88e_reg.h
@@ -121,5 +121,6 @@
/* Bits for R88E_XCK_OUT_CTRL. */
#define R88E_XCK_OUT_CTRL_EN 1
+#define R88E_USB_DELAY_US_DEF 1000
#endif /* R88E_REG_H */
diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
index 2d4713e92bd2..672cdb79f175 100644
--- a/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
+++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_attach.c
@@ -58,6 +58,7 @@
#include <dev/rtwn/rtl8188e/r88e_rom_image.h> /* for 'macaddr' field */
#include <dev/rtwn/rtl8188e/usb/r88eu.h>
+#include <dev/rtwn/rtl8188e/r88e_reg.h>
static struct rtwn_r88e_txpwr r88e_txpwr;
@@ -122,6 +123,7 @@ r88eu_attach(struct rtwn_usb_softc *uc)
/* USB part. */
uc->uc_align_rx = r92cu_align_rx;
uc->tx_agg_desc_num = 6;
+ uc->uc_delay_us = R88E_USB_DELAY_US_DEF;
/* Common part. */
sc->sc_flags = RTWN_FLAG_EXT_HDR;
diff --git a/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c b/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
index f4f936493cda..510a820b71ad 100644
--- a/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
+++ b/sys/dev/rtwn/rtl8188e/usb/r88eu_init.c
@@ -48,6 +48,8 @@
#include <dev/rtwn/rtl8192c/r92c.h>
#include <dev/rtwn/rtl8192c/r92c_var.h>
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
#include <dev/rtwn/rtl8188e/usb/r88eu.h>
#include <dev/rtwn/rtl8188e/usb/r88eu_reg.h>
@@ -76,8 +78,12 @@ r88eu_power_on(struct rtwn_softc *sc)
if (res != 0) \
return (EIO); \
} while(0)
+ struct rtwn_usb_softc *uc;
int ntries;
+ if ((uc = RTWN_USB_SOFTC(sc)) != NULL)
+ uc->uc_write_delay = 1;
+
/* Wait for power ready bit. */
for (ntries = 0; ntries < 5000; ntries++) {
if (rtwn_read_4(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_SUS_HOST)
@@ -85,6 +91,8 @@ r88eu_power_on(struct rtwn_softc *sc)
rtwn_delay(sc, 10);
}
if (ntries == 5000) {
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
device_printf(sc->sc_dev,
"timeout waiting for chip power up\n");
return (ETIMEDOUT);
@@ -112,7 +120,10 @@ r88eu_power_on(struct rtwn_softc *sc)
break;
rtwn_delay(sc, 10);
}
- if (ntries == 5000)
+ if (ntries == 5000) {
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
+ }
return (ETIMEDOUT);
/* Enable LDO normal mode. */
@@ -128,6 +139,8 @@ r88eu_power_on(struct rtwn_softc *sc)
((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) |
R92C_CR_CALTMR_EN));
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
return (0);
#undef RTWN_CHK
}
diff --git a/sys/dev/rtwn/rtl8192c/r92c_chan.c b/sys/dev/rtwn/rtl8192c/r92c_chan.c
index f93159a3c94e..f22916b312f2 100644
--- a/sys/dev/rtwn/rtl8192c/r92c_chan.c
+++ b/sys/dev/rtwn/rtl8192c/r92c_chan.c
@@ -52,6 +52,7 @@
#include <dev/rtwn/rtl8192c/r92c_priv.h>
#include <dev/rtwn/rtl8192c/r92c_reg.h>
#include <dev/rtwn/rtl8192c/r92c_var.h>
+#include <dev/rtwn/usb/rtwn_usb_var.h>
void
r92c_dump_txpower(struct rtwn_softc *sc, int chain,
@@ -361,9 +362,13 @@ void
r92c_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c)
{
struct r92c_softc *rs = sc->sc_priv;
+ struct rtwn_usb_softc *uc;
u_int chan;
int i;
+ if ((uc = RTWN_USB_SOFTC(sc)) != NULL)
+ uc->uc_write_delay = 1;
+
chan = rtwn_chan2centieee(c);
/* Set Tx power for this new channel. */
@@ -377,6 +382,9 @@ r92c_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c)
r92c_set_bw40(sc, chan, IEEE80211_IS_CHAN_HT40U(c));
else
rtwn_r92c_set_bw20(sc, chan);
+
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
}
void
diff --git a/sys/dev/rtwn/rtl8192c/r92c_reg.h b/sys/dev/rtwn/rtl8192c/r92c_reg.h
index e6d232a88834..bc75f5444d9c 100644
--- a/sys/dev/rtwn/rtl8192c/r92c_reg.h
+++ b/sys/dev/rtwn/rtl8192c/r92c_reg.h
@@ -926,4 +926,6 @@
#define R92C_RF_T_METER_VAL_M 0x1f
#define R92C_RF_T_METER_VAL_S 0
+#define R92C_USB_DELAY_US_DEF 1000
+
#endif /* R92C_REG_H */
diff --git a/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c b/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
index cd350c7fcd8a..3ed581fe3634 100644
--- a/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
+++ b/sys/dev/rtwn/rtl8192c/usb/r92cu_attach.c
@@ -151,6 +151,7 @@ r92cu_attach(struct rtwn_usb_softc *uc)
/* USB part. */
uc->uc_align_rx = r92cu_align_rx;
uc->tx_agg_desc_num = 6;
+ uc->uc_delay_us = R92C_USB_DELAY_US_DEF;
/* Common part. */
sc->sc_flags = RTWN_FLAG_CAM_FIXED;
diff --git a/sys/dev/rtwn/rtl8192e/r92e_chan.c b/sys/dev/rtwn/rtl8192e/r92e_chan.c
index 4c7121a80c89..b6e208220c3a 100644
--- a/sys/dev/rtwn/rtl8192e/r92e_chan.c
+++ b/sys/dev/rtwn/rtl8192e/r92e_chan.c
@@ -60,6 +60,7 @@
#include <dev/rtwn/rtl8192e/r92e.h>
#include <dev/rtwn/rtl8192e/r92e_reg.h>
#include <dev/rtwn/rtl8192e/r92e_var.h>
+#include <dev/rtwn/usb/rtwn_usb_var.h>
static int
r92e_get_power_group(struct rtwn_softc *sc, struct ieee80211_channel *c)
@@ -235,9 +236,12 @@ void
r92e_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c)
{
struct r92e_softc *rs = sc->sc_priv;
+ struct rtwn_usb_softc *uc;
u_int chan;
int i;
+ if ((uc = RTWN_USB_SOFTC(sc)) != NULL)
+ uc->uc_write_delay = 1;
chan = rtwn_chan2centieee(c);
for (i = 0; i < sc->nrxchains; i++) {
@@ -252,4 +256,6 @@ r92e_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c)
/* Set Tx power for this new channel. */
r92e_set_txpower(sc, c);
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
}
diff --git a/sys/dev/rtwn/rtl8192e/r92e_init.c b/sys/dev/rtwn/rtl8192e/r92e_init.c
index 925221bdabb1..11c51df63ade 100644
--- a/sys/dev/rtwn/rtl8192e/r92e_init.c
+++ b/sys/dev/rtwn/rtl8192e/r92e_init.c
@@ -53,6 +53,8 @@
#include <dev/rtwn/if_rtwn_debug.h>
+#include <dev/rtwn/usb/rtwn_usb_var.h>
+
#include <dev/rtwn/rtl8192c/r92c.h>
#include <dev/rtwn/rtl8192e/r92e.h>
@@ -224,8 +226,12 @@ r92e_power_on(struct rtwn_softc *sc)
if (res != 0) \
return (EIO); \
} while(0)
+ struct rtwn_usb_softc *uc;
int ntries;
+ if ((uc = RTWN_USB_SOFTC(sc)) != NULL)
+ uc->uc_write_delay = 1;
+
if (rtwn_read_4(sc, R92C_SYS_CFG) & R92C_SYS_CFG_TRP_BT_EN)
RTWN_CHK(rtwn_write_1(sc, R92C_LDO_SWR_CTRL, 0xc3));
else {
@@ -252,6 +258,8 @@ r92e_power_on(struct rtwn_softc *sc)
rtwn_delay(sc, 10);
}
if (ntries == 5000) {
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
device_printf(sc->sc_dev,
"timeout waiting for chip power up\n");
return (ETIMEDOUT);
@@ -269,8 +277,11 @@ r92e_power_on(struct rtwn_softc *sc)
break;
rtwn_delay(sc, 10);
}
- if (ntries == 5000)
+ if (ntries == 5000) {
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
return (ETIMEDOUT);
+ }
/* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
RTWN_CHK(rtwn_write_2(sc, R92C_CR, 0));
@@ -281,18 +292,27 @@ r92e_power_on(struct rtwn_softc *sc)
((sc->sc_hwcrypto != RTWN_CRYPTO_SW) ? R92C_CR_ENSEC : 0) |
R92C_CR_CALTMR_EN));
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
return (0);
}
void
r92e_power_off(struct rtwn_softc *sc)
{
+ struct rtwn_usb_softc *uc;
int error, ntries;
+ if ((uc = RTWN_USB_SOFTC(sc)) != NULL)
+ uc->uc_write_delay = 1;
+
/* Stop Rx. */
error = rtwn_write_1(sc, R92C_CR, 0);
- if (error == ENXIO) /* hardware gone */
+ if (error == ENXIO) { /* hardware gone */
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
return;
+ }
/* Move card to Low Power state. */
/* Block all Tx queues. */
@@ -306,6 +326,8 @@ r92e_power_off(struct rtwn_softc *sc)
rtwn_delay(sc, 10);
}
if (ntries == 5000) {
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
device_printf(sc->sc_dev, "%s: failed to block Tx queues\n",
__func__);
return;
@@ -363,6 +385,8 @@ r92e_power_off(struct rtwn_softc *sc)
rtwn_delay(sc, 10);
}
if (ntries == 5000) {
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
device_printf(sc->sc_dev, "%s: could not turn off MAC\n",
__func__);
return;
@@ -385,4 +409,7 @@ r92e_power_off(struct rtwn_softc *sc)
/* Enable SW LPS. */
rtwn_setbits_1_shift(sc, R92C_APS_FSMCO, 0,
R92C_APS_FSMCO_APFM_RSM, 1);
+
+ if (uc != NULL)
+ uc->uc_write_delay = 0;
}
diff --git a/sys/dev/rtwn/rtl8192e/r92e_reg.h b/sys/dev/rtwn/rtl8192e/r92e_reg.h
index 5106bcf9d5f0..edcc2fcb2d57 100644
--- a/sys/dev/rtwn/rtl8192e/r92e_reg.h
+++ b/sys/dev/rtwn/rtl8192e/r92e_reg.h
@@ -41,5 +41,6 @@
/* Bits for R92E_AFE_XTAL_CTRL. */
#define R92E_AFE_XTAL_CTRL_ADDR_M 0x00fff000
#define R92E_AFE_XTAL_CTRL_ADDR_S 12
+#define R92E_USB_DELAY_US_DEF 1000
#endif /* R92E_REG_H */
diff --git a/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c b/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c
index a11a6bb79c5d..35741e58a11e 100644
--- a/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c
+++ b/sys/dev/rtwn/rtl8192e/usb/r92eu_attach.c
@@ -100,6 +100,7 @@ r92eu_attach(struct rtwn_usb_softc *uc)
/* USB part. */
uc->uc_align_rx = r12au_align_rx;
uc->tx_agg_desc_num = 3;
+ uc->uc_delay_us = R92E_USB_DELAY_US_DEF;
/* Common part. */
sc->sc_flags = RTWN_FLAG_EXT_HDR;
diff --git a/sys/dev/rtwn/usb/rtwn_usb_attach.c b/sys/dev/rtwn/usb/rtwn_usb_attach.c
index 4958939a768a..30d4da75cf8f 100644
--- a/sys/dev/rtwn/usb/rtwn_usb_attach.c
+++ b/sys/dev/rtwn/usb/rtwn_usb_attach.c
@@ -377,6 +377,11 @@ rtwn_usb_sysctlattach(struct rtwn_softc *sc)
uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MIN;
if (uc->uc_rx_buf_size > RTWN_USB_RXBUFSZ_MAX)
uc->uc_rx_buf_size = RTWN_USB_RXBUFSZ_MAX;
+
+ uc->uc_delay_us = RTWN_USB_DELAY_US_DEF;
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "delay_us", CTLFLAG_RWTUN, &uc->uc_delay_us,
+ uc->uc_delay_us, "RTWN USB set channel delay microseconds");
}
static int
diff --git a/sys/dev/rtwn/usb/rtwn_usb_reg.c b/sys/dev/rtwn/usb/rtwn_usb_reg.c
index 5a992379e248..ba178b1265c4 100644
--- a/sys/dev/rtwn/usb/rtwn_usb_reg.c
+++ b/sys/dev/rtwn/usb/rtwn_usb_reg.c
@@ -88,12 +88,16 @@ rtwn_usb_write_region_1(struct rtwn_softc *sc, uint16_t addr, uint8_t *buf,
int len)
{
usb_device_request_t req;
+ struct rtwn_usb_softc *uc;
req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
req.bRequest = R92C_REQ_REGS;
USETW(req.wValue, addr);
USETW(req.wIndex, 0);
USETW(req.wLength, len);
+ uc = RTWN_USB_SOFTC(sc);
+ if (uc->uc_write_delay == 1)
+ (sc->sc_delay)(sc,uc->uc_delay_us);
return (rtwn_do_request(sc, &req, buf));
}
diff --git a/sys/dev/rtwn/usb/rtwn_usb_var.h b/sys/dev/rtwn/usb/rtwn_usb_var.h
index 27cd2b4e2762..2ff0ba852eed 100644
--- a/sys/dev/rtwn/usb/rtwn_usb_var.h
+++ b/sys/dev/rtwn/usb/rtwn_usb_var.h
@@ -27,6 +27,7 @@
#define RTWN_USB_RXBUFSZ_DEF (24)
#define RTWN_USB_RXBUFSZ_MAX (64)
#define RTWN_USB_TXBUFSZ (16 * 1024)
+#define RTWN_USB_DELAY_US_DEF 0
#define RTWN_IFACE_INDEX 0
@@ -82,6 +83,9 @@ struct rtwn_usb_softc {
int tx_agg_desc_num;
uint8_t wme2qid[4];
+
+ int uc_delay_us;
+ int uc_write_delay;
};
#define RTWN_USB_SOFTC(sc) ((struct rtwn_usb_softc *)(sc))
--
2.47.1