mirror of
https://github.com/shenmintao/aic8800d80.git
synced 2026-09-26 17:44:16 +00:00
fix: avoid spurious WARN in rwnx_close during USB teardown
Unplugging the adapter while the interface is connecting or disconnecting prints a spurious kernel warning: rwnx_close connecting or disconnecting, not finish WARNING: CPU: ... rwnx_close+0x96/0x3f0 [aic8800_fdrv] rwnx_close() waits up to 4 seconds for drv_conn_state to leave CONNECTING/DISCONNECTING, but that state only changes when the firmware answers the pending request. During USB teardown the bus is already down by the time rwnx_close() runs, and rwnx_send_msg() drops the message and returns 0, so the confirmation never arrives. The wait therefore always runs its full timeout and fires WARN_ON(1) for a condition that cannot be satisfied. Skip both waits when the bus is down, using the same condition already used a few lines below in the vif_started path. This removes the wait itself, not just the warning: previously teardown blocked for up to 4 (and 2) seconds waiting on a dead bus. Reproduced on 6.12.107+deb13 with an AIC8800D80: unplug while connected fires the warning on main and produces none with this change, while the replug path still re-enumerates and restores Wi-Fi and Bluetooth. Builds on 5.15.0-191, 6.1.0-53, 6.8.0-139, 6.11.0-8 and 6.12.107+deb13 with no new warnings.
This commit is contained in:
@@ -1518,18 +1518,30 @@ static int rwnx_close(struct net_device *dev)
|
||||
|
||||
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||
|
||||
test_counter = waiting_counter;
|
||||
while(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING||
|
||||
atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTING){
|
||||
AICWFDBG(LOGDEBUG, "%s wifi is connecting or disconnecting, waiting 200ms for state to stable\r\n", __func__);
|
||||
msleep(200);
|
||||
test_counter--;
|
||||
if(test_counter == 0){
|
||||
AICWFDBG(LOGERROR, "%s connecting or disconnecting, not finish\r\n", __func__);
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* A CONNECTING/DISCONNECTING state is only left when the firmware answers
|
||||
* the pending request. If the bus is already down the answer can never
|
||||
* arrive: rwnx_send_msg() silently drops the message and returns 0
|
||||
* (rwnx_msg_tx.c), so the wait below would always run its full timeout and
|
||||
* fire the spurious WARN_ON() during USB teardown. Skip the wait when the
|
||||
* bus is down, using the same condition the vif_started path uses below.
|
||||
*/
|
||||
if (bus_if &&
|
||||
(usbdev == NULL || (usbdev->bus_if->state != BUS_DOWN_ST &&
|
||||
usbdev->state != USB_DOWN_ST))) {
|
||||
test_counter = waiting_counter;
|
||||
while(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING||
|
||||
atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTING){
|
||||
AICWFDBG(LOGDEBUG, "%s wifi is connecting or disconnecting, waiting 200ms for state to stable\r\n", __func__);
|
||||
msleep(200);
|
||||
test_counter--;
|
||||
if(test_counter == 0){
|
||||
AICWFDBG(LOGERROR, "%s connecting or disconnecting, not finish\r\n", __func__);
|
||||
WARN_ON(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT)
|
||||
if (rwnx_hw->scanning){
|
||||
@@ -1587,13 +1599,18 @@ static int rwnx_close(struct net_device *dev)
|
||||
test_counter = waiting_counter;
|
||||
if(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTED){
|
||||
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, RWNX_DRV_STATUS_DISCONNECTING);
|
||||
rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, 3);
|
||||
while (atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING) {
|
||||
AICWFDBG(LOGDEBUG, "%s wifi is disconnecting, waiting 100ms for state to stable\r\n", __func__);
|
||||
msleep(100);
|
||||
test_counter--;
|
||||
if (test_counter ==0)
|
||||
break;
|
||||
/* Same reasoning as above: with the bus down the disconnect
|
||||
* confirmation cannot arrive, so do not wait for it. */
|
||||
if (usbdev->bus_if->state != BUS_DOWN_ST &&
|
||||
usbdev->state != USB_DOWN_ST) {
|
||||
rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, 3);
|
||||
while (atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING) {
|
||||
AICWFDBG(LOGDEBUG, "%s wifi is disconnecting, waiting 100ms for state to stable\r\n", __func__);
|
||||
msleep(100);
|
||||
test_counter--;
|
||||
if (test_counter ==0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user