Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2012 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs
0023  */
0024 #include "nv50.h"
0025 #include "ram.h"
0026 
0027 #include <core/client.h>
0028 #include <core/enum.h>
0029 #include <engine/fifo.h>
0030 
0031 static int
0032 nv50_fb_ram_new(struct nvkm_fb *base, struct nvkm_ram **pram)
0033 {
0034     struct nv50_fb *fb = nv50_fb(base);
0035     return fb->func->ram_new(&fb->base, pram);
0036 }
0037 
0038 static const struct nvkm_enum vm_dispatch_subclients[] = {
0039     { 0x00000000, "GRCTX" },
0040     { 0x00000001, "NOTIFY" },
0041     { 0x00000002, "QUERY" },
0042     { 0x00000003, "COND" },
0043     { 0x00000004, "M2M_IN" },
0044     { 0x00000005, "M2M_OUT" },
0045     { 0x00000006, "M2M_NOTIFY" },
0046     {}
0047 };
0048 
0049 static const struct nvkm_enum vm_ccache_subclients[] = {
0050     { 0x00000000, "CB" },
0051     { 0x00000001, "TIC" },
0052     { 0x00000002, "TSC" },
0053     {}
0054 };
0055 
0056 static const struct nvkm_enum vm_prop_subclients[] = {
0057     { 0x00000000, "RT0" },
0058     { 0x00000001, "RT1" },
0059     { 0x00000002, "RT2" },
0060     { 0x00000003, "RT3" },
0061     { 0x00000004, "RT4" },
0062     { 0x00000005, "RT5" },
0063     { 0x00000006, "RT6" },
0064     { 0x00000007, "RT7" },
0065     { 0x00000008, "ZETA" },
0066     { 0x00000009, "LOCAL" },
0067     { 0x0000000a, "GLOBAL" },
0068     { 0x0000000b, "STACK" },
0069     { 0x0000000c, "DST2D" },
0070     {}
0071 };
0072 
0073 static const struct nvkm_enum vm_pfifo_subclients[] = {
0074     { 0x00000000, "PUSHBUF" },
0075     { 0x00000001, "SEMAPHORE" },
0076     {}
0077 };
0078 
0079 static const struct nvkm_enum vm_bar_subclients[] = {
0080     { 0x00000000, "FB" },
0081     { 0x00000001, "IN" },
0082     {}
0083 };
0084 
0085 static const struct nvkm_enum vm_client[] = {
0086     { 0x00000000, "STRMOUT" },
0087     { 0x00000003, "DISPATCH", vm_dispatch_subclients },
0088     { 0x00000004, "PFIFO_WRITE" },
0089     { 0x00000005, "CCACHE", vm_ccache_subclients },
0090     { 0x00000006, "PMSPPP" },
0091     { 0x00000007, "CLIPID" },
0092     { 0x00000008, "PFIFO_READ" },
0093     { 0x00000009, "VFETCH" },
0094     { 0x0000000a, "TEXTURE" },
0095     { 0x0000000b, "PROP", vm_prop_subclients },
0096     { 0x0000000c, "PVP" },
0097     { 0x0000000d, "PBSP" },
0098     { 0x0000000e, "PCRYPT" },
0099     { 0x0000000f, "PCOUNTER" },
0100     { 0x00000011, "PDAEMON" },
0101     {}
0102 };
0103 
0104 static const struct nvkm_enum vm_engine[] = {
0105     { 0x00000000, "PGRAPH" },
0106     { 0x00000001, "PVP" },
0107     { 0x00000004, "PEEPHOLE" },
0108     { 0x00000005, "PFIFO", vm_pfifo_subclients },
0109     { 0x00000006, "BAR", vm_bar_subclients },
0110     { 0x00000008, "PMSPPP" },
0111     { 0x00000008, "PMPEG" },
0112     { 0x00000009, "PBSP" },
0113     { 0x0000000a, "PCRYPT" },
0114     { 0x0000000b, "PCOUNTER" },
0115     { 0x0000000c, "SEMAPHORE_BG" },
0116     { 0x0000000d, "PCE0" },
0117     { 0x0000000e, "PMU" },
0118     {}
0119 };
0120 
0121 static const struct nvkm_enum vm_fault[] = {
0122     { 0x00000000, "PT_NOT_PRESENT" },
0123     { 0x00000001, "PT_TOO_SHORT" },
0124     { 0x00000002, "PAGE_NOT_PRESENT" },
0125     { 0x00000003, "PAGE_SYSTEM_ONLY" },
0126     { 0x00000004, "PAGE_READ_ONLY" },
0127     { 0x00000006, "NULL_DMAOBJ" },
0128     { 0x00000007, "WRONG_MEMTYPE" },
0129     { 0x0000000b, "VRAM_LIMIT" },
0130     { 0x0000000f, "DMAOBJ_LIMIT" },
0131     {}
0132 };
0133 
0134 static void
0135 nv50_fb_intr(struct nvkm_fb *base)
0136 {
0137     struct nv50_fb *fb = nv50_fb(base);
0138     struct nvkm_subdev *subdev = &fb->base.subdev;
0139     struct nvkm_device *device = subdev->device;
0140     struct nvkm_fifo *fifo = device->fifo;
0141     struct nvkm_fifo_chan *chan;
0142     const struct nvkm_enum *en, *re, *cl, *sc;
0143     u32 trap[6], idx, inst;
0144     u8 st0, st1, st2, st3;
0145     unsigned long flags;
0146     int i;
0147 
0148     idx = nvkm_rd32(device, 0x100c90);
0149     if (!(idx & 0x80000000))
0150         return;
0151     idx &= 0x00ffffff;
0152 
0153     for (i = 0; i < 6; i++) {
0154         nvkm_wr32(device, 0x100c90, idx | i << 24);
0155         trap[i] = nvkm_rd32(device, 0x100c94);
0156     }
0157     nvkm_wr32(device, 0x100c90, idx | 0x80000000);
0158 
0159     /* decode status bits into something more useful */
0160     if (device->chipset  < 0xa3 ||
0161         device->chipset == 0xaa || device->chipset == 0xac) {
0162         st0 = (trap[0] & 0x0000000f) >> 0;
0163         st1 = (trap[0] & 0x000000f0) >> 4;
0164         st2 = (trap[0] & 0x00000f00) >> 8;
0165         st3 = (trap[0] & 0x0000f000) >> 12;
0166     } else {
0167         st0 = (trap[0] & 0x000000ff) >> 0;
0168         st1 = (trap[0] & 0x0000ff00) >> 8;
0169         st2 = (trap[0] & 0x00ff0000) >> 16;
0170         st3 = (trap[0] & 0xff000000) >> 24;
0171     }
0172     inst = ((trap[2] << 16) | trap[1]) << 12;
0173 
0174     en = nvkm_enum_find(vm_engine, st0);
0175     re = nvkm_enum_find(vm_fault , st1);
0176     cl = nvkm_enum_find(vm_client, st2);
0177     if      (cl && cl->data) sc = nvkm_enum_find(cl->data, st3);
0178     else if (en && en->data) sc = nvkm_enum_find(en->data, st3);
0179     else                     sc = NULL;
0180 
0181     chan = nvkm_fifo_chan_inst(fifo, inst, &flags);
0182     nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel %d [%08x %s] "
0183                "engine %02x [%s] client %02x [%s] "
0184                "subclient %02x [%s] reason %08x [%s]\n",
0185            (trap[5] & 0x00000100) ? "read" : "write",
0186            trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff,
0187            chan ? chan->chid : -1, inst,
0188            chan ? chan->object.client->name : "unknown",
0189            st0, en ? en->name : "",
0190            st2, cl ? cl->name : "", st3, sc ? sc->name : "",
0191            st1, re ? re->name : "");
0192     nvkm_fifo_chan_put(fifo, flags, &chan);
0193 }
0194 
0195 static int
0196 nv50_fb_oneinit(struct nvkm_fb *base)
0197 {
0198     struct nv50_fb *fb = nv50_fb(base);
0199     struct nvkm_device *device = fb->base.subdev.device;
0200 
0201     fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
0202     if (fb->r100c08_page) {
0203         fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0,
0204                        PAGE_SIZE, DMA_BIDIRECTIONAL);
0205         if (dma_mapping_error(device->dev, fb->r100c08))
0206             return -EFAULT;
0207     }
0208 
0209     return 0;
0210 }
0211 
0212 static void
0213 nv50_fb_init(struct nvkm_fb *base)
0214 {
0215     struct nv50_fb *fb = nv50_fb(base);
0216     struct nvkm_device *device = fb->base.subdev.device;
0217 
0218     /* Not a clue what this is exactly.  Without pointing it at a
0219      * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
0220      * cause IOMMU "read from address 0" errors (rh#561267)
0221      */
0222     nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8);
0223 
0224     /* This is needed to get meaningful information from 100c90
0225      * on traps. No idea what these values mean exactly. */
0226     nvkm_wr32(device, 0x100c90, fb->func->trap);
0227 }
0228 
0229 static u32
0230 nv50_fb_tags(struct nvkm_fb *base)
0231 {
0232     struct nv50_fb *fb = nv50_fb(base);
0233     if (fb->func->tags)
0234         return fb->func->tags(&fb->base);
0235     return 0;
0236 }
0237 
0238 static void *
0239 nv50_fb_dtor(struct nvkm_fb *base)
0240 {
0241     struct nv50_fb *fb = nv50_fb(base);
0242     struct nvkm_device *device = fb->base.subdev.device;
0243 
0244     if (fb->r100c08_page) {
0245         dma_unmap_page(device->dev, fb->r100c08, PAGE_SIZE,
0246                    DMA_BIDIRECTIONAL);
0247         __free_page(fb->r100c08_page);
0248     }
0249 
0250     return fb;
0251 }
0252 
0253 static const struct nvkm_fb_func
0254 nv50_fb_ = {
0255     .dtor = nv50_fb_dtor,
0256     .tags = nv50_fb_tags,
0257     .oneinit = nv50_fb_oneinit,
0258     .init = nv50_fb_init,
0259     .intr = nv50_fb_intr,
0260     .ram_new = nv50_fb_ram_new,
0261 };
0262 
0263 int
0264 nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device,
0265          enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
0266 {
0267     struct nv50_fb *fb;
0268 
0269     if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL)))
0270         return -ENOMEM;
0271     nvkm_fb_ctor(&nv50_fb_, device, type, inst, &fb->base);
0272     fb->func = func;
0273     *pfb = &fb->base;
0274     return 0;
0275 }
0276 
0277 static const struct nv50_fb_func
0278 nv50_fb = {
0279     .ram_new = nv50_ram_new,
0280     .tags = nv20_fb_tags,
0281     .trap = 0x000707ff,
0282 };
0283 
0284 int
0285 nv50_fb_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst, struct nvkm_fb **pfb)
0286 {
0287     return nv50_fb_new_(&nv50_fb, device, type, inst, pfb);
0288 }