Commit | Line | Data |
---|---|---|
9a65a38c 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 | #include "channv04.h" | |
25 | #include "regsnv04.h" | |
26 | ||
27 | #include <core/client.h> | |
28 | #include <core/ramht.h> | |
29 | #include <subdev/instmem.h> | |
30 | ||
31 | #include <nvif/class.h> | |
8ed1730c | 32 | #include <nvif/cl006b.h> |
9a65a38c BS |
33 | #include <nvif/unpack.h> |
34 | ||
9a65a38c | 35 | void |
8f0649b5 | 36 | nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *base, int cookie) |
9a65a38c | 37 | { |
8f0649b5 BS |
38 | struct nv04_fifo_chan *chan = nv04_fifo_chan(base); |
39 | struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; | |
666ca3d8 IM |
40 | |
41 | mutex_lock(&chan->fifo->base.engine.subdev.mutex); | |
9a65a38c | 42 | nvkm_ramht_remove(imem->ramht, cookie); |
666ca3d8 | 43 | mutex_unlock(&chan->fifo->base.engine.subdev.mutex); |
9a65a38c BS |
44 | } |
45 | ||
8f0649b5 BS |
46 | static int |
47 | nv04_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, | |
48 | struct nvkm_object *object) | |
9a65a38c | 49 | { |
8f0649b5 BS |
50 | struct nv04_fifo_chan *chan = nv04_fifo_chan(base); |
51 | struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; | |
52 | u32 context = 0x80000000 | chan->base.chid << 24; | |
53 | u32 handle = object->handle; | |
54 | int hash; | |
55 | ||
56 | switch (object->engine->subdev.index) { | |
68f3f702 BS |
57 | case NVKM_ENGINE_DMAOBJ: |
58 | case NVKM_ENGINE_SW : context |= 0x00000000; break; | |
59 | case NVKM_ENGINE_GR : context |= 0x00010000; break; | |
60 | case NVKM_ENGINE_MPEG : context |= 0x00020000; break; | |
8f0649b5 BS |
61 | default: |
62 | WARN_ON(1); | |
63 | return -EINVAL; | |
9a65a38c BS |
64 | } |
65 | ||
8f0649b5 BS |
66 | mutex_lock(&chan->fifo->base.engine.subdev.mutex); |
67 | hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4, | |
68 | handle, context); | |
69 | mutex_unlock(&chan->fifo->base.engine.subdev.mutex); | |
70 | return hash; | |
9a65a38c BS |
71 | } |
72 | ||
8f0649b5 BS |
73 | void |
74 | nv04_fifo_dma_fini(struct nvkm_fifo_chan *base) | |
9a65a38c | 75 | { |
8f0649b5 BS |
76 | struct nv04_fifo_chan *chan = nv04_fifo_chan(base); |
77 | struct nv04_fifo *fifo = chan->fifo; | |
9a65a38c BS |
78 | struct nvkm_device *device = fifo->base.engine.subdev.device; |
79 | struct nvkm_memory *fctx = device->imem->ramfc; | |
13de7f46 | 80 | const struct nv04_fifo_ramfc *c; |
9a65a38c | 81 | unsigned long flags; |
8f0649b5 | 82 | u32 mask = fifo->base.nr - 1; |
9a65a38c BS |
83 | u32 data = chan->ramfc; |
84 | u32 chid; | |
85 | ||
86 | /* prevent fifo context switches */ | |
87 | spin_lock_irqsave(&fifo->base.lock, flags); | |
88 | nvkm_wr32(device, NV03_PFIFO_CACHES, 0); | |
89 | ||
90 | /* if this channel is active, replace it with a null context */ | |
8f0649b5 | 91 | chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & mask; |
9a65a38c BS |
92 | if (chid == chan->base.chid) { |
93 | nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); | |
94 | nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); | |
95 | nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); | |
96 | ||
13de7f46 | 97 | c = fifo->ramfc; |
9a65a38c BS |
98 | do { |
99 | u32 rm = ((1ULL << c->bits) - 1) << c->regs; | |
100 | u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; | |
101 | u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs; | |
102 | u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm); | |
103 | nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); | |
104 | } while ((++c)->bits); | |
105 | ||
13de7f46 | 106 | c = fifo->ramfc; |
9a65a38c BS |
107 | do { |
108 | nvkm_wr32(device, c->regp, 0x00000000); | |
109 | } while ((++c)->bits); | |
110 | ||
111 | nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0); | |
112 | nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0); | |
8f0649b5 | 113 | nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, mask); |
9a65a38c BS |
114 | nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); |
115 | nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); | |
116 | } | |
117 | ||
118 | /* restore normal operation, after disabling dma mode */ | |
119 | nvkm_mask(device, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); | |
120 | nvkm_wr32(device, NV03_PFIFO_CACHES, 1); | |
121 | spin_unlock_irqrestore(&fifo->base.lock, flags); | |
9a65a38c BS |
122 | } |
123 | ||
8f0649b5 BS |
124 | void |
125 | nv04_fifo_dma_init(struct nvkm_fifo_chan *base) | |
9a65a38c | 126 | { |
8f0649b5 BS |
127 | struct nv04_fifo_chan *chan = nv04_fifo_chan(base); |
128 | struct nv04_fifo *fifo = chan->fifo; | |
9a65a38c BS |
129 | struct nvkm_device *device = fifo->base.engine.subdev.device; |
130 | u32 mask = 1 << chan->base.chid; | |
131 | unsigned long flags; | |
9a65a38c BS |
132 | spin_lock_irqsave(&fifo->base.lock, flags); |
133 | nvkm_mask(device, NV04_PFIFO_MODE, mask, mask); | |
134 | spin_unlock_irqrestore(&fifo->base.lock, flags); | |
9a65a38c BS |
135 | } |
136 | ||
8f0649b5 BS |
137 | void * |
138 | nv04_fifo_dma_dtor(struct nvkm_fifo_chan *base) | |
9a65a38c | 139 | { |
8f0649b5 BS |
140 | struct nv04_fifo_chan *chan = nv04_fifo_chan(base); |
141 | struct nv04_fifo *fifo = chan->fifo; | |
9a65a38c | 142 | struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; |
13de7f46 | 143 | const struct nv04_fifo_ramfc *c = fifo->ramfc; |
9a65a38c BS |
144 | |
145 | nvkm_kmap(imem->ramfc); | |
146 | do { | |
147 | nvkm_wo32(imem->ramfc, chan->ramfc + c->ctxp, 0x00000000); | |
148 | } while ((++c)->bits); | |
149 | nvkm_done(imem->ramfc); | |
8f0649b5 | 150 | return chan; |
9a65a38c BS |
151 | } |
152 | ||
8f0649b5 BS |
153 | const struct nvkm_fifo_chan_func |
154 | nv04_fifo_dma_func = { | |
155 | .dtor = nv04_fifo_dma_dtor, | |
156 | .init = nv04_fifo_dma_init, | |
157 | .fini = nv04_fifo_dma_fini, | |
158 | .object_ctor = nv04_fifo_dma_object_ctor, | |
159 | .object_dtor = nv04_fifo_dma_object_dtor, | |
160 | }; | |
161 | ||
9a65a38c | 162 | static int |
8f0649b5 BS |
163 | nv04_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, |
164 | void *data, u32 size, struct nvkm_object **pobject) | |
9a65a38c | 165 | { |
8f0649b5 | 166 | struct nvkm_object *parent = oclass->parent; |
9a65a38c BS |
167 | union { |
168 | struct nv03_channel_dma_v0 v0; | |
169 | } *args = data; | |
8f0649b5 BS |
170 | struct nv04_fifo *fifo = nv04_fifo(base); |
171 | struct nv04_fifo_chan *chan = NULL; | |
172 | struct nvkm_device *device = fifo->base.engine.subdev.device; | |
173 | struct nvkm_instmem *imem = device->imem; | |
f01c4e68 | 174 | int ret = -ENOSYS; |
9a65a38c BS |
175 | |
176 | nvif_ioctl(parent, "create channel dma size %d\n", size); | |
f01c4e68 | 177 | if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { |
9a65a38c BS |
178 | nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " |
179 | "offset %08x\n", args->v0.version, | |
180 | args->v0.pushbuf, args->v0.offset); | |
8f0649b5 BS |
181 | if (!args->v0.pushbuf) |
182 | return -EINVAL; | |
9a65a38c BS |
183 | } else |
184 | return ret; | |
185 | ||
8f0649b5 BS |
186 | if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) |
187 | return -ENOMEM; | |
188 | *pobject = &chan->base.object; | |
189 | ||
190 | ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, | |
191 | 0x1000, 0x1000, false, 0, args->v0.pushbuf, | |
68f3f702 BS |
192 | (1ULL << NVKM_ENGINE_DMAOBJ) | |
193 | (1ULL << NVKM_ENGINE_GR) | | |
194 | (1ULL << NVKM_ENGINE_SW), | |
8f0649b5 BS |
195 | 0, 0x800000, 0x10000, oclass, &chan->base); |
196 | chan->fifo = fifo; | |
9a65a38c BS |
197 | if (ret) |
198 | return ret; | |
199 | ||
200 | args->v0.chid = chan->base.chid; | |
9a65a38c BS |
201 | chan->ramfc = chan->base.chid * 32; |
202 | ||
203 | nvkm_kmap(imem->ramfc); | |
204 | nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); | |
205 | nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); | |
8f0649b5 | 206 | nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.push->addr >> 4); |
9a65a38c BS |
207 | nvkm_wo32(imem->ramfc, chan->ramfc + 0x10, |
208 | NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | | |
209 | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | | |
210 | #ifdef __BIG_ENDIAN | |
211 | NV_PFIFO_CACHE1_BIG_ENDIAN | | |
212 | #endif | |
213 | NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); | |
214 | nvkm_done(imem->ramfc); | |
215 | return 0; | |
216 | } | |
217 | ||
8f0649b5 BS |
218 | const struct nvkm_fifo_chan_oclass |
219 | nv04_fifo_dma_oclass = { | |
220 | .base.oclass = NV03_CHANNEL_DMA, | |
221 | .base.minver = 0, | |
222 | .base.maxver = 0, | |
223 | .ctor = nv04_fifo_dma_new, | |
9a65a38c | 224 | }; |