diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvc0_instmem.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_instmem.c | 326 |
1 files changed, 142 insertions, 184 deletions
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 | ||