Commit 8af4a436 authored by Ahsan Atta's avatar Ahsan Atta Committed by Herbert Xu

crypto: qat - flush vf workqueue at driver removal

There is a race condition during shutdown in adf_disable_sriov() where
both the PF and the VF drivers are loaded on the host system.
The PF notifies a VF with a "RESTARTING" message due to which the VF
starts an asynchronous worker to stop and shutdown itself.
At the same time the PF calls pci_disable_sriov() which invokes the
remove() routine on the VF device driver triggering the shutdown flow
again.

This change fixes the problem by ensuring that the VF flushes the worker
that performs stop()/shutdown() before these two functions are called in
the remove(). To make sure that no additional PV/VF messages are
processed by the VF, interrupts are disabled before flushing the
workqueue.
Signed-off-by: default avatarAhsan Atta <ahsan.atta@intel.com>
Co-developed-by: default avatarGiovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: default avatarGiovanni Cabiddu <giovanni.cabiddu@intel.com>
Reviewed-by: default avatarFiona Trahe <fiona.trahe@intel.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent e6dac5ea
...@@ -211,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev) ...@@ -211,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n"); pr_err("QAT: Driver removal failed\n");
return; return;
} }
adf_flush_vf_wq(accel_dev);
adf_dev_stop(accel_dev); adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev); adf_dev_shutdown(accel_dev);
adf_cleanup_accel(accel_dev); adf_cleanup_accel(accel_dev);
......
...@@ -211,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev) ...@@ -211,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n"); pr_err("QAT: Driver removal failed\n");
return; return;
} }
adf_flush_vf_wq(accel_dev);
adf_dev_stop(accel_dev); adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev); adf_dev_shutdown(accel_dev);
adf_cleanup_accel(accel_dev); adf_cleanup_accel(accel_dev);
......
...@@ -207,6 +207,7 @@ int adf_init_pf_wq(void); ...@@ -207,6 +207,7 @@ int adf_init_pf_wq(void);
void adf_exit_pf_wq(void); void adf_exit_pf_wq(void);
int adf_init_vf_wq(void); int adf_init_vf_wq(void);
void adf_exit_vf_wq(void); void adf_exit_vf_wq(void);
void adf_flush_vf_wq(struct adf_accel_dev *accel_dev);
#else #else
#define adf_sriov_configure NULL #define adf_sriov_configure NULL
...@@ -249,5 +250,9 @@ static inline void adf_exit_vf_wq(void) ...@@ -249,5 +250,9 @@ static inline void adf_exit_vf_wq(void)
{ {
} }
static inline void adf_flush_vf_wq(struct adf_accel_dev *accel_dev)
{
}
#endif #endif
#endif #endif
...@@ -48,6 +48,7 @@ void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) ...@@ -48,6 +48,7 @@ void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev)
ADF_CSR_WR(pmisc_bar_addr, ADF_VINTMSK_OFFSET, 0x2); ADF_CSR_WR(pmisc_bar_addr, ADF_VINTMSK_OFFSET, 0x2);
} }
EXPORT_SYMBOL_GPL(adf_disable_pf2vf_interrupts);
static int adf_enable_msi(struct adf_accel_dev *accel_dev) static int adf_enable_msi(struct adf_accel_dev *accel_dev)
{ {
...@@ -316,6 +317,30 @@ int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev) ...@@ -316,6 +317,30 @@ int adf_vf_isr_resource_alloc(struct adf_accel_dev *accel_dev)
} }
EXPORT_SYMBOL_GPL(adf_vf_isr_resource_alloc); EXPORT_SYMBOL_GPL(adf_vf_isr_resource_alloc);
/**
* adf_flush_vf_wq() - Flush workqueue for VF
* @accel_dev: Pointer to acceleration device.
*
* Function disables the PF/VF interrupts on the VF so that no new messages
* are received and flushes the workqueue 'adf_vf_stop_wq'.
*
* Return: void.
*/
void adf_flush_vf_wq(struct adf_accel_dev *accel_dev)
{
adf_disable_pf2vf_interrupts(accel_dev);
flush_workqueue(adf_vf_stop_wq);
}
EXPORT_SYMBOL_GPL(adf_flush_vf_wq);
/**
* adf_init_vf_wq() - Init workqueue for VF
*
* Function init workqueue 'adf_vf_stop_wq' for VF.
*
* Return: 0 on success, error code otherwise.
*/
int __init adf_init_vf_wq(void) int __init adf_init_vf_wq(void)
{ {
adf_vf_stop_wq = alloc_workqueue("adf_vf_stop_wq", WQ_MEM_RECLAIM, 0); adf_vf_stop_wq = alloc_workqueue("adf_vf_stop_wq", WQ_MEM_RECLAIM, 0);
......
...@@ -211,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev) ...@@ -211,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev)
pr_err("QAT: Driver removal failed\n"); pr_err("QAT: Driver removal failed\n");
return; return;
} }
adf_flush_vf_wq(accel_dev);
adf_dev_stop(accel_dev); adf_dev_stop(accel_dev);
adf_dev_shutdown(accel_dev); adf_dev_shutdown(accel_dev);
adf_cleanup_accel(accel_dev); adf_cleanup_accel(accel_dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment