2017-12-21 00:45:38 +01:00
/*
2022-01-19 18:14:10 +00:00
* Copyright ( C ) 2018 - 2022 Intel Corporation
2017-12-21 00:45:38 +01:00
*
2018-09-18 09:11:08 +02:00
* SPDX - License - Identifier : MIT
2017-12-21 00:45:38 +01:00
*
*/
2020-02-23 22:44:01 +01:00
# include "shared/source/os_interface/linux/drm_buffer_object.h"
2019-02-27 11:39:32 +01:00
2020-05-06 03:37:15 -07:00
# include "shared/source/helpers/aligned_memory.h"
2020-02-23 22:44:01 +01:00
# include "shared/source/helpers/debug_helpers.h"
# include "shared/source/os_interface/linux/drm_memory_manager.h"
2021-06-17 14:14:05 +00:00
# include "shared/source/os_interface/linux/drm_memory_operations_handler.h"
2020-05-06 03:37:15 -07:00
# include "shared/source/os_interface/linux/drm_neo.h"
2022-05-17 17:16:13 +00:00
# include "shared/source/os_interface/linux/drm_wrappers.h"
2022-01-19 18:14:10 +00:00
# include "shared/source/os_interface/linux/ioctl_helper.h"
2021-09-03 11:40:34 +00:00
# include "shared/source/os_interface/linux/os_context_linux.h"
2020-02-23 22:44:01 +01:00
# include "shared/source/os_interface/linux/os_time_linux.h"
2020-08-11 14:00:41 +02:00
# include "shared/source/os_interface/os_context.h"
2020-02-23 22:44:01 +01:00
# include "shared/source/utilities/stackvec.h"
2017-12-21 00:45:38 +01:00
# include <errno.h>
# include <fcntl.h>
2020-05-06 03:37:15 -07:00
# include <map>
2019-02-27 11:39:32 +01:00
# include <stdarg.h>
2020-05-06 03:37:15 -07:00
# include <string.h>
2019-02-27 11:39:32 +01:00
# include <sys/ioctl.h>
# include <sys/mman.h>
# include <sys/syscall.h>
# include <sys/types.h>
2017-12-21 00:45:38 +01:00
# include <unistd.h>
2019-03-26 11:59:46 +01:00
namespace NEO {
2017-12-21 00:45:38 +01:00
2022-05-09 17:40:30 +00:00
BufferObject : : BufferObject ( Drm * drm , uint64_t patIndex , int handle , size_t size , size_t maxOsContextCount ) : drm ( drm ) , refCount ( 1 ) , handle ( handle ) , size ( size ) {
2022-06-21 17:41:40 +02:00
auto ioctlHelper = drm - > getIoctlHelper ( ) ;
this - > tilingMode = ioctlHelper - > getDrmParamValue ( DrmParam : : TilingNone ) ;
2018-02-26 23:23:43 +01:00
this - > lockedAddress = nullptr ;
2022-04-19 19:24:19 +00:00
this - > patIndex = patIndex ;
2020-08-11 14:00:41 +02:00
perContextVmsUsed = drm - > isPerContextVMRequired ( ) ;
2021-11-08 21:42:07 +00:00
requiresExplicitResidency = drm - > hasPageFaultSupport ( ) ;
2020-08-11 14:00:41 +02:00
if ( perContextVmsUsed ) {
2020-08-20 13:20:20 +02:00
bindInfo . resize ( maxOsContextCount ) ;
2020-08-11 14:00:41 +02:00
for ( auto & iter : bindInfo ) {
iter . fill ( false ) ;
}
} else {
bindInfo . resize ( 1 ) ;
bindInfo [ 0 ] . fill ( false ) ;
}
2017-12-21 00:45:38 +01:00
}
uint32_t BufferObject : : getRefCount ( ) const {
return this - > refCount . load ( ) ;
}
2022-05-11 14:59:23 +00:00
void BufferObject : : setAddress ( uint64_t address ) {
auto gmmHelper = drm - > getRootDeviceEnvironment ( ) . getGmmHelper ( ) ;
this - > gpuAddress = gmmHelper - > canonize ( address ) ;
}
2017-12-21 00:45:38 +01:00
bool BufferObject : : close ( ) {
2022-05-24 16:13:02 +00:00
GemClose close { } ;
2017-12-21 00:45:38 +01:00
close . handle = this - > handle ;
2020-09-25 11:24:15 +02:00
PRINT_DEBUG_STRING ( DebugManager . flags . PrintBOCreateDestroyResult . get ( ) , stdout , " Calling gem close on handle: BO-%d \n " , this - > handle ) ;
2020-08-13 10:10:48 +02:00
2022-06-28 17:56:14 +00:00
auto ioctlHelper = this - > drm - > getIoctlHelper ( ) ;
2022-06-29 16:49:29 +00:00
int ret = ioctlHelper - > ioctl ( DrmIoctl : : GemClose , & close ) ;
2017-12-21 00:45:38 +01:00
if ( ret ! = 0 ) {
int err = errno ;
2020-09-25 11:24:15 +02:00
PRINT_DEBUG_STRING ( DebugManager . flags . PrintDebugMessages . get ( ) , stderr , " ioctl(GEM_CLOSE) failed with %d. errno=%d(%s) \n " , ret , err , strerror ( err ) ) ;
2017-12-20 14:28:42 +01:00
DEBUG_BREAK_IF ( true ) ;
2017-12-21 00:45:38 +01:00
return false ;
}
this - > handle = - 1 ;
return true ;
}
int BufferObject : : wait ( int64_t timeoutNs ) {
2021-04-29 08:58:16 +00:00
if ( this - > drm - > isVmBindAvailable ( ) ) {
2021-02-16 15:25:26 +00:00
return 0 ;
}
2021-06-15 11:31:12 +00:00
int ret = this - > drm - > waitHandle ( this - > handle , - 1 ) ;
2017-12-21 00:45:38 +01:00
UNRECOVERABLE_IF ( ret ! = 0 ) ;
return ret ;
}
bool BufferObject : : setTiling ( uint32_t mode , uint32_t stride ) {
2022-01-20 18:13:07 +00:00
if ( this - > tilingMode = = mode ) {
2017-12-21 00:45:38 +01:00
return true ;
}
2022-05-16 14:41:00 +00:00
GemSetTiling setTiling { } ;
2022-05-12 14:04:41 +00:00
setTiling . handle = this - > handle ;
2022-05-16 14:41:00 +00:00
setTiling . tilingMode = mode ;
2022-05-12 14:04:41 +00:00
setTiling . stride = stride ;
2022-06-28 17:56:14 +00:00
auto ioctlHelper = this - > drm - > getIoctlHelper ( ) ;
2017-12-21 00:45:38 +01:00
2022-06-29 16:49:29 +00:00
if ( ioctlHelper - > ioctl ( DrmIoctl : : GemSetTiling , & setTiling ) ! = 0 ) {
2017-12-21 00:45:38 +01:00
return false ;
}
2022-05-16 14:41:00 +00:00
this - > tilingMode = setTiling . tilingMode ;
2017-12-21 00:45:38 +01:00
2022-05-16 14:41:00 +00:00
return setTiling . tilingMode = = mode ;
2018-02-26 23:23:43 +01:00
}
2017-12-21 00:45:38 +01:00
2020-10-15 08:48:58 +02:00
uint32_t BufferObject : : getOsContextId ( OsContext * osContext ) {
return perContextVmsUsed ? osContext - > getContextId ( ) : 0u ;
}
2022-05-11 15:06:01 +00:00
void BufferObject : : fillExecObject ( ExecObject & execObject , OsContext * osContext , uint32_t vmHandleId , uint32_t drmContextId ) {
2022-02-15 15:50:04 +00:00
const auto osContextId = drm - > isPerContextVMRequired ( ) ? osContext - > getContextId ( ) : 0 ;
2022-05-11 15:06:01 +00:00
auto ioctlHelper = drm - > getIoctlHelper ( ) ;
ioctlHelper - > fillExecObject ( execObject , this - > handle , this - > gpuAddress , drmContextId , this - > bindInfo [ osContextId ] [ vmHandleId ] , this - > isMarkedForCapture ( ) ) ;
2017-12-21 00:45:38 +01:00
}
2022-01-19 18:14:10 +00:00
int BufferObject : : exec ( uint32_t used , size_t startOffset , unsigned int flags , bool requiresCoherency , OsContext * osContext , uint32_t vmHandleId , uint32_t drmContextId ,
2022-05-11 15:06:01 +00:00
BufferObject * const residency [ ] , size_t residencyCount , ExecObject * execObjectsStorage , uint64_t completionGpuAddress , uint32_t completionValue ) {
2020-05-06 03:37:15 -07:00
for ( size_t i = 0 ; i < residencyCount ; i + + ) {
2020-08-11 14:00:41 +02:00
residency [ i ] - > fillExecObject ( execObjectsStorage [ i ] , osContext , vmHandleId , drmContextId ) ;
2020-05-06 03:37:15 -07:00
}
2020-08-11 14:00:41 +02:00
this - > fillExecObject ( execObjectsStorage [ residencyCount ] , osContext , vmHandleId , drmContextId ) ;
2022-05-12 15:56:50 +00:00
auto ioctlHelper = drm - > getIoctlHelper ( ) ;
2020-05-06 03:37:15 -07:00
2022-05-12 15:56:50 +00:00
ExecBuffer execbuf { } ;
ioctlHelper - > fillExecBuffer ( execbuf , reinterpret_cast < uintptr_t > ( execObjectsStorage ) ,
static_cast < uint32_t > ( residencyCount + 1u ) , static_cast < uint32_t > ( startOffset ) ,
alignUp ( used , 8 ) , flags , drmContextId ) ;
2020-05-06 03:37:15 -07:00
2020-06-09 10:00:59 +02:00
if ( DebugManager . flags . PrintExecutionBuffer . get ( ) ) {
2021-09-03 11:40:34 +00:00
PRINT_DEBUG_STRING ( DebugManager . flags . PrintExecutionBuffer . get ( ) , stdout , " Exec called with drmVmId = %u \n " ,
static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) . size ( ) ? static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) [ vmHandleId ] : 0 ) ;
2020-08-13 10:10:48 +02:00
printExecutionBuffer ( execbuf , residencyCount , execObjectsStorage , residency ) ;
2020-06-09 10:00:59 +02:00
}
2022-06-29 16:49:29 +00:00
int ret = ioctlHelper - > execBuffer ( & execbuf , completionGpuAddress , completionValue ) ;
2021-05-27 09:41:28 +00:00
2021-06-17 14:14:05 +00:00
if ( ret ! = 0 ) {
2021-10-12 01:32:45 +00:00
int err = this - > drm - > getErrno ( ) ;
if ( err = = EOPNOTSUPP ) {
PRINT_DEBUG_STRING ( DebugManager . flags . PrintDebugMessages . get ( ) , stderr , " ioctl(I915_GEM_EXECBUFFER2) failed with %d. errno=%d(%s) \n " , ret , err , strerror ( err ) ) ;
return err ;
}
2022-04-13 10:42:27 +00:00
evictUnusedAllocations ( false , true ) ;
2022-06-29 16:49:29 +00:00
ret = ioctlHelper - > execBuffer ( & execbuf , completionGpuAddress , completionValue ) ;
2021-07-28 12:35:06 +00:00
}
if ( ret ! = 0 ) {
2022-04-13 10:42:27 +00:00
const auto status = evictUnusedAllocations ( true , true ) ;
if ( status = = MemoryOperationsStatus : : GPU_HANG_DETECTED_DURING_OPERATION ) {
2022-05-09 17:40:30 +00:00
PRINT_DEBUG_STRING ( DebugManager . flags . PrintDebugMessages . get ( ) , stderr , " Error! GPU hang detected in BufferObject::exec(). Returning %d \n " , gpuHangDetected ) ;
return gpuHangDetected ;
2022-04-13 10:42:27 +00:00
}
2022-06-29 16:49:29 +00:00
ret = ioctlHelper - > execBuffer ( & execbuf , completionGpuAddress , completionValue ) ;
2021-06-17 14:14:05 +00:00
}
2020-05-06 03:37:15 -07:00
if ( ret = = 0 ) {
return 0 ;
}
int err = this - > drm - > getErrno ( ) ;
2020-09-25 11:24:15 +02:00
PRINT_DEBUG_STRING ( DebugManager . flags . PrintDebugMessages . get ( ) , stderr , " ioctl(I915_GEM_EXECBUFFER2) failed with %d. errno=%d(%s) \n " , ret , err , strerror ( err ) ) ;
2020-05-06 03:37:15 -07:00
return err ;
}
2022-04-13 10:42:27 +00:00
MemoryOperationsStatus BufferObject : : evictUnusedAllocations ( bool waitForCompletion , bool isLockNeeded ) {
return static_cast < DrmMemoryOperationsHandler * > ( this - > drm - > getRootDeviceEnvironment ( ) . memoryOperationsInterface . get ( ) ) - > evictUnusedAllocations ( waitForCompletion , isLockNeeded ) ;
}
2022-02-04 15:28:20 +00:00
void BufferObject : : printBOBindingResult ( OsContext * osContext , uint32_t vmHandleId , bool bind , int retVal ) {
if ( retVal = = 0 ) {
if ( bind ) {
PRINT_DEBUG_STRING ( DebugManager . flags . PrintBOBindingResult . get ( ) , stdout , " bind BO-%d to VM %u, drmVmId = %u, range: %llx - %llx, size: %lld, result: %d \n " ,
this - > handle , vmHandleId , static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) . size ( ) ? static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) [ vmHandleId ] : 0 , this - > gpuAddress , ptrOffset ( this - > gpuAddress , this - > size ) , this - > size , retVal ) ;
} else {
PRINT_DEBUG_STRING ( DebugManager . flags . PrintBOBindingResult . get ( ) , stdout , " unbind BO-%d from VM %u, drmVmId = %u, range: %llx - %llx, size: %lld, result: %d \n " ,
this - > handle , vmHandleId , static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) . size ( ) ? static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) [ vmHandleId ] : 0 , this - > gpuAddress , ptrOffset ( this - > gpuAddress , this - > size ) , this - > size , retVal ) ;
}
} else {
auto err = this - > drm - > getErrno ( ) ;
if ( bind ) {
PRINT_DEBUG_STRING ( DebugManager . flags . PrintBOBindingResult . get ( ) , stderr , " bind BO-%d to VM %u, drmVmId = %u, range: %llx - %llx, size: %lld, result: %d, errno: %d(%s) \n " ,
this - > handle , vmHandleId , static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) . size ( ) ? static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) [ vmHandleId ] : 0 , this - > gpuAddress , ptrOffset ( this - > gpuAddress , this - > size ) , this - > size , retVal , err , strerror ( err ) ) ;
} else {
PRINT_DEBUG_STRING ( DebugManager . flags . PrintBOBindingResult . get ( ) , stderr , " unbind BO-%d from VM %u, drmVmId = %u, range: %llx - %llx, size: %lld, result: %d, errno: %d(%s) \n " ,
this - > handle , vmHandleId , static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) . size ( ) ? static_cast < const OsContextLinux * > ( osContext ) - > getDrmVmIds ( ) [ vmHandleId ] : 0 , this - > gpuAddress , ptrOffset ( this - > gpuAddress , this - > size ) , this - > size , retVal , err , strerror ( err ) ) ;
}
}
}
2020-10-16 12:59:27 +02:00
int BufferObject : : bind ( OsContext * osContext , uint32_t vmHandleId ) {
int retVal = 0 ;
2020-10-15 08:48:58 +02:00
auto contextId = getOsContextId ( osContext ) ;
2020-08-11 14:00:41 +02:00
if ( ! this - > bindInfo [ contextId ] [ vmHandleId ] ) {
2020-10-16 12:59:27 +02:00
retVal = this - > drm - > bindBufferObject ( osContext , vmHandleId , this ) ;
2022-02-04 15:28:20 +00:00
if ( DebugManager . flags . PrintBOBindingResult . get ( ) ) {
printBOBindingResult ( osContext , vmHandleId , true , retVal ) ;
}
2020-10-16 12:59:27 +02:00
if ( ! retVal ) {
this - > bindInfo [ contextId ] [ vmHandleId ] = true ;
}
2020-07-28 07:48:41 +02:00
}
2020-10-16 12:59:27 +02:00
return retVal ;
2020-07-02 11:49:46 +02:00
}
2020-10-16 12:59:27 +02:00
int BufferObject : : unbind ( OsContext * osContext , uint32_t vmHandleId ) {
int retVal = 0 ;
2020-10-15 08:48:58 +02:00
auto contextId = getOsContextId ( osContext ) ;
2020-08-11 14:00:41 +02:00
if ( this - > bindInfo [ contextId ] [ vmHandleId ] ) {
2020-10-16 12:59:27 +02:00
retVal = this - > drm - > unbindBufferObject ( osContext , vmHandleId , this ) ;
2022-02-04 15:28:20 +00:00
if ( DebugManager . flags . PrintBOBindingResult . get ( ) ) {
printBOBindingResult ( osContext , vmHandleId , false , retVal ) ;
}
2020-10-16 12:59:27 +02:00
if ( ! retVal ) {
this - > bindInfo [ contextId ] [ vmHandleId ] = false ;
}
2020-07-28 07:48:41 +02:00
}
2020-10-16 12:59:27 +02:00
return retVal ;
2020-07-02 11:49:46 +02:00
}
2022-05-12 15:56:50 +00:00
void BufferObject : : printExecutionBuffer ( ExecBuffer & execbuf , const size_t & residencyCount , ExecObject * execObjectsStorage , BufferObject * const residency [ ] ) {
2022-05-11 15:06:01 +00:00
auto ioctlHelper = drm - > getIoctlHelper ( ) ;
2020-08-13 10:10:48 +02:00
std : : stringstream logger ;
2022-05-12 15:56:50 +00:00
ioctlHelper - > logExecBuffer ( execbuf , logger ) ;
2020-08-13 10:10:48 +02:00
size_t i ;
for ( i = 0 ; i < residencyCount ; i + + ) {
2022-05-11 15:06:01 +00:00
ioctlHelper - > logExecObject ( execObjectsStorage [ i ] , logger , residency [ i ] - > peekSize ( ) ) ;
2020-06-09 10:00:59 +02:00
}
2022-05-11 15:06:01 +00:00
logger < < " Command " ;
ioctlHelper - > logExecObject ( execObjectsStorage [ i ] , logger , this - > peekSize ( ) ) ;
2020-08-13 10:10:48 +02:00
2021-05-27 09:41:28 +00:00
printf ( " %s \n " , logger . str ( ) . c_str ( ) ) ;
2020-06-09 10:00:59 +02:00
}
2021-08-04 11:56:36 +00:00
int bindBOsWithinContext ( BufferObject * const boToPin [ ] , size_t numberOfBos , OsContext * osContext , uint32_t vmHandleId ) {
2020-09-30 08:29:12 +02:00
auto retVal = 0 ;
2020-10-15 08:48:58 +02:00
2020-10-16 13:46:25 +02:00
for ( auto drmIterator = 0u ; drmIterator < osContext - > getDeviceBitfield ( ) . size ( ) ; drmIterator + + ) {
if ( osContext - > getDeviceBitfield ( ) . test ( drmIterator ) ) {
for ( size_t i = 0 ; i < numberOfBos ; i + + ) {
retVal | = boToPin [ i ] - > bind ( osContext , drmIterator ) ;
2020-09-30 08:29:12 +02:00
}
}
2020-10-16 13:46:25 +02:00
}
return retVal ;
}
int BufferObject : : pin ( BufferObject * const boToPin [ ] , size_t numberOfBos , OsContext * osContext , uint32_t vmHandleId , uint32_t drmContextId ) {
auto retVal = 0 ;
2020-11-19 20:43:01 +00:00
if ( this - > drm - > isVmBindAvailable ( ) ) {
2021-08-04 11:56:36 +00:00
retVal = bindBOsWithinContext ( boToPin , numberOfBos , osContext , vmHandleId ) ;
2020-10-16 13:46:25 +02:00
} else {
2022-05-11 15:06:01 +00:00
StackVec < ExecObject , maxFragmentsCount + 1 > execObject ( numberOfBos + 1 ) ;
2022-01-19 18:14:10 +00:00
retVal = this - > exec ( 4u , 0u , 0u , false , osContext , vmHandleId , drmContextId , boToPin , numberOfBos , & execObject [ 0 ] , 0 , 0 ) ;
2020-10-16 13:46:25 +02:00
}
return retVal ;
}
int BufferObject : : validateHostPtr ( BufferObject * const boToPin [ ] , size_t numberOfBos , OsContext * osContext , uint32_t vmHandleId , uint32_t drmContextId ) {
auto retVal = 0 ;
2021-05-13 14:28:51 +00:00
if ( this - > drm - > isVmBindAvailable ( ) ) {
2021-08-04 11:56:36 +00:00
for ( size_t i = 0 ; i < numberOfBos ; i + + ) {
retVal = boToPin [ i ] - > bind ( osContext , vmHandleId ) ;
if ( retVal ) {
break ;
}
}
2020-09-30 08:29:12 +02:00
} else {
2022-05-11 15:06:01 +00:00
StackVec < ExecObject , maxFragmentsCount + 1 > execObject ( numberOfBos + 1 ) ;
2022-01-19 18:14:10 +00:00
retVal = this - > exec ( 4u , 0u , 0u , false , osContext , vmHandleId , drmContextId , boToPin , numberOfBos , & execObject [ 0 ] , 0 , 0 ) ;
2020-09-30 08:29:12 +02:00
}
2020-10-15 08:48:58 +02:00
2020-09-30 08:29:12 +02:00
return retVal ;
2017-12-21 00:45:38 +01:00
}
2018-02-28 12:09:48 +01:00
2020-09-14 13:28:47 +02:00
void BufferObject : : addBindExtHandle ( uint32_t handle ) {
bindExtHandles . push_back ( handle ) ;
}
2019-03-26 11:59:46 +01:00
} // namespace NEO