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