diff mbox series

media: camss: Allocate power domain resources dynamically

Message ID 20220512082318.189398-1-vladimir.zapolskiy@linaro.org
State Accepted
Commit 6b1814e2698968a223af4f363dcb32fb2c74e265
Headers show
Series media: camss: Allocate power domain resources dynamically | expand

Commit Message

Vladimir Zapolskiy May 12, 2022, 8:23 a.m. UTC
To simplify the driver's maintenance it makes sense to escape from
hardcoded numbers of power domain resources per platform and statical
allocation of the resources. For instance on a QCOM SM8450 platform
the number of CAMSS power domains shall be bumped up to 6, also notably
CAMSS on MSM8916 has only one power domain, however it expects to get 2,
and thus it should result in a runtime error on driver probe.

The change fixes an issue mentioned above and gives more flexibility
to support more platforms in future.

Signed-off-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>
---
 drivers/media/platform/qcom/camss/camss.c | 38 +++++++++++++----------
 drivers/media/platform/qcom/camss/camss.h |  7 ++---
 2 files changed, 24 insertions(+), 21 deletions(-)

Comments

Marek Szyprowski June 17, 2022, 8:44 a.m. UTC | #1
On 12.05.2022 10:23, Vladimir Zapolskiy wrote:
> To simplify the driver's maintenance it makes sense to escape from
> hardcoded numbers of power domain resources per platform and statical
> allocation of the resources. For instance on a QCOM SM8450 platform
> the number of CAMSS power domains shall be bumped up to 6, also notably
> CAMSS on MSM8916 has only one power domain, however it expects to get 2,
> and thus it should result in a runtime error on driver probe.
>
> The change fixes an issue mentioned above and gives more flexibility
> to support more platforms in future.
>
> Signed-off-by: Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>

This patch landed recently in linux next-20220616 as commit f673698ceee5 
("media: camss: Allocate power domain resources dynamically"). 
Unfortunately it causes serious issues on DragonBoard 410c SBC 
(arch/arm64/boot/dts/qcom/apq8016-sbc.dts), like multiple 'Unable to 
handle kernel NULL pointer dereference at virtual address 0000000000000000'.

The problem originates in camss_configure_pd() function. Old version 
assigned 0 to camss->genpd_num on that board, while the new one sets it 
to 1 as a result of of_count_phandle_with_args(). When it is set to 1, 
it causes issues somewhere later in the code, the stack traces points to 
sysfs:

Unable to handle kernel NULL pointer dereference at virtual address 
0000000000000000
Mem abort info:
   ESR = 0x0000000096000006
   EC = 0x25: DABT (current EL), IL = 32 bits
   SET = 0, FnV = 0
   EA = 0, S1PTW = 0
   FSC = 0x06: level 2 translation fault
Data abort info:
   ISV = 0, ISS = 0x00000006
   CM = 0, WnR = 0
