diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_drm.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 149 |
1 files changed, 56 insertions, 93 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 051e7104106d..309be93de597 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -30,18 +30,10 @@ | |||
30 | #include "drmP.h" | 30 | #include "drmP.h" |
31 | #include "drm_crtc_helper.h" | 31 | #include "drm_crtc_helper.h" |
32 | #include <core/device.h> | 32 | #include <core/device.h> |
33 | #include <core/client.h> | ||
34 | #include <core/gpuobj.h> | 33 | #include <core/gpuobj.h> |
35 | #include <core/class.h> | 34 | #include <core/class.h> |
36 | #include <core/option.h> | 35 | #include <core/option.h> |
37 | 36 | ||
38 | #include <engine/device.h> | ||
39 | #include <engine/disp.h> | ||
40 | #include <engine/fifo.h> | ||
41 | #include <engine/software.h> | ||
42 | |||
43 | #include <subdev/vm.h> | ||
44 | |||
45 | #include "nouveau_drm.h" | 37 | #include "nouveau_drm.h" |
46 | #include "nouveau_dma.h" | 38 | #include "nouveau_dma.h" |
47 | #include "nouveau_ttm.h" | 39 | #include "nouveau_ttm.h" |
@@ -109,40 +101,34 @@ static int | |||
109 | nouveau_cli_create(u64 name, const char *sname, | 101 | nouveau_cli_create(u64 name, const char *sname, |
110 | int size, void **pcli) | 102 | int size, void **pcli) |
111 | { | 103 | { |
112 | struct nouveau_cli *cli; | 104 | struct nouveau_cli *cli = *pcli = kzalloc(size, GFP_KERNEL); |
113 | int ret; | 105 | if (cli) { |
114 | 106 | int ret = nvif_client_init(NULL, NULL, sname, name, | |
115 | *pcli = NULL; | 107 | nouveau_config, nouveau_debug, |
116 | ret = nouveau_client_create_(sname, name, nouveau_config, | 108 | &cli->base); |
117 | nouveau_debug, size, pcli); | 109 | if (ret == 0) |
118 | cli = *pcli; | 110 | mutex_init(&cli->mutex); |
119 | if (ret) { | ||
120 | if (cli) | ||
121 | nouveau_client_destroy(&cli->base); | ||
122 | *pcli = NULL; | ||
123 | return ret; | 111 | return ret; |
124 | } | 112 | } |
125 | 113 | return -ENOMEM; | |
126 | mutex_init(&cli->mutex); | ||
127 | return 0; | ||
128 | } | 114 | } |
129 | 115 | ||
130 | static void | 116 | static void |
131 | nouveau_cli_destroy(struct nouveau_cli *cli) | 117 | nouveau_cli_destroy(struct nouveau_cli *cli) |
132 | { | 118 | { |
133 | struct nouveau_object *client = nv_object(cli); | 119 | nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL); |
134 | nouveau_vm_ref(NULL, &cli->base.vm, NULL); | 120 | nvif_client_fini(&cli->base); |
135 | nouveau_client_fini(&cli->base, false); | ||
136 | atomic_set(&client->refcount, 1); | ||
137 | nouveau_object_ref(NULL, &client); | ||
138 | } | 121 | } |
139 | 122 | ||
140 | static void | 123 | static void |
141 | nouveau_accel_fini(struct nouveau_drm *drm) | 124 | nouveau_accel_fini(struct nouveau_drm *drm) |
142 | { | 125 | { |
143 | nouveau_gpuobj_ref(NULL, &drm->notify); | ||
144 | nouveau_channel_del(&drm->channel); | 126 | nouveau_channel_del(&drm->channel); |
127 | nvif_object_fini(&drm->ntfy); | ||
128 | nouveau_gpuobj_ref(NULL, &drm->notify); | ||
129 | nvif_object_fini(&drm->nvsw); | ||
145 | nouveau_channel_del(&drm->cechan); | 130 | nouveau_channel_del(&drm->cechan); |
131 | nvif_object_fini(&drm->ttm.copy); | ||
146 | if (drm->fence) | 132 | if (drm->fence) |
147 | nouveau_fence(drm)->dtor(drm); | 133 | nouveau_fence(drm)->dtor(drm); |
148 | } | 134 | } |
@@ -151,7 +137,6 @@ static void | |||
151 | nouveau_accel_init(struct nouveau_drm *drm) | 137 | nouveau_accel_init(struct nouveau_drm *drm) |
152 | { | 138 | { |
153 | struct nvif_device *device = &drm->device; | 139 | struct nvif_device *device = &drm->device; |
154 | struct nouveau_object *object; | ||
155 | u32 arg0, arg1; | 140 | u32 arg0, arg1; |
156 | u32 sclass[16]; | 141 | u32 sclass[16]; |
157 | int ret, i; | 142 | int ret, i; |
@@ -163,8 +148,7 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
163 | /*XXX: this is crap, but the fence/channel stuff is a little | 148 | /*XXX: this is crap, but the fence/channel stuff is a little |
164 | * backwards in some places. this will be fixed. | 149 | * backwards in some places. this will be fixed. |
165 | */ | 150 | */ |
166 | ret = nouveau_parent_lclass(nvkm_object(device), sclass, | 151 | ret = nvif_object_sclass(&device->base, sclass, ARRAY_SIZE(sclass)); |
167 | ARRAY_SIZE(sclass)); | ||
168 | if (ret < 0) | 152 | if (ret < 0) |
169 | return; | 153 | return; |
170 | 154 | ||
@@ -202,8 +186,7 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
202 | } | 186 | } |
203 | 187 | ||
204 | if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { | 188 | if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { |
205 | ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, | 189 | ret = nouveau_channel_new(drm, &drm->device, NVDRM_CHAN + 1, |
206 | NVDRM_CHAN + 1, | ||
207 | NVE0_CHANNEL_IND_ENGINE_CE0 | | 190 | NVE0_CHANNEL_IND_ENGINE_CE0 | |
208 | NVE0_CHANNEL_IND_ENGINE_CE1, 0, | 191 | NVE0_CHANNEL_IND_ENGINE_CE1, 0, |
209 | &drm->cechan); | 192 | &drm->cechan); |
@@ -216,9 +199,8 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
216 | if (device->info.chipset >= 0xa3 && | 199 | if (device->info.chipset >= 0xa3 && |
217 | device->info.chipset != 0xaa && | 200 | device->info.chipset != 0xaa && |
218 | device->info.chipset != 0xac) { | 201 | device->info.chipset != 0xac) { |
219 | ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, | 202 | ret = nouveau_channel_new(drm, &drm->device, NVDRM_CHAN + 1, |
220 | NVDRM_CHAN + 1, NvDmaFB, NvDmaTT, | 203 | NvDmaFB, NvDmaTT, &drm->cechan); |
221 | &drm->cechan); | ||
222 | if (ret) | 204 | if (ret) |
223 | NV_ERROR(drm, "failed to create ce channel, %d\n", ret); | 205 | NV_ERROR(drm, "failed to create ce channel, %d\n", ret); |
224 | 206 | ||
@@ -229,18 +211,18 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
229 | arg1 = NvDmaTT; | 211 | arg1 = NvDmaTT; |
230 | } | 212 | } |
231 | 213 | ||
232 | ret = nouveau_channel_new(drm, &drm->client, NVDRM_DEVICE, NVDRM_CHAN, | 214 | ret = nouveau_channel_new(drm, &drm->device, NVDRM_CHAN, arg0, arg1, |
233 | arg0, arg1, &drm->channel); | 215 | &drm->channel); |
234 | if (ret) { | 216 | if (ret) { |
235 | NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); | 217 | NV_ERROR(drm, "failed to create kernel channel, %d\n", ret); |
236 | nouveau_accel_fini(drm); | 218 | nouveau_accel_fini(drm); |
237 | return; | 219 | return; |
238 | } | 220 | } |
239 | 221 | ||
240 | ret = nouveau_object_new(nv_object(drm), NVDRM_CHAN, NVDRM_NVSW, | 222 | ret = nvif_object_init(drm->channel->object, NULL, NVDRM_NVSW, |
241 | nouveau_abi16_swclass(drm), NULL, 0, &object); | 223 | nouveau_abi16_swclass(drm), NULL, 0, &drm->nvsw); |
242 | if (ret == 0) { | 224 | if (ret == 0) { |
243 | struct nouveau_software_chan *swch = (void *)object->parent; | 225 | struct nouveau_software_chan *swch; |
244 | ret = RING_SPACE(drm->channel, 2); | 226 | ret = RING_SPACE(drm->channel, 2); |
245 | if (ret == 0) { | 227 | if (ret == 0) { |
246 | if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { | 228 | if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { |
@@ -252,7 +234,7 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
252 | OUT_RING (drm->channel, 0x001f0000); | 234 | OUT_RING (drm->channel, 0x001f0000); |
253 | } | 235 | } |
254 | } | 236 | } |
255 | swch = (void *)object->parent; | 237 | swch = (void *)nvkm_object(&drm->nvsw)->parent; |
256 | swch->flip = nouveau_flip_complete; | 238 | swch->flip = nouveau_flip_complete; |
257 | swch->flip_data = drm->channel; | 239 | swch->flip_data = drm->channel; |
258 | } | 240 | } |
@@ -272,15 +254,15 @@ nouveau_accel_init(struct nouveau_drm *drm) | |||
272 | return; | 254 | return; |
273 | } | 255 | } |
274 | 256 | ||
275 | ret = nouveau_object_new(nv_object(drm), | 257 | ret = nvif_object_init(drm->channel->object, NULL, NvNotify0, |
276 | drm->channel->handle, NvNotify0, | 258 | NV_DMA_IN_MEMORY_CLASS, |
277 | 0x003d, &(struct nv_dma_class) { | 259 | &(struct nv_dma_class) { |
278 | .flags = NV_DMA_TARGET_VRAM | | 260 | .flags = NV_DMA_TARGET_VRAM | |
279 | NV_DMA_ACCESS_RDWR, | 261 | NV_DMA_ACCESS_RDWR, |
280 | .start = drm->notify->addr, | 262 | .start = drm->notify->addr, |
281 | .limit = drm->notify->addr + 31 | 263 | .limit = drm->notify->addr + 31 |
282 | }, sizeof(struct nv_dma_class), | 264 | }, sizeof(struct nv_dma_class), |
283 | &object); | 265 | &drm->ntfy); |
284 | if (ret) { | 266 | if (ret) { |
285 | nouveau_accel_fini(drm); | 267 | nouveau_accel_fini(drm); |
286 | return; | 268 | return; |
@@ -373,27 +355,6 @@ nouveau_get_hdmi_dev(struct nouveau_drm *drm) | |||
373 | } | 355 | } |
374 | } | 356 | } |
375 | 357 | ||
376 | void | ||
377 | nouveau_drm_hack_device(struct nouveau_drm *drm, struct nvif_device *device) | ||
378 | { | ||
379 | drm->device.info.chipset = nvkm_device(&drm->device)->chipset; | ||
380 | switch (nvkm_device(&drm->device)->card_type) { | ||
381 | case NV_04: device->info.family = NV_DEVICE_INFO_V0_TNT; break; | ||
382 | case NV_10: device->info.family = NV_DEVICE_INFO_V0_CELSIUS; break; | ||
383 | case NV_11: device->info.family = NV_DEVICE_INFO_V0_CELSIUS; break; | ||
384 | case NV_20: device->info.family = NV_DEVICE_INFO_V0_KELVIN; break; | ||
385 | case NV_30: device->info.family = NV_DEVICE_INFO_V0_RANKINE; break; | ||
386 | case NV_40: device->info.family = NV_DEVICE_INFO_V0_CURIE; break; | ||
387 | case NV_50: device->info.family = NV_DEVICE_INFO_V0_TESLA; break; | ||
388 | case NV_C0: device->info.family = NV_DEVICE_INFO_V0_FERMI; break; | ||
389 | case NV_E0: device->info.family = NV_DEVICE_INFO_V0_KEPLER; break; | ||
390 | case GM100: device->info.family = NV_DEVICE_INFO_V0_MAXWELL; break; | ||
391 | default: | ||
392 | BUG_ON(1); | ||
393 | break; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | static int | 358 | static int |
398 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) | 359 | nouveau_drm_load(struct drm_device *dev, unsigned long flags) |
399 | { | 360 | { |
@@ -408,7 +369,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
408 | 369 | ||
409 | dev->dev_private = drm; | 370 | dev->dev_private = drm; |
410 | drm->dev = dev; | 371 | drm->dev = dev; |
411 | nouveau_client(drm)->debug = nouveau_dbgopt(nouveau_debug, "DRM"); | 372 | nvkm_client(&drm->client.base)->debug = |
373 | nouveau_dbgopt(nouveau_debug, "DRM"); | ||
412 | 374 | ||
413 | INIT_LIST_HEAD(&drm->clients); | 375 | INIT_LIST_HEAD(&drm->clients); |
414 | spin_lock_init(&drm->tile.lock); | 376 | spin_lock_init(&drm->tile.lock); |
@@ -422,39 +384,34 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
422 | /* dummy device object, doesn't init anything, but allows | 384 | /* dummy device object, doesn't init anything, but allows |
423 | * agp code access to registers | 385 | * agp code access to registers |
424 | */ | 386 | */ |
425 | ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, | 387 | ret = nvif_device_init(&drm->client.base.base, NULL, |
426 | NVDRM_DEVICE, 0x0080, | 388 | NVDRM_DEVICE, NV_DEVICE_CLASS, |
427 | &(struct nv_device_class) { | 389 | &(struct nv_device_class) { |
428 | .device = ~0, | 390 | .device = ~0, |
429 | .disable = | 391 | .disable = |
430 | ~(NV_DEVICE_DISABLE_MMIO | | 392 | ~(NV_DEVICE_DISABLE_MMIO | |
431 | NV_DEVICE_DISABLE_IDENTIFY), | 393 | NV_DEVICE_DISABLE_IDENTIFY), |
432 | .debug0 = ~0, | 394 | .debug0 = ~0, |
433 | }, sizeof(struct nv_device_class), | 395 | }, sizeof(struct nv_device_class), |
434 | (struct nouveau_object **) | 396 | &drm->device); |
435 | &drm->device.object); | ||
436 | if (ret) | 397 | if (ret) |
437 | goto fail_device; | 398 | goto fail_device; |
438 | 399 | ||
439 | nouveau_drm_hack_device(drm, &drm->device); | ||
440 | |||
441 | nouveau_agp_reset(drm); | 400 | nouveau_agp_reset(drm); |
442 | nouveau_object_del(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE); | 401 | nvif_device_fini(&drm->device); |
443 | } | 402 | } |
444 | 403 | ||
445 | ret = nouveau_object_new(nv_object(drm), NVDRM_CLIENT, NVDRM_DEVICE, | 404 | ret = nvif_device_init(&drm->client.base.base, NULL, NVDRM_DEVICE, |
446 | 0x0080, &(struct nv_device_class) { | 405 | NV_DEVICE_CLASS, |
406 | &(struct nv_device_class) { | ||
447 | .device = ~0, | 407 | .device = ~0, |
448 | .disable = 0, | 408 | .disable = 0, |
449 | .debug0 = 0, | 409 | .debug0 = 0, |
450 | }, sizeof(struct nv_device_class), | 410 | }, sizeof(struct nv_device_class), |
451 | (struct nouveau_object **) | 411 | &drm->device); |
452 | &drm->device.object); | ||
453 | if (ret) | 412 | if (ret) |
454 | goto fail_device; | 413 | goto fail_device; |
455 | 414 | ||
456 | nouveau_drm_hack_device(drm, &drm->device); | ||
457 | |||
458 | dev->irq_enabled = true; | 415 | dev->irq_enabled = true; |
459 | 416 | ||
460 | /* workaround an odd issue on nvc1 by disabling the device's | 417 | /* workaround an odd issue on nvc1 by disabling the device's |
@@ -473,7 +430,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
473 | if (ret) | 430 | if (ret) |
474 | goto fail_device; | 431 | goto fail_device; |
475 | 432 | ||
476 | drm->client.base.vm = drm->client.vm; | 433 | nvkm_client(&drm->client.base)->vm = drm->client.vm; |
477 | } | 434 | } |
478 | 435 | ||
479 | ret = nouveau_ttm_init(drm); | 436 | ret = nouveau_ttm_init(drm); |
@@ -519,6 +476,7 @@ fail_ttm: | |||
519 | nouveau_agp_fini(drm); | 476 | nouveau_agp_fini(drm); |
520 | nouveau_vga_fini(drm); | 477 | nouveau_vga_fini(drm); |
521 | fail_device: | 478 | fail_device: |
479 | nvif_device_fini(&drm->device); | ||
522 | nouveau_cli_destroy(&drm->client); | 480 | nouveau_cli_destroy(&drm->client); |
523 | return ret; | 481 | return ret; |
524 | } | 482 | } |
@@ -544,6 +502,7 @@ nouveau_drm_unload(struct drm_device *dev) | |||
544 | nouveau_agp_fini(drm); | 502 | nouveau_agp_fini(drm); |
545 | nouveau_vga_fini(drm); | 503 | nouveau_vga_fini(drm); |
546 | 504 | ||
505 | nvif_device_fini(&drm->device); | ||
547 | if (drm->hdmi_device) | 506 | if (drm->hdmi_device) |
548 | pci_dev_put(drm->hdmi_device); | 507 | pci_dev_put(drm->hdmi_device); |
549 | nouveau_cli_destroy(&drm->client); | 508 | nouveau_cli_destroy(&drm->client); |
@@ -554,10 +513,12 @@ void | |||
554 | nouveau_drm_device_remove(struct drm_device *dev) | 513 | nouveau_drm_device_remove(struct drm_device *dev) |
555 | { | 514 | { |
556 | struct nouveau_drm *drm = nouveau_drm(dev); | 515 | struct nouveau_drm *drm = nouveau_drm(dev); |
516 | struct nouveau_client *client; | ||
557 | struct nouveau_object *device; | 517 | struct nouveau_object *device; |
558 | 518 | ||
559 | dev->irq_enabled = false; | 519 | dev->irq_enabled = false; |
560 | device = drm->client.base.device; | 520 | client = nvkm_client(&drm->client.base); |
521 | device = client->device; | ||
561 | drm_put_dev(dev); | 522 | drm_put_dev(dev); |
562 | 523 | ||
563 | nouveau_object_ref(NULL, &device); | 524 | nouveau_object_ref(NULL, &device); |
@@ -612,13 +573,13 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) | |||
612 | } | 573 | } |
613 | 574 | ||
614 | list_for_each_entry(cli, &drm->clients, head) { | 575 | list_for_each_entry(cli, &drm->clients, head) { |
615 | ret = nouveau_client_fini(&cli->base, true); | 576 | ret = nvif_client_suspend(&cli->base); |
616 | if (ret) | 577 | if (ret) |
617 | goto fail_client; | 578 | goto fail_client; |
618 | } | 579 | } |
619 | 580 | ||
620 | NV_INFO(drm, "suspending kernel object tree...\n"); | 581 | NV_INFO(drm, "suspending kernel object tree...\n"); |
621 | ret = nouveau_client_fini(&drm->client.base, true); | 582 | ret = nvif_client_suspend(&drm->client.base); |
622 | if (ret) | 583 | if (ret) |
623 | goto fail_client; | 584 | goto fail_client; |
624 | 585 | ||
@@ -627,7 +588,7 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) | |||
627 | 588 | ||
628 | fail_client: | 589 | fail_client: |
629 | list_for_each_entry_continue_reverse(cli, &drm->clients, head) { | 590 | list_for_each_entry_continue_reverse(cli, &drm->clients, head) { |
630 | nouveau_client_init(&cli->base); | 591 | nvif_client_resume(&cli->base); |
631 | } | 592 | } |
632 | 593 | ||
633 | if (drm->fence && nouveau_fence(drm)->resume) | 594 | if (drm->fence && nouveau_fence(drm)->resume) |
@@ -675,7 +636,7 @@ nouveau_do_resume(struct drm_device *dev) | |||
675 | nouveau_agp_reset(drm); | 636 | nouveau_agp_reset(drm); |
676 | 637 | ||
677 | NV_INFO(drm, "resuming kernel object tree...\n"); | 638 | NV_INFO(drm, "resuming kernel object tree...\n"); |
678 | nouveau_client_init(&drm->client.base); | 639 | nvif_client_resume(&drm->client.base); |
679 | nouveau_agp_init(drm); | 640 | nouveau_agp_init(drm); |
680 | 641 | ||
681 | NV_INFO(drm, "resuming client object trees...\n"); | 642 | NV_INFO(drm, "resuming client object trees...\n"); |
@@ -683,7 +644,7 @@ nouveau_do_resume(struct drm_device *dev) | |||
683 | nouveau_fence(drm)->resume(drm); | 644 | nouveau_fence(drm)->resume(drm); |
684 | 645 | ||
685 | list_for_each_entry(cli, &drm->clients, head) { | 646 | list_for_each_entry(cli, &drm->clients, head) { |
686 | nouveau_client_init(&cli->base); | 647 | nvif_client_resume(&cli->base); |
687 | } | 648 | } |
688 | 649 | ||
689 | nouveau_run_vbios_init(dev); | 650 | nouveau_run_vbios_init(dev); |
@@ -779,6 +740,8 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) | |||
779 | if (ret) | 740 | if (ret) |
780 | goto out_suspend; | 741 | goto out_suspend; |
781 | 742 | ||
743 | cli->base.super = false; | ||
744 | |||
782 | if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { | 745 | if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { |
783 | ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40), | 746 | ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40), |
784 | 0x1000, &cli->vm); | 747 | 0x1000, &cli->vm); |
@@ -787,7 +750,7 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) | |||
787 | goto out_suspend; | 750 | goto out_suspend; |
788 | } | 751 | } |
789 | 752 | ||
790 | cli->base.vm = cli->vm; | 753 | nvkm_client(&cli->base)->vm = cli->vm; |
791 | } | 754 | } |
792 | 755 | ||
793 | fpriv->driver_priv = cli; | 756 | fpriv->driver_priv = cli; |