Skip to contentSkip to conversation

media: iris: Fix issues in the driver unbind path

PATCH In review Vishnu Reddy 2 participants 8 messages Nov 10 – Nov 11

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

v2 cover media: iris: Fix issues in the driver unbind path

The driver unbind can be triggered through sysfs while a client has a video session running. The devm resources are freed when the unbind completes. That leads to use after free for the running sessions.

The core and its device are now kept allocated until the last file descriptor is closed. New sessions are stopped as soon as the removal starts. The interrupt is freed before the core, so the interrupt thread cannot run on freed memory.

The system error work was only cancelled during the removal. An interrupt could still arrive afterwards and queue the work again. The work is now disabled.

The runtime PM usage count was dropped twice when a resume failed. This happens for a command written after runtime PM is disabled. The count underflowed. The reference is no longer dropped a second time.

---
Changes in v2:
- Updated the commit description of patch 3 (Bryan)
- Split the interrupt freeing into a separate patch (Bryan)
- Added a new patch to wake up clients blocked on open sessions at removal.
- Link to v1: https://lore.kernel.org/r/[email protected]

---
Vishnu Reddy (5):
media: iris: Fix runtime PM reference imbalance on failed resume
media: iris: Disable the system error work on removal
media: iris: Fix use-after-free on unbind with open sessions
media: iris: Wake up blocked clients when the driver is removed
media: iris: Free the interrupt in iris_remove()

 drivers/media/platform/qcom/iris/iris_core.c      | 10 +++-
 drivers/media/platform/qcom/iris/iris_core.h      |  2 +
 drivers/media/platform/qcom/iris/iris_hfi_queue.c | 17 +++++-
 drivers/media/platform/qcom/iris/iris_instance.h  |  2 +
 drivers/media/platform/qcom/iris/iris_power.c     | 13 +++++
 drivers/media/platform/qcom/iris/iris_probe.c     | 64 +++++++++++++++++++----
 drivers/media/platform/qcom/iris/iris_vidc.c      |  8 +++
 7 files changed, 103 insertions(+), 13 deletions(-)

---
base-commit: 630059a5a632377b9b7b487baccde92b7ae1dd47
change-id: 20261013-iris-handle-unbind-fe09689e6696

Best regards,

Signature · 1 line
Vishnu Reddy <[email protected]>
#1 lore raw

PATCH v2 1/5 media: iris: Fix runtime PM reference imbalance on failed resume

pm_runtime_resume_and_get() drops its usage count when the resume fails. iris_hfi_queue_cmd_write() dropped it a second time on that path, resulting in a runtime PM usage count underflow warning:

qcom-iris aa00000.video-codec: Runtime PM usage count underflow!

Fixes bb8a95aa038e ("media: iris: implement power management")
---
 drivers/media/platform/qcom/iris/iris_hfi_queue.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/qcom/iris/iris_hfi_queue.c +1 -1
index bf6db23b53e21..545bbe75e1740 100644
@@ -132,7 +132,7 @@ int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size)
 
 	ret = pm_runtime_resume_and_get(core->dev);
 	if (ret < 0)
-		goto exit;
+		return ret;
 
 	mutex_lock(&core->lock);
 	ret = iris_hfi_queue_cmd_write_locked(core, pkt, pkt_size);
Signature · 1 line
2.34.1
#2 lore raw

PATCH v2 2/5 media: iris: Disable the system error work on removal

In reply to Vishnu Reddy

iris_remove() calls cancel_delayed_work_sync() to stop the system error work. This cancels a pending work and waits for a running one. It does not stop the work from being queued again afterwards.

A system error interrupt can still arrive after that call. The interrupt handler queues the work again. The work then runs after the removal and uses resources that are already freed.

Use disable_delayed_work_sync() instead. Once it returns no new work can be queued. The work cannot run again during or after the removal.

Fixes 452480931648 ("media: iris: cancel sys error work on driver removal")
---
 drivers/media/platform/qcom/iris/iris_probe.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/media/platform/qcom/iris/iris_probe.c +1 -1
index 343e44c6b9c4..6f02bb629867 100644
@@ -251,7 +251,7 @@ static void iris_remove(struct platform_device *pdev)
 	if (!core)
 		return;
 
-	cancel_delayed_work_sync(&core->sys_error_handler);
+	disable_delayed_work_sync(&core->sys_error_handler);
 
 	iris_core_deinit(core);
 
Signature · 1 line
2.34.1
#3 lore raw