user pgtable: 4k pages, 48-bit VAs, pgdp=0000000080fba000
[0000000000000000] pgd=0800000080fd7003, p4d=0800000080fd7003, 
pud=0800000080fdb003, pmd=0000000000000000
Internal error: Oops: 96000006 [#2] PREEMPT SMP
Modules linked in: crct10dif_ce asix(+) qcom_wcnss_pil socinfo adv7511 
snd_soc_msm8916_digital snd_soc_lpass_apq8016 snd_soc_lpass_cpu 
snd_soc_lpass_platform snd_soc_apq8016_sbc snd_soc_qcom_common qrtr 
qcom_q6v5_mss qcom_pil_info qcom_q6v5 qcom_sysmon qcom_common 
qcom_glink_smem qmi_helpers snd_soc_msm8916_analog qcom_camss 
qnoc_msm8916 icc_smd_rpm videobuf2_dma_sg v4l2_fwnode 
qcom_spmi_temp_alarm v4l2_async rtc_pm8xxx videobuf2_memops venus_core 
qcom_pon v4l2_mem2mem videobuf2_v4l2 qcom_spmi_vadc qcom_vadc_common 
videobuf2_common qcom_rng qcom_stats msm videodev i2c_qcom_cci mc 
mdt_loader gpu_sched drm_dp_aux_bus display_connector rmtfs_mem
CPU: 0 PID: 255 Comm: systemd-udevd Tainted: G      D W 
5.19.0-rc2-next-20220616 #12197
Hardware name: Qualcomm Technologies, Inc. APQ 8016 SBC (DT)
pstate: 00000005 (nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : sysfs_kf_seq_show+0x34/0x140
lr : sysfs_kf_seq_show+0x30/0x140
ng swap..[   23.849418] sp : ffff80000c643bc0
...
Call trace:
  sysfs_kf_seq_show+0x34/0x140
  kernfs_seq_show+0x28/0x30
  seq_read_iter+0x118/0x440
  kernfs_fop_read_iter+0x11c/0x1b0
  new_sync_read+0xd0/0x188
  vfs_read+0x134/0x1d0
  ksys_read+0x64/0xf0
  __arm64_sys_read+0x14/0x20
  invoke_syscall+0x40/0xf8
  el0_svc_common.constprop.3+0x8c/0x120
  do_el0_svc_compat+0x18/0x48
  el0_svc_compat+0x48/0xd0
  el0t_32_sync_handler+0xec/0x140
  el0t_32_sync+0x160/0x164
Code: f9401821 f9404437 97fffe37 aa0003f5 (f9400000)
---[ end trace 0000000000000000 ]---


> ---
>   drivers/media/platform/qcom/camss/camss.c | 38 +++++++++++++----------
>   drivers/media/platform/qcom/camss/camss.h |  7 ++---
>   2 files changed, 24 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
> index 79ad82e233cb..32d72b4f947b 100644
> --- a/drivers/media/platform/qcom/camss/camss.c
> +++ b/drivers/media/platform/qcom/camss/camss.c
> @@ -1452,19 +1452,31 @@ static const struct media_device_ops camss_media_ops = {
>   
>   static int camss_configure_pd(struct camss *camss)
>   {
> -	int nbr_pm_domains = 0;
> +	struct device *dev = camss->dev;
>   	int last_pm_domain = 0;
>   	int i;
>   	int ret;
>   
> -	if (camss->version == CAMSS_8x96 ||
> -	    camss->version == CAMSS_660)
> -		nbr_pm_domains = PM_DOMAIN_GEN1_COUNT;
> -	else if (camss->version == CAMSS_845 ||
> -		 camss->version == CAMSS_8250)
> -		nbr_pm_domains = PM_DOMAIN_GEN2_COUNT;
> +	camss->genpd_num = of_count_phandle_with_args(dev->of_node,
> +						      "power-domains",
> +						      "#power-domain-cells");
> +	if (camss->genpd_num < 0) {
> +		dev_err(dev, "Power domains are not defined for camss\n");
> +		return camss->genpd_num;
> +	}
> +
> +	camss->genpd = devm_kmalloc_array(dev, camss->genpd_num,
> +					  sizeof(*camss->genpd), GFP_KERNEL);
> +	if (!camss->genpd)
> +		return -ENOMEM;
>   
> -	for (i = 0; i < nbr_pm_domains; i++) {
> +	camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num,
> +					       sizeof(*camss->genpd_link),
> +					       GFP_KERNEL);
> +	if (!camss->genpd_link)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < camss->genpd_num; i++) {
>   		camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
>   		if (IS_ERR(camss->genpd[i])) {
>   			ret = PTR_ERR(camss->genpd[i]);
> @@ -1689,7 +1701,6 @@ static int camss_probe(struct platform_device *pdev)
>   
>   void camss_delete(struct camss *camss)
>   {
> -	int nbr_pm_domains = 0;
>   	int i;
>   
>   	v4l2_device_unregister(&camss->v4l2_dev);
> @@ -1698,14 +1709,7 @@ void camss_delete(struct camss *camss)
>   
>   	pm_runtime_disable(camss->dev);
>   
> -	if (camss->version == CAMSS_8x96 ||
> -	    camss->version == CAMSS_660)
> -		nbr_pm_domains = PM_DOMAIN_GEN1_COUNT;
> -	else if (camss->version == CAMSS_845 ||
> -		 camss->version == CAMSS_8250)
> -		nbr_pm_domains = PM_DOMAIN_GEN2_COUNT;
> -
> -	for (i = 0; i < nbr_pm_domains; i++) {
> +	for (i = 0; i < camss->genpd_num; i++) {
>   		device_link_del(camss->genpd_link[i]);
>   		dev_pm_domain_detach(camss->genpd[i], true);
>   	}
> diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
> index c9b3e0df5be8..0db80cadbbaa 100644
> --- a/drivers/media/platform/qcom/camss/camss.h
> +++ b/drivers/media/platform/qcom/camss/camss.h
> @@ -69,9 +69,7 @@ struct resources_icc {
>   enum pm_domain {
>   	PM_DOMAIN_VFE0 = 0,
>   	PM_DOMAIN_VFE1 = 1,
> -	PM_DOMAIN_GEN1_COUNT = 2,	/* CAMSS series of ISPs */
>   	PM_DOMAIN_VFELITE = 2,		/* VFELITE / TOP GDSC */
> -	PM_DOMAIN_GEN2_COUNT = 3,	/* Titan series of ISPs */
>   };
>   
>   enum camss_version {
> @@ -101,8 +99,9 @@ struct camss {
>   	int vfe_num;
>   	struct vfe_device *vfe;
>   	atomic_t ref_count;
> -	struct device *genpd[PM_DOMAIN_GEN2_COUNT];
> -	struct device_link *genpd_link[PM_DOMAIN_GEN2_COUNT];
> +	int genpd_num;
> +	struct device **genpd;
> +	struct device_link **genpd_link;
>   	struct icc_path *icc_path[ICC_SM8250_COUNT];
>   	struct icc_bw_tbl icc_bw_tbl[ICC_SM8250_COUNT];
>   };

Best regards
diff mbox series

Patch

diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 79ad82e233cb..32d72b4f947b 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -1452,19 +1452,31 @@  static const struct media_device_ops camss_media_ops = {
 
 static int camss_configure_pd(struct camss *camss)
 {
-	int nbr_pm_domains = 0;
+	struct device *dev = camss->dev;
 	int last_pm_domain = 0;
 	int i;
 	int ret;
 
-	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660)
-		nbr_pm_domains = PM_DOMAIN_GEN1_COUNT;
-	else if (camss->version == CAMSS_845 ||
-		 camss->version == CAMSS_8250)
-		nbr_pm_domains = PM_DOMAIN_GEN2_COUNT;
+	camss->genpd_num = of_count_phandle_with_args(dev->of_node,
+						      "power-domains",
+						      "#power-domain-cells");
+	if (camss->genpd_num < 0) {
+		dev_err(dev, "Power domains are not defined for camss\n");
+		return camss->genpd_num;
+	}
+
+	camss->genpd = devm_kmalloc_array(dev, camss->genpd_num,
+					  sizeof(*camss->genpd), GFP_KERNEL);
+	if (!camss->genpd)
+		return -ENOMEM;
 
-	for (i = 0; i < nbr_pm_domains; i++) {
+	camss->genpd_link = devm_kmalloc_array(dev, camss->genpd_num,
+					       sizeof(*camss->genpd_link),
+					       GFP_KERNEL);
+	if (!camss->genpd_link)
+		return -ENOMEM;
+
+	for (i = 0; i < camss->genpd_num; i++) {
 		camss->genpd[i] = dev_pm_domain_attach_by_id(camss->dev, i);
 		if (IS_ERR(camss->genpd[i])) {
 			ret = PTR_ERR(camss->genpd[i]);
@@ -1689,7 +1701,6 @@  static int camss_probe(struct platform_device *pdev)
 
 void camss_delete(struct camss *camss)
 {
-	int nbr_pm_domains = 0;
 	int i;
 
 	v4l2_device_unregister(&camss->v4l2_dev);
@@ -1698,14 +1709,7 @@  void camss_delete(struct camss *camss)
 
 	pm_runtime_disable(camss->dev);
 
-	if (camss->version == CAMSS_8x96 ||
-	    camss->version == CAMSS_660)
-		nbr_pm_domains = PM_DOMAIN_GEN1_COUNT;
-	else if (camss->version == CAMSS_845 ||
-		 camss->version == CAMSS_8250)
-		nbr_pm_domains = PM_DOMAIN_GEN2_COUNT;
-
-	for (i = 0; i < nbr_pm_domains; i++) {
+	for (i = 0; i < camss->genpd_num; i++) {
 		device_link_del(camss->genpd_link[i]);
 		dev_pm_domain_detach(camss->genpd[i], true);
 	}
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index c9b3e0df5be8..0db80cadbbaa 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -69,9 +69,7 @@  struct resources_icc {
 enum pm_domain {
 	PM_DOMAIN_VFE0 = 0,
 	PM_DOMAIN_VFE1 = 1,
-	PM_DOMAIN_GEN1_COUNT = 2,	/* CAMSS series of ISPs */
 	PM_DOMAIN_VFELITE = 2,		/* VFELITE / TOP GDSC */
-	PM_DOMAIN_GEN2_COUNT = 3,	/* Titan series of ISPs */
 };
 
 enum camss_version {
@@ -101,8 +99,9 @@  struct camss {
 	int vfe_num;
 	struct vfe_device *vfe;
 	atomic_t ref_count;
-	struct device *genpd[PM_DOMAIN_GEN2_COUNT];
-	struct device_link *genpd_link[PM_DOMAIN_GEN2_COUNT];
+	int genpd_num;
+	struct device **genpd;
+	struct device_link **genpd_link;
 	struct icc_path *icc_path[ICC_SM8250_COUNT];
 	struct icc_bw_tbl icc_bw_tbl[ICC_SM8250_COUNT];
 };