diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv98_crypt.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv98_crypt.c | 166 |
1 files changed, 152 insertions, 14 deletions
diff --git a/drivers/gpu/drm/nouveau/nv98_crypt.c b/drivers/gpu/drm/nouveau/nv98_crypt.c index db94ff0a9fab..e25e13fb894e 100644 --- a/drivers/gpu/drm/nouveau/nv98_crypt.c +++ b/drivers/gpu/drm/nouveau/nv98_crypt.c | |||
@@ -23,21 +23,93 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "drmP.h" | 25 | #include "drmP.h" |
26 | |||
26 | #include "nouveau_drv.h" | 27 | #include "nouveau_drv.h" |
27 | #include "nouveau_util.h" | 28 | #include "nouveau_util.h" |
28 | #include "nouveau_vm.h" | 29 | #include "nouveau_vm.h" |
29 | #include "nouveau_ramht.h" | 30 | #include "nouveau_ramht.h" |
30 | 31 | ||
31 | struct nv98_crypt_engine { | 32 | #include "nv98_crypt.fuc.h" |
33 | |||
34 | struct nv98_crypt_priv { | ||
32 | struct nouveau_exec_engine base; | 35 | struct nouveau_exec_engine base; |
33 | }; | 36 | }; |
34 | 37 | ||
38 | struct nv98_crypt_chan { | ||
39 | struct nouveau_gpuobj *mem; | ||
40 | }; | ||
41 | |||
35 | static int | 42 | static int |
36 | nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend) | 43 | nv98_crypt_context_new(struct nouveau_channel *chan, int engine) |
44 | { | ||
45 | struct drm_device *dev = chan->dev; | ||
46 | struct drm_nouveau_private *dev_priv = dev->dev_private; | ||
47 | struct nv98_crypt_priv *priv = nv_engine(dev, engine); | ||
48 | struct nv98_crypt_chan *cctx; | ||
49 | int ret; | ||
50 | |||
51 | cctx = chan->engctx[engine] = kzalloc(sizeof(*cctx), GFP_KERNEL); | ||
52 | if (!cctx) | ||
53 | return -ENOMEM; | ||
54 | |||
55 | atomic_inc(&chan->vm->engref[engine]); | ||
56 | |||
57 | ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC | | ||
58 | NVOBJ_FLAG_ZERO_FREE, &cctx->mem); | ||
59 | if (ret) | ||
60 | goto error; | ||
61 | |||
62 | nv_wo32(chan->ramin, 0xa0, 0x00190000); | ||
63 | nv_wo32(chan->ramin, 0xa4, cctx->mem->vinst + cctx->mem->size - 1); | ||
64 | nv_wo32(chan->ramin, 0xa8, cctx->mem->vinst); | ||
65 | nv_wo32(chan->ramin, 0xac, 0x00000000); | ||
66 | nv_wo32(chan->ramin, 0xb0, 0x00000000); | ||
67 | nv_wo32(chan->ramin, 0xb4, 0x00000000); | ||
68 | dev_priv->engine.instmem.flush(dev); | ||
69 | |||
70 | error: | ||
71 | if (ret) | ||
72 | priv->base.context_del(chan, engine); | ||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | static void | ||
77 | nv98_crypt_context_del(struct nouveau_channel *chan, int engine) | ||
78 | { | ||
79 | struct nv98_crypt_chan *cctx = chan->engctx[engine]; | ||
80 | int i; | ||
81 | |||
82 | for (i = 0xa0; i < 0xb4; i += 4) | ||
83 | nv_wo32(chan->ramin, i, 0x00000000); | ||
84 | |||
85 | nouveau_gpuobj_ref(NULL, &cctx->mem); | ||
86 | |||
87 | atomic_dec(&chan->vm->engref[engine]); | ||
88 | chan->engctx[engine] = NULL; | ||
89 | kfree(cctx); | ||
90 | } | ||
91 | |||
92 | static int | ||
93 | nv98_crypt_object_new(struct nouveau_channel *chan, int engine, | ||
94 | u32 handle, u16 class) | ||
37 | { | 95 | { |
38 | if (!(nv_rd32(dev, 0x000200) & 0x00004000)) | 96 | struct nv98_crypt_chan *cctx = chan->engctx[engine]; |
39 | return 0; | 97 | |
98 | /* fuc engine doesn't need an object, our ramht code does.. */ | ||
99 | cctx->mem->engine = 5; | ||
100 | cctx->mem->class = class; | ||
101 | return nouveau_ramht_insert(chan, handle, cctx->mem); | ||
102 | } | ||
40 | 103 | ||
104 | static void | ||
105 | nv98_crypt_tlb_flush(struct drm_device *dev, int engine) | ||
106 | { | ||
107 | nv50_vm_flush_engine(dev, 0x0a); | ||
108 | } | ||
109 | |||
110 | static int | ||
111 | nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend) | ||
112 | { | ||
41 | nv_mask(dev, 0x000200, 0x00004000, 0x00000000); | 113 | nv_mask(dev, 0x000200, 0x00004000, 0x00000000); |
42 | return 0; | 114 | return 0; |
43 | } | 115 | } |
@@ -45,34 +117,100 @@ nv98_crypt_fini(struct drm_device *dev, int engine, bool suspend) | |||
45 | static int | 117 | static int |
46 | nv98_crypt_init(struct drm_device *dev, int engine) | 118 | nv98_crypt_init(struct drm_device *dev, int engine) |
47 | { | 119 | { |
120 | int i; | ||
121 | |||
122 | /* reset! */ | ||
48 | nv_mask(dev, 0x000200, 0x00004000, 0x00000000); | 123 | nv_mask(dev, 0x000200, 0x00004000, 0x00000000); |
49 | nv_mask(dev, 0x000200, 0x00004000, 0x00004000); | 124 | nv_mask(dev, 0x000200, 0x00004000, 0x00004000); |
125 | |||
126 | /* wait for exit interrupt to signal */ | ||
127 | nv_wait(dev, 0x087008, 0x00000010, 0x00000010); | ||
128 | nv_wr32(dev, 0x087004, 0x00000010); | ||
129 | |||
130 | /* upload microcode code and data segments */ | ||
131 | nv_wr32(dev, 0x087ff8, 0x00100000); | ||
132 | for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_code); i++) | ||
133 | nv_wr32(dev, 0x087ff4, nv98_pcrypt_code[i]); | ||
134 | |||
135 | nv_wr32(dev, 0x087ff8, 0x00000000); | ||
136 | for (i = 0; i < ARRAY_SIZE(nv98_pcrypt_data); i++) | ||
137 | nv_wr32(dev, 0x087ff4, nv98_pcrypt_data[i]); | ||
138 | |||
139 | /* start it running */ | ||
140 | nv_wr32(dev, 0x08710c, 0x00000000); | ||
141 | nv_wr32(dev, 0x087104, 0x00000000); /* ENTRY */ | ||
142 | nv_wr32(dev, 0x087100, 0x00000002); /* TRIGGER */ | ||
50 | return 0; | 143 | return 0; |
51 | } | 144 | } |
52 | 145 | ||
146 | static struct nouveau_enum nv98_crypt_isr_error_name[] = { | ||
147 | { 0x0000, "ILLEGAL_MTHD" }, | ||
148 | { 0x0001, "INVALID_BITFIELD" }, | ||
149 | { 0x0002, "INVALID_ENUM" }, | ||
150 | { 0x0003, "QUERY" }, | ||
151 | {} | ||
152 | }; | ||
153 | |||
154 | static void | ||
155 | nv98_crypt_isr(struct drm_device *dev) | ||
156 | { | ||
157 | u32 disp = nv_rd32(dev, 0x08701c); | ||
158 | u32 stat = nv_rd32(dev, 0x087008) & disp & ~(disp >> 16); | ||
159 | u32 inst = nv_rd32(dev, 0x087050) & 0x3fffffff; | ||
160 | u32 ssta = nv_rd32(dev, 0x087040) & 0x0000ffff; | ||
161 | u32 addr = nv_rd32(dev, 0x087040) >> 16; | ||
162 | u32 mthd = (addr & 0x07ff) << 2; | ||
163 | u32 subc = (addr & 0x3800) >> 11; | ||
164 | u32 data = nv_rd32(dev, 0x087044); | ||
165 | int chid = nv50_graph_isr_chid(dev, inst); | ||
166 | |||
167 | if (stat & 0x00000040) { | ||
168 | NV_INFO(dev, "PCRYPT: DISPATCH_ERROR ["); | ||
169 | nouveau_enum_print(nv98_crypt_isr_error_name, ssta); | ||
170 | printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n", | ||
171 | chid, inst, subc, mthd, data); | ||
172 | nv_wr32(dev, 0x087004, 0x00000040); | ||
173 | stat &= ~0x00000040; | ||
174 | } | ||
175 | |||
176 | if (stat) { | ||
177 | NV_INFO(dev, "PCRYPT: unhandled intr 0x%08x\n", stat); | ||
178 | nv_wr32(dev, 0x087004, stat); | ||
179 | } | ||
180 | |||
181 | nv50_fb_vm_trap(dev, 1); | ||
182 | } | ||
183 | |||
53 | static void | 184 | static void |
54 | nv98_crypt_destroy(struct drm_device *dev, int engine) | 185 | nv98_crypt_destroy(struct drm_device *dev, int engine) |
55 | { | 186 | { |
56 | struct nv98_crypt_engine *pcrypt = nv_engine(dev, engine); | 187 | struct nv98_crypt_priv *priv = nv_engine(dev, engine); |
57 | 188 | ||
189 | nouveau_irq_unregister(dev, 14); | ||
58 | NVOBJ_ENGINE_DEL(dev, CRYPT); | 190 | NVOBJ_ENGINE_DEL(dev, CRYPT); |
59 | 191 | kfree(priv); | |
60 | kfree(pcrypt); | ||
61 | } | 192 | } |
62 | 193 | ||
63 | int | 194 | int |
64 | nv98_crypt_create(struct drm_device *dev) | 195 | nv98_crypt_create(struct drm_device *dev) |
65 | { | 196 | { |
66 | struct nv98_crypt_engine *pcrypt; | 197 | struct nv98_crypt_priv *priv; |
67 | 198 | ||
68 | pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL); | 199 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
69 | if (!pcrypt) | 200 | if (!priv) |
70 | return -ENOMEM; | 201 | return -ENOMEM; |
71 | 202 | ||
72 | pcrypt->base.destroy = nv98_crypt_destroy; | 203 | priv->base.destroy = nv98_crypt_destroy; |
73 | pcrypt->base.init = nv98_crypt_init; | 204 | priv->base.init = nv98_crypt_init; |
74 | pcrypt->base.fini = nv98_crypt_fini; | 205 | priv->base.fini = nv98_crypt_fini; |
206 | priv->base.context_new = nv98_crypt_context_new; | ||
207 | priv->base.context_del = nv98_crypt_context_del; | ||
208 | priv->base.object_new = nv98_crypt_object_new; | ||
209 | priv->base.tlb_flush = nv98_crypt_tlb_flush; | ||
210 | |||
211 | nouveau_irq_register(dev, 14, nv98_crypt_isr); | ||
75 | 212 | ||
76 | NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base); | 213 | NVOBJ_ENGINE_ADD(dev, CRYPT, &priv->base); |
214 | NVOBJ_CLASS(dev, 0x88b4, CRYPT); | ||
77 | return 0; | 215 | return 0; |
78 | } | 216 | } |