summaryrefslogtreecommitdiffstats
path: root/bsp/meta-rcar/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0447-media-soc_camera-rcar_vin-Fix-crash-when-the-module-.patch
blob: c6b384e88e0d91174ca5305a609e6cd2afccb764 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
From b7b603c33d7cc369f1165773a0f3fa14f7f71baf Mon Sep 17 00:00:00 2001
From: Valentine Barshak <valentine.barshak@cogentembedded.com>
Date: Sun, 8 Dec 2019 01:30:38 +0300
Subject: [PATCH] media: soc_camera: rcar_vin: Fix crash when the module is
 removed

The kernel may crash when removing rcar_csi2 or re-inserting
rcar_vin module after having removed it. This happens when
multiple ports are used. Multiple async clients are created
in this case. Each client registers a notifier which is added
to the notifier_list. However, only the last one, referenced
by the async_client pointer, is removed form the notifier_list
later when the rcar_vin module is removed.

Fix this issue by using a linked list and removing all the
async clients in the list when removing rcar_vin device.

Signed-off-by: Valentine Barshak <valentine.barshak@cogentembedded.com>
---
 drivers/media/platform/soc_camera/rcar_vin.c | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 501598c..e13a046 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -922,7 +922,7 @@ struct rcar_vin_priv {
 	bool				deser_sync;
 	int				lut_updated;
 
-	struct rcar_vin_async_client	*async_client;
+	struct list_head		async_client;
 	/* Asynchronous CSI2 linking */
 	struct v4l2_subdev		*csi2_sd;
 	/* Asynchronous Deserializer linking */
@@ -3032,7 +3032,7 @@ static int rcar_vin_soc_of_bind(struct rcar_vin_priv *priv,
 	sasc->notifier.num_subdevs = 1;
 	sasc->notifier.ops = &rcar_vin_sensor_ops;
 
-	priv->async_client = sasc;
+	list_add(&sasc->list, &priv->async_client);
 
 	client = of_find_i2c_device_by_node(remote);
 
@@ -3368,6 +3368,7 @@ static int rcar_vin_probe(struct platform_device *pdev)
 
 	spin_lock_init(&priv->lock);
 	INIT_LIST_HEAD(&priv->capture);
+	INIT_LIST_HEAD(&priv->async_client);
 
 	priv->state = STOPPED;
 
@@ -3417,11 +3418,16 @@ static int rcar_vin_remove(struct platform_device *pdev)
 	struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
 	struct rcar_vin_priv *priv = container_of(soc_host,
 						  struct rcar_vin_priv, ici);
+	struct rcar_vin_async_client *sasc, *tmp;
 
-	platform_device_del(priv->async_client->pdev);
-	platform_device_put(priv->async_client->pdev);
+	list_for_each_entry_safe(sasc, tmp, &priv->async_client, list) {
+		v4l2_async_notifier_unregister(&sasc->notifier);
+		v4l2_async_notifier_cleanup(&sasc->notifier);
+		list_del(&sasc->list);
 
-	v4l2_async_notifier_unregister(&priv->async_client->notifier);
+		platform_device_del(sasc->pdev);
+		platform_device_put(sasc->pdev);
+	}
 
 	soc_camera_host_unregister(soc_host);
 	pm_runtime_disable(&pdev->dev);
-- 
2.7.4