On Wed, Jun 17, 2020 at 08:15:50PM +0300, Dan Carpenter wrote: > There were a couple problems with error handling in the probe function: > 1) If the "drvdata" allocation failed then it lead to a NULL > dereference. > 2) On several error paths we decremented "nr_cti_cpu" before it was > incremented which lead to a reference counting bug. > > There were also some parts of the error handling which were not bugs but > were messy. The error handling was confusing to read. It printed some > unnecessary error messages. > > The simplest way to fix these problems was to create a cti_pm_setup() > function that did all the power management setup in one go. That way > when we call cti_pm_release() we don't have to deal with the > complications of a partially configured power management config. > > I reversed the "if (drvdata->ctidev.cpu >= 0)" condition in cti_pm_release() > so that it mirros the new cti_pm_setup() function. > > Fixes: 6a0953ce7de9 ("coresight: cti: Add CPU idle pm notifer to CTI devices") > Signed-off-by: Dan Carpenter <dan.carpenter@xxxxxxxxxx> > --- > v2: I accidentally introduced a bug in cti_pm_release() in v1. Thanks for the cleanup. I'll send this to Greg for a 5.8 fixup. Regards, Mathieu > > drivers/hwtracing/coresight/coresight-cti.c | 96 ++++++++++++--------- > 1 file changed, 54 insertions(+), 42 deletions(-) > > diff --git a/drivers/hwtracing/coresight/coresight-cti.c b/drivers/hwtracing/coresight/coresight-cti.c > index 40387d58c8e7..d2da5bf9f552 100644 > --- a/drivers/hwtracing/coresight/coresight-cti.c > +++ b/drivers/hwtracing/coresight/coresight-cti.c > @@ -747,17 +747,50 @@ static int cti_dying_cpu(unsigned int cpu) > return 0; > } > > +static int cti_pm_setup(struct cti_drvdata *drvdata) > +{ > + int ret; > + > + if (drvdata->ctidev.cpu == -1) > + return 0; > + > + if (nr_cti_cpu) > + goto done; > + > + cpus_read_lock(); > + ret = cpuhp_setup_state_nocalls_cpuslocked( > + CPUHP_AP_ARM_CORESIGHT_CTI_STARTING, > + "arm/coresight_cti:starting", > + cti_starting_cpu, cti_dying_cpu); > + if (ret) { > + cpus_read_unlock(); > + return ret; > + } > + > + ret = cpu_pm_register_notifier(&cti_cpu_pm_nb); > + cpus_read_unlock(); > + if (ret) { > + cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_CTI_STARTING); > + return ret; > + } > + > +done: > + nr_cti_cpu++; > + cti_cpu_drvdata[drvdata->ctidev.cpu] = drvdata; > + > + return 0; > +} > + > /* release PM registrations */ > static void cti_pm_release(struct cti_drvdata *drvdata) > { > - if (drvdata->ctidev.cpu >= 0) { > - if (--nr_cti_cpu == 0) { > - cpu_pm_unregister_notifier(&cti_cpu_pm_nb); > + if (drvdata->ctidev.cpu == -1) > + return; > > - cpuhp_remove_state_nocalls( > - CPUHP_AP_ARM_CORESIGHT_CTI_STARTING); > - } > - cti_cpu_drvdata[drvdata->ctidev.cpu] = NULL; > + cti_cpu_drvdata[drvdata->ctidev.cpu] = NULL; > + if (--nr_cti_cpu == 0) { > + cpu_pm_unregister_notifier(&cti_cpu_pm_nb); > + cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_CTI_STARTING); > } > } > > @@ -823,19 +856,14 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) > > /* driver data*/ > drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); > - if (!drvdata) { > - ret = -ENOMEM; > - dev_info(dev, "%s, mem err\n", __func__); > - goto err_out; > - } > + if (!drvdata) > + return -ENOMEM; > > /* Validity for the resource is already checked by the AMBA core */ > base = devm_ioremap_resource(dev, res); > - if (IS_ERR(base)) { > - ret = PTR_ERR(base); > - dev_err(dev, "%s, remap err\n", __func__); > - goto err_out; > - } > + if (IS_ERR(base)) > + return PTR_ERR(base); > + > drvdata->base = base; > > dev_set_drvdata(dev, drvdata); > @@ -854,8 +882,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) > pdata = coresight_cti_get_platform_data(dev); > if (IS_ERR(pdata)) { > dev_err(dev, "coresight_cti_get_platform_data err\n"); > - ret = PTR_ERR(pdata); > - goto err_out; > + return PTR_ERR(pdata); > } > > /* default to powered - could change on PM notifications */ > @@ -867,35 +894,20 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) > drvdata->ctidev.cpu); > else > cti_desc.name = coresight_alloc_device_name(&cti_sys_devs, dev); > - if (!cti_desc.name) { > - ret = -ENOMEM; > - goto err_out; > - } > + if (!cti_desc.name) > + return -ENOMEM; > > /* setup CPU power management handling for CPU bound CTI devices. */ > - if (drvdata->ctidev.cpu >= 0) { > - cti_cpu_drvdata[drvdata->ctidev.cpu] = drvdata; > - if (!nr_cti_cpu++) { > - cpus_read_lock(); > - ret = cpuhp_setup_state_nocalls_cpuslocked( > - CPUHP_AP_ARM_CORESIGHT_CTI_STARTING, > - "arm/coresight_cti:starting", > - cti_starting_cpu, cti_dying_cpu); > - > - if (!ret) > - ret = cpu_pm_register_notifier(&cti_cpu_pm_nb); > - cpus_read_unlock(); > - if (ret) > - goto err_out; > - } > - } > + ret = cti_pm_setup(drvdata); > + if (ret) > + return ret; > > /* create dynamic attributes for connections */ > ret = cti_create_cons_sysfs(dev, drvdata); > if (ret) { > dev_err(dev, "%s: create dynamic sysfs entries failed\n", > cti_desc.name); > - goto err_out; > + goto pm_release; > } > > /* set up coresight component description */ > @@ -908,7 +920,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) > drvdata->csdev = coresight_register(&cti_desc); > if (IS_ERR(drvdata->csdev)) { > ret = PTR_ERR(drvdata->csdev); > - goto err_out; > + goto pm_release; > } > > /* add to list of CTI devices */ > @@ -927,7 +939,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id) > dev_info(&drvdata->csdev->dev, "CTI initialized\n"); > return 0; > > -err_out: > +pm_release: > cti_pm_release(drvdata); > return ret; > } > -- > 2.27.0