crypto: qat - fix use of destroyed vf2pf_lock on VF restart

adf_dev_stop_async() sends the RESTARTING_COMPLETE message after
adf_dev_down() has returned, but adf_dev_down() already destroyed the
lock that message takes.

Both run in sequence in the same worker, so every PF restart locks a
destroyed mutex. With CONFIG_DEBUG_MUTEXES on a dh895xcc with 32 host-bound
VFs this trips on the first PF reset:

  DEBUG_LOCKS_WARN_ON(lock->magic != lock)
  WARNING: kernel/locking/mutex.c:159 at mutex_lock+0x171/0x1c0
  Workqueue: adf_vf_stop_wq adf_dev_stop_async [intel_qat]
  Call Trace:
   adf_gen2_pfvf_send+0x210/0x530 [intel_qat]
   adf_vf2pf_notify_restart_complete+0x55/0x80 [intel_qat]
   adf_dev_stop_async+0xdb/0x140 [intel_qat]

The notification cannot move before adf_dev_down(): the PF waits for it
before its own reset and the VF must tear down its rings first.

vf2pf_lock protects the VF2PF CSR and is unrelated to the PF2VF bottom half
it is initialised alongside. Tie its lifetime to the accel device, next to
state_lock in adf_devmgr_add_dev()/adf_devmgr_rm_dev(), so it stays valid
for messages sent outside the device up/down cycle. It is only touched for
VFs, which set is_vf before adf_devmgr_add_dev() and keep it set until
adf_devmgr_rm_dev().

Fixes: 6f1b523634 ("crypto: qat - fix recovery flow for VFs")
Cc: stable@vger.kernel.org
Signed-off-by: Ahsan Atta <ahsan.atta@intel.com>
Reviewed-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
Ahsan Atta 2026-10-06 16:06:48 +01:00 committed by Herbert Xu
parent 4ad7c1bd5f
commit 4921634ac0
2 changed files with 8 additions and 2 deletions

View File

@ -138,6 +138,12 @@ int adf_devmgr_add_dev(struct adf_accel_dev *accel_dev,
mutex_lock(&table_lock);
atomic_set(&accel_dev->ref_count, 0);
mutex_init(&accel_dev->state_lock);
/*
* The VF2PF lock is used to send messages to the PF outside of the
* device up/down cycle, so it must live as long as the accel device.
*/
if (accel_dev->is_vf)
mutex_init(&accel_dev->vf.vf2pf_lock);
/* PF on host or VF on guest - optimized to remove redundant is_vf */
if (!accel_dev->is_vf || !pf) {
@ -257,6 +263,8 @@ void adf_devmgr_rm_dev(struct adf_accel_dev *accel_dev,
}
}
unlock:
if (accel_dev->is_vf)
mutex_destroy(&accel_dev->vf.vf2pf_lock);
mutex_destroy(&accel_dev->state_lock);
list_del(&accel_dev->list);
mutex_unlock(&table_lock);

View File

@ -118,7 +118,6 @@ static int adf_setup_pf2vf_bh(struct adf_accel_dev *accel_dev)
tasklet_init(&accel_dev->vf.pf2vf_bh_tasklet,
(void *)adf_pf2vf_bh_handler, (unsigned long)accel_dev);
mutex_init(&accel_dev->vf.vf2pf_lock);
return 0;
}
@ -126,7 +125,6 @@ static void adf_cleanup_pf2vf_bh(struct adf_accel_dev *accel_dev)
{
tasklet_disable(&accel_dev->vf.pf2vf_bh_tasklet);
tasklet_kill(&accel_dev->vf.pf2vf_bh_tasklet);
mutex_destroy(&accel_dev->vf.vf2pf_lock);
}
static irqreturn_t adf_isr(int irq, void *privdata)