drm/nouveau: hang drm client of a master
authorBen Skeggs <bskeggs@redhat.com>
Tue, 31 Oct 2017 17:56:19 +0000 (03:56 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 2 Nov 2017 03:32:21 +0000 (13:32 +1000)
TTM memory allocations will be hanging off the DRM's client, but the
locking needed to do so gets really tricky with all the other use of
the DRM's object tree.

To solve this, we make the normal DRM client a child of a new master,
where the memory allocations will be done from instead.

This also solves a potential race with client creation.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drv.h

index 632edb73ed5381324823da0a925534071fe3bdef..a705e56f0e578abafec58eeaabc9fb589341739c 100644 (file)
@@ -117,7 +117,9 @@ 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);
+       mutex_lock(&cli->drm->master.lock);
        nvif_client_fini(&cli->base);
+       mutex_unlock(&cli->drm->master.lock);
 }
 
 static int
@@ -132,12 +134,16 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname,
        mutex_init(&cli->mutex);
        usif_client_init(cli);
 
-       if (cli == &drm->client) {
+       mutex_init(&cli->lock);
+
+       if (cli == &drm->master) {
                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,
+               mutex_lock(&drm->master.lock);
+               ret = nvif_client_init(&drm->master.base, cli->name, device,
                                       &cli->base);
+               mutex_unlock(&drm->master.lock);
        }
        if (ret) {
                NV_ERROR(drm, "Client allocation failed: %d\n", ret);
@@ -433,6 +439,10 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        dev->dev_private = drm;
        drm->dev = dev;
 
+       ret = nouveau_cli_init(drm, "DRM-master", &drm->master);
+       if (ret)
+               return ret;
+
        ret = nouveau_cli_init(drm, "DRM", &drm->client);
        if (ret)
                return ret;
@@ -518,6 +528,7 @@ fail_ttm:
        nouveau_vga_fini(drm);
 fail_device:
        nouveau_cli_fini(&drm->client);
+       nouveau_cli_fini(&drm->master);
        kfree(drm);
        return ret;
 }
@@ -550,6 +561,7 @@ nouveau_drm_unload(struct drm_device *dev)
        if (drm->hdmi_device)
                pci_dev_put(drm->hdmi_device);
        nouveau_cli_fini(&drm->client);
+       nouveau_cli_fini(&drm->master);
        kfree(drm);
 }
 
@@ -618,7 +630,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime)
        }
 
        NV_DEBUG(drm, "suspending object tree...\n");
-       ret = nvif_client_suspend(&drm->client.base);
+       ret = nvif_client_suspend(&drm->master.base);
        if (ret)
                goto fail_client;
 
@@ -642,7 +654,7 @@ nouveau_do_resume(struct drm_device *dev, bool runtime)
        struct nouveau_drm *drm = nouveau_drm(dev);
 
        NV_DEBUG(drm, "resuming object tree...\n");
-       nvif_client_resume(&drm->client.base);
+       nvif_client_resume(&drm->master.base);
 
        NV_DEBUG(drm, "resuming fence...\n");
        if (drm->fence && nouveau_fence(drm)->resume)
index 84b84704225392fb3e49d314b7f86b5959d04ad3..610245970c991d60e3810137386124b34f235b28 100644 (file)
@@ -97,6 +97,8 @@ struct nouveau_cli {
        struct list_head objects;
        struct list_head notifys;
        char name[32];
+
+       struct mutex lock;
 };
 
 static inline struct nouveau_cli *
@@ -109,6 +111,7 @@ nouveau_cli(struct drm_file *fpriv)
 #include <nvif/device.h>
 
 struct nouveau_drm {
+       struct nouveau_cli master;
        struct nouveau_cli client;
        struct drm_device *dev;