PATCH v2 3/5 media: iris: Fix use-after-free on unbind with open sessions

In reply to Vishnu Reddy

The driver can be unbound through sysfs while a client has a video session open. The core is devm allocated and freed when remove() returns, so the open sessions then use freed memory.

Only the core structure needs to outlive remove(), because it is the only thing the file operations of an open session still use. Allocate it with kzalloc and tie it to the reference count of its v4l2_device, which every registered video device holds. It is freed when the last file descriptor is closed. The other devm resources (register mapping, response packet, clocks, power domains, interconnects) are only used by the power on/off sequence, the clock and bandwidth votes and the interrupt handler. All of them are released with the unbind, after the core is shut down.

To make sure nothing uses them afterwards, set a removing flag at the start of iris_remove(). It makes core init, new sessions, command writes and the clock and interconnect votes fail with -ENODEV, so a client still holding a file descriptor cannot power the hardware on or vote for resources that are gone. A client waiting for the firmware only times out and returns an error without touching them. Runtime PM is also disabled explicitly in iris_remove() instead of with devm, because its callbacks use the core.

Fixes 38506cb7e8d2 ("media: iris: add platform driver for iris video device")
---
 drivers/media/platform/qcom/iris/iris_core.c      | 10 +++++-
 drivers/media/platform/qcom/iris/iris_core.h      |  2 ++
 drivers/media/platform/qcom/iris/iris_hfi_queue.c | 15 +++++++-
 drivers/media/platform/qcom/iris/iris_power.c     | 13 +++++++
 drivers/media/platform/qcom/iris/iris_probe.c     | 44 ++++++++++++++++++-----
 drivers/media/platform/qcom/iris/iris_vidc.c      |  3 ++
 6 files changed, 76 insertions(+), 11 deletions(-)
drivers/media/platform/qcom/iris/iris_core.c +9 -1
index d558475986ff0..bdac6b8c98e44 100644
@@ -43,7 +43,10 @@ static int iris_wait_for_system_response(struct iris_core *core)
 	ret = wait_for_completion_timeout(&core->core_init_done,
 					  msecs_to_jiffies(HW_RESPONSE_TIMEOUT_VALUE));
 	if (!ret) {
-		core->state = IRIS_CORE_ERROR;
+		mutex_lock(&core->lock);
+		if (!core->removing)
+			core->state = IRIS_CORE_ERROR;
+		mutex_unlock(&core->lock);
 		return -ETIMEDOUT;
 	}
 
@@ -56,6 +59,11 @@ int iris_core_init(struct iris_core *core)
 	int ret;
 
 	mutex_lock(&core->lock);
