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