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);
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
);
108 nvkm_wr32(device
, c
->regp
, 0x00000000);
109 } while ((++c
)->bits
);
111 nvkm_wr32(device
, NV03_PFIFO_CACHE1_GET
, 0);
112 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUT
, 0);
113 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUSH1
, mask
);
114 nvkm_wr32(device
, NV03_PFIFO_CACHE1_PUSH0
, 1);
115 nvkm_wr32(device
, NV04_PFIFO_CACHE1_PULL0
, 1);
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
);
125 nv04_fifo_dma_init(struct nvkm_fifo_chan
*base
)
127 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
128 struct nv04_fifo
*fifo
= chan
->fifo
;
129 struct nvkm_device
*device
= fifo
->base
.engine
.subdev
.device
;
130 u32 mask
= 1 << chan
->base
.chid
;
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
);
138 nv04_fifo_dma_dtor(struct nvkm_fifo_chan
*base
)
140 struct nv04_fifo_chan
*chan
= nv04_fifo_chan(base
);
141 struct nv04_fifo
*fifo
= chan
->fifo
;
142 struct nvkm_instmem
*imem
= fifo
->base
.engine
.subdev
.device
->imem
;
143 const struct nv04_fifo_ramfc
*c
= fifo
->ramfc
;
145 nvkm_kmap(imem
->ramfc
);
147 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ c
->ctxp
, 0x00000000);
148 } while ((++c
)->bits
);
149 nvkm_done(imem
->ramfc
);
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
,
163 nv04_fifo_dma_new(struct nvkm_fifo
*base
, const struct nvkm_oclass
*oclass
,
164 void *data
, u32 size
, struct nvkm_object
**pobject
)
166 struct nvkm_object
*parent
= oclass
->parent
;
168 struct nv03_channel_dma_v0 v0
;
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
;
176 nvif_ioctl(parent
, "create channel dma size %d\n", size
);
177 if (!(ret
= nvif_unpack(ret
, &data
, &size
, args
->v0
, 0, 0, false))) {
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
);
181 if (!args
->v0
.pushbuf
)
186 if (!(chan
= kzalloc(sizeof(*chan
), GFP_KERNEL
)))
188 *pobject
= &chan
->base
.object
;
190 ret
= nvkm_fifo_chan_ctor(&nv04_fifo_dma_func
, &fifo
->base
,
191 0x1000, 0x1000, false, 0, args
->v0
.pushbuf
,
192 (1ULL << NVKM_ENGINE_DMAOBJ
) |
193 (1ULL << NVKM_ENGINE_GR
) |
194 (1ULL << NVKM_ENGINE_SW
),
195 0, 0x800000, 0x10000, oclass
, &chan
->base
);
200 args
->v0
.chid
= chan
->base
.chid
;
201 chan
->ramfc
= chan
->base
.chid
* 32;
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
);
206 nvkm_wo32(imem
->ramfc
, chan
->ramfc
+ 0x08, chan
->base
.push
->addr
>> 4);
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
|
211 NV_PFIFO_CACHE1_BIG_ENDIAN
|
213 NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8
);
214 nvkm_done(imem
->ramfc
);
218 const struct nvkm_fifo_chan_oclass
219 nv04_fifo_dma_oclass
= {
220 .base
.oclass
= NV03_CHANNEL_DMA
,
223 .ctor
= nv04_fifo_dma_new
,