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 <bske...@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