2012-05-08 04:24:27 +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 .
*
*/
2014-08-09 22:10:23 +04:00
# include <nvif/client.h>
# include <nvif/driver.h>
# include <nvif/ioctl.h>
2014-08-09 22:10:23 +04:00
# include <nvif/class.h>
2015-11-08 04:28:26 +03:00
# include <nvif/cla06f.h>
2015-11-03 04:21:43 +03:00
# include <nvif/unpack.h>
2012-05-08 04:24:27 +04:00
2012-07-20 02:17:34 +04:00
# include "nouveau_drm.h"
2012-05-08 04:24:27 +04:00
# include "nouveau_dma.h"
2012-07-20 02:17:34 +04:00
# include "nouveau_gem.h"
# include "nouveau_chan.h"
2012-05-08 04:24:27 +04:00
# include "nouveau_abi16.h"
2012-07-20 02:17:34 +04:00
2015-11-03 03:55:45 +03:00
static struct nouveau_abi16 *
nouveau_abi16 ( struct drm_file * file_priv )
2012-07-20 02:17:34 +04:00
{
struct nouveau_cli * cli = nouveau_cli ( file_priv ) ;
if ( ! cli - > abi16 ) {
struct nouveau_abi16 * abi16 ;
cli - > abi16 = abi16 = kzalloc ( sizeof ( * abi16 ) , GFP_KERNEL ) ;
if ( cli - > abi16 ) {
2014-08-09 22:10:24 +04:00
struct nv_device_v0 args = {
. device = ~ 0ULL ,
} ;
2012-07-20 02:17:34 +04:00
INIT_LIST_HEAD ( & abi16 - > channels ) ;
/* allocate device object targeting client's default
* device ( ie . the one that belongs to the fd it
* opened )
*/
2015-09-04 07:40:32 +03:00
if ( nvif_device_init ( & cli - > base . object , 0 , NV_DEVICE ,
2014-08-09 22:10:24 +04:00
& args , sizeof ( args ) ,
2014-08-09 22:10:22 +04:00
& abi16 - > device ) = = 0 )
2012-07-20 02:17:34 +04:00
return cli - > abi16 ;
kfree ( cli - > abi16 ) ;
cli - > abi16 = NULL ;
}
}
return cli - > abi16 ;
}
2015-11-03 03:55:45 +03:00
struct nouveau_abi16 *
nouveau_abi16_get ( struct drm_file * file_priv )
{
struct nouveau_cli * cli = nouveau_cli ( file_priv ) ;
mutex_lock ( & cli - > mutex ) ;
if ( nouveau_abi16 ( file_priv ) )
return cli - > abi16 ;
mutex_unlock ( & cli - > mutex ) ;
return NULL ;
}
2012-07-20 02:17:34 +04:00
int
nouveau_abi16_put ( struct nouveau_abi16 * abi16 , int ret )
{
2015-08-20 07:54:15 +03:00
struct nouveau_cli * cli = ( void * ) abi16 - > device . object . client ;
2012-07-20 02:17:34 +04:00
mutex_unlock ( & cli - > mutex ) ;
return ret ;
}
2015-08-20 07:54:16 +03:00
s32
2012-07-20 02:17:34 +04:00
nouveau_abi16_swclass ( struct nouveau_drm * drm )
{
2014-08-09 22:10:22 +04:00
switch ( drm - > device . info . family ) {
case NV_DEVICE_INFO_V0_TNT :
2015-11-08 03:18:19 +03:00
return NVIF_CLASS_SW_NV04 ;
2014-08-09 22:10:22 +04:00
case NV_DEVICE_INFO_V0_CELSIUS :
case NV_DEVICE_INFO_V0_KELVIN :
case NV_DEVICE_INFO_V0_RANKINE :
case NV_DEVICE_INFO_V0_CURIE :
2015-11-08 03:18:19 +03:00
return NVIF_CLASS_SW_NV10 ;
2014-08-09 22:10:22 +04:00
case NV_DEVICE_INFO_V0_TESLA :
2015-11-08 03:18:19 +03:00
return NVIF_CLASS_SW_NV50 ;
2014-08-09 22:10:22 +04:00
case NV_DEVICE_INFO_V0_FERMI :
case NV_DEVICE_INFO_V0_KEPLER :
case NV_DEVICE_INFO_V0_MAXWELL :
2015-11-08 03:18:19 +03:00
return NVIF_CLASS_SW_GF100 ;
2012-07-20 02:17:34 +04:00
}
return 0x0000 ;
}
static void
nouveau_abi16_ntfy_fini ( struct nouveau_abi16_chan * chan ,
struct nouveau_abi16_ntfy * ntfy )
{
2015-08-20 07:54:15 +03:00
nvif_object_fini ( & ntfy - > object ) ;
2015-01-14 08:36:34 +03:00
nvkm_mm_free ( & chan - > heap , & ntfy - > node ) ;
2012-07-20 02:17:34 +04:00
list_del ( & ntfy - > head ) ;
kfree ( ntfy ) ;
}
static void
nouveau_abi16_chan_fini ( struct nouveau_abi16 * abi16 ,
struct nouveau_abi16_chan * chan )
{
struct nouveau_abi16_ntfy * ntfy , * temp ;
2013-03-03 21:58:45 +04:00
/* wait for all activity to stop before releasing notify object, which
* may be still in use */
if ( chan - > chan & & chan - > ntfy )
nouveau_channel_idle ( chan - > chan ) ;
2012-07-20 02:17:34 +04:00
/* cleanup notifier state */
list_for_each_entry_safe ( ntfy , temp , & chan - > notifiers , head ) {
nouveau_abi16_ntfy_fini ( chan , ntfy ) ;
}
if ( chan - > ntfy ) {
nouveau_bo_vma_del ( chan - > ntfy , & chan - > ntfy_vma ) ;
2013-06-27 15:38:20 +04:00
nouveau_bo_unpin ( chan - > ntfy ) ;
2013-10-02 12:15:17 +04:00
drm_gem_object_unreference_unlocked ( & chan - > ntfy - > gem ) ;
2012-07-20 02:17:34 +04:00
}
if ( chan - > heap . block_size )
2015-01-14 08:36:34 +03:00
nvkm_mm_fini ( & chan - > heap ) ;
2012-07-20 02:17:34 +04:00
/* destroy channel object, all children will be killed too */
if ( chan - > chan ) {
2015-08-20 07:54:22 +03:00
nouveau_channel_idle ( chan - > chan ) ;
2012-07-20 02:17:34 +04:00
nouveau_channel_del ( & chan - > chan ) ;
}
list_del ( & chan - > head ) ;
kfree ( chan ) ;
}
void
nouveau_abi16_fini ( struct nouveau_abi16 * abi16 )
{
2015-08-20 07:54:15 +03:00
struct nouveau_cli * cli = ( void * ) abi16 - > device . object . client ;
2012-07-20 02:17:34 +04:00
struct nouveau_abi16_chan * chan , * temp ;
/* cleanup channels */
list_for_each_entry_safe ( chan , temp , & abi16 - > channels , head ) {
nouveau_abi16_chan_fini ( abi16 , chan ) ;
}
/* destroy the device object */
2014-08-09 22:10:22 +04:00
nvif_device_fini ( & abi16 - > device ) ;
2012-07-20 02:17:34 +04:00
kfree ( cli - > abi16 ) ;
cli - > abi16 = NULL ;
}
2012-05-08 04:24:27 +04:00
int
nouveau_abi16_ioctl_getparam ( ABI16_IOCTL_ARGS )
{
2014-08-09 22:10:22 +04:00
struct nouveau_cli * cli = nouveau_cli ( file_priv ) ;
2012-07-20 02:17:34 +04:00
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
2014-08-09 22:10:22 +04:00
struct nvif_device * device = & drm - > device ;
2015-01-14 08:36:34 +03:00
struct nvkm_gr * gr = nvxx_gr ( device ) ;
2012-05-08 04:24:27 +04:00
struct drm_nouveau_getparam * getparam = data ;
switch ( getparam - > param ) {
case NOUVEAU_GETPARAM_CHIPSET_ID :
2014-08-09 22:10:22 +04:00
getparam - > value = device - > info . chipset ;
2012-05-08 04:24:27 +04:00
break ;
case NOUVEAU_GETPARAM_PCI_VENDOR :
2015-08-20 07:54:23 +03:00
if ( nvxx_device ( device ) - > func - > pci )
2014-02-17 10:17:26 +04:00
getparam - > value = dev - > pdev - > vendor ;
else
getparam - > value = 0 ;
2012-05-08 04:24:27 +04:00
break ;
case NOUVEAU_GETPARAM_PCI_DEVICE :
2015-08-20 07:54:23 +03:00
if ( nvxx_device ( device ) - > func - > pci )
2014-02-17 10:17:26 +04:00
getparam - > value = dev - > pdev - > device ;
else
getparam - > value = 0 ;
2012-05-08 04:24:27 +04:00
break ;
case NOUVEAU_GETPARAM_BUS_TYPE :
2015-08-20 07:54:23 +03:00
if ( ! nvxx_device ( device ) - > func - > pci )
2014-02-17 10:17:26 +04:00
getparam - > value = 3 ;
else
2012-05-08 04:24:27 +04:00
if ( drm_pci_device_is_agp ( dev ) )
getparam - > value = 0 ;
else
if ( ! pci_is_pcie ( dev - > pdev ) )
getparam - > value = 1 ;
else
getparam - > value = 2 ;
break ;
case NOUVEAU_GETPARAM_FB_SIZE :
2012-07-20 02:17:34 +04:00
getparam - > value = drm - > gem . vram_available ;
2012-05-08 04:24:27 +04:00
break ;
case NOUVEAU_GETPARAM_AGP_SIZE :
2012-07-20 02:17:34 +04:00
getparam - > value = drm - > gem . gart_available ;
2012-05-08 04:24:27 +04:00
break ;
case NOUVEAU_GETPARAM_VM_VRAM_BASE :
getparam - > value = 0 ; /* deprecated */
break ;
case NOUVEAU_GETPARAM_PTIMER_TIME :
2015-08-20 07:54:10 +03:00
getparam - > value = nvif_device_time ( device ) ;
2012-05-08 04:24:27 +04:00
break ;
case NOUVEAU_GETPARAM_HAS_BO_USAGE :
getparam - > value = 1 ;
break ;
case NOUVEAU_GETPARAM_HAS_PAGEFLIP :
getparam - > value = 1 ;
break ;
case NOUVEAU_GETPARAM_GRAPH_UNITS :
2015-08-20 07:54:22 +03:00
getparam - > value = nvkm_gr_units ( gr ) ;
2013-03-28 01:16:54 +04:00
break ;
2012-05-08 04:24:27 +04:00
default :
2015-08-20 07:54:13 +03:00
NV_PRINTK ( dbg , cli , " unknown parameter %lld \n " , getparam - > param ) ;
2012-05-08 04:24:27 +04:00
return - EINVAL ;
}
return 0 ;
}
int
nouveau_abi16_ioctl_setparam ( ABI16_IOCTL_ARGS )
{
return - EINVAL ;
}
int
nouveau_abi16_ioctl_channel_alloc ( ABI16_IOCTL_ARGS )
{
struct drm_nouveau_channel_alloc * init = data ;
2012-07-20 02:17:34 +04:00
struct nouveau_cli * cli = nouveau_cli ( file_priv ) ;
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
2015-11-03 03:17:49 +03:00
struct nouveau_abi16 * abi16 = nouveau_abi16_get ( file_priv ) ;
2012-07-20 02:17:34 +04:00
struct nouveau_abi16_chan * chan ;
2014-08-09 22:10:22 +04:00
struct nvif_device * device ;
2012-05-08 04:24:27 +04:00
int ret ;
2012-07-20 02:17:34 +04:00
if ( unlikely ( ! abi16 ) )
return - ENOMEM ;
2012-11-11 23:00:09 +04:00
if ( ! drm - > channel )
return nouveau_abi16_put ( abi16 , - ENODEV ) ;
2014-08-09 22:10:22 +04:00
device = & abi16 - > device ;
2012-07-20 02:17:34 +04:00
2012-11-22 07:43:55 +04:00
/* hack to allow channel engine type specification on kepler */
2014-08-09 22:10:22 +04:00
if ( device - > info . family > = NV_DEVICE_INFO_V0_KEPLER ) {
2012-11-22 07:43:55 +04:00
if ( init - > fb_ctxdma_handle ! = ~ 0 )
2014-08-09 22:10:25 +04:00
init - > fb_ctxdma_handle = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR ;
2012-11-22 07:43:55 +04:00
else
init - > fb_ctxdma_handle = init - > tt_ctxdma_handle ;
/* allow flips to be executed if this is a graphics channel */
init - > tt_ctxdma_handle = 0 ;
2014-08-09 22:10:25 +04:00
if ( init - > fb_ctxdma_handle = = KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR )
2012-11-22 07:43:55 +04:00
init - > tt_ctxdma_handle = 1 ;
}
if ( init - > fb_ctxdma_handle = = ~ 0 | | init - > tt_ctxdma_handle = = ~ 0 )
return nouveau_abi16_put ( abi16 , - EINVAL ) ;
2012-07-20 02:17:34 +04:00
/* allocate "abi16 channel" data and make up a handle for it */
chan = kzalloc ( sizeof ( * chan ) , GFP_KERNEL ) ;
if ( ! chan )
return nouveau_abi16_put ( abi16 , - ENOMEM ) ;
INIT_LIST_HEAD ( & chan - > notifiers ) ;
list_add ( & chan - > head , & abi16 - > channels ) ;
2012-05-08 04:24:27 +04:00
2012-07-20 02:17:34 +04:00
/* create channel object and initialise dma and fence management */
2015-09-04 07:40:32 +03:00
ret = nouveau_channel_new ( drm , device , init - > fb_ctxdma_handle ,
2012-07-20 02:17:34 +04:00
init - > tt_ctxdma_handle , & chan - > chan ) ;
2012-05-08 04:24:27 +04:00
if ( ret )
2012-07-20 02:17:34 +04:00
goto done ;
2015-09-04 07:40:32 +03:00
init - > channel = chan - > chan - > chid ;
2014-08-09 22:10:22 +04:00
if ( device - > info . family > = NV_DEVICE_INFO_V0_TESLA )
2012-07-20 02:17:34 +04:00
init - > pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM |
NOUVEAU_GEM_DOMAIN_GART ;
else
if ( chan - > chan - > push . buffer - > bo . mem . mem_type = = TTM_PL_VRAM )
2012-05-08 04:24:27 +04:00
init - > pushbuf_domains = NOUVEAU_GEM_DOMAIN_VRAM ;
2012-07-20 02:17:34 +04:00
else
init - > pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART ;
2012-05-08 04:24:27 +04:00
2014-08-09 22:10:22 +04:00
if ( device - > info . family < NV_DEVICE_INFO_V0_CELSIUS ) {
2012-05-08 04:24:27 +04:00
init - > subchan [ 0 ] . handle = 0x00000000 ;
init - > subchan [ 0 ] . grclass = 0x0000 ;
2014-08-09 22:10:23 +04:00
init - > subchan [ 1 ] . handle = chan - > chan - > nvsw . handle ;
2012-07-20 02:17:34 +04:00
init - > subchan [ 1 ] . grclass = 0x506e ;
2012-05-08 04:24:27 +04:00
init - > nr_subchan = 2 ;
}
/* Named memory object area */
2012-07-20 02:17:34 +04:00
ret = nouveau_gem_new ( dev , PAGE_SIZE , 0 , NOUVEAU_GEM_DOMAIN_GART ,
0 , 0 , & chan - > ntfy ) ;
if ( ret = = 0 )
2014-11-10 04:24:27 +03:00
ret = nouveau_bo_pin ( chan - > ntfy , TTM_PL_FLAG_TT , false ) ;
2012-07-20 02:17:34 +04:00
if ( ret )
goto done ;
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 - > ntfy , cli - > vm ,
2012-07-20 02:17:34 +04:00
& chan - > ntfy_vma ) ;
if ( ret )
goto done ;
}
2013-10-02 12:15:17 +04:00
ret = drm_gem_handle_create ( file_priv , & chan - > ntfy - > gem ,
2012-05-08 04:24:27 +04:00
& init - > notifier_handle ) ;
2012-07-20 02:17:34 +04:00
if ( ret )
goto done ;
2012-05-08 04:24:27 +04:00
2015-01-14 08:36:34 +03:00
ret = nvkm_mm_init ( & chan - > heap , 0 , PAGE_SIZE , 1 ) ;
2012-07-20 02:17:34 +04:00
done :
if ( ret )
nouveau_abi16_chan_fini ( abi16 , chan ) ;
return nouveau_abi16_put ( abi16 , ret ) ;
2012-05-08 04:24:27 +04:00
}
2014-08-09 22:10:23 +04:00
static struct nouveau_abi16_chan *
nouveau_abi16_chan ( struct nouveau_abi16 * abi16 , int channel )
{
struct nouveau_abi16_chan * chan ;
list_for_each_entry ( chan , & abi16 - > channels , head ) {
2015-09-04 07:40:32 +03:00
if ( chan - > chan - > chid = = channel )
2014-08-09 22:10:23 +04:00
return chan ;
}
return NULL ;
}
2012-07-20 02:17:34 +04:00
2015-11-03 04:21:43 +03:00
int
nouveau_abi16_usif ( struct drm_file * file_priv , void * data , u32 size )
{
union {
struct nvif_ioctl_v0 v0 ;
} * args = data ;
struct nouveau_abi16_chan * chan ;
struct nouveau_abi16 * abi16 ;
int ret ;
if ( nvif_unpack ( args - > v0 , 0 , 0 , true ) ) {
switch ( args - > v0 . type ) {
case NVIF_IOCTL_V0_NEW :
case NVIF_IOCTL_V0_MTHD :
case NVIF_IOCTL_V0_SCLASS :
break ;
default :
return - EACCES ;
}
} else
return ret ;
if ( ! ( abi16 = nouveau_abi16 ( file_priv ) ) )
return - ENOMEM ;
if ( args - > v0 . token ! = ~ 0ULL ) {
if ( ! ( chan = nouveau_abi16_chan ( abi16 , args - > v0 . token ) ) )
return - EINVAL ;
args - > v0 . object = nvif_handle ( & chan - > chan - > user ) ;
args - > v0 . owner = NVIF_IOCTL_V0_OWNER_ANY ;
return 0 ;
}
args - > v0 . object = nvif_handle ( & abi16 - > device . object ) ;
args - > v0 . owner = NVIF_IOCTL_V0_OWNER_ANY ;
return 0 ;
}
2012-05-08 04:24:27 +04:00
int
nouveau_abi16_ioctl_channel_free ( ABI16_IOCTL_ARGS )
{
struct drm_nouveau_channel_free * req = data ;
2015-11-03 03:17:49 +03:00
struct nouveau_abi16 * abi16 = nouveau_abi16_get ( file_priv ) ;
2012-07-20 02:17:34 +04:00
struct nouveau_abi16_chan * chan ;
2012-05-08 04:24:27 +04:00
2012-07-20 02:17:34 +04:00
if ( unlikely ( ! abi16 ) )
return - ENOMEM ;
2012-05-08 04:24:27 +04:00
2014-08-09 22:10:23 +04:00
chan = nouveau_abi16_chan ( abi16 , req - > channel ) ;
if ( ! chan )
return nouveau_abi16_put ( abi16 , - ENOENT ) ;
nouveau_abi16_chan_fini ( abi16 , chan ) ;
return nouveau_abi16_put ( abi16 , 0 ) ;
2012-05-08 04:24:27 +04:00
}
int
nouveau_abi16_ioctl_grobj_alloc ( ABI16_IOCTL_ARGS )
{
struct drm_nouveau_grobj_alloc * init = data ;
2015-11-03 03:17:49 +03:00
struct nouveau_abi16 * abi16 = nouveau_abi16_get ( file_priv ) ;
2015-08-20 07:54:15 +03:00
struct nouveau_abi16_chan * chan ;
struct nouveau_abi16_ntfy * ntfy ;
2014-08-09 22:10:23 +04:00
struct nvif_client * client ;
2015-08-20 07:54:16 +03:00
struct nvif_sclass * sclass ;
2015-08-20 07:54:16 +03:00
s32 oclass = 0 ;
int ret , i ;
2012-05-08 04:24:27 +04:00
2012-07-20 02:17:34 +04:00
if ( unlikely ( ! abi16 ) )
return - ENOMEM ;
2012-05-08 04:24:27 +04:00
if ( init - > handle = = ~ 0 )
2012-07-20 02:17:34 +04:00
return nouveau_abi16_put ( abi16 , - EINVAL ) ;
2015-08-20 07:54:15 +03:00
client = abi16 - > device . object . client ;
2012-05-08 04:24:27 +04:00
2015-08-20 07:54:15 +03:00
chan = nouveau_abi16_chan ( abi16 , init - > channel ) ;
if ( ! chan )
return nouveau_abi16_put ( abi16 , - ENOENT ) ;
2015-08-20 07:54:16 +03:00
ret = nvif_object_sclass_get ( & chan - > chan - > user , & sclass ) ;
2015-08-20 07:54:16 +03:00
if ( ret < 0 )
return nouveau_abi16_put ( abi16 , ret ) ;
if ( ( init - > class & 0x00ff ) = = 0x006e ) {
/* nvsw: compatibility with older 0x*6e class identifier */
for ( i = 0 ; ! oclass & & i < ret ; i + + ) {
2015-08-20 07:54:16 +03:00
switch ( sclass [ i ] . oclass ) {
2015-11-08 03:18:19 +03:00
case NVIF_CLASS_SW_NV04 :
case NVIF_CLASS_SW_NV10 :
case NVIF_CLASS_SW_NV50 :
case NVIF_CLASS_SW_GF100 :
2015-08-20 07:54:16 +03:00
oclass = sclass [ i ] . oclass ;
2015-08-20 07:54:16 +03:00
break ;
default :
break ;
}
}
} else
if ( ( init - > class & 0x00ff ) = = 0x00b1 ) {
/* msvld: compatibility with incorrect version exposure */
for ( i = 0 ; i < ret ; i + + ) {
2015-08-20 07:54:16 +03:00
if ( ( sclass [ i ] . oclass & 0x00ff ) = = 0x00b1 ) {
oclass = sclass [ i ] . oclass ;
2015-08-20 07:54:16 +03:00
break ;
}
}
} else
if ( ( init - > class & 0x00ff ) = = 0x00b2 ) { /* mspdec */
/* mspdec: compatibility with incorrect version exposure */
for ( i = 0 ; i < ret ; i + + ) {
2015-08-20 07:54:16 +03:00
if ( ( sclass [ i ] . oclass & 0x00ff ) = = 0x00b2 ) {
oclass = sclass [ i ] . oclass ;
2015-08-20 07:54:16 +03:00
break ;
}
}
} else
if ( ( init - > class & 0x00ff ) = = 0x00b3 ) { /* msppp */
/* msppp: compatibility with incorrect version exposure */
for ( i = 0 ; i < ret ; i + + ) {
2015-08-20 07:54:16 +03:00
if ( ( sclass [ i ] . oclass & 0x00ff ) = = 0x00b3 ) {
oclass = sclass [ i ] . oclass ;
2015-08-20 07:54:16 +03:00
break ;
}
}
} else {
oclass = init - > class ;
}
2015-08-20 07:54:16 +03:00
nvif_object_sclass_put ( & sclass ) ;
2015-08-20 07:54:16 +03:00
if ( ! oclass )
return nouveau_abi16_put ( abi16 , - EINVAL ) ;
2015-08-20 07:54:15 +03:00
ntfy = kzalloc ( sizeof ( * ntfy ) , GFP_KERNEL ) ;
if ( ! ntfy )
return nouveau_abi16_put ( abi16 , - ENOMEM ) ;
list_add ( & ntfy - > head , & chan - > notifiers ) ;
client - > route = NVDRM_OBJECT_ABI16 ;
2015-08-20 07:54:16 +03:00
ret = nvif_object_init ( & chan - > chan - > user , init - > handle , oclass ,
2015-08-20 07:54:15 +03:00
NULL , 0 , & ntfy - > object ) ;
client - > route = NVDRM_OBJECT_NVIF ;
if ( ret )
nouveau_abi16_ntfy_fini ( chan , ntfy ) ;
2012-07-20 02:17:34 +04:00
return nouveau_abi16_put ( abi16 , ret ) ;
2012-05-08 04:24:27 +04:00
}
int
nouveau_abi16_ioctl_notifierobj_alloc ( ABI16_IOCTL_ARGS )
{
2012-07-20 02:17:34 +04:00
struct drm_nouveau_notifierobj_alloc * info = data ;
struct nouveau_drm * drm = nouveau_drm ( dev ) ;
2015-11-03 03:17:49 +03:00
struct nouveau_abi16 * abi16 = nouveau_abi16_get ( file_priv ) ;
2014-08-09 22:10:23 +04:00
struct nouveau_abi16_chan * chan ;
2012-07-20 02:17:34 +04:00
struct nouveau_abi16_ntfy * ntfy ;
2014-08-09 22:10:22 +04:00
struct nvif_device * device = & abi16 - > device ;
2014-08-09 22:10:23 +04:00
struct nvif_client * client ;
2015-08-20 07:54:15 +03:00
struct nv_dma_v0 args = { } ;
2012-05-08 04:24:27 +04:00
int ret ;
2012-07-20 02:17:34 +04:00
if ( unlikely ( ! abi16 ) )
return - ENOMEM ;
2012-05-08 04:24:27 +04:00
/* completely unnecessary for these chipsets... */
2014-08-09 22:10:22 +04:00
if ( unlikely ( device - > info . family > = NV_DEVICE_INFO_V0_FERMI ) )
2012-07-20 02:17:34 +04:00
return nouveau_abi16_put ( abi16 , - EINVAL ) ;
2015-08-20 07:54:15 +03:00
client = abi16 - > device . object . client ;
2012-05-08 04:24:27 +04:00
2014-08-09 22:10:23 +04:00
chan = nouveau_abi16_chan ( abi16 , info - > channel ) ;
2012-07-20 02:17:34 +04:00
if ( ! chan )
return nouveau_abi16_put ( abi16 , - ENOENT ) ;
ntfy = kzalloc ( sizeof ( * ntfy ) , GFP_KERNEL ) ;
if ( ! ntfy )
return nouveau_abi16_put ( abi16 , - ENOMEM ) ;
list_add ( & ntfy - > head , & chan - > notifiers ) ;
2015-01-14 08:36:34 +03:00
ret = nvkm_mm_head ( & chan - > heap , 0 , 1 , info - > size , info - > size , 1 ,
& ntfy - > node ) ;
2012-07-20 02:17:34 +04:00
if ( ret )
goto done ;
2015-08-20 07:54:15 +03:00
args . start = ntfy - > node - > offset ;
args . limit = ntfy - > node - > offset + ntfy - > node - > length - 1 ;
2014-08-09 22:10:22 +04:00
if ( device - > info . family > = NV_DEVICE_INFO_V0_TESLA ) {
2015-08-20 07:54:15 +03:00
args . target = NV_DMA_V0_TARGET_VM ;
args . access = NV_DMA_V0_ACCESS_VM ;
args . start + = chan - > ntfy_vma . offset ;
args . limit + = chan - > ntfy_vma . offset ;
2012-07-20 02:17:34 +04:00
} else
2015-08-20 07:54:23 +03:00
if ( drm - > agp . bridge ) {
2015-08-20 07:54:15 +03:00
args . target = NV_DMA_V0_TARGET_AGP ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
args . start + = drm - > agp . base + chan - > ntfy - > bo . offset ;
args . limit + = drm - > agp . base + chan - > ntfy - > bo . offset ;
2012-07-20 02:17:34 +04:00
} else {
2015-08-20 07:54:15 +03:00
args . target = NV_DMA_V0_TARGET_VM ;
args . access = NV_DMA_V0_ACCESS_RDWR ;
args . start + = chan - > ntfy - > bo . offset ;
args . limit + = chan - > ntfy - > bo . offset ;
2012-07-20 02:17:34 +04:00
}
2015-08-20 07:54:15 +03:00
client - > route = NVDRM_OBJECT_ABI16 ;
client - > super = true ;
ret = nvif_object_init ( & chan - > chan - > user , info - > handle ,
NV_DMA_IN_MEMORY , & args , sizeof ( args ) ,
& ntfy - > object ) ;
2014-08-09 22:10:23 +04:00
client - > super = false ;
2015-08-20 07:54:15 +03:00
client - > route = NVDRM_OBJECT_NVIF ;
2012-07-20 02:17:34 +04:00
if ( ret )
goto done ;
2014-01-06 02:59:07 +04:00
info - > offset = ntfy - > node - > offset ;
2012-07-20 02:17:34 +04:00
done :
if ( ret )
nouveau_abi16_ntfy_fini ( chan , ntfy ) ;
return nouveau_abi16_put ( abi16 , ret ) ;
2012-05-08 04:24:27 +04:00
}
int
nouveau_abi16_ioctl_gpuobj_free ( ABI16_IOCTL_ARGS )
{
2012-07-20 02:17:34 +04:00
struct drm_nouveau_gpuobj_free * fini = data ;
2015-11-03 03:17:49 +03:00
struct nouveau_abi16 * abi16 = nouveau_abi16_get ( file_priv ) ;
2014-08-09 22:10:23 +04:00
struct nouveau_abi16_chan * chan ;
2012-07-20 02:17:34 +04:00
struct nouveau_abi16_ntfy * ntfy ;
2015-08-20 07:54:15 +03:00
int ret = - ENOENT ;
2012-05-08 04:24:27 +04:00
2012-07-20 02:17:34 +04:00
if ( unlikely ( ! abi16 ) )
return - ENOMEM ;
2014-08-09 22:10:23 +04:00
chan = nouveau_abi16_chan ( abi16 , fini - > channel ) ;
2012-07-20 02:17:34 +04:00
if ( ! chan )
2015-08-20 07:54:15 +03:00
return nouveau_abi16_put ( abi16 , - EINVAL ) ;
2012-05-08 04:24:27 +04:00
2012-07-20 02:17:34 +04:00
/* synchronize with the user channel and destroy the gpu object */
nouveau_channel_idle ( chan - > chan ) ;
2012-05-08 04:24:27 +04:00
2012-07-20 02:17:34 +04:00
list_for_each_entry ( ntfy , & chan - > notifiers , head ) {
2015-08-20 07:54:15 +03:00
if ( ntfy - > object . handle = = fini - > handle ) {
nouveau_abi16_ntfy_fini ( chan , ntfy ) ;
ret = 0 ;
2012-07-20 02:17:34 +04:00
break ;
}
}
2015-08-20 07:54:15 +03:00
return nouveau_abi16_put ( abi16 , ret ) ;
2012-05-08 04:24:27 +04:00
}