--- /dev/null
+From stable+bounces-181947-greg=kroah.com@vger.kernel.org Mon Sep 29 17:47:52 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Sep 2025 11:47:41 -0400
+Subject: iommufd: Fix race during abort for file descriptors
+To: stable@vger.kernel.org
+Cc: Jason Gunthorpe <jgg@nvidia.com>, Nicolin Chen <nicolinc@nvidia.com>, Nirmoy Das <nirmoyd@nvidia.com>, Kevin Tian <kevin.tian@intel.com>, syzbot+80620e2d0d0a33b09f93@syzkaller.appspotmail.com, Sasha Levin <sashal@kernel.org>
+Message-ID: <20250929154741.136377-1-sashal@kernel.org>
+
+From: Jason Gunthorpe <jgg@nvidia.com>
+
+[ Upstream commit 4e034bf045b12852a24d5d33f2451850818ba0c1 ]
+
+fput() doesn't actually call file_operations release() synchronously, it
+puts the file on a work queue and it will be released eventually.
+
+This is normally fine, except for iommufd the file and the iommufd_object
+are tied to gether. The file has the object as it's private_data and holds
+a users refcount, while the object is expected to remain alive as long as
+the file is.
+
+When the allocation of a new object aborts before installing the file it
+will fput() the file and then go on to immediately kfree() the obj. This
+causes a UAF once the workqueue completes the fput() and tries to
+decrement the users refcount.
+
+Fix this by putting the core code in charge of the file lifetime, and call
+__fput_sync() during abort to ensure that release() is called before
+kfree. __fput_sync() is a bit too tricky to open code in all the object
+implementations. Instead the objects tell the core code where the file
+pointer is and the core will take care of the life cycle.
+
+If the object is successfully allocated then the file will hold a users
+refcount and the iommufd_object cannot be destroyed.
+
+It is worth noting that close(); ioctl(IOMMU_DESTROY); doesn't have an
+issue because close() is already using a synchronous version of fput().
+
+The UAF looks like this:
+
+ BUG: KASAN: slab-use-after-free in iommufd_eventq_fops_release+0x45/0xc0 drivers/iommu/iommufd/eventq.c:376
+ Write of size 4 at addr ffff888059c97804 by task syz.0.46/6164
+
+ CPU: 0 UID: 0 PID: 6164 Comm: syz.0.46 Not tainted syzkaller #0 PREEMPT(full)
+ Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/18/2025
+ Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:94 [inline]
+ dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120
+ print_address_description mm/kasan/report.c:378 [inline]
+ print_report+0xcd/0x630 mm/kasan/report.c:482
+ kasan_report+0xe0/0x110 mm/kasan/report.c:595
+ check_region_inline mm/kasan/generic.c:183 [inline]
+ kasan_check_range+0x100/0x1b0 mm/kasan/generic.c:189
+ instrument_atomic_read_write include/linux/instrumented.h:96 [inline]
+ atomic_fetch_sub_release include/linux/atomic/atomic-instrumented.h:400 [inline]
+ __refcount_dec include/linux/refcount.h:455 [inline]
+ refcount_dec include/linux/refcount.h:476 [inline]
+ iommufd_eventq_fops_release+0x45/0xc0 drivers/iommu/iommufd/eventq.c:376
+ __fput+0x402/0xb70 fs/file_table.c:468
+ task_work_run+0x14d/0x240 kernel/task_work.c:227
+ resume_user_mode_work include/linux/resume_user_mode.h:50 [inline]
+ exit_to_user_mode_loop+0xeb/0x110 kernel/entry/common.c:43
+ exit_to_user_mode_prepare include/linux/irq-entry-common.h:225 [inline]
+ syscall_exit_to_user_mode_work include/linux/entry-common.h:175 [inline]
+ syscall_exit_to_user_mode include/linux/entry-common.h:210 [inline]
+ do_syscall_64+0x41c/0x4c0 arch/x86/entry/syscall_64.c:100
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Link: https://patch.msgid.link/r/1-v1-02cd136829df+31-iommufd_syz_fput_jgg@nvidia.com
+Cc: stable@vger.kernel.org
+Fixes: 07838f7fd529 ("iommufd: Add iommufd fault object")
+Reviewed-by: Nicolin Chen <nicolinc@nvidia.com>
+Reviewed-by: Nirmoy Das <nirmoyd@nvidia.com>
+Reviewed-by: Kevin Tian <kevin.tian@intel.com>
+Tested-by: Nicolin Chen <nicolinc@nvidia.com>
+Reported-by: syzbot+80620e2d0d0a33b09f93@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/r/68c8583d.050a0220.2ff435.03a2.GAE@google.com
+Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
+[ Adjust context ]
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/iommu/iommufd/eventq.c | 9 ++-------
+ drivers/iommu/iommufd/main.c | 35 ++++++++++++++++++++++++++++++++---
+ 2 files changed, 34 insertions(+), 10 deletions(-)
+
+--- a/drivers/iommu/iommufd/eventq.c
++++ b/drivers/iommu/iommufd/eventq.c
+@@ -393,12 +393,12 @@ static int iommufd_eventq_init(struct io
+ const struct file_operations *fops)
+ {
+ struct file *filep;
+- int fdno;
+
+ spin_lock_init(&eventq->lock);
+ INIT_LIST_HEAD(&eventq->deliver);
+ init_waitqueue_head(&eventq->wait_queue);
+
++ /* The filep is fput() by the core code during failure */
+ filep = anon_inode_getfile(name, fops, eventq, O_RDWR);
+ if (IS_ERR(filep))
+ return PTR_ERR(filep);
+@@ -408,10 +408,7 @@ static int iommufd_eventq_init(struct io
+ eventq->filep = filep;
+ refcount_inc(&eventq->obj.users);
+
+- fdno = get_unused_fd_flags(O_CLOEXEC);
+- if (fdno < 0)
+- fput(filep);
+- return fdno;
++ return get_unused_fd_flags(O_CLOEXEC);
+ }
+
+ static const struct file_operations iommufd_fault_fops =
+@@ -455,7 +452,6 @@ int iommufd_fault_alloc(struct iommufd_u
+ return 0;
+ out_put_fdno:
+ put_unused_fd(fdno);
+- fput(fault->common.filep);
+ out_abort:
+ iommufd_object_abort_and_destroy(ucmd->ictx, &fault->common.obj);
+
+@@ -542,7 +538,6 @@ int iommufd_veventq_alloc(struct iommufd
+
+ out_put_fdno:
+ put_unused_fd(fdno);
+- fput(veventq->common.filep);
+ out_abort:
+ iommufd_object_abort_and_destroy(ucmd->ictx, &veventq->common.obj);
+ out_unlock_veventqs:
+--- a/drivers/iommu/iommufd/main.c
++++ b/drivers/iommu/iommufd/main.c
+@@ -23,6 +23,7 @@
+ #include "iommufd_test.h"
+
+ struct iommufd_object_ops {
++ size_t file_offset;
+ void (*destroy)(struct iommufd_object *obj);
+ void (*abort)(struct iommufd_object *obj);
+ };
+@@ -71,10 +72,30 @@ void iommufd_object_abort(struct iommufd
+ void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx,
+ struct iommufd_object *obj)
+ {
+- if (iommufd_object_ops[obj->type].abort)
+- iommufd_object_ops[obj->type].abort(obj);
++ const struct iommufd_object_ops *ops = &iommufd_object_ops[obj->type];
++
++ if (ops->file_offset) {
++ struct file **filep = ((void *)obj) + ops->file_offset;
++
++ /*
++ * A file should hold a users refcount while the file is open
++ * and put it back in its release. The file should hold a
++ * pointer to obj in their private data. Normal fput() is
++ * deferred to a workqueue and can get out of order with the
++ * following kfree(obj). Using the sync version ensures the
++ * release happens immediately. During abort we require the file
++ * refcount is one at this point - meaning the object alloc
++ * function cannot do anything to allow another thread to take a
++ * refcount prior to a guaranteed success.
++ */
++ if (*filep)
++ __fput_sync(*filep);
++ }
++
++ if (ops->abort)
++ ops->abort(obj);
+ else
+- iommufd_object_ops[obj->type].destroy(obj);
++ ops->destroy(obj);
+ iommufd_object_abort(ictx, obj);
+ }
+
+@@ -493,6 +514,12 @@ void iommufd_ctx_put(struct iommufd_ctx
+ }
+ EXPORT_SYMBOL_NS_GPL(iommufd_ctx_put, "IOMMUFD");
+
++#define IOMMUFD_FILE_OFFSET(_struct, _filep, _obj) \
++ .file_offset = (offsetof(_struct, _filep) + \
++ BUILD_BUG_ON_ZERO(!__same_type( \
++ struct file *, ((_struct *)NULL)->_filep)) + \
++ BUILD_BUG_ON_ZERO(offsetof(_struct, _obj)))
++
+ static const struct iommufd_object_ops iommufd_object_ops[] = {
+ [IOMMUFD_OBJ_ACCESS] = {
+ .destroy = iommufd_access_destroy_object,
+@@ -502,6 +529,7 @@ static const struct iommufd_object_ops i
+ },
+ [IOMMUFD_OBJ_FAULT] = {
+ .destroy = iommufd_fault_destroy,
++ IOMMUFD_FILE_OFFSET(struct iommufd_fault, common.filep, common.obj),
+ },
+ [IOMMUFD_OBJ_HWPT_PAGING] = {
+ .destroy = iommufd_hwpt_paging_destroy,
+@@ -520,6 +548,7 @@ static const struct iommufd_object_ops i
+ [IOMMUFD_OBJ_VEVENTQ] = {
+ .destroy = iommufd_veventq_destroy,
+ .abort = iommufd_veventq_abort,
++ IOMMUFD_FILE_OFFSET(struct iommufd_veventq, common.filep, common.obj),
+ },
+ [IOMMUFD_OBJ_VIOMMU] = {
+ .destroy = iommufd_viommu_destroy,
wifi-iwlwifi-pcie-fix-byte-count-table-for-some-devices.patch
sched_ext-idle-make-local-functions-static-in-ext_idle.c.patch
sched_ext-idle-handle-migration-disabled-tasks-in-bpf-code.patch
+spi-cadence-quadspi-implement-refcount-to-handle-unbind-during-busy.patch
+spi-cadence-qspi-defer-runtime-support-on-socfpga-if-reset-bit-is-enabled.patch
+iommufd-fix-race-during-abort-for-file-descriptors.patch
--- /dev/null
+From stable+bounces-181994-greg=kroah.com@vger.kernel.org Mon Sep 29 21:43:08 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Sep 2025 15:42:55 -0400
+Subject: spi: cadence-qspi: defer runtime support on socfpga if reset bit is enabled
+To: stable@vger.kernel.org
+Cc: Khairul Anuar Romli <khairul.anuar.romli@altera.com>, Adrian Ng Ho Yin <adrianhoyin.ng@altera.com>, Niravkumar L Rabara <nirav.rabara@altera.com>, Matthew Gerlach <matthew.gerlach@altera.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20250929194255.332788-2-sashal@kernel.org>
+
+From: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
+
+[ Upstream commit 30dbc1c8d50f13c1581b49abe46fe89f393eacbf ]
+
+Enabling runtime PM allows the kernel to gate clocks and power to idle
+devices. On SoCFPGA, a warm reset does not fully reinitialize these
+domains.This leaves devices suspended and powered down, preventing U-Boot
+or the kernel from reusing them after a warm reset, which breaks the boot
+process.
+
+Fixes: 4892b374c9b7 ("mtd: spi-nor: cadence-quadspi: Add runtime PM support")
+CC: stable@vger.kernel.org # 6.12+
+Signed-off-by: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
+Signed-off-by: Adrian Ng Ho Yin <adrianhoyin.ng@altera.com>
+Reviewed-by: Niravkumar L Rabara <nirav.rabara@altera.com>
+Reviewed-by: Matthew Gerlach <matthew.gerlach@altera.com>
+Link: https://patch.msgid.link/910aad68ba5d948919a7b90fa85a2fadb687229b.1757491372.git.khairul.anuar.romli@altera.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-cadence-quadspi.c | 57 +++++++++++++++++++++++++-------------
+ 1 file changed, 38 insertions(+), 19 deletions(-)
+
+--- a/drivers/spi/spi-cadence-quadspi.c
++++ b/drivers/spi/spi-cadence-quadspi.c
+@@ -46,6 +46,7 @@ static_assert(CQSPI_MAX_CHIPSELECT <= SP
+ #define CQSPI_DMA_SET_MASK BIT(7)
+ #define CQSPI_SUPPORT_DEVICE_RESET BIT(8)
+ #define CQSPI_DISABLE_STIG_MODE BIT(9)
++#define CQSPI_DISABLE_RUNTIME_PM BIT(10)
+
+ /* Capabilities */
+ #define CQSPI_SUPPORTS_OCTAL BIT(0)
+@@ -1468,14 +1469,17 @@ static int cqspi_exec_mem_op(struct spi_
+ int ret;
+ struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
+ struct device *dev = &cqspi->pdev->dev;
++ const struct cqspi_driver_platdata *ddata = of_device_get_match_data(dev);
+
+ if (refcount_read(&cqspi->inflight_ops) == 0)
+ return -ENODEV;
+
+- ret = pm_runtime_resume_and_get(dev);
+- if (ret) {
+- dev_err(&mem->spi->dev, "resume failed with %d\n", ret);
+- return ret;
++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
++ ret = pm_runtime_resume_and_get(dev);
++ if (ret) {
++ dev_err(&mem->spi->dev, "resume failed with %d\n", ret);
++ return ret;
++ }
+ }
+
+ if (!refcount_read(&cqspi->refcount))
+@@ -1491,8 +1495,10 @@ static int cqspi_exec_mem_op(struct spi_
+
+ ret = cqspi_mem_process(mem, op);
+
+- pm_runtime_mark_last_busy(dev);
+- pm_runtime_put_autosuspend(dev);
++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
++ pm_runtime_mark_last_busy(dev);
++ pm_runtime_put_autosuspend(dev);
++ }
+
+ if (ret)
+ dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
+@@ -1986,11 +1992,12 @@ static int cqspi_probe(struct platform_d
+ goto probe_setup_failed;
+ }
+
+- pm_runtime_enable(dev);
+-
+- pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT);
+- pm_runtime_use_autosuspend(dev);
+- pm_runtime_get_noresume(dev);
++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
++ pm_runtime_enable(dev);
++ pm_runtime_set_autosuspend_delay(dev, CQSPI_AUTOSUSPEND_TIMEOUT);
++ pm_runtime_use_autosuspend(dev);
++ pm_runtime_get_noresume(dev);
++ }
+
+ ret = spi_register_controller(host);
+ if (ret) {
+@@ -1998,13 +2005,17 @@ static int cqspi_probe(struct platform_d
+ goto probe_setup_failed;
+ }
+
+- pm_runtime_mark_last_busy(dev);
+- pm_runtime_put_autosuspend(dev);
++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
++ pm_runtime_put_autosuspend(dev);
++ pm_runtime_mark_last_busy(dev);
++ pm_runtime_put_autosuspend(dev);
++ }
+
+ return 0;
+ probe_setup_failed:
+ cqspi_controller_enable(cqspi, 0);
+- pm_runtime_disable(dev);
++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
++ pm_runtime_disable(dev);
+ probe_reset_failed:
+ if (cqspi->is_jh7110)
+ cqspi_jh7110_disable_clk(pdev, cqspi);
+@@ -2015,7 +2026,11 @@ probe_clk_failed:
+
+ static void cqspi_remove(struct platform_device *pdev)
+ {
++ const struct cqspi_driver_platdata *ddata;
+ struct cqspi_st *cqspi = platform_get_drvdata(pdev);
++ struct device *dev = &pdev->dev;
++
++ ddata = of_device_get_match_data(dev);
+
+ refcount_set(&cqspi->refcount, 0);
+
+@@ -2028,14 +2043,17 @@ static void cqspi_remove(struct platform
+ if (cqspi->rx_chan)
+ dma_release_channel(cqspi->rx_chan);
+
+- if (pm_runtime_get_sync(&pdev->dev) >= 0)
+- clk_disable(cqspi->clk);
++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM)))
++ if (pm_runtime_get_sync(&pdev->dev) >= 0)
++ clk_disable(cqspi->clk);
+
+ if (cqspi->is_jh7110)
+ cqspi_jh7110_disable_clk(pdev, cqspi);
+
+- pm_runtime_put_sync(&pdev->dev);
+- pm_runtime_disable(&pdev->dev);
++ if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) {
++ pm_runtime_put_sync(&pdev->dev);
++ pm_runtime_disable(&pdev->dev);
++ }
+ }
+
+ static int cqspi_runtime_suspend(struct device *dev)
+@@ -2114,7 +2132,8 @@ static const struct cqspi_driver_platdat
+ .quirks = CQSPI_DISABLE_DAC_MODE
+ | CQSPI_NO_SUPPORT_WR_COMPLETION
+ | CQSPI_SLOW_SRAM
+- | CQSPI_DISABLE_STIG_MODE,
++ | CQSPI_DISABLE_STIG_MODE
++ | CQSPI_DISABLE_RUNTIME_PM,
+ };
+
+ static const struct cqspi_driver_platdata versal_ospi = {
--- /dev/null
+From stable+bounces-181993-greg=kroah.com@vger.kernel.org Mon Sep 29 21:43:06 2025
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 29 Sep 2025 15:42:54 -0400
+Subject: spi: cadence-quadspi: Implement refcount to handle unbind during busy
+To: stable@vger.kernel.org
+Cc: Khairul Anuar Romli <khairul.anuar.romli@altera.com>, Matthew Gerlach <matthew.gerlach@altera.com>, Niravkumar L Rabara <nirav.rabara@altera.com>, Mark Brown <broonie@kernel.org>, Sasha Levin <sashal@kernel.org>
+Message-ID: <20250929194255.332788-1-sashal@kernel.org>
+
+From: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
+
+[ Upstream commit 7446284023e8ef694fb392348185349c773eefb3 ]
+
+driver support indirect read and indirect write operation with
+assumption no force device removal(unbind) operation. However
+force device removal(removal) is still available to root superuser.
+
+Unbinding driver during operation causes kernel crash. This changes
+ensure driver able to handle such operation for indirect read and
+indirect write by implementing refcount to track attached devices
+to the controller and gracefully wait and until attached devices
+remove operation completed before proceed with removal operation.
+
+Signed-off-by: Khairul Anuar Romli <khairul.anuar.romli@altera.com>
+Reviewed-by: Matthew Gerlach <matthew.gerlach@altera.com>
+Reviewed-by: Niravkumar L Rabara <nirav.rabara@altera.com>
+Link: https://patch.msgid.link/8704fd6bd2ff4d37bba4a0eacf5eba3ba001079e.1756168074.git.khairul.anuar.romli@altera.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Stable-dep-of: 30dbc1c8d50f ("spi: cadence-qspi: defer runtime support on socfpga if reset bit is enabled")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/spi/spi-cadence-quadspi.c | 33 +++++++++++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+--- a/drivers/spi/spi-cadence-quadspi.c
++++ b/drivers/spi/spi-cadence-quadspi.c
+@@ -108,6 +108,8 @@ struct cqspi_st {
+
+ bool is_jh7110; /* Flag for StarFive JH7110 SoC */
+ bool disable_stig_mode;
++ refcount_t refcount;
++ refcount_t inflight_ops;
+
+ const struct cqspi_driver_platdata *ddata;
+ };
+@@ -735,6 +737,9 @@ static int cqspi_indirect_read_execute(s
+ u8 *rxbuf_end = rxbuf + n_rx;
+ int ret = 0;
+
++ if (!refcount_read(&cqspi->refcount))
++ return -ENODEV;
++
+ writel(from_addr, reg_base + CQSPI_REG_INDIRECTRDSTARTADDR);
+ writel(remaining, reg_base + CQSPI_REG_INDIRECTRDBYTES);
+
+@@ -1071,6 +1076,9 @@ static int cqspi_indirect_write_execute(
+ unsigned int write_bytes;
+ int ret;
+
++ if (!refcount_read(&cqspi->refcount))
++ return -ENODEV;
++
+ writel(to_addr, reg_base + CQSPI_REG_INDIRECTWRSTARTADDR);
+ writel(remaining, reg_base + CQSPI_REG_INDIRECTWRBYTES);
+
+@@ -1461,12 +1469,26 @@ static int cqspi_exec_mem_op(struct spi_
+ struct cqspi_st *cqspi = spi_controller_get_devdata(mem->spi->controller);
+ struct device *dev = &cqspi->pdev->dev;
+
++ if (refcount_read(&cqspi->inflight_ops) == 0)
++ return -ENODEV;
++
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret) {
+ dev_err(&mem->spi->dev, "resume failed with %d\n", ret);
+ return ret;
+ }
+
++ if (!refcount_read(&cqspi->refcount))
++ return -EBUSY;
++
++ refcount_inc(&cqspi->inflight_ops);
++
++ if (!refcount_read(&cqspi->refcount)) {
++ if (refcount_read(&cqspi->inflight_ops))
++ refcount_dec(&cqspi->inflight_ops);
++ return -EBUSY;
++ }
++
+ ret = cqspi_mem_process(mem, op);
+
+ pm_runtime_mark_last_busy(dev);
+@@ -1475,6 +1497,9 @@ static int cqspi_exec_mem_op(struct spi_
+ if (ret)
+ dev_err(&mem->spi->dev, "operation failed with %d\n", ret);
+
++ if (refcount_read(&cqspi->inflight_ops) > 1)
++ refcount_dec(&cqspi->inflight_ops);
++
+ return ret;
+ }
+
+@@ -1926,6 +1951,9 @@ static int cqspi_probe(struct platform_d
+ }
+ }
+
++ refcount_set(&cqspi->refcount, 1);
++ refcount_set(&cqspi->inflight_ops, 1);
++
+ ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
+ pdev->name, cqspi);
+ if (ret) {
+@@ -1989,6 +2017,11 @@ static void cqspi_remove(struct platform
+ {
+ struct cqspi_st *cqspi = platform_get_drvdata(pdev);
+
++ refcount_set(&cqspi->refcount, 0);
++
++ if (!refcount_dec_and_test(&cqspi->inflight_ops))
++ cqspi_wait_idle(cqspi);
++
+ spi_unregister_controller(cqspi->host);
+ cqspi_controller_enable(cqspi, 0);
+