2015-04-20 16:55:21 -04:00
/*
* Copyright 2014 Advanced Micro Devices , 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 .
*
*/
# include <drm/drmP.h>
# include "amdgpu.h"
# include "amdgpu_ih.h"
/**
* amdgpu_ih_ring_init - initialize the IH state
*
* @ adev : amdgpu_device pointer
2018-09-16 20:13:21 +02:00
* @ ih : ih ring to initialize
* @ ring_size : ring size to allocate
* @ use_bus_addr : true when we can use dma_alloc_coherent
2015-04-20 16:55:21 -04:00
*
* Initializes the IH state and allocates a buffer
* for the IH ring buffer .
* Returns 0 for success , errors for failure .
*/
2018-09-16 20:13:21 +02:00
int amdgpu_ih_ring_init ( struct amdgpu_device * adev , struct amdgpu_ih_ring * ih ,
unsigned ring_size , bool use_bus_addr )
2015-04-20 16:55:21 -04:00
{
u32 rb_bufsz ;
int r ;
/* Align ring size */
rb_bufsz = order_base_2 ( ring_size / 4 ) ;
ring_size = ( 1 < < rb_bufsz ) * 4 ;
2018-09-16 20:13:21 +02:00
ih - > ring_size = ring_size ;
ih - > ptr_mask = ih - > ring_size - 1 ;
ih - > rptr = 0 ;
ih - > use_bus_addr = use_bus_addr ;
if ( use_bus_addr ) {
2018-09-18 14:24:49 +02:00
dma_addr_t dma_addr ;
2018-09-16 20:13:21 +02:00
if ( ih - > ring )
return 0 ;
/* add 8 bytes for the rptr/wptr shadows and
* add them to the end of the ring allocation .
*/
ih - > ring = dma_alloc_coherent ( adev - > dev , ih - > ring_size + 8 ,
2018-09-18 14:24:49 +02:00
& dma_addr , GFP_KERNEL ) ;
2018-09-16 20:13:21 +02:00
if ( ih - > ring = = NULL )
return - ENOMEM ;
memset ( ( void * ) ih - > ring , 0 , ih - > ring_size + 8 ) ;
2018-09-18 14:24:49 +02:00
ih - > gpu_addr = dma_addr ;
ih - > wptr_addr = dma_addr + ih - > ring_size ;
ih - > wptr_cpu = & ih - > ring [ ih - > ring_size / 4 ] ;
ih - > rptr_addr = dma_addr + ih - > ring_size + 4 ;
ih - > rptr_cpu = & ih - > ring [ ( ih - > ring_size / 4 ) + 1 ] ;
2015-04-20 16:55:21 -04:00
} else {
2018-09-18 14:24:49 +02:00
unsigned wptr_offs , rptr_offs ;
r = amdgpu_device_wb_get ( adev , & wptr_offs ) ;
2018-09-16 20:13:21 +02:00
if ( r )
return r ;
2018-09-18 14:24:49 +02:00
r = amdgpu_device_wb_get ( adev , & rptr_offs ) ;
2015-04-20 16:55:21 -04:00
if ( r ) {
2018-09-18 14:24:49 +02:00
amdgpu_device_wb_free ( adev , wptr_offs ) ;
2015-04-20 16:55:21 -04:00
return r ;
}
2018-09-16 20:13:21 +02:00
r = amdgpu_bo_create_kernel ( adev , ih - > ring_size , PAGE_SIZE ,
AMDGPU_GEM_DOMAIN_GTT ,
& ih - > ring_obj , & ih - > gpu_addr ,
( void * * ) & ih - > ring ) ;
2015-04-20 16:55:21 -04:00
if ( r ) {
2018-09-18 14:24:49 +02:00
amdgpu_device_wb_free ( adev , rptr_offs ) ;
amdgpu_device_wb_free ( adev , wptr_offs ) ;
2015-04-20 16:55:21 -04:00
return r ;
}
2018-09-18 14:24:49 +02:00
ih - > wptr_addr = adev - > wb . gpu_addr + wptr_offs * 4 ;
ih - > wptr_cpu = & adev - > wb . wb [ wptr_offs ] ;
ih - > rptr_addr = adev - > wb . gpu_addr + rptr_offs * 4 ;
ih - > rptr_cpu = & adev - > wb . wb [ rptr_offs ] ;
2015-04-20 16:55:21 -04:00
}
2018-09-16 20:13:21 +02:00
return 0 ;
2015-04-20 16:55:21 -04:00
}
/**
* amdgpu_ih_ring_fini - tear down the IH state
*
* @ adev : amdgpu_device pointer
2018-09-16 20:13:21 +02:00
* @ ih : ih ring to tear down
2015-04-20 16:55:21 -04:00
*
* Tears down the IH state and frees buffer
* used for the IH ring buffer .
*/
2018-09-16 20:13:21 +02:00
void amdgpu_ih_ring_fini ( struct amdgpu_device * adev , struct amdgpu_ih_ring * ih )
2015-04-20 16:55:21 -04:00
{
2018-09-16 20:13:21 +02:00
if ( ih - > use_bus_addr ) {
if ( ! ih - > ring )
return ;
/* add 8 bytes for the rptr/wptr shadows and
* add them to the end of the ring allocation .
*/
dma_free_coherent ( adev - > dev , ih - > ring_size + 8 ,
2018-09-18 14:24:49 +02:00
( void * ) ih - > ring , ih - > gpu_addr ) ;
2018-09-16 20:13:21 +02:00
ih - > ring = NULL ;
2015-04-20 16:55:21 -04:00
} else {
2018-09-16 20:13:21 +02:00
amdgpu_bo_free_kernel ( & ih - > ring_obj , & ih - > gpu_addr ,
( void * * ) & ih - > ring ) ;
2018-09-18 14:24:49 +02:00
amdgpu_device_wb_free ( adev , ( ih - > wptr_addr - ih - > gpu_addr ) / 4 ) ;
amdgpu_device_wb_free ( adev , ( ih - > rptr_addr - ih - > gpu_addr ) / 4 ) ;
2015-04-20 16:55:21 -04:00
}
}
/**
* amdgpu_ih_process - interrupt handler
*
* @ adev : amdgpu_device pointer
2018-09-16 20:13:21 +02:00
* @ ih : ih ring to process
2015-04-20 16:55:21 -04:00
*
* Interrupt hander ( VI ) , walk the IH ring .
* Returns irq process return code .
*/
2019-01-09 15:36:29 +01:00
int amdgpu_ih_process ( struct amdgpu_device * adev , struct amdgpu_ih_ring * ih )
2015-04-20 16:55:21 -04:00
{
u32 wptr ;
2018-09-16 20:13:21 +02:00
if ( ! ih - > enabled | | adev - > shutdown )
2015-04-20 16:55:21 -04:00
return IRQ_NONE ;
2018-09-17 16:13:49 +02:00
wptr = amdgpu_ih_get_wptr ( adev , ih ) ;
2015-04-20 16:55:21 -04:00
restart_ih :
/* is somebody else already processing irqs? */
2018-09-16 20:13:21 +02:00
if ( atomic_xchg ( & ih - > lock , 1 ) )
2015-04-20 16:55:21 -04:00
return IRQ_NONE ;
2018-09-16 20:13:21 +02:00
DRM_DEBUG ( " %s: rptr %d, wptr %d \n " , __func__ , ih - > rptr , wptr ) ;
2015-04-20 16:55:21 -04:00
/* Order reading of wptr vs. reading of IH ring data */
rmb ( ) ;
2018-09-16 20:13:21 +02:00
while ( ih - > rptr ! = wptr ) {
2019-01-09 15:36:29 +01:00
amdgpu_irq_dispatch ( adev , ih ) ;
2018-09-16 20:13:21 +02:00
ih - > rptr & = ih - > ptr_mask ;
2015-04-20 16:55:21 -04:00
}
2018-09-17 15:18:37 +02:00
2018-09-17 16:13:49 +02:00
amdgpu_ih_set_rptr ( adev , ih ) ;
2018-09-16 20:13:21 +02:00
atomic_set ( & ih - > lock , 0 ) ;
2015-04-20 16:55:21 -04:00
/* make sure wptr hasn't changed while processing */
2018-09-17 16:13:49 +02:00
wptr = amdgpu_ih_get_wptr ( adev , ih ) ;
2018-09-16 20:13:21 +02:00
if ( wptr ! = ih - > rptr )
2015-04-20 16:55:21 -04:00
goto restart_ih ;
return IRQ_HANDLED ;
}
2017-08-26 02:43:06 -04:00