+	if (core->removing) {
+		ret = -ENODEV;
+		goto exit;
+	}
+
 	if (core->state == IRIS_CORE_INIT) {
 		ret = 0;
 		goto exit;
drivers/media/platform/qcom/iris/iris_core.h +2 -0
index 3e4cf652bf39a..379f0666a42cb 100644
@@ -62,6 +62,7 @@ struct qcom_ubwc_cfg_data;
  * @iris_firmware_desc: a pointer to the firmware-specific descriptive data
  * @ubwc_cfg: UBWC configuration for the platform
  * @state: current state of core
+ * @removing: set when driver removal starts, blocks core init and resource votes
  * @iface_q_table_daddr: device address for interface queue table memory
  * @sfr_daddr: device address for SFR (Sub System Failure Reason) register memory
  * @iface_q_table_vaddr: virtual address for interface queue table memory
@@ -108,6 +109,7 @@ struct iris_core {
 	const struct iris_firmware_desc		*iris_firmware_desc;
 	const struct qcom_ubwc_cfg_data		*ubwc_cfg;
 	enum iris_core_state			state;
+	bool					removing;
 	dma_addr_t				iface_q_table_daddr;
 	dma_addr_t				sfr_daddr;
 	void					*iface_q_table_vaddr;
drivers/media/platform/qcom/iris/iris_hfi_queue.c +14 -1
index 545bbe75e1740..e0cfa5107d1d9 100644
@@ -128,13 +128,26 @@ int iris_hfi_queue_cmd_write_locked(struct iris_core *core, void *pkt, u32 pkt_s
 
 int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size)
 {
-	int ret;
+	int ret = 0;
+
+	mutex_lock(&core->lock);
+	if (core->removing)
+		ret = -ENODEV;
+	mutex_unlock(&core->lock);
+	if (ret)
+		return ret;
 
 	ret = pm_runtime_resume_and_get(core->dev);
 	if (ret < 0)
 		return ret;
 
 	mutex_lock(&core->lock);
+	if (core->removing) {
+		mutex_unlock(&core->lock);
+		ret = -ENODEV;
+		goto exit;
+	}
+
 	ret = iris_hfi_queue_cmd_write_locked(core, pkt, pkt_size);
 	if (ret) {
 		mutex_unlock(&core->lock);
drivers/media/platform/qcom/iris/iris_power.c +13 -0
index 91aa21d4070eb..1f2a7e1bb9e1f 100644
@@ -47,6 +47,11 @@ static int iris_set_interconnects(struct iris_inst *inst)
 	int ret;
 
 	mutex_lock(&core->lock);
+	if (core->removing) {
+		ret = -ENODEV;
+		goto exit;
+	}
+
 	list_for_each_entry(instance, &core->instances, list) {
 		if (!instance->max_input_data_size)
 			continue;
@@ -56,6 +61,7 @@ static int iris_set_interconnects(struct iris_inst *inst)
 
 	ret = iris_set_icc_bw(core, total_bw_ddr);
 
+exit:
 	mutex_unlock(&core->lock);
 
 	return ret;
@@ -83,6 +89,11 @@ static int iris_set_clocks(struct iris_inst *inst)
 	int ret;
 
 	mutex_lock(&core->lock);
+	if (core->removing) {
+		ret = -ENODEV;
+		goto exit;
+	}
+
 	list_for_each_entry(instance, &core->instances, list) {
 		if (!instance->max_input_data_size)
 			continue;
@@ -92,6 +103,8 @@ static int iris_set_clocks(struct iris_inst *inst)
 
 	core->power.clk_freq = freq;
 	ret = iris_opp_set_rate(core->dev, freq);
+
+exit:
 	mutex_unlock(&core->lock);
 
 	return ret;
drivers/media/platform/qcom/iris/iris_probe.c +35 -9

83 lines not on this page · raw message

drivers/media/platform/qcom/iris/iris_vidc.c +3 -0
index 05aab6e3005d5..04bd37b934457 100644
@@ -64,6 +64,9 @@ static int iris_add_session(struct iris_inst *inst)
 
 	guard(mutex)(&core->lock);
 
+	if (core->removing)
+		return -ENODEV;
+
 	list_for_each_entry(iter, &core->instances, list)
 		count++;
 
Signature · 1 line
2.34.1
#4 lore raw

Re: [PATCH v2 3/5] media: iris: Fix use-after-free on unbind with open sessions

Quoted 104 lines · Vishnu Reddy

The driver can be unbound through sysfs while a client has a video session open. The core is devm allocated and freed when remove() returns, so the open sessions then use freed memory.

Only the core structure needs to outlive remove(), because it is the only thing the file operations of an open session still use. Allocate it with kzalloc and tie it to the reference count of its v4l2_device, which every registered video device holds. It is freed when the last file descriptor is closed. The other devm resources (register mapping, response packet, clocks, power domains, interconnects) are only used by the power on/off sequence, the clock and bandwidth votes and the interrupt handler. All of them are released with the unbind, after the core is shut down.

To make sure nothing uses them afterwards, set a removing flag at the start of iris_remove(). It makes core init, new sessions, command writes and the clock and interconnect votes fail with -ENODEV, so a client still holding a file descriptor cannot power the hardware on or vote for resources that are gone. A client waiting for the firmware only times out and returns an error without touching them. Runtime PM is also disabled explicitly in iris_remove() instead of with devm, because its callbacks use the core.

Fixes 38506cb7e8d2 ("media: iris: add platform driver for iris video device")
---
  drivers/media/platform/qcom/iris/iris_core.c      | 10 +++++-
  drivers/media/platform/qcom/iris/iris_core.h      |  2 ++
  drivers/media/platform/qcom/iris/iris_hfi_queue.c | 15 +++++++-
  drivers/media/platform/qcom/iris/iris_power.c     | 13 +++++++
  drivers/media/platform/qcom/iris/iris_probe.c     | 44 ++++++++++++++++++-----
  drivers/media/platform/qcom/iris/iris_vidc.c      |  3 ++
  6 files changed, 76 insertions(+), 11 deletions(-)
drivers/media/platform/qcom/iris/iris_core.c +9 -1
index d558475986ff0..bdac6b8c98e44 100644
@@ -43,7 +43,10 @@ static int iris_wait_for_system_response(struct iris_core *core)
  	ret = wait_for_completion_timeout(&core->core_init_done,
  					  msecs_to_jiffies(HW_RESPONSE_TIMEOUT_VALUE));
  	if (!ret) {
-		core->state = IRIS_CORE_ERROR;
+		mutex_lock(&core->lock);
+		if (!core->removing)
+			core->state = IRIS_CORE_ERROR;
+		mutex_unlock(&core->lock);
  		return -ETIMEDOUT;
  	}
 
@@ -56,6 +59,11 @@ int iris_core_init(struct iris_core *core)
  	int ret;
 
  	mutex_lock(&core->lock);
+	if (core->removing) {
+		ret = -ENODEV;
+		goto exit;
+	}
+
  	if (core->state == IRIS_CORE_INIT) {
  		ret = 0;
  		goto exit;
drivers/media/platform/qcom/iris/iris_core.h +2 -0
index 3e4cf652bf39a..379f0666a42cb 100644
@@ -62,6 +62,7 @@ struct qcom_ubwc_cfg_data;
   * @iris_firmware_desc: a pointer to the firmware-specific descriptive data
   * @ubwc_cfg: UBWC configuration for the platform
   * @state: current state of core
+ * @removing: set when driver removal starts, blocks core init and resource votes
   * @iface_q_table_daddr: device address for interface queue table memory
   * @sfr_daddr: device address for SFR (Sub System Failure Reason) register memory
   * @iface_q_table_vaddr: virtual address for interface queue table memory
@@ -108,6 +109,7 @@ struct iris_core {
  	const struct iris_firmware_desc		*iris_firmware_desc;
  	const struct qcom_ubwc_cfg_data		*ubwc_cfg;
  	enum iris_core_state			state;
+	bool					removing;
  	dma_addr_t				iface_q_table_daddr;
  	dma_addr_t				sfr_daddr;
  	void					*iface_q_table_vaddr;
drivers/media/platform/qcom/iris/iris_hfi_queue.c +8 -1
index 545bbe75e1740..e0cfa5107d1d9 100644
@@ -128,13 +128,26 @@ int iris_hfi_queue_cmd_write_locked(struct iris_core *core, void *pkt, u32 pkt_s
 
  int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size)
  {
-	int ret;
+	int ret = 0;
+
+	mutex_lock(&core->lock);
+	if (core->removing)
+		ret = -ENODEV;
+	mutex_unlock(&core->lock);
+	if (ret)
+		return ret;
 
  	ret = pm_runtime_resume_and_get(core->dev);

drivers/media/platform/qcom/iris/iris_hfi_queue.c int iris_hfi_queue_cmd_write_locked(struct iris_core *core, void *pkt, u32 pkt_s · line 150

Quoted 10 lines
drivers/media/platform/qcom/iris/iris_hfi_queue.c +6 -0
  	if (ret < 0)
  		return ret;
 
  	mutex_lock(&core->lock);
+	if (core->removing) {
+		mutex_unlock(&core->lock);
+		ret = -ENODEV;
+		goto exit;
+	}
+

This locking scheme is looks racy, what's the point of this granularity ?

---
bod

#5 lore raw

Re: [PATCH v2 3/5] media: iris: Fix use-after-free on unbind with open sessions

Quoted 112 lines · Bryan O'Donoghue
Quoted 111 lines · Vishnu Reddy

The driver can be unbound through sysfs while a client has a video session open. The core is devm allocated and freed when remove() returns, so the open sessions then use freed memory.

Only the core structure needs to outlive remove(), because it is the only thing the file operations of an open session still use. Allocate it with kzalloc and tie it to the reference count of its v4l2_device, which every registered video device holds. It is freed when the last file descriptor is closed. The other devm resources (register mapping, response packet, clocks, power domains, interconnects) are only used by the power on/off sequence, the clock and bandwidth votes and the interrupt handler. All of them are released with the unbind, after the core is shut down.

To make sure nothing uses them afterwards, set a removing flag at the start of iris_remove(). It makes core init, new sessions, command writes and the clock and interconnect votes fail with -ENODEV, so a client still holding a file descriptor cannot power the hardware on or vote for resources that are gone. A client waiting for the firmware only times out and returns an error without touching them. Runtime PM is also disabled explicitly in iris_remove() instead of with devm, because its callbacks use the core.

Fixes 38506cb7e8d2 ("media: iris: add platform driver for iris video device")

---
  drivers/media/platform/qcom/iris/iris_core.c      | 10 +++++- drivers/media/platform/qcom/iris/iris_core.h      |  2 ++ drivers/media/platform/qcom/iris/iris_hfi_queue.c | 15 +++++++- drivers/media/platform/qcom/iris/iris_power.c     | 13 +++++++ drivers/media/platform/qcom/iris/iris_probe.c     | 44 ++++++++++++++++++----- drivers/media/platform/qcom/iris/iris_vidc.c      |  3 ++

  6 files changed, 76 insertions(+), 11 deletions(-)
drivers/media/platform/qcom/iris/iris_core.c +4 -1
index d558475986ff0..bdac6b8c98e44 100644
@@ -43,7 +43,10 @@ static int iris_wait_for_system_response(struct iris_core
 *core)
       ret = wait_for_completion_timeout(&core->core_init_done,
                         msecs_to_jiffies(HW_RESPONSE_TIMEOUT_VALUE));
       if (!ret) {
-        core->state = IRIS_CORE_ERROR;
+        mutex_lock(&core->lock);
+        if (!core->removing)
+            core->state = IRIS_CORE_ERROR;
+        mutex_unlock(&core->lock);
           return -ETIMEDOUT;
       }

  @@ -56,6 +59,11 @@ int iris_core_init(struct iris_core *core) int ret;
        mutex_lock(&core->lock);
+    if (core->removing) {
+        ret = -ENODEV;
+        goto exit;
+    }
+
      if (core->state == IRIS_CORE_INIT) {
          ret = 0;
          goto exit;

drivers/media/platform/qcom/iris/iris_core.h +1 -0
index 3e4cf652bf39a..379f0666a42cb 100644
@@ -62,6 +62,7 @@ struct qcom_ubwc_cfg_data;
    * @iris_firmware_desc: a pointer to the firmware-specific descriptive data
    * @ubwc_cfg: UBWC configuration for the platform
    * @state: current state of core
+ * @removing: set when driver removal starts, blocks core init and resource

votes
   * @iface_q_table_daddr: device address for interface queue table memory
   * @sfr_daddr: device address for SFR (Sub System Failure Reason) register memory
   * @iface_q_table_vaddr: virtual address for interface queue table memory

drivers/media/platform/qcom/iris/iris_core.h +1 -0
@@ -108,6 +109,7 @@ struct iris_core {
       const struct iris_firmware_desc        *iris_firmware_desc;
       const struct qcom_ubwc_cfg_data        *ubwc_cfg;
       enum iris_core_state            state;
+    bool                    removing;
       dma_addr_t                iface_q_table_daddr;
       dma_addr_t                sfr_daddr;
       void                    *iface_q_table_vaddr;
drivers/media/platform/qcom/iris/iris_hfi_queue.c +0 -0
index 545bbe75e1740..e0cfa5107d1d9 100644
@@ -128,13 +128,26 @@ int iris_hfi_queue_cmd_write_locked(struct iris_core
 *core, void *pkt, u32 pkt_s

    int iris_hfi_queue_cmd_write(struct iris_core *core, void *pkt, u32 pkt_size)
  {
-    int ret;
+    int ret = 0;
+
+    mutex_lock(&core->lock);
+    if (core->removing)
+        ret = -ENODEV;
+    mutex_unlock(&core->lock);
+    if (ret)
+        return ret;
        ret = pm_runtime_resume_and_get(core->dev);
      if (ret < 0)
          return ret;
        mutex_lock(&core->lock);

Quoted 8 lines
Quoted 6 lines

+    if (core->removing) {
+        mutex_unlock(&core->lock);
+        ret = -ENODEV;
+        goto exit;
+    }
+

This locking scheme is looks racy, what's the point of this granularity ?

The first check is an early reject when removal is already in progress. The second re-validates the state after resume, since iris_remove() can start while pm_runtime_resume_and_get() is in progress. Without the second check, a command could be issued after teardown has started. Also, core->lock cannot be held across the entire function because iris_resume() also acquires core->lock.

Quoted 3 lines

---
bod

#6 lore raw

PATCH v2 4/5 media: iris: Wake up blocked clients when the driver is removed

In reply to Vishnu Reddy

iris_remove() does not wake up a client that is blocked in VIDIOC_DQBUF or poll() on an open session. The client stays blocked and keeps its file descriptor open.

Flag the vb2 queues of all open instances as errored after the core is shut down. This wakes up the blocked clients, which fail with an error and can close the file descriptor. Skip the instances that are already closing, as iris_close() releases their queues.

Fixes 38506cb7e8d2 ("media: iris: add platform driver for iris video device")
---
 drivers/media/platform/qcom/iris/iris_instance.h |  2 ++
 drivers/media/platform/qcom/iris/iris_probe.c    | 16 ++++++++++++++++
 drivers/media/platform/qcom/iris/iris_vidc.c     |  5 +++++
 3 files changed, 23 insertions(+)
drivers/media/platform/qcom/iris/iris_instance.h +2 -0
index 771269e705d9..cb84753e4f91 100644
@@ -50,6 +50,7 @@ struct iris_hfi_session_ops;
  * @icc_data: structure of interconnect data
  * @m2m_dev:	a reference to m2m device structure
  * @m2m_ctx:	a reference to m2m context structure
+ * @closing: set on close, skips the queue error during removal
  * @sequence_cap: a sequence counter for capture queue
  * @sequence_out: a sequence counter for output queue
  * @tss: timestamp metadata
@@ -98,6 +99,7 @@ struct iris_inst {
 	struct icc_vote_data		icc_data;
 	struct v4l2_m2m_dev		*m2m_dev;
 	struct v4l2_m2m_ctx		*m2m_ctx;
+	bool				closing;
 	u32				sequence_cap;
 	u32				sequence_out;
 	struct iris_ts_metadata		tss[VIDEO_MAX_FRAME];
drivers/media/platform/qcom/iris/iris_probe.c +16 -0
index dc83daccea5f..51054862bc64 100644
@@ -12,8 +12,10 @@
 #include <linux/reset.h>
 #include <linux/soc/qcom/ubwc.h>
 
+#include "iris_buffer.h"
 #include "iris_core.h"
 #include "iris_ctrls.h"
+#include "iris_instance.h"
 #include "iris_vidc.h"
 
 static int iris_init_icc(struct iris_core *core)
@@ -259,6 +261,18 @@ static void iris_core_put(void *data)
 	v4l2_device_put(&core->v4l2_dev);
 }
 
+static void iris_instances_vb2_queue_error(struct iris_core *core)
+{
+	struct iris_inst *inst;
+
+	mutex_lock(&core->lock);
+	list_for_each_entry(inst, &core->instances, list) {
+		if (!inst->closing)
+			iris_vb2_queue_error(inst);
+	}
+	mutex_unlock(&core->lock);
+}
+
 static void iris_remove(struct platform_device *pdev)
 {
 	struct iris_core *core;
@@ -278,6 +292,8 @@ static void iris_remove(struct platform_device *pdev)
 
 	iris_core_deinit(core);
 
+	iris_instances_vb2_queue_error(core);
+
 	pm_runtime_dont_use_autosuspend(core->dev);
 	pm_runtime_disable(core->dev);
 
drivers/media/platform/qcom/iris/iris_vidc.c +5 -0
index 04bd37b93445..bb3519eff3b1 100644
@@ -312,6 +312,11 @@ static void iris_check_num_queued_internal_buffers(struct iris_inst *inst, u32 p
 int iris_close(struct file *filp)
 {
 	struct iris_inst *inst = iris_get_inst(filp);
+	struct iris_core *core = inst->core;
+
+	mutex_lock(&core->lock);
+	inst->closing = true;
+	mutex_unlock(&core->lock);
 
 	v4l2_ctrl_handler_free(&inst->ctrl_handler);
 	v4l2_m2m_ctx_release(inst->m2m_ctx);
Signature · 1 line
2.34.1
#7 lore raw

PATCH v2 5/5 media: iris: Free the interrupt in iris_remove()

In reply to Vishnu Reddy

The interrupt is requested with devm_request_threaded_irq(), so it is only freed after iris_remove() returns. Until then the threaded handler can still run while the rest of the removal is in progress.

Free the interrupt explicitly in iris_remove(), right after the core is shut down.

Fixes fb583a214337 ("media: iris: introduce host firmware interface with necessary hooks")
---
 drivers/media/platform/qcom/iris/iris_probe.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/media/platform/qcom/iris/iris_probe.c +2 -0
index 51054862bc64..925a450a8597 100644
@@ -292,6 +292,8 @@ static void iris_remove(struct platform_device *pdev)
 
 	iris_core_deinit(core);
 
+	devm_free_irq(core->dev, core->irq, core);
+
 	iris_instances_vb2_queue_error(core);
 
 	pm_runtime_dont_use_autosuspend(core->dev);
Signature · 1 line
2.34.1