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.nawro...@samsung.com>
Acked-by: Kyungmin Park <kyungmin.p...@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 --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)
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to