LinuxKPI: 802.11: sort the fallback to software scan for rtw88
In the special case hardware scan fails to start, we cancel the scan with net80211 and cleanup our part. In that case we now sleep and wait for a wakeup. The wakeup was moved to a different callback function to serve both cases (hw scan cancelled, and hw scan failed). In the very special case the hardware scan fails with a return code of 1, we need to start a software scan. I cannot fully imagine this ever worked well (some rtw88 chipsets are using this). The trouble is that the cancael_scan runs in a taskq in net80211 and by the time we tried to start the new scan, the old one was not fully cleaned up and finished (or could have been restarted in case we enable bgscan). So defer starting the software scan to the taskq as well and it will run once the previous finished. The RTW8821ce I tested with seemed a lot more happy. Sponsored by: The FreeBSD Foundation MFC after: 3 days
This commit is contained in:
@@ -173,6 +173,7 @@ const struct cfg80211_ops linuxkpi_mac80211cfgops = {
|
|||||||
static struct lkpi_sta *lkpi_find_lsta_by_ni(struct lkpi_vif *,
|
static struct lkpi_sta *lkpi_find_lsta_by_ni(struct lkpi_vif *,
|
||||||
struct ieee80211_node *);
|
struct ieee80211_node *);
|
||||||
#endif
|
#endif
|
||||||
|
static void lkpi_sw_scan_task(void *, int);
|
||||||
static void lkpi_80211_txq_tx_one(struct lkpi_sta *, struct mbuf *);
|
static void lkpi_80211_txq_tx_one(struct lkpi_sta *, struct mbuf *);
|
||||||
static void lkpi_80211_txq_task(void *, int);
|
static void lkpi_80211_txq_task(void *, int);
|
||||||
static void lkpi_80211_lhw_rxq_task(void *, int);
|
static void lkpi_80211_lhw_rxq_task(void *, int);
|
||||||
@@ -3856,6 +3857,7 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
|
|||||||
|
|
||||||
lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO);
|
lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO);
|
||||||
mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF);
|
mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF);
|
||||||
|
TASK_INIT(&lvif->sw_scan_task, 0, lkpi_sw_scan_task, lvif);
|
||||||
INIT_LIST_HEAD(&lvif->lsta_list);
|
INIT_LIST_HEAD(&lvif->lsta_list);
|
||||||
lvif->lvif_bss = NULL;
|
lvif->lvif_bss = NULL;
|
||||||
refcount_init(&lvif->nt_unlocked, 0);
|
refcount_init(&lvif->nt_unlocked, 0);
|
||||||
@@ -4094,6 +4096,8 @@ lkpi_ic_vap_delete(struct ieee80211vap *vap)
|
|||||||
/* Clear up per-VIF/VAP sysctls. */
|
/* Clear up per-VIF/VAP sysctls. */
|
||||||
sysctl_ctx_free(&lvif->sysctl_ctx);
|
sysctl_ctx_free(&lvif->sysctl_ctx);
|
||||||
|
|
||||||
|
ieee80211_draintask(ic, &lvif->sw_scan_task);
|
||||||
|
|
||||||
LKPI_80211_LHW_LVIF_LOCK(lhw);
|
LKPI_80211_LHW_LVIF_LOCK(lhw);
|
||||||
TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry);
|
TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry);
|
||||||
LKPI_80211_LHW_LVIF_UNLOCK(lhw);
|
LKPI_80211_LHW_LVIF_UNLOCK(lhw);
|
||||||
@@ -4485,7 +4489,7 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
|
|||||||
if (!is_hw_scan) {
|
if (!is_hw_scan) {
|
||||||
/* If hw_scan is cleared clear FEXT_SCAN_OFFLOAD too. */
|
/* If hw_scan is cleared clear FEXT_SCAN_OFFLOAD too. */
|
||||||
vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;
|
vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;
|
||||||
sw_scan:
|
|
||||||
lvif = VAP_TO_LVIF(vap);
|
lvif = VAP_TO_LVIF(vap);
|
||||||
vif = LVIF_TO_VIF(lvif);
|
vif = LVIF_TO_VIF(lvif);
|
||||||
|
|
||||||
@@ -4498,6 +4502,8 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
|
|||||||
|
|
||||||
lkpi_update_mcast_filter(ic);
|
lkpi_update_mcast_filter(ic);
|
||||||
|
|
||||||
|
TRACE_SCAN(vap->iv_ic, "Starting SW_SCAN: scan_flags %b",
|
||||||
|
lhw->scan_flags, LKPI_LHW_SCAN_BITS);
|
||||||
lkpi_80211_mo_sw_scan_start(hw, vif, vif->addr);
|
lkpi_80211_mo_sw_scan_start(hw, vif, vif->addr);
|
||||||
/* net80211::scan_start() handled PS for us. */
|
/* net80211::scan_start() handled PS for us. */
|
||||||
IMPROVE();
|
IMPROVE();
|
||||||
@@ -4752,6 +4758,9 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
|
|||||||
|
|
||||||
error = lkpi_80211_mo_hw_scan(hw, vif, hw_req);
|
error = lkpi_80211_mo_hw_scan(hw, vif, hw_req);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
|
bool scan_done;
|
||||||
|
int e;
|
||||||
|
|
||||||
TRACE_SCAN(ic, "hw_scan failed; scan_flags %b, error %d",
|
TRACE_SCAN(ic, "hw_scan failed; scan_flags %b, error %d",
|
||||||
lhw->scan_flags, LKPI_LHW_SCAN_BITS, error);
|
lhw->scan_flags, LKPI_LHW_SCAN_BITS, error);
|
||||||
ieee80211_cancel_scan(vap);
|
ieee80211_cancel_scan(vap);
|
||||||
@@ -4770,14 +4779,35 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
|
|||||||
* So we cannot rely on that behaviour and have to check
|
* So we cannot rely on that behaviour and have to check
|
||||||
* and balance between both code paths.
|
* and balance between both code paths.
|
||||||
*/
|
*/
|
||||||
|
e = 0;
|
||||||
|
scan_done = true;
|
||||||
LKPI_80211_LHW_SCAN_LOCK(lhw);
|
LKPI_80211_LHW_SCAN_LOCK(lhw);
|
||||||
if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {
|
if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {
|
||||||
|
|
||||||
free(lhw->hw_req, M_LKPI80211);
|
free(lhw->hw_req, M_LKPI80211);
|
||||||
lhw->hw_req = NULL;
|
lhw->hw_req = NULL;
|
||||||
|
/*
|
||||||
|
* The ieee80211_cancel_scan() above runs in a
|
||||||
|
* taskq and it may take ages for the previous
|
||||||
|
* scan to clear; starting a new one right away
|
||||||
|
* we run into the problem that the old one is
|
||||||
|
* still active.
|
||||||
|
*/
|
||||||
|
e = msleep(lhw, &lhw->scan_mtx, 0, "lhwscanstop", hz);
|
||||||
|
scan_done = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now we can clear running if no one else did.
|
||||||
|
*/
|
||||||
lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
|
lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
|
||||||
}
|
}
|
||||||
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
|
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
|
||||||
lkpi_update_mcast_filter(ic);
|
lkpi_update_mcast_filter(ic);
|
||||||
|
if (!scan_done) {
|
||||||
|
ic_printf(ic, "ERROR: %s: timeout/error to wait "
|
||||||
|
"for ieee80211_cancel_scan: %d\n", __func__, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX-SIGH magic number.
|
* XXX-SIGH magic number.
|
||||||
@@ -4785,33 +4815,59 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
|
|||||||
* not possible. Fall back to sw scan in that case.
|
* not possible. Fall back to sw scan in that case.
|
||||||
*/
|
*/
|
||||||
if (error == 1) {
|
if (error == 1) {
|
||||||
LKPI_80211_LHW_SCAN_LOCK(lhw);
|
|
||||||
lhw->scan_flags &= ~LKPI_LHW_SCAN_HW;
|
|
||||||
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
|
|
||||||
/*
|
/*
|
||||||
* XXX If we clear this now and later a driver
|
* We need to put this into some defered context
|
||||||
* thinks it * can do a hw_scan again, we will
|
* the net80211 scan may not be done yet
|
||||||
* currently not re-enable it?
|
* (ic_flags & IEEE80211_F_SCAN) and we cannot
|
||||||
|
* wait here; if we do scan_curchan_task always
|
||||||
|
* runs after our timeout to finalize the scan.
|
||||||
*/
|
*/
|
||||||
vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;
|
ieee80211_runtask(ic, &lvif->sw_scan_task);
|
||||||
ieee80211_start_scan(vap,
|
return;
|
||||||
IEEE80211_SCAN_ACTIVE |
|
|
||||||
IEEE80211_SCAN_NOPICK |
|
|
||||||
IEEE80211_SCAN_ONCE,
|
|
||||||
IEEE80211_SCAN_FOREVER,
|
|
||||||
ss->ss_mindwell ? ss->ss_mindwell : msecs_to_ticks(20),
|
|
||||||
ss->ss_maxdwell ? ss->ss_maxdwell : msecs_to_ticks(200),
|
|
||||||
vap->iv_des_nssid, vap->iv_des_ssid);
|
|
||||||
goto sw_scan;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ic_printf(ic, "ERROR: %s: hw_scan returned %d\n",
|
ic_printf(ic, "ERROR: %s: hw_scan returned %d\n",
|
||||||
__func__, error);
|
__func__, error);
|
||||||
ieee80211_cancel_scan(vap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lkpi_sw_scan_task(void *arg, int pending __unused)
|
||||||
|
{
|
||||||
|
struct lkpi_hw *lhw;
|
||||||
|
struct lkpi_vif *lvif;
|
||||||
|
struct ieee80211vap *vap;
|
||||||
|
struct ieee80211_scan_state *ss;
|
||||||
|
|
||||||
|
lvif = arg;
|
||||||
|
vap = LVIF_TO_VAP(lvif);
|
||||||
|
lhw = vap->iv_ic->ic_softc;
|
||||||
|
ss = vap->iv_ic->ic_scan;
|
||||||
|
|
||||||
|
LKPI_80211_LHW_SCAN_LOCK(lhw);
|
||||||
|
/*
|
||||||
|
* We will re-enable this at scan_end calling lkpi_enable_hw_scan().
|
||||||
|
* IEEE80211_FEXT_SCAN_OFFLOAD will be cleared by lkpi_ic_scan_start.
|
||||||
|
*/
|
||||||
|
lhw->scan_flags &= ~LKPI_LHW_SCAN_HW;
|
||||||
|
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
|
||||||
|
|
||||||
|
TRACE_SCAN(vap->iv_ic, "Triggering SW_SCAN: pending %d, scan_flags %b",
|
||||||
|
pending, lhw->scan_flags, LKPI_LHW_SCAN_BITS);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This will call ic_scan_start() and we will get into the right path
|
||||||
|
* unless other scans started in between.
|
||||||
|
*/
|
||||||
|
ieee80211_start_scan(vap,
|
||||||
|
IEEE80211_SCAN_ONCE,
|
||||||
|
msecs_to_ticks(10000), /* 10000 ms (=~ 50 chan * 200 ms) */
|
||||||
|
ss->ss_mindwell ? ss->ss_mindwell : msecs_to_ticks(20),
|
||||||
|
ss->ss_maxdwell ? ss->ss_maxdwell : msecs_to_ticks(200),
|
||||||
|
vap->iv_des_nssid, vap->iv_des_ssid);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
lkpi_ic_scan_end(struct ieee80211com *ic)
|
lkpi_ic_scan_end(struct ieee80211com *ic)
|
||||||
{
|
{
|
||||||
@@ -4855,6 +4911,10 @@ lkpi_ic_scan_end(struct ieee80211com *ic)
|
|||||||
* switched to swscan, re-enable hw_scan if available.
|
* switched to swscan, re-enable hw_scan if available.
|
||||||
*/
|
*/
|
||||||
lkpi_enable_hw_scan(lhw);
|
lkpi_enable_hw_scan(lhw);
|
||||||
|
|
||||||
|
LKPI_80211_LHW_SCAN_LOCK(lhw);
|
||||||
|
wakeup(lhw);
|
||||||
|
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -6973,7 +7033,8 @@ linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *hw,
|
|||||||
free(lhw->hw_req, M_LKPI80211);
|
free(lhw->hw_req, M_LKPI80211);
|
||||||
lhw->hw_req = NULL;
|
lhw->hw_req = NULL;
|
||||||
lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
|
lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
|
||||||
wakeup(lhw);
|
/* The wakeup(lhw) will be called from lkpi_ic_scan_end(). */
|
||||||
|
/* wakeup(lhw); */
|
||||||
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
|
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ struct lkpi_vif {
|
|||||||
struct mbuf *, int,
|
struct mbuf *, int,
|
||||||
const struct ieee80211_rx_stats *,
|
const struct ieee80211_rx_stats *,
|
||||||
int, int);
|
int, int);
|
||||||
|
struct task sw_scan_task;
|
||||||
|
|
||||||
struct list_head lsta_list;
|
struct list_head lsta_list;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user