]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/blobdiff - drivers/gpu/drm/nouveau/nouveau_drm.c
Merge airlied/drm-next into drm-misc-next
[mirror_ubuntu-eoan-kernel.git] / drivers / gpu / drm / nouveau / nouveau_drm.c
index 279497b15e7be45726293647730c9e2178d6056b..d234a3b70bad6a50e18c1c74ec5280cb50b1049f 100644 (file)
@@ -37,6 +37,8 @@
 #include <core/pci.h>
 #include <core/tegra.h>
 
+#include <nvif/driver.h>
+
 #include <nvif/class.h>
 #include <nvif/cl0002.h>
 #include <nvif/cla06f.h>
@@ -109,35 +111,53 @@ nouveau_name(struct drm_device *dev)
                return nouveau_platform_name(dev->platformdev);
 }
 
+static void
+nouveau_cli_fini(struct nouveau_cli *cli)
+{
+       nvkm_vm_ref(NULL, &nvxx_client(&cli->base)->vm, NULL);
+       usif_client_fini(cli);
+       nvif_device_fini(&cli->device);
+       nvif_client_fini(&cli->base);
+}
+
 static int
-nouveau_cli_create(struct drm_device *dev, const char *sname,
-                  int size, void **pcli)
+nouveau_cli_init(struct nouveau_drm *drm, const char *sname,
+                struct nouveau_cli *cli)
 {
-       struct nouveau_cli *cli = *pcli = kzalloc(size, GFP_KERNEL);
+       u64 device = nouveau_name(drm->dev);
        int ret;
-       if (cli) {
-               snprintf(cli->name, sizeof(cli->name), "%s", sname);
-               cli->dev = dev;
 
-               ret = nvif_client_init(NULL, cli->name, nouveau_name(dev),
-                                      nouveau_config, nouveau_debug,
+       snprintf(cli->name, sizeof(cli->name), "%s", sname);
+       cli->dev = drm->dev;
+       mutex_init(&cli->mutex);
+       usif_client_init(cli);
+
+       if (cli == &drm->client) {
+               ret = nvif_driver_init(NULL, nouveau_config, nouveau_debug,
+                                      cli->name, device, &cli->base);
+       } else {
+               ret = nvif_client_init(&drm->client.base, cli->name, device,
                                       &cli->base);
-               if (ret == 0) {
-                       mutex_init(&cli->mutex);
-                       usif_client_init(cli);
-               }
-               return ret;
        }
-       return -ENOMEM;
-}
+       if (ret) {
+               NV_ERROR(drm, "Client allocation failed: %d\n", ret);
+               goto done;
+       }
 
-static void
-nouveau_cli_destroy(struct nouveau_cli *cli)
-{
-       nvkm_vm_ref(NULL, &nvxx_client(&cli->base)->vm, NULL);
-       nvif_client_fini(&cli->base);
-       usif_client_fini(cli);
-       kfree(cli);
+       ret = nvif_device_init(&cli->base.object, 0, NV_DEVICE,
+                              &(struct nv_device_v0) {
+                                       .device = ~0,
+                              }, sizeof(struct nv_device_v0),
+                              &cli->device);
+       if (ret) {
+               NV_ERROR(drm, "Device allocation failed: %d\n", ret);
+               goto done;
+       }
+
+done:
+       if (ret)
+               nouveau_cli_fini(cli);
+       return ret;
 }
 
 static void
@@ -161,7 +181,7 @@ nouveau_accel_fini(struct nouveau_drm *drm)
 static void
 nouveau_accel_init(struct nouveau_drm *drm)
 {
-       struct nvif_device *device = &drm->device;
+       struct nvif_device *device = &drm->client.device;
        struct nvif_sclass *sclass;
        u32 arg0, arg1;
        int ret, i, n;
@@ -215,7 +235,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
        }
 
        if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
-               ret = nouveau_channel_new(drm, &drm->device,
+               ret = nouveau_channel_new(drm, &drm->client.device,
                                          NVA06F_V0_ENGINE_CE0 |
                                          NVA06F_V0_ENGINE_CE1,
                                          0, &drm->cechan);
@@ -228,7 +248,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
        if (device->info.chipset >= 0xa3 &&
            device->info.chipset != 0xaa &&
            device->info.chipset != 0xac) {
-               ret = nouveau_channel_new(drm, &drm->device,
+               ret = nouveau_channel_new(drm, &drm->client.device,
                                          NvDmaFB, NvDmaTT, &drm->cechan);
                if (ret)
                        NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
@@ -240,7 +260,8 @@ nouveau_accel_init(struct nouveau_drm *drm)
                arg1 = NvDmaTT;
        }
 
-       ret = nouveau_channel_new(drm, &drm->device, arg0, arg1, &drm->channel);
+       ret = nouveau_channel_new(drm, &drm->client.device,
+                                 arg0, arg1, &drm->channel);
        if (ret) {
                NV_ERROR(drm, "failed to create kernel channel, %d\n", ret);
                nouveau_accel_fini(drm);
@@ -280,8 +301,8 @@ nouveau_accel_init(struct nouveau_drm *drm)
        }
 
        if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
-               ret = nvkm_gpuobj_new(nvxx_device(&drm->device), 32, 0, false,
-                                     NULL, &drm->notify);
+               ret = nvkm_gpuobj_new(nvxx_device(&drm->client.device), 32, 0,
+                                     false, NULL, &drm->notify);
                if (ret) {
                        NV_ERROR(drm, "failed to allocate notifier, %d\n", ret);
                        nouveau_accel_fini(drm);
@@ -407,12 +428,17 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        struct nouveau_drm *drm;
        int ret;
 
-       ret = nouveau_cli_create(dev, "DRM", sizeof(*drm), (void **)&drm);
+       if (!(drm = kzalloc(sizeof(*drm), GFP_KERNEL)))
+               return -ENOMEM;
+       dev->dev_private = drm;
+       drm->dev = dev;
+
+       ret = nouveau_cli_init(drm, "DRM", &drm->client);
        if (ret)
                return ret;
 
-       dev->dev_private = drm;
-       drm->dev = dev;
+       dev->irq_enabled = true;
+
        nvxx_client(&drm->client.base)->debug =
                nvkm_dbgopt(nouveau_debug, "DRM");
 
@@ -421,33 +447,24 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
 
        nouveau_get_hdmi_dev(drm);
 
-       ret = nvif_device_init(&drm->client.base.object, 0, NV_DEVICE,
-                              &(struct nv_device_v0) {
-                                       .device = ~0,
-                              }, sizeof(struct nv_device_v0),
-                              &drm->device);
-       if (ret)
-               goto fail_device;
-
-       dev->irq_enabled = true;
-
        /* workaround an odd issue on nvc1 by disabling the device's
         * nosnoop capability.  hopefully won't cause issues until a
         * better fix is found - assuming there is one...
         */
-       if (drm->device.info.chipset == 0xc1)
-               nvif_mask(&drm->device.object, 0x00088080, 0x00000800, 0x00000000);
+       if (drm->client.device.info.chipset == 0xc1)
+               nvif_mask(&drm->client.device.object, 0x00088080, 0x00000800, 0x00000000);
 
        nouveau_vga_init(drm);
 
-       if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
-               if (!nvxx_device(&drm->device)->mmu) {
+       if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
+               if (!nvxx_device(&drm->client.device)->mmu) {
                        ret = -ENOSYS;
                        goto fail_device;
                }
 
-               ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40),
-                                 0x1000, NULL, &drm->client.vm);
+               ret = nvkm_vm_new(nvxx_device(&drm->client.device),
+                                 0, (1ULL << 40), 0x1000, NULL,
+                                 &drm->client.vm);
                if (ret)
                        goto fail_device;
 
@@ -497,8 +514,8 @@ fail_bios:
 fail_ttm:
        nouveau_vga_fini(drm);
 fail_device:
-       nvif_device_fini(&drm->device);
-       nouveau_cli_destroy(&drm->client);
+       nouveau_cli_fini(&drm->client);
+       kfree(drm);
        return ret;
 }
 
@@ -527,10 +544,10 @@ nouveau_drm_unload(struct drm_device *dev)
        nouveau_ttm_fini(drm);
        nouveau_vga_fini(drm);
 
-       nvif_device_fini(&drm->device);
        if (drm->hdmi_device)
                pci_dev_put(drm->hdmi_device);
-       nouveau_cli_destroy(&drm->client);
+       nouveau_cli_fini(&drm->client);
+       kfree(drm);
 }
 
 void
@@ -560,7 +577,6 @@ static int
 nouveau_do_suspend(struct drm_device *dev, bool runtime)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_cli *cli;
        int ret;
 
        nouveau_led_suspend(dev);
@@ -590,7 +606,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
                        goto fail_display;
        }
 
-       NV_INFO(drm, "suspending client object trees...\n");
+       NV_INFO(drm, "suspending fence...\n");
        if (drm->fence && nouveau_fence(drm)->suspend) {
                if (!nouveau_fence(drm)->suspend(drm)) {
                        ret = -ENOMEM;
@@ -598,13 +614,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
                }
        }
 
-       list_for_each_entry(cli, &drm->clients, head) {
-               ret = nvif_client_suspend(&cli->base);
-               if (ret)
-                       goto fail_client;
-       }
-
-       NV_INFO(drm, "suspending kernel object tree...\n");
+       NV_INFO(drm, "suspending object tree...\n");
        ret = nvif_client_suspend(&drm->client.base);
        if (ret)
                goto fail_client;
@@ -612,10 +622,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
        return 0;
 
 fail_client:
-       list_for_each_entry_continue_reverse(cli, &drm->clients, head) {
-               nvif_client_resume(&cli->base);
-       }
-
        if (drm->fence && nouveau_fence(drm)->resume)
                nouveau_fence(drm)->resume(drm);
 
@@ -631,19 +637,14 @@ static int
 nouveau_do_resume(struct drm_device *dev, bool runtime)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_cli *cli;
 
-       NV_INFO(drm, "resuming kernel object tree...\n");
+       NV_INFO(drm, "resuming object tree...\n");
        nvif_client_resume(&drm->client.base);
 
-       NV_INFO(drm, "resuming client object trees...\n");
+       NV_INFO(drm, "resuming fence...\n");
        if (drm->fence && nouveau_fence(drm)->resume)
                nouveau_fence(drm)->resume(drm);
 
-       list_for_each_entry(cli, &drm->clients, head) {
-               nvif_client_resume(&cli->base);
-       }
-
        nouveau_run_vbios_init(dev);
 
        if (dev->mode_config.num_crtc) {
@@ -758,7 +759,7 @@ nouveau_pmops_runtime_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       struct nvif_device *device = &nouveau_drm(drm_dev)->device;
+       struct nvif_device *device = &nouveau_drm(drm_dev)->client.device;
        int ret;
 
        if (nouveau_runtime_pm == 0)
@@ -772,7 +773,10 @@ nouveau_pmops_runtime_resume(struct device *dev)
        pci_set_master(pdev);
 
        ret = nouveau_do_resume(drm_dev, true);
-       drm_kms_helper_poll_enable(drm_dev);
+
+       if (!drm_dev->mode_config.poll_enabled)
+               drm_kms_helper_poll_enable(drm_dev);
+
        /* do magic */
        nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25));
        vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
@@ -841,20 +845,20 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
        get_task_comm(tmpname, current);
        snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid));
 
-       ret = nouveau_cli_create(dev, name, sizeof(*cli), (void **)&cli);
+       if (!(cli = kzalloc(sizeof(*cli), GFP_KERNEL)))
+               return ret;
 
+       ret = nouveau_cli_init(drm, name, cli);
        if (ret)
-               goto out_suspend;
+               goto done;
 
        cli->base.super = false;
 
-       if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
-               ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40),
-                                 0x1000, NULL, &cli->vm);
-               if (ret) {
-                       nouveau_cli_destroy(cli);
-                       goto out_suspend;
-               }
+       if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
+               ret = nvkm_vm_new(nvxx_device(&drm->client.device), 0,
+                                 (1ULL << 40), 0x1000, NULL, &cli->vm);
+               if (ret)
+                       goto done;
 
                nvxx_client(&cli->base)->vm = cli->vm;
        }
@@ -865,10 +869,14 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
        list_add(&cli->head, &drm->clients);
        mutex_unlock(&drm->client.mutex);
 
-out_suspend:
+done:
+       if (ret && cli) {
+               nouveau_cli_fini(cli);
+               kfree(cli);
+       }
+
        pm_runtime_mark_last_busy(dev->dev);
        pm_runtime_put_autosuspend(dev->dev);
-
        return ret;
 }
 
@@ -895,7 +903,8 @@ static void
 nouveau_drm_postclose(struct drm_device *dev, struct drm_file *fpriv)
 {
        struct nouveau_cli *cli = nouveau_cli(fpriv);
-       nouveau_cli_destroy(cli);
+       nouveau_cli_fini(cli);
+       kfree(cli);
        pm_runtime_mark_last_busy(dev->dev);
        pm_runtime_put_autosuspend(dev->dev);
 }