diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_instmem.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_instmem.c | 418 |
1 files changed, 185 insertions, 233 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_instmem.c b/drivers/gpu/drm/nouveau/nv50_instmem.c index 91ef93cf1f35..a53fc974332b 100644 --- a/drivers/gpu/drm/nouveau/nv50_instmem.c +++ b/drivers/gpu/drm/nouveau/nv50_instmem.c | |||
@@ -32,39 +32,87 @@ | |||
32 | struct nv50_instmem_priv { | 32 | struct nv50_instmem_priv { |
33 | uint32_t save1700[5]; /* 0x1700->0x1710 */ | 33 | uint32_t save1700[5]; /* 0x1700->0x1710 */ |
34 | 34 | ||
35 | struct nouveau_gpuobj_ref *pramin_pt; | 35 | struct nouveau_gpuobj *pramin_pt; |
36 | struct nouveau_gpuobj_ref *pramin_bar; | 36 | struct nouveau_gpuobj *pramin_bar; |
37 | struct nouveau_gpuobj_ref *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 | uint32_t offset; \ | 48 | return; |
48 | if ((g)->im_backing) { \ | 49 | |
49 | offset = (g)->im_backing_start; \ | 50 | nouveau_gpuobj_ref(NULL, &chan->ramfc); |
50 | } else { \ | 51 | nouveau_gpuobj_ref(NULL, &chan->vm_pd); |
51 | offset = chan->ramin->gpuobj->im_backing_start; \ | 52 | if (chan->ramin_heap.free_stack.next) |
52 | offset += (g)->im_pramin->start; \ | 53 | drm_mm_takedown(&chan->ramin_heap); |
53 | } \ | 54 | nouveau_gpuobj_ref(NULL, &chan->ramin); |
54 | offset += (o); \ | 55 | kfree(chan); |
55 | nv_wr32(dev, NV_RAMIN + (offset & 0xfffff), (v)); \ | 56 | } |
56 | } while (0) | 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 | } | ||
57 | 107 | ||
58 | int | 108 | int |
59 | nv50_instmem_init(struct drm_device *dev) | 109 | nv50_instmem_init(struct drm_device *dev) |
60 | { | 110 | { |
61 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 111 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
62 | struct nouveau_channel *chan; | ||
63 | uint32_t c_offset, c_size, c_ramfc, c_vmpd, c_base, pt_size; | ||
64 | uint32_t save_nv001700; | ||
65 | uint64_t v; | ||
66 | struct nv50_instmem_priv *priv; | 112 | struct nv50_instmem_priv *priv; |
113 | struct nouveau_channel *chan; | ||
67 | int ret, i; | 114 | int ret, i; |
115 | u32 tmp; | ||
68 | 116 | ||
69 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 117 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
70 | if (!priv) | 118 | if (!priv) |
@@ -75,212 +123,115 @@ nv50_instmem_init(struct drm_device *dev) | |||
75 | for (i = 0x1700; i <= 0x1710; i += 4) | 123 | for (i = 0x1700; i <= 0x1710; i += 4) |
76 | priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); | 124 | priv->save1700[(i-0x1700)/4] = nv_rd32(dev, i); |
77 | 125 | ||
78 | /* Reserve the last MiB of VRAM, we should probably try to avoid | 126 | /* Global PRAMIN heap */ |
79 | * 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); |
80 | * some point. | 128 | if (ret) { |
81 | */ | 129 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); |
82 | dev_priv->ramin_rsvd_vram = 1 << 20; | ||
83 | c_offset = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; | ||
84 | c_size = 128 << 10; | ||
85 | c_vmpd = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x1400 : 0x200; | ||
86 | c_ramfc = ((dev_priv->chipset & 0xf0) == 0x50) ? 0x0 : 0x20; | ||
87 | c_base = c_vmpd + 0x4000; | ||
88 | pt_size = NV50_INSTMEM_PT_SIZE(dev_priv->ramin_size); | ||
89 | |||
90 | NV_DEBUG(dev, " Rsvd VRAM base: 0x%08x\n", c_offset); | ||
91 | NV_DEBUG(dev, " VBIOS image: 0x%08x\n", | ||
92 | (nv_rd32(dev, 0x619f04) & ~0xff) << 8); | ||
93 | NV_DEBUG(dev, " Aperture size: %d MiB\n", dev_priv->ramin_size >> 20); | ||
94 | NV_DEBUG(dev, " PT size: %d KiB\n", pt_size >> 10); | ||
95 | |||
96 | /* Determine VM layout, we need to do this first to make sure | ||
97 | * we allocate enough memory for all the page tables. | ||
98 | */ | ||
99 | dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); | ||
100 | dev_priv->vm_gart_size = NV50_VM_BLOCK; | ||
101 | |||
102 | dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size; | ||
103 | dev_priv->vm_vram_size = dev_priv->vram_size; | ||
104 | if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM) | ||
105 | dev_priv->vm_vram_size = NV50_VM_MAX_VRAM; | ||
106 | dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK); | ||
107 | dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK; | ||
108 | |||
109 | dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size; | ||
110 | |||
111 | NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n", | ||
112 | dev_priv->vm_gart_base, | ||
113 | dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1); | ||
114 | NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n", | ||
115 | dev_priv->vm_vram_base, | ||
116 | dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1); | ||
117 | |||
118 | c_size += dev_priv->vm_vram_pt_nr * (NV50_VM_BLOCK / 65536 * 8); | ||
119 | |||
120 | /* Map BAR0 PRAMIN aperture over the memory we want to use */ | ||
121 | save_nv001700 = nv_rd32(dev, NV50_PUNK_BAR0_PRAMIN); | ||
122 | nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (c_offset >> 16)); | ||
123 | |||
124 | /* Create a fake channel, and use it as our "dummy" channels 0/127. | ||
125 | * The main reason for creating a channel is so we can use the gpuobj | ||
126 | * code. However, it's probably worth noting that NVIDIA also setup | ||
127 | * their channels 0/127 with the same values they configure here. | ||
128 | * So, there may be some other reason for doing this. | ||
129 | * | ||
130 | * Have to create the entire channel manually, as the real channel | ||
131 | * creation code assumes we have PRAMIN access, and we don't until | ||
132 | * we're done here. | ||
133 | */ | ||
134 | chan = kzalloc(sizeof(*chan), GFP_KERNEL); | ||
135 | if (!chan) | ||
136 | return -ENOMEM; | 130 | return -ENOMEM; |
137 | chan->id = 0; | 131 | } |
138 | chan->dev = dev; | ||
139 | chan->file_priv = (struct drm_file *)-2; | ||
140 | dev_priv->fifos[0] = dev_priv->fifos[127] = chan; | ||
141 | |||
142 | INIT_LIST_HEAD(&chan->ramht_refs); | ||
143 | 132 | ||
144 | /* Channel's PRAMIN object + heap */ | 133 | /* we need a channel to plug into the hw to control the BARs */ |
145 | ret = nouveau_gpuobj_new_fake(dev, 0, c_offset, c_size, 0, | 134 | ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]); |
146 | NULL, &chan->ramin); | ||
147 | if (ret) | 135 | if (ret) |
148 | return ret; | 136 | return ret; |
137 | chan = dev_priv->fifos[127] = dev_priv->fifos[0]; | ||
149 | 138 | ||
150 | if (drm_mm_init(&chan->ramin_heap, c_base, c_size - c_base)) | 139 | /* allocate page table for PRAMIN BAR */ |
151 | return -ENOMEM; | 140 | ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8, |
152 | 141 | 0x1000, NVOBJ_FLAG_ZERO_ALLOC, | |
153 | /* RAMFC + zero channel's PRAMIN up to start of VM pagedir */ | 142 | &priv->pramin_pt); |
154 | ret = nouveau_gpuobj_new_fake(dev, c_ramfc, c_offset + c_ramfc, | ||
155 | 0x4000, 0, NULL, &chan->ramfc); | ||
156 | if (ret) | 143 | if (ret) |
157 | return ret; | 144 | return ret; |
158 | 145 | ||
159 | for (i = 0; i < c_vmpd; i += 4) | 146 | nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63); |
160 | BAR0_WI32(chan->ramin->gpuobj, i, 0); | 147 | nv_wo32(chan->vm_pd, 0x0004, 0); |
161 | 148 | ||
162 | /* VM page directory */ | 149 | /* DMA object for PRAMIN BAR */ |
163 | 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); |
164 | 0x4000, 0, &chan->vm_pd, NULL); | ||
165 | if (ret) | 151 | if (ret) |
166 | return ret; | 152 | return ret; |
167 | for (i = 0; i < 0x4000; i += 8) { | 153 | nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000); |
168 | BAR0_WI32(chan->vm_pd, i + 0x00, 0x00000000); | 154 | nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1); |
169 | BAR0_WI32(chan->vm_pd, i + 0x04, 0x00000000); | 155 | nv_wo32(priv->pramin_bar, 0x08, 0x00000000); |
170 | } | 156 | nv_wo32(priv->pramin_bar, 0x0c, 0x00000000); |
171 | 157 | nv_wo32(priv->pramin_bar, 0x10, 0x00000000); | |
172 | /* PRAMIN page table, cheat and map into VM at 0x0000000000. | 158 | nv_wo32(priv->pramin_bar, 0x14, 0x00000000); |
173 | * We map the entire fake channel into the start of the PRAMIN BAR | 159 | |
174 | */ | 160 | /* map channel into PRAMIN, gpuobj didn't do it for us */ |
175 | ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, pt_size, 0x1000, | 161 | ret = nv50_instmem_bind(dev, chan->ramin); |
176 | 0, &priv->pramin_pt); | ||
177 | if (ret) | 162 | if (ret) |
178 | return ret; | 163 | return ret; |
179 | 164 | ||
180 | v = c_offset | 1; | 165 | /* poke regs... */ |
181 | if (dev_priv->vram_sys_base) { | 166 | nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12)); |
182 | v += dev_priv->vram_sys_base; | 167 | nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12)); |
183 | v |= 0x30; | 168 | nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4)); |
184 | } | ||
185 | 169 | ||
186 | i = 0; | 170 | tmp = nv_ri32(dev, 0); |
187 | while (v < dev_priv->vram_sys_base + c_offset + c_size) { | 171 | nv_wi32(dev, 0, ~tmp); |
188 | BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, lower_32_bits(v)); | 172 | if (nv_ri32(dev, 0) != ~tmp) { |
189 | BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, upper_32_bits(v)); | 173 | NV_ERROR(dev, "PRAMIN readback failed\n"); |
190 | v += 0x1000; | 174 | return -EIO; |
191 | i += 8; | ||
192 | } | 175 | } |
176 | nv_wi32(dev, 0, tmp); | ||
193 | 177 | ||
194 | while (i < pt_size) { | 178 | dev_priv->ramin_available = true; |
195 | BAR0_WI32(priv->pramin_pt->gpuobj, i + 0, 0x00000000); | ||
196 | BAR0_WI32(priv->pramin_pt->gpuobj, i + 4, 0x00000000); | ||
197 | i += 8; | ||
198 | } | ||
199 | 179 | ||
200 | BAR0_WI32(chan->vm_pd, 0x00, priv->pramin_pt->instance | 0x63); | 180 | /* Determine VM layout */ |
201 | BAR0_WI32(chan->vm_pd, 0x04, 0x00000000); | 181 | dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); |
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; | ||
190 | |||
191 | dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size; | ||
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); | ||
202 | 199 | ||
203 | /* VRAM page table(s), mapped into VM at +1GiB */ | 200 | /* VRAM page table(s), mapped into VM at +1GiB */ |
204 | for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { | 201 | for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { |
205 | ret = nouveau_gpuobj_new_ref(dev, chan, NULL, 0, | 202 | ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8, |
206 | NV50_VM_BLOCK/65536*8, 0, 0, | 203 | 0, NVOBJ_FLAG_ZERO_ALLOC, |
207 | &chan->vm_vram_pt[i]); | 204 | &chan->vm_vram_pt[i]); |
208 | if (ret) { | 205 | if (ret) { |
209 | NV_ERROR(dev, "Error creating VRAM page tables: %d\n", | 206 | NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret); |
210 | ret); | ||
211 | dev_priv->vm_vram_pt_nr = i; | 207 | dev_priv->vm_vram_pt_nr = i; |
212 | return ret; | 208 | return ret; |
213 | } | 209 | } |
214 | dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]->gpuobj; | 210 | dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]; |
215 | 211 | ||
216 | for (v = 0; v < dev_priv->vm_vram_pt[i]->im_pramin->size; | 212 | nv_wo32(chan->vm_pd, 0x10 + (i*8), |
217 | v += 4) | 213 | chan->vm_vram_pt[i]->vinst | 0x61); |
218 | BAR0_WI32(dev_priv->vm_vram_pt[i], v, 0); | 214 | nv_wo32(chan->vm_pd, 0x14 + (i*8), 0); |
219 | |||
220 | BAR0_WI32(chan->vm_pd, 0x10 + (i*8), | ||
221 | chan->vm_vram_pt[i]->instance | 0x61); | ||
222 | BAR0_WI32(chan->vm_pd, 0x14 + (i*8), 0); | ||
223 | } | 215 | } |
224 | 216 | ||
225 | /* DMA object for PRAMIN BAR */ | ||
226 | ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0, | ||
227 | &priv->pramin_bar); | ||
228 | if (ret) | ||
229 | return ret; | ||
230 | BAR0_WI32(priv->pramin_bar->gpuobj, 0x00, 0x7fc00000); | ||
231 | BAR0_WI32(priv->pramin_bar->gpuobj, 0x04, dev_priv->ramin_size - 1); | ||
232 | BAR0_WI32(priv->pramin_bar->gpuobj, 0x08, 0x00000000); | ||
233 | BAR0_WI32(priv->pramin_bar->gpuobj, 0x0c, 0x00000000); | ||
234 | BAR0_WI32(priv->pramin_bar->gpuobj, 0x10, 0x00000000); | ||
235 | BAR0_WI32(priv->pramin_bar->gpuobj, 0x14, 0x00000000); | ||
236 | |||
237 | /* DMA object for FB BAR */ | 217 | /* DMA object for FB BAR */ |
238 | ret = nouveau_gpuobj_new_ref(dev, chan, chan, 0, 6*4, 16, 0, | 218 | ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar); |
239 | &priv->fb_bar); | ||
240 | if (ret) | 219 | if (ret) |
241 | return ret; | 220 | return ret; |
242 | BAR0_WI32(priv->fb_bar->gpuobj, 0x00, 0x7fc00000); | 221 | nv_wo32(priv->fb_bar, 0x00, 0x7fc00000); |
243 | BAR0_WI32(priv->fb_bar->gpuobj, 0x04, 0x40000000 + | 222 | nv_wo32(priv->fb_bar, 0x04, 0x40000000 + |
244 | pci_resource_len(dev->pdev, 1) - 1); | 223 | pci_resource_len(dev->pdev, 1) - 1); |
245 | BAR0_WI32(priv->fb_bar->gpuobj, 0x08, 0x40000000); | 224 | nv_wo32(priv->fb_bar, 0x08, 0x40000000); |
246 | BAR0_WI32(priv->fb_bar->gpuobj, 0x0c, 0x00000000); | 225 | nv_wo32(priv->fb_bar, 0x0c, 0x00000000); |
247 | BAR0_WI32(priv->fb_bar->gpuobj, 0x10, 0x00000000); | 226 | nv_wo32(priv->fb_bar, 0x10, 0x00000000); |
248 | BAR0_WI32(priv->fb_bar->gpuobj, 0x14, 0x00000000); | 227 | nv_wo32(priv->fb_bar, 0x14, 0x00000000); |
249 | 228 | ||
250 | /* Poke the relevant regs, and pray it works :) */ | 229 | dev_priv->engine.instmem.flush(dev); |
251 | nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12)); | ||
252 | nv_wr32(dev, NV50_PUNK_UNK1710, 0); | ||
253 | nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) | | ||
254 | NV50_PUNK_BAR_CFG_BASE_VALID); | ||
255 | nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) | | ||
256 | NV50_PUNK_BAR1_CTXDMA_VALID); | ||
257 | nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) | | ||
258 | NV50_PUNK_BAR3_CTXDMA_VALID); | ||
259 | 230 | ||
231 | nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4)); | ||
260 | for (i = 0; i < 8; i++) | 232 | for (i = 0; i < 8; i++) |
261 | nv_wr32(dev, 0x1900 + (i*4), 0); | 233 | nv_wr32(dev, 0x1900 + (i*4), 0); |
262 | 234 | ||
263 | /* Assume that praying isn't enough, check that we can re-read the | ||
264 | * entire fake channel back from the PRAMIN BAR */ | ||
265 | for (i = 0; i < c_size; i += 4) { | ||
266 | if (nv_rd32(dev, NV_RAMIN + i) != nv_ri32(dev, i)) { | ||
267 | NV_ERROR(dev, "Error reading back PRAMIN at 0x%08x\n", | ||
268 | i); | ||
269 | return -EINVAL; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, save_nv001700); | ||
274 | |||
275 | /* Global PRAMIN heap */ | ||
276 | if (drm_mm_init(&dev_priv->ramin_heap, c_size, dev_priv->ramin_size - c_size)) { | ||
277 | NV_ERROR(dev, "Failed to init RAMIN heap\n"); | ||
278 | } | ||
279 | |||
280 | /*XXX: incorrect, but needed to make hash func "work" */ | ||
281 | dev_priv->ramht_offset = 0x10000; | ||
282 | dev_priv->ramht_bits = 9; | ||
283 | dev_priv->ramht_size = (1 << dev_priv->ramht_bits) * 8; | ||
284 | return 0; | 235 | return 0; |
285 | } | 236 | } |
286 | 237 | ||
@@ -297,29 +248,24 @@ nv50_instmem_takedown(struct drm_device *dev) | |||
297 | if (!priv) | 248 | if (!priv) |
298 | return; | 249 | return; |
299 | 250 | ||
251 | dev_priv->ramin_available = false; | ||
252 | |||
300 | /* Restore state from before init */ | 253 | /* Restore state from before init */ |
301 | for (i = 0x1700; i <= 0x1710; i += 4) | 254 | for (i = 0x1700; i <= 0x1710; i += 4) |
302 | nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); | 255 | nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); |
303 | 256 | ||
304 | nouveau_gpuobj_ref_del(dev, &priv->fb_bar); | 257 | nouveau_gpuobj_ref(NULL, &priv->fb_bar); |
305 | nouveau_gpuobj_ref_del(dev, &priv->pramin_bar); | 258 | nouveau_gpuobj_ref(NULL, &priv->pramin_bar); |
306 | nouveau_gpuobj_ref_del(dev, &priv->pramin_pt); | 259 | nouveau_gpuobj_ref(NULL, &priv->pramin_pt); |
307 | 260 | ||
308 | /* Destroy dummy channel */ | 261 | /* Destroy dummy channel */ |
309 | if (chan) { | 262 | if (chan) { |
310 | for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { | 263 | for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) |
311 | nouveau_gpuobj_ref_del(dev, &chan->vm_vram_pt[i]); | 264 | nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); |
312 | dev_priv->vm_vram_pt[i] = NULL; | ||
313 | } | ||
314 | dev_priv->vm_vram_pt_nr = 0; | 265 | dev_priv->vm_vram_pt_nr = 0; |
315 | 266 | ||
316 | nouveau_gpuobj_del(dev, &chan->vm_pd); | 267 | nv50_channel_del(&dev_priv->fifos[0]); |
317 | nouveau_gpuobj_ref_del(dev, &chan->ramfc); | 268 | dev_priv->fifos[127] = NULL; |
318 | nouveau_gpuobj_ref_del(dev, &chan->ramin); | ||
319 | drm_mm_takedown(&chan->ramin_heap); | ||
320 | |||
321 | dev_priv->fifos[0] = dev_priv->fifos[127] = NULL; | ||
322 | kfree(chan); | ||
323 | } | 269 | } |
324 | 270 | ||
325 | dev_priv->engine.instmem.priv = NULL; | 271 | dev_priv->engine.instmem.priv = NULL; |
@@ -331,14 +277,14 @@ nv50_instmem_suspend(struct drm_device *dev) | |||
331 | { | 277 | { |
332 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 278 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
333 | struct nouveau_channel *chan = dev_priv->fifos[0]; | 279 | struct nouveau_channel *chan = dev_priv->fifos[0]; |
334 | struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; | 280 | struct nouveau_gpuobj *ramin = chan->ramin; |
335 | int i; | 281 | int i; |
336 | 282 | ||
337 | ramin->im_backing_suspend = vmalloc(ramin->im_pramin->size); | 283 | ramin->im_backing_suspend = vmalloc(ramin->size); |
338 | if (!ramin->im_backing_suspend) | 284 | if (!ramin->im_backing_suspend) |
339 | return -ENOMEM; | 285 | return -ENOMEM; |
340 | 286 | ||
341 | for (i = 0; i < ramin->im_pramin->size; i += 4) | 287 | for (i = 0; i < ramin->size; i += 4) |
342 | ramin->im_backing_suspend[i/4] = nv_ri32(dev, i); | 288 | ramin->im_backing_suspend[i/4] = nv_ri32(dev, i); |
343 | return 0; | 289 | return 0; |
344 | } | 290 | } |
@@ -349,23 +295,25 @@ nv50_instmem_resume(struct drm_device *dev) | |||
349 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 295 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
350 | struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; | 296 | struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; |
351 | struct nouveau_channel *chan = dev_priv->fifos[0]; | 297 | struct nouveau_channel *chan = dev_priv->fifos[0]; |
352 | struct nouveau_gpuobj *ramin = chan->ramin->gpuobj; | 298 | struct nouveau_gpuobj *ramin = chan->ramin; |
353 | int i; | 299 | int i; |
354 | 300 | ||
355 | nv_wr32(dev, NV50_PUNK_BAR0_PRAMIN, (ramin->im_backing_start >> 16)); | 301 | dev_priv->ramin_available = false; |
356 | for (i = 0; i < ramin->im_pramin->size; i += 4) | 302 | dev_priv->ramin_base = ~0; |
357 | BAR0_WI32(ramin, i, ramin->im_backing_suspend[i/4]); | 303 | for (i = 0; i < ramin->size; i += 4) |
304 | nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]); | ||
305 | dev_priv->ramin_available = true; | ||
358 | vfree(ramin->im_backing_suspend); | 306 | vfree(ramin->im_backing_suspend); |
359 | ramin->im_backing_suspend = NULL; | 307 | ramin->im_backing_suspend = NULL; |
360 | 308 | ||
361 | /* Poke the relevant regs, and pray it works :) */ | 309 | /* Poke the relevant regs, and pray it works :) */ |
362 | nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12)); | 310 | nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12)); |
363 | nv_wr32(dev, NV50_PUNK_UNK1710, 0); | 311 | nv_wr32(dev, NV50_PUNK_UNK1710, 0); |
364 | nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->instance >> 12) | | 312 | nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) | |
365 | NV50_PUNK_BAR_CFG_BASE_VALID); | 313 | NV50_PUNK_BAR_CFG_BASE_VALID); |
366 | nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->instance >> 4) | | 314 | nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) | |
367 | NV50_PUNK_BAR1_CTXDMA_VALID); | 315 | NV50_PUNK_BAR1_CTXDMA_VALID); |
368 | nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->instance >> 4) | | 316 | nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) | |
369 | NV50_PUNK_BAR3_CTXDMA_VALID); | 317 | NV50_PUNK_BAR3_CTXDMA_VALID); |
370 | 318 | ||
371 | for (i = 0; i < 8; i++) | 319 | for (i = 0; i < 8; i++) |
@@ -381,7 +329,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, | |||
381 | if (gpuobj->im_backing) | 329 | if (gpuobj->im_backing) |
382 | return -EINVAL; | 330 | return -EINVAL; |
383 | 331 | ||
384 | *sz = ALIGN(*sz, NV50_INSTMEM_PAGE_SIZE); | 332 | *sz = ALIGN(*sz, 4096); |
385 | if (*sz == 0) | 333 | if (*sz == 0) |
386 | return -EINVAL; | 334 | return -EINVAL; |
387 | 335 | ||
@@ -399,9 +347,7 @@ nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, | |||
399 | return ret; | 347 | return ret; |
400 | } | 348 | } |
401 | 349 | ||
402 | gpuobj->im_backing_start = gpuobj->im_backing->bo.mem.mm_node->start; | 350 | gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT; |
403 | gpuobj->im_backing_start <<= PAGE_SHIFT; | ||
404 | |||
405 | return 0; | 351 | return 0; |
406 | } | 352 | } |
407 | 353 | ||
@@ -424,7 +370,7 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |||
424 | { | 370 | { |
425 | struct drm_nouveau_private *dev_priv = dev->dev_private; | 371 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
426 | struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; | 372 | struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; |
427 | struct nouveau_gpuobj *pramin_pt = priv->pramin_pt->gpuobj; | 373 | struct nouveau_gpuobj *pramin_pt = priv->pramin_pt; |
428 | uint32_t pte, pte_end; | 374 | uint32_t pte, pte_end; |
429 | uint64_t vram; | 375 | uint64_t vram; |
430 | 376 | ||
@@ -436,11 +382,11 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |||
436 | 382 | ||
437 | pte = (gpuobj->im_pramin->start >> 12) << 1; | 383 | pte = (gpuobj->im_pramin->start >> 12) << 1; |
438 | pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; | 384 | pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; |
439 | vram = gpuobj->im_backing_start; | 385 | vram = gpuobj->vinst; |
440 | 386 | ||
441 | NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", | 387 | NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", |
442 | gpuobj->im_pramin->start, pte, pte_end); | 388 | gpuobj->im_pramin->start, pte, pte_end); |
443 | NV_DEBUG(dev, "first vram page: 0x%08x\n", gpuobj->im_backing_start); | 389 | NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); |
444 | 390 | ||
445 | vram |= 1; | 391 | vram |= 1; |
446 | if (dev_priv->vram_sys_base) { | 392 | if (dev_priv->vram_sys_base) { |
@@ -449,9 +395,10 @@ nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |||
449 | } | 395 | } |
450 | 396 | ||
451 | while (pte < pte_end) { | 397 | while (pte < pte_end) { |
452 | nv_wo32(dev, pramin_pt, pte++, lower_32_bits(vram)); | 398 | nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); |
453 | nv_wo32(dev, pramin_pt, pte++, upper_32_bits(vram)); | 399 | nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); |
454 | vram += NV50_INSTMEM_PAGE_SIZE; | 400 | vram += 0x1000; |
401 | pte += 2; | ||
455 | } | 402 | } |
456 | dev_priv->engine.instmem.flush(dev); | 403 | dev_priv->engine.instmem.flush(dev); |
457 | 404 | ||
@@ -472,12 +419,17 @@ nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) | |||
472 | if (gpuobj->im_bound == 0) | 419 | if (gpuobj->im_bound == 0) |
473 | return -EINVAL; | 420 | return -EINVAL; |
474 | 421 | ||
422 | /* can happen during late takedown */ | ||
423 | if (unlikely(!dev_priv->ramin_available)) | ||
424 | return 0; | ||
425 | |||
475 | pte = (gpuobj->im_pramin->start >> 12) << 1; | 426 | pte = (gpuobj->im_pramin->start >> 12) << 1; |
476 | pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; | 427 | pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; |
477 | 428 | ||
478 | while (pte < pte_end) { | 429 | while (pte < pte_end) { |
479 | nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); | 430 | nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000); |
480 | nv_wo32(dev, priv->pramin_pt->gpuobj, pte++, 0x00000000); | 431 | nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000); |
432 | pte += 2; | ||
481 | } | 433 | } |
482 | dev_priv->engine.instmem.flush(dev); | 434 | dev_priv->engine.instmem.flush(dev); |
483 | 435 | ||
@@ -489,7 +441,7 @@ void | |||
489 | nv50_instmem_flush(struct drm_device *dev) | 441 | nv50_instmem_flush(struct drm_device *dev) |
490 | { | 442 | { |
491 | nv_wr32(dev, 0x00330c, 0x00000001); | 443 | nv_wr32(dev, 0x00330c, 0x00000001); |
492 | if (!nv_wait(0x00330c, 0x00000002, 0x00000000)) | 444 | if (!nv_wait(dev, 0x00330c, 0x00000002, 0x00000000)) |
493 | NV_ERROR(dev, "PRAMIN flush timeout\n"); | 445 | NV_ERROR(dev, "PRAMIN flush timeout\n"); |
494 | } | 446 | } |
495 | 447 | ||
@@ -497,7 +449,7 @@ void | |||
497 | nv84_instmem_flush(struct drm_device *dev) | 449 | nv84_instmem_flush(struct drm_device *dev) |
498 | { | 450 | { |
499 | nv_wr32(dev, 0x070000, 0x00000001); | 451 | nv_wr32(dev, 0x070000, 0x00000001); |
500 | if (!nv_wait(0x070000, 0x00000002, 0x00000000)) | 452 | if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) |
501 | NV_ERROR(dev, "PRAMIN flush timeout\n"); | 453 | NV_ERROR(dev, "PRAMIN flush timeout\n"); |
502 | } | 454 | } |
503 | 455 | ||
@@ -505,7 +457,7 @@ void | |||
505 | nv50_vm_flush(struct drm_device *dev, int engine) | 457 | nv50_vm_flush(struct drm_device *dev, int engine) |
506 | { | 458 | { |
507 | nv_wr32(dev, 0x100c80, (engine << 16) | 1); | 459 | nv_wr32(dev, 0x100c80, (engine << 16) | 1); |
508 | if (!nv_wait(0x100c80, 0x00000001, 0x00000000)) | 460 | if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) |
509 | NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); | 461 | NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); |
510 | } | 462 | } |
511 | 463 | ||