Set memory attributes on page
[pscnv.git] / pscnv / nv98_crypt.c
blobb8b5dbb96d90d9706c3ea10fb09fad7f771af980
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2010 PathScale Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include "drm.h"
28 #include "nouveau_drv.h"
29 #include "pscnv_engine.h"
30 #include "pscnv_chan.h"
31 #include "nv50_chan.h"
32 #include "nv50_vm.h"
33 #include "nv98_crypt.fuc.h"
35 struct nv98_crypt_engine {
36 struct pscnv_engine base;
37 spinlock_t lock;
40 struct nv98_crypt_chan {
41 struct pscnv_bo *crctx;
44 #define nv98_crypt(x) container_of(x, struct nv98_crypt_engine, base)
46 static int nv98_crypt_oclasses[] = {
47 0x88f4,
51 void nv98_crypt_takedown(struct pscnv_engine *eng);
52 void nv98_crypt_irq_handler(struct drm_device *dev, int irq);
53 int nv98_crypt_tlb_flush(struct pscnv_engine *eng, struct pscnv_vspace *vs);
54 int nv86_crypt_tlb_flush(struct pscnv_engine *eng, struct pscnv_vspace *vs);
55 int nv98_crypt_chan_alloc(struct pscnv_engine *eng, struct pscnv_chan *ch);
56 void nv98_crypt_chan_free(struct pscnv_engine *eng, struct pscnv_chan *ch);
57 void nv98_crypt_chan_kill(struct pscnv_engine *eng, struct pscnv_chan *ch);
58 int nv98_crypt_chan_obj_new(struct pscnv_engine *eng, struct pscnv_chan *ch, uint32_t handle, uint32_t oclass, uint32_t flags);
60 int nv98_crypt_init(struct drm_device *dev) {
61 struct drm_nouveau_private *dev_priv = dev->dev_private;
62 struct nv98_crypt_engine *res = kzalloc(sizeof *res, GFP_KERNEL);
63 int i;
65 if (!res) {
66 NV_ERROR(dev, "PCRYPT: Couldn't allocate engine!\n");
67 return -ENOMEM;
70 res->base.dev = dev;
71 res->base.oclasses = nv98_crypt_oclasses;
72 res->base.takedown = nv98_crypt_takedown;
73 res->base.tlb_flush = nv98_crypt_tlb_flush;
74 res->base.chan_alloc = nv98_crypt_chan_alloc;
75 res->base.chan_kill = nv98_crypt_chan_kill;
76 res->base.chan_free = nv98_crypt_chan_free;
77 res->base.chan_obj_new = nv98_crypt_chan_obj_new;
78 spin_lock_init(&res->lock);
80 /* reset everything */
81 nv_wr32(dev, 0x200, 0xffffbfff);
82 nv_wr32(dev, 0x200, 0xffffffff);
84 while (!(nv_rd32(dev, 0x87008) & 0x10));
85 nv_wr32(dev, 0x87004, 0x10);
87 nv_wr32(dev, 0x87ff8, 0x00100000);
88 for (i = 0; i < sizeof(nv98_pcrypt_code); i += 4)
89 nv_wr32(dev, 0x87ff4, nv98_pcrypt_code[i] | nv98_pcrypt_code[i+1] << 8 | nv98_pcrypt_code[i+2] << 16 | nv98_pcrypt_code[i+3] << 24);
90 nv_wr32(dev, 0x87ff8, 0x00000000);
91 for (i = 0; i < sizeof(nv98_pcrypt_data); i += 4)
92 nv_wr32(dev, 0x87ff4, nv98_pcrypt_data[i] | nv98_pcrypt_data[i+1] << 8 | nv98_pcrypt_data[i+2] << 16 | nv98_pcrypt_data[i+3] << 24);
94 dev_priv->engines[PSCNV_ENGINE_CRYPT] = &res->base;
96 nouveau_irq_register(dev, 14, nv98_crypt_irq_handler);
98 nv_wr32(dev, 0x8710c, 0);
99 nv_wr32(dev, 0x87104, 0); /* ENTRY */
100 nv_wr32(dev, 0x87100, 2); /* TRIGGER */
101 return 0;
104 void nv98_crypt_takedown(struct pscnv_engine *eng) {
105 struct drm_nouveau_private *dev_priv = eng->dev->dev_private;
106 nv_wr32(eng->dev, 0x87014, -1); /* INTR_EN */
107 nouveau_irq_unregister(eng->dev, 14);
108 /* XXX */
109 kfree(eng);
110 dev_priv->engines[PSCNV_ENGINE_CRYPT] = 0;
113 int nv98_crypt_chan_alloc(struct pscnv_engine *eng, struct pscnv_chan *ch) {
114 struct drm_device *dev = eng->dev;
115 struct drm_nouveau_private *dev_priv = dev->dev_private;
116 uint32_t hdr;
117 uint64_t limit;
118 int i;
119 struct nv98_crypt_chan *crch = kzalloc(sizeof *crch, GFP_KERNEL);
121 if (!crch) {
122 NV_ERROR(dev, "PCRYPT: Couldn't allocate channel!\n");
123 return -ENOMEM;
126 hdr = 0xa0;
127 crch->crctx = pscnv_mem_alloc(dev, 0x100, PSCNV_GEM_CONTIG, 0, 0xc7c07e47);
128 if (!crch->crctx) {
129 NV_ERROR(dev, "PCRYPT: No VRAM for context!\n");
130 kfree(crch);
131 return -ENOMEM;
133 for (i = 0; i < 0x100; i += 4)
134 nv_wv32(crch->crctx, i, 0);
135 limit = crch->crctx->start + 0x80 - 1;
137 nv_wv32(ch->bo, hdr + 0x00, 0x00190000);
138 nv_wv32(ch->bo, hdr + 0x04, limit);
139 nv_wv32(ch->bo, hdr + 0x08, crch->crctx->start);
140 nv_wv32(ch->bo, hdr + 0x0c, (limit >> 32) << 24 | (crch->crctx->start >> 32));
141 nv_wv32(ch->bo, hdr + 0x10, 0);
142 nv_wv32(ch->bo, hdr + 0x14, 0);
143 dev_priv->vm->bar_flush(dev);
145 nv50_vs(ch->vspace)->engref[PSCNV_ENGINE_CRYPT]++;
146 ch->engdata[PSCNV_ENGINE_CRYPT] = crch;
147 return 0;
150 int nv98_crypt_tlb_flush(struct pscnv_engine *eng, struct pscnv_vspace *vs) {
151 return nv50_vm_flush(eng->dev, 0xa);
154 void nv98_crypt_chan_kill(struct pscnv_engine *eng, struct pscnv_chan *ch) {
155 struct drm_device *dev = eng->dev;
156 struct nv98_crypt_engine *crypt = nv98_crypt(eng);
157 uint64_t start;
158 unsigned long flags;
159 spin_lock_irqsave(&crypt->lock, flags);
160 start = nv04_timer_read(dev);
161 /* disable PFIFO access */
162 nv_wr32(dev, 0x87048, 0);
163 /* check if the channel we're freeing is active on PCRYPT. */
164 if (nv_rd32(dev, 0x87050) == (0x40000000 | ch->bo->start >> 12)) {
165 NV_INFO(dev, "Kicking channel %d off PCRYPT.\n", ch->cid);
166 nv_wr32(dev, 0x87050, 0);
168 /* or maybe it was just going to be loaded in? */
169 if (nv_rd32(dev, 0x87054) == (0x40000000 | ch->bo->start >> 12)) {
170 nv_wr32(dev, 0x87054, 0);
172 /* back to normal state. */
173 nv_wr32(dev, 0x87048, 0x3);
174 spin_unlock_irqrestore(&crypt->lock, flags);
177 void nv98_crypt_chan_free(struct pscnv_engine *eng, struct pscnv_chan *ch) {
178 struct nv98_crypt_chan *crch = ch->engdata[PSCNV_ENGINE_CRYPT];
179 pscnv_mem_free(crch->crctx);
180 kfree(crch);
181 nv50_vs(ch->vspace)->engref[PSCNV_ENGINE_CRYPT]--;
182 ch->engdata[PSCNV_ENGINE_CRYPT] = 0;
183 nv98_crypt_tlb_flush(eng, ch->vspace);
186 int nv98_crypt_chan_obj_new(struct pscnv_engine *eng, struct pscnv_chan *ch, uint32_t handle, uint32_t oclass, uint32_t flags) {
187 uint32_t inst = nv50_chan_iobj_new(ch, 0x20);
188 if (!inst) {
189 return -ENOMEM;
191 nv_wv32(ch->bo, inst, oclass);
192 nv_wv32(ch->bo, inst + 4, 0);
193 nv_wv32(ch->bo, inst + 8, 0);
194 nv_wv32(ch->bo, inst + 0xc, 0);
195 nv_wv32(ch->bo, inst + 0x10, 0);
196 nv_wv32(ch->bo, inst + 0x14, 0);
197 nv_wv32(ch->bo, inst + 0x18, 0);
198 nv_wv32(ch->bo, inst + 0x1c, 0);
199 return pscnv_ramht_insert (&ch->ramht, handle, 0x500000 | inst >> 4);
202 void nv98_crypt_irq_handler(struct drm_device *dev, int irq) {
203 struct drm_nouveau_private *dev_priv = dev->dev_private;
204 struct nv98_crypt_engine *crypt = nv98_crypt(dev_priv->engines[PSCNV_ENGINE_CRYPT]);
205 uint32_t status, dispatch;
206 unsigned long flags;
207 uint32_t chandle, data, addr, subc, mthd, ecode;
208 int cid;
209 spin_lock_irqsave(&crypt->lock, flags);
210 dispatch = nv_rd32(dev, 0x8701c);
211 status = nv_rd32(dev, 0x87008) & dispatch & ~(dispatch >> 16);
212 addr = nv_rd32(dev, 0x87040) >> 16;
213 ecode = nv_rd32(dev, 0x87040) & 0xffff;
215 data = nv_rd32(dev, 0x87044);
216 mthd = addr << 2 & 0x1ffc;
217 subc = addr >> 11 & 7;
218 chandle = nv_rd32(dev, 0x87050) & 0x3fffffff;
219 cid = pscnv_chan_handle_lookup(dev, chandle);
220 if (cid == 128) {
221 NV_ERROR(dev, "PCRYPT: UNKNOWN channel %x active!\n", chandle);
224 if (status & 0x40) {
225 switch (ecode) {
226 case 0:
227 NV_ERROR(dev, "PCRYPT_ILLEGAL_MTHD: ch %d subc %d mthd %04x data %08x\n", cid, subc, mthd, data);
228 break;
229 case 1:
230 NV_ERROR(dev, "PCRYPT_INVALID_BITFIELD: ch %d subc %d mthd %04x data %08x\n", cid, subc, mthd, data);
231 break;
232 case 2:
233 NV_ERROR(dev, "PCRYPT_INVALID_ENUM: ch %d subc %d mthd %04x data %08x\n", cid, subc, mthd, data);
234 break;
235 case 3:
236 NV_ERROR(dev, "PCRYPT_QUERY: ch %d subc %d mthd %04x data %08x\n", cid, subc, mthd, data);
237 break;
238 default:
239 NV_ERROR(dev, "PCRYPT_DISPATCH_ERROR [%x]: ch %d subc %d mthd %04x data %08x\n", ecode, cid, subc, mthd, data);
240 break;
242 nv_wr32(dev, 0x87004, 0x40);
243 status &= ~0x40;
246 if (status & 0x200) {
247 NV_ERROR(dev, "PCRYPT_FAULT: ch %d\n", cid);
248 nv_wr32(dev, 0x87004, 0x200);
249 status &= ~0x200;
252 if (status) {
253 NV_ERROR(dev, "Unknown PCRYPT interrupt %08x\n", status);
254 NV_ERROR(dev, "PCRYPT: ch %d\n", cid);
255 nv_wr32(dev, 0x87004, status);
257 nv50_vm_trap(dev);
258 spin_unlock_irqrestore(&crypt->lock, flags);