xref: /freebsd/sys/dev/qat/qat_common/adf_aer.c (revision 01518f5eede79cf65319d455eb50e78c9efa2b51)
178ee8d1cSJulian Grajkowski /* SPDX-License-Identifier: BSD-3-Clause */
278ee8d1cSJulian Grajkowski /* Copyright(c) 2007-2022 Intel Corporation */
378ee8d1cSJulian Grajkowski #include "qat_freebsd.h"
478ee8d1cSJulian Grajkowski #include "adf_cfg.h"
578ee8d1cSJulian Grajkowski #include "adf_common_drv.h"
678ee8d1cSJulian Grajkowski #include "adf_accel_devices.h"
778ee8d1cSJulian Grajkowski #include "icp_qat_uclo.h"
878ee8d1cSJulian Grajkowski #include "icp_qat_fw.h"
978ee8d1cSJulian Grajkowski #include "icp_qat_fw_init_admin.h"
1078ee8d1cSJulian Grajkowski #include "adf_cfg_strings.h"
1178ee8d1cSJulian Grajkowski #include "adf_transport_access_macros.h"
1278ee8d1cSJulian Grajkowski #include "adf_transport_internal.h"
1378ee8d1cSJulian Grajkowski #include <sys/bus.h>
1478ee8d1cSJulian Grajkowski #include <dev/pci/pcireg.h>
1578ee8d1cSJulian Grajkowski #include <dev/pci/pcivar.h>
1678ee8d1cSJulian Grajkowski #include <sys/systm.h>
1778ee8d1cSJulian Grajkowski 
1878ee8d1cSJulian Grajkowski #define ADF_PPAERUCM_MASK (BIT(14) | BIT(20) | BIT(22))
1978ee8d1cSJulian Grajkowski 
2078ee8d1cSJulian Grajkowski static struct workqueue_struct *fatal_error_wq;
2178ee8d1cSJulian Grajkowski struct adf_fatal_error_data {
2278ee8d1cSJulian Grajkowski 	struct adf_accel_dev *accel_dev;
2378ee8d1cSJulian Grajkowski 	struct work_struct work;
2478ee8d1cSJulian Grajkowski };
2578ee8d1cSJulian Grajkowski 
2678ee8d1cSJulian Grajkowski static struct workqueue_struct *device_reset_wq;
2778ee8d1cSJulian Grajkowski 
2878ee8d1cSJulian Grajkowski void
2978ee8d1cSJulian Grajkowski linux_complete_common(struct completion *c, int all)
3078ee8d1cSJulian Grajkowski {
3178ee8d1cSJulian Grajkowski 	sleepq_lock(c);
3278ee8d1cSJulian Grajkowski 	c->done++;
3378ee8d1cSJulian Grajkowski 	if (all)
34*01518f5eSMark Johnston 		sleepq_broadcast(c, SLEEPQ_SLEEP, 0, 0);
3578ee8d1cSJulian Grajkowski 	else
36*01518f5eSMark Johnston 		sleepq_signal(c, SLEEPQ_SLEEP, 0, 0);
3778ee8d1cSJulian Grajkowski 	sleepq_release(c);
3878ee8d1cSJulian Grajkowski }
3978ee8d1cSJulian Grajkowski 
4078ee8d1cSJulian Grajkowski /* reset dev data */
4178ee8d1cSJulian Grajkowski struct adf_reset_dev_data {
4278ee8d1cSJulian Grajkowski 	int mode;
4378ee8d1cSJulian Grajkowski 	struct adf_accel_dev *accel_dev;
4478ee8d1cSJulian Grajkowski 	struct completion compl;
4578ee8d1cSJulian Grajkowski 	struct work_struct reset_work;
4678ee8d1cSJulian Grajkowski };
4778ee8d1cSJulian Grajkowski 
4878ee8d1cSJulian Grajkowski int
4978ee8d1cSJulian Grajkowski adf_aer_store_ppaerucm_reg(device_t dev, struct adf_hw_device_data *hw_data)
5078ee8d1cSJulian Grajkowski {
5178ee8d1cSJulian Grajkowski 	unsigned int aer_offset, reg_val = 0;
5278ee8d1cSJulian Grajkowski 
5378ee8d1cSJulian Grajkowski 	if (!hw_data)
5478ee8d1cSJulian Grajkowski 		return -EINVAL;
5578ee8d1cSJulian Grajkowski 
5678ee8d1cSJulian Grajkowski 	if (pci_find_extcap(dev, PCIZ_AER, &aer_offset) == 0) {
5778ee8d1cSJulian Grajkowski 		reg_val =
5878ee8d1cSJulian Grajkowski 		    pci_read_config(dev, aer_offset + PCIR_AER_UC_MASK, 4);
5978ee8d1cSJulian Grajkowski 
6078ee8d1cSJulian Grajkowski 		hw_data->aerucm_mask = reg_val;
6178ee8d1cSJulian Grajkowski 	} else {
6278ee8d1cSJulian Grajkowski 		device_printf(dev,
6378ee8d1cSJulian Grajkowski 			      "Unable to find AER capability of the device\n");
6478ee8d1cSJulian Grajkowski 		return -ENODEV;
6578ee8d1cSJulian Grajkowski 	}
6678ee8d1cSJulian Grajkowski 
6778ee8d1cSJulian Grajkowski 	return 0;
6878ee8d1cSJulian Grajkowski }
6978ee8d1cSJulian Grajkowski 
7078ee8d1cSJulian Grajkowski void
7178ee8d1cSJulian Grajkowski adf_reset_sbr(struct adf_accel_dev *accel_dev)
7278ee8d1cSJulian Grajkowski {
7378ee8d1cSJulian Grajkowski 	device_t pdev = accel_to_pci_dev(accel_dev);
7478ee8d1cSJulian Grajkowski 	device_t parent = device_get_parent(device_get_parent(pdev));
7578ee8d1cSJulian Grajkowski 	uint16_t bridge_ctl = 0;
7678ee8d1cSJulian Grajkowski 
7778ee8d1cSJulian Grajkowski 	if (accel_dev->is_vf)
7878ee8d1cSJulian Grajkowski 		return;
7978ee8d1cSJulian Grajkowski 
8078ee8d1cSJulian Grajkowski 	if (!parent)
8178ee8d1cSJulian Grajkowski 		parent = pdev;
8278ee8d1cSJulian Grajkowski 
8378ee8d1cSJulian Grajkowski 	if (!pcie_wait_for_pending_transactions(pdev, 0))
8478ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev),
8578ee8d1cSJulian Grajkowski 			      "Transaction still in progress. Proceeding\n");
8678ee8d1cSJulian Grajkowski 
8778ee8d1cSJulian Grajkowski 	device_printf(GET_DEV(accel_dev), "Secondary bus reset\n");
8878ee8d1cSJulian Grajkowski 
8978ee8d1cSJulian Grajkowski 	pci_save_state(pdev);
9078ee8d1cSJulian Grajkowski 	bridge_ctl = pci_read_config(parent, PCIR_BRIDGECTL_1, 2);
9178ee8d1cSJulian Grajkowski 	bridge_ctl |= PCIB_BCR_SECBUS_RESET;
9278ee8d1cSJulian Grajkowski 	pci_write_config(parent, PCIR_BRIDGECTL_1, bridge_ctl, 2);
9378ee8d1cSJulian Grajkowski 	pause_ms("adfrst", 100);
9478ee8d1cSJulian Grajkowski 	bridge_ctl &= ~PCIB_BCR_SECBUS_RESET;
9578ee8d1cSJulian Grajkowski 	pci_write_config(parent, PCIR_BRIDGECTL_1, bridge_ctl, 2);
9678ee8d1cSJulian Grajkowski 	pause_ms("adfrst", 100);
9778ee8d1cSJulian Grajkowski 	pci_restore_state(pdev);
9878ee8d1cSJulian Grajkowski }
9978ee8d1cSJulian Grajkowski 
10078ee8d1cSJulian Grajkowski void
10178ee8d1cSJulian Grajkowski adf_reset_flr(struct adf_accel_dev *accel_dev)
10278ee8d1cSJulian Grajkowski {
10378ee8d1cSJulian Grajkowski 	device_t pdev = accel_to_pci_dev(accel_dev);
10478ee8d1cSJulian Grajkowski 
10578ee8d1cSJulian Grajkowski 	pci_save_state(pdev);
10678ee8d1cSJulian Grajkowski 	if (pcie_flr(pdev,
10778ee8d1cSJulian Grajkowski 		     max(pcie_get_max_completion_timeout(pdev) / 1000, 10),
10878ee8d1cSJulian Grajkowski 		     true)) {
10978ee8d1cSJulian Grajkowski 		pci_restore_state(pdev);
11078ee8d1cSJulian Grajkowski 		return;
11178ee8d1cSJulian Grajkowski 	}
11278ee8d1cSJulian Grajkowski 	pci_restore_state(pdev);
11378ee8d1cSJulian Grajkowski 	device_printf(GET_DEV(accel_dev),
11478ee8d1cSJulian Grajkowski 		      "FLR qat_dev%d failed trying secondary bus reset\n",
11578ee8d1cSJulian Grajkowski 		      accel_dev->accel_id);
11678ee8d1cSJulian Grajkowski 	adf_reset_sbr(accel_dev);
11778ee8d1cSJulian Grajkowski }
11878ee8d1cSJulian Grajkowski 
11978ee8d1cSJulian Grajkowski void
12078ee8d1cSJulian Grajkowski adf_dev_pre_reset(struct adf_accel_dev *accel_dev)
12178ee8d1cSJulian Grajkowski {
12278ee8d1cSJulian Grajkowski 	struct adf_hw_device_data *hw_device = accel_dev->hw_device;
12378ee8d1cSJulian Grajkowski 	device_t pdev = accel_to_pci_dev(accel_dev);
12478ee8d1cSJulian Grajkowski 	u32 aer_offset, reg_val = 0;
12578ee8d1cSJulian Grajkowski 
12678ee8d1cSJulian Grajkowski 	if (pci_find_extcap(pdev, PCIZ_AER, &aer_offset) == 0) {
12778ee8d1cSJulian Grajkowski 		reg_val =
12878ee8d1cSJulian Grajkowski 		    pci_read_config(pdev, aer_offset + PCIR_AER_UC_MASK, 4);
12978ee8d1cSJulian Grajkowski 		reg_val |= ADF_PPAERUCM_MASK;
13078ee8d1cSJulian Grajkowski 		pci_write_config(pdev,
13178ee8d1cSJulian Grajkowski 				 aer_offset + PCIR_AER_UC_MASK,
13278ee8d1cSJulian Grajkowski 				 reg_val,
13378ee8d1cSJulian Grajkowski 				 4);
13478ee8d1cSJulian Grajkowski 	} else {
13578ee8d1cSJulian Grajkowski 		device_printf(pdev,
13678ee8d1cSJulian Grajkowski 			      "Unable to find AER capability of the device\n");
13778ee8d1cSJulian Grajkowski 	}
13878ee8d1cSJulian Grajkowski 
13978ee8d1cSJulian Grajkowski 	if (hw_device->disable_arb) {
14078ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev), "Disable arbiter.\n");
14178ee8d1cSJulian Grajkowski 		hw_device->disable_arb(accel_dev);
14278ee8d1cSJulian Grajkowski 	}
14378ee8d1cSJulian Grajkowski }
14478ee8d1cSJulian Grajkowski 
14578ee8d1cSJulian Grajkowski void
14678ee8d1cSJulian Grajkowski adf_dev_post_reset(struct adf_accel_dev *accel_dev)
14778ee8d1cSJulian Grajkowski {
14878ee8d1cSJulian Grajkowski 	struct adf_hw_device_data *hw_device = accel_dev->hw_device;
14978ee8d1cSJulian Grajkowski 	device_t pdev = accel_to_pci_dev(accel_dev);
15078ee8d1cSJulian Grajkowski 	u32 aer_offset;
15178ee8d1cSJulian Grajkowski 
15278ee8d1cSJulian Grajkowski 	if (pci_find_extcap(pdev, PCIZ_AER, &aer_offset) == 0) {
15378ee8d1cSJulian Grajkowski 		pci_write_config(pdev,
15478ee8d1cSJulian Grajkowski 				 aer_offset + PCIR_AER_UC_MASK,
15578ee8d1cSJulian Grajkowski 				 hw_device->aerucm_mask,
15678ee8d1cSJulian Grajkowski 				 4);
15778ee8d1cSJulian Grajkowski 	} else {
15878ee8d1cSJulian Grajkowski 		device_printf(pdev,
15978ee8d1cSJulian Grajkowski 			      "Unable to find AER capability of the device\n");
16078ee8d1cSJulian Grajkowski 	}
16178ee8d1cSJulian Grajkowski }
16278ee8d1cSJulian Grajkowski 
16378ee8d1cSJulian Grajkowski void
16478ee8d1cSJulian Grajkowski adf_dev_restore(struct adf_accel_dev *accel_dev)
16578ee8d1cSJulian Grajkowski {
16678ee8d1cSJulian Grajkowski 	struct adf_hw_device_data *hw_device = accel_dev->hw_device;
16778ee8d1cSJulian Grajkowski 	device_t pdev = accel_to_pci_dev(accel_dev);
16878ee8d1cSJulian Grajkowski 
16978ee8d1cSJulian Grajkowski 	if (hw_device->pre_reset) {
17078ee8d1cSJulian Grajkowski 		dev_dbg(GET_DEV(accel_dev), "Performing pre reset save\n");
17178ee8d1cSJulian Grajkowski 		hw_device->pre_reset(accel_dev);
17278ee8d1cSJulian Grajkowski 	}
17378ee8d1cSJulian Grajkowski 
17478ee8d1cSJulian Grajkowski 	if (hw_device->reset_device) {
17578ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev),
17678ee8d1cSJulian Grajkowski 			      "Resetting device qat_dev%d\n",
17778ee8d1cSJulian Grajkowski 			      accel_dev->accel_id);
17878ee8d1cSJulian Grajkowski 		hw_device->reset_device(accel_dev);
17978ee8d1cSJulian Grajkowski 		pci_restore_state(pdev);
18078ee8d1cSJulian Grajkowski 		pci_save_state(pdev);
18178ee8d1cSJulian Grajkowski 	}
18278ee8d1cSJulian Grajkowski 
18378ee8d1cSJulian Grajkowski 	if (hw_device->post_reset) {
18478ee8d1cSJulian Grajkowski 		dev_dbg(GET_DEV(accel_dev), "Performing post reset restore\n");
18578ee8d1cSJulian Grajkowski 		hw_device->post_reset(accel_dev);
18678ee8d1cSJulian Grajkowski 	}
18778ee8d1cSJulian Grajkowski }
18878ee8d1cSJulian Grajkowski 
18978ee8d1cSJulian Grajkowski static void
19078ee8d1cSJulian Grajkowski adf_device_reset_worker(struct work_struct *work)
19178ee8d1cSJulian Grajkowski {
19278ee8d1cSJulian Grajkowski 	struct adf_reset_dev_data *reset_data =
19378ee8d1cSJulian Grajkowski 	    container_of(work, struct adf_reset_dev_data, reset_work);
19478ee8d1cSJulian Grajkowski 	struct adf_accel_dev *accel_dev = reset_data->accel_dev;
19578ee8d1cSJulian Grajkowski 
19678ee8d1cSJulian Grajkowski 	if (adf_dev_restarting_notify(accel_dev)) {
19778ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev),
19878ee8d1cSJulian Grajkowski 			      "Unable to send RESTARTING notification.\n");
19978ee8d1cSJulian Grajkowski 		return;
20078ee8d1cSJulian Grajkowski 	}
20178ee8d1cSJulian Grajkowski 
20278ee8d1cSJulian Grajkowski 	if (adf_dev_stop(accel_dev)) {
20378ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev), "Stopping device failed.\n");
20478ee8d1cSJulian Grajkowski 		return;
20578ee8d1cSJulian Grajkowski 	}
20678ee8d1cSJulian Grajkowski 
20778ee8d1cSJulian Grajkowski 	adf_dev_shutdown(accel_dev);
20878ee8d1cSJulian Grajkowski 
20978ee8d1cSJulian Grajkowski 	if (adf_dev_init(accel_dev) || adf_dev_start(accel_dev)) {
21078ee8d1cSJulian Grajkowski 		/* The device hanged and we can't restart it */
21178ee8d1cSJulian Grajkowski 		/* so stop here */
21278ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev), "Restart device failed\n");
21378ee8d1cSJulian Grajkowski 		if (reset_data->mode == ADF_DEV_RESET_ASYNC)
21478ee8d1cSJulian Grajkowski 			kfree(reset_data);
21578ee8d1cSJulian Grajkowski 		WARN(1, "QAT: device restart failed. Device is unusable\n");
21678ee8d1cSJulian Grajkowski 		return;
21778ee8d1cSJulian Grajkowski 	}
21878ee8d1cSJulian Grajkowski 
21978ee8d1cSJulian Grajkowski 	adf_dev_restarted_notify(accel_dev);
22078ee8d1cSJulian Grajkowski 	clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
22178ee8d1cSJulian Grajkowski 
22278ee8d1cSJulian Grajkowski 	/* The dev is back alive. Notify the caller if in sync mode */
22378ee8d1cSJulian Grajkowski 	if (reset_data->mode == ADF_DEV_RESET_SYNC)
22478ee8d1cSJulian Grajkowski 		complete(&reset_data->compl);
22578ee8d1cSJulian Grajkowski 	else
22678ee8d1cSJulian Grajkowski 		kfree(reset_data);
22778ee8d1cSJulian Grajkowski }
22878ee8d1cSJulian Grajkowski 
22978ee8d1cSJulian Grajkowski int
23078ee8d1cSJulian Grajkowski adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev,
23178ee8d1cSJulian Grajkowski 			   enum adf_dev_reset_mode mode)
23278ee8d1cSJulian Grajkowski {
23378ee8d1cSJulian Grajkowski 	struct adf_reset_dev_data *reset_data;
23478ee8d1cSJulian Grajkowski 	if (!adf_dev_started(accel_dev) ||
23578ee8d1cSJulian Grajkowski 	    test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
23678ee8d1cSJulian Grajkowski 		return 0;
23778ee8d1cSJulian Grajkowski 	set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
23878ee8d1cSJulian Grajkowski 	reset_data = kzalloc(sizeof(*reset_data), GFP_ATOMIC);
23978ee8d1cSJulian Grajkowski 	if (!reset_data)
24078ee8d1cSJulian Grajkowski 		return -ENOMEM;
24178ee8d1cSJulian Grajkowski 	reset_data->accel_dev = accel_dev;
24278ee8d1cSJulian Grajkowski 	init_completion(&reset_data->compl);
24378ee8d1cSJulian Grajkowski 	reset_data->mode = mode;
24478ee8d1cSJulian Grajkowski 	INIT_WORK(&reset_data->reset_work, adf_device_reset_worker);
24578ee8d1cSJulian Grajkowski 	queue_work(device_reset_wq, &reset_data->reset_work);
24678ee8d1cSJulian Grajkowski 	/* If in sync mode wait for the result */
24778ee8d1cSJulian Grajkowski 	if (mode == ADF_DEV_RESET_SYNC) {
24878ee8d1cSJulian Grajkowski 		int ret = 0;
24978ee8d1cSJulian Grajkowski 		/* Maximum device reset time is 10 seconds */
25078ee8d1cSJulian Grajkowski 		unsigned long wait_jiffies = msecs_to_jiffies(10000);
25178ee8d1cSJulian Grajkowski 		unsigned long timeout =
25278ee8d1cSJulian Grajkowski 		    wait_for_completion_timeout(&reset_data->compl,
25378ee8d1cSJulian Grajkowski 						wait_jiffies);
25478ee8d1cSJulian Grajkowski 		if (!timeout) {
25578ee8d1cSJulian Grajkowski 			device_printf(GET_DEV(accel_dev),
25678ee8d1cSJulian Grajkowski 				      "Reset device timeout expired\n");
25778ee8d1cSJulian Grajkowski 			ret = -EFAULT;
25878ee8d1cSJulian Grajkowski 		}
25978ee8d1cSJulian Grajkowski 		kfree(reset_data);
26078ee8d1cSJulian Grajkowski 		return ret;
26178ee8d1cSJulian Grajkowski 	}
26278ee8d1cSJulian Grajkowski 	return 0;
26378ee8d1cSJulian Grajkowski }
26478ee8d1cSJulian Grajkowski 
26578ee8d1cSJulian Grajkowski int
26678ee8d1cSJulian Grajkowski adf_dev_autoreset(struct adf_accel_dev *accel_dev)
26778ee8d1cSJulian Grajkowski {
26878ee8d1cSJulian Grajkowski 	if (accel_dev->autoreset_on_error)
26978ee8d1cSJulian Grajkowski 		return adf_dev_reset(accel_dev, ADF_DEV_RESET_ASYNC);
27078ee8d1cSJulian Grajkowski 	return 0;
27178ee8d1cSJulian Grajkowski }
27278ee8d1cSJulian Grajkowski 
27378ee8d1cSJulian Grajkowski static void
27478ee8d1cSJulian Grajkowski adf_notify_fatal_error_work(struct work_struct *work)
27578ee8d1cSJulian Grajkowski {
27678ee8d1cSJulian Grajkowski 	struct adf_fatal_error_data *wq_data =
27778ee8d1cSJulian Grajkowski 	    container_of(work, struct adf_fatal_error_data, work);
27878ee8d1cSJulian Grajkowski 	struct adf_accel_dev *accel_dev = wq_data->accel_dev;
27978ee8d1cSJulian Grajkowski 
28078ee8d1cSJulian Grajkowski 	adf_error_notifier((uintptr_t)accel_dev);
28178ee8d1cSJulian Grajkowski 	if (!accel_dev->is_vf) {
28278ee8d1cSJulian Grajkowski 		adf_dev_autoreset(accel_dev);
28378ee8d1cSJulian Grajkowski 	}
28478ee8d1cSJulian Grajkowski 
28578ee8d1cSJulian Grajkowski 	kfree(wq_data);
28678ee8d1cSJulian Grajkowski }
28778ee8d1cSJulian Grajkowski 
28878ee8d1cSJulian Grajkowski int
28978ee8d1cSJulian Grajkowski adf_notify_fatal_error(struct adf_accel_dev *accel_dev)
29078ee8d1cSJulian Grajkowski {
29178ee8d1cSJulian Grajkowski 	struct adf_fatal_error_data *wq_data;
29278ee8d1cSJulian Grajkowski 
29378ee8d1cSJulian Grajkowski 	wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC);
29478ee8d1cSJulian Grajkowski 	if (!wq_data) {
29578ee8d1cSJulian Grajkowski 		device_printf(GET_DEV(accel_dev),
29678ee8d1cSJulian Grajkowski 			      "Failed to allocate memory\n");
29778ee8d1cSJulian Grajkowski 		return ENOMEM;
29878ee8d1cSJulian Grajkowski 	}
29978ee8d1cSJulian Grajkowski 	wq_data->accel_dev = accel_dev;
30078ee8d1cSJulian Grajkowski 
30178ee8d1cSJulian Grajkowski 	INIT_WORK(&wq_data->work, adf_notify_fatal_error_work);
30278ee8d1cSJulian Grajkowski 	queue_work(fatal_error_wq, &wq_data->work);
30378ee8d1cSJulian Grajkowski 
30478ee8d1cSJulian Grajkowski 	return 0;
30578ee8d1cSJulian Grajkowski }
30678ee8d1cSJulian Grajkowski 
30778ee8d1cSJulian Grajkowski int __init
30878ee8d1cSJulian Grajkowski adf_init_fatal_error_wq(void)
30978ee8d1cSJulian Grajkowski {
31078ee8d1cSJulian Grajkowski 	fatal_error_wq = create_workqueue("qat_fatal_error_wq");
31178ee8d1cSJulian Grajkowski 	return !fatal_error_wq ? EFAULT : 0;
31278ee8d1cSJulian Grajkowski }
31378ee8d1cSJulian Grajkowski 
31478ee8d1cSJulian Grajkowski void
31578ee8d1cSJulian Grajkowski adf_exit_fatal_error_wq(void)
31678ee8d1cSJulian Grajkowski {
31778ee8d1cSJulian Grajkowski 	if (fatal_error_wq)
31878ee8d1cSJulian Grajkowski 		destroy_workqueue(fatal_error_wq);
31978ee8d1cSJulian Grajkowski 	fatal_error_wq = NULL;
32078ee8d1cSJulian Grajkowski }
32178ee8d1cSJulian Grajkowski 
32278ee8d1cSJulian Grajkowski int
32378ee8d1cSJulian Grajkowski adf_init_aer(void)
32478ee8d1cSJulian Grajkowski {
32578ee8d1cSJulian Grajkowski 	device_reset_wq = create_workqueue("qat_device_reset_wq");
32678ee8d1cSJulian Grajkowski 	return !device_reset_wq ? -EFAULT : 0;
32778ee8d1cSJulian Grajkowski }
32878ee8d1cSJulian Grajkowski 
32978ee8d1cSJulian Grajkowski void
33078ee8d1cSJulian Grajkowski adf_exit_aer(void)
33178ee8d1cSJulian Grajkowski {
33278ee8d1cSJulian Grajkowski 	if (device_reset_wq)
33378ee8d1cSJulian Grajkowski 		destroy_workqueue(device_reset_wq);
33478ee8d1cSJulian Grajkowski 	device_reset_wq = NULL;
33578ee8d1cSJulian Grajkowski }
336