gpu: host1x-nvhost: Fix client unloading

After unloading the NVDLA driver and then reloading the NVDLA, the
kernel is crashing. The host1x-nvhost driver is missing a call to
class_destroy() in nvhost_client_device_release() which gets called when
removing the DLA driver and this is preventing the DLA driver from
creating the class again when reloading. The crash then occurs because
when the driver is reloaded, creating the class for the DLA driver
fails and then the host1x-nvhost driver incorrectly calls
device_destroy() even though the device has not been created yet. Fix
this by ensuring the class_destroy() is called by
nvhost_client_device_release() and in the necessary error paths and then
remove the call to device_destroy().

Finally, replace request_irq() with devm_request_irq() to ensure that
the interrupts are also released as necessary on removal.

Bug 3641820

Change-Id: Ia328bf63d528e8c31bff1d7b3ac0d5dddc22f1f5
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2710546
Reviewed-by: svcacv <svcacv@nvidia.com>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Jon Hunter
2022-05-10 16:11:19 +01:00
committed by Laxman Dewangan
parent c103925414
commit ad8058fce9

View File

@@ -106,6 +106,7 @@ static struct device *nvhost_client_device_create(struct platform_device *pdev,
err = cdev_add(cdev, devno, 1);
if (err < 0) {
dev_err(&pdev->dev, "failed to add cdev\n");
class_destroy(pdata->nvhost_class);
return ERR_PTR(err);
}
@@ -115,6 +116,7 @@ static struct device *nvhost_client_device_create(struct platform_device *pdev,
if (IS_ERR(dev)) {
dev_err(&pdev->dev, "failed to create %s device\n", cdev_name);
class_destroy(pdata->nvhost_class);
cdev_del(cdev);
}
@@ -156,19 +158,12 @@ int nvhost_client_device_init(struct platform_device *pdev)
pdata->ctrl_node = nvhost_client_device_create(pdev, &pdata->ctrl_cdev,
"ctrl-", devno,
pdata->ctrl_ops);
if (IS_ERR(pdata->ctrl_node)) {
err = PTR_ERR(pdata->ctrl_node);
goto destroy;
}
if (IS_ERR(pdata->ctrl_node))
return PTR_ERR(pdata->ctrl_node);
pdata->cdev_region = devno;
return 0;
destroy:
device_destroy(pdata->nvhost_class, pdata->ctrl_cdev.dev);
return err;
}
EXPORT_SYMBOL(nvhost_client_device_init);
@@ -179,6 +174,7 @@ int nvhost_client_device_release(struct platform_device *pdev)
if (!IS_ERR_OR_NULL(pdata->ctrl_node)) {
device_destroy(pdata->nvhost_class, pdata->ctrl_cdev.dev);
cdev_del(&pdata->ctrl_cdev);
class_destroy(pdata->nvhost_class);
}
unregister_chrdev_region(pdata->cdev_region, NVHOST_NUM_CDEV);
@@ -418,7 +414,8 @@ int flcn_intr_init(struct platform_device *pdev)
}
spin_lock_init(&pdata->mirq_lock);
ret = request_irq(pdata->irq, flcn_isr, 0, dev_name(&pdev->dev), pdev);
ret = devm_request_irq(&pdev->dev, pdata->irq, flcn_isr, 0,
dev_name(&pdev->dev), pdev);
if (ret) {
dev_err(&pdev->dev, "failed to request irq. err %d\n", ret);
return ret;