[PATCH 07/21] drm/nouveau/nvkm: cleanup in nvkm_device_{pci, tegra}_new() on failure

Ben Skeggs bskeggs at nvidia.com
Thu Jun 13 16:59:59 UTC 2024


These previously depended on the caller calling nvkm_device_del() to
cleanup if nvkm_device_*_new() fails.

That's a little odd for starters, but only the Tegra path cleaned up,
and the PCI path would have leaked the memory, FWs etc that had been
allocated as NVKM ran each subdev's ctor().

A later patch turns these into pci/platform driver probe() functions,
so they need to learn how to clean up after themselves regardless.

Signed-off-by: Ben Skeggs <bskeggs at nvidia.com>
---
 drivers/gpu/drm/nouveau/nouveau_drm.c       |  2 +-
 drivers/gpu/drm/nouveau/nvkm/device/pci.c   | 26 ++++++++++++++-------
 drivers/gpu/drm/nouveau/nvkm/device/tegra.c | 11 +++++----
 3 files changed, 24 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 0bf39b05926f..6c1cfc38d8fa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -1351,7 +1351,7 @@ nouveau_platform_device_create(const struct nvkm_device_tegra_func *func,
 
 	err = nvkm_device_tegra_new(func, pdev, nouveau_config, nouveau_debug, pdevice);
 	if (err)
-		goto err_free;
+		return ERR_PTR(err);
 
 	drm = nouveau_drm_device_new(&driver_platform, &pdev->dev, *pdevice);
 	if (IS_ERR(drm)) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/device/pci.c
index 8bfedd79d7a5..e48f3219f047 100644
--- a/drivers/gpu/drm/nouveau/nvkm/device/pci.c
+++ b/drivers/gpu/drm/nouveau/nvkm/device/pci.c
@@ -1633,12 +1633,9 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg,
 	const struct nvkm_device_pci_vendor *pciv;
 	const char *name = NULL;
 	struct nvkm_device_pci *pdev;
+	struct nvkm_device *device;
 	int ret, bits;
 
-	ret = pci_enable_device(pci_dev);
-	if (ret)
-		return ret;
-
 	switch (pci_dev->vendor) {
 	case 0x10de: pcid = nvkm_device_pci_10de; break;
 	default:
@@ -1664,12 +1661,16 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg,
 		pcid++;
 	}
 
-	if (!(pdev = kzalloc(sizeof(*pdev), GFP_KERNEL))) {
-		pci_disable_device(pci_dev);
+	if (!(pdev = kzalloc(sizeof(*pdev), GFP_KERNEL)))
 		return -ENOMEM;
-	}
-	*pdevice = &pdev->device;
 	pdev->pdev = pci_dev;
+	device = &pdev->device;
+
+	ret = pci_enable_device(pci_dev);
+	if (ret) {
+		kfree(pdev);
+		return ret;
+	}
 
 	ret = nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev,
 			       pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE :
@@ -1682,7 +1683,7 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg,
 			       &pdev->device);
 
 	if (ret)
-		return ret;
+		goto done;
 
 	/* Set DMA mask based on capabilities reported by the MMU subdev. */
 	if (pdev->device.mmu && !pdev->device.pci->agp.bridge)
@@ -1696,5 +1697,12 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg,
 		pdev->device.mmu->dma_bits = 32;
 	}
 
+done:
+	if (ret) {
+		nvkm_device_del(&device);
+		return ret;
+	}
+
+	*pdevice = &pdev->device;
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/device/tegra.c
index bb514ccdfff4..9c3673c74b19 100644
--- a/drivers/gpu/drm/nouveau/nvkm/device/tegra.c
+++ b/drivers/gpu/drm/nouveau/nvkm/device/tegra.c
@@ -240,6 +240,7 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
 		      struct nvkm_device **pdevice)
 {
 	struct nvkm_device_tegra *tdev;
+	struct nvkm_device *device;
 	unsigned long rate;
 	int ret;
 
@@ -248,6 +249,7 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
 
 	tdev->func = func;
 	tdev->pdev = pdev;
+	device = &tdev->device;
 
 	if (func->require_vdd) {
 		tdev->vdd = devm_regulator_get(&pdev->dev, "vdd");
@@ -311,15 +313,14 @@ nvkm_device_tegra_new(const struct nvkm_device_tegra_func *func,
 	ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev,
 			       NVKM_DEVICE_TEGRA, pdev->id, NULL,
 			       &tdev->device);
-	if (ret)
-		goto powerdown;
+	if (ret) {
+		nvkm_device_del(&device);
+		return ret;
+	}
 
 	*pdevice = &tdev->device;
-
 	return 0;
 
-powerdown:
-	nvkm_device_tegra_power_down(tdev);
 remove:
 	nvkm_device_tegra_remove_iommu(tdev);
 free:
-- 
2.44.0



More information about the dri-devel mailing list