diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2010-09-01 01:24:34 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2010-09-24 02:22:42 -0400 |
commit | fbd2895e45aebdb3d3ea73a3a796cf3bb9c912da (patch) | |
tree | 1939bf1e1f66d6f7b4e7528e7105b5a0517822eb /drivers/gpu | |
parent | 6c3d7ef25e3b4a0ea511b1e9d4a0a212750874a6 (diff) |
drm/nouveau: rework init ordering so nv50_instmem.c can be less bad
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bo.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 75 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_object.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv04_instmem.c | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_instmem.c | 341 |
7 files changed, 243 insertions, 303 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 841c63f28867..8e4a9bce4f3b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -403,7 +403,10 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | |||
403 | man->available_caching = TTM_PL_FLAG_UNCACHED | | 403 | man->available_caching = TTM_PL_FLAG_UNCACHED | |
404 | TTM_PL_FLAG_WC; | 404 | TTM_PL_FLAG_WC; |
405 | man->default_caching = TTM_PL_FLAG_WC; | 405 | man->default_caching = TTM_PL_FLAG_WC; |
406 | man->gpu_offset = dev_priv->vm_vram_base; | 406 | if (dev_priv->card_type == NV_50) |
407 | man->gpu_offset = 0x40000000; | ||
408 | else | ||
409 | man->gpu_offset = 0; | ||
407 | break; | 410 | break; |
408 | case TTM_PL_TT: | 411 | case TTM_PL_TT: |
409 | switch (dev_priv->gart_info.type) { | 412 | switch (dev_priv->gart_info.type) { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 150fdeea11a1..3ba7a649fe51 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -700,8 +700,10 @@ extern bool nouveau_wait_for_idle(struct drm_device *); | |||
700 | extern int nouveau_card_init(struct drm_device *); | 700 | extern int nouveau_card_init(struct drm_device *); |
701 | 701 | ||
702 | /* nouveau_mem.c */ | 702 | /* nouveau_mem.c */ |
703 | extern int nouveau_mem_detect(struct drm_device *dev); | 703 | extern int nouveau_mem_vram_init(struct drm_device *); |
704 | extern int nouveau_mem_init(struct drm_device *); | 704 | extern void nouveau_mem_vram_fini(struct drm_device *); |
705 | extern int nouveau_mem_gart_init(struct drm_device *); | ||
706 | extern void nouveau_mem_gart_fini(struct drm_device *); | ||
705 | extern int nouveau_mem_init_agp(struct drm_device *); | 707 | extern int nouveau_mem_init_agp(struct drm_device *); |
706 | extern int nouveau_mem_reset_agp(struct drm_device *); | 708 | extern int nouveau_mem_reset_agp(struct drm_device *); |
707 | extern void nouveau_mem_close(struct drm_device *); | 709 | extern void nouveau_mem_close(struct drm_device *); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 6eeaeac56293..fb15a1b0dda9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c | |||
@@ -221,7 +221,7 @@ nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) | |||
221 | * Cleanup everything | 221 | * Cleanup everything |
222 | */ | 222 | */ |
223 | void | 223 | void |
224 | nouveau_mem_close(struct drm_device *dev) | 224 | nouveau_mem_vram_fini(struct drm_device *dev) |
225 | { | 225 | { |
226 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 226 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
227 | 227 | ||
@@ -232,6 +232,19 @@ nouveau_mem_close(struct drm_device *dev) | |||
232 | 232 | ||
233 | nouveau_ttm_global_release(dev_priv); | 233 | nouveau_ttm_global_release(dev_priv); |
234 | 234 | ||
235 | if (dev_priv->fb_mtrr >= 0) { | ||
236 | drm_mtrr_del(dev_priv->fb_mtrr, | ||
237 | pci_resource_start(dev->pdev, 1), | ||
238 | pci_resource_len(dev->pdev, 1), DRM_MTRR_WC); | ||
239 | dev_priv->fb_mtrr = -1; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | void | ||
244 | nouveau_mem_gart_fini(struct drm_device *dev) | ||
245 | { | ||
246 | nouveau_sgdma_takedown(dev); | ||
247 | |||
235 | if (drm_core_has_AGP(dev) && dev->agp) { | 248 | if (drm_core_has_AGP(dev) && dev->agp) { |
236 | struct drm_agp_mem *entry, *tempe; | 249 | struct drm_agp_mem *entry, *tempe; |
237 | 250 | ||
@@ -251,13 +264,6 @@ nouveau_mem_close(struct drm_device *dev) | |||
251 | dev->agp->acquired = 0; | 264 | dev->agp->acquired = 0; |
252 | dev->agp->enabled = 0; | 265 | dev->agp->enabled = 0; |
253 | } | 266 | } |
254 | |||
255 | if (dev_priv->fb_mtrr) { | ||
256 | drm_mtrr_del(dev_priv->fb_mtrr, | ||
257 | pci_resource_start(dev->pdev, 1), | ||
258 | pci_resource_len(dev->pdev, 1), DRM_MTRR_WC); | ||
259 | dev_priv->fb_mtrr = -1; | ||
260 | } | ||
261 | } | 267 | } |
262 | 268 | ||
263 | static uint32_t | 269 | static uint32_t |
@@ -363,7 +369,7 @@ nvaa_vram_preinit(struct drm_device *dev) | |||
363 | dev_priv->vram_rblock_size = 1; | 369 | dev_priv->vram_rblock_size = 1; |
364 | } | 370 | } |
365 | 371 | ||
366 | int | 372 | static int |
367 | nouveau_mem_detect(struct drm_device *dev) | 373 | nouveau_mem_detect(struct drm_device *dev) |
368 | { | 374 | { |
369 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 375 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
@@ -500,24 +506,27 @@ nouveau_mem_init_agp(struct drm_device *dev) | |||
500 | } | 506 | } |
501 | 507 | ||
502 | int | 508 | int |
503 | nouveau_mem_init(struct drm_device *dev) | 509 | nouveau_mem_vram_init(struct drm_device *dev) |
504 | { | 510 | { |
505 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 511 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
506 | struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; | 512 | struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; |
507 | int ret, dma_bits = 32; | 513 | int ret, dma_bits; |
508 | |||
509 | dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); | ||
510 | dev_priv->gart_info.type = NOUVEAU_GART_NONE; | ||
511 | 514 | ||
512 | if (dev_priv->card_type >= NV_50 && | 515 | if (dev_priv->card_type >= NV_50 && |
513 | pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) | 516 | pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) |
514 | dma_bits = 40; | 517 | dma_bits = 40; |
518 | else | ||
519 | dma_bits = 32; | ||
515 | 520 | ||
516 | ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits)); | 521 | ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits)); |
517 | if (ret) { | 522 | if (ret) |
518 | NV_ERROR(dev, "Error setting DMA mask: %d\n", ret); | ||
519 | return ret; | 523 | return ret; |
520 | } | 524 | |
525 | ret = nouveau_mem_detect(dev); | ||
526 | if (ret) | ||
527 | return ret; | ||
528 | |||
529 | dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); | ||
521 | 530 | ||
522 | ret = nouveau_ttm_global_init(dev_priv); | 531 | ret = nouveau_ttm_global_init(dev_priv); |
523 | if (ret) | 532 | if (ret) |
@@ -541,7 +550,16 @@ nouveau_mem_init(struct drm_device *dev) | |||
541 | pci_resource_len(dev->pdev, 1); | 550 | pci_resource_len(dev->pdev, 1); |
542 | dev_priv->fb_mappable_pages >>= PAGE_SHIFT; | 551 | dev_priv->fb_mappable_pages >>= PAGE_SHIFT; |
543 | 552 | ||
544 | /* remove reserved space at end of vram from available amount */ | 553 | /* reserve space at end of VRAM for PRAMIN */ |
554 | if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 || | ||
555 | dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) | ||
556 | dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024); | ||
557 | else | ||
558 | if (dev_priv->card_type >= NV_40) | ||
559 | dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024); | ||
560 | else | ||
561 | dev_priv->ramin_rsvd_vram = (512 * 1024); | ||
562 | |||
545 | dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram; | 563 | dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram; |
546 | dev_priv->fb_aper_free = dev_priv->fb_available_size; | 564 | dev_priv->fb_aper_free = dev_priv->fb_available_size; |
547 | 565 | ||
@@ -562,7 +580,21 @@ nouveau_mem_init(struct drm_device *dev) | |||
562 | nouveau_bo_ref(NULL, &dev_priv->vga_ram); | 580 | nouveau_bo_ref(NULL, &dev_priv->vga_ram); |
563 | } | 581 | } |
564 | 582 | ||
565 | /* GART */ | 583 | dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), |
584 | pci_resource_len(dev->pdev, 1), | ||
585 | DRM_MTRR_WC); | ||
586 | return 0; | ||
587 | } | ||
588 | |||
589 | int | ||
590 | nouveau_mem_gart_init(struct drm_device *dev) | ||
591 | { | ||
592 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
593 | struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; | ||
594 | int ret; | ||
595 | |||
596 | dev_priv->gart_info.type = NOUVEAU_GART_NONE; | ||
597 | |||
566 | #if !defined(__powerpc__) && !defined(__ia64__) | 598 | #if !defined(__powerpc__) && !defined(__ia64__) |
567 | if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) { | 599 | if (drm_device_is_agp(dev) && dev->agp && !nouveau_noagp) { |
568 | ret = nouveau_mem_init_agp(dev); | 600 | ret = nouveau_mem_init_agp(dev); |
@@ -590,11 +622,6 @@ nouveau_mem_init(struct drm_device *dev) | |||
590 | return ret; | 622 | return ret; |
591 | } | 623 | } |
592 | 624 | ||
593 | dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), | ||
594 | pci_resource_len(dev->pdev, 1), | ||
595 | DRM_MTRR_WC); | ||
596 | |||
597 | return 0; | 625 | return 0; |
598 | } | 626 | } |
599 | 627 | ||
600 | |||
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index df445fcb8321..b68922f2fe54 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c | |||
@@ -130,7 +130,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, | |||
130 | 130 | ||
131 | /* if we got a chunk of the aperture, map pages into it */ | 131 | /* if we got a chunk of the aperture, map pages into it */ |
132 | gpuobj->im_pramin = ramin; | 132 | gpuobj->im_pramin = ramin; |
133 | if (!chan && gpuobj->im_pramin) { | 133 | if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) { |
134 | ret = engine->instmem.bind(dev, gpuobj); | 134 | ret = engine->instmem.bind(dev, gpuobj); |
135 | if (ret) { | 135 | if (ret) { |
136 | nouveau_gpuobj_ref(NULL, &gpuobj); | 136 | nouveau_gpuobj_ref(NULL, &gpuobj); |
@@ -173,7 +173,7 @@ nouveau_gpuobj_new(struct drm_device *dev, struct nouveau_channel *chan, | |||
173 | } | 173 | } |
174 | 174 | ||
175 | int | 175 | int |
176 | nouveau_gpuobj_early_init(struct drm_device *dev) | 176 | nouveau_gpuobj_init(struct drm_device *dev) |
177 | { | 177 | { |
178 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 178 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
179 | 179 | ||
@@ -186,29 +186,6 @@ nouveau_gpuobj_early_init(struct drm_device *dev) | |||
186 | return 0; | 186 | return 0; |
187 | } | 187 | } |
188 | 188 | ||
189 | int | ||
190 | nouveau_gpuobj_init(struct drm_device *dev) | ||
191 | { | ||
192 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
193 | struct nouveau_gpuobj *ramht = NULL; | ||
194 | int ret; | ||
195 | |||
196 | NV_DEBUG(dev, "\n"); | ||
197 | |||
198 | if (dev_priv->card_type >= NV_50) | ||
199 | return 0; | ||
200 | |||
201 | ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset, ~0, | ||
202 | dev_priv->ramht_size, | ||
203 | NVOBJ_FLAG_ZERO_ALLOC, &ramht); | ||
204 | if (ret) | ||
205 | return ret; | ||
206 | |||
207 | ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht); | ||
208 | nouveau_gpuobj_ref(NULL, &ramht); | ||
209 | return ret; | ||
210 | } | ||
211 | |||
212 | void | 189 | void |
213 | nouveau_gpuobj_takedown(struct drm_device *dev) | 190 | nouveau_gpuobj_takedown(struct drm_device *dev) |
214 | { | 191 | { |
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index fec29522298d..19eb06dca899 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -532,35 +532,26 @@ nouveau_card_init(struct drm_device *dev) | |||
532 | if (ret) | 532 | if (ret) |
533 | goto out_display_early; | 533 | goto out_display_early; |
534 | 534 | ||
535 | ret = nouveau_mem_detect(dev); | 535 | ret = nouveau_mem_vram_init(dev); |
536 | if (ret) | 536 | if (ret) |
537 | goto out_bios; | 537 | goto out_bios; |
538 | 538 | ||
539 | ret = nouveau_gpuobj_early_init(dev); | 539 | ret = nouveau_gpuobj_init(dev); |
540 | if (ret) | 540 | if (ret) |
541 | goto out_bios; | 541 | goto out_vram; |
542 | 542 | ||
543 | /* Initialise instance memory, must happen before mem_init so we | ||
544 | * know exactly how much VRAM we're able to use for "normal" | ||
545 | * purposes. | ||
546 | */ | ||
547 | ret = engine->instmem.init(dev); | 543 | ret = engine->instmem.init(dev); |
548 | if (ret) | 544 | if (ret) |
549 | goto out_gpuobj_early; | 545 | goto out_gpuobj; |
550 | 546 | ||
551 | /* Setup the memory manager */ | 547 | ret = nouveau_mem_gart_init(dev); |
552 | ret = nouveau_mem_init(dev); | ||
553 | if (ret) | 548 | if (ret) |
554 | goto out_instmem; | 549 | goto out_instmem; |
555 | 550 | ||
556 | ret = nouveau_gpuobj_init(dev); | ||
557 | if (ret) | ||
558 | goto out_mem; | ||
559 | |||
560 | /* PMC */ | 551 | /* PMC */ |
561 | ret = engine->mc.init(dev); | 552 | ret = engine->mc.init(dev); |
562 | if (ret) | 553 | if (ret) |
563 | goto out_gpuobj; | 554 | goto out_gart; |
564 | 555 | ||
565 | /* PGPIO */ | 556 | /* PGPIO */ |
566 | ret = engine->gpio.init(dev); | 557 | ret = engine->gpio.init(dev); |
@@ -640,15 +631,14 @@ out_gpio: | |||
640 | engine->gpio.takedown(dev); | 631 | engine->gpio.takedown(dev); |
641 | out_mc: | 632 | out_mc: |
642 | engine->mc.takedown(dev); | 633 | engine->mc.takedown(dev); |
643 | out_gpuobj: | 634 | out_gart: |
644 | nouveau_gpuobj_takedown(dev); | 635 | nouveau_mem_gart_fini(dev); |
645 | out_mem: | ||
646 | nouveau_sgdma_takedown(dev); | ||
647 | nouveau_mem_close(dev); | ||
648 | out_instmem: | 636 | out_instmem: |
649 | engine->instmem.takedown(dev); | 637 | engine->instmem.takedown(dev); |
650 | out_gpuobj_early: | 638 | out_gpuobj: |
651 | nouveau_gpuobj_late_takedown(dev); | 639 | nouveau_gpuobj_takedown(dev); |
640 | out_vram: | ||
641 | nouveau_mem_vram_fini(dev); | ||
652 | out_bios: | 642 | out_bios: |
653 | nouveau_bios_takedown(dev); | 643 | nouveau_bios_takedown(dev); |
654 | out_display_early: | 644 | out_display_early: |
@@ -684,15 +674,14 @@ static void nouveau_card_takedown(struct drm_device *dev) | |||
684 | ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); | 674 | ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM); |
685 | ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); | 675 | ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); |
686 | mutex_unlock(&dev->struct_mutex); | 676 | mutex_unlock(&dev->struct_mutex); |
687 | nouveau_sgdma_takedown(dev); | 677 | nouveau_mem_gart_fini(dev); |
688 | 678 | ||
689 | nouveau_gpuobj_takedown(dev); | ||
690 | nouveau_mem_close(dev); | ||
691 | engine->instmem.takedown(dev); | 679 | engine->instmem.takedown(dev); |
680 | nouveau_gpuobj_takedown(dev); | ||
681 | nouveau_mem_vram_fini(dev); | ||
692 | 682 | ||
693 | drm_irq_uninstall(dev); | 683 | drm_irq_uninstall(dev); |
694 | 684 | ||
695 | nouveau_gpuobj_late_takedown(dev); | ||
696 | nouveau_bios_takedown(dev); | 685 | nouveau_bios_takedown(dev); |
697 | 686 | ||
698 | vga_client_register(dev->pdev, NULL, NULL, NULL); | 687 | vga_client_register(dev->pdev, NULL, NULL, NULL); |
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c index 3aba7674560c..15cd468f4c29 100644 --- a/drivers/gpu/drm/nouveau/nv04_instmem.c +++ b/drivers/gpu/drm/nouveau/nv04_instmem.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include "drmP.h" | 1 | #include "drmP.h" |
2 | #include "drm.h" | 2 | #include "drm.h" |
3 | #include "nouveau_drv.h" | 3 | #include "nouveau_drv.h" |
4 | #include "nouveau_ramht.h" | ||
4 | 5 | ||
5 | /* returns the size of fifo context */ | 6 | /* returns the size of fifo context */ |
6 | static int | 7 | static int |
@@ -18,42 +19,6 @@ nouveau_fifo_ctx_size(struct drm_device *dev) | |||
18 | } | 19 | } |
19 | 20 | ||
20 | static void | 21 | static void |
21 | nv04_instmem_determine_amount(struct drm_device *dev) | ||
22 | { | ||
23 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
24 | int i; | ||
25 | |||
26 | /* Figure out how much instance memory we need */ | ||
27 | if (dev_priv->card_type >= NV_40) { | ||
28 | /* We'll want more instance memory than this on some NV4x cards. | ||
29 | * There's a 16MB aperture to play with that maps onto the end | ||
30 | * of vram. For now, only reserve a small piece until we know | ||
31 | * more about what each chipset requires. | ||
32 | */ | ||
33 | switch (dev_priv->chipset) { | ||
34 | case 0x40: | ||
35 | case 0x47: | ||
36 | case 0x49: | ||
37 | case 0x4b: | ||
38 | dev_priv->ramin_rsvd_vram = (2 * 1024 * 1024); | ||
39 | break; | ||
40 | default: | ||
41 | dev_priv->ramin_rsvd_vram = (1 * 1024 * 1024); | ||
42 | break; | ||
43 | } | ||
44 | } else { | ||
45 | /*XXX: what *are* the limits on <NV40 cards? | ||
46 | */ | ||
47 | dev_priv->ramin_rsvd_vram = (512 * 1024); | ||
48 | } | ||
49 | NV_DEBUG(dev, "RAMIN size: %dKiB\n", dev_priv->ramin_rsvd_vram >> 10); | ||
50 | |||
51 | /* Clear all of it, except the BIOS image that's in the first 64KiB */ | ||
52 | for (i = 64 * 1024; i < dev_priv->ramin_rsvd_vram; i += 4) | ||
53 | nv_wi32(dev, i, 0x00000000); | ||
54 | } | ||
55 | |||
56 | static void | ||
57 | nv04_instmem_configure_fixed_tables(struct drm_device *dev) | 22 | nv04_instmem_configure_fixed_tables(struct drm_device *dev) |
58 | { | 23 | { |
59 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 24 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
@@ -103,12 +68,24 @@ nv04_instmem_configure_fixed_tables(struct drm_device *dev) | |||
103 | int nv04_instmem_init(struct drm_device *dev) | 68 | int nv04_instmem_init(struct drm_device *dev) |
104 | { | 69 | { |
105 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 70 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
71 | struct nouveau_gpuobj *ramht = NULL; | ||
106 | uint32_t offset; | 72 | uint32_t offset; |
107 | int ret; | 73 | int ret; |
108 | 74 | ||
109 | nv04_instmem_determine_amount(dev); | ||
110 | nv04_instmem_configure_fixed_tables(dev); | 75 | nv04_instmem_configure_fixed_tables(dev); |
111 | 76 | ||
77 | /* Setup shared RAMHT */ | ||
78 | ret = nouveau_gpuobj_new_fake(dev, dev_priv->ramht_offset, ~0, | ||
79 | dev_priv->ramht_size, | ||
80 | NVOBJ_FLAG_ZERO_ALLOC, &ramht); | ||
81 | if (ret) | ||
82 | return ret; | ||
83 | |||
84 | ret = nouveau_ramht_new(dev, ramht, &dev_priv->ramht); | ||
85 | nouveau_gpuobj_ref(NULL, &ramht); | ||
86 | if (ret) | ||
87 | return ret; | ||
88 | |||
112 | /* Create a heap to manage RAMIN allocations, we don't allocate | 89 | /* Create a heap to manage RAMIN allocations, we don't allocate |
113 | * the space that was reserved for RAMHT/FC/RO. | 90 | * the space that was reserved for RAMHT/FC/RO. |
114 | */ | 91 | */ |
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 5c617f807b23..d932594449c1 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c | |||
@@ -37,27 +37,82 @@ struct nv50_instmem_priv { | |||
37 | struct nouveau_gpuobj *fb_bar; | 37 | struct nouveau_gpuobj *fb_bar; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | #define NV50_INSTMEM_PAGE_SHIFT 12 | 40 | static void |
41 | #define NV50_INSTMEM_PAGE_SIZE (1 << NV50_INSTMEM_PAGE_SHIFT) | 41 | nv50_channel_del(struct nouveau_channel **pchan) |
42 | #define NV50_INSTMEM_PT_SIZE(a) (((a) >> 12) << 3) | 42 | { |
43 | struct nouveau_channel *chan; | ||
43 | 44 | ||
44 | /*NOTE: - Assumes 0x1700 already covers the correct MiB of PRAMIN | 45 | chan = *pchan; |
45 | */ | 46 | *pchan = NULL; |
46 | #define BAR0_WI32(g, o, v) do { \ | 47 | if (!chan) |
47 | u32 offset = (g)->vinst + (o); \ | 48 | return; |
48 | nv_wr32(dev, NV_RAMIN + (offset & 0xfffff), (v)); \ | 49 | |
49 | } while (0) | 50 | nouveau_gpuobj_ref(NULL, &chan->ramfc); |
51 | nouveau_gpuobj_ref(NULL, &chan->vm_pd); | ||
52 | if (chan->ramin_heap.free_stack.next) | ||
53 | drm_mm_takedown(&chan->ramin_heap); | ||
54 | nouveau_gpuobj_ref(NULL, &chan->ramin); | ||
55 | kfree(chan); | ||
56 | } | ||
57 | |||
58 | static int | ||
59 | nv50_channel_new(struct drm_device *dev, u32 size, | ||
60 | struct nouveau_channel **pchan) | ||
61 | { | ||
62 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
63 | u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; | ||
64 | u32 fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200; | ||
65 | struct nouveau_channel *chan; | ||
66 | int ret; | ||
67 | |||
68 | chan = kzalloc(sizeof(*chan), GFP_KERNEL); | ||
69 | if (!chan) | ||
70 | return -ENOMEM; | ||
71 | chan->dev = dev; | ||
72 | |||
73 | ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); | ||
74 | if (ret) { | ||
75 | nv50_channel_del(&chan); | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | ret = drm_mm_init(&chan->ramin_heap, 0x6000, chan->ramin->size); | ||
80 | if (ret) { | ||
81 | nv50_channel_del(&chan); | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 : | ||
86 | chan->ramin->pinst + pgd, | ||
87 | chan->ramin->vinst + pgd, | ||
88 | 0x4000, NVOBJ_FLAG_ZERO_ALLOC, | ||
89 | &chan->vm_pd); | ||
90 | if (ret) { | ||
91 | nv50_channel_del(&chan); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 : | ||
96 | chan->ramin->pinst + fc, | ||
97 | chan->ramin->vinst + fc, 0x100, | ||
98 | NVOBJ_FLAG_ZERO_ALLOC, &chan->ramfc); | ||
99 | if (ret) { | ||
100 | nv50_channel_del(&chan); | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | *pchan = chan; | ||
105 | return 0; | ||
106 | } | ||
50 | 107 | ||
51 | int | 108 | int |
52 | nv50_instmem_init(struct drm_device *dev) | 109 | nv50_instmem_init(struct drm_device *dev) |
53 | { | 110 | { |
54 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 111 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
55 | struct nouveau_channel *chan; | ||
56 | uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size; | ||
57 | uint32_t save_nv001700; | ||
58 | uint64_t v; | ||
59 | struct nv50_instmem_priv *priv; | 112 | struct nv50_instmem_priv *priv; |
113 | struct nouveau_channel *chan; | ||
60 | int ret, i; | 114 | int ret, i; |
115 | u32 tmp; | ||
61 | 116 | ||
62 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 117 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
63 | if (!priv) | 118 | if (!priv) |
@@ -68,206 +123,113 @@ nv50_instmem_init(struct drm_device *dev) | |||
68 | for (i = 0x1700; i <= 0x1710; i += 4) | 123 | for (i = 0x1700; i <= 0x1710; i += 4) |
69 | priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); | 124 | priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); |
70 | 125 | ||
71 | /* Reserve the last MiB of VRAM, we should probably try to avoid | 126 | /* Global PRAMIN heap */ |
72 | * setting up the below tables over the top of the VBIOS image at | 127 | ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size); |
73 | * some point. | 128 | if (ret) { |
74 | */ | 129 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); |
75 | dev_priv->ramin_rsvd_vram = 1 << 20; | ||
76 | c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | ||
77 | c_size = 128 << 10; | ||
78 | c_vmpd = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200; | ||
79 | c_ramfc = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20; | ||
80 | c_base = c_vmpd + 0x4000; | ||
81 | pt_size = NV50_INSTMEM_PT_SIZE(dev_priv->ramin_size); | ||
82 | |||
83 | NV_DEBUG(dev, " Rsvd VRAM base: 0x%08x\n", c_offset); | ||
84 | NV_DEBUG(dev, " VBIOS image: 0x%08x\n", | ||
85 | (nv_rd32(dev, 0x619f04) & ~0xff) << 8); | ||
86 | NV_DEBUG(dev, " Aperture size: %d MiB\n", dev_priv->ramin_size >> 20); | ||
87 | NV_DEBUG(dev, " PT size: %d KiB\n", pt_size >> 10); | ||
88 | |||
89 | /* Determine VM layout, we need to do this first to make sure | ||
90 | * we allocate enough memory for all the page tables. | ||
91 | */ | ||
92 | dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); | ||
93 | dev_priv->vm_gart_size = NV50_VM_BLOCK; | ||
94 | |||
95 | dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size; | ||
96 | dev_priv->vm_vram_size = dev_priv->vram_size; | ||
97 | if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM) | ||
98 | dev_priv->vm_vram_size = NV50_VM_MAX_VRAM; | ||
99 | dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK); | ||
100 | dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK; | ||
101 | |||
102 | dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size; | ||
103 | |||
104 | NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n", | ||
105 | dev_priv->vm_gart_base, | ||
106 | dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1); | ||
107 | NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n", | ||
108 | dev_priv->vm_vram_base, | ||
109 | dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1); | ||
110 | |||
111 | c_size += dev_priv->vm_vram_pt_nr * (NV50_VM_BLOCK / 65536 * 8); | ||
112 | |||
113 | /* Map BAR0 PRAMIN aperture over the memory we want to use */ | ||
114 | save_nv001700 = nv_rd32(dev, NV50_PUNK_BAR0_PRAMIN); | ||
115 | nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (c_offset >> 16)); | ||
116 | |||
117 | /* Create a fake channel, and use it as our "dummy" channels 0/127. | ||
118 | * The main reason for creating a channel is so we can use the gpuobj | ||
119 | * code. However, it's probably worth noting that NVIDIA also setup | ||
120 | * their channels 0/127 with the same values they configure here. | ||
121 | * So, there may be some other reason for doing this. | ||
122 | * | ||
123 | * Have to create the entire channel manually, as the real channel | ||
124 | * creation code assumes we have PRAMIN access, and we don't until | ||
125 | * we're done here. | ||
126 | */ | ||
127 | chan = kzalloc(sizeof(*chan), GFP_KERNEL); | ||
128 | if (!chan) | ||
129 | return -ENOMEM; | 130 | return -ENOMEM; |
130 | chan->id = 0; | 131 | } |
131 | chan->dev = dev; | ||
132 | chan->file_priv = (struct drm_file *)-2; | ||
133 | dev_priv->fifos[0] = dev_priv->fifos[127] = chan; | ||
134 | |||
135 | INIT_LIST_HEAD(&chan->ramht_refs); | ||
136 | 132 | ||
137 | /* Channel's PRAMIN object + heap */ | 133 | /* we need a channel to plug into the hw to control the BARs */ |
138 | ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0, &chan->ramin); | 134 | ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]); |
139 | if (ret) | 135 | if (ret) |
140 | return ret; | 136 | return ret; |
137 | chan = dev_priv->fifos[127] = dev_priv->fifos[0]; | ||
141 | 138 | ||
142 | if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base)) | 139 | /* allocate page table for PRAMIN BAR */ |
143 | return -ENOMEM; | 140 | ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8, |
144 | 141 | 0x1000, NVOBJ_FLAG_ZERO_ALLOC, | |
145 | /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */ | 142 | &priv->pramin_pt); |
146 | ret = nouveau_gpuobj_new_fake(dev, c_ramfc, c_offset + c_ramfc, | ||
147 | 0x4000, 0, &chan->ramfc); | ||
148 | if (ret) | 143 | if (ret) |
149 | return ret; | 144 | return ret; |
150 | 145 | ||
151 | for (i = 0; i < c_vmpd; i += 4) | 146 | nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63); |
152 | BAR0_WI32(chan->ramin, i, 0); | 147 | nv_wo32(chan->vm_pd, 0x0004, 0); |
153 | 148 | ||
154 | /* VM page directory */ | 149 | /* DMA object for PRAMIN BAR */ |
155 | ret = nouveau_gpuobj_new_fake(dev, c_vmpd, c_offset + c_vmpd, | 150 | ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar); |
156 | 0x4000, 0, &chan->vm_pd); | ||
157 | if (ret) | 151 | if (ret) |
158 | return ret; | 152 | return ret; |
159 | for (i = 0; i < 0x4000; i += 8) { | 153 | nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000); |
160 | BAR0_WI32(chan->vm_pd, i + 0x00, 0x00000000); | 154 | nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1); |
161 | BAR0_WI32(chan->vm_pd, i + 0x04, 0x00000000); | 155 | nv_wo32(priv->pramin_bar, 0x08, 0x00000000); |
162 | } | 156 | nv_wo32(priv->pramin_bar, 0x0c, 0x00000000); |
163 | 157 | nv_wo32(priv->pramin_bar, 0x10, 0x00000000); | |
164 | /* PRAMIN page table, cheat and map into VM at 0x0000000000. | 158 | nv_wo32(priv->pramin_bar, 0x14, 0x00000000); |
165 | * We map the entire fake channel into the start of the PRAMIN BAR | 159 | |
166 | */ | 160 | /* map channel into PRAMIN, gpuobj didn't do it for us */ |
167 | ret = nouveau_gpuobj_new(dev, chan, pt_size, 0x1000, 0, | 161 | ret = nv50_instmem_bind(dev, chan->ramin); |
168 | &priv->pramin_pt); | ||
169 | if (ret) | 162 | if (ret) |
170 | return ret; | 163 | return ret; |
171 | 164 | ||
172 | v = c_offset | 1; | 165 | /* poke regs... */ |
173 | if (dev_priv->vram_sys_base) { | 166 | nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12)); |
174 | v += dev_priv->vram_sys_base; | 167 | nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12)); |
175 | v |= 0x30; | 168 | nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4)); |
176 | } | ||
177 | 169 | ||
178 | i = 0; | 170 | tmp = nv_ri32(dev, 0); |
179 | while (v < dev_priv->vram_sys_base + c_offset + c_size) { | 171 | nv_wi32(dev, 0, ~tmp); |
180 | BAR0_WI32(priv->pramin_pt, i + 0, lower_32_bits(v)); | 172 | if (nv_ri32(dev, 0) != ~tmp) { |
181 | BAR0_WI32(priv->pramin_pt, i + 4, upper_32_bits(v)); | 173 | NV_ERROR(dev, "PRAMIN readback failed\n"); |
182 | v += 0x1000; | 174 | return -EIO; |
183 | i += 8; | ||
184 | } | 175 | } |
176 | nv_wi32(dev, 0, tmp); | ||
185 | 177 | ||
186 | while (i < pt_size) { | 178 | dev_priv->ramin_available = true; |
187 | BAR0_WI32(priv->pramin_pt, i + 0, 0x00000000); | 179 | |
188 | BAR0_WI32(priv->pramin_pt, i + 4, 0x00000000); | 180 | /* Determine VM layout */ |
189 | i += 8; | 181 | dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); |
190 | } | 182 | dev_priv->vm_gart_size = NV50_VM_BLOCK; |
183 | |||
184 | dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size; | ||
185 | dev_priv->vm_vram_size = dev_priv->vram_size; | ||
186 | if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM) | ||
187 | dev_priv->vm_vram_size = NV50_VM_MAX_VRAM; | ||
188 | dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK); | ||
189 | dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK; | ||
191 | 190 | ||
192 | BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->vinst | 0x63); | 191 | dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size; |
193 | BAR0_WI32(chan->vm_pd, 0x04, 0x00000000); | 192 | |
193 | NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n", | ||
194 | dev_priv->vm_gart_base, | ||
195 | dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1); | ||
196 | NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n", | ||
197 | dev_priv->vm_vram_base, | ||
198 | dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1); | ||
194 | 199 | ||
195 | /* VRAM page table(s), mapped into VM at +1GiB */ | 200 | /* VRAM page table(s), mapped into VM at +1GiB */ |
196 | for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { | 201 | for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { |
197 | ret = nouveau_gpuobj_new(dev, chan, NV50_VM_BLOCK / 0x10000 * 8, | 202 | ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8, |
198 | 0, 0, &chan->vm_vram_pt[i]); | 203 | 0, NVOBJ_FLAG_ZERO_ALLOC, |
204 | &chan->vm_vram_pt[i]); | ||
199 | if (ret) { | 205 | if (ret) { |
200 | NV_ERROR(dev, "Error creating VRAM page tables: %d\n", | 206 | NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret); |
201 | ret); | ||
202 | dev_priv->vm_vram_pt_nr = i; | 207 | dev_priv->vm_vram_pt_nr = i; |
203 | return ret; | 208 | return ret; |
204 | } | 209 | } |
205 | /*XXX: double-check this is ok */ | ||
206 | dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]; | 210 | dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]; |
207 | 211 | ||
208 | for (v = 0; v < dev_priv->vm_vram_pt[i]->size; v += 4) | 212 | nv_wo32(chan->vm_pd, 0x10 + (i*8), |
209 | BAR0_WI32(dev_priv->vm_vram_pt[i], v, 0); | 213 | chan->vm_vram_pt[i]->vinst | 0x61); |
210 | 214 | nv_wo32(chan->vm_pd, 0x14 + (i*8), 0); | |
211 | BAR0_WI32(chan->vm_pd, 0x10 + (i*8), | ||
212 | chan->vm_vram_pt[i]->vinst | 0x61); | ||
213 | BAR0_WI32(chan->vm_pd, 0x14 + (i*8), 0); | ||
214 | } | 215 | } |
215 | 216 | ||
216 | /* DMA object for PRAMIN BAR */ | ||
217 | ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar); | ||
218 | if (ret) | ||
219 | return ret; | ||
220 | BAR0_WI32(priv->pramin_bar, 0x00, 0x7fc00000); | ||
221 | BAR0_WI32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1); | ||
222 | BAR0_WI32(priv->pramin_bar, 0x08, 0x00000000); | ||
223 | BAR0_WI32(priv->pramin_bar, 0x0c, 0x00000000); | ||
224 | BAR0_WI32(priv->pramin_bar, 0x10, 0x00000000); | ||
225 | BAR0_WI32(priv->pramin_bar, 0x14, 0x00000000); | ||
226 | |||
227 | /* DMA object for FB BAR */ | 217 | /* DMA object for FB BAR */ |
228 | ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar); | 218 | ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar); |
229 | if (ret) | 219 | if (ret) |
230 | return ret; | 220 | return ret; |
231 | BAR0_WI32(priv->fb_bar, 0x00, 0x7fc00000); | 221 | nv_wo32(priv->fb_bar, 0x00, 0x7fc00000); |
232 | BAR0_WI32(priv->fb_bar, 0x04, 0x40000000 + | 222 | nv_wo32(priv->fb_bar, 0x04, 0x40000000 + |
233 | pci_resource_len(dev->pdev, 1) - 1); | 223 | pci_resource_len(dev->pdev, 1) - 1); |
234 | BAR0_WI32(priv->fb_bar, 0x08, 0x40000000); | 224 | nv_wo32(priv->fb_bar, 0x08, 0x40000000); |
235 | BAR0_WI32(priv->fb_bar, 0x0c, 0x00000000); | 225 | nv_wo32(priv->fb_bar, 0x0c, 0x00000000); |
236 | BAR0_WI32(priv->fb_bar, 0x10, 0x00000000); | 226 | nv_wo32(priv->fb_bar, 0x10, 0x00000000); |
237 | BAR0_WI32(priv->fb_bar, 0x14, 0x00000000); | 227 | nv_wo32(priv->fb_bar, 0x14, 0x00000000); |
238 | 228 | ||
239 | /* Poke the relevant regs, and pray it works :) */ | 229 | nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4)); |
240 | nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12)); | ||
241 | nv_wr32(dev, NV50_PUNK_UNK1710, 0); | ||
242 | nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) | | ||
243 | NV50_PUNK_BAR_CFG_BASE_VALID); | ||
244 | nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) | | ||
245 | NV50_PUNK_BAR1_CTXDMA_VALID); | ||
246 | nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) | | ||
247 | NV50_PUNK_BAR3_CTXDMA_VALID); | ||
248 | |||
249 | for (i = 0; i < 8; i++) | 230 | for (i = 0; i < 8; i++) |
250 | nv_wr32(dev, 0x1900 + (i*4), 0); | 231 | nv_wr32(dev, 0x1900 + (i*4), 0); |
251 | 232 | ||
252 | dev_priv->ramin_available = true; | ||
253 | |||
254 | /* Assume that praying isn't enough, check that we can re-read the | ||
255 | * entire fake channel back from the PRAMIN BAR */ | ||
256 | for (i = 0; i < c_size; i += 4) { | ||
257 | if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) { | ||
258 | NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n", | ||
259 | i); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700); | ||
265 | |||
266 | /* Global PRAMIN heap */ | ||
267 | if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) { | ||
268 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); | ||
269 | } | ||
270 | |||
271 | /*XXX: incorrect, but needed to make hash func "work" */ | 233 | /*XXX: incorrect, but needed to make hash func "work" */ |
272 | dev_priv->ramht_offset = 0x10000; | 234 | dev_priv->ramht_offset = 0x10000; |
273 | dev_priv->ramht_bits = 9; | 235 | dev_priv->ramht_bits = 9; |
@@ -288,6 +250,8 @@ nv50_instmem_takedown(struct drm_device *dev) | |||
288 | if (!priv) | 250 | if (!priv) |
289 | return; | 251 | return; |
290 | 252 | ||
253 | dev_priv->ramin_available = false; | ||
254 | |||
291 | /* Restore state from before init */ | 255 | /* Restore state from before init */ |
292 | for (i = 0x1700; i <= 0x1710; i += 4) | 256 | for (i = 0x1700; i <= 0x1710; i += 4) |
293 | nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); | 257 | nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); |
@@ -302,13 +266,8 @@ nv50_instmem_takedown(struct drm_device *dev) | |||
302 | nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); | 266 | nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); |
303 | dev_priv->vm_vram_pt_nr = 0; | 267 | dev_priv->vm_vram_pt_nr = 0; |
304 | 268 | ||
305 | nouveau_gpuobj_ref(NULL, &chan->vm_pd); | 269 | nv50_channel_del(&dev_priv->fifos[0]); |
306 | nouveau_gpuobj_ref(NULL, &chan->ramfc); | 270 | dev_priv->fifos[127] = NULL; |
307 | nouveau_gpuobj_ref(NULL, &chan->ramin); | ||
308 | drm_mm_takedown(&chan->ramin_heap); | ||
309 | |||
310 | dev_priv->fifos[0] = dev_priv->fifos[127] = NULL; | ||
311 | kfree(chan); | ||
312 | } | 271 | } |
313 | 272 | ||
314 | dev_priv->engine.instmem.priv = NULL; | 273 | dev_priv->engine.instmem.priv = NULL; |
@@ -341,9 +300,11 @@ nv50_instmem_resume(struct drm_device *dev) | |||
341 | struct nouveau_gpuobj *ramin = chan->ramin; | 300 | struct nouveau_gpuobj *ramin = chan->ramin; |
342 | int i; | 301 | int i; |
343 | 302 | ||
344 | nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (ramin->vinst >> 16)); | 303 | dev_priv->ramin_available = false; |
304 | dev_priv->ramin_base = ~0; | ||
345 | for (i = 0; i < ramin->size; i += 4) | 305 | for (i = 0; i < ramin->size; i += 4) |
346 | BAR0_WI32(ramin, i, ramin->im_backing_suspend[i/4]); | 306 | nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]); |
307 | dev_priv->ramin_available = true; | ||
347 | vfree(ramin->im_backing_suspend); | 308 | vfree(ramin->im_backing_suspend); |
348 | ramin->im_backing_suspend = NULL; | 309 | ramin->im_backing_suspend = NULL; |
349 | 310 | ||
@@ -370,7 +331,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, | |||
370 | if (gpuobj->im_backing) | 331 | if (gpuobj->im_backing) |
371 | return -EINVAL; | 332 | return -EINVAL; |
372 | 333 | ||
373 | *sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE); | 334 | *sz = ALIGN(*sz, 4096); |
374 | if (*sz == 0) | 335 | if (*sz == 0) |
375 | return -EINVAL; | 336 | return -EINVAL; |
376 | 337 | ||
@@ -438,7 +399,7 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |||
438 | while (pte < pte_end) { | 399 | while (pte < pte_end) { |
439 | nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); | 400 | nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); |
440 | nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); | 401 | nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); |
441 | vram += NV50_INSTMEM_PAGE_SIZE; | 402 | vram += 0x1000; |
442 | pte += 2; | 403 | pte += 2; |
443 | } | 404 | } |
444 | dev_priv->engine.instmem.flush(dev); | 405 | dev_priv->engine.instmem.flush(dev); |
@@ -460,6 +421,10 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |||
460 | if (gpuobj->im_bound == 0) | 421 | if (gpuobj->im_bound == 0) |
461 | return -EINVAL; | 422 | return -EINVAL; |
462 | 423 | ||
424 | /* can happen during late takedown */ | ||
425 | if (unlikely(!dev_priv->ramin_available)) | ||
426 | return 0; | ||
427 | |||
463 | pte = (gpuobj->im_pramin->start >> 12) << 1; | 428 | pte = (gpuobj->im_pramin->start >> 12) << 1; |
464 | pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; | 429 | pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; |
465 | 430 | ||