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/unpack.h>
35 nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan
*base
, int cookie
)
37 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
38 struct nvkm_instmem
*imem
= chan
->fifo
->base
.engine
.subdev
.device
->imem
;
39 nvkm_ramht_remove(imem
->ramht
, cookie
);
43 nv04_fifo_dma_object_ctor(struct nvkm_fifo_chan
*base
,
44 struct nvkm_object
*object
)
46 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
47 struct nvkm_instmem
*imem
= chan
->fifo
->base
.engine
.subdev
.device
->imem
;
48 u32 context
= 0x80000000 | chan
->base
.chid
<< 24;
49 u32 handle
= object
->handle
;
52 switch (object
->engine
->subdev
.index
) {
53 case NVKM_ENGINE_DMAOBJ
:
54 case NVKM_ENGINE_SW
: context
|= 0x00000000; break;
55 case NVKM_ENGINE_GR
: context
|= 0x00010000; break;
56 case NVKM_ENGINE_MPEG
: context
|= 0x00020000; break;
62 mutex_lock(&chan
->fifo
->base
.engine
.subdev
.mutex
);
63 hash
= nvkm_ramht_insert(imem
->ramht
, object
, chan
->base
.chid
, 4,
65 mutex_unlock(&chan
->fifo
->base
.engine
.subdev
.mutex
);
70 nv04_fifo_dma_fini(struct nvkm_fifo_chan
*base
)
72 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
73 struct nv04_fifo
*fifo
= chan
->fifo
;
74 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
75 struct nvkm_memory
*fctx
= device
->imem
->ramfc
;
76 const struct nv04_fifo_ramfc
*c
;
78 u32 mask
= fifo
->base
.nr
- 1;
79 u32 data
= chan
->ramfc
;
82 /* prevent fifo context switches */
83 spin_lock_irqsave(&fifo
->base
.lock
, flags
);
84 nvkm_wr32(device
, NV03_PFIFO_CACHES
, 0);
86 /* if this channel is active, replace it with a null context */
87 chid
= nvkm_rd32(device
, NV03_PFIFO_CACHE1_PUSH1
) & mask
;
88 if (chid
== chan
->base
.chid
) {
89 nvkm_mask(device
, NV04_PFIFO_CACHE1_DMA_PUSH
, 0x00000001, 0);
90 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUSH0
, 0);
91 nvkm_mask(device
, NV04_PFIFO_CACHE1_PULL0
, 0x00000001, 0);
95 u32 rm
= ((1ULL << c
->bits
) - 1) << c
->regs
;
96 u32 cm
= ((1ULL << c
->bits
) - 1) << c
->ctxs
;
97 u32 rv
= (nvkm_rd32(device
, c
->regp
) & rm
) >> c
->regs
;
98 u32 cv
= (nvkm_ro32(fctx
, c
->ctxp
+ data
) & ~cm
);
99 nvkm_wo32(fctx
, c
->ctxp
+ data
, cv
| (rv
<< c
->ctxs
));
100 } while ((++c
)->bits
);
104 nvkm_wr32(device
, c
->regp
, 0x00000000);
105 } while ((++c
)->bits
);
107 nvkm_wr32(device
, NV03_PFIFO_CACHE1_GET
, 0);
108 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUT
, 0);
109 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUSH1
, mask
);
110 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUSH0
, 1);
111 nvkm_wr32(device
, NV04_PFIFO_CACHE1_PULL0
, 1);
114 /* restore normal operation, after disabling dma mode */
115 nvkm_mask(device
, NV04_PFIFO_MODE
, 1 << chan
->base
.chid
, 0);
116 nvkm_wr32(device
, NV03_PFIFO_CACHES
, 1);
117 spin_unlock_irqrestore(&fifo
->base
.lock
, flags
);
121 nv04_fifo_dma_init(struct nvkm_fifo_chan
*base
)
123 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
124 struct nv04_fifo
*fifo
= chan
->fifo
;
125 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
126 u32 mask
= 1 << chan
->base
.chid
;
128 spin_lock_irqsave(&fifo
->base
.lock
, flags
);
129 nvkm_mask(device
, NV04_PFIFO_MODE
, mask
, mask
);
130 spin_unlock_irqrestore(&fifo
->base
.lock
, flags
);
134 nv04_fifo_dma_dtor(struct nvkm_fifo_chan
*base
)
136 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
137 struct nv04_fifo
*fifo
= chan
->fifo
;
138 struct nvkm_instmem
*imem
= fifo
->base
.engine
.subdev
.device
->imem
;
139 const struct nv04_fifo_ramfc
*c
= fifo
->ramfc
;
141 nvkm_kmap(imem
->ramfc
);
143 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ c
->ctxp
, 0x00000000);
144 } while ((++c
)->bits
);
145 nvkm_done(imem
->ramfc
);
149 const struct nvkm_fifo_chan_func
150 nv04_fifo_dma_func
= {
151 .dtor
= nv04_fifo_dma_dtor
,
152 .init
= nv04_fifo_dma_init
,
153 .fini
= nv04_fifo_dma_fini
,
154 .object_ctor
= nv04_fifo_dma_object_ctor
,
155 .object_dtor
= nv04_fifo_dma_object_dtor
,
159 nv04_fifo_dma_new(struct nvkm_fifo
*base
, const struct nvkm_oclass
*oclass
,
160 void *data
, u32 size
, struct nvkm_object
**pobject
)
162 struct nvkm_object
*parent
= oclass
->parent
;
164 struct nv03_channel_dma_v0 v0
;
166 struct nv04_fifo
*fifo
= nv04_fifo(base
);
167 struct nv04_fifo_chan
*chan
= NULL
;
168 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
169 struct nvkm_instmem
*imem
= device
->imem
;
172 nvif_ioctl(parent
, "create channel dma size %d\n", size
);
173 if (nvif_unpack(args
->v0
, 0, 0, false)) {
174 nvif_ioctl(parent
, "create channel dma vers %d pushbuf %llx "
175 "offset %08x\n", args
->v0
.version
,
176 args
->v0
.pushbuf
, args
->v0
.offset
);
177 if (!args
->v0
.pushbuf
)
182 if (!(chan
= kzalloc(sizeof(*chan
), GFP_KERNEL
)))
184 *pobject
= &chan
->base
.object
;
186 ret
= nvkm_fifo_chan_ctor(&nv04_fifo_dma_func
, &fifo
->base
,
187 0x1000, 0x1000, false, 0, args
->v0
.pushbuf
,
188 (1ULL << NVKM_ENGINE_DMAOBJ
) |
189 (1ULL << NVKM_ENGINE_GR
) |
190 (1ULL << NVKM_ENGINE_SW
),
191 0, 0x800000, 0x10000, oclass
, &chan
->base
);
196 args
->v0
.chid
= chan
->base
.chid
;
197 chan
->ramfc
= chan
->base
.chid
* 32;
199 nvkm_kmap(imem
->ramfc
);
200 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x00, args
->v0
.offset
);
201 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x04, args
->v0
.offset
);
202 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x08, chan
->base
.push
->addr
>> 4);
203 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x10,
204 NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES
|
205 NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES
|
207 NV_PFIFO_CACHE1_BIG_ENDIAN
|
209 NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8
);
210 nvkm_done(imem
->ramfc
);
214 const struct nvkm_fifo_chan_oclass
215 nv04_fifo_dma_oclass
= {
216 .base
.oclass
= NV03_CHANNEL_DMA
,
219 .ctor
= nv04_fifo_dma_new
,