diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_bo.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drv.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mem.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_mm.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_state.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_instmem.c | 326 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_vram.c | 91 |
8 files changed, 266 insertions, 204 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index e89d89593af1..d9d22ffff81e 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile | |||
@@ -28,7 +28,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ | |||
28 | nv10_gpio.o nv50_gpio.o \ | 28 | nv10_gpio.o nv50_gpio.o \ |
29 | nv50_calc.o \ | 29 | nv50_calc.o \ |
30 | nv04_pm.o nv50_pm.o nva3_pm.o \ | 30 | nv04_pm.o nv50_pm.o nva3_pm.o \ |
31 | nv50_vram.o nv50_vm.o nvc0_vm.o | 31 | nv50_vram.o nvc0_vram.o \ |
32 | nv50_vm.o nvc0_vm.o | ||
32 | 33 | ||
33 | nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o | 34 | nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o |
34 | nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o | 35 | nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o |
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index d17ffea3c617..6f3096a50297 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c | |||
@@ -120,6 +120,9 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, | |||
120 | align >>= PAGE_SHIFT; | 120 | align >>= PAGE_SHIFT; |
121 | 121 | ||
122 | if (!nvbo->no_vm && dev_priv->chan_vm) { | 122 | if (!nvbo->no_vm && dev_priv->chan_vm) { |
123 | if (dev_priv->card_type == NV_C0) | ||
124 | page_shift = 12; | ||
125 | |||
123 | ret = nouveau_vm_get(dev_priv->chan_vm, size, page_shift, | 126 | ret = nouveau_vm_get(dev_priv->chan_vm, size, page_shift, |
124 | NV_MEM_ACCESS_RW, &nvbo->vma); | 127 | NV_MEM_ACCESS_RW, &nvbo->vma); |
125 | if (ret) { | 128 | if (ret) { |
@@ -413,7 +416,7 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, | |||
413 | man->default_caching = TTM_PL_FLAG_CACHED; | 416 | man->default_caching = TTM_PL_FLAG_CACHED; |
414 | break; | 417 | break; |
415 | case TTM_PL_VRAM: | 418 | case TTM_PL_VRAM: |
416 | if (dev_priv->card_type == NV_50) { | 419 | if (dev_priv->card_type >= NV_50) { |
417 | man->func = &nouveau_vram_manager; | 420 | man->func = &nouveau_vram_manager; |
418 | man->io_reserve_fastpath = false; | 421 | man->io_reserve_fastpath = false; |
419 | man->use_io_reserve_lru = true; | 422 | man->use_io_reserve_lru = true; |
@@ -901,6 +904,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | |||
901 | case TTM_PL_VRAM: | 904 | case TTM_PL_VRAM: |
902 | { | 905 | { |
903 | struct nouveau_vram *vram = mem->mm_node; | 906 | struct nouveau_vram *vram = mem->mm_node; |
907 | u8 page_shift; | ||
904 | 908 | ||
905 | if (!dev_priv->bar1_vm) { | 909 | if (!dev_priv->bar1_vm) { |
906 | mem->bus.offset = mem->start << PAGE_SHIFT; | 910 | mem->bus.offset = mem->start << PAGE_SHIFT; |
@@ -909,8 +913,13 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | |||
909 | break; | 913 | break; |
910 | } | 914 | } |
911 | 915 | ||
916 | if (dev_priv->card_type == NV_C0) | ||
917 | page_shift = vram->page_shift; | ||
918 | else | ||
919 | page_shift = 12; | ||
920 | |||
912 | ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size, | 921 | ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size, |
913 | vram->page_shift, NV_MEM_ACCESS_RW, | 922 | page_shift, NV_MEM_ACCESS_RW, |
914 | &vram->bar_vma); | 923 | &vram->bar_vma); |
915 | if (ret) | 924 | if (ret) |
916 | return ret; | 925 | return ret; |
@@ -921,8 +930,9 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) | |||
921 | return ret; | 930 | return ret; |
922 | } | 931 | } |
923 | 932 | ||
924 | mem->bus.offset = vram->bar_vma.offset; | 933 | mem->bus.offset = vram->bar_vma.offset; |
925 | mem->bus.offset -= 0x0020000000ULL; | 934 | if (dev_priv->card_type == NV_50) /*XXX*/ |
935 | mem->bus.offset -= 0x0020000000ULL; | ||
926 | mem->bus.base = pci_resource_start(dev->pdev, 1); | 936 | mem->bus.base = pci_resource_start(dev->pdev, 1); |
927 | mem->bus.is_iomem = true; | 937 | mem->bus.is_iomem = true; |
928 | } | 938 | } |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 57da219fb18b..c1e85c4c7ac2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h | |||
@@ -842,6 +842,9 @@ extern void nv10_mem_put_tile_region(struct drm_device *dev, | |||
842 | struct nouveau_fence *fence); | 842 | struct nouveau_fence *fence); |
843 | extern const struct ttm_mem_type_manager_func nouveau_vram_manager; | 843 | extern const struct ttm_mem_type_manager_func nouveau_vram_manager; |
844 | 844 | ||
845 | /* nvc0_vram.c */ | ||
846 | extern const struct ttm_mem_type_manager_func nvc0_vram_manager; | ||
847 | |||
845 | /* nouveau_notifier.c */ | 848 | /* nouveau_notifier.c */ |
846 | extern int nouveau_notifier_init_channel(struct nouveau_channel *); | 849 | extern int nouveau_notifier_init_channel(struct nouveau_channel *); |
847 | extern void nouveau_notifier_takedown_channel(struct nouveau_channel *); | 850 | extern void nouveau_notifier_takedown_channel(struct nouveau_channel *); |
@@ -1229,11 +1232,6 @@ extern int nvc0_instmem_init(struct drm_device *); | |||
1229 | extern void nvc0_instmem_takedown(struct drm_device *); | 1232 | extern void nvc0_instmem_takedown(struct drm_device *); |
1230 | extern int nvc0_instmem_suspend(struct drm_device *); | 1233 | extern int nvc0_instmem_suspend(struct drm_device *); |
1231 | extern void nvc0_instmem_resume(struct drm_device *); | 1234 | extern void nvc0_instmem_resume(struct drm_device *); |
1232 | extern int nvc0_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align); | ||
1233 | extern void nvc0_instmem_put(struct nouveau_gpuobj *); | ||
1234 | extern int nvc0_instmem_map(struct nouveau_gpuobj *); | ||
1235 | extern void nvc0_instmem_unmap(struct nouveau_gpuobj *); | ||
1236 | extern void nvc0_instmem_flush(struct drm_device *); | ||
1237 | 1235 | ||
1238 | /* nv04_mc.c */ | 1236 | /* nv04_mc.c */ |
1239 | extern int nv04_mc_init(struct drm_device *); | 1237 | extern int nv04_mc_init(struct drm_device *); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 07be1dd04530..69044eb104bb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c | |||
@@ -255,9 +255,6 @@ nouveau_mem_detect(struct drm_device *dev) | |||
255 | if (dev_priv->card_type < NV_50) { | 255 | if (dev_priv->card_type < NV_50) { |
256 | dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); | 256 | dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); |
257 | dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; | 257 | dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; |
258 | } else { | ||
259 | dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; | ||
260 | dev_priv->vram_size *= nv_rd32(dev, 0x121c74); | ||
261 | } | 258 | } |
262 | 259 | ||
263 | if (dev_priv->vram_size) | 260 | if (dev_priv->vram_size) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_mm.h b/drivers/gpu/drm/nouveau/nouveau_mm.h index 250e642de0a7..af3844933036 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mm.h +++ b/drivers/gpu/drm/nouveau/nouveau_mm.h | |||
@@ -59,4 +59,9 @@ int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc, | |||
59 | void nv50_vram_del(struct drm_device *, struct nouveau_vram **); | 59 | void nv50_vram_del(struct drm_device *, struct nouveau_vram **); |
60 | bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags); | 60 | bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags); |
61 | 61 | ||
62 | int nvc0_vram_init(struct drm_device *); | ||
63 | int nvc0_vram_new(struct drm_device *, u64 size, u32 align, u32 ncmin, | ||
64 | u32 memtype, struct nouveau_vram **); | ||
65 | bool nvc0_vram_flags_valid(struct drm_device *, u32 tile_flags); | ||
66 | |||
62 | #endif | 67 | #endif |
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 8eac943e8fd2..813790f4c7c7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c | |||
@@ -464,11 +464,11 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
464 | engine->instmem.takedown = nvc0_instmem_takedown; | 464 | engine->instmem.takedown = nvc0_instmem_takedown; |
465 | engine->instmem.suspend = nvc0_instmem_suspend; | 465 | engine->instmem.suspend = nvc0_instmem_suspend; |
466 | engine->instmem.resume = nvc0_instmem_resume; | 466 | engine->instmem.resume = nvc0_instmem_resume; |
467 | engine->instmem.get = nvc0_instmem_get; | 467 | engine->instmem.get = nv50_instmem_get; |
468 | engine->instmem.put = nvc0_instmem_put; | 468 | engine->instmem.put = nv50_instmem_put; |
469 | engine->instmem.map = nvc0_instmem_map; | 469 | engine->instmem.map = nv50_instmem_map; |
470 | engine->instmem.unmap = nvc0_instmem_unmap; | 470 | engine->instmem.unmap = nv50_instmem_unmap; |
471 | engine->instmem.flush = nvc0_instmem_flush; | 471 | engine->instmem.flush = nv84_instmem_flush; |
472 | engine->mc.init = nv50_mc_init; | 472 | engine->mc.init = nv50_mc_init; |
473 | engine->mc.takedown = nv50_mc_takedown; | 473 | engine->mc.takedown = nv50_mc_takedown; |
474 | engine->timer.init = nv04_timer_init; | 474 | engine->timer.init = nv04_timer_init; |
@@ -509,8 +509,10 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev) | |||
509 | engine->gpio.irq_enable = nv50_gpio_irq_enable; | 509 | engine->gpio.irq_enable = nv50_gpio_irq_enable; |
510 | engine->crypt.init = nouveau_stub_init; | 510 | engine->crypt.init = nouveau_stub_init; |
511 | engine->crypt.takedown = nouveau_stub_takedown; | 511 | engine->crypt.takedown = nouveau_stub_takedown; |
512 | engine->vram.init = nouveau_mem_detect; | 512 | engine->vram.init = nvc0_vram_init; |
513 | engine->vram.flags_valid = nouveau_mem_flags_valid; | 513 | engine->vram.get = nvc0_vram_new; |
514 | engine->vram.put = nv50_vram_del; | ||
515 | engine->vram.flags_valid = nvc0_vram_flags_valid; | ||
514 | break; | 516 | break; |
515 | default: | 517 | default: |
516 | NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); | 518 | NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); |
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 39232085193d..211099736553 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c | |||
@@ -25,233 +25,191 @@ | |||
25 | #include "drmP.h" | 25 | #include "drmP.h" |
26 | 26 | ||
27 | #include "nouveau_drv.h" | 27 | #include "nouveau_drv.h" |
28 | #include "nouveau_vm.h" | ||
28 | 29 | ||
29 | struct nvc0_gpuobj_node { | 30 | struct nvc0_instmem_priv { |
30 | struct nouveau_bo *vram; | 31 | struct nouveau_gpuobj *bar1_pgd; |
31 | struct drm_mm_node *ramin; | 32 | struct nouveau_channel *bar1; |
32 | u32 align; | 33 | struct nouveau_gpuobj *bar3_pgd; |
34 | struct nouveau_channel *bar3; | ||
33 | }; | 35 | }; |
34 | 36 | ||
35 | int | 37 | int |
36 | nvc0_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) | 38 | nvc0_instmem_suspend(struct drm_device *dev) |
37 | { | 39 | { |
38 | struct drm_device *dev = gpuobj->dev; | 40 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
39 | struct nvc0_gpuobj_node *node = NULL; | ||
40 | int ret; | ||
41 | |||
42 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
43 | if (!node) | ||
44 | return -ENOMEM; | ||
45 | node->align = align; | ||
46 | |||
47 | ret = nouveau_bo_new(dev, NULL, size, align, TTM_PL_FLAG_VRAM, | ||
48 | 0, 0x0000, true, false, &node->vram); | ||
49 | if (ret) { | ||
50 | NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); | ||
51 | return ret; | ||
52 | } | ||
53 | |||
54 | ret = nouveau_bo_pin(node->vram, TTM_PL_FLAG_VRAM); | ||
55 | if (ret) { | ||
56 | NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); | ||
57 | nouveau_bo_ref(NULL, &node->vram); | ||
58 | return ret; | ||
59 | } | ||
60 | 41 | ||
61 | gpuobj->vinst = node->vram->bo.mem.start << PAGE_SHIFT; | 42 | dev_priv->ramin_available = false; |
62 | gpuobj->size = node->vram->bo.mem.num_pages << PAGE_SHIFT; | ||
63 | gpuobj->node = node; | ||
64 | return 0; | 43 | return 0; |
65 | } | 44 | } |
66 | 45 | ||
67 | void | 46 | void |
68 | nvc0_instmem_put(struct nouveau_gpuobj *gpuobj) | 47 | nvc0_instmem_resume(struct drm_device *dev) |
69 | { | 48 | { |
70 | struct nvc0_gpuobj_node *node; | 49 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
71 | 50 | struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; | |
72 | node = gpuobj->node; | ||
73 | gpuobj->node = NULL; | ||
74 | 51 | ||
75 | nouveau_bo_unpin(node->vram); | 52 | nv_mask(dev, 0x100c80, 0x00000001, 0x00000000); |
76 | nouveau_bo_ref(NULL, &node->vram); | 53 | nv_wr32(dev, 0x001704, 0x80000000 | priv->bar1->ramin->vinst >> 12); |
77 | kfree(node); | 54 | nv_wr32(dev, 0x001714, 0xc0000000 | priv->bar3->ramin->vinst >> 12); |
55 | dev_priv->ramin_available = true; | ||
78 | } | 56 | } |
79 | 57 | ||
80 | int | 58 | static void |
81 | nvc0_instmem_map(struct nouveau_gpuobj *gpuobj) | 59 | nvc0_channel_del(struct nouveau_channel **pchan) |
82 | { | 60 | { |
83 | struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; | 61 | struct nouveau_channel *chan; |
84 | struct nvc0_gpuobj_node *node = gpuobj->node; | ||
85 | struct drm_device *dev = gpuobj->dev; | ||
86 | struct drm_mm_node *ramin = NULL; | ||
87 | u32 pte, pte_end; | ||
88 | u64 vram; | ||
89 | |||
90 | do { | ||
91 | if (drm_mm_pre_get(&dev_priv->ramin_heap)) | ||
92 | return -ENOMEM; | ||
93 | |||
94 | spin_lock(&dev_priv->ramin_lock); | ||
95 | ramin = drm_mm_search_free(&dev_priv->ramin_heap, gpuobj->size, | ||
96 | node->align, 0); | ||
97 | if (ramin == NULL) { | ||
98 | spin_unlock(&dev_priv->ramin_lock); | ||
99 | return -ENOMEM; | ||
100 | } | ||
101 | |||
102 | ramin = drm_mm_get_block_atomic(ramin, gpuobj->size, node->align); | ||
103 | spin_unlock(&dev_priv->ramin_lock); | ||
104 | } while (ramin == NULL); | ||
105 | |||
106 | pte = (ramin->start >> 12) << 1; | ||
107 | pte_end = ((ramin->size >> 12) << 1) + pte; | ||
108 | vram = gpuobj->vinst; | ||
109 | |||
110 | NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", | ||
111 | ramin->start, pte, pte_end); | ||
112 | NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); | ||
113 | |||
114 | while (pte < pte_end) { | ||
115 | nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); | ||
116 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | ||
117 | vram += 4096; | ||
118 | pte++; | ||
119 | } | ||
120 | dev_priv->engine.instmem.flush(dev); | ||
121 | 62 | ||
122 | if (1) { | 63 | chan = *pchan; |
123 | u32 chan = nv_rd32(dev, 0x1700) << 16; | 64 | *pchan = NULL; |
124 | nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); | 65 | if (!chan) |
125 | nv_wr32(dev, 0x100cbc, 0x80000005); | 66 | return; |
126 | } | ||
127 | 67 | ||
128 | node->ramin = ramin; | 68 | nouveau_vm_ref(NULL, &chan->vm, NULL); |
129 | gpuobj->pinst = ramin->start; | 69 | if (chan->ramin_heap.free_stack.next) |
130 | return 0; | 70 | drm_mm_takedown(&chan->ramin_heap); |
71 | nouveau_gpuobj_ref(NULL, &chan->ramin); | ||
72 | kfree(chan); | ||
131 | } | 73 | } |
132 | 74 | ||
133 | void | 75 | static int |
134 | nvc0_instmem_unmap(struct nouveau_gpuobj *gpuobj) | 76 | nvc0_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, |
77 | struct nouveau_channel **pchan, | ||
78 | struct nouveau_gpuobj *pgd, u64 vm_size) | ||
135 | { | 79 | { |
136 | struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; | 80 | struct nouveau_channel *chan; |
137 | struct nvc0_gpuobj_node *node = gpuobj->node; | 81 | int ret; |
138 | u32 pte, pte_end; | ||
139 | 82 | ||
140 | if (!node->ramin || !dev_priv->ramin_available) | 83 | chan = kzalloc(sizeof(*chan), GFP_KERNEL); |
141 | return; | 84 | if (!chan) |
85 | return -ENOMEM; | ||
86 | chan->dev = dev; | ||
142 | 87 | ||
143 | pte = (node->ramin->start >> 12) << 1; | 88 | ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); |
144 | pte_end = ((node->ramin->size >> 12) << 1) + pte; | 89 | if (ret) { |
90 | nvc0_channel_del(&chan); | ||
91 | return ret; | ||
92 | } | ||
145 | 93 | ||
146 | while (pte < pte_end) { | 94 | ret = drm_mm_init(&chan->ramin_heap, 0x1000, size - 0x1000); |
147 | nv_wr32(gpuobj->dev, 0x702000 + (pte * 8), 0); | 95 | if (ret) { |
148 | nv_wr32(gpuobj->dev, 0x702004 + (pte * 8), 0); | 96 | nvc0_channel_del(&chan); |
149 | pte++; | 97 | return ret; |
150 | } | 98 | } |
151 | dev_priv->engine.instmem.flush(gpuobj->dev); | ||
152 | 99 | ||
153 | spin_lock(&dev_priv->ramin_lock); | 100 | ret = nouveau_vm_ref(vm, &chan->vm, NULL); |
154 | drm_mm_put_block(node->ramin); | 101 | if (ret) { |
155 | node->ramin = NULL; | 102 | nvc0_channel_del(&chan); |
156 | spin_unlock(&dev_priv->ramin_lock); | 103 | return ret; |
157 | } | 104 | } |
158 | 105 | ||
159 | void | 106 | nv_wo32(chan->ramin, 0x0200, lower_32_bits(pgd->vinst)); |
160 | nvc0_instmem_flush(struct drm_device *dev) | 107 | nv_wo32(chan->ramin, 0x0204, upper_32_bits(pgd->vinst)); |
161 | { | 108 | nv_wo32(chan->ramin, 0x0208, lower_32_bits(vm_size - 1)); |
162 | nv_wr32(dev, 0x070000, 1); | 109 | nv_wo32(chan->ramin, 0x020c, upper_32_bits(vm_size - 1)); |
163 | if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) | 110 | |
164 | NV_ERROR(dev, "PRAMIN flush timeout\n"); | 111 | *pchan = chan; |
112 | return 0; | ||
165 | } | 113 | } |
166 | 114 | ||
167 | int | 115 | int |
168 | nvc0_instmem_suspend(struct drm_device *dev) | 116 | nvc0_instmem_init(struct drm_device *dev) |
169 | { | 117 | { |
170 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 118 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
171 | u32 *buf; | 119 | struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; |
172 | int i; | 120 | struct pci_dev *pdev = dev->pdev; |
121 | struct nvc0_instmem_priv *priv; | ||
122 | struct nouveau_vm *vm = NULL; | ||
123 | int ret; | ||
173 | 124 | ||
174 | dev_priv->susres.ramin_copy = vmalloc(65536); | 125 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
175 | if (!dev_priv->susres.ramin_copy) | 126 | if (!priv) |
176 | return -ENOMEM; | 127 | return -ENOMEM; |
177 | buf = dev_priv->susres.ramin_copy; | 128 | pinstmem->priv = priv; |
178 | 129 | ||
179 | for (i = 0; i < 65536; i += 4) | 130 | /* BAR3 VM */ |
180 | buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i); | 131 | ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 3), 0, |
132 | &dev_priv->bar3_vm); | ||
133 | if (ret) | ||
134 | goto error; | ||
135 | |||
136 | ret = nouveau_gpuobj_new(dev, NULL, | ||
137 | (pci_resource_len(pdev, 3) >> 12) * 8, 0, | ||
138 | NVOBJ_FLAG_DONT_MAP | | ||
139 | NVOBJ_FLAG_ZERO_ALLOC, | ||
140 | &dev_priv->bar3_vm->pgt[0].obj[0]); | ||
141 | if (ret) | ||
142 | goto error; | ||
143 | dev_priv->bar3_vm->pgt[0].refcount[0] = 1; | ||
144 | |||
145 | nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); | ||
146 | |||
147 | ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, | ||
148 | NVOBJ_FLAG_ZERO_ALLOC, &priv->bar3_pgd); | ||
149 | if (ret) | ||
150 | goto error; | ||
151 | |||
152 | ret = nouveau_vm_ref(dev_priv->bar3_vm, &vm, priv->bar3_pgd); | ||
153 | if (ret) | ||
154 | goto error; | ||
155 | nouveau_vm_ref(NULL, &vm, NULL); | ||
156 | |||
157 | ret = nvc0_channel_new(dev, 8192, dev_priv->bar3_vm, &priv->bar3, | ||
158 | priv->bar3_pgd, pci_resource_len(dev->pdev, 3)); | ||
159 | if (ret) | ||
160 | goto error; | ||
161 | |||
162 | /* BAR1 VM */ | ||
163 | ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 1), 0, &vm); | ||
164 | if (ret) | ||
165 | goto error; | ||
166 | |||
167 | ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, | ||
168 | NVOBJ_FLAG_ZERO_ALLOC, &priv->bar1_pgd); | ||
169 | if (ret) | ||
170 | goto error; | ||
171 | |||
172 | ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, priv->bar1_pgd); | ||
173 | if (ret) | ||
174 | goto error; | ||
175 | nouveau_vm_ref(NULL, &vm, NULL); | ||
176 | |||
177 | ret = nvc0_channel_new(dev, 8192, dev_priv->bar1_vm, &priv->bar1, | ||
178 | priv->bar1_pgd, pci_resource_len(dev->pdev, 1)); | ||
179 | if (ret) | ||
180 | goto error; | ||
181 | |||
182 | nvc0_instmem_resume(dev); | ||
181 | return 0; | 183 | return 0; |
184 | error: | ||
185 | nvc0_instmem_takedown(dev); | ||
186 | return ret; | ||
182 | } | 187 | } |
183 | 188 | ||
184 | void | 189 | void |
185 | nvc0_instmem_resume(struct drm_device *dev) | 190 | nvc0_instmem_takedown(struct drm_device *dev) |
186 | { | ||
187 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
188 | u32 *buf = dev_priv->susres.ramin_copy; | ||
189 | u64 chan; | ||
190 | int i; | ||
191 | |||
192 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | ||
193 | nv_wr32(dev, 0x001700, chan >> 16); | ||
194 | |||
195 | for (i = 0; i < 65536; i += 4) | ||
196 | nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]); | ||
197 | vfree(dev_priv->susres.ramin_copy); | ||
198 | dev_priv->susres.ramin_copy = NULL; | ||
199 | |||
200 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | ||
201 | } | ||
202 | |||
203 | int | ||
204 | nvc0_instmem_init(struct drm_device *dev) | ||
205 | { | 191 | { |
206 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 192 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
207 | u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; | 193 | struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; |
208 | int ret, i; | 194 | struct nouveau_vm *vm = NULL; |
209 | |||
210 | dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; | ||
211 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | ||
212 | imem = 4096 + 4096 + 32768; | ||
213 | |||
214 | nv_wr32(dev, 0x001700, chan >> 16); | ||
215 | |||
216 | /* channel setup */ | ||
217 | nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); | ||
218 | nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); | ||
219 | nv_wr32(dev, 0x700208, lower_32_bits(lim3)); | ||
220 | nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); | ||
221 | |||
222 | /* point pgd -> pgt */ | ||
223 | nv_wr32(dev, 0x701000, 0); | ||
224 | nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); | ||
225 | |||
226 | /* point pgt -> physical vram for channel */ | ||
227 | pgt3 = 0x2000; | ||
228 | for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { | ||
229 | nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); | ||
230 | nv_wr32(dev, 0x700004 + pgt3, 0); | ||
231 | } | ||
232 | 195 | ||
233 | /* clear rest of pgt */ | 196 | nvc0_instmem_suspend(dev); |
234 | for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { | ||
235 | nv_wr32(dev, 0x700000 + pgt3, 0); | ||
236 | nv_wr32(dev, 0x700004 + pgt3, 0); | ||
237 | } | ||
238 | 197 | ||
239 | /* point bar3 at the channel */ | 198 | nv_wr32(dev, 0x1704, 0x00000000); |
240 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | 199 | nv_wr32(dev, 0x1714, 0x00000000); |
241 | 200 | ||
242 | /* Global PRAMIN heap */ | 201 | nvc0_channel_del(&priv->bar1); |
243 | ret = drm_mm_init(&dev_priv->ramin_heap, imem, | 202 | nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd); |
244 | dev_priv->ramin_size - imem); | 203 | nouveau_gpuobj_ref(NULL, &priv->bar1_pgd); |
245 | if (ret) { | ||
246 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); | ||
247 | return -ENOMEM; | ||
248 | } | ||
249 | 204 | ||
250 | return 0; | 205 | nvc0_channel_del(&priv->bar3); |
251 | } | 206 | nouveau_vm_ref(dev_priv->bar3_vm, &vm, NULL); |
207 | nouveau_vm_ref(NULL, &vm, priv->bar3_pgd); | ||
208 | nouveau_gpuobj_ref(NULL, &priv->bar3_pgd); | ||
209 | nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); | ||
210 | nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); | ||
252 | 211 | ||
253 | void | 212 | dev_priv->engine.instmem.priv = NULL; |
254 | nvc0_instmem_takedown(struct drm_device *dev) | 213 | kfree(priv); |
255 | { | ||
256 | } | 214 | } |
257 | 215 | ||
diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c new file mode 100644 index 000000000000..41fcae5ffba4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvc0_vram.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Red Hat Inc. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
20 | * OTHER DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Authors: Ben Skeggs | ||
23 | */ | ||
24 | |||
25 | #include "drmP.h" | ||
26 | #include "nouveau_drv.h" | ||
27 | #include "nouveau_mm.h" | ||
28 | |||
29 | bool | ||
30 | nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags) | ||
31 | { | ||
32 | if (likely(!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK))) | ||
33 | return true; | ||
34 | return false; | ||
35 | } | ||
36 | |||
37 | int | ||
38 | nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, | ||
39 | u32 type, struct nouveau_vram **pvram) | ||
40 | { | ||
41 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
42 | struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; | ||
43 | struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; | ||
44 | struct nouveau_mm *mm = man->priv; | ||
45 | struct nouveau_mm_node *r; | ||
46 | struct nouveau_vram *vram; | ||
47 | int ret; | ||
48 | |||
49 | size >>= 12; | ||
50 | align >>= 12; | ||
51 | ncmin >>= 12; | ||
52 | |||
53 | vram = kzalloc(sizeof(*vram), GFP_KERNEL); | ||
54 | if (!vram) | ||
55 | return -ENOMEM; | ||
56 | |||
57 | INIT_LIST_HEAD(&vram->regions); | ||
58 | vram->dev = dev_priv->dev; | ||
59 | vram->memtype = type; | ||
60 | vram->size = size; | ||
61 | |||
62 | mutex_lock(&mm->mutex); | ||
63 | do { | ||
64 | ret = nouveau_mm_get(mm, 1, size, ncmin, align, &r); | ||
65 | if (ret) { | ||
66 | mutex_unlock(&mm->mutex); | ||
67 | nv50_vram_del(dev, &vram); | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | list_add_tail(&r->rl_entry, &vram->regions); | ||
72 | size -= r->length; | ||
73 | } while (size); | ||
74 | mutex_unlock(&mm->mutex); | ||
75 | |||
76 | r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); | ||
77 | vram->offset = (u64)r->offset << 12; | ||
78 | *pvram = vram; | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | int | ||
83 | nvc0_vram_init(struct drm_device *dev) | ||
84 | { | ||
85 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
86 | |||
87 | dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; | ||
88 | dev_priv->vram_size *= nv_rd32(dev, 0x121c74); | ||
89 | dev_priv->vram_rblock_size = 4096; | ||
90 | return 0; | ||
91 | } | ||