diff mbox

[V2,2/4] exynos4-is: Move firmware request to subdev open()

Message ID 1399570516-29782-2-git-send-email-s.nawrocki@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Move the firmware request to the FIMC-IS-ISP subdev open callback
so we can avoid crashed on error paths in probe and deferred probing,
when firmware request was sheduled and is in progress while the
fimc-is device is being unregistered and its driver detached.

Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/media/platform/exynos4-is/fimc-is.c  |   31 ++++++++------------------
 drivers/media/platform/exynos4-is/fimc-is.h  |    2 +-
 drivers/media/platform/exynos4-is/fimc-isp.c |   10 ++++++++-
 3 files changed, 19 insertions(+), 24 deletions(-)
diff mbox

Patch

diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 5476dce..6bbb6ca 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -374,22 +374,22 @@  static void fimc_is_free_cpu_memory(struct fimc_is *is)
 			  is->memory.paddr);
 }
 
-static void fimc_is_load_firmware(const struct firmware *fw, void *context)
+int fimc_is_request_firmware(struct fimc_is *is, const char *fw_name)
 {
-	struct fimc_is *is = context;
+	const struct firmware *fw;
 	struct device *dev = &is->pdev->dev;
 	void *buf;
 	int ret;
 
-	if (fw == NULL) {
+	ret = request_firmware(&fw, fw_name, &is->pdev->dev);
+	if (ret < 0) {
 		dev_err(dev, "firmware request failed\n");
-		return;
+		return ret;
 	}
-	mutex_lock(&is->lock);
 
 	if (fw->size < FIMC_IS_FW_SIZE_MIN || fw->size > FIMC_IS_FW_SIZE_MAX) {
 		dev_err(dev, "wrong firmware size: %d\n", fw->size);
-		goto done;
+		return -EINVAL;
 	}
 
 	is->fw.size = fw->size;
@@ -397,7 +397,7 @@  static void fimc_is_load_firmware(const struct firmware *fw, void *context)
 	ret = fimc_is_alloc_cpu_memory(is);
 	if (ret < 0) {
 		dev_err(dev, "failed to allocate FIMC-IS CPU memory\n");
-		goto done;
+		return -ENOMEM;
 	}
 
 	memcpy(is->memory.vaddr, fw->data, fw->size);
@@ -430,16 +430,9 @@  static void fimc_is_load_firmware(const struct firmware *fw, void *context)
 	 */
 	if (is->fw.f_w)
 		release_firmware(is->fw.f_w);
-	is->fw.f_w = fw;
-done:
-	mutex_unlock(&is->lock);
-}
 
-static int fimc_is_request_firmware(struct fimc_is *is, const char *fw_name)
-{
-	return request_firmware_nowait(THIS_MODULE,
-				FW_ACTION_HOTPLUG, fw_name, &is->pdev->dev,
-				GFP_KERNEL, is, fimc_is_load_firmware);
+	is->fw.f_w = fw;
+	return 0;
 }
 
 /* General IS interrupt handler */
@@ -795,7 +788,6 @@  static int fimc_is_probe(struct platform_device *pdev)
 
 	init_waitqueue_head(&is->irq_queue);
 	spin_lock_init(&is->slock);
-	mutex_init(&is->lock);
 
 	ret = of_address_to_resource(dev->of_node, 0, &res);
 	if (ret < 0)
@@ -859,17 +851,12 @@  static int fimc_is_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err_sd;
 
-	ret = fimc_is_request_firmware(is, FIMC_IS_FW_FILENAME);
-	if (ret < 0)
-		goto err_dfs;
 
 	pm_runtime_put_sync(dev);
 
 	dev_dbg(dev, "FIMC-IS registered successfully\n");
 	return 0;
 
-err_dfs:
-	fimc_is_debugfs_remove(is);
 err_sd:
 	fimc_is_unregister_subdevs(is);
 err_vb:
diff --git a/drivers/media/platform/exynos4-is/fimc-is.h b/drivers/media/platform/exynos4-is/fimc-is.h
index e0be691..16afd9c 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.h
+++ b/drivers/media/platform/exynos4-is/fimc-is.h
@@ -234,7 +234,6 @@  struct chain_config {
  * @pctrl: pointer to pinctrl structure for this device
  * @v4l2_dev: pointer to top the level v4l2_device
  * @alloc_ctx: videobuf2 memory allocator context
- * @lock: mutex serializing video device and the subdev operations
  * @slock: spinlock protecting this data structure and the hw registers
  * @clocks: FIMC-LITE gate clock
  * @regs: MCUCTL mmapped registers region
@@ -336,6 +335,7 @@  static inline u32 pmuisp_read(struct fimc_is *is, unsigned int offset)
 
 int fimc_is_wait_event(struct fimc_is *is, unsigned long bit,
 		       unsigned int state, unsigned int timeout);
+int fimc_is_request_firmware(struct fimc_is *is, const char *fw_name);
 int fimc_is_cpu_set_power(struct fimc_is *is, int on);
 int fimc_is_start_firmware(struct fimc_is *is);
 int fimc_is_hw_initialize(struct fimc_is *is);
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index be62d6b..915c46b 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -366,8 +366,11 @@  static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
 static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
 				struct v4l2_subdev_fh *fh)
 {
+	struct fimc_isp *isp = v4l2_get_subdevdata(sd);
+	struct fimc_is *is = fimc_isp_to_is(isp);
 	struct v4l2_mbus_framefmt fmt;
 	struct v4l2_mbus_framefmt *format;
+	int ret;
 
 	format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SINK);
 
@@ -386,7 +389,12 @@  static int fimc_isp_subdev_open(struct v4l2_subdev *sd,
 	format = v4l2_subdev_get_try_format(fh, FIMC_ISP_SD_PAD_SRC_DMA);
 	*format = fmt;
 
-	return 0;
+	mutex_lock(&isp->subdev_lock);
+	if (is->fw.f_w == NULL)
+		ret = fimc_is_request_firmware(is, FIMC_IS_FW_FILENAME);
+
+	mutex_unlock(&isp->subdev_lock);
+	return ret;
 }
 
 static int fimc_isp_subdev_registered(struct v4l2_subdev *sd)