2012-07-20 02:17:34 +04:00
/*
* Copyright 2012 Red Hat Inc .
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the " Software " ) ,
* to deal in the Software without restriction , including without limitation
* the rights to use , copy , modify , merge , publish , distribute , sublicense ,
* and / or sell copies of the Software , and to permit persons to whom the
* Software is furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDER ( S ) OR AUTHOR ( S ) BE LIABLE FOR ANY CLAIM , DAMAGES OR
* OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE ,
* ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE .
*
* Authors : Ben Skeggs
*/
2014-08-09 22:10:23 +04:00
# include <nvif/os.h>
# include <nvif/class.h>
2015-11-08 05:16:40 +03:00
# include <nvif/cl0002.h>
2015-11-08 04:28:26 +03:00
# include <nvif/cl006b.h>
# include <nvif/cl506f.h>
# include <nvif/cl906f.h>
# include <nvif/cla06f.h>
2015-08-20 07:54:16 +03:00
# include <nvif/ioctl.h>
2014-08-09 22:10:23 +04:00
/*XXX*/
2012-07-20 02:17:34 +04:00
# include <core/client.h>
2016-05-20 02:22:55 +03:00
# include "nouveau_drv.h"
2012-07-20 02:17:34 +04:00
# include "nouveau_dma.h"
# include "nouveau_bo.h"
# include "nouveau_chan.h"
# include "nouveau_fence.h"
# include "nouveau_abi16.h"
MODULE_PARM_DESC ( vram_pushbuf , " Create DMA push buffers in VRAM " ) ;
2014-08-19 00:43:24 +04:00
int nouveau_vram_pushbuf ;
2012-07-20 02:17:34 +04:00
module_param_named ( vram_pushbuf , nouveau_vram_pushbuf , int , 0400 ) ;
2016-11-05 06:31:25 +03:00
static int
nouveau_channel_killed ( struct nvif_notify * ntfy )
{
struct nouveau_channel * chan = container_of ( ntfy , typeof ( * chan ) , kill ) ;
struct nouveau_cli * cli = ( void * ) chan - > user . client ;
NV_PRINTK ( warn , cli , " channel %d killed! \n " , chan - > chid ) ;
atomic_set ( & chan - > killed , 1 ) ;
return NVIF_NOTIFY_DROP ;
}
2012-07-20 02:17:34 +04:00
int
nouveau_channel_idle ( struct nouveau_channel * chan )
{
2017-01-24 09:56:52 +03:00
if ( likely ( chan & & chan - > fence & & ! atomic_read ( & chan - > killed ) ) ) {
2015-08-20 07:54:22 +03:00
struct nouveau_cli * cli = ( void * ) chan - > user . client ;
struct nouveau_fence * fence = NULL ;
int ret ;
2012-07-20 02:17:34 +04:00
2015-08-20 07:54:22 +03:00
ret = nouveau_fence_new ( chan , false , & fence ) ;
if ( ! ret ) {
ret = nouveau_fence_wait ( fence , false , false ) ;
nouveau_fence_unref ( & fence ) ;
}
2012-07-20 02:17:34 +04:00
2015-08-20 07:54:22 +03:00
if ( ret ) {
2015-09-04 07:40:32 +03:00
NV_PRINTK ( err , cli , " failed to idle channel %d [%s] \n " ,
chan - > chid , nvxx_client ( & cli - > base ) - > name ) ;
2015-08-20 07:54:22 +03:00
return ret ;
}
}
return 0 ;
2012-07-20 02:17:34 +04:00
}
void
nouveau_channel_del ( struct nouveau_channel * * pchan )
{
struct nouveau_channel * chan = * pchan ;
if ( chan ) {
2015-08-20 07:54:22 +03:00
if ( chan - > fence )
2012-07-20 02:17:34 +04:00
nouveau_fence ( chan - > drm ) - > context_del ( chan ) ;
2014-08-09 22:10:22 +04:00
nvif_object_fini ( & chan - > nvsw ) ;
nvif_object_fini ( & chan - > gart ) ;
nvif_object_fini ( & chan - > vram ) ;
2016-11-05 06:31:25 +03:00
nvif_notify_fini ( & chan - > kill ) ;
2015-08-20 07:54:15 +03:00
nvif_object_fini ( & chan - > user ) ;
2014-08-09 22:10:22 +04:00
nvif_object_fini ( & chan - > push . ctxdma ) ;
2012-07-20 02:17:34 +04:00
nouveau_bo_vma_del ( chan - > push . buffer , & chan - > push . vma ) ;
nouveau_bo_unmap ( chan - > push . buffer ) ;
2012-11-26 02:02:28 +04:00
if ( chan - > push . buffer & & chan - > push . buffer - > pin_refcnt )
nouveau_bo_unpin ( chan - > push . buffer ) ;
2012-07-20 02:17:34 +04:00
nouveau_bo_ref ( NULL , & chan - > push . buffer ) ;
kfree ( chan ) ;
}
* pchan = NULL ;
}
static int
2014-08-09 22:10:22 +04:00
nouveau_channel_prep ( struct nouveau_drm * drm , struct nvif_device * device ,
2015-09-04 07:40:32 +03:00
u32 size , struct nouveau_channel * * pchan )
2012-07-20 02:17:34 +04:00
{
2015-08-20 07:54:15 +03:00
struct nouveau_cli * cli = ( void * ) device - > object . client ;
2015-01-14 08:36:34 +03:00
struct nvkm_mmu * mmu = nvxx_mmu ( device ) ;
2014-08-09 22:10:24 +04:00
struct nv_dma_v0 args = { } ;
2012-07-20 02:17:34 +04:00
struct nouveau_channel * chan ;
u32 target ;
int ret ;
chan = * pchan = kzalloc ( sizeof ( * chan ) , GFP_KERNEL ) ;
if ( ! chan )
return - ENOMEM ;
2015-08-20 07:54:15 +03:00
chan - > device = device ;
2012-07-20 02:17:34 +04:00
chan - > drm = drm ;
2016-11-05 06:31:25 +03:00
atomic_set ( & chan - > killed , 0 ) ;
2012-07-20 02:17:34 +04:00
/* allocate memory for dma push buffer */
2014-10-27 12:49:18 +03:00
target = TTM_PL_FLAG_TT | TTM_PL_FLAG_UNCACHED ;
2012-07-20 02:17:34 +04:00
if ( nouveau_vram_pushbuf )
target = TTM_PL_FLAG_VRAM ;
2016-05-24 10:26:48 +03:00
ret = nouveau_bo_new ( cli , size , 0 , target , 0 , 0 , NULL , NULL ,
2012-07-20 02:17:34 +04:00
& chan - > push . buffer ) ;
if ( ret = = 0 ) {
2014-11-10 04:24:27 +03:00
ret = nouveau_bo_pin ( chan - > push . buffer , target , false ) ;
2012-07-20 02:17:34 +04:00
if ( ret = = 0 )
ret = nouveau_bo_map ( chan - > push . buffer ) ;
}
if ( ret ) {
nouveau_channel_del ( pchan ) ;
return ret ;
}
/* create dma object covering the *entire* memory space that the
* pushbuf lives in , this is because the GEM code requires that
* we be able to call out to other ( indirect ) push buffers
*/
chan - > push . vma . offset = chan - > push . buffer - > bo . offset ;
2014-08-09 22:10:22 +04:00
if ( device - > info . family > = NV_DEVICE_INFO_V0_TESLA ) {
2014-08-09 22:10:22 +04:00
ret = nouveau_bo_vma_add ( chan - > push . buffer , cli - > vm ,
2012-07-20 02:17:34 +04:00
& chan - > push . vma ) ;
if ( ret ) {
nouveau_channel_del ( pchan ) ;
return ret ;
}
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_VM ;
args . access = NV_DMA_V0_ACCESS_VM ;
2012-07-20 02:17:34 +04:00
args . start = 0 ;
2015-01-14 02:57:36 +03:00
args . limit = cli - > vm - > mmu - > limit - 1 ;
2012-07-20 02:17:34 +04:00
} else
if ( chan - > push . buffer - > bo . mem . mem_type = = TTM_PL_VRAM ) {
2014-08-09 22:10:22 +04:00
if ( device - > info . family = = NV_DEVICE_INFO_V0_TNT ) {
2012-07-20 02:17:34 +04:00
/* nv04 vram pushbuf hack, retarget to its location in
* the framebuffer bar rather than direct vram access . .
* nfi why this exists , it came from the - nv ddx .
*/
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_PCI ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
2015-08-20 07:54:23 +03:00
args . start = nvxx_device ( device ) - > func - >
resource_addr ( nvxx_device ( device ) , 1 ) ;
2014-08-09 22:10:28 +04:00
args . limit = args . start + device - > info . ram_user - 1 ;
2012-07-20 02:17:34 +04:00
} else {
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_VRAM ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
2012-07-20 02:17:34 +04:00
args . start = 0 ;
2014-08-09 22:10:28 +04:00
args . limit = device - > info . ram_user - 1 ;
2012-07-20 02:17:34 +04:00
}
} else {
2015-08-20 07:54:23 +03:00
if ( chan - > drm - > agp . bridge ) {
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_AGP ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
2012-07-20 02:17:34 +04:00
args . start = chan - > drm - > agp . base ;
args . limit = chan - > drm - > agp . base +
chan - > drm - > agp . size - 1 ;
} else {
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_VM ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
2012-07-20 02:17:34 +04:00
args . start = 0 ;
2015-01-14 02:57:36 +03:00
args . limit = mmu - > limit - 1 ;
2012-07-20 02:17:34 +04:00
}
}
2015-09-04 07:40:32 +03:00
ret = nvif_object_init ( & device - > object , 0 , NV_DMA_FROM_MEMORY ,
2014-08-09 22:10:22 +04:00
& args , sizeof ( args ) , & chan - > push . ctxdma ) ;
2012-07-20 02:17:34 +04:00
if ( ret ) {
nouveau_channel_del ( pchan ) ;
return ret ;
}
return 0 ;
}
2012-08-20 01:00:00 +04:00
static int
2014-08-09 22:10:22 +04:00
nouveau_channel_ind ( struct nouveau_drm * drm , struct nvif_device * device ,
2015-09-04 07:40:32 +03:00
u32 engine , struct nouveau_channel * * pchan )
2012-07-20 02:17:34 +04:00
{
2016-07-09 03:41:01 +03:00
static const u16 oclasses [ ] = { PASCAL_CHANNEL_GPFIFO_A ,
MAXWELL_CHANNEL_GPFIFO_A ,
2016-03-11 06:09:28 +03:00
KEPLER_CHANNEL_GPFIFO_B ,
2015-04-14 04:47:24 +03:00
KEPLER_CHANNEL_GPFIFO_A ,
2014-08-09 22:10:25 +04:00
FERMI_CHANNEL_GPFIFO ,
G82_CHANNEL_GPFIFO ,
NV50_CHANNEL_GPFIFO ,
2012-08-19 10:03:00 +04:00
0 } ;
2012-07-20 02:17:34 +04:00
const u16 * oclass = oclasses ;
2014-08-09 22:10:25 +04:00
union {
struct nv50_channel_gpfifo_v0 nv50 ;
2015-08-20 07:54:16 +03:00
struct fermi_channel_gpfifo_v0 fermi ;
2014-08-09 22:10:25 +04:00
struct kepler_channel_gpfifo_a_v0 kepler ;
2015-08-20 07:54:15 +03:00
} args ;
2012-07-20 02:17:34 +04:00
struct nouveau_channel * chan ;
2014-08-09 22:10:25 +04:00
u32 size ;
2012-07-20 02:17:34 +04:00
int ret ;
/* allocate dma push buffer */
2015-09-04 07:40:32 +03:00
ret = nouveau_channel_prep ( drm , device , 0x12000 , & chan ) ;
2012-07-20 02:17:34 +04:00
* pchan = chan ;
if ( ret )
return ret ;
/* create channel object */
do {
2014-08-09 22:10:25 +04:00
if ( oclass [ 0 ] > = KEPLER_CHANNEL_GPFIFO_A ) {
args . kepler . version = 0 ;
2016-03-11 06:09:28 +03:00
args . kepler . engines = engine ;
2014-08-09 22:10:25 +04:00
args . kepler . ilength = 0x02000 ;
args . kepler . ioffset = 0x10000 + chan - > push . vma . offset ;
2015-08-20 07:54:16 +03:00
args . kepler . vm = 0 ;
2014-08-09 22:10:25 +04:00
size = sizeof ( args . kepler ) ;
2015-08-20 07:54:16 +03:00
} else
if ( oclass [ 0 ] > = FERMI_CHANNEL_GPFIFO ) {
args . fermi . version = 0 ;
args . fermi . ilength = 0x02000 ;
args . fermi . ioffset = 0x10000 + chan - > push . vma . offset ;
args . fermi . vm = 0 ;
size = sizeof ( args . fermi ) ;
2014-08-09 22:10:25 +04:00
} else {
args . nv50 . version = 0 ;
args . nv50 . ilength = 0x02000 ;
args . nv50 . ioffset = 0x10000 + chan - > push . vma . offset ;
2015-08-20 07:54:16 +03:00
args . nv50 . pushbuf = nvif_handle ( & chan - > push . ctxdma ) ;
args . nv50 . vm = 0 ;
2014-08-09 22:10:25 +04:00
size = sizeof ( args . nv50 ) ;
}
2015-09-04 07:40:32 +03:00
ret = nvif_object_init ( & device - > object , 0 , * oclass + + ,
2015-08-20 07:54:15 +03:00
& args , size , & chan - > user ) ;
2014-08-09 22:10:25 +04:00
if ( ret = = 0 ) {
2015-08-20 07:54:15 +03:00
if ( chan - > user . oclass > = KEPLER_CHANNEL_GPFIFO_A )
chan - > chid = args . kepler . chid ;
2015-08-20 07:54:16 +03:00
else
if ( chan - > user . oclass > = FERMI_CHANNEL_GPFIFO )
chan - > chid = args . fermi . chid ;
2014-08-09 22:10:25 +04:00
else
2015-08-20 07:54:15 +03:00
chan - > chid = args . nv50 . chid ;
2012-07-20 02:17:34 +04:00
return ret ;
2014-08-09 22:10:25 +04:00
}
2012-07-20 02:17:34 +04:00
} while ( * oclass ) ;
nouveau_channel_del ( pchan ) ;
return ret ;
}
static int
2014-08-09 22:10:22 +04:00
nouveau_channel_dma ( struct nouveau_drm * drm , struct nvif_device * device ,
2015-09-04 07:40:32 +03:00
struct nouveau_channel * * pchan )
2012-07-20 02:17:34 +04:00
{
2014-08-09 22:10:25 +04:00
static const u16 oclasses [ ] = { NV40_CHANNEL_DMA ,
NV17_CHANNEL_DMA ,
NV10_CHANNEL_DMA ,
NV03_CHANNEL_DMA ,
2012-08-19 10:03:00 +04:00
0 } ;
2012-07-20 02:17:34 +04:00
const u16 * oclass = oclasses ;
2015-08-20 07:54:15 +03:00
struct nv03_channel_dma_v0 args ;
2012-07-20 02:17:34 +04:00
struct nouveau_channel * chan ;
int ret ;
/* allocate dma push buffer */
2015-09-04 07:40:32 +03:00
ret = nouveau_channel_prep ( drm , device , 0x10000 , & chan ) ;
2012-07-20 02:17:34 +04:00
* pchan = chan ;
if ( ret )
return ret ;
/* create channel object */
2014-08-09 22:10:25 +04:00
args . version = 0 ;
2015-08-20 07:54:16 +03:00
args . pushbuf = nvif_handle ( & chan - > push . ctxdma ) ;
2012-07-20 02:17:34 +04:00
args . offset = chan - > push . vma . offset ;
do {
2015-09-04 07:40:32 +03:00
ret = nvif_object_init ( & device - > object , 0 , * oclass + + ,
2015-08-20 07:54:15 +03:00
& args , sizeof ( args ) , & chan - > user ) ;
2014-08-09 22:10:25 +04:00
if ( ret = = 0 ) {
2015-08-20 07:54:15 +03:00
chan - > chid = args . chid ;
2012-07-20 02:17:34 +04:00
return ret ;
2014-08-09 22:10:25 +04:00
}
2012-07-20 02:17:34 +04:00
} while ( ret & & * oclass ) ;
nouveau_channel_del ( pchan ) ;
return ret ;
}
static int
nouveau_channel_init ( struct nouveau_channel * chan , u32 vram , u32 gart )
{
2014-08-09 22:10:22 +04:00
struct nvif_device * device = chan - > device ;
2015-08-20 07:54:15 +03:00
struct nouveau_cli * cli = ( void * ) chan - > user . client ;
2016-11-05 06:31:25 +03:00
struct nouveau_drm * drm = chan - > drm ;
2015-01-14 08:36:34 +03:00
struct nvkm_mmu * mmu = nvxx_mmu ( device ) ;
2014-08-09 22:10:24 +04:00
struct nv_dma_v0 args = { } ;
2012-07-20 02:17:34 +04:00
int ret , i ;
2015-08-20 07:54:15 +03:00
nvif_object_map ( & chan - > user ) ;
2014-08-09 22:10:25 +04:00
2016-11-05 06:31:25 +03:00
if ( chan - > user . oclass > = FERMI_CHANNEL_GPFIFO ) {
ret = nvif_notify_init ( & chan - > user , nouveau_channel_killed ,
true , NV906F_V0_NTFY_KILLED ,
NULL , 0 , 0 , & chan - > kill ) ;
if ( ret = = 0 )
ret = nvif_notify_get ( & chan - > kill ) ;
if ( ret ) {
NV_ERROR ( drm , " Failed to request channel kill "
" notification: %d \n " , ret ) ;
return ret ;
}
}
2012-07-20 02:17:34 +04:00
/* allocate dma objects to cover all allowed vram, and gart */
2014-08-09 22:10:22 +04:00
if ( device - > info . family < NV_DEVICE_INFO_V0_FERMI ) {
if ( device - > info . family > = NV_DEVICE_INFO_V0_TESLA ) {
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_VM ;
args . access = NV_DMA_V0_ACCESS_VM ;
2012-07-20 02:17:34 +04:00
args . start = 0 ;
2015-01-14 02:57:36 +03:00
args . limit = cli - > vm - > mmu - > limit - 1 ;
2012-07-20 02:17:34 +04:00
} else {
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_VRAM ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
2012-07-20 02:17:34 +04:00
args . start = 0 ;
2014-08-09 22:10:28 +04:00
args . limit = device - > info . ram_user - 1 ;
2012-07-20 02:17:34 +04:00
}
2015-08-20 07:54:15 +03:00
ret = nvif_object_init ( & chan - > user , vram , NV_DMA_IN_MEMORY ,
& args , sizeof ( args ) , & chan - > vram ) ;
2012-07-20 02:17:34 +04:00
if ( ret )
return ret ;
2014-08-09 22:10:22 +04:00
if ( device - > info . family > = NV_DEVICE_INFO_V0_TESLA ) {
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_VM ;
args . access = NV_DMA_V0_ACCESS_VM ;
2012-07-20 02:17:34 +04:00
args . start = 0 ;
2015-01-14 02:57:36 +03:00
args . limit = cli - > vm - > mmu - > limit - 1 ;
2012-07-20 02:17:34 +04:00
} else
2015-08-20 07:54:23 +03:00
if ( chan - > drm - > agp . bridge ) {
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_AGP ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
2012-07-20 02:17:34 +04:00
args . start = chan - > drm - > agp . base ;
args . limit = chan - > drm - > agp . base +
chan - > drm - > agp . size - 1 ;
} else {
2014-08-09 22:10:24 +04:00
args . target = NV_DMA_V0_TARGET_VM ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
2012-07-20 02:17:34 +04:00
args . start = 0 ;
2015-01-14 02:57:36 +03:00
args . limit = mmu - > limit - 1 ;
2012-07-20 02:17:34 +04:00
}
2015-08-20 07:54:15 +03:00
ret = nvif_object_init ( & chan - > user , gart , NV_DMA_IN_MEMORY ,
& args , sizeof ( args ) , & chan - > gart ) ;
2012-07-20 02:17:34 +04:00
if ( ret )
return ret ;
}
/* initialise dma tracking parameters */
2015-08-20 07:54:15 +03:00
switch ( chan - > user . oclass & 0x00ff ) {
2012-08-14 08:53:51 +04:00
case 0x006b :
2012-07-20 02:17:34 +04:00
case 0x006e :
chan - > user_put = 0x40 ;
chan - > user_get = 0x44 ;
chan - > dma . max = ( 0x10000 / 4 ) - 2 ;
break ;
default :
chan - > user_put = 0x40 ;
chan - > user_get = 0x44 ;
chan - > user_get_hi = 0x60 ;
chan - > dma . ib_base = 0x10000 / 4 ;
chan - > dma . ib_max = ( 0x02000 / 8 ) - 1 ;
chan - > dma . ib_put = 0 ;
chan - > dma . ib_free = chan - > dma . ib_max - chan - > dma . ib_put ;
chan - > dma . max = chan - > dma . ib_base ;
break ;
}
chan - > dma . put = 0 ;
chan - > dma . cur = chan - > dma . put ;
chan - > dma . free = chan - > dma . max - chan - > dma . cur ;
ret = RING_SPACE ( chan , NOUVEAU_DMA_SKIPS ) ;
if ( ret )
return ret ;
for ( i = 0 ; i < NOUVEAU_DMA_SKIPS ; i + + )
OUT_RING ( chan , 0x00000000 ) ;
2013-11-13 04:58:51 +04:00
/* allocate software object class (used for fences on <= nv05) */
2014-08-09 22:10:22 +04:00
if ( device - > info . family < NV_DEVICE_INFO_V0_CELSIUS ) {
2015-08-20 07:54:16 +03:00
ret = nvif_object_init ( & chan - > user , 0x006e ,
2015-11-08 03:18:19 +03:00
NVIF_CLASS_SW_NV04 ,
2014-08-09 22:10:22 +04:00
NULL , 0 , & chan - > nvsw ) ;
2012-08-06 13:38:25 +04:00
if ( ret )
return ret ;
2012-07-20 02:17:34 +04:00
ret = RING_SPACE ( chan , 2 ) ;
if ( ret )
return ret ;
BEGIN_NV04 ( chan , NvSubSw , 0x0000 , 1 ) ;
2014-08-09 22:10:23 +04:00
OUT_RING ( chan , chan - > nvsw . handle ) ;
2012-07-20 02:17:34 +04:00
FIRE_RING ( chan ) ;
}
/* initialise synchronisation */
2014-10-20 09:49:33 +04:00
return nouveau_fence ( chan - > drm ) - > context_new ( chan ) ;
2012-07-20 02:17:34 +04:00
}
int
2014-08-09 22:10:22 +04:00
nouveau_channel_new ( struct nouveau_drm * drm , struct nvif_device * device ,
2015-09-04 07:40:32 +03:00
u32 arg0 , u32 arg1 , struct nouveau_channel * * pchan )
2012-07-20 02:17:34 +04:00
{
2015-08-20 07:54:15 +03:00
struct nouveau_cli * cli = ( void * ) device - > object . client ;
2014-10-20 09:49:33 +04:00
bool super ;
2012-07-20 02:17:34 +04:00
int ret ;
2014-10-20 09:49:33 +04:00
/* hack until fencenv50 is fixed, and agp access relaxed */
super = cli - > base . super ;
cli - > base . super = true ;
2015-09-04 07:40:32 +03:00
ret = nouveau_channel_ind ( drm , device , arg0 , pchan ) ;
2012-07-20 02:17:34 +04:00
if ( ret ) {
2015-08-20 07:54:13 +03:00
NV_PRINTK ( dbg , cli , " ib channel create, %d \n " , ret ) ;
2015-09-04 07:40:32 +03:00
ret = nouveau_channel_dma ( drm , device , pchan ) ;
2012-07-20 02:17:34 +04:00
if ( ret ) {
2015-08-20 07:54:13 +03:00
NV_PRINTK ( dbg , cli , " dma channel create, %d \n " , ret ) ;
2014-10-20 09:49:33 +04:00
goto done ;
2012-07-20 02:17:34 +04:00
}
}
2012-08-06 13:38:25 +04:00
ret = nouveau_channel_init ( * pchan , arg0 , arg1 ) ;
2012-07-20 02:17:34 +04:00
if ( ret ) {
2015-08-20 07:54:13 +03:00
NV_PRINTK ( err , cli , " channel failed to initialise, %d \n " , ret ) ;
2012-07-20 02:17:34 +04:00
nouveau_channel_del ( pchan ) ;
}
2014-10-20 09:49:33 +04:00
done :
cli - > base . super = super ;
return ret ;
2012-07-20 02:17:34 +04:00
}