18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2018 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 58c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 68c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 78c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 88c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 98c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 128c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 158c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 168c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 178c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 188c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 198c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 208c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "amdgpu.h" 258c2ecf20Sopenharmony_ci#include "amdgpu_sdma.h" 268c2ecf20Sopenharmony_ci#include "amdgpu_ras.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define AMDGPU_CSA_SDMA_SIZE 64 298c2ecf20Sopenharmony_ci/* SDMA CSA reside in the 3rd page of CSA */ 308c2ecf20Sopenharmony_ci#define AMDGPU_CSA_SDMA_OFFSET (4096 * 2) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * GPU SDMA IP block helpers function. 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct amdgpu_sdma_instance *amdgpu_sdma_get_instance_from_ring(struct amdgpu_ring *ring) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 398c2ecf20Sopenharmony_ci int i; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci for (i = 0; i < adev->sdma.num_instances; i++) 428c2ecf20Sopenharmony_ci if (ring == &adev->sdma.instance[i].ring || 438c2ecf20Sopenharmony_ci ring == &adev->sdma.instance[i].page) 448c2ecf20Sopenharmony_ci return &adev->sdma.instance[i]; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return NULL; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciint amdgpu_sdma_get_index_from_ring(struct amdgpu_ring *ring, uint32_t *index) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 528c2ecf20Sopenharmony_ci int i; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci for (i = 0; i < adev->sdma.num_instances; i++) { 558c2ecf20Sopenharmony_ci if (ring == &adev->sdma.instance[i].ring || 568c2ecf20Sopenharmony_ci ring == &adev->sdma.instance[i].page) { 578c2ecf20Sopenharmony_ci *index = i; 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return -EINVAL; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ciuint64_t amdgpu_sdma_get_csa_mc_addr(struct amdgpu_ring *ring, 668c2ecf20Sopenharmony_ci unsigned vmid) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 698c2ecf20Sopenharmony_ci uint64_t csa_mc_addr; 708c2ecf20Sopenharmony_ci uint32_t index = 0; 718c2ecf20Sopenharmony_ci int r; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* don't enable OS preemption on SDMA under SRIOV */ 748c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev) || vmid == 0 || !amdgpu_mcbp) 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci r = amdgpu_sdma_get_index_from_ring(ring, &index); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (r || index > 31) 808c2ecf20Sopenharmony_ci csa_mc_addr = 0; 818c2ecf20Sopenharmony_ci else 828c2ecf20Sopenharmony_ci csa_mc_addr = amdgpu_csa_vaddr(adev) + 838c2ecf20Sopenharmony_ci AMDGPU_CSA_SDMA_OFFSET + 848c2ecf20Sopenharmony_ci index * AMDGPU_CSA_SDMA_SIZE; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return csa_mc_addr; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciint amdgpu_sdma_ras_late_init(struct amdgpu_device *adev, 908c2ecf20Sopenharmony_ci void *ras_ih_info) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci int r, i; 938c2ecf20Sopenharmony_ci struct ras_ih_if *ih_info = (struct ras_ih_if *)ras_ih_info; 948c2ecf20Sopenharmony_ci struct ras_fs_if fs_info = { 958c2ecf20Sopenharmony_ci .sysfs_name = "sdma_err_count", 968c2ecf20Sopenharmony_ci }; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (!ih_info) 998c2ecf20Sopenharmony_ci return -EINVAL; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (!adev->sdma.ras_if) { 1028c2ecf20Sopenharmony_ci adev->sdma.ras_if = kmalloc(sizeof(struct ras_common_if), GFP_KERNEL); 1038c2ecf20Sopenharmony_ci if (!adev->sdma.ras_if) 1048c2ecf20Sopenharmony_ci return -ENOMEM; 1058c2ecf20Sopenharmony_ci adev->sdma.ras_if->block = AMDGPU_RAS_BLOCK__SDMA; 1068c2ecf20Sopenharmony_ci adev->sdma.ras_if->type = AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE; 1078c2ecf20Sopenharmony_ci adev->sdma.ras_if->sub_block_index = 0; 1088c2ecf20Sopenharmony_ci strcpy(adev->sdma.ras_if->name, "sdma"); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci fs_info.head = ih_info->head = *adev->sdma.ras_if; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci r = amdgpu_ras_late_init(adev, adev->sdma.ras_if, 1138c2ecf20Sopenharmony_ci &fs_info, ih_info); 1148c2ecf20Sopenharmony_ci if (r) 1158c2ecf20Sopenharmony_ci goto free; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (amdgpu_ras_is_supported(adev, adev->sdma.ras_if->block)) { 1188c2ecf20Sopenharmony_ci for (i = 0; i < adev->sdma.num_instances; i++) { 1198c2ecf20Sopenharmony_ci r = amdgpu_irq_get(adev, &adev->sdma.ecc_irq, 1208c2ecf20Sopenharmony_ci AMDGPU_SDMA_IRQ_INSTANCE0 + i); 1218c2ecf20Sopenharmony_ci if (r) 1228c2ecf20Sopenharmony_ci goto late_fini; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci } else { 1258c2ecf20Sopenharmony_ci r = 0; 1268c2ecf20Sopenharmony_ci goto free; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return 0; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cilate_fini: 1328c2ecf20Sopenharmony_ci amdgpu_ras_late_fini(adev, adev->sdma.ras_if, ih_info); 1338c2ecf20Sopenharmony_cifree: 1348c2ecf20Sopenharmony_ci kfree(adev->sdma.ras_if); 1358c2ecf20Sopenharmony_ci adev->sdma.ras_if = NULL; 1368c2ecf20Sopenharmony_ci return r; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_civoid amdgpu_sdma_ras_fini(struct amdgpu_device *adev) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA) && 1428c2ecf20Sopenharmony_ci adev->sdma.ras_if) { 1438c2ecf20Sopenharmony_ci struct ras_common_if *ras_if = adev->sdma.ras_if; 1448c2ecf20Sopenharmony_ci struct ras_ih_if ih_info = { 1458c2ecf20Sopenharmony_ci .head = *ras_if, 1468c2ecf20Sopenharmony_ci /* the cb member will not be used by 1478c2ecf20Sopenharmony_ci * amdgpu_ras_interrupt_remove_handler, init it only 1488c2ecf20Sopenharmony_ci * to cheat the check in ras_late_fini 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci .cb = amdgpu_sdma_process_ras_data_cb, 1518c2ecf20Sopenharmony_ci }; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci amdgpu_ras_late_fini(adev, ras_if, &ih_info); 1548c2ecf20Sopenharmony_ci kfree(ras_if); 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ciint amdgpu_sdma_process_ras_data_cb(struct amdgpu_device *adev, 1598c2ecf20Sopenharmony_ci void *err_data, 1608c2ecf20Sopenharmony_ci struct amdgpu_iv_entry *entry) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); 1638c2ecf20Sopenharmony_ci amdgpu_ras_reset_gpu(adev); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return AMDGPU_RAS_SUCCESS; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciint amdgpu_sdma_process_ecc_irq(struct amdgpu_device *adev, 1698c2ecf20Sopenharmony_ci struct amdgpu_irq_src *source, 1708c2ecf20Sopenharmony_ci struct amdgpu_iv_entry *entry) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct ras_common_if *ras_if = adev->sdma.ras_if; 1738c2ecf20Sopenharmony_ci struct ras_dispatch_if ih_data = { 1748c2ecf20Sopenharmony_ci .entry = entry, 1758c2ecf20Sopenharmony_ci }; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (!ras_if) 1788c2ecf20Sopenharmony_ci return 0; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ih_data.head = *ras_if; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci amdgpu_ras_interrupt_dispatch(adev, &ih_data); 1838c2ecf20Sopenharmony_ci return 0; 1848c2ecf20Sopenharmony_ci} 185