summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2017-11-01 03:56:19 +1000
committerBen Skeggs <bskeggs@redhat.com>2017-11-02 13:32:21 +1000
commitcb7e88e70f52878f4be0fbcc04350cff72f67278 (patch)
tree84b9f512876fa08272a6958250cc7898ed28e8d1
parent6be4421a9f5f6d1e980a88e189453cb766744cac (diff)
drm/nouveau: hang drm client of a master
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>
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c20
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h3
2 files changed, 19 insertions, 4 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 632edb73ed53..a705e56f0e57 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -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)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 84b847042253..610245970c99 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -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;