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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]<

 



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@xxxxxxxxxx>
---
 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




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux