diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvc0_instmem.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvc0_instmem.c | 317 |
1 files changed, 159 insertions, 158 deletions
diff --git a/drivers/gpu/drm/nouveau/nvc0_instmem.c b/drivers/gpu/drm/nouveau/nvc0_instmem.c index 13a0f78a9088..c09091749054 100644 --- a/drivers/gpu/drm/nouveau/nvc0_instmem.c +++ b/drivers/gpu/drm/nouveau/nvc0_instmem.c | |||
@@ -25,206 +25,207 @@ | |||
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" | ||
29 | |||
30 | struct nvc0_instmem_priv { | ||
31 | struct nouveau_gpuobj *bar1_pgd; | ||
32 | struct nouveau_channel *bar1; | ||
33 | struct nouveau_gpuobj *bar3_pgd; | ||
34 | struct nouveau_channel *bar3; | ||
35 | struct nouveau_gpuobj *chan_pgd; | ||
36 | }; | ||
28 | 37 | ||
29 | int | 38 | int |
30 | nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, | 39 | nvc0_instmem_suspend(struct drm_device *dev) |
31 | uint32_t *size) | ||
32 | { | 40 | { |
33 | int ret; | 41 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
34 | |||
35 | *size = ALIGN(*size, 4096); | ||
36 | if (*size == 0) | ||
37 | return -EINVAL; | ||
38 | |||
39 | ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, | ||
40 | true, false, &gpuobj->im_backing); | ||
41 | if (ret) { | ||
42 | NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); | ||
43 | return ret; | ||
44 | } | ||
45 | |||
46 | ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); | ||
47 | if (ret) { | ||
48 | NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); | ||
49 | nouveau_bo_ref(NULL, &gpuobj->im_backing); | ||
50 | return ret; | ||
51 | } | ||
52 | 42 | ||
53 | gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT; | 43 | dev_priv->ramin_available = false; |
54 | return 0; | 44 | return 0; |
55 | } | 45 | } |
56 | 46 | ||
57 | void | 47 | void |
58 | nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | 48 | nvc0_instmem_resume(struct drm_device *dev) |
59 | { | 49 | { |
60 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 50 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
51 | struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; | ||
61 | 52 | ||
62 | if (gpuobj && gpuobj->im_backing) { | 53 | nv_mask(dev, 0x100c80, 0x00000001, 0x00000000); |
63 | if (gpuobj->im_bound) | 54 | nv_wr32(dev, 0x001704, 0x80000000 | priv->bar1->ramin->vinst >> 12); |
64 | dev_priv->engine.instmem.unbind(dev, gpuobj); | 55 | nv_wr32(dev, 0x001714, 0xc0000000 | priv->bar3->ramin->vinst >> 12); |
65 | nouveau_bo_unpin(gpuobj->im_backing); | 56 | dev_priv->ramin_available = true; |
66 | nouveau_bo_ref(NULL, &gpuobj->im_backing); | ||
67 | gpuobj->im_backing = NULL; | ||
68 | } | ||
69 | } | 57 | } |
70 | 58 | ||
71 | int | 59 | static void |
72 | nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | 60 | nvc0_channel_del(struct nouveau_channel **pchan) |
73 | { | 61 | { |
74 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 62 | struct nouveau_channel *chan; |
75 | uint32_t pte, pte_end; | 63 | |
76 | uint64_t vram; | 64 | chan = *pchan; |
77 | 65 | *pchan = NULL; | |
78 | if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) | 66 | if (!chan) |
79 | return -EINVAL; | 67 | return; |
80 | 68 | ||
81 | NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", | 69 | nouveau_vm_ref(NULL, &chan->vm, NULL); |
82 | gpuobj->im_pramin->start, gpuobj->im_pramin->size); | 70 | if (chan->ramin_heap.free_stack.next) |
71 | drm_mm_takedown(&chan->ramin_heap); | ||
72 | nouveau_gpuobj_ref(NULL, &chan->ramin); | ||
73 | kfree(chan); | ||
74 | } | ||
83 | 75 | ||
84 | pte = gpuobj->im_pramin->start >> 12; | 76 | static int |
85 | pte_end = (gpuobj->im_pramin->size >> 12) + pte; | 77 | nvc0_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, |
86 | vram = gpuobj->vinst; | 78 | struct nouveau_channel **pchan, |
79 | struct nouveau_gpuobj *pgd, u64 vm_size) | ||
80 | { | ||
81 | struct nouveau_channel *chan; | ||
82 | int ret; | ||
87 | 83 | ||
88 | NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", | 84 | chan = kzalloc(sizeof(*chan), GFP_KERNEL); |
89 | gpuobj->im_pramin->start, pte, pte_end); | 85 | if (!chan) |
90 | NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); | 86 | return -ENOMEM; |
87 | chan->dev = dev; | ||
91 | 88 | ||
92 | while (pte < pte_end) { | 89 | ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); |
93 | nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); | 90 | if (ret) { |
94 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | 91 | nvc0_channel_del(&chan); |
95 | vram += 4096; | 92 | return ret; |
96 | pte++; | ||
97 | } | 93 | } |
98 | dev_priv->engine.instmem.flush(dev); | ||
99 | 94 | ||
100 | if (1) { | 95 | ret = drm_mm_init(&chan->ramin_heap, 0x1000, size - 0x1000); |
101 | u32 chan = nv_rd32(dev, 0x1700) << 16; | 96 | if (ret) { |
102 | nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); | 97 | nvc0_channel_del(&chan); |
103 | nv_wr32(dev, 0x100cbc, 0x80000005); | 98 | return ret; |
104 | } | 99 | } |
105 | 100 | ||
106 | gpuobj->im_bound = 1; | 101 | ret = nouveau_vm_ref(vm, &chan->vm, NULL); |
107 | return 0; | 102 | if (ret) { |
108 | } | 103 | nvc0_channel_del(&chan); |
109 | 104 | return ret; | |
110 | int | ||
111 | nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | ||
112 | { | ||
113 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
114 | uint32_t pte, pte_end; | ||
115 | |||
116 | if (gpuobj->im_bound == 0) | ||
117 | return -EINVAL; | ||
118 | |||
119 | pte = gpuobj->im_pramin->start >> 12; | ||
120 | pte_end = (gpuobj->im_pramin->size >> 12) + pte; | ||
121 | while (pte < pte_end) { | ||
122 | nv_wr32(dev, 0x702000 + (pte * 8), 0); | ||
123 | nv_wr32(dev, 0x702004 + (pte * 8), 0); | ||
124 | pte++; | ||
125 | } | 105 | } |
126 | dev_priv->engine.instmem.flush(dev); | ||
127 | 106 | ||
128 | gpuobj->im_bound = 0; | 107 | nv_wo32(chan->ramin, 0x0200, lower_32_bits(pgd->vinst)); |
129 | return 0; | 108 | nv_wo32(chan->ramin, 0x0204, upper_32_bits(pgd->vinst)); |
130 | } | 109 | nv_wo32(chan->ramin, 0x0208, lower_32_bits(vm_size - 1)); |
110 | nv_wo32(chan->ramin, 0x020c, upper_32_bits(vm_size - 1)); | ||
131 | 111 | ||
132 | void | 112 | *pchan = chan; |
133 | nvc0_instmem_flush(struct drm_device *dev) | 113 | return 0; |
134 | { | ||
135 | nv_wr32(dev, 0x070000, 1); | ||
136 | if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) | ||
137 | NV_ERROR(dev, "PRAMIN flush timeout\n"); | ||
138 | } | 114 | } |
139 | 115 | ||
140 | int | 116 | int |
141 | nvc0_instmem_suspend(struct drm_device *dev) | 117 | nvc0_instmem_init(struct drm_device *dev) |
142 | { | 118 | { |
143 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 119 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
144 | u32 *buf; | 120 | struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; |
145 | int i; | 121 | struct pci_dev *pdev = dev->pdev; |
122 | struct nvc0_instmem_priv *priv; | ||
123 | struct nouveau_vm *vm = NULL; | ||
124 | int ret; | ||
146 | 125 | ||
147 | dev_priv->susres.ramin_copy = vmalloc(65536); | 126 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
148 | if (!dev_priv->susres.ramin_copy) | 127 | if (!priv) |
149 | return -ENOMEM; | 128 | return -ENOMEM; |
150 | buf = dev_priv->susres.ramin_copy; | 129 | pinstmem->priv = priv; |
151 | 130 | ||
152 | for (i = 0; i < 65536; i += 4) | 131 | /* BAR3 VM */ |
153 | buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i); | 132 | ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 3), 0, |
133 | &dev_priv->bar3_vm); | ||
134 | if (ret) | ||
135 | goto error; | ||
136 | |||
137 | ret = nouveau_gpuobj_new(dev, NULL, | ||
138 | (pci_resource_len(pdev, 3) >> 12) * 8, 0, | ||
139 | NVOBJ_FLAG_DONT_MAP | | ||
140 | NVOBJ_FLAG_ZERO_ALLOC, | ||
141 | &dev_priv->bar3_vm->pgt[0].obj[0]); | ||
142 | if (ret) | ||
143 | goto error; | ||
144 | dev_priv->bar3_vm->pgt[0].refcount[0] = 1; | ||
145 | |||
146 | nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); | ||
147 | |||
148 | ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, | ||
149 | NVOBJ_FLAG_ZERO_ALLOC, &priv->bar3_pgd); | ||
150 | if (ret) | ||
151 | goto error; | ||
152 | |||
153 | ret = nouveau_vm_ref(dev_priv->bar3_vm, &vm, priv->bar3_pgd); | ||
154 | if (ret) | ||
155 | goto error; | ||
156 | nouveau_vm_ref(NULL, &vm, NULL); | ||
157 | |||
158 | ret = nvc0_channel_new(dev, 8192, dev_priv->bar3_vm, &priv->bar3, | ||
159 | priv->bar3_pgd, pci_resource_len(dev->pdev, 3)); | ||
160 | if (ret) | ||
161 | goto error; | ||
162 | |||
163 | /* BAR1 VM */ | ||
164 | ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 1), 0, &vm); | ||
165 | if (ret) | ||
166 | goto error; | ||
167 | |||
168 | ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, | ||
169 | NVOBJ_FLAG_ZERO_ALLOC, &priv->bar1_pgd); | ||
170 | if (ret) | ||
171 | goto error; | ||
172 | |||
173 | ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, priv->bar1_pgd); | ||
174 | if (ret) | ||
175 | goto error; | ||
176 | nouveau_vm_ref(NULL, &vm, NULL); | ||
177 | |||
178 | ret = nvc0_channel_new(dev, 8192, dev_priv->bar1_vm, &priv->bar1, | ||
179 | priv->bar1_pgd, pci_resource_len(dev->pdev, 1)); | ||
180 | if (ret) | ||
181 | goto error; | ||
182 | |||
183 | /* channel vm */ | ||
184 | ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, &vm); | ||
185 | if (ret) | ||
186 | goto error; | ||
187 | |||
188 | ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, 0, &priv->chan_pgd); | ||
189 | if (ret) | ||
190 | goto error; | ||
191 | |||
192 | nouveau_vm_ref(vm, &dev_priv->chan_vm, priv->chan_pgd); | ||
193 | nouveau_vm_ref(NULL, &vm, NULL); | ||
194 | |||
195 | nvc0_instmem_resume(dev); | ||
154 | return 0; | 196 | return 0; |
197 | error: | ||
198 | nvc0_instmem_takedown(dev); | ||
199 | return ret; | ||
155 | } | 200 | } |
156 | 201 | ||
157 | void | 202 | void |
158 | nvc0_instmem_resume(struct drm_device *dev) | 203 | nvc0_instmem_takedown(struct drm_device *dev) |
159 | { | 204 | { |
160 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 205 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
161 | u32 *buf = dev_priv->susres.ramin_copy; | 206 | struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; |
162 | u64 chan; | 207 | struct nouveau_vm *vm = NULL; |
163 | int i; | ||
164 | 208 | ||
165 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | 209 | nvc0_instmem_suspend(dev); |
166 | nv_wr32(dev, 0x001700, chan >> 16); | ||
167 | 210 | ||
168 | for (i = 0; i < 65536; i += 4) | 211 | nv_wr32(dev, 0x1704, 0x00000000); |
169 | nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]); | 212 | nv_wr32(dev, 0x1714, 0x00000000); |
170 | vfree(dev_priv->susres.ramin_copy); | ||
171 | dev_priv->susres.ramin_copy = NULL; | ||
172 | 213 | ||
173 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | 214 | nouveau_vm_ref(NULL, &dev_priv->chan_vm, priv->chan_pgd); |
174 | } | 215 | nouveau_gpuobj_ref(NULL, &priv->chan_pgd); |
175 | 216 | ||
176 | int | 217 | nvc0_channel_del(&priv->bar1); |
177 | nvc0_instmem_init(struct drm_device *dev) | 218 | nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd); |
178 | { | 219 | nouveau_gpuobj_ref(NULL, &priv->bar1_pgd); |
179 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
180 | u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; | ||
181 | int ret, i; | ||
182 | |||
183 | dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; | ||
184 | chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | ||
185 | imem = 4096 + 4096 + 32768; | ||
186 | |||
187 | nv_wr32(dev, 0x001700, chan >> 16); | ||
188 | |||
189 | /* channel setup */ | ||
190 | nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); | ||
191 | nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); | ||
192 | nv_wr32(dev, 0x700208, lower_32_bits(lim3)); | ||
193 | nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); | ||
194 | |||
195 | /* point pgd -> pgt */ | ||
196 | nv_wr32(dev, 0x701000, 0); | ||
197 | nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); | ||
198 | |||
199 | /* point pgt -> physical vram for channel */ | ||
200 | pgt3 = 0x2000; | ||
201 | for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { | ||
202 | nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); | ||
203 | nv_wr32(dev, 0x700004 + pgt3, 0); | ||
204 | } | ||
205 | |||
206 | /* clear rest of pgt */ | ||
207 | for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { | ||
208 | nv_wr32(dev, 0x700000 + pgt3, 0); | ||
209 | nv_wr32(dev, 0x700004 + pgt3, 0); | ||
210 | } | ||
211 | |||
212 | /* point bar3 at the channel */ | ||
213 | nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); | ||
214 | |||
215 | /* Global PRAMIN heap */ | ||
216 | ret = drm_mm_init(&dev_priv->ramin_heap, imem, | ||
217 | dev_priv->ramin_size - imem); | ||
218 | if (ret) { | ||
219 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); | ||
220 | return -ENOMEM; | ||
221 | } | ||
222 | 220 | ||
223 | return 0; | 221 | nvc0_channel_del(&priv->bar3); |
224 | } | 222 | nouveau_vm_ref(dev_priv->bar3_vm, &vm, NULL); |
223 | nouveau_vm_ref(NULL, &vm, priv->bar3_pgd); | ||
224 | nouveau_gpuobj_ref(NULL, &priv->bar3_pgd); | ||
225 | nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); | ||
226 | nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); | ||
225 | 227 | ||
226 | void | 228 | dev_priv->engine.instmem.priv = NULL; |
227 | nvc0_instmem_takedown(struct drm_device *dev) | 229 | kfree(priv); |
228 | { | ||
229 | } | 230 | } |
230 | 231 | ||