2014-07-16 21:08:55 +03: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 .
*/
2017-12-08 19:22:12 -05:00
# if defined(CONFIG_AMD_IOMMU_V2_MODULE) || defined(CONFIG_AMD_IOMMU_V2)
2014-07-16 21:08:55 +03:00
# include <linux/amd-iommu.h>
2017-12-08 19:22:12 -05:00
# endif
2014-07-16 21:08:55 +03:00
# include <linux/bsearch.h>
# include <linux/pci.h>
# include <linux/slab.h>
# include "kfd_priv.h"
2014-07-17 01:27:00 +03:00
# include "kfd_device_queue_manager.h"
2017-08-15 23:00:15 -04:00
# include "kfd_pm4_headers_vi.h"
2017-11-14 16:41:19 -05:00
# include "cwsr_trap_handler_gfx8.asm"
2017-12-08 19:22:12 -05:00
# include "kfd_iommu.h"
2014-07-16 21:08:55 +03:00
2014-07-16 23:25:31 +03:00
# define MQD_SIZE_ALIGNED 768
2018-02-06 20:32:45 -05:00
static atomic_t kfd_device_suspended = ATOMIC_INIT ( 0 ) ;
2014-07-16 23:25:31 +03:00
2017-12-08 19:22:12 -05:00
# ifdef KFD_SUPPORT_IOMMU_V2
2014-07-16 21:08:55 +03:00
static const struct kfd_device_info kaveri_device_info = {
2015-01-01 17:10:01 +02:00
. asic_family = CHIP_KAVERI ,
. max_pasid_bits = 16 ,
2015-05-20 13:43:04 +03:00
/* max num of queues for KV.TODO should be a dynamic value */
. max_no_of_hqd = 24 ,
2015-01-01 17:10:01 +02:00
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
2015-05-10 12:15:46 +03:00
. event_interrupt_class = & event_interrupt_class_cik ,
2015-05-20 13:48:26 +03:00
. num_of_watch_points = 4 ,
2017-11-14 16:41:19 -05:00
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = false ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = true ,
2018-01-04 17:17:41 -05:00
. needs_pci_atomics = false ,
2015-01-01 17:10:01 +02:00
} ;
static const struct kfd_device_info carrizo_device_info = {
. asic_family = CHIP_CARRIZO ,
2014-07-16 21:08:55 +03:00
. max_pasid_bits = 16 ,
2015-06-06 21:45:43 +03:00
/* max num of queues for CZ.TODO should be a dynamic value */
. max_no_of_hqd = 24 ,
2014-07-17 01:37:30 +03:00
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
2015-06-06 21:45:43 +03:00
. event_interrupt_class = & event_interrupt_class_cik ,
2014-10-13 16:35:12 +03:00
. num_of_watch_points = 4 ,
2017-11-14 16:41:19 -05:00
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = true ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = true ,
2018-01-04 17:17:41 -05:00
. needs_pci_atomics = false ,
2014-07-16 21:08:55 +03:00
} ;
2017-12-08 19:22:12 -05:00
# endif
2014-07-16 21:08:55 +03:00
2018-01-04 17:17:47 -05:00
static const struct kfd_device_info hawaii_device_info = {
. asic_family = CHIP_HAWAII ,
. max_pasid_bits = 16 ,
/* max num of queues for KV.TODO should be a dynamic value */
. max_no_of_hqd = 24 ,
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
. event_interrupt_class = & event_interrupt_class_cik ,
. num_of_watch_points = 4 ,
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = false ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = false ,
2018-01-04 17:17:47 -05:00
. needs_pci_atomics = false ,
} ;
static const struct kfd_device_info tonga_device_info = {
. asic_family = CHIP_TONGA ,
. max_pasid_bits = 16 ,
. max_no_of_hqd = 24 ,
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
. event_interrupt_class = & event_interrupt_class_cik ,
. num_of_watch_points = 4 ,
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = false ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = false ,
2018-01-04 17:17:47 -05:00
. needs_pci_atomics = true ,
} ;
static const struct kfd_device_info tonga_vf_device_info = {
. asic_family = CHIP_TONGA ,
. max_pasid_bits = 16 ,
. max_no_of_hqd = 24 ,
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
. event_interrupt_class = & event_interrupt_class_cik ,
. num_of_watch_points = 4 ,
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = false ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = false ,
2018-01-04 17:17:47 -05:00
. needs_pci_atomics = false ,
} ;
static const struct kfd_device_info fiji_device_info = {
. asic_family = CHIP_FIJI ,
. max_pasid_bits = 16 ,
. max_no_of_hqd = 24 ,
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
. event_interrupt_class = & event_interrupt_class_cik ,
. num_of_watch_points = 4 ,
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = true ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = false ,
2018-01-04 17:17:47 -05:00
. needs_pci_atomics = true ,
} ;
static const struct kfd_device_info fiji_vf_device_info = {
. asic_family = CHIP_FIJI ,
. max_pasid_bits = 16 ,
. max_no_of_hqd = 24 ,
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
. event_interrupt_class = & event_interrupt_class_cik ,
. num_of_watch_points = 4 ,
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = true ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = false ,
2018-01-04 17:17:47 -05:00
. needs_pci_atomics = false ,
} ;
static const struct kfd_device_info polaris10_device_info = {
. asic_family = CHIP_POLARIS10 ,
. max_pasid_bits = 16 ,
. max_no_of_hqd = 24 ,
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
. event_interrupt_class = & event_interrupt_class_cik ,
. num_of_watch_points = 4 ,
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = true ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = false ,
2018-01-04 17:17:47 -05:00
. needs_pci_atomics = true ,
} ;
static const struct kfd_device_info polaris10_vf_device_info = {
. asic_family = CHIP_POLARIS10 ,
. max_pasid_bits = 16 ,
. max_no_of_hqd = 24 ,
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
. event_interrupt_class = & event_interrupt_class_cik ,
. num_of_watch_points = 4 ,
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = true ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = false ,
2018-01-04 17:17:47 -05:00
. needs_pci_atomics = false ,
} ;
static const struct kfd_device_info polaris11_device_info = {
. asic_family = CHIP_POLARIS11 ,
. max_pasid_bits = 16 ,
. max_no_of_hqd = 24 ,
. ih_ring_entry_size = 4 * sizeof ( uint32_t ) ,
. event_interrupt_class = & event_interrupt_class_cik ,
. num_of_watch_points = 4 ,
. mqd_size_aligned = MQD_SIZE_ALIGNED ,
. supports_cwsr = true ,
2017-12-08 19:22:12 -05:00
. needs_iommu_device = false ,
2018-01-04 17:17:47 -05:00
. needs_pci_atomics = true ,
} ;
2014-07-16 21:08:55 +03:00
struct kfd_deviceid {
unsigned short did ;
const struct kfd_device_info * device_info ;
} ;
static const struct kfd_deviceid supported_devices [ ] = {
2017-12-08 19:22:12 -05:00
# ifdef KFD_SUPPORT_IOMMU_V2
2014-07-16 21:08:55 +03:00
{ 0x1304 , & kaveri_device_info } , /* Kaveri */
{ 0x1305 , & kaveri_device_info } , /* Kaveri */
{ 0x1306 , & kaveri_device_info } , /* Kaveri */
{ 0x1307 , & kaveri_device_info } , /* Kaveri */
{ 0x1309 , & kaveri_device_info } , /* Kaveri */
{ 0x130A , & kaveri_device_info } , /* Kaveri */
{ 0x130B , & kaveri_device_info } , /* Kaveri */
{ 0x130C , & kaveri_device_info } , /* Kaveri */
{ 0x130D , & kaveri_device_info } , /* Kaveri */
{ 0x130E , & kaveri_device_info } , /* Kaveri */
{ 0x130F , & kaveri_device_info } , /* Kaveri */
{ 0x1310 , & kaveri_device_info } , /* Kaveri */
{ 0x1311 , & kaveri_device_info } , /* Kaveri */
{ 0x1312 , & kaveri_device_info } , /* Kaveri */
{ 0x1313 , & kaveri_device_info } , /* Kaveri */
{ 0x1315 , & kaveri_device_info } , /* Kaveri */
{ 0x1316 , & kaveri_device_info } , /* Kaveri */
{ 0x1317 , & kaveri_device_info } , /* Kaveri */
{ 0x1318 , & kaveri_device_info } , /* Kaveri */
{ 0x131B , & kaveri_device_info } , /* Kaveri */
{ 0x131C , & kaveri_device_info } , /* Kaveri */
2015-01-12 14:37:24 +02:00
{ 0x131D , & kaveri_device_info } , /* Kaveri */
{ 0x9870 , & carrizo_device_info } , /* Carrizo */
{ 0x9874 , & carrizo_device_info } , /* Carrizo */
{ 0x9875 , & carrizo_device_info } , /* Carrizo */
{ 0x9876 , & carrizo_device_info } , /* Carrizo */
2018-01-04 17:17:47 -05:00
{ 0x9877 , & carrizo_device_info } , /* Carrizo */
2017-12-08 19:22:12 -05:00
# endif
2018-01-04 17:17:47 -05:00
{ 0x67A0 , & hawaii_device_info } , /* Hawaii */
{ 0x67A1 , & hawaii_device_info } , /* Hawaii */
{ 0x67A2 , & hawaii_device_info } , /* Hawaii */
{ 0x67A8 , & hawaii_device_info } , /* Hawaii */
{ 0x67A9 , & hawaii_device_info } , /* Hawaii */
{ 0x67AA , & hawaii_device_info } , /* Hawaii */
{ 0x67B0 , & hawaii_device_info } , /* Hawaii */
{ 0x67B1 , & hawaii_device_info } , /* Hawaii */
{ 0x67B8 , & hawaii_device_info } , /* Hawaii */
{ 0x67B9 , & hawaii_device_info } , /* Hawaii */
{ 0x67BA , & hawaii_device_info } , /* Hawaii */
{ 0x67BE , & hawaii_device_info } , /* Hawaii */
{ 0x6920 , & tonga_device_info } , /* Tonga */
{ 0x6921 , & tonga_device_info } , /* Tonga */
{ 0x6928 , & tonga_device_info } , /* Tonga */
{ 0x6929 , & tonga_device_info } , /* Tonga */
{ 0x692B , & tonga_device_info } , /* Tonga */
{ 0x692F , & tonga_vf_device_info } , /* Tonga vf */
{ 0x6938 , & tonga_device_info } , /* Tonga */
{ 0x6939 , & tonga_device_info } , /* Tonga */
{ 0x7300 , & fiji_device_info } , /* Fiji */
{ 0x730F , & fiji_vf_device_info } , /* Fiji vf*/
{ 0x67C0 , & polaris10_device_info } , /* Polaris10 */
{ 0x67C1 , & polaris10_device_info } , /* Polaris10 */
{ 0x67C2 , & polaris10_device_info } , /* Polaris10 */
{ 0x67C4 , & polaris10_device_info } , /* Polaris10 */
{ 0x67C7 , & polaris10_device_info } , /* Polaris10 */
{ 0x67C8 , & polaris10_device_info } , /* Polaris10 */
{ 0x67C9 , & polaris10_device_info } , /* Polaris10 */
{ 0x67CA , & polaris10_device_info } , /* Polaris10 */
{ 0x67CC , & polaris10_device_info } , /* Polaris10 */
{ 0x67CF , & polaris10_device_info } , /* Polaris10 */
{ 0x67D0 , & polaris10_vf_device_info } , /* Polaris10 vf*/
{ 0x67DF , & polaris10_device_info } , /* Polaris10 */
{ 0x67E0 , & polaris11_device_info } , /* Polaris11 */
{ 0x67E1 , & polaris11_device_info } , /* Polaris11 */
{ 0x67E3 , & polaris11_device_info } , /* Polaris11 */
{ 0x67E7 , & polaris11_device_info } , /* Polaris11 */
{ 0x67E8 , & polaris11_device_info } , /* Polaris11 */
{ 0x67E9 , & polaris11_device_info } , /* Polaris11 */
{ 0x67EB , & polaris11_device_info } , /* Polaris11 */
{ 0x67EF , & polaris11_device_info } , /* Polaris11 */
{ 0x67FF , & polaris11_device_info } , /* Polaris11 */
2014-07-16 21:08:55 +03:00
} ;
2014-10-27 14:36:07 +02:00
static int kfd_gtt_sa_init ( struct kfd_dev * kfd , unsigned int buf_size ,
unsigned int chunk_size ) ;
static void kfd_gtt_sa_fini ( struct kfd_dev * kfd ) ;
2017-09-20 18:10:13 -04:00
static int kfd_resume ( struct kfd_dev * kfd ) ;
2014-07-16 21:08:55 +03:00
static const struct kfd_device_info * lookup_device_info ( unsigned short did )
{
size_t i ;
for ( i = 0 ; i < ARRAY_SIZE ( supported_devices ) ; i + + ) {
if ( supported_devices [ i ] . did = = did ) {
2017-08-15 23:00:12 -04:00
WARN_ON ( ! supported_devices [ i ] . device_info ) ;
2014-07-16 21:08:55 +03:00
return supported_devices [ i ] . device_info ;
}
}
2017-08-15 23:00:13 -04:00
dev_warn ( kfd_device , " DID %04x is missing in supported_devices \n " ,
did ) ;
2014-07-16 21:08:55 +03:00
return NULL ;
}
2015-03-17 19:32:53 +08:00
struct kfd_dev * kgd2kfd_probe ( struct kgd_dev * kgd ,
struct pci_dev * pdev , const struct kfd2kgd_calls * f2g )
2014-07-16 21:08:55 +03:00
{
struct kfd_dev * kfd ;
const struct kfd_device_info * device_info =
lookup_device_info ( pdev - > device ) ;
2017-08-15 23:00:13 -04:00
if ( ! device_info ) {
dev_err ( kfd_device , " kgd2kfd_probe failed \n " ) ;
2014-07-16 21:08:55 +03:00
return NULL ;
2017-08-15 23:00:13 -04:00
}
2014-07-16 21:08:55 +03:00
2018-01-04 17:17:41 -05:00
if ( device_info - > needs_pci_atomics ) {
/* Allow BIF to recode atomics to PCIe 3.0
* AtomicOps . 32 and 64 - bit requests are possible and
* must be supported .
*/
if ( pci_enable_atomic_ops_to_root ( pdev ,
PCI_EXP_DEVCAP2_ATOMIC_COMP32 |
PCI_EXP_DEVCAP2_ATOMIC_COMP64 ) < 0 ) {
dev_info ( kfd_device ,
" skipped device %x:%x, PCI rejects atomics " ,
pdev - > vendor , pdev - > device ) ;
return NULL ;
}
}
2014-07-16 21:08:55 +03:00
kfd = kzalloc ( sizeof ( * kfd ) , GFP_KERNEL ) ;
if ( ! kfd )
return NULL ;
kfd - > kgd = kgd ;
kfd - > device_info = device_info ;
kfd - > pdev = pdev ;
2014-07-16 23:25:31 +03:00
kfd - > init_complete = false ;
2015-03-17 19:32:53 +08:00
kfd - > kfd2kgd = f2g ;
mutex_init ( & kfd - > doorbell_mutex ) ;
memset ( & kfd - > doorbell_available_index , 0 ,
sizeof ( kfd - > doorbell_available_index ) ) ;
2014-07-16 21:08:55 +03:00
return kfd ;
}
2017-11-14 16:41:19 -05:00
static void kfd_cwsr_init ( struct kfd_dev * kfd )
{
if ( cwsr_enable & & kfd - > device_info - > supports_cwsr ) {
BUILD_BUG_ON ( sizeof ( cwsr_trap_gfx8_hex ) > PAGE_SIZE ) ;
kfd - > cwsr_isa = cwsr_trap_gfx8_hex ;
kfd - > cwsr_isa_size = sizeof ( cwsr_trap_gfx8_hex ) ;
kfd - > cwsr_enabled = true ;
}
}
2014-07-16 21:08:55 +03:00
bool kgd2kfd_device_init ( struct kfd_dev * kfd ,
const struct kgd2kfd_shared_resources * gpu_resources )
{
2014-07-16 23:25:31 +03:00
unsigned int size ;
2014-07-16 21:08:55 +03:00
kfd - > shared_resources = * gpu_resources ;
2017-09-20 18:10:18 -04:00
kfd - > vm_info . first_vmid_kfd = ffs ( gpu_resources - > compute_vmid_bitmap ) - 1 ;
kfd - > vm_info . last_vmid_kfd = fls ( gpu_resources - > compute_vmid_bitmap ) - 1 ;
kfd - > vm_info . vmid_num_kfd = kfd - > vm_info . last_vmid_kfd
- kfd - > vm_info . first_vmid_kfd + 1 ;
2017-11-27 18:29:45 -05:00
/* Verify module parameters regarding mapped process number*/
if ( ( hws_max_conc_proc < 0 )
| | ( hws_max_conc_proc > kfd - > vm_info . vmid_num_kfd ) ) {
dev_err ( kfd_device ,
" hws_max_conc_proc %d must be between 0 and %d, use %d instead \n " ,
hws_max_conc_proc , kfd - > vm_info . vmid_num_kfd ,
kfd - > vm_info . vmid_num_kfd ) ;
kfd - > max_proc_per_quantum = kfd - > vm_info . vmid_num_kfd ;
} else
kfd - > max_proc_per_quantum = hws_max_conc_proc ;
2014-07-16 23:25:31 +03:00
/* calculate max size of mqds needed for queues */
2015-01-18 13:18:01 +02:00
size = max_num_of_queues_per_device *
kfd - > device_info - > mqd_size_aligned ;
2014-07-16 23:25:31 +03:00
2014-10-26 10:12:22 +02:00
/*
* calculate max size of runlist packet .
* There can be only 2 packets at once
*/
2017-08-15 23:00:15 -04:00
size + = ( KFD_MAX_NUM_OF_PROCESSES * sizeof ( struct pm4_mes_map_process ) +
max_num_of_queues_per_device * sizeof ( struct pm4_mes_map_queues )
+ sizeof ( struct pm4_mes_runlist ) ) * 2 ;
2014-10-26 10:12:22 +02:00
/* Add size of HIQ & DIQ */
size + = KFD_KERNEL_QUEUE_SIZE * 2 ;
/* add another 512KB for all other allocations on gart (HPD, fences) */
2014-07-16 23:25:31 +03:00
size + = 512 * 1024 ;
2015-03-17 19:32:53 +08:00
if ( kfd - > kfd2kgd - > init_gtt_mem_allocation (
kfd - > kgd , size , & kfd - > gtt_mem ,
& kfd - > gtt_start_gpu_addr , & kfd - > gtt_start_cpu_ptr ) ) {
2017-08-15 23:00:05 -04:00
dev_err ( kfd_device , " Could not allocate %d bytes \n " , size ) ;
2014-07-16 23:25:31 +03:00
goto out ;
}
2017-08-15 23:00:05 -04:00
dev_info ( kfd_device , " Allocated %d bytes on gart \n " , size ) ;
2014-10-26 10:12:22 +02:00
2014-10-26 09:53:37 +02:00
/* Initialize GTT sa with 512 byte chunk size */
if ( kfd_gtt_sa_init ( kfd , size , 512 ) ! = 0 ) {
2017-08-15 23:00:05 -04:00
dev_err ( kfd_device , " Error initializing gtt sub-allocator \n " ) ;
2014-10-26 09:53:37 +02:00
goto kfd_gtt_sa_init_error ;
}
2017-08-15 23:00:10 -04:00
if ( kfd_doorbell_init ( kfd ) ) {
dev_err ( kfd_device ,
" Error initializing doorbell aperture \n " ) ;
goto kfd_doorbell_error ;
}
2014-07-16 23:25:31 +03:00
2017-08-15 23:00:06 -04:00
if ( kfd_topology_add_device ( kfd ) ) {
2017-08-15 23:00:05 -04:00
dev_err ( kfd_device , " Error adding device to topology \n " ) ;
2014-07-16 23:25:31 +03:00
goto kfd_topology_add_device_error ;
}
2014-07-17 01:37:30 +03:00
if ( kfd_interrupt_init ( kfd ) ) {
2017-08-15 23:00:05 -04:00
dev_err ( kfd_device , " Error initializing interrupts \n " ) ;
2014-07-17 01:37:30 +03:00
goto kfd_interrupt_error ;
}
2014-07-17 01:27:00 +03:00
kfd - > dqm = device_queue_manager_init ( kfd ) ;
if ( ! kfd - > dqm ) {
2017-08-15 23:00:05 -04:00
dev_err ( kfd_device , " Error initializing queue manager \n " ) ;
2014-07-17 01:27:00 +03:00
goto device_queue_manager_error ;
}
2017-12-08 19:22:12 -05:00
if ( kfd_iommu_device_init ( kfd ) ) {
dev_err ( kfd_device , " Error initializing iommuv2 \n " ) ;
goto device_iommu_error ;
2014-07-17 01:27:00 +03:00
}
2017-11-14 16:41:19 -05:00
kfd_cwsr_init ( kfd ) ;
2017-09-20 18:10:13 -04:00
if ( kfd_resume ( kfd ) )
goto kfd_resume_error ;
2015-05-20 13:48:26 +03:00
kfd - > dbgmgr = NULL ;
2014-07-16 21:08:55 +03:00
kfd - > init_complete = true ;
2017-08-15 23:00:05 -04:00
dev_info ( kfd_device , " added device %x:%x \n " , kfd - > pdev - > vendor ,
2014-07-16 21:08:55 +03:00
kfd - > pdev - > device ) ;
2017-08-15 23:00:05 -04:00
pr_debug ( " Starting kfd with the following scheduling policy %d \n " ,
2018-01-04 17:17:43 -05:00
kfd - > dqm - > sched_policy ) ;
2014-07-17 01:27:00 +03:00
2014-07-16 23:25:31 +03:00
goto out ;
2017-09-20 18:10:13 -04:00
kfd_resume_error :
2017-12-08 19:22:12 -05:00
device_iommu_error :
2014-07-17 01:27:00 +03:00
device_queue_manager_uninit ( kfd - > dqm ) ;
device_queue_manager_error :
2014-07-17 01:37:30 +03:00
kfd_interrupt_exit ( kfd ) ;
kfd_interrupt_error :
2014-07-17 00:06:27 +03:00
kfd_topology_remove_device ( kfd ) ;
2014-07-16 23:25:31 +03:00
kfd_topology_add_device_error :
2017-08-15 23:00:10 -04:00
kfd_doorbell_fini ( kfd ) ;
kfd_doorbell_error :
2014-10-26 09:53:37 +02:00
kfd_gtt_sa_fini ( kfd ) ;
kfd_gtt_sa_init_error :
2015-03-17 19:32:53 +08:00
kfd - > kfd2kgd - > free_gtt_mem ( kfd - > kgd , kfd - > gtt_mem ) ;
2014-07-16 23:25:31 +03:00
dev_err ( kfd_device ,
2017-08-15 23:00:05 -04:00
" device %x:%x NOT added due to errors \n " ,
2014-07-16 23:25:31 +03:00
kfd - > pdev - > vendor , kfd - > pdev - > device ) ;
out :
return kfd - > init_complete ;
2014-07-16 21:08:55 +03:00
}
void kgd2kfd_device_exit ( struct kfd_dev * kfd )
{
2014-07-17 00:06:27 +03:00
if ( kfd - > init_complete ) {
2017-09-20 18:10:13 -04:00
kgd2kfd_suspend ( kfd ) ;
2014-07-17 01:27:00 +03:00
device_queue_manager_uninit ( kfd - > dqm ) ;
2014-07-17 01:37:30 +03:00
kfd_interrupt_exit ( kfd ) ;
2014-07-17 00:06:27 +03:00
kfd_topology_remove_device ( kfd ) ;
2017-08-15 23:00:10 -04:00
kfd_doorbell_fini ( kfd ) ;
2014-10-26 09:53:37 +02:00
kfd_gtt_sa_fini ( kfd ) ;
2015-03-17 19:32:53 +08:00
kfd - > kfd2kgd - > free_gtt_mem ( kfd - > kgd , kfd - > gtt_mem ) ;
2014-07-17 00:06:27 +03:00
}
2014-07-16 21:22:32 +03:00
2014-07-16 21:08:55 +03:00
kfree ( kfd ) ;
}
void kgd2kfd_suspend ( struct kfd_dev * kfd )
{
2017-09-20 18:10:14 -04:00
if ( ! kfd - > init_complete )
return ;
2018-02-06 20:32:45 -05:00
/* For first KFD device suspend all the KFD processes */
if ( atomic_inc_return ( & kfd_device_suspended ) = = 1 )
kfd_suspend_all_processes ( ) ;
2017-09-20 18:10:14 -04:00
kfd - > dqm - > ops . stop ( kfd - > dqm ) ;
2017-12-08 19:22:12 -05:00
kfd_iommu_suspend ( kfd ) ;
2014-07-16 21:08:55 +03:00
}
int kgd2kfd_resume ( struct kfd_dev * kfd )
{
2018-02-06 20:32:45 -05:00
int ret , count ;
2017-09-20 18:10:13 -04:00
if ( ! kfd - > init_complete )
return 0 ;
2014-07-17 00:06:27 +03:00
2018-02-06 20:32:45 -05:00
ret = kfd_resume ( kfd ) ;
if ( ret )
return ret ;
count = atomic_dec_return ( & kfd_device_suspended ) ;
WARN_ONCE ( count < 0 , " KFD suspend / resume ref. error " ) ;
if ( count = = 0 )
ret = kfd_resume_all_processes ( ) ;
2014-07-17 00:06:27 +03:00
2018-02-06 20:32:45 -05:00
return ret ;
2017-09-20 18:10:13 -04:00
}
static int kfd_resume ( struct kfd_dev * kfd )
{
int err = 0 ;
2017-12-08 19:22:12 -05:00
err = kfd_iommu_resume ( kfd ) ;
if ( err ) {
dev_err ( kfd_device ,
" Failed to resume IOMMU for device %x:%x \n " ,
kfd - > pdev - > vendor , kfd - > pdev - > device ) ;
return err ;
}
2017-09-20 18:10:14 -04:00
2017-09-20 18:10:13 -04:00
err = kfd - > dqm - > ops . start ( kfd - > dqm ) ;
if ( err ) {
dev_err ( kfd_device ,
" Error starting queue manager for device %x:%x \n " ,
kfd - > pdev - > vendor , kfd - > pdev - > device ) ;
goto dqm_start_error ;
2014-07-17 00:06:27 +03:00
}
2017-09-20 18:10:13 -04:00
return err ;
dqm_start_error :
2017-12-08 19:22:12 -05:00
kfd_iommu_suspend ( kfd ) ;
2017-09-20 18:10:13 -04:00
return err ;
2014-07-16 21:08:55 +03:00
}
2014-07-17 01:37:30 +03:00
/* This is called directly from KGD at ISR. */
void kgd2kfd_interrupt ( struct kfd_dev * kfd , const void * ih_ring_entry )
2014-07-16 21:08:55 +03:00
{
2014-07-17 01:37:30 +03:00
if ( ! kfd - > init_complete )
return ;
spin_lock ( & kfd - > interrupt_lock ) ;
if ( kfd - > interrupts_active
& & interrupt_is_wanted ( kfd , ih_ring_entry )
& & enqueue_ih_ring_entry ( kfd , ih_ring_entry ) )
2017-10-27 19:35:34 -04:00
queue_work ( kfd - > ih_wq , & kfd - > interrupt_work ) ;
2014-07-17 01:37:30 +03:00
spin_unlock ( & kfd - > interrupt_lock ) ;
2014-07-16 21:08:55 +03:00
}
2014-10-27 14:36:07 +02:00
2018-02-06 20:32:45 -05:00
/** kgd2kfd_schedule_evict_and_restore_process - Schedules work queue that will
* prepare for safe eviction of KFD BOs that belong to the specified
* process .
*
* @ mm : mm_struct that identifies the specified KFD process
* @ fence : eviction fence attached to KFD process BOs
*
*/
int kgd2kfd_schedule_evict_and_restore_process ( struct mm_struct * mm ,
struct dma_fence * fence )
{
struct kfd_process * p ;
unsigned long active_time ;
unsigned long delay_jiffies = msecs_to_jiffies ( PROCESS_ACTIVE_TIME_MS ) ;
if ( ! fence )
return - EINVAL ;
if ( dma_fence_is_signaled ( fence ) )
return 0 ;
p = kfd_lookup_process_by_mm ( mm ) ;
if ( ! p )
return - ENODEV ;
if ( fence - > seqno = = p - > last_eviction_seqno )
goto out ;
p - > last_eviction_seqno = fence - > seqno ;
/* Avoid KFD process starvation. Wait for at least
* PROCESS_ACTIVE_TIME_MS before evicting the process again
*/
active_time = get_jiffies_64 ( ) - p - > last_restore_timestamp ;
if ( delay_jiffies > active_time )
delay_jiffies - = active_time ;
else
delay_jiffies = 0 ;
/* During process initialization eviction_work.dwork is initialized
* to kfd_evict_bo_worker
*/
schedule_delayed_work ( & p - > eviction_work , delay_jiffies ) ;
out :
kfd_unref_process ( p ) ;
return 0 ;
}
2014-10-27 14:36:07 +02:00
static int kfd_gtt_sa_init ( struct kfd_dev * kfd , unsigned int buf_size ,
unsigned int chunk_size )
{
2017-08-15 23:00:11 -04:00
unsigned int num_of_longs ;
2014-10-27 14:36:07 +02:00
2017-08-15 23:00:12 -04:00
if ( WARN_ON ( buf_size < chunk_size ) )
return - EINVAL ;
if ( WARN_ON ( buf_size = = 0 ) )
return - EINVAL ;
if ( WARN_ON ( chunk_size = = 0 ) )
return - EINVAL ;
2014-10-27 14:36:07 +02:00
kfd - > gtt_sa_chunk_size = chunk_size ;
kfd - > gtt_sa_num_of_chunks = buf_size / chunk_size ;
2017-08-15 23:00:11 -04:00
num_of_longs = ( kfd - > gtt_sa_num_of_chunks + BITS_PER_LONG - 1 ) /
BITS_PER_LONG ;
2014-10-27 14:36:07 +02:00
2017-08-15 23:00:11 -04:00
kfd - > gtt_sa_bitmap = kcalloc ( num_of_longs , sizeof ( long ) , GFP_KERNEL ) ;
2014-10-27 14:36:07 +02:00
if ( ! kfd - > gtt_sa_bitmap )
return - ENOMEM ;
2017-08-15 23:00:05 -04:00
pr_debug ( " gtt_sa_num_of_chunks = %d, gtt_sa_bitmap = %p \n " ,
2014-10-27 14:36:07 +02:00
kfd - > gtt_sa_num_of_chunks , kfd - > gtt_sa_bitmap ) ;
mutex_init ( & kfd - > gtt_sa_lock ) ;
return 0 ;
}
static void kfd_gtt_sa_fini ( struct kfd_dev * kfd )
{
mutex_destroy ( & kfd - > gtt_sa_lock ) ;
kfree ( kfd - > gtt_sa_bitmap ) ;
}
static inline uint64_t kfd_gtt_sa_calc_gpu_addr ( uint64_t start_addr ,
unsigned int bit_num ,
unsigned int chunk_size )
{
return start_addr + bit_num * chunk_size ;
}
static inline uint32_t * kfd_gtt_sa_calc_cpu_addr ( void * start_addr ,
unsigned int bit_num ,
unsigned int chunk_size )
{
return ( uint32_t * ) ( ( uint64_t ) start_addr + bit_num * chunk_size ) ;
}
int kfd_gtt_sa_allocate ( struct kfd_dev * kfd , unsigned int size ,
struct kfd_mem_obj * * mem_obj )
{
unsigned int found , start_search , cur_size ;
if ( size = = 0 )
return - EINVAL ;
if ( size > kfd - > gtt_sa_num_of_chunks * kfd - > gtt_sa_chunk_size )
return - ENOMEM ;
* mem_obj = kmalloc ( sizeof ( struct kfd_mem_obj ) , GFP_KERNEL ) ;
if ( ( * mem_obj ) = = NULL )
return - ENOMEM ;
2017-08-15 23:00:05 -04:00
pr_debug ( " Allocated mem_obj = %p for size = %d \n " , * mem_obj , size ) ;
2014-10-27 14:36:07 +02:00
start_search = 0 ;
mutex_lock ( & kfd - > gtt_sa_lock ) ;
kfd_gtt_restart_search :
/* Find the first chunk that is free */
found = find_next_zero_bit ( kfd - > gtt_sa_bitmap ,
kfd - > gtt_sa_num_of_chunks ,
start_search ) ;
2017-08-15 23:00:05 -04:00
pr_debug ( " Found = %d \n " , found ) ;
2014-10-27 14:36:07 +02:00
/* If there wasn't any free chunk, bail out */
if ( found = = kfd - > gtt_sa_num_of_chunks )
goto kfd_gtt_no_free_chunk ;
/* Update fields of mem_obj */
( * mem_obj ) - > range_start = found ;
( * mem_obj ) - > range_end = found ;
( * mem_obj ) - > gpu_addr = kfd_gtt_sa_calc_gpu_addr (
kfd - > gtt_start_gpu_addr ,
found ,
kfd - > gtt_sa_chunk_size ) ;
( * mem_obj ) - > cpu_ptr = kfd_gtt_sa_calc_cpu_addr (
kfd - > gtt_start_cpu_ptr ,
found ,
kfd - > gtt_sa_chunk_size ) ;
2017-08-15 23:00:05 -04:00
pr_debug ( " gpu_addr = %p, cpu_addr = %p \n " ,
2014-10-27 14:36:07 +02:00
( uint64_t * ) ( * mem_obj ) - > gpu_addr , ( * mem_obj ) - > cpu_ptr ) ;
/* If we need only one chunk, mark it as allocated and get out */
if ( size < = kfd - > gtt_sa_chunk_size ) {
2017-08-15 23:00:05 -04:00
pr_debug ( " Single bit \n " ) ;
2014-10-27 14:36:07 +02:00
set_bit ( found , kfd - > gtt_sa_bitmap ) ;
goto kfd_gtt_out ;
}
/* Otherwise, try to see if we have enough contiguous chunks */
cur_size = size - kfd - > gtt_sa_chunk_size ;
do {
( * mem_obj ) - > range_end =
find_next_zero_bit ( kfd - > gtt_sa_bitmap ,
kfd - > gtt_sa_num_of_chunks , + + found ) ;
/*
* If next free chunk is not contiguous than we need to
* restart our search from the last free chunk we found ( which
* wasn ' t contiguous to the previous ones
*/
if ( ( * mem_obj ) - > range_end ! = found ) {
start_search = found ;
goto kfd_gtt_restart_search ;
}
/*
* If we reached end of buffer , bail out with error
*/
if ( found = = kfd - > gtt_sa_num_of_chunks )
goto kfd_gtt_no_free_chunk ;
/* Check if we don't need another chunk */
if ( cur_size < = kfd - > gtt_sa_chunk_size )
cur_size = 0 ;
else
cur_size - = kfd - > gtt_sa_chunk_size ;
} while ( cur_size > 0 ) ;
2017-08-15 23:00:05 -04:00
pr_debug ( " range_start = %d, range_end = %d \n " ,
2014-10-27 14:36:07 +02:00
( * mem_obj ) - > range_start , ( * mem_obj ) - > range_end ) ;
/* Mark the chunks as allocated */
for ( found = ( * mem_obj ) - > range_start ;
found < = ( * mem_obj ) - > range_end ;
found + + )
set_bit ( found , kfd - > gtt_sa_bitmap ) ;
kfd_gtt_out :
mutex_unlock ( & kfd - > gtt_sa_lock ) ;
return 0 ;
kfd_gtt_no_free_chunk :
2017-08-15 23:00:05 -04:00
pr_debug ( " Allocation failed with mem_obj = %p \n " , mem_obj ) ;
2014-10-27 14:36:07 +02:00
mutex_unlock ( & kfd - > gtt_sa_lock ) ;
kfree ( mem_obj ) ;
return - ENOMEM ;
}
int kfd_gtt_sa_free ( struct kfd_dev * kfd , struct kfd_mem_obj * mem_obj )
{
unsigned int bit ;
2015-01-12 22:34:21 +02:00
/* Act like kfree when trying to free a NULL object */
if ( ! mem_obj )
return 0 ;
2014-10-27 14:36:07 +02:00
2017-08-15 23:00:05 -04:00
pr_debug ( " Free mem_obj = %p, range_start = %d, range_end = %d \n " ,
2014-10-27 14:36:07 +02:00
mem_obj , mem_obj - > range_start , mem_obj - > range_end ) ;
mutex_lock ( & kfd - > gtt_sa_lock ) ;
/* Mark the chunks as free */
for ( bit = mem_obj - > range_start ;
bit < = mem_obj - > range_end ;
bit + + )
clear_bit ( bit , kfd - > gtt_sa_bitmap ) ;
mutex_unlock ( & kfd - > gtt_sa_lock ) ;
kfree ( mem_obj ) ;
return 0 ;
}