2 * Copyright 2012 Red Hat Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
27 #include <core/client.h>
28 #include <core/ramht.h>
29 #include <subdev/instmem.h>
31 #include <nvif/class.h>
32 #include <nvif/cl006b.h>
33 #include <nvif/unpack.h>
36 nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan
*base
, int cookie
)
38 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
39 struct nvkm_instmem
*imem
= chan
->fifo
->base
.engine
.subdev
.device
->imem
;
41 mutex_lock(&chan
->fifo
->base
.engine
.subdev
.mutex
);
42 nvkm_ramht_remove(imem
->ramht
, cookie
);
43 mutex_unlock(&chan
->fifo
->base
.engine
.subdev
.mutex
);
47 nv04_fifo_dma_object_ctor(struct nvkm_fifo_chan
*base
,
48 struct nvkm_object
*object
)
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
;
56 switch (object
->engine
->subdev
.index
) {
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;
66 mutex_lock(&chan
->fifo
->base
.engine
.subdev
.mutex
);
67 hash
= nvkm_ramht_insert(imem
->ramht
, object
, chan
->base
.chid
, 4,
69 mutex_unlock(&chan
->fifo
->base
.engine
.subdev
.mutex
);
74 nv04_fifo_dma_fini(struct nvkm_fifo_chan
*base
)
76 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
77 struct nv04_fifo
*fifo
= chan
->fifo
;
78 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
79 struct nvkm_memory
*fctx
= device
->imem
->ramfc
;
80 const struct nv04_fifo_ramfc
*c
;
82 u32 mask
= fifo
->base
.nr
- 1;
83 u32 data
= chan
->ramfc
;
86 /* prevent fifo context switches */
87 spin_lock_irqsave(&fifo
->base
.lock
, flags
);
88 nvkm_wr32(device
, NV03_PFIFO_CACHES
, 0);
90 /* if this channel is active, replace it with a null context */
91 chid
= nvkm_rd32(device
, NV03_PFIFO_CACHE1_PUSH1
) & mask
;
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);
100 u32 rm
= ((1ULL << c
->bits
) - 1) << c
->regs
;
101 u32 cm
= ((1ULL << c
->bits
) - 1) << c
->ctxs
;
102 u32 rv
= (nvkm_rd32(device
, c
->regp
) & rm
) >> c
->regs
;
103 u32 cv
= (nvkm_ro32(fctx
, c
->ctxp
+ data
) & ~cm
);
104 nvkm_wo32(fctx
, c
->ctxp
+ data
, cv
| (rv
<< c
->ctxs
));
105 } while ((++c
)->bits
);
110 nvkm_wr32(device
, c
->regp
, 0x00000000);
111 } while ((++c
)->bits
);
113 nvkm_wr32(device
, NV03_PFIFO_CACHE1_GET
, 0);
114 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUT
, 0);
115 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUSH1
, mask
);
116 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUSH0
, 1);
117 nvkm_wr32(device
, NV04_PFIFO_CACHE1_PULL0
, 1);
120 /* restore normal operation, after disabling dma mode */
121 nvkm_mask(device
, NV04_PFIFO_MODE
, 1 << chan
->base
.chid
, 0);
122 nvkm_wr32(device
, NV03_PFIFO_CACHES
, 1);
123 spin_unlock_irqrestore(&fifo
->base
.lock
, flags
);
127 nv04_fifo_dma_init(struct nvkm_fifo_chan
*base
)
129 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
130 struct nv04_fifo
*fifo
= chan
->fifo
;
131 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
132 u32 mask
= 1 << chan
->base
.chid
;
134 spin_lock_irqsave(&fifo
->base
.lock
, flags
);
135 nvkm_mask(device
, NV04_PFIFO_MODE
, mask
, mask
);
136 spin_unlock_irqrestore(&fifo
->base
.lock
, flags
);
140 nv04_fifo_dma_dtor(struct nvkm_fifo_chan
*base
)
142 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
143 struct nv04_fifo
*fifo
= chan
->fifo
;
144 struct nvkm_instmem
*imem
= fifo
->base
.engine
.subdev
.device
->imem
;
145 const struct nv04_fifo_ramfc
*c
= fifo
->ramfc
;
147 nvkm_kmap(imem
->ramfc
);
149 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ c
->ctxp
, 0x00000000);
150 } while ((++c
)->bits
);
151 nvkm_done(imem
->ramfc
);
155 const struct nvkm_fifo_chan_func
156 nv04_fifo_dma_func
= {
157 .dtor
= nv04_fifo_dma_dtor
,
158 .init
= nv04_fifo_dma_init
,
159 .fini
= nv04_fifo_dma_fini
,
160 .object_ctor
= nv04_fifo_dma_object_ctor
,
161 .object_dtor
= nv04_fifo_dma_object_dtor
,
165 nv04_fifo_dma_new(struct nvkm_fifo
*base
, const struct nvkm_oclass
*oclass
,
166 void *data
, u32 size
, struct nvkm_object
**pobject
)
168 struct nvkm_object
*parent
= oclass
->parent
;
170 struct nv03_channel_dma_v0 v0
;
172 struct nv04_fifo
*fifo
= nv04_fifo(base
);
173 struct nv04_fifo_chan
*chan
= NULL
;
174 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
175 struct nvkm_instmem
*imem
= device
->imem
;
178 nvif_ioctl(parent
, "create channel dma size %d\n", size
);
179 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
180 nvif_ioctl(parent
, "create channel dma vers %d pushbuf %llx "
181 "offset %08x\n", args
->v0
.version
,
182 args
->v0
.pushbuf
, args
->v0
.offset
);
183 if (!args
->v0
.pushbuf
)
188 if (!(chan
= kzalloc(sizeof(*chan
), GFP_KERNEL
)))
190 *pobject
= &chan
->base
.object
;
192 ret
= nvkm_fifo_chan_ctor(&nv04_fifo_dma_func
, &fifo
->base
,
193 0x1000, 0x1000, false, 0, args
->v0
.pushbuf
,
194 (1ULL << NVKM_ENGINE_DMAOBJ
) |
195 (1ULL << NVKM_ENGINE_GR
) |
196 (1ULL << NVKM_ENGINE_SW
),
197 0, 0x800000, 0x10000, oclass
, &chan
->base
);
202 args
->v0
.chid
= chan
->base
.chid
;
203 chan
->ramfc
= chan
->base
.chid
* 32;
205 nvkm_kmap(imem
->ramfc
);
206 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x00, args
->v0
.offset
);
207 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x04, args
->v0
.offset
);
208 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x08, chan
->base
.push
->addr
>> 4);
209 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x10,
210 NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES
|
211 NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES
|
213 NV_PFIFO_CACHE1_BIG_ENDIAN
|
215 NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8
);
216 nvkm_done(imem
->ramfc
);
220 const struct nvkm_fifo_chan_oclass
221 nv04_fifo_dma_oclass
= {
222 .base
.oclass
= NV03_CHANNEL_DMA
,
225 .ctor
= nv04_fifo_dma_new
,