]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
drm/nouveau/devinit: namespace + nvidia gpu names (no binary change)
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / nouveau / nvkm / subdev / fb / nv50.c
CommitLineData
861d2107
BS
1/*
2 * Copyright 2012 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
93260d3c 25#include <core/client.h>
861d2107 26#include <core/enum.h>
93260d3c
MS
27#include <core/engctx.h>
28#include <core/object.h>
861d2107 29
861d2107 30#include <subdev/bios.h>
304424e1 31
9ca3037e 32#include "nv50.h"
20f63afe 33
dceef5d8
BS
34int
35nv50_fb_memtype[0x80] = {
861d2107
BS
36 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
37 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
38 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
39 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
40 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
41 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
42 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2,
43 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0
44};
45
20cdeaf9 46bool
861d2107 47nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
8f7286f8 48{
dceef5d8 49 return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
861d2107
BS
50}
51
e6626254 52static const struct nouveau_enum vm_dispatch_subclients[] = {
312d1d5f
BS
53 { 0x00000000, "GRCTX", NULL },
54 { 0x00000001, "NOTIFY", NULL },
55 { 0x00000002, "QUERY", NULL },
56 { 0x00000003, "COND", NULL },
57 { 0x00000004, "M2M_IN", NULL },
58 { 0x00000005, "M2M_OUT", NULL },
59 { 0x00000006, "M2M_NOTIFY", NULL },
60 {}
61};
62
e6626254 63static const struct nouveau_enum vm_ccache_subclients[] = {
312d1d5f
BS
64 { 0x00000000, "CB", NULL },
65 { 0x00000001, "TIC", NULL },
66 { 0x00000002, "TSC", NULL },
67 {}
68};
69
e6626254 70static const struct nouveau_enum vm_prop_subclients[] = {
312d1d5f
BS
71 { 0x00000000, "RT0", NULL },
72 { 0x00000001, "RT1", NULL },
73 { 0x00000002, "RT2", NULL },
74 { 0x00000003, "RT3", NULL },
75 { 0x00000004, "RT4", NULL },
76 { 0x00000005, "RT5", NULL },
77 { 0x00000006, "RT6", NULL },
78 { 0x00000007, "RT7", NULL },
79 { 0x00000008, "ZETA", NULL },
80 { 0x00000009, "LOCAL", NULL },
81 { 0x0000000a, "GLOBAL", NULL },
82 { 0x0000000b, "STACK", NULL },
83 { 0x0000000c, "DST2D", NULL },
84 {}
85};
86
e6626254 87static const struct nouveau_enum vm_pfifo_subclients[] = {
312d1d5f
BS
88 { 0x00000000, "PUSHBUF", NULL },
89 { 0x00000001, "SEMAPHORE", NULL },
90 {}
91};
92
e6626254 93static const struct nouveau_enum vm_bar_subclients[] = {
312d1d5f
BS
94 { 0x00000000, "FB", NULL },
95 { 0x00000001, "IN", NULL },
96 {}
97};
98
e6626254 99static const struct nouveau_enum vm_client[] = {
312d1d5f
BS
100 { 0x00000000, "STRMOUT", NULL },
101 { 0x00000003, "DISPATCH", vm_dispatch_subclients },
102 { 0x00000004, "PFIFO_WRITE", NULL },
103 { 0x00000005, "CCACHE", vm_ccache_subclients },
fd8666f7 104 { 0x00000006, "PMSPPP", NULL },
312d1d5f
BS
105 { 0x00000007, "CLIPID", NULL },
106 { 0x00000008, "PFIFO_READ", NULL },
107 { 0x00000009, "VFETCH", NULL },
108 { 0x0000000a, "TEXTURE", NULL },
109 { 0x0000000b, "PROP", vm_prop_subclients },
110 { 0x0000000c, "PVP", NULL },
111 { 0x0000000d, "PBSP", NULL },
112 { 0x0000000e, "PCRYPT", NULL },
113 { 0x0000000f, "PCOUNTER", NULL },
114 { 0x00000011, "PDAEMON", NULL },
115 {}
116};
117
e6626254 118static const struct nouveau_enum vm_engine[] = {
93260d3c
MS
119 { 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR },
120 { 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP },
312d1d5f 121 { 0x00000004, "PEEPHOLE", NULL },
93260d3c 122 { 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO },
312d1d5f 123 { 0x00000006, "BAR", vm_bar_subclients },
fd8666f7 124 { 0x00000008, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP },
93260d3c
MS
125 { 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG },
126 { 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP },
93d90ad7 127 { 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CIPHER },
312d1d5f
BS
128 { 0x0000000b, "PCOUNTER", NULL },
129 { 0x0000000c, "SEMAPHORE_BG", NULL },
aedf24ff 130 { 0x0000000d, "PCE0", NULL, NVDEV_ENGINE_CE0 },
312d1d5f
BS
131 { 0x0000000e, "PDAEMON", NULL },
132 {}
133};
134
e6626254 135static const struct nouveau_enum vm_fault[] = {
312d1d5f
BS
136 { 0x00000000, "PT_NOT_PRESENT", NULL },
137 { 0x00000001, "PT_TOO_SHORT", NULL },
138 { 0x00000002, "PAGE_NOT_PRESENT", NULL },
139 { 0x00000003, "PAGE_SYSTEM_ONLY", NULL },
140 { 0x00000004, "PAGE_READ_ONLY", NULL },
141 { 0x00000006, "NULL_DMAOBJ", NULL },
142 { 0x00000007, "WRONG_MEMTYPE", NULL },
143 { 0x0000000b, "VRAM_LIMIT", NULL },
144 { 0x0000000f, "DMAOBJ_LIMIT", NULL },
145 {}
146};
147
874309a5
BS
148static void
149nv50_fb_intr(struct nouveau_subdev *subdev)
d96773e7 150{
874309a5 151 struct nouveau_device *device = nv_device(subdev);
93260d3c 152 struct nouveau_engine *engine;
874309a5 153 struct nv50_fb_priv *priv = (void *)subdev;
312d1d5f 154 const struct nouveau_enum *en, *cl;
93260d3c 155 struct nouveau_object *engctx = NULL;
861d2107 156 u32 trap[6], idx, chan;
312d1d5f 157 u8 st0, st1, st2, st3;
861d2107 158 int i;
d96773e7 159
861d2107 160 idx = nv_rd32(priv, 0x100c90);
d96773e7
BS
161 if (!(idx & 0x80000000))
162 return;
163 idx &= 0x00ffffff;
164
165 for (i = 0; i < 6; i++) {
861d2107
BS
166 nv_wr32(priv, 0x100c90, idx | i << 24);
167 trap[i] = nv_rd32(priv, 0x100c94);
d96773e7 168 }
861d2107 169 nv_wr32(priv, 0x100c90, idx | 0x80000000);
d96773e7 170
312d1d5f 171 /* decode status bits into something more useful */
861d2107
BS
172 if (device->chipset < 0xa3 ||
173 device->chipset == 0xaa || device->chipset == 0xac) {
312d1d5f
BS
174 st0 = (trap[0] & 0x0000000f) >> 0;
175 st1 = (trap[0] & 0x000000f0) >> 4;
176 st2 = (trap[0] & 0x00000f00) >> 8;
177 st3 = (trap[0] & 0x0000f000) >> 12;
178 } else {
179 st0 = (trap[0] & 0x000000ff) >> 0;
180 st1 = (trap[0] & 0x0000ff00) >> 8;
181 st2 = (trap[0] & 0x00ff0000) >> 16;
182 st3 = (trap[0] & 0xff000000) >> 24;
183 }
861d2107 184 chan = (trap[2] << 16) | trap[1];
312d1d5f 185
93260d3c
MS
186 en = nouveau_enum_find(vm_engine, st0);
187
188 if (en && en->data2) {
189 const struct nouveau_enum *orig_en = en;
190 while (en->name && en->value == st0 && en->data2) {
191 engine = nouveau_engine(subdev, en->data2);
eccf7e8a
BS
192 /*XXX: clean this up */
193 if (!engine && en->data2 == NVDEV_ENGINE_BSP)
194 engine = nouveau_engine(subdev, NVDEV_ENGINE_MSVLD);
93d90ad7
BS
195 if (!engine && en->data2 == NVDEV_ENGINE_CIPHER)
196 engine = nouveau_engine(subdev, NVDEV_ENGINE_SEC);
37a5d028
BS
197 if (!engine && en->data2 == NVDEV_ENGINE_VP)
198 engine = nouveau_engine(subdev, NVDEV_ENGINE_MSPDEC);
93260d3c
MS
199 if (engine) {
200 engctx = nouveau_engctx_get(engine, chan);
201 if (engctx)
202 break;
203 }
204 en++;
205 }
206 if (!engctx)
207 en = orig_en;
208 }
209
210 nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ",
861d2107 211 (trap[5] & 0x00000100) ? "read" : "write",
93260d3c
MS
212 trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan,
213 nouveau_client_name(engctx));
214
215 nouveau_engctx_put(engctx);
312d1d5f 216
312d1d5f 217 if (en)
f533da10 218 pr_cont("%s/", en->name);
312d1d5f 219 else
f533da10 220 pr_cont("%02x/", st0);
312d1d5f
BS
221
222 cl = nouveau_enum_find(vm_client, st2);
223 if (cl)
f533da10 224 pr_cont("%s/", cl->name);
312d1d5f 225 else
f533da10 226 pr_cont("%02x/", st2);
312d1d5f
BS
227
228 if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3);
229 else if (en && en->data) cl = nouveau_enum_find(en->data, st3);
230 else cl = NULL;
231 if (cl)
f533da10 232 pr_cont("%s", cl->name);
312d1d5f 233 else
f533da10 234 pr_cont("%02x", st3);
312d1d5f 235
f533da10 236 pr_cont(" reason: ");
312d1d5f
BS
237 en = nouveau_enum_find(vm_fault, st1);
238 if (en)
f533da10 239 pr_cont("%s\n", en->name);
312d1d5f 240 else
f533da10 241 pr_cont("0x%08x\n", st1);
d96773e7 242}
874309a5 243
9ca3037e 244int
874309a5
BS
245nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
246 struct nouveau_oclass *oclass, void *data, u32 size,
247 struct nouveau_object **pobject)
248{
249 struct nouveau_device *device = nv_device(parent);
250 struct nv50_fb_priv *priv;
251 int ret;
252
8613e731 253 ret = nouveau_fb_create(parent, engine, oclass, &priv);
874309a5
BS
254 *pobject = nv_object(priv);
255 if (ret)
256 return ret;
257
258 priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
259 if (priv->r100c08_page) {
fd1496a0
AC
260 priv->r100c08 = dma_map_page(nv_device_base(device),
261 priv->r100c08_page, 0, PAGE_SIZE,
262 DMA_BIDIRECTIONAL);
838f6fe7
BS
263 if (dma_mapping_error(nv_device_base(device), priv->r100c08))
264 return -EFAULT;
874309a5
BS
265 } else {
266 nv_warn(priv, "failed 0x100c08 page alloc\n");
267 }
268
874309a5 269 nv_subdev(priv)->intr = nv50_fb_intr;
dceef5d8 270 return 0;
874309a5
BS
271}
272
9ca3037e 273void
874309a5
BS
274nv50_fb_dtor(struct nouveau_object *object)
275{
276 struct nouveau_device *device = nv_device(object);
277 struct nv50_fb_priv *priv = (void *)object;
278
279 if (priv->r100c08_page) {
fd1496a0
AC
280 dma_unmap_page(nv_device_base(device), priv->r100c08, PAGE_SIZE,
281 DMA_BIDIRECTIONAL);
874309a5
BS
282 __free_page(priv->r100c08_page);
283 }
284
285 nouveau_fb_destroy(&priv->base);
286}
287
9ca3037e 288int
874309a5
BS
289nv50_fb_init(struct nouveau_object *object)
290{
9ca3037e 291 struct nv50_fb_impl *impl = (void *)object->oclass;
874309a5
BS
292 struct nv50_fb_priv *priv = (void *)object;
293 int ret;
294
295 ret = nouveau_fb_init(&priv->base);
296 if (ret)
297 return ret;
298
299 /* Not a clue what this is exactly. Without pointing it at a
300 * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
301 * cause IOMMU "read from address 0" errors (rh#561267)
302 */
303 nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
304
305 /* This is needed to get meaningful information from 100c90
306 * on traps. No idea what these values mean exactly. */
9ca3037e 307 nv_wr32(priv, 0x100c90, impl->trap);
874309a5
BS
308 return 0;
309}
310
1e9fc30e 311struct nouveau_oclass *
9ca3037e 312nv50_fb_oclass = &(struct nv50_fb_impl) {
8613e731
BS
313 .base.base.handle = NV_SUBDEV(FB, 0x50),
314 .base.base.ofuncs = &(struct nouveau_ofuncs) {
874309a5
BS
315 .ctor = nv50_fb_ctor,
316 .dtor = nv50_fb_dtor,
317 .init = nv50_fb_init,
318 .fini = _nouveau_fb_fini,
319 },
20cdeaf9 320 .base.memtype = nv50_fb_memtype_valid,
8613e731 321 .base.ram = &nv50_ram_oclass,
9ca3037e 322 .trap = 0x000707ff,
8613e731 323}.base.base;