2 #include "nouveau_drv.h"
3 #include "nouveau_reg.h"
4 #include "pscnv_ioctl.h"
6 #include "pscnv_chan.h"
7 #include "pscnv_fifo.h"
10 #include "nvc0_graph.h"
11 #include "pscnv_kapi.h"
13 #include "nvc0_pgraph.xml.h"
15 #ifdef PSCNV_KAPI_GETPARAM_BUS_TYPE
16 #define DEVICE_IS_AGP(dev) drm_device_is_agp(dev)
17 #define DEVICE_IS_PCIE(dev) drm_device_is_pcie(dev)
19 #define DEVICE_IS_AGP(dev) drm_pci_device_is_agp(dev)
20 #define DEVICE_IS_PCIE(dev) pci_is_pcie(dev->pdev)
23 int pscnv_ioctl_getparam(struct drm_device
*dev
, void *data
,
24 struct drm_file
*file_priv
)
26 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
27 struct drm_pscnv_getparam
*getparam
= data
;
28 struct nvc0_graph_engine
*nvc0_graph
;
30 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
32 switch ((u32
)getparam
->param
) {
33 case PSCNV_GETPARAM_MP_COUNT
:
34 if (dev_priv
->chipset
< 0xc0)
36 nvc0_graph
= NVC0_GRAPH(dev_priv
->engines
[PSCNV_ENGINE_GRAPH
]);
37 getparam
->value
= nvc0_graph
->tp_count
; /* MPs == TPs */
39 case PSCNV_GETPARAM_CHIPSET_ID
:
40 getparam
->value
= dev_priv
->chipset
;
42 case PSCNV_GETPARAM_PCI_VENDOR
:
43 getparam
->value
= dev
->pci_vendor
;
45 case PSCNV_GETPARAM_PCI_DEVICE
:
46 getparam
->value
= dev
->pci_device
;
48 case PSCNV_GETPARAM_BUS_TYPE
:
49 if (DEVICE_IS_AGP(dev
))
50 getparam
->value
= NV_AGP
;
51 else if (DEVICE_IS_PCIE(dev
))
52 getparam
->value
= NV_PCIE
;
54 getparam
->value
= NV_PCI
;
56 case PSCNV_GETPARAM_PTIMER_TIME
:
57 getparam
->value
= nv04_timer_read(dev
);
59 case PSCNV_GETPARAM_FB_SIZE
:
60 getparam
->value
= dev_priv
->vram_size
;
62 case PSCNV_GETPARAM_GPC_COUNT
:
63 if (dev_priv
->card_type
< NV_C0
)
65 getparam
->value
= nv_rd32(dev
, NVC0_PGRAPH_CTXCTL_UNITS
);
66 getparam
->value
&= NVC0_PGRAPH_CTXCTL_UNITS_GPC_COUNT__MASK
;
68 case PSCNV_GETPARAM_TP_COUNT_IDX
: {
70 if (dev_priv
->card_type
< NV_C0
)
72 units
= nv_rd32(dev
, NVC0_PGRAPH_CTXCTL_UNITS
);
73 units
&= NVC0_PGRAPH_CTXCTL_UNITS_GPC_COUNT__MASK
;
74 i
= getparam
->param
>> 32ULL;
77 getparam
->value
= nv_rd32(dev
, NVC0_PGRAPH_GPC_CTXCTL_UNITS(i
));
78 getparam
->value
&= NVC0_PGRAPH_GPC_CTXCTL_UNITS_TP_COUNT__MASK
;
81 case PSCNV_GETPARAM_BAR0_ADDR
:
82 getparam
->value
= drm_get_resource_start(dev
, 0);
84 case PSCNV_GETPARAM_GRAPH_UNITS
:
85 /* NV40 and NV50 versions are quite different, but register
86 * address is the same. User is supposed to know the card
88 if (dev_priv
->card_type
>= NV_40
&& dev_priv
->card_type
< NV_C0
) {
89 getparam
->value
= nv_rd32(dev
, NV40_PMC_GRAPH_UNITS
);
99 NV_ERROR(dev
, "unknown parameter %lld\n", getparam
->param
);
103 int pscnv_ioctl_gem_new(struct drm_device
*dev
, void *data
,
104 struct drm_file
*file_priv
)
106 struct drm_pscnv_gem_info
*info
= data
;
107 struct drm_gem_object
*obj
;
111 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
113 obj
= pscnv_gem_new(dev
, info
->size
, info
->flags
, info
->tile_flags
, info
->cookie
, info
->user
);
117 bo
= obj
->driver_private
;
119 /* could change due to page size align */
120 info
->size
= bo
->size
;
121 info
->handle
= 0; /* FreeBSD expects this to be 0 else allocation fails */
122 ret
= drm_gem_handle_create(file_priv
, obj
, &info
->handle
);
124 if (pscnv_gem_debug
>= 1)
125 NV_INFO(dev
, "GEM handle %x is VO %x/%d\n", info
->handle
, bo
->cookie
, bo
->serial
);
128 info
->map_handle
= (uint64_t)info
->handle
<< 32;
130 info
->map_handle
= DRM_GEM_MAPPING_OFF(obj
->map_list
.key
) |
133 drm_gem_object_handle_unreference_unlocked (obj
);
138 int pscnv_ioctl_gem_info(struct drm_device
*dev
, void *data
,
139 struct drm_file
*file_priv
)
141 struct drm_pscnv_gem_info
*info
= data
;
142 struct drm_gem_object
*obj
;
146 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
148 obj
= drm_gem_object_lookup(dev
, file_priv
, info
->handle
);
152 bo
= obj
->driver_private
;
154 info
->cookie
= bo
->cookie
;
155 info
->flags
= bo
->flags
;
156 info
->tile_flags
= bo
->tile_flags
;
157 info
->size
= obj
->size
;
159 info
->map_handle
= (uint64_t)info
->handle
| 32;
161 info
->map_handle
= DRM_GEM_MAPPING_OFF(obj
->map_list
.key
) |
164 for (i
= 0; i
< DRM_ARRAY_SIZE(bo
->user
); i
++)
165 info
->user
[i
] = bo
->user
[i
];
167 drm_gem_object_unreference_unlocked(obj
);
172 static struct pscnv_vspace
*
173 pscnv_get_vspace(struct drm_device
*dev
, struct drm_file
*file_priv
, int vid
)
175 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
177 spin_lock_irqsave(&dev_priv
->vm
->vs_lock
, flags
);
179 if (vid
< 128 && vid
>= 0 && dev_priv
->vm
->vspaces
[vid
] && dev_priv
->vm
->vspaces
[vid
]->filp
== file_priv
) {
180 struct pscnv_vspace
*res
= dev_priv
->vm
->vspaces
[vid
];
181 pscnv_vspace_ref(res
);
182 spin_unlock_irqrestore(&dev_priv
->vm
->vs_lock
, flags
);
185 spin_unlock_irqrestore(&dev_priv
->vm
->vs_lock
, flags
);
189 int pscnv_ioctl_vspace_new(struct drm_device
*dev
, void *data
,
190 struct drm_file
*file_priv
)
192 struct drm_pscnv_vspace_req
*req
= data
;
193 struct pscnv_vspace
*vs
;
195 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
197 vs
= pscnv_vspace_new(dev
, 1ull << 40, 0, 0);
203 vs
->filp
= file_priv
;
208 int pscnv_ioctl_vspace_free(struct drm_device
*dev
, void *data
,
209 struct drm_file
*file_priv
)
211 struct drm_pscnv_vspace_req
*req
= data
;
213 struct pscnv_vspace
*vs
;
215 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
217 vs
= pscnv_get_vspace(dev
, file_priv
, vid
);
222 pscnv_vspace_unref(vs
);
223 pscnv_vspace_unref(vs
);
228 int pscnv_ioctl_vspace_map(struct drm_device
*dev
, void *data
,
229 struct drm_file
*file_priv
)
231 struct drm_pscnv_vspace_map
*req
= data
;
232 struct pscnv_vspace
*vs
;
233 struct drm_gem_object
*obj
;
235 struct pscnv_mm_node
*map
;
238 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
240 vs
= pscnv_get_vspace(dev
, file_priv
, req
->vid
);
244 obj
= drm_gem_object_lookup(dev
, file_priv
, req
->handle
);
246 pscnv_vspace_unref(vs
);
250 bo
= obj
->driver_private
;
252 ret
= pscnv_vspace_map(vs
, bo
, req
->start
, req
->end
, req
->back
, &map
);
254 req
->offset
= map
->start
;
256 pscnv_vspace_unref(vs
);
261 int pscnv_ioctl_vspace_unmap(struct drm_device
*dev
, void *data
,
262 struct drm_file
*file_priv
)
264 struct drm_pscnv_vspace_unmap
*req
= data
;
265 struct pscnv_vspace
*vs
;
268 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
271 vs
= pscnv_get_vspace(dev
, file_priv
, req
->vid
);
275 ret
= pscnv_vspace_unmap(vs
, req
->offset
);
277 pscnv_vspace_unref(vs
);
282 void pscnv_vspace_cleanup(struct drm_device
*dev
, struct drm_file
*file_priv
) {
284 struct pscnv_vspace
*vs
;
286 for (vid
= 0; vid
< 128; vid
++) {
287 vs
= pscnv_get_vspace(dev
, file_priv
, vid
);
291 pscnv_vspace_unref(vs
);
292 pscnv_vspace_unref(vs
);
297 pscnv_get_chan(struct drm_device
*dev
, struct drm_file
*file_priv
, int cid
)
299 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
301 spin_lock_irqsave(&dev_priv
->chan
->ch_lock
, flags
);
303 if (cid
< 128 && cid
>= 0 && dev_priv
->chan
->chans
[cid
] && dev_priv
->chan
->chans
[cid
]->filp
== file_priv
) {
304 struct pscnv_chan
*res
= dev_priv
->chan
->chans
[cid
];
306 spin_unlock_irqrestore(&dev_priv
->chan
->ch_lock
, flags
);
309 spin_unlock_irqrestore(&dev_priv
->chan
->ch_lock
, flags
);
313 int pscnv_ioctl_chan_new(struct drm_device
*dev
, void *data
,
314 struct drm_file
*file_priv
)
316 struct drm_pscnv_chan_new
*req
= data
;
317 struct pscnv_vspace
*vs
;
318 struct pscnv_chan
*ch
;
320 struct drm_gem_object
*obj
;
322 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
324 vs
= pscnv_get_vspace(dev
, file_priv
, req
->vid
);
328 ch
= pscnv_chan_new(dev
, vs
, 0);
330 pscnv_vspace_unref(vs
);
333 pscnv_vspace_unref(vs
);
335 if (!(obj
= pscnv_gem_wrap(dev
, ch
->bo
))) {
336 pscnv_chan_unref(ch
);
339 req
->map_handle
= DRM_GEM_MAPPING_OFF(obj
->map_list
.key
) |
342 req
->map_handle
= 0xc0000000 | ch
->cid
<< 16;
347 ch
->filp
= file_priv
;
352 int pscnv_ioctl_chan_free(struct drm_device
*dev
, void *data
,
353 struct drm_file
*file_priv
)
355 struct drm_pscnv_chan_free
*req
= data
;
356 struct pscnv_chan
*ch
;
358 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
360 ch
= pscnv_get_chan(dev
, file_priv
, req
->cid
);
365 pscnv_chan_unref(ch
);
366 pscnv_chan_unref(ch
);
371 int pscnv_ioctl_obj_vdma_new(struct drm_device
*dev
, void *data
,
372 struct drm_file
*file_priv
) {
373 struct drm_pscnv_obj_vdma_new
*req
= data
;
374 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
375 struct pscnv_chan
*ch
;
377 uint32_t oclass
, inst
;
379 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
381 if (dev_priv
->card_type
!= NV_50
)
384 oclass
= req
->oclass
;
386 if (oclass
!= 2 && oclass
!= 3 && oclass
!= 0x3d)
389 ch
= pscnv_get_chan(dev
, file_priv
, req
->cid
);
393 inst
= nv50_chan_dmaobj_new(ch
, 0x7fc00000 | oclass
, req
->start
, req
->size
);
395 pscnv_chan_unref(ch
);
399 ret
= pscnv_ramht_insert (&ch
->ramht
, req
->handle
, inst
>> 4);
401 pscnv_chan_unref(ch
);
406 void pscnv_chan_cleanup(struct drm_device
*dev
, struct drm_file
*file_priv
) {
408 struct pscnv_chan
*ch
;
410 for (cid
= 0; cid
< 128; cid
++) {
411 ch
= pscnv_get_chan(dev
, file_priv
, cid
);
415 pscnv_chan_unref(ch
);
416 pscnv_chan_unref(ch
);
420 int pscnv_ioctl_obj_eng_new(struct drm_device
*dev
, void *data
,
421 struct drm_file
*file_priv
) {
422 struct drm_pscnv_obj_eng_new
*req
= data
;
423 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
424 struct pscnv_chan
*ch
;
427 uint32_t oclass
= req
->oclass
;
429 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
431 for (i
= 0; i
< PSCNV_ENGINES_NUM
; i
++)
432 if (dev_priv
->engines
[i
]) {
433 uint32_t *pclass
= dev_priv
->engines
[i
]->oclasses
;
437 if (*pclass
== oclass
)
445 ch
= pscnv_get_chan(dev
, file_priv
, req
->cid
);
449 if (!ch
->engdata
[i
]) {
450 ret
= dev_priv
->engines
[i
]->chan_alloc(dev_priv
->engines
[i
], ch
);
452 pscnv_chan_unref(ch
);
457 ret
= dev_priv
->engines
[i
]->chan_obj_new(dev_priv
->engines
[i
], ch
, req
->handle
, oclass
, req
->flags
);
459 pscnv_chan_unref(ch
);
463 int pscnv_ioctl_fifo_init(struct drm_device
*dev
, void *data
,
464 struct drm_file
*file_priv
) {
465 struct drm_pscnv_fifo_init
*req
= data
;
466 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
467 struct pscnv_chan
*ch
;
470 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
472 if (!dev_priv
->fifo
|| !dev_priv
->fifo
->chan_init_dma
)
475 ch
= pscnv_get_chan(dev
, file_priv
, req
->cid
);
479 ret
= dev_priv
->fifo
->chan_init_dma(ch
, req
->pb_handle
, req
->flags
, req
->slimask
, req
->pb_start
);
481 pscnv_chan_unref(ch
);
486 int pscnv_ioctl_fifo_init_ib(struct drm_device
*dev
, void *data
,
487 struct drm_file
*file_priv
) {
488 struct drm_pscnv_fifo_init_ib
*req
= data
;
489 struct drm_nouveau_private
*dev_priv
= dev
->dev_private
;
490 struct pscnv_chan
*ch
;
493 NOUVEAU_CHECK_INITIALISED_WITH_RETURN
;
495 if (!dev_priv
->fifo
|| !dev_priv
->fifo
->chan_init_ib
)
498 ch
= pscnv_get_chan(dev
, file_priv
, req
->cid
);
502 ret
= dev_priv
->fifo
->chan_init_ib(ch
, req
->pb_handle
, req
->flags
, req
->slimask
, req
->ib_start
, req
->ib_order
);
504 pscnv_chan_unref(ch
);