Several paths request an FLR asynchronously, including S3/S4 resume, resume recovery, HCI reset, and hardware-error recovery. A queued reset may run before the PM callback releases the PCI device lock, causing pci_try_reset_function() to return -EAGAIN without attempting the FLR. Use pci_reset_function() so reset work waits for the device lock and performs the FLR once the PM callback releases it. If the reset fails, clear the recovery in-progress flag so a later reset request can try again. Fixes: 9c36951474d8 ("Bluetooth: btintel_pcie: Refactor FLR to use device_reprobe()") Signed-off-by: Ravindra --- drivers/bluetooth/btintel_pcie.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 3a555aa50c87..92b91f058fce 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -3745,13 +3745,10 @@ static int btintel_pcie_perform_flr(struct btintel_pcie_data *data) struct pci_dev *pdev = data->pdev; int err; - /* pci_try_reset_function() avoids the device_lock ABBA against - * btintel_pcie_remove(): .remove() runs with device_lock held and - * then waits for this work via disable_work_sync(); the blocking - * pci_reset_function() would deadlock by trying to re-acquire - * device_lock here. + /* Reset work runs asynchronously, so it can wait for the device lock + * held by a PM callback to be released. */ - err = pci_try_reset_function(pdev); + err = pci_reset_function(pdev); if (err) { BT_ERR("Failed resetting the pcie device (%d)", err); return err; @@ -3817,6 +3814,7 @@ static void btintel_pcie_reset_work(struct work_struct *wk) enable_work(&data->hwexp_work); enable_work(&data->fwtrigger_work); enable_work(&data->mbox_work); + clear_bit(BTINTEL_PCIE_RECOVERY_IN_PROGRESS, &data->flags); } out: @@ -3841,10 +3839,9 @@ static void btintel_pcie_reset_work(struct work_struct *wk) * in-flight one (whose recovery will reinitialize the device * regardless of the dropped trigger's variant). * - * The bit is cleared only by .remove() / re-probe via fresh devm - * allocation, which is the intended one-shot semantics: a reset - * tears down and re-probes 'data', so there is no "in-flight" - * reset to follow up after device_reprobe() succeeds. + * A successful reset clears the bit through .remove() / re-probe via + * fresh devm allocation. A failed FLR clears it in reset_work so a + * later request can retry; there is no in-flight reset after failure. */ static void btintel_pcie_request_reset(struct btintel_pcie_data *data, enum btintel_pcie_reset_type type) -- 2.43.0