18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc. 38c2ecf20Sopenharmony_ci * Copyright 2008 Red Hat Inc. 48c2ecf20Sopenharmony_ci * Copyright 2009 Jerome Glisse. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 88c2ecf20Sopenharmony_ci * to deal in the Software without restriction, including without limitation 98c2ecf20Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 108c2ecf20Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 118c2ecf20Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 148c2ecf20Sopenharmony_ci * all copies or substantial portions of the Software. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 178c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 188c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 198c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 208c2ecf20Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 218c2ecf20Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 228c2ecf20Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Authors: Dave Airlie 258c2ecf20Sopenharmony_ci * Alex Deucher 268c2ecf20Sopenharmony_ci * Jerome Glisse 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci#include <linux/power_supply.h> 298c2ecf20Sopenharmony_ci#include <linux/kthread.h> 308c2ecf20Sopenharmony_ci#include <linux/module.h> 318c2ecf20Sopenharmony_ci#include <linux/console.h> 328c2ecf20Sopenharmony_ci#include <linux/slab.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 358c2ecf20Sopenharmony_ci#include <drm/drm_probe_helper.h> 368c2ecf20Sopenharmony_ci#include <drm/amdgpu_drm.h> 378c2ecf20Sopenharmony_ci#include <linux/vgaarb.h> 388c2ecf20Sopenharmony_ci#include <linux/vga_switcheroo.h> 398c2ecf20Sopenharmony_ci#include <linux/efi.h> 408c2ecf20Sopenharmony_ci#include "amdgpu.h" 418c2ecf20Sopenharmony_ci#include "amdgpu_trace.h" 428c2ecf20Sopenharmony_ci#include "amdgpu_i2c.h" 438c2ecf20Sopenharmony_ci#include "atom.h" 448c2ecf20Sopenharmony_ci#include "amdgpu_atombios.h" 458c2ecf20Sopenharmony_ci#include "amdgpu_atomfirmware.h" 468c2ecf20Sopenharmony_ci#include "amd_pcie.h" 478c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_SI 488c2ecf20Sopenharmony_ci#include "si.h" 498c2ecf20Sopenharmony_ci#endif 508c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 518c2ecf20Sopenharmony_ci#include "cik.h" 528c2ecf20Sopenharmony_ci#endif 538c2ecf20Sopenharmony_ci#include "vi.h" 548c2ecf20Sopenharmony_ci#include "soc15.h" 558c2ecf20Sopenharmony_ci#include "nv.h" 568c2ecf20Sopenharmony_ci#include "bif/bif_4_1_d.h" 578c2ecf20Sopenharmony_ci#include <linux/pci.h> 588c2ecf20Sopenharmony_ci#include <linux/firmware.h> 598c2ecf20Sopenharmony_ci#include "amdgpu_vf_error.h" 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#include "amdgpu_amdkfd.h" 628c2ecf20Sopenharmony_ci#include "amdgpu_pm.h" 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#include "amdgpu_xgmi.h" 658c2ecf20Sopenharmony_ci#include "amdgpu_ras.h" 668c2ecf20Sopenharmony_ci#include "amdgpu_pmu.h" 678c2ecf20Sopenharmony_ci#include "amdgpu_fru_eeprom.h" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#include <linux/suspend.h> 708c2ecf20Sopenharmony_ci#include <drm/task_barrier.h> 718c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin"); 748c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin"); 758c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/raven_gpu_info.bin"); 768c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/picasso_gpu_info.bin"); 778c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/raven2_gpu_info.bin"); 788c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/arcturus_gpu_info.bin"); 798c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/renoir_gpu_info.bin"); 808c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/navi10_gpu_info.bin"); 818c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/navi14_gpu_info.bin"); 828c2ecf20Sopenharmony_ciMODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin"); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define AMDGPU_RESUME_MS 2000 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ciconst char *amdgpu_asic_name[] = { 878c2ecf20Sopenharmony_ci "TAHITI", 888c2ecf20Sopenharmony_ci "PITCAIRN", 898c2ecf20Sopenharmony_ci "VERDE", 908c2ecf20Sopenharmony_ci "OLAND", 918c2ecf20Sopenharmony_ci "HAINAN", 928c2ecf20Sopenharmony_ci "BONAIRE", 938c2ecf20Sopenharmony_ci "KAVERI", 948c2ecf20Sopenharmony_ci "KABINI", 958c2ecf20Sopenharmony_ci "HAWAII", 968c2ecf20Sopenharmony_ci "MULLINS", 978c2ecf20Sopenharmony_ci "TOPAZ", 988c2ecf20Sopenharmony_ci "TONGA", 998c2ecf20Sopenharmony_ci "FIJI", 1008c2ecf20Sopenharmony_ci "CARRIZO", 1018c2ecf20Sopenharmony_ci "STONEY", 1028c2ecf20Sopenharmony_ci "POLARIS10", 1038c2ecf20Sopenharmony_ci "POLARIS11", 1048c2ecf20Sopenharmony_ci "POLARIS12", 1058c2ecf20Sopenharmony_ci "VEGAM", 1068c2ecf20Sopenharmony_ci "VEGA10", 1078c2ecf20Sopenharmony_ci "VEGA12", 1088c2ecf20Sopenharmony_ci "VEGA20", 1098c2ecf20Sopenharmony_ci "RAVEN", 1108c2ecf20Sopenharmony_ci "ARCTURUS", 1118c2ecf20Sopenharmony_ci "RENOIR", 1128c2ecf20Sopenharmony_ci "NAVI10", 1138c2ecf20Sopenharmony_ci "NAVI14", 1148c2ecf20Sopenharmony_ci "NAVI12", 1158c2ecf20Sopenharmony_ci "SIENNA_CICHLID", 1168c2ecf20Sopenharmony_ci "NAVY_FLOUNDER", 1178c2ecf20Sopenharmony_ci "LAST", 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/** 1218c2ecf20Sopenharmony_ci * DOC: pcie_replay_count 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * The amdgpu driver provides a sysfs API for reporting the total number 1248c2ecf20Sopenharmony_ci * of PCIe replays (NAKs) 1258c2ecf20Sopenharmony_ci * The file pcie_replay_count is used for this and returns the total 1268c2ecf20Sopenharmony_ci * number of replays as a sum of the NAKs generated and NAKs received 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic ssize_t amdgpu_device_get_pcie_replay_count(struct device *dev, 1308c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct drm_device *ddev = dev_get_drvdata(dev); 1338c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(ddev); 1348c2ecf20Sopenharmony_ci uint64_t cnt = amdgpu_asic_get_pcie_replay_count(adev); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%llu\n", cnt); 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pcie_replay_count, S_IRUGO, 1408c2ecf20Sopenharmony_ci amdgpu_device_get_pcie_replay_count, NULL); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void amdgpu_device_get_pcie_info(struct amdgpu_device *adev); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/** 1458c2ecf20Sopenharmony_ci * DOC: product_name 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * The amdgpu driver provides a sysfs API for reporting the product name 1488c2ecf20Sopenharmony_ci * for the device 1498c2ecf20Sopenharmony_ci * The file serial_number is used for this and returns the product name 1508c2ecf20Sopenharmony_ci * as returned from the FRU. 1518c2ecf20Sopenharmony_ci * NOTE: This is only available for certain server cards 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic ssize_t amdgpu_device_get_product_name(struct device *dev, 1558c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct drm_device *ddev = dev_get_drvdata(dev); 1588c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(ddev); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", adev->product_name); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic DEVICE_ATTR(product_name, S_IRUGO, 1648c2ecf20Sopenharmony_ci amdgpu_device_get_product_name, NULL); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * DOC: product_number 1688c2ecf20Sopenharmony_ci * 1698c2ecf20Sopenharmony_ci * The amdgpu driver provides a sysfs API for reporting the part number 1708c2ecf20Sopenharmony_ci * for the device 1718c2ecf20Sopenharmony_ci * The file serial_number is used for this and returns the part number 1728c2ecf20Sopenharmony_ci * as returned from the FRU. 1738c2ecf20Sopenharmony_ci * NOTE: This is only available for certain server cards 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic ssize_t amdgpu_device_get_product_number(struct device *dev, 1778c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci struct drm_device *ddev = dev_get_drvdata(dev); 1808c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(ddev); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", adev->product_number); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic DEVICE_ATTR(product_number, S_IRUGO, 1868c2ecf20Sopenharmony_ci amdgpu_device_get_product_number, NULL); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/** 1898c2ecf20Sopenharmony_ci * DOC: serial_number 1908c2ecf20Sopenharmony_ci * 1918c2ecf20Sopenharmony_ci * The amdgpu driver provides a sysfs API for reporting the serial number 1928c2ecf20Sopenharmony_ci * for the device 1938c2ecf20Sopenharmony_ci * The file serial_number is used for this and returns the serial number 1948c2ecf20Sopenharmony_ci * as returned from the FRU. 1958c2ecf20Sopenharmony_ci * NOTE: This is only available for certain server cards 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic ssize_t amdgpu_device_get_serial_number(struct device *dev, 1998c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct drm_device *ddev = dev_get_drvdata(dev); 2028c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(ddev); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", adev->serial); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic DEVICE_ATTR(serial_number, S_IRUGO, 2088c2ecf20Sopenharmony_ci amdgpu_device_get_serial_number, NULL); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/** 2118c2ecf20Sopenharmony_ci * amdgpu_device_supports_boco - Is the device a dGPU with HG/PX power control 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * @dev: drm_device pointer 2148c2ecf20Sopenharmony_ci * 2158c2ecf20Sopenharmony_ci * Returns true if the device is a dGPU with HG/PX power control, 2168c2ecf20Sopenharmony_ci * otherwise return false. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_cibool amdgpu_device_supports_boco(struct drm_device *dev) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (adev->flags & AMD_IS_PX) 2238c2ecf20Sopenharmony_ci return true; 2248c2ecf20Sopenharmony_ci return false; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * amdgpu_device_supports_baco - Does the device support BACO 2298c2ecf20Sopenharmony_ci * 2308c2ecf20Sopenharmony_ci * @dev: drm_device pointer 2318c2ecf20Sopenharmony_ci * 2328c2ecf20Sopenharmony_ci * Returns true if the device supporte BACO, 2338c2ecf20Sopenharmony_ci * otherwise return false. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_cibool amdgpu_device_supports_baco(struct drm_device *dev) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci return amdgpu_asic_supports_baco(adev); 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* 2438c2ecf20Sopenharmony_ci * VRAM access helper functions 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/** 2478c2ecf20Sopenharmony_ci * amdgpu_device_vram_access - read/write a buffer in vram 2488c2ecf20Sopenharmony_ci * 2498c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 2508c2ecf20Sopenharmony_ci * @pos: offset of the buffer in vram 2518c2ecf20Sopenharmony_ci * @buf: virtual address of the buffer in system memory 2528c2ecf20Sopenharmony_ci * @size: read/write size, sizeof(@buf) must > @size 2538c2ecf20Sopenharmony_ci * @write: true - write to vram, otherwise - read from vram 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_civoid amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, 2568c2ecf20Sopenharmony_ci uint32_t *buf, size_t size, bool write) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci unsigned long flags; 2598c2ecf20Sopenharmony_ci uint32_t hi = ~0; 2608c2ecf20Sopenharmony_ci uint64_t last; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT 2648c2ecf20Sopenharmony_ci last = min(pos + size, adev->gmc.visible_vram_size); 2658c2ecf20Sopenharmony_ci if (last > pos) { 2668c2ecf20Sopenharmony_ci void __iomem *addr = adev->mman.aper_base_kaddr + pos; 2678c2ecf20Sopenharmony_ci size_t count = last - pos; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (write) { 2708c2ecf20Sopenharmony_ci memcpy_toio(addr, buf, count); 2718c2ecf20Sopenharmony_ci mb(); 2728c2ecf20Sopenharmony_ci amdgpu_asic_flush_hdp(adev, NULL); 2738c2ecf20Sopenharmony_ci } else { 2748c2ecf20Sopenharmony_ci amdgpu_asic_invalidate_hdp(adev, NULL); 2758c2ecf20Sopenharmony_ci mb(); 2768c2ecf20Sopenharmony_ci memcpy_fromio(buf, addr, count); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (count == size) 2808c2ecf20Sopenharmony_ci return; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci pos += count; 2838c2ecf20Sopenharmony_ci buf += count / 4; 2848c2ecf20Sopenharmony_ci size -= count; 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci#endif 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci spin_lock_irqsave(&adev->mmio_idx_lock, flags); 2898c2ecf20Sopenharmony_ci for (last = pos + size; pos < last; pos += 4) { 2908c2ecf20Sopenharmony_ci uint32_t tmp = pos >> 31; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t)pos) | 0x80000000); 2938c2ecf20Sopenharmony_ci if (tmp != hi) { 2948c2ecf20Sopenharmony_ci WREG32_NO_KIQ(mmMM_INDEX_HI, tmp); 2958c2ecf20Sopenharmony_ci hi = tmp; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci if (write) 2988c2ecf20Sopenharmony_ci WREG32_NO_KIQ(mmMM_DATA, *buf++); 2998c2ecf20Sopenharmony_ci else 3008c2ecf20Sopenharmony_ci *buf++ = RREG32_NO_KIQ(mmMM_DATA); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adev->mmio_idx_lock, flags); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/* 3068c2ecf20Sopenharmony_ci * register access helper functions. 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ci/** 3098c2ecf20Sopenharmony_ci * amdgpu_device_rreg - read a memory mapped IO or indirect register 3108c2ecf20Sopenharmony_ci * 3118c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 3128c2ecf20Sopenharmony_ci * @reg: dword aligned register offset 3138c2ecf20Sopenharmony_ci * @acc_flags: access flags which require special behavior 3148c2ecf20Sopenharmony_ci * 3158c2ecf20Sopenharmony_ci * Returns the 32 bit value from the offset specified. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ciuint32_t amdgpu_device_rreg(struct amdgpu_device *adev, 3188c2ecf20Sopenharmony_ci uint32_t reg, uint32_t acc_flags) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci uint32_t ret; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 3238c2ecf20Sopenharmony_ci return 0; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if ((reg * 4) < adev->rmmio_size) { 3268c2ecf20Sopenharmony_ci if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && 3278c2ecf20Sopenharmony_ci amdgpu_sriov_runtime(adev) && 3288c2ecf20Sopenharmony_ci down_read_trylock(&adev->reset_sem)) { 3298c2ecf20Sopenharmony_ci ret = amdgpu_kiq_rreg(adev, reg); 3308c2ecf20Sopenharmony_ci up_read(&adev->reset_sem); 3318c2ecf20Sopenharmony_ci } else { 3328c2ecf20Sopenharmony_ci ret = readl(((void __iomem *)adev->rmmio) + (reg * 4)); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } else { 3358c2ecf20Sopenharmony_ci ret = adev->pcie_rreg(adev, reg * 4); 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci trace_amdgpu_device_rreg(adev->pdev->device, reg, ret); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return ret; 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/* 3448c2ecf20Sopenharmony_ci * MMIO register read with bytes helper functions 3458c2ecf20Sopenharmony_ci * @offset:bytes offset from MMIO start 3468c2ecf20Sopenharmony_ci * 3478c2ecf20Sopenharmony_ci*/ 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/** 3508c2ecf20Sopenharmony_ci * amdgpu_mm_rreg8 - read a memory mapped IO register 3518c2ecf20Sopenharmony_ci * 3528c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 3538c2ecf20Sopenharmony_ci * @offset: byte aligned register offset 3548c2ecf20Sopenharmony_ci * 3558c2ecf20Sopenharmony_ci * Returns the 8 bit value from the offset specified. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ciuint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (offset < adev->rmmio_size) 3638c2ecf20Sopenharmony_ci return (readb(adev->rmmio + offset)); 3648c2ecf20Sopenharmony_ci BUG(); 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci/* 3688c2ecf20Sopenharmony_ci * MMIO register write with bytes helper functions 3698c2ecf20Sopenharmony_ci * @offset:bytes offset from MMIO start 3708c2ecf20Sopenharmony_ci * @value: the value want to be written to the register 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci*/ 3738c2ecf20Sopenharmony_ci/** 3748c2ecf20Sopenharmony_ci * amdgpu_mm_wreg8 - read a memory mapped IO register 3758c2ecf20Sopenharmony_ci * 3768c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 3778c2ecf20Sopenharmony_ci * @offset: byte aligned register offset 3788c2ecf20Sopenharmony_ci * @value: 8 bit value to write 3798c2ecf20Sopenharmony_ci * 3808c2ecf20Sopenharmony_ci * Writes the value specified to the offset specified. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_civoid amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 3858c2ecf20Sopenharmony_ci return; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (offset < adev->rmmio_size) 3888c2ecf20Sopenharmony_ci writeb(value, adev->rmmio + offset); 3898c2ecf20Sopenharmony_ci else 3908c2ecf20Sopenharmony_ci BUG(); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci/** 3948c2ecf20Sopenharmony_ci * amdgpu_device_wreg - write to a memory mapped IO or indirect register 3958c2ecf20Sopenharmony_ci * 3968c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 3978c2ecf20Sopenharmony_ci * @reg: dword aligned register offset 3988c2ecf20Sopenharmony_ci * @v: 32 bit value to write to the register 3998c2ecf20Sopenharmony_ci * @acc_flags: access flags which require special behavior 4008c2ecf20Sopenharmony_ci * 4018c2ecf20Sopenharmony_ci * Writes the value specified to the offset specified. 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_civoid amdgpu_device_wreg(struct amdgpu_device *adev, 4048c2ecf20Sopenharmony_ci uint32_t reg, uint32_t v, 4058c2ecf20Sopenharmony_ci uint32_t acc_flags) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 4088c2ecf20Sopenharmony_ci return; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if ((reg * 4) < adev->rmmio_size) { 4118c2ecf20Sopenharmony_ci if (!(acc_flags & AMDGPU_REGS_NO_KIQ) && 4128c2ecf20Sopenharmony_ci amdgpu_sriov_runtime(adev) && 4138c2ecf20Sopenharmony_ci down_read_trylock(&adev->reset_sem)) { 4148c2ecf20Sopenharmony_ci amdgpu_kiq_wreg(adev, reg, v); 4158c2ecf20Sopenharmony_ci up_read(&adev->reset_sem); 4168c2ecf20Sopenharmony_ci } else { 4178c2ecf20Sopenharmony_ci writel(v, ((void __iomem *)adev->rmmio) + (reg * 4)); 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } else { 4208c2ecf20Sopenharmony_ci adev->pcie_wreg(adev, reg * 4, v); 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci trace_amdgpu_device_wreg(adev->pdev->device, reg, v); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/* 4278c2ecf20Sopenharmony_ci * amdgpu_mm_wreg_mmio_rlc - write register either with mmio or with RLC path if in range 4288c2ecf20Sopenharmony_ci * 4298c2ecf20Sopenharmony_ci * this function is invoked only the debugfs register access 4308c2ecf20Sopenharmony_ci * */ 4318c2ecf20Sopenharmony_civoid amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev, 4328c2ecf20Sopenharmony_ci uint32_t reg, uint32_t v) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 4358c2ecf20Sopenharmony_ci return; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (amdgpu_sriov_fullaccess(adev) && 4388c2ecf20Sopenharmony_ci adev->gfx.rlc.funcs && 4398c2ecf20Sopenharmony_ci adev->gfx.rlc.funcs->is_rlcg_access_range) { 4408c2ecf20Sopenharmony_ci if (adev->gfx.rlc.funcs->is_rlcg_access_range(adev, reg)) 4418c2ecf20Sopenharmony_ci return adev->gfx.rlc.funcs->rlcg_wreg(adev, reg, v); 4428c2ecf20Sopenharmony_ci } else { 4438c2ecf20Sopenharmony_ci writel(v, ((void __iomem *)adev->rmmio) + (reg * 4)); 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/** 4488c2ecf20Sopenharmony_ci * amdgpu_io_rreg - read an IO register 4498c2ecf20Sopenharmony_ci * 4508c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 4518c2ecf20Sopenharmony_ci * @reg: dword aligned register offset 4528c2ecf20Sopenharmony_ci * 4538c2ecf20Sopenharmony_ci * Returns the 32 bit value from the offset specified. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_ciu32 amdgpu_io_rreg(struct amdgpu_device *adev, u32 reg) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci if ((reg * 4) < adev->rio_mem_size) 4618c2ecf20Sopenharmony_ci return ioread32(adev->rio_mem + (reg * 4)); 4628c2ecf20Sopenharmony_ci else { 4638c2ecf20Sopenharmony_ci iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4)); 4648c2ecf20Sopenharmony_ci return ioread32(adev->rio_mem + (mmMM_DATA * 4)); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci/** 4698c2ecf20Sopenharmony_ci * amdgpu_io_wreg - write to an IO register 4708c2ecf20Sopenharmony_ci * 4718c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 4728c2ecf20Sopenharmony_ci * @reg: dword aligned register offset 4738c2ecf20Sopenharmony_ci * @v: 32 bit value to write to the register 4748c2ecf20Sopenharmony_ci * 4758c2ecf20Sopenharmony_ci * Writes the value specified to the offset specified. 4768c2ecf20Sopenharmony_ci */ 4778c2ecf20Sopenharmony_civoid amdgpu_io_wreg(struct amdgpu_device *adev, u32 reg, u32 v) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 4808c2ecf20Sopenharmony_ci return; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci if ((reg * 4) < adev->rio_mem_size) 4838c2ecf20Sopenharmony_ci iowrite32(v, adev->rio_mem + (reg * 4)); 4848c2ecf20Sopenharmony_ci else { 4858c2ecf20Sopenharmony_ci iowrite32((reg * 4), adev->rio_mem + (mmMM_INDEX * 4)); 4868c2ecf20Sopenharmony_ci iowrite32(v, adev->rio_mem + (mmMM_DATA * 4)); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci/** 4918c2ecf20Sopenharmony_ci * amdgpu_mm_rdoorbell - read a doorbell dword 4928c2ecf20Sopenharmony_ci * 4938c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 4948c2ecf20Sopenharmony_ci * @index: doorbell index 4958c2ecf20Sopenharmony_ci * 4968c2ecf20Sopenharmony_ci * Returns the value in the doorbell aperture at the 4978c2ecf20Sopenharmony_ci * requested doorbell index (CIK). 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_ciu32 amdgpu_mm_rdoorbell(struct amdgpu_device *adev, u32 index) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (index < adev->doorbell.num_doorbells) { 5058c2ecf20Sopenharmony_ci return readl(adev->doorbell.ptr + index); 5068c2ecf20Sopenharmony_ci } else { 5078c2ecf20Sopenharmony_ci DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index); 5088c2ecf20Sopenharmony_ci return 0; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/** 5138c2ecf20Sopenharmony_ci * amdgpu_mm_wdoorbell - write a doorbell dword 5148c2ecf20Sopenharmony_ci * 5158c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 5168c2ecf20Sopenharmony_ci * @index: doorbell index 5178c2ecf20Sopenharmony_ci * @v: value to write 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * Writes @v to the doorbell aperture at the 5208c2ecf20Sopenharmony_ci * requested doorbell index (CIK). 5218c2ecf20Sopenharmony_ci */ 5228c2ecf20Sopenharmony_civoid amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v) 5238c2ecf20Sopenharmony_ci{ 5248c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 5258c2ecf20Sopenharmony_ci return; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if (index < adev->doorbell.num_doorbells) { 5288c2ecf20Sopenharmony_ci writel(v, adev->doorbell.ptr + index); 5298c2ecf20Sopenharmony_ci } else { 5308c2ecf20Sopenharmony_ci DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/** 5358c2ecf20Sopenharmony_ci * amdgpu_mm_rdoorbell64 - read a doorbell Qword 5368c2ecf20Sopenharmony_ci * 5378c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 5388c2ecf20Sopenharmony_ci * @index: doorbell index 5398c2ecf20Sopenharmony_ci * 5408c2ecf20Sopenharmony_ci * Returns the value in the doorbell aperture at the 5418c2ecf20Sopenharmony_ci * requested doorbell index (VEGA10+). 5428c2ecf20Sopenharmony_ci */ 5438c2ecf20Sopenharmony_ciu64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 5468c2ecf20Sopenharmony_ci return 0; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci if (index < adev->doorbell.num_doorbells) { 5498c2ecf20Sopenharmony_ci return atomic64_read((atomic64_t *)(adev->doorbell.ptr + index)); 5508c2ecf20Sopenharmony_ci } else { 5518c2ecf20Sopenharmony_ci DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index); 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/** 5578c2ecf20Sopenharmony_ci * amdgpu_mm_wdoorbell64 - write a doorbell Qword 5588c2ecf20Sopenharmony_ci * 5598c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 5608c2ecf20Sopenharmony_ci * @index: doorbell index 5618c2ecf20Sopenharmony_ci * @v: value to write 5628c2ecf20Sopenharmony_ci * 5638c2ecf20Sopenharmony_ci * Writes @v to the doorbell aperture at the 5648c2ecf20Sopenharmony_ci * requested doorbell index (VEGA10+). 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_civoid amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci if (adev->in_pci_err_recovery) 5698c2ecf20Sopenharmony_ci return; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (index < adev->doorbell.num_doorbells) { 5728c2ecf20Sopenharmony_ci atomic64_set((atomic64_t *)(adev->doorbell.ptr + index), v); 5738c2ecf20Sopenharmony_ci } else { 5748c2ecf20Sopenharmony_ci DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci} 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci/** 5798c2ecf20Sopenharmony_ci * amdgpu_device_indirect_rreg - read an indirect register 5808c2ecf20Sopenharmony_ci * 5818c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 5828c2ecf20Sopenharmony_ci * @pcie_index: mmio register offset 5838c2ecf20Sopenharmony_ci * @pcie_data: mmio register offset 5848c2ecf20Sopenharmony_ci * 5858c2ecf20Sopenharmony_ci * Returns the value of indirect register @reg_addr 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_ciu32 amdgpu_device_indirect_rreg(struct amdgpu_device *adev, 5888c2ecf20Sopenharmony_ci u32 pcie_index, u32 pcie_data, 5898c2ecf20Sopenharmony_ci u32 reg_addr) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci unsigned long flags; 5928c2ecf20Sopenharmony_ci u32 r; 5938c2ecf20Sopenharmony_ci void __iomem *pcie_index_offset; 5948c2ecf20Sopenharmony_ci void __iomem *pcie_data_offset; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci spin_lock_irqsave(&adev->pcie_idx_lock, flags); 5978c2ecf20Sopenharmony_ci pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4; 5988c2ecf20Sopenharmony_ci pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci writel(reg_addr, pcie_index_offset); 6018c2ecf20Sopenharmony_ci readl(pcie_index_offset); 6028c2ecf20Sopenharmony_ci r = readl(pcie_data_offset); 6038c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adev->pcie_idx_lock, flags); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci return r; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci/** 6098c2ecf20Sopenharmony_ci * amdgpu_device_indirect_rreg64 - read a 64bits indirect register 6108c2ecf20Sopenharmony_ci * 6118c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 6128c2ecf20Sopenharmony_ci * @pcie_index: mmio register offset 6138c2ecf20Sopenharmony_ci * @pcie_data: mmio register offset 6148c2ecf20Sopenharmony_ci * 6158c2ecf20Sopenharmony_ci * Returns the value of indirect register @reg_addr 6168c2ecf20Sopenharmony_ci */ 6178c2ecf20Sopenharmony_ciu64 amdgpu_device_indirect_rreg64(struct amdgpu_device *adev, 6188c2ecf20Sopenharmony_ci u32 pcie_index, u32 pcie_data, 6198c2ecf20Sopenharmony_ci u32 reg_addr) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci unsigned long flags; 6228c2ecf20Sopenharmony_ci u64 r; 6238c2ecf20Sopenharmony_ci void __iomem *pcie_index_offset; 6248c2ecf20Sopenharmony_ci void __iomem *pcie_data_offset; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci spin_lock_irqsave(&adev->pcie_idx_lock, flags); 6278c2ecf20Sopenharmony_ci pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4; 6288c2ecf20Sopenharmony_ci pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci /* read low 32 bits */ 6318c2ecf20Sopenharmony_ci writel(reg_addr, pcie_index_offset); 6328c2ecf20Sopenharmony_ci readl(pcie_index_offset); 6338c2ecf20Sopenharmony_ci r = readl(pcie_data_offset); 6348c2ecf20Sopenharmony_ci /* read high 32 bits */ 6358c2ecf20Sopenharmony_ci writel(reg_addr + 4, pcie_index_offset); 6368c2ecf20Sopenharmony_ci readl(pcie_index_offset); 6378c2ecf20Sopenharmony_ci r |= ((u64)readl(pcie_data_offset) << 32); 6388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adev->pcie_idx_lock, flags); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci return r; 6418c2ecf20Sopenharmony_ci} 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci/** 6448c2ecf20Sopenharmony_ci * amdgpu_device_indirect_wreg - write an indirect register address 6458c2ecf20Sopenharmony_ci * 6468c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 6478c2ecf20Sopenharmony_ci * @pcie_index: mmio register offset 6488c2ecf20Sopenharmony_ci * @pcie_data: mmio register offset 6498c2ecf20Sopenharmony_ci * @reg_addr: indirect register offset 6508c2ecf20Sopenharmony_ci * @reg_data: indirect register data 6518c2ecf20Sopenharmony_ci * 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_civoid amdgpu_device_indirect_wreg(struct amdgpu_device *adev, 6548c2ecf20Sopenharmony_ci u32 pcie_index, u32 pcie_data, 6558c2ecf20Sopenharmony_ci u32 reg_addr, u32 reg_data) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci unsigned long flags; 6588c2ecf20Sopenharmony_ci void __iomem *pcie_index_offset; 6598c2ecf20Sopenharmony_ci void __iomem *pcie_data_offset; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci spin_lock_irqsave(&adev->pcie_idx_lock, flags); 6628c2ecf20Sopenharmony_ci pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4; 6638c2ecf20Sopenharmony_ci pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci writel(reg_addr, pcie_index_offset); 6668c2ecf20Sopenharmony_ci readl(pcie_index_offset); 6678c2ecf20Sopenharmony_ci writel(reg_data, pcie_data_offset); 6688c2ecf20Sopenharmony_ci readl(pcie_data_offset); 6698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adev->pcie_idx_lock, flags); 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/** 6738c2ecf20Sopenharmony_ci * amdgpu_device_indirect_wreg64 - write a 64bits indirect register address 6748c2ecf20Sopenharmony_ci * 6758c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 6768c2ecf20Sopenharmony_ci * @pcie_index: mmio register offset 6778c2ecf20Sopenharmony_ci * @pcie_data: mmio register offset 6788c2ecf20Sopenharmony_ci * @reg_addr: indirect register offset 6798c2ecf20Sopenharmony_ci * @reg_data: indirect register data 6808c2ecf20Sopenharmony_ci * 6818c2ecf20Sopenharmony_ci */ 6828c2ecf20Sopenharmony_civoid amdgpu_device_indirect_wreg64(struct amdgpu_device *adev, 6838c2ecf20Sopenharmony_ci u32 pcie_index, u32 pcie_data, 6848c2ecf20Sopenharmony_ci u32 reg_addr, u64 reg_data) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci unsigned long flags; 6878c2ecf20Sopenharmony_ci void __iomem *pcie_index_offset; 6888c2ecf20Sopenharmony_ci void __iomem *pcie_data_offset; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci spin_lock_irqsave(&adev->pcie_idx_lock, flags); 6918c2ecf20Sopenharmony_ci pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4; 6928c2ecf20Sopenharmony_ci pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* write low 32 bits */ 6958c2ecf20Sopenharmony_ci writel(reg_addr, pcie_index_offset); 6968c2ecf20Sopenharmony_ci readl(pcie_index_offset); 6978c2ecf20Sopenharmony_ci writel((u32)(reg_data & 0xffffffffULL), pcie_data_offset); 6988c2ecf20Sopenharmony_ci readl(pcie_data_offset); 6998c2ecf20Sopenharmony_ci /* write high 32 bits */ 7008c2ecf20Sopenharmony_ci writel(reg_addr + 4, pcie_index_offset); 7018c2ecf20Sopenharmony_ci readl(pcie_index_offset); 7028c2ecf20Sopenharmony_ci writel((u32)(reg_data >> 32), pcie_data_offset); 7038c2ecf20Sopenharmony_ci readl(pcie_data_offset); 7048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adev->pcie_idx_lock, flags); 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci/** 7088c2ecf20Sopenharmony_ci * amdgpu_invalid_rreg - dummy reg read function 7098c2ecf20Sopenharmony_ci * 7108c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 7118c2ecf20Sopenharmony_ci * @reg: offset of register 7128c2ecf20Sopenharmony_ci * 7138c2ecf20Sopenharmony_ci * Dummy register read function. Used for register blocks 7148c2ecf20Sopenharmony_ci * that certain asics don't have (all asics). 7158c2ecf20Sopenharmony_ci * Returns the value in the register. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_cistatic uint32_t amdgpu_invalid_rreg(struct amdgpu_device *adev, uint32_t reg) 7188c2ecf20Sopenharmony_ci{ 7198c2ecf20Sopenharmony_ci DRM_ERROR("Invalid callback to read register 0x%04X\n", reg); 7208c2ecf20Sopenharmony_ci BUG(); 7218c2ecf20Sopenharmony_ci return 0; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci/** 7258c2ecf20Sopenharmony_ci * amdgpu_invalid_wreg - dummy reg write function 7268c2ecf20Sopenharmony_ci * 7278c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 7288c2ecf20Sopenharmony_ci * @reg: offset of register 7298c2ecf20Sopenharmony_ci * @v: value to write to the register 7308c2ecf20Sopenharmony_ci * 7318c2ecf20Sopenharmony_ci * Dummy register read function. Used for register blocks 7328c2ecf20Sopenharmony_ci * that certain asics don't have (all asics). 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_cistatic void amdgpu_invalid_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci DRM_ERROR("Invalid callback to write register 0x%04X with 0x%08X\n", 7378c2ecf20Sopenharmony_ci reg, v); 7388c2ecf20Sopenharmony_ci BUG(); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci/** 7428c2ecf20Sopenharmony_ci * amdgpu_invalid_rreg64 - dummy 64 bit reg read function 7438c2ecf20Sopenharmony_ci * 7448c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 7458c2ecf20Sopenharmony_ci * @reg: offset of register 7468c2ecf20Sopenharmony_ci * 7478c2ecf20Sopenharmony_ci * Dummy register read function. Used for register blocks 7488c2ecf20Sopenharmony_ci * that certain asics don't have (all asics). 7498c2ecf20Sopenharmony_ci * Returns the value in the register. 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_cistatic uint64_t amdgpu_invalid_rreg64(struct amdgpu_device *adev, uint32_t reg) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci DRM_ERROR("Invalid callback to read 64 bit register 0x%04X\n", reg); 7548c2ecf20Sopenharmony_ci BUG(); 7558c2ecf20Sopenharmony_ci return 0; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci/** 7598c2ecf20Sopenharmony_ci * amdgpu_invalid_wreg64 - dummy reg write function 7608c2ecf20Sopenharmony_ci * 7618c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 7628c2ecf20Sopenharmony_ci * @reg: offset of register 7638c2ecf20Sopenharmony_ci * @v: value to write to the register 7648c2ecf20Sopenharmony_ci * 7658c2ecf20Sopenharmony_ci * Dummy register read function. Used for register blocks 7668c2ecf20Sopenharmony_ci * that certain asics don't have (all asics). 7678c2ecf20Sopenharmony_ci */ 7688c2ecf20Sopenharmony_cistatic void amdgpu_invalid_wreg64(struct amdgpu_device *adev, uint32_t reg, uint64_t v) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci DRM_ERROR("Invalid callback to write 64 bit register 0x%04X with 0x%08llX\n", 7718c2ecf20Sopenharmony_ci reg, v); 7728c2ecf20Sopenharmony_ci BUG(); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci/** 7768c2ecf20Sopenharmony_ci * amdgpu_block_invalid_rreg - dummy reg read function 7778c2ecf20Sopenharmony_ci * 7788c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 7798c2ecf20Sopenharmony_ci * @block: offset of instance 7808c2ecf20Sopenharmony_ci * @reg: offset of register 7818c2ecf20Sopenharmony_ci * 7828c2ecf20Sopenharmony_ci * Dummy register read function. Used for register blocks 7838c2ecf20Sopenharmony_ci * that certain asics don't have (all asics). 7848c2ecf20Sopenharmony_ci * Returns the value in the register. 7858c2ecf20Sopenharmony_ci */ 7868c2ecf20Sopenharmony_cistatic uint32_t amdgpu_block_invalid_rreg(struct amdgpu_device *adev, 7878c2ecf20Sopenharmony_ci uint32_t block, uint32_t reg) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci DRM_ERROR("Invalid callback to read register 0x%04X in block 0x%04X\n", 7908c2ecf20Sopenharmony_ci reg, block); 7918c2ecf20Sopenharmony_ci BUG(); 7928c2ecf20Sopenharmony_ci return 0; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci/** 7968c2ecf20Sopenharmony_ci * amdgpu_block_invalid_wreg - dummy reg write function 7978c2ecf20Sopenharmony_ci * 7988c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 7998c2ecf20Sopenharmony_ci * @block: offset of instance 8008c2ecf20Sopenharmony_ci * @reg: offset of register 8018c2ecf20Sopenharmony_ci * @v: value to write to the register 8028c2ecf20Sopenharmony_ci * 8038c2ecf20Sopenharmony_ci * Dummy register read function. Used for register blocks 8048c2ecf20Sopenharmony_ci * that certain asics don't have (all asics). 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_cistatic void amdgpu_block_invalid_wreg(struct amdgpu_device *adev, 8078c2ecf20Sopenharmony_ci uint32_t block, 8088c2ecf20Sopenharmony_ci uint32_t reg, uint32_t v) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci DRM_ERROR("Invalid block callback to write register 0x%04X in block 0x%04X with 0x%08X\n", 8118c2ecf20Sopenharmony_ci reg, block, v); 8128c2ecf20Sopenharmony_ci BUG(); 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci/** 8168c2ecf20Sopenharmony_ci * amdgpu_device_asic_init - Wrapper for atom asic_init 8178c2ecf20Sopenharmony_ci * 8188c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 8198c2ecf20Sopenharmony_ci * 8208c2ecf20Sopenharmony_ci * Does any asic specific work and then calls atom asic init. 8218c2ecf20Sopenharmony_ci */ 8228c2ecf20Sopenharmony_cistatic int amdgpu_device_asic_init(struct amdgpu_device *adev) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci amdgpu_asic_pre_asic_init(adev); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return amdgpu_atom_asic_init(adev->mode_info.atom_context); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci/** 8308c2ecf20Sopenharmony_ci * amdgpu_device_vram_scratch_init - allocate the VRAM scratch page 8318c2ecf20Sopenharmony_ci * 8328c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 8338c2ecf20Sopenharmony_ci * 8348c2ecf20Sopenharmony_ci * Allocates a scratch page of VRAM for use by various things in the 8358c2ecf20Sopenharmony_ci * driver. 8368c2ecf20Sopenharmony_ci */ 8378c2ecf20Sopenharmony_cistatic int amdgpu_device_vram_scratch_init(struct amdgpu_device *adev) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci return amdgpu_bo_create_kernel(adev, AMDGPU_GPU_PAGE_SIZE, 8408c2ecf20Sopenharmony_ci PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM, 8418c2ecf20Sopenharmony_ci &adev->vram_scratch.robj, 8428c2ecf20Sopenharmony_ci &adev->vram_scratch.gpu_addr, 8438c2ecf20Sopenharmony_ci (void **)&adev->vram_scratch.ptr); 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci/** 8478c2ecf20Sopenharmony_ci * amdgpu_device_vram_scratch_fini - Free the VRAM scratch page 8488c2ecf20Sopenharmony_ci * 8498c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 8508c2ecf20Sopenharmony_ci * 8518c2ecf20Sopenharmony_ci * Frees the VRAM scratch page. 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_cistatic void amdgpu_device_vram_scratch_fini(struct amdgpu_device *adev) 8548c2ecf20Sopenharmony_ci{ 8558c2ecf20Sopenharmony_ci amdgpu_bo_free_kernel(&adev->vram_scratch.robj, NULL, NULL); 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci/** 8598c2ecf20Sopenharmony_ci * amdgpu_device_program_register_sequence - program an array of registers. 8608c2ecf20Sopenharmony_ci * 8618c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 8628c2ecf20Sopenharmony_ci * @registers: pointer to the register array 8638c2ecf20Sopenharmony_ci * @array_size: size of the register array 8648c2ecf20Sopenharmony_ci * 8658c2ecf20Sopenharmony_ci * Programs an array or registers with and and or masks. 8668c2ecf20Sopenharmony_ci * This is a helper for setting golden registers. 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_civoid amdgpu_device_program_register_sequence(struct amdgpu_device *adev, 8698c2ecf20Sopenharmony_ci const u32 *registers, 8708c2ecf20Sopenharmony_ci const u32 array_size) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci u32 tmp, reg, and_mask, or_mask; 8738c2ecf20Sopenharmony_ci int i; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci if (array_size % 3) 8768c2ecf20Sopenharmony_ci return; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci for (i = 0; i < array_size; i +=3) { 8798c2ecf20Sopenharmony_ci reg = registers[i + 0]; 8808c2ecf20Sopenharmony_ci and_mask = registers[i + 1]; 8818c2ecf20Sopenharmony_ci or_mask = registers[i + 2]; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci if (and_mask == 0xffffffff) { 8848c2ecf20Sopenharmony_ci tmp = or_mask; 8858c2ecf20Sopenharmony_ci } else { 8868c2ecf20Sopenharmony_ci tmp = RREG32(reg); 8878c2ecf20Sopenharmony_ci tmp &= ~and_mask; 8888c2ecf20Sopenharmony_ci if (adev->family >= AMDGPU_FAMILY_AI) 8898c2ecf20Sopenharmony_ci tmp |= (or_mask & and_mask); 8908c2ecf20Sopenharmony_ci else 8918c2ecf20Sopenharmony_ci tmp |= or_mask; 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci WREG32(reg, tmp); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci/** 8988c2ecf20Sopenharmony_ci * amdgpu_device_pci_config_reset - reset the GPU 8998c2ecf20Sopenharmony_ci * 9008c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 9018c2ecf20Sopenharmony_ci * 9028c2ecf20Sopenharmony_ci * Resets the GPU using the pci config reset sequence. 9038c2ecf20Sopenharmony_ci * Only applicable to asics prior to vega10. 9048c2ecf20Sopenharmony_ci */ 9058c2ecf20Sopenharmony_civoid amdgpu_device_pci_config_reset(struct amdgpu_device *adev) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci pci_write_config_dword(adev->pdev, 0x7c, AMDGPU_ASIC_RESET_DATA); 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci/* 9118c2ecf20Sopenharmony_ci * GPU doorbell aperture helpers function. 9128c2ecf20Sopenharmony_ci */ 9138c2ecf20Sopenharmony_ci/** 9148c2ecf20Sopenharmony_ci * amdgpu_device_doorbell_init - Init doorbell driver information. 9158c2ecf20Sopenharmony_ci * 9168c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 9178c2ecf20Sopenharmony_ci * 9188c2ecf20Sopenharmony_ci * Init doorbell driver information (CIK) 9198c2ecf20Sopenharmony_ci * Returns 0 on success, error on failure. 9208c2ecf20Sopenharmony_ci */ 9218c2ecf20Sopenharmony_cistatic int amdgpu_device_doorbell_init(struct amdgpu_device *adev) 9228c2ecf20Sopenharmony_ci{ 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci /* No doorbell on SI hardware generation */ 9258c2ecf20Sopenharmony_ci if (adev->asic_type < CHIP_BONAIRE) { 9268c2ecf20Sopenharmony_ci adev->doorbell.base = 0; 9278c2ecf20Sopenharmony_ci adev->doorbell.size = 0; 9288c2ecf20Sopenharmony_ci adev->doorbell.num_doorbells = 0; 9298c2ecf20Sopenharmony_ci adev->doorbell.ptr = NULL; 9308c2ecf20Sopenharmony_ci return 0; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci if (pci_resource_flags(adev->pdev, 2) & IORESOURCE_UNSET) 9348c2ecf20Sopenharmony_ci return -EINVAL; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci amdgpu_asic_init_doorbell_index(adev); 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci /* doorbell bar mapping */ 9398c2ecf20Sopenharmony_ci adev->doorbell.base = pci_resource_start(adev->pdev, 2); 9408c2ecf20Sopenharmony_ci adev->doorbell.size = pci_resource_len(adev->pdev, 2); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci adev->doorbell.num_doorbells = min_t(u32, adev->doorbell.size / sizeof(u32), 9438c2ecf20Sopenharmony_ci adev->doorbell_index.max_assignment+1); 9448c2ecf20Sopenharmony_ci if (adev->doorbell.num_doorbells == 0) 9458c2ecf20Sopenharmony_ci return -EINVAL; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* For Vega, reserve and map two pages on doorbell BAR since SDMA 9488c2ecf20Sopenharmony_ci * paging queue doorbell use the second page. The 9498c2ecf20Sopenharmony_ci * AMDGPU_DOORBELL64_MAX_ASSIGNMENT definition assumes all the 9508c2ecf20Sopenharmony_ci * doorbells are in the first page. So with paging queue enabled, 9518c2ecf20Sopenharmony_ci * the max num_doorbells should + 1 page (0x400 in dword) 9528c2ecf20Sopenharmony_ci */ 9538c2ecf20Sopenharmony_ci if (adev->asic_type >= CHIP_VEGA10) 9548c2ecf20Sopenharmony_ci adev->doorbell.num_doorbells += 0x400; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci adev->doorbell.ptr = ioremap(adev->doorbell.base, 9578c2ecf20Sopenharmony_ci adev->doorbell.num_doorbells * 9588c2ecf20Sopenharmony_ci sizeof(u32)); 9598c2ecf20Sopenharmony_ci if (adev->doorbell.ptr == NULL) 9608c2ecf20Sopenharmony_ci return -ENOMEM; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci return 0; 9638c2ecf20Sopenharmony_ci} 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci/** 9668c2ecf20Sopenharmony_ci * amdgpu_device_doorbell_fini - Tear down doorbell driver information. 9678c2ecf20Sopenharmony_ci * 9688c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 9698c2ecf20Sopenharmony_ci * 9708c2ecf20Sopenharmony_ci * Tear down doorbell driver information (CIK) 9718c2ecf20Sopenharmony_ci */ 9728c2ecf20Sopenharmony_cistatic void amdgpu_device_doorbell_fini(struct amdgpu_device *adev) 9738c2ecf20Sopenharmony_ci{ 9748c2ecf20Sopenharmony_ci iounmap(adev->doorbell.ptr); 9758c2ecf20Sopenharmony_ci adev->doorbell.ptr = NULL; 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci/* 9818c2ecf20Sopenharmony_ci * amdgpu_device_wb_*() 9828c2ecf20Sopenharmony_ci * Writeback is the method by which the GPU updates special pages in memory 9838c2ecf20Sopenharmony_ci * with the status of certain GPU events (fences, ring pointers,etc.). 9848c2ecf20Sopenharmony_ci */ 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci/** 9878c2ecf20Sopenharmony_ci * amdgpu_device_wb_fini - Disable Writeback and free memory 9888c2ecf20Sopenharmony_ci * 9898c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 9908c2ecf20Sopenharmony_ci * 9918c2ecf20Sopenharmony_ci * Disables Writeback and frees the Writeback memory (all asics). 9928c2ecf20Sopenharmony_ci * Used at driver shutdown. 9938c2ecf20Sopenharmony_ci */ 9948c2ecf20Sopenharmony_cistatic void amdgpu_device_wb_fini(struct amdgpu_device *adev) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci if (adev->wb.wb_obj) { 9978c2ecf20Sopenharmony_ci amdgpu_bo_free_kernel(&adev->wb.wb_obj, 9988c2ecf20Sopenharmony_ci &adev->wb.gpu_addr, 9998c2ecf20Sopenharmony_ci (void **)&adev->wb.wb); 10008c2ecf20Sopenharmony_ci adev->wb.wb_obj = NULL; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci/** 10058c2ecf20Sopenharmony_ci * amdgpu_device_wb_init- Init Writeback driver info and allocate memory 10068c2ecf20Sopenharmony_ci * 10078c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 10088c2ecf20Sopenharmony_ci * 10098c2ecf20Sopenharmony_ci * Initializes writeback and allocates writeback memory (all asics). 10108c2ecf20Sopenharmony_ci * Used at driver startup. 10118c2ecf20Sopenharmony_ci * Returns 0 on success or an -error on failure. 10128c2ecf20Sopenharmony_ci */ 10138c2ecf20Sopenharmony_cistatic int amdgpu_device_wb_init(struct amdgpu_device *adev) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci int r; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (adev->wb.wb_obj == NULL) { 10188c2ecf20Sopenharmony_ci /* AMDGPU_MAX_WB * sizeof(uint32_t) * 8 = AMDGPU_MAX_WB 256bit slots */ 10198c2ecf20Sopenharmony_ci r = amdgpu_bo_create_kernel(adev, AMDGPU_MAX_WB * sizeof(uint32_t) * 8, 10208c2ecf20Sopenharmony_ci PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, 10218c2ecf20Sopenharmony_ci &adev->wb.wb_obj, &adev->wb.gpu_addr, 10228c2ecf20Sopenharmony_ci (void **)&adev->wb.wb); 10238c2ecf20Sopenharmony_ci if (r) { 10248c2ecf20Sopenharmony_ci dev_warn(adev->dev, "(%d) create WB bo failed\n", r); 10258c2ecf20Sopenharmony_ci return r; 10268c2ecf20Sopenharmony_ci } 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci adev->wb.num_wb = AMDGPU_MAX_WB; 10298c2ecf20Sopenharmony_ci memset(&adev->wb.used, 0, sizeof(adev->wb.used)); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* clear wb memory */ 10328c2ecf20Sopenharmony_ci memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t) * 8); 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return 0; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/** 10398c2ecf20Sopenharmony_ci * amdgpu_device_wb_get - Allocate a wb entry 10408c2ecf20Sopenharmony_ci * 10418c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 10428c2ecf20Sopenharmony_ci * @wb: wb index 10438c2ecf20Sopenharmony_ci * 10448c2ecf20Sopenharmony_ci * Allocate a wb slot for use by the driver (all asics). 10458c2ecf20Sopenharmony_ci * Returns 0 on success or -EINVAL on failure. 10468c2ecf20Sopenharmony_ci */ 10478c2ecf20Sopenharmony_ciint amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci unsigned long offset = find_first_zero_bit(adev->wb.used, adev->wb.num_wb); 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci if (offset < adev->wb.num_wb) { 10528c2ecf20Sopenharmony_ci __set_bit(offset, adev->wb.used); 10538c2ecf20Sopenharmony_ci *wb = offset << 3; /* convert to dw offset */ 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci } else { 10568c2ecf20Sopenharmony_ci return -EINVAL; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci/** 10618c2ecf20Sopenharmony_ci * amdgpu_device_wb_free - Free a wb entry 10628c2ecf20Sopenharmony_ci * 10638c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 10648c2ecf20Sopenharmony_ci * @wb: wb index 10658c2ecf20Sopenharmony_ci * 10668c2ecf20Sopenharmony_ci * Free a wb slot allocated for use by the driver (all asics) 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_civoid amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb) 10698c2ecf20Sopenharmony_ci{ 10708c2ecf20Sopenharmony_ci wb >>= 3; 10718c2ecf20Sopenharmony_ci if (wb < adev->wb.num_wb) 10728c2ecf20Sopenharmony_ci __clear_bit(wb, adev->wb.used); 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci/** 10768c2ecf20Sopenharmony_ci * amdgpu_device_resize_fb_bar - try to resize FB BAR 10778c2ecf20Sopenharmony_ci * 10788c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 10798c2ecf20Sopenharmony_ci * 10808c2ecf20Sopenharmony_ci * Try to resize FB BAR to make all VRAM CPU accessible. We try very hard not 10818c2ecf20Sopenharmony_ci * to fail, but if any of the BARs is not accessible after the size we abort 10828c2ecf20Sopenharmony_ci * driver loading by returning -ENODEV. 10838c2ecf20Sopenharmony_ci */ 10848c2ecf20Sopenharmony_ciint amdgpu_device_resize_fb_bar(struct amdgpu_device *adev) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci u64 space_needed = roundup_pow_of_two(adev->gmc.real_vram_size); 10878c2ecf20Sopenharmony_ci u32 rbar_size = order_base_2(((space_needed >> 20) | 1)) - 1; 10888c2ecf20Sopenharmony_ci struct pci_bus *root; 10898c2ecf20Sopenharmony_ci struct resource *res; 10908c2ecf20Sopenharmony_ci unsigned i; 10918c2ecf20Sopenharmony_ci u16 cmd; 10928c2ecf20Sopenharmony_ci int r; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT)) 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Bypass for VF */ 10988c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 10998c2ecf20Sopenharmony_ci return 0; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci /* skip if the bios has already enabled large BAR */ 11028c2ecf20Sopenharmony_ci if (adev->gmc.real_vram_size && 11038c2ecf20Sopenharmony_ci (pci_resource_len(adev->pdev, 0) >= adev->gmc.real_vram_size)) 11048c2ecf20Sopenharmony_ci return 0; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci /* Check if the root BUS has 64bit memory resources */ 11078c2ecf20Sopenharmony_ci root = adev->pdev->bus; 11088c2ecf20Sopenharmony_ci while (root->parent) 11098c2ecf20Sopenharmony_ci root = root->parent; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci pci_bus_for_each_resource(root, res, i) { 11128c2ecf20Sopenharmony_ci if (res && res->flags & (IORESOURCE_MEM | IORESOURCE_MEM_64) && 11138c2ecf20Sopenharmony_ci res->start > 0x100000000ull) 11148c2ecf20Sopenharmony_ci break; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* Trying to resize is pointless without a root hub window above 4GB */ 11188c2ecf20Sopenharmony_ci if (!res) 11198c2ecf20Sopenharmony_ci return 0; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* Disable memory decoding while we change the BAR addresses and size */ 11228c2ecf20Sopenharmony_ci pci_read_config_word(adev->pdev, PCI_COMMAND, &cmd); 11238c2ecf20Sopenharmony_ci pci_write_config_word(adev->pdev, PCI_COMMAND, 11248c2ecf20Sopenharmony_ci cmd & ~PCI_COMMAND_MEMORY); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* Free the VRAM and doorbell BAR, we most likely need to move both. */ 11278c2ecf20Sopenharmony_ci amdgpu_device_doorbell_fini(adev); 11288c2ecf20Sopenharmony_ci if (adev->asic_type >= CHIP_BONAIRE) 11298c2ecf20Sopenharmony_ci pci_release_resource(adev->pdev, 2); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci pci_release_resource(adev->pdev, 0); 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci r = pci_resize_resource(adev->pdev, 0, rbar_size); 11348c2ecf20Sopenharmony_ci if (r == -ENOSPC) 11358c2ecf20Sopenharmony_ci DRM_INFO("Not enough PCI address space for a large BAR."); 11368c2ecf20Sopenharmony_ci else if (r && r != -ENOTSUPP) 11378c2ecf20Sopenharmony_ci DRM_ERROR("Problem resizing BAR0 (%d).", r); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci pci_assign_unassigned_bus_resources(adev->pdev->bus); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* When the doorbell or fb BAR isn't available we have no chance of 11428c2ecf20Sopenharmony_ci * using the device. 11438c2ecf20Sopenharmony_ci */ 11448c2ecf20Sopenharmony_ci r = amdgpu_device_doorbell_init(adev); 11458c2ecf20Sopenharmony_ci if (r || (pci_resource_flags(adev->pdev, 0) & IORESOURCE_UNSET)) 11468c2ecf20Sopenharmony_ci return -ENODEV; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci pci_write_config_word(adev->pdev, PCI_COMMAND, cmd); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci return 0; 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci/* 11548c2ecf20Sopenharmony_ci * GPU helpers function. 11558c2ecf20Sopenharmony_ci */ 11568c2ecf20Sopenharmony_ci/** 11578c2ecf20Sopenharmony_ci * amdgpu_device_need_post - check if the hw need post or not 11588c2ecf20Sopenharmony_ci * 11598c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 11608c2ecf20Sopenharmony_ci * 11618c2ecf20Sopenharmony_ci * Check if the asic has been initialized (all asics) at driver startup 11628c2ecf20Sopenharmony_ci * or post is needed if hw reset is performed. 11638c2ecf20Sopenharmony_ci * Returns true if need or false if not. 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_cibool amdgpu_device_need_post(struct amdgpu_device *adev) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci uint32_t reg; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 11708c2ecf20Sopenharmony_ci return false; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci if (amdgpu_passthrough(adev)) { 11738c2ecf20Sopenharmony_ci /* for FIJI: In whole GPU pass-through virtualization case, after VM reboot 11748c2ecf20Sopenharmony_ci * some old smc fw still need driver do vPost otherwise gpu hang, while 11758c2ecf20Sopenharmony_ci * those smc fw version above 22.15 doesn't have this flaw, so we force 11768c2ecf20Sopenharmony_ci * vpost executed for smc version below 22.15 11778c2ecf20Sopenharmony_ci */ 11788c2ecf20Sopenharmony_ci if (adev->asic_type == CHIP_FIJI) { 11798c2ecf20Sopenharmony_ci int err; 11808c2ecf20Sopenharmony_ci uint32_t fw_ver; 11818c2ecf20Sopenharmony_ci err = request_firmware(&adev->pm.fw, "amdgpu/fiji_smc.bin", adev->dev); 11828c2ecf20Sopenharmony_ci /* force vPost if error occured */ 11838c2ecf20Sopenharmony_ci if (err) 11848c2ecf20Sopenharmony_ci return true; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci fw_ver = *((uint32_t *)adev->pm.fw->data + 69); 11878c2ecf20Sopenharmony_ci release_firmware(adev->pm.fw); 11888c2ecf20Sopenharmony_ci if (fw_ver < 0x00160e00) 11898c2ecf20Sopenharmony_ci return true; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (adev->has_hw_reset) { 11948c2ecf20Sopenharmony_ci adev->has_hw_reset = false; 11958c2ecf20Sopenharmony_ci return true; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci /* bios scratch used on CIK+ */ 11998c2ecf20Sopenharmony_ci if (adev->asic_type >= CHIP_BONAIRE) 12008c2ecf20Sopenharmony_ci return amdgpu_atombios_scratch_need_asic_init(adev); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci /* check MEM_SIZE for older asics */ 12038c2ecf20Sopenharmony_ci reg = amdgpu_asic_get_config_memsize(adev); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if ((reg != 0) && (reg != 0xffffffff)) 12068c2ecf20Sopenharmony_ci return false; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci return true; 12098c2ecf20Sopenharmony_ci} 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci/* if we get transitioned to only one device, take VGA back */ 12128c2ecf20Sopenharmony_ci/** 12138c2ecf20Sopenharmony_ci * amdgpu_device_vga_set_decode - enable/disable vga decode 12148c2ecf20Sopenharmony_ci * 12158c2ecf20Sopenharmony_ci * @cookie: amdgpu_device pointer 12168c2ecf20Sopenharmony_ci * @state: enable/disable vga decode 12178c2ecf20Sopenharmony_ci * 12188c2ecf20Sopenharmony_ci * Enable/disable vga decode (all asics). 12198c2ecf20Sopenharmony_ci * Returns VGA resource flags. 12208c2ecf20Sopenharmony_ci */ 12218c2ecf20Sopenharmony_cistatic unsigned int amdgpu_device_vga_set_decode(void *cookie, bool state) 12228c2ecf20Sopenharmony_ci{ 12238c2ecf20Sopenharmony_ci struct amdgpu_device *adev = cookie; 12248c2ecf20Sopenharmony_ci amdgpu_asic_set_vga_state(adev, state); 12258c2ecf20Sopenharmony_ci if (state) 12268c2ecf20Sopenharmony_ci return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM | 12278c2ecf20Sopenharmony_ci VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 12288c2ecf20Sopenharmony_ci else 12298c2ecf20Sopenharmony_ci return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci/** 12338c2ecf20Sopenharmony_ci * amdgpu_device_check_block_size - validate the vm block size 12348c2ecf20Sopenharmony_ci * 12358c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 12368c2ecf20Sopenharmony_ci * 12378c2ecf20Sopenharmony_ci * Validates the vm block size specified via module parameter. 12388c2ecf20Sopenharmony_ci * The vm block size defines number of bits in page table versus page directory, 12398c2ecf20Sopenharmony_ci * a page is 4KB so we have 12 bits offset, minimum 9 bits in the 12408c2ecf20Sopenharmony_ci * page table and the remaining bits are in the page directory. 12418c2ecf20Sopenharmony_ci */ 12428c2ecf20Sopenharmony_cistatic void amdgpu_device_check_block_size(struct amdgpu_device *adev) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci /* defines number of bits in page table versus page directory, 12458c2ecf20Sopenharmony_ci * a page is 4KB so we have 12 bits offset, minimum 9 bits in the 12468c2ecf20Sopenharmony_ci * page table and the remaining bits are in the page directory */ 12478c2ecf20Sopenharmony_ci if (amdgpu_vm_block_size == -1) 12488c2ecf20Sopenharmony_ci return; 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (amdgpu_vm_block_size < 9) { 12518c2ecf20Sopenharmony_ci dev_warn(adev->dev, "VM page table size (%d) too small\n", 12528c2ecf20Sopenharmony_ci amdgpu_vm_block_size); 12538c2ecf20Sopenharmony_ci amdgpu_vm_block_size = -1; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci/** 12588c2ecf20Sopenharmony_ci * amdgpu_device_check_vm_size - validate the vm size 12598c2ecf20Sopenharmony_ci * 12608c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 12618c2ecf20Sopenharmony_ci * 12628c2ecf20Sopenharmony_ci * Validates the vm size in GB specified via module parameter. 12638c2ecf20Sopenharmony_ci * The VM size is the size of the GPU virtual memory space in GB. 12648c2ecf20Sopenharmony_ci */ 12658c2ecf20Sopenharmony_cistatic void amdgpu_device_check_vm_size(struct amdgpu_device *adev) 12668c2ecf20Sopenharmony_ci{ 12678c2ecf20Sopenharmony_ci /* no need to check the default value */ 12688c2ecf20Sopenharmony_ci if (amdgpu_vm_size == -1) 12698c2ecf20Sopenharmony_ci return; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci if (amdgpu_vm_size < 1) { 12728c2ecf20Sopenharmony_ci dev_warn(adev->dev, "VM size (%d) too small, min is 1GB\n", 12738c2ecf20Sopenharmony_ci amdgpu_vm_size); 12748c2ecf20Sopenharmony_ci amdgpu_vm_size = -1; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci} 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_cistatic void amdgpu_device_check_smu_prv_buffer_size(struct amdgpu_device *adev) 12798c2ecf20Sopenharmony_ci{ 12808c2ecf20Sopenharmony_ci struct sysinfo si; 12818c2ecf20Sopenharmony_ci bool is_os_64 = (sizeof(void *) == 8); 12828c2ecf20Sopenharmony_ci uint64_t total_memory; 12838c2ecf20Sopenharmony_ci uint64_t dram_size_seven_GB = 0x1B8000000; 12848c2ecf20Sopenharmony_ci uint64_t dram_size_three_GB = 0xB8000000; 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci if (amdgpu_smu_memory_pool_size == 0) 12878c2ecf20Sopenharmony_ci return; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (!is_os_64) { 12908c2ecf20Sopenharmony_ci DRM_WARN("Not 64-bit OS, feature not supported\n"); 12918c2ecf20Sopenharmony_ci goto def_value; 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci si_meminfo(&si); 12948c2ecf20Sopenharmony_ci total_memory = (uint64_t)si.totalram * si.mem_unit; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci if ((amdgpu_smu_memory_pool_size == 1) || 12978c2ecf20Sopenharmony_ci (amdgpu_smu_memory_pool_size == 2)) { 12988c2ecf20Sopenharmony_ci if (total_memory < dram_size_three_GB) 12998c2ecf20Sopenharmony_ci goto def_value1; 13008c2ecf20Sopenharmony_ci } else if ((amdgpu_smu_memory_pool_size == 4) || 13018c2ecf20Sopenharmony_ci (amdgpu_smu_memory_pool_size == 8)) { 13028c2ecf20Sopenharmony_ci if (total_memory < dram_size_seven_GB) 13038c2ecf20Sopenharmony_ci goto def_value1; 13048c2ecf20Sopenharmony_ci } else { 13058c2ecf20Sopenharmony_ci DRM_WARN("Smu memory pool size not supported\n"); 13068c2ecf20Sopenharmony_ci goto def_value; 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci adev->pm.smu_prv_buffer_size = amdgpu_smu_memory_pool_size << 28; 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci return; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_cidef_value1: 13138c2ecf20Sopenharmony_ci DRM_WARN("No enough system memory\n"); 13148c2ecf20Sopenharmony_cidef_value: 13158c2ecf20Sopenharmony_ci adev->pm.smu_prv_buffer_size = 0; 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci/** 13198c2ecf20Sopenharmony_ci * amdgpu_device_check_arguments - validate module params 13208c2ecf20Sopenharmony_ci * 13218c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 13228c2ecf20Sopenharmony_ci * 13238c2ecf20Sopenharmony_ci * Validates certain module parameters and updates 13248c2ecf20Sopenharmony_ci * the associated values used by the driver (all asics). 13258c2ecf20Sopenharmony_ci */ 13268c2ecf20Sopenharmony_cistatic int amdgpu_device_check_arguments(struct amdgpu_device *adev) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci if (amdgpu_sched_jobs < 4) { 13298c2ecf20Sopenharmony_ci dev_warn(adev->dev, "sched jobs (%d) must be at least 4\n", 13308c2ecf20Sopenharmony_ci amdgpu_sched_jobs); 13318c2ecf20Sopenharmony_ci amdgpu_sched_jobs = 4; 13328c2ecf20Sopenharmony_ci } else if (!is_power_of_2(amdgpu_sched_jobs)){ 13338c2ecf20Sopenharmony_ci dev_warn(adev->dev, "sched jobs (%d) must be a power of 2\n", 13348c2ecf20Sopenharmony_ci amdgpu_sched_jobs); 13358c2ecf20Sopenharmony_ci amdgpu_sched_jobs = roundup_pow_of_two(amdgpu_sched_jobs); 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci if (amdgpu_gart_size != -1 && amdgpu_gart_size < 32) { 13398c2ecf20Sopenharmony_ci /* gart size must be greater or equal to 32M */ 13408c2ecf20Sopenharmony_ci dev_warn(adev->dev, "gart size (%d) too small\n", 13418c2ecf20Sopenharmony_ci amdgpu_gart_size); 13428c2ecf20Sopenharmony_ci amdgpu_gart_size = -1; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (amdgpu_gtt_size != -1 && amdgpu_gtt_size < 32) { 13468c2ecf20Sopenharmony_ci /* gtt size must be greater or equal to 32M */ 13478c2ecf20Sopenharmony_ci dev_warn(adev->dev, "gtt size (%d) too small\n", 13488c2ecf20Sopenharmony_ci amdgpu_gtt_size); 13498c2ecf20Sopenharmony_ci amdgpu_gtt_size = -1; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* valid range is between 4 and 9 inclusive */ 13538c2ecf20Sopenharmony_ci if (amdgpu_vm_fragment_size != -1 && 13548c2ecf20Sopenharmony_ci (amdgpu_vm_fragment_size > 9 || amdgpu_vm_fragment_size < 4)) { 13558c2ecf20Sopenharmony_ci dev_warn(adev->dev, "valid range is between 4 and 9\n"); 13568c2ecf20Sopenharmony_ci amdgpu_vm_fragment_size = -1; 13578c2ecf20Sopenharmony_ci } 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci if (amdgpu_sched_hw_submission < 2) { 13608c2ecf20Sopenharmony_ci dev_warn(adev->dev, "sched hw submission jobs (%d) must be at least 2\n", 13618c2ecf20Sopenharmony_ci amdgpu_sched_hw_submission); 13628c2ecf20Sopenharmony_ci amdgpu_sched_hw_submission = 2; 13638c2ecf20Sopenharmony_ci } else if (!is_power_of_2(amdgpu_sched_hw_submission)) { 13648c2ecf20Sopenharmony_ci dev_warn(adev->dev, "sched hw submission jobs (%d) must be a power of 2\n", 13658c2ecf20Sopenharmony_ci amdgpu_sched_hw_submission); 13668c2ecf20Sopenharmony_ci amdgpu_sched_hw_submission = roundup_pow_of_two(amdgpu_sched_hw_submission); 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci amdgpu_device_check_smu_prv_buffer_size(adev); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci amdgpu_device_check_vm_size(adev); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci amdgpu_device_check_block_size(adev); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci adev->firmware.load_type = amdgpu_ucode_get_load_type(adev, amdgpu_fw_load_type); 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci amdgpu_gmc_tmz_set(adev); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (amdgpu_num_kcq == -1) { 13808c2ecf20Sopenharmony_ci amdgpu_num_kcq = 8; 13818c2ecf20Sopenharmony_ci } else if (amdgpu_num_kcq > 8 || amdgpu_num_kcq < 0) { 13828c2ecf20Sopenharmony_ci amdgpu_num_kcq = 8; 13838c2ecf20Sopenharmony_ci dev_warn(adev->dev, "set kernel compute queue number to 8 due to invalid parameter provided by user\n"); 13848c2ecf20Sopenharmony_ci } 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci amdgpu_gmc_noretry_set(adev); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci return 0; 13898c2ecf20Sopenharmony_ci} 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci/** 13928c2ecf20Sopenharmony_ci * amdgpu_switcheroo_set_state - set switcheroo state 13938c2ecf20Sopenharmony_ci * 13948c2ecf20Sopenharmony_ci * @pdev: pci dev pointer 13958c2ecf20Sopenharmony_ci * @state: vga_switcheroo state 13968c2ecf20Sopenharmony_ci * 13978c2ecf20Sopenharmony_ci * Callback for the switcheroo driver. Suspends or resumes the 13988c2ecf20Sopenharmony_ci * the asics before or after it is powered up using ACPI methods. 13998c2ecf20Sopenharmony_ci */ 14008c2ecf20Sopenharmony_cistatic void amdgpu_switcheroo_set_state(struct pci_dev *pdev, 14018c2ecf20Sopenharmony_ci enum vga_switcheroo_state state) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 14048c2ecf20Sopenharmony_ci int r; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (amdgpu_device_supports_boco(dev) && state == VGA_SWITCHEROO_OFF) 14078c2ecf20Sopenharmony_ci return; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (state == VGA_SWITCHEROO_ON) { 14108c2ecf20Sopenharmony_ci pr_info("switched on\n"); 14118c2ecf20Sopenharmony_ci /* don't suspend or resume card normally */ 14128c2ecf20Sopenharmony_ci dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci pci_set_power_state(dev->pdev, PCI_D0); 14158c2ecf20Sopenharmony_ci amdgpu_device_load_pci_state(dev->pdev); 14168c2ecf20Sopenharmony_ci r = pci_enable_device(dev->pdev); 14178c2ecf20Sopenharmony_ci if (r) 14188c2ecf20Sopenharmony_ci DRM_WARN("pci_enable_device failed (%d)\n", r); 14198c2ecf20Sopenharmony_ci amdgpu_device_resume(dev, true); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci dev->switch_power_state = DRM_SWITCH_POWER_ON; 14228c2ecf20Sopenharmony_ci drm_kms_helper_poll_enable(dev); 14238c2ecf20Sopenharmony_ci } else { 14248c2ecf20Sopenharmony_ci pr_info("switched off\n"); 14258c2ecf20Sopenharmony_ci drm_kms_helper_poll_disable(dev); 14268c2ecf20Sopenharmony_ci dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; 14278c2ecf20Sopenharmony_ci amdgpu_device_suspend(dev, true); 14288c2ecf20Sopenharmony_ci amdgpu_device_cache_pci_state(dev->pdev); 14298c2ecf20Sopenharmony_ci /* Shut down the device */ 14308c2ecf20Sopenharmony_ci pci_disable_device(dev->pdev); 14318c2ecf20Sopenharmony_ci pci_set_power_state(dev->pdev, PCI_D3cold); 14328c2ecf20Sopenharmony_ci dev->switch_power_state = DRM_SWITCH_POWER_OFF; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci} 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci/** 14378c2ecf20Sopenharmony_ci * amdgpu_switcheroo_can_switch - see if switcheroo state can change 14388c2ecf20Sopenharmony_ci * 14398c2ecf20Sopenharmony_ci * @pdev: pci dev pointer 14408c2ecf20Sopenharmony_ci * 14418c2ecf20Sopenharmony_ci * Callback for the switcheroo driver. Check of the switcheroo 14428c2ecf20Sopenharmony_ci * state can be changed. 14438c2ecf20Sopenharmony_ci * Returns true if the state can be changed, false if not. 14448c2ecf20Sopenharmony_ci */ 14458c2ecf20Sopenharmony_cistatic bool amdgpu_switcheroo_can_switch(struct pci_dev *pdev) 14468c2ecf20Sopenharmony_ci{ 14478c2ecf20Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci /* 14508c2ecf20Sopenharmony_ci * FIXME: open_count is protected by drm_global_mutex but that would lead to 14518c2ecf20Sopenharmony_ci * locking inversion with the driver load path. And the access here is 14528c2ecf20Sopenharmony_ci * completely racy anyway. So don't bother with locking for now. 14538c2ecf20Sopenharmony_ci */ 14548c2ecf20Sopenharmony_ci return atomic_read(&dev->open_count) == 0; 14558c2ecf20Sopenharmony_ci} 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_cistatic const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = { 14588c2ecf20Sopenharmony_ci .set_gpu_state = amdgpu_switcheroo_set_state, 14598c2ecf20Sopenharmony_ci .reprobe = NULL, 14608c2ecf20Sopenharmony_ci .can_switch = amdgpu_switcheroo_can_switch, 14618c2ecf20Sopenharmony_ci}; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci/** 14648c2ecf20Sopenharmony_ci * amdgpu_device_ip_set_clockgating_state - set the CG state 14658c2ecf20Sopenharmony_ci * 14668c2ecf20Sopenharmony_ci * @dev: amdgpu_device pointer 14678c2ecf20Sopenharmony_ci * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) 14688c2ecf20Sopenharmony_ci * @state: clockgating state (gate or ungate) 14698c2ecf20Sopenharmony_ci * 14708c2ecf20Sopenharmony_ci * Sets the requested clockgating state for all instances of 14718c2ecf20Sopenharmony_ci * the hardware IP specified. 14728c2ecf20Sopenharmony_ci * Returns the error code from the last instance. 14738c2ecf20Sopenharmony_ci */ 14748c2ecf20Sopenharmony_ciint amdgpu_device_ip_set_clockgating_state(void *dev, 14758c2ecf20Sopenharmony_ci enum amd_ip_block_type block_type, 14768c2ecf20Sopenharmony_ci enum amd_clockgating_state state) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct amdgpu_device *adev = dev; 14798c2ecf20Sopenharmony_ci int i, r = 0; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 14828c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 14838c2ecf20Sopenharmony_ci continue; 14848c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type != block_type) 14858c2ecf20Sopenharmony_ci continue; 14868c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].version->funcs->set_clockgating_state) 14878c2ecf20Sopenharmony_ci continue; 14888c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->set_clockgating_state( 14898c2ecf20Sopenharmony_ci (void *)adev, state); 14908c2ecf20Sopenharmony_ci if (r) 14918c2ecf20Sopenharmony_ci DRM_ERROR("set_clockgating_state of IP block <%s> failed %d\n", 14928c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci return r; 14958c2ecf20Sopenharmony_ci} 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci/** 14988c2ecf20Sopenharmony_ci * amdgpu_device_ip_set_powergating_state - set the PG state 14998c2ecf20Sopenharmony_ci * 15008c2ecf20Sopenharmony_ci * @dev: amdgpu_device pointer 15018c2ecf20Sopenharmony_ci * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) 15028c2ecf20Sopenharmony_ci * @state: powergating state (gate or ungate) 15038c2ecf20Sopenharmony_ci * 15048c2ecf20Sopenharmony_ci * Sets the requested powergating state for all instances of 15058c2ecf20Sopenharmony_ci * the hardware IP specified. 15068c2ecf20Sopenharmony_ci * Returns the error code from the last instance. 15078c2ecf20Sopenharmony_ci */ 15088c2ecf20Sopenharmony_ciint amdgpu_device_ip_set_powergating_state(void *dev, 15098c2ecf20Sopenharmony_ci enum amd_ip_block_type block_type, 15108c2ecf20Sopenharmony_ci enum amd_powergating_state state) 15118c2ecf20Sopenharmony_ci{ 15128c2ecf20Sopenharmony_ci struct amdgpu_device *adev = dev; 15138c2ecf20Sopenharmony_ci int i, r = 0; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 15168c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 15178c2ecf20Sopenharmony_ci continue; 15188c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type != block_type) 15198c2ecf20Sopenharmony_ci continue; 15208c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].version->funcs->set_powergating_state) 15218c2ecf20Sopenharmony_ci continue; 15228c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->set_powergating_state( 15238c2ecf20Sopenharmony_ci (void *)adev, state); 15248c2ecf20Sopenharmony_ci if (r) 15258c2ecf20Sopenharmony_ci DRM_ERROR("set_powergating_state of IP block <%s> failed %d\n", 15268c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci return r; 15298c2ecf20Sopenharmony_ci} 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci/** 15328c2ecf20Sopenharmony_ci * amdgpu_device_ip_get_clockgating_state - get the CG state 15338c2ecf20Sopenharmony_ci * 15348c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 15358c2ecf20Sopenharmony_ci * @flags: clockgating feature flags 15368c2ecf20Sopenharmony_ci * 15378c2ecf20Sopenharmony_ci * Walks the list of IPs on the device and updates the clockgating 15388c2ecf20Sopenharmony_ci * flags for each IP. 15398c2ecf20Sopenharmony_ci * Updates @flags with the feature flags for each hardware IP where 15408c2ecf20Sopenharmony_ci * clockgating is enabled. 15418c2ecf20Sopenharmony_ci */ 15428c2ecf20Sopenharmony_civoid amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev, 15438c2ecf20Sopenharmony_ci u32 *flags) 15448c2ecf20Sopenharmony_ci{ 15458c2ecf20Sopenharmony_ci int i; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 15488c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 15498c2ecf20Sopenharmony_ci continue; 15508c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->funcs->get_clockgating_state) 15518c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->get_clockgating_state((void *)adev, flags); 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci/** 15568c2ecf20Sopenharmony_ci * amdgpu_device_ip_wait_for_idle - wait for idle 15578c2ecf20Sopenharmony_ci * 15588c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 15598c2ecf20Sopenharmony_ci * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) 15608c2ecf20Sopenharmony_ci * 15618c2ecf20Sopenharmony_ci * Waits for the request hardware IP to be idle. 15628c2ecf20Sopenharmony_ci * Returns 0 for success or a negative error code on failure. 15638c2ecf20Sopenharmony_ci */ 15648c2ecf20Sopenharmony_ciint amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev, 15658c2ecf20Sopenharmony_ci enum amd_ip_block_type block_type) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci int i, r; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 15708c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 15718c2ecf20Sopenharmony_ci continue; 15728c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == block_type) { 15738c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->wait_for_idle((void *)adev); 15748c2ecf20Sopenharmony_ci if (r) 15758c2ecf20Sopenharmony_ci return r; 15768c2ecf20Sopenharmony_ci break; 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci return 0; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci/** 15848c2ecf20Sopenharmony_ci * amdgpu_device_ip_is_idle - is the hardware IP idle 15858c2ecf20Sopenharmony_ci * 15868c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 15878c2ecf20Sopenharmony_ci * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) 15888c2ecf20Sopenharmony_ci * 15898c2ecf20Sopenharmony_ci * Check if the hardware IP is idle or not. 15908c2ecf20Sopenharmony_ci * Returns true if it the IP is idle, false if not. 15918c2ecf20Sopenharmony_ci */ 15928c2ecf20Sopenharmony_cibool amdgpu_device_ip_is_idle(struct amdgpu_device *adev, 15938c2ecf20Sopenharmony_ci enum amd_ip_block_type block_type) 15948c2ecf20Sopenharmony_ci{ 15958c2ecf20Sopenharmony_ci int i; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 15988c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 15998c2ecf20Sopenharmony_ci continue; 16008c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == block_type) 16018c2ecf20Sopenharmony_ci return adev->ip_blocks[i].version->funcs->is_idle((void *)adev); 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci return true; 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci} 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci/** 16088c2ecf20Sopenharmony_ci * amdgpu_device_ip_get_ip_block - get a hw IP pointer 16098c2ecf20Sopenharmony_ci * 16108c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 16118c2ecf20Sopenharmony_ci * @type: Type of hardware IP (SMU, GFX, UVD, etc.) 16128c2ecf20Sopenharmony_ci * 16138c2ecf20Sopenharmony_ci * Returns a pointer to the hardware IP block structure 16148c2ecf20Sopenharmony_ci * if it exists for the asic, otherwise NULL. 16158c2ecf20Sopenharmony_ci */ 16168c2ecf20Sopenharmony_cistruct amdgpu_ip_block * 16178c2ecf20Sopenharmony_ciamdgpu_device_ip_get_ip_block(struct amdgpu_device *adev, 16188c2ecf20Sopenharmony_ci enum amd_ip_block_type type) 16198c2ecf20Sopenharmony_ci{ 16208c2ecf20Sopenharmony_ci int i; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) 16238c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == type) 16248c2ecf20Sopenharmony_ci return &adev->ip_blocks[i]; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci return NULL; 16278c2ecf20Sopenharmony_ci} 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci/** 16308c2ecf20Sopenharmony_ci * amdgpu_device_ip_block_version_cmp 16318c2ecf20Sopenharmony_ci * 16328c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 16338c2ecf20Sopenharmony_ci * @type: enum amd_ip_block_type 16348c2ecf20Sopenharmony_ci * @major: major version 16358c2ecf20Sopenharmony_ci * @minor: minor version 16368c2ecf20Sopenharmony_ci * 16378c2ecf20Sopenharmony_ci * return 0 if equal or greater 16388c2ecf20Sopenharmony_ci * return 1 if smaller or the ip_block doesn't exist 16398c2ecf20Sopenharmony_ci */ 16408c2ecf20Sopenharmony_ciint amdgpu_device_ip_block_version_cmp(struct amdgpu_device *adev, 16418c2ecf20Sopenharmony_ci enum amd_ip_block_type type, 16428c2ecf20Sopenharmony_ci u32 major, u32 minor) 16438c2ecf20Sopenharmony_ci{ 16448c2ecf20Sopenharmony_ci struct amdgpu_ip_block *ip_block = amdgpu_device_ip_get_ip_block(adev, type); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci if (ip_block && ((ip_block->version->major > major) || 16478c2ecf20Sopenharmony_ci ((ip_block->version->major == major) && 16488c2ecf20Sopenharmony_ci (ip_block->version->minor >= minor)))) 16498c2ecf20Sopenharmony_ci return 0; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci return 1; 16528c2ecf20Sopenharmony_ci} 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci/** 16558c2ecf20Sopenharmony_ci * amdgpu_device_ip_block_add 16568c2ecf20Sopenharmony_ci * 16578c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 16588c2ecf20Sopenharmony_ci * @ip_block_version: pointer to the IP to add 16598c2ecf20Sopenharmony_ci * 16608c2ecf20Sopenharmony_ci * Adds the IP block driver information to the collection of IPs 16618c2ecf20Sopenharmony_ci * on the asic. 16628c2ecf20Sopenharmony_ci */ 16638c2ecf20Sopenharmony_ciint amdgpu_device_ip_block_add(struct amdgpu_device *adev, 16648c2ecf20Sopenharmony_ci const struct amdgpu_ip_block_version *ip_block_version) 16658c2ecf20Sopenharmony_ci{ 16668c2ecf20Sopenharmony_ci if (!ip_block_version) 16678c2ecf20Sopenharmony_ci return -EINVAL; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci DRM_INFO("add ip block number %d <%s>\n", adev->num_ip_blocks, 16708c2ecf20Sopenharmony_ci ip_block_version->funcs->name); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci adev->ip_blocks[adev->num_ip_blocks++].version = ip_block_version; 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci return 0; 16758c2ecf20Sopenharmony_ci} 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci/** 16788c2ecf20Sopenharmony_ci * amdgpu_device_enable_virtual_display - enable virtual display feature 16798c2ecf20Sopenharmony_ci * 16808c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 16818c2ecf20Sopenharmony_ci * 16828c2ecf20Sopenharmony_ci * Enabled the virtual display feature if the user has enabled it via 16838c2ecf20Sopenharmony_ci * the module parameter virtual_display. This feature provides a virtual 16848c2ecf20Sopenharmony_ci * display hardware on headless boards or in virtualized environments. 16858c2ecf20Sopenharmony_ci * This function parses and validates the configuration string specified by 16868c2ecf20Sopenharmony_ci * the user and configues the virtual display configuration (number of 16878c2ecf20Sopenharmony_ci * virtual connectors, crtcs, etc.) specified. 16888c2ecf20Sopenharmony_ci */ 16898c2ecf20Sopenharmony_cistatic void amdgpu_device_enable_virtual_display(struct amdgpu_device *adev) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci adev->enable_virtual_display = false; 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci if (amdgpu_virtual_display) { 16948c2ecf20Sopenharmony_ci struct drm_device *ddev = adev_to_drm(adev); 16958c2ecf20Sopenharmony_ci const char *pci_address_name = pci_name(ddev->pdev); 16968c2ecf20Sopenharmony_ci char *pciaddstr, *pciaddstr_tmp, *pciaddname_tmp, *pciaddname; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci pciaddstr = kstrdup(amdgpu_virtual_display, GFP_KERNEL); 16998c2ecf20Sopenharmony_ci pciaddstr_tmp = pciaddstr; 17008c2ecf20Sopenharmony_ci while ((pciaddname_tmp = strsep(&pciaddstr_tmp, ";"))) { 17018c2ecf20Sopenharmony_ci pciaddname = strsep(&pciaddname_tmp, ","); 17028c2ecf20Sopenharmony_ci if (!strcmp("all", pciaddname) 17038c2ecf20Sopenharmony_ci || !strcmp(pci_address_name, pciaddname)) { 17048c2ecf20Sopenharmony_ci long num_crtc; 17058c2ecf20Sopenharmony_ci int res = -1; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci adev->enable_virtual_display = true; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (pciaddname_tmp) 17108c2ecf20Sopenharmony_ci res = kstrtol(pciaddname_tmp, 10, 17118c2ecf20Sopenharmony_ci &num_crtc); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if (!res) { 17148c2ecf20Sopenharmony_ci if (num_crtc < 1) 17158c2ecf20Sopenharmony_ci num_crtc = 1; 17168c2ecf20Sopenharmony_ci if (num_crtc > 6) 17178c2ecf20Sopenharmony_ci num_crtc = 6; 17188c2ecf20Sopenharmony_ci adev->mode_info.num_crtc = num_crtc; 17198c2ecf20Sopenharmony_ci } else { 17208c2ecf20Sopenharmony_ci adev->mode_info.num_crtc = 1; 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci break; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci DRM_INFO("virtual display string:%s, %s:virtual_display:%d, num_crtc:%d\n", 17278c2ecf20Sopenharmony_ci amdgpu_virtual_display, pci_address_name, 17288c2ecf20Sopenharmony_ci adev->enable_virtual_display, adev->mode_info.num_crtc); 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci kfree(pciaddstr); 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci} 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci/** 17358c2ecf20Sopenharmony_ci * amdgpu_device_parse_gpu_info_fw - parse gpu info firmware 17368c2ecf20Sopenharmony_ci * 17378c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 17388c2ecf20Sopenharmony_ci * 17398c2ecf20Sopenharmony_ci * Parses the asic configuration parameters specified in the gpu info 17408c2ecf20Sopenharmony_ci * firmware and makes them availale to the driver for use in configuring 17418c2ecf20Sopenharmony_ci * the asic. 17428c2ecf20Sopenharmony_ci * Returns 0 on success, -EINVAL on failure. 17438c2ecf20Sopenharmony_ci */ 17448c2ecf20Sopenharmony_cistatic int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci const char *chip_name; 17478c2ecf20Sopenharmony_ci char fw_name[40]; 17488c2ecf20Sopenharmony_ci int err; 17498c2ecf20Sopenharmony_ci const struct gpu_info_firmware_header_v1_0 *hdr; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci adev->firmware.gpu_info_fw = NULL; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci if (adev->mman.discovery_bin) { 17548c2ecf20Sopenharmony_ci amdgpu_discovery_get_gfx_info(adev); 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci /* 17578c2ecf20Sopenharmony_ci * FIXME: The bounding box is still needed by Navi12, so 17588c2ecf20Sopenharmony_ci * temporarily read it from gpu_info firmware. Should be droped 17598c2ecf20Sopenharmony_ci * when DAL no longer needs it. 17608c2ecf20Sopenharmony_ci */ 17618c2ecf20Sopenharmony_ci if (adev->asic_type != CHIP_NAVI12) 17628c2ecf20Sopenharmony_ci return 0; 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci switch (adev->asic_type) { 17668c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_SI 17678c2ecf20Sopenharmony_ci case CHIP_VERDE: 17688c2ecf20Sopenharmony_ci case CHIP_TAHITI: 17698c2ecf20Sopenharmony_ci case CHIP_PITCAIRN: 17708c2ecf20Sopenharmony_ci case CHIP_OLAND: 17718c2ecf20Sopenharmony_ci case CHIP_HAINAN: 17728c2ecf20Sopenharmony_ci#endif 17738c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 17748c2ecf20Sopenharmony_ci case CHIP_BONAIRE: 17758c2ecf20Sopenharmony_ci case CHIP_HAWAII: 17768c2ecf20Sopenharmony_ci case CHIP_KAVERI: 17778c2ecf20Sopenharmony_ci case CHIP_KABINI: 17788c2ecf20Sopenharmony_ci case CHIP_MULLINS: 17798c2ecf20Sopenharmony_ci#endif 17808c2ecf20Sopenharmony_ci case CHIP_TOPAZ: 17818c2ecf20Sopenharmony_ci case CHIP_TONGA: 17828c2ecf20Sopenharmony_ci case CHIP_FIJI: 17838c2ecf20Sopenharmony_ci case CHIP_POLARIS10: 17848c2ecf20Sopenharmony_ci case CHIP_POLARIS11: 17858c2ecf20Sopenharmony_ci case CHIP_POLARIS12: 17868c2ecf20Sopenharmony_ci case CHIP_VEGAM: 17878c2ecf20Sopenharmony_ci case CHIP_CARRIZO: 17888c2ecf20Sopenharmony_ci case CHIP_STONEY: 17898c2ecf20Sopenharmony_ci case CHIP_VEGA20: 17908c2ecf20Sopenharmony_ci case CHIP_SIENNA_CICHLID: 17918c2ecf20Sopenharmony_ci case CHIP_NAVY_FLOUNDER: 17928c2ecf20Sopenharmony_ci default: 17938c2ecf20Sopenharmony_ci return 0; 17948c2ecf20Sopenharmony_ci case CHIP_VEGA10: 17958c2ecf20Sopenharmony_ci chip_name = "vega10"; 17968c2ecf20Sopenharmony_ci break; 17978c2ecf20Sopenharmony_ci case CHIP_VEGA12: 17988c2ecf20Sopenharmony_ci chip_name = "vega12"; 17998c2ecf20Sopenharmony_ci break; 18008c2ecf20Sopenharmony_ci case CHIP_RAVEN: 18018c2ecf20Sopenharmony_ci if (adev->apu_flags & AMD_APU_IS_RAVEN2) 18028c2ecf20Sopenharmony_ci chip_name = "raven2"; 18038c2ecf20Sopenharmony_ci else if (adev->apu_flags & AMD_APU_IS_PICASSO) 18048c2ecf20Sopenharmony_ci chip_name = "picasso"; 18058c2ecf20Sopenharmony_ci else 18068c2ecf20Sopenharmony_ci chip_name = "raven"; 18078c2ecf20Sopenharmony_ci break; 18088c2ecf20Sopenharmony_ci case CHIP_ARCTURUS: 18098c2ecf20Sopenharmony_ci chip_name = "arcturus"; 18108c2ecf20Sopenharmony_ci break; 18118c2ecf20Sopenharmony_ci case CHIP_RENOIR: 18128c2ecf20Sopenharmony_ci if (adev->apu_flags & AMD_APU_IS_RENOIR) 18138c2ecf20Sopenharmony_ci chip_name = "renoir"; 18148c2ecf20Sopenharmony_ci else 18158c2ecf20Sopenharmony_ci chip_name = "green_sardine"; 18168c2ecf20Sopenharmony_ci break; 18178c2ecf20Sopenharmony_ci case CHIP_NAVI10: 18188c2ecf20Sopenharmony_ci chip_name = "navi10"; 18198c2ecf20Sopenharmony_ci break; 18208c2ecf20Sopenharmony_ci case CHIP_NAVI14: 18218c2ecf20Sopenharmony_ci chip_name = "navi14"; 18228c2ecf20Sopenharmony_ci break; 18238c2ecf20Sopenharmony_ci case CHIP_NAVI12: 18248c2ecf20Sopenharmony_ci chip_name = "navi12"; 18258c2ecf20Sopenharmony_ci break; 18268c2ecf20Sopenharmony_ci } 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_gpu_info.bin", chip_name); 18298c2ecf20Sopenharmony_ci err = request_firmware(&adev->firmware.gpu_info_fw, fw_name, adev->dev); 18308c2ecf20Sopenharmony_ci if (err) { 18318c2ecf20Sopenharmony_ci dev_err(adev->dev, 18328c2ecf20Sopenharmony_ci "Failed to load gpu_info firmware \"%s\"\n", 18338c2ecf20Sopenharmony_ci fw_name); 18348c2ecf20Sopenharmony_ci goto out; 18358c2ecf20Sopenharmony_ci } 18368c2ecf20Sopenharmony_ci err = amdgpu_ucode_validate(adev->firmware.gpu_info_fw); 18378c2ecf20Sopenharmony_ci if (err) { 18388c2ecf20Sopenharmony_ci dev_err(adev->dev, 18398c2ecf20Sopenharmony_ci "Failed to validate gpu_info firmware \"%s\"\n", 18408c2ecf20Sopenharmony_ci fw_name); 18418c2ecf20Sopenharmony_ci goto out; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci hdr = (const struct gpu_info_firmware_header_v1_0 *)adev->firmware.gpu_info_fw->data; 18458c2ecf20Sopenharmony_ci amdgpu_ucode_print_gpu_info_hdr(&hdr->header); 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci switch (hdr->version_major) { 18488c2ecf20Sopenharmony_ci case 1: 18498c2ecf20Sopenharmony_ci { 18508c2ecf20Sopenharmony_ci const struct gpu_info_firmware_v1_0 *gpu_info_fw = 18518c2ecf20Sopenharmony_ci (const struct gpu_info_firmware_v1_0 *)(adev->firmware.gpu_info_fw->data + 18528c2ecf20Sopenharmony_ci le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci /* 18558c2ecf20Sopenharmony_ci * Should be droped when DAL no longer needs it. 18568c2ecf20Sopenharmony_ci */ 18578c2ecf20Sopenharmony_ci if (adev->asic_type == CHIP_NAVI12) 18588c2ecf20Sopenharmony_ci goto parse_soc_bounding_box; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci adev->gfx.config.max_shader_engines = le32_to_cpu(gpu_info_fw->gc_num_se); 18618c2ecf20Sopenharmony_ci adev->gfx.config.max_cu_per_sh = le32_to_cpu(gpu_info_fw->gc_num_cu_per_sh); 18628c2ecf20Sopenharmony_ci adev->gfx.config.max_sh_per_se = le32_to_cpu(gpu_info_fw->gc_num_sh_per_se); 18638c2ecf20Sopenharmony_ci adev->gfx.config.max_backends_per_se = le32_to_cpu(gpu_info_fw->gc_num_rb_per_se); 18648c2ecf20Sopenharmony_ci adev->gfx.config.max_texture_channel_caches = 18658c2ecf20Sopenharmony_ci le32_to_cpu(gpu_info_fw->gc_num_tccs); 18668c2ecf20Sopenharmony_ci adev->gfx.config.max_gprs = le32_to_cpu(gpu_info_fw->gc_num_gprs); 18678c2ecf20Sopenharmony_ci adev->gfx.config.max_gs_threads = le32_to_cpu(gpu_info_fw->gc_num_max_gs_thds); 18688c2ecf20Sopenharmony_ci adev->gfx.config.gs_vgt_table_depth = le32_to_cpu(gpu_info_fw->gc_gs_table_depth); 18698c2ecf20Sopenharmony_ci adev->gfx.config.gs_prim_buffer_depth = le32_to_cpu(gpu_info_fw->gc_gsprim_buff_depth); 18708c2ecf20Sopenharmony_ci adev->gfx.config.double_offchip_lds_buf = 18718c2ecf20Sopenharmony_ci le32_to_cpu(gpu_info_fw->gc_double_offchip_lds_buffer); 18728c2ecf20Sopenharmony_ci adev->gfx.cu_info.wave_front_size = le32_to_cpu(gpu_info_fw->gc_wave_size); 18738c2ecf20Sopenharmony_ci adev->gfx.cu_info.max_waves_per_simd = 18748c2ecf20Sopenharmony_ci le32_to_cpu(gpu_info_fw->gc_max_waves_per_simd); 18758c2ecf20Sopenharmony_ci adev->gfx.cu_info.max_scratch_slots_per_cu = 18768c2ecf20Sopenharmony_ci le32_to_cpu(gpu_info_fw->gc_max_scratch_slots_per_cu); 18778c2ecf20Sopenharmony_ci adev->gfx.cu_info.lds_size = le32_to_cpu(gpu_info_fw->gc_lds_size); 18788c2ecf20Sopenharmony_ci if (hdr->version_minor >= 1) { 18798c2ecf20Sopenharmony_ci const struct gpu_info_firmware_v1_1 *gpu_info_fw = 18808c2ecf20Sopenharmony_ci (const struct gpu_info_firmware_v1_1 *)(adev->firmware.gpu_info_fw->data + 18818c2ecf20Sopenharmony_ci le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 18828c2ecf20Sopenharmony_ci adev->gfx.config.num_sc_per_sh = 18838c2ecf20Sopenharmony_ci le32_to_cpu(gpu_info_fw->num_sc_per_sh); 18848c2ecf20Sopenharmony_ci adev->gfx.config.num_packer_per_sc = 18858c2ecf20Sopenharmony_ci le32_to_cpu(gpu_info_fw->num_packer_per_sc); 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ciparse_soc_bounding_box: 18898c2ecf20Sopenharmony_ci /* 18908c2ecf20Sopenharmony_ci * soc bounding box info is not integrated in disocovery table, 18918c2ecf20Sopenharmony_ci * we always need to parse it from gpu info firmware if needed. 18928c2ecf20Sopenharmony_ci */ 18938c2ecf20Sopenharmony_ci if (hdr->version_minor == 2) { 18948c2ecf20Sopenharmony_ci const struct gpu_info_firmware_v1_2 *gpu_info_fw = 18958c2ecf20Sopenharmony_ci (const struct gpu_info_firmware_v1_2 *)(adev->firmware.gpu_info_fw->data + 18968c2ecf20Sopenharmony_ci le32_to_cpu(hdr->header.ucode_array_offset_bytes)); 18978c2ecf20Sopenharmony_ci adev->dm.soc_bounding_box = &gpu_info_fw->soc_bounding_box; 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci break; 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ci default: 19028c2ecf20Sopenharmony_ci dev_err(adev->dev, 19038c2ecf20Sopenharmony_ci "Unsupported gpu_info table %d\n", hdr->header.ucode_version); 19048c2ecf20Sopenharmony_ci err = -EINVAL; 19058c2ecf20Sopenharmony_ci goto out; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ciout: 19088c2ecf20Sopenharmony_ci return err; 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci/** 19128c2ecf20Sopenharmony_ci * amdgpu_device_ip_early_init - run early init for hardware IPs 19138c2ecf20Sopenharmony_ci * 19148c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 19158c2ecf20Sopenharmony_ci * 19168c2ecf20Sopenharmony_ci * Early initialization pass for hardware IPs. The hardware IPs that make 19178c2ecf20Sopenharmony_ci * up each asic are discovered each IP's early_init callback is run. This 19188c2ecf20Sopenharmony_ci * is the first stage in initializing the asic. 19198c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 19208c2ecf20Sopenharmony_ci */ 19218c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_early_init(struct amdgpu_device *adev) 19228c2ecf20Sopenharmony_ci{ 19238c2ecf20Sopenharmony_ci int i, r; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci amdgpu_device_enable_virtual_display(adev); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) { 19288c2ecf20Sopenharmony_ci r = amdgpu_virt_request_full_gpu(adev, true); 19298c2ecf20Sopenharmony_ci if (r) 19308c2ecf20Sopenharmony_ci return r; 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci switch (adev->asic_type) { 19348c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_SI 19358c2ecf20Sopenharmony_ci case CHIP_VERDE: 19368c2ecf20Sopenharmony_ci case CHIP_TAHITI: 19378c2ecf20Sopenharmony_ci case CHIP_PITCAIRN: 19388c2ecf20Sopenharmony_ci case CHIP_OLAND: 19398c2ecf20Sopenharmony_ci case CHIP_HAINAN: 19408c2ecf20Sopenharmony_ci adev->family = AMDGPU_FAMILY_SI; 19418c2ecf20Sopenharmony_ci r = si_set_ip_blocks(adev); 19428c2ecf20Sopenharmony_ci if (r) 19438c2ecf20Sopenharmony_ci return r; 19448c2ecf20Sopenharmony_ci break; 19458c2ecf20Sopenharmony_ci#endif 19468c2ecf20Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_CIK 19478c2ecf20Sopenharmony_ci case CHIP_BONAIRE: 19488c2ecf20Sopenharmony_ci case CHIP_HAWAII: 19498c2ecf20Sopenharmony_ci case CHIP_KAVERI: 19508c2ecf20Sopenharmony_ci case CHIP_KABINI: 19518c2ecf20Sopenharmony_ci case CHIP_MULLINS: 19528c2ecf20Sopenharmony_ci if (adev->flags & AMD_IS_APU) 19538c2ecf20Sopenharmony_ci adev->family = AMDGPU_FAMILY_KV; 19548c2ecf20Sopenharmony_ci else 19558c2ecf20Sopenharmony_ci adev->family = AMDGPU_FAMILY_CI; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci r = cik_set_ip_blocks(adev); 19588c2ecf20Sopenharmony_ci if (r) 19598c2ecf20Sopenharmony_ci return r; 19608c2ecf20Sopenharmony_ci break; 19618c2ecf20Sopenharmony_ci#endif 19628c2ecf20Sopenharmony_ci case CHIP_TOPAZ: 19638c2ecf20Sopenharmony_ci case CHIP_TONGA: 19648c2ecf20Sopenharmony_ci case CHIP_FIJI: 19658c2ecf20Sopenharmony_ci case CHIP_POLARIS10: 19668c2ecf20Sopenharmony_ci case CHIP_POLARIS11: 19678c2ecf20Sopenharmony_ci case CHIP_POLARIS12: 19688c2ecf20Sopenharmony_ci case CHIP_VEGAM: 19698c2ecf20Sopenharmony_ci case CHIP_CARRIZO: 19708c2ecf20Sopenharmony_ci case CHIP_STONEY: 19718c2ecf20Sopenharmony_ci if (adev->flags & AMD_IS_APU) 19728c2ecf20Sopenharmony_ci adev->family = AMDGPU_FAMILY_CZ; 19738c2ecf20Sopenharmony_ci else 19748c2ecf20Sopenharmony_ci adev->family = AMDGPU_FAMILY_VI; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci r = vi_set_ip_blocks(adev); 19778c2ecf20Sopenharmony_ci if (r) 19788c2ecf20Sopenharmony_ci return r; 19798c2ecf20Sopenharmony_ci break; 19808c2ecf20Sopenharmony_ci case CHIP_VEGA10: 19818c2ecf20Sopenharmony_ci case CHIP_VEGA12: 19828c2ecf20Sopenharmony_ci case CHIP_VEGA20: 19838c2ecf20Sopenharmony_ci case CHIP_RAVEN: 19848c2ecf20Sopenharmony_ci case CHIP_ARCTURUS: 19858c2ecf20Sopenharmony_ci case CHIP_RENOIR: 19868c2ecf20Sopenharmony_ci if (adev->flags & AMD_IS_APU) 19878c2ecf20Sopenharmony_ci adev->family = AMDGPU_FAMILY_RV; 19888c2ecf20Sopenharmony_ci else 19898c2ecf20Sopenharmony_ci adev->family = AMDGPU_FAMILY_AI; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci r = soc15_set_ip_blocks(adev); 19928c2ecf20Sopenharmony_ci if (r) 19938c2ecf20Sopenharmony_ci return r; 19948c2ecf20Sopenharmony_ci break; 19958c2ecf20Sopenharmony_ci case CHIP_NAVI10: 19968c2ecf20Sopenharmony_ci case CHIP_NAVI14: 19978c2ecf20Sopenharmony_ci case CHIP_NAVI12: 19988c2ecf20Sopenharmony_ci case CHIP_SIENNA_CICHLID: 19998c2ecf20Sopenharmony_ci case CHIP_NAVY_FLOUNDER: 20008c2ecf20Sopenharmony_ci adev->family = AMDGPU_FAMILY_NV; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci r = nv_set_ip_blocks(adev); 20038c2ecf20Sopenharmony_ci if (r) 20048c2ecf20Sopenharmony_ci return r; 20058c2ecf20Sopenharmony_ci break; 20068c2ecf20Sopenharmony_ci default: 20078c2ecf20Sopenharmony_ci /* FIXME: not supported yet */ 20088c2ecf20Sopenharmony_ci return -EINVAL; 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci amdgpu_amdkfd_device_probe(adev); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci adev->pm.pp_feature = amdgpu_pp_feature_mask; 20148c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS) 20158c2ecf20Sopenharmony_ci adev->pm.pp_feature &= ~PP_GFXOFF_MASK; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 20188c2ecf20Sopenharmony_ci if ((amdgpu_ip_block_mask & (1 << i)) == 0) { 20198c2ecf20Sopenharmony_ci DRM_ERROR("disabled ip block: %d <%s>\n", 20208c2ecf20Sopenharmony_ci i, adev->ip_blocks[i].version->funcs->name); 20218c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.valid = false; 20228c2ecf20Sopenharmony_ci } else { 20238c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->funcs->early_init) { 20248c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->early_init((void *)adev); 20258c2ecf20Sopenharmony_ci if (r == -ENOENT) { 20268c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.valid = false; 20278c2ecf20Sopenharmony_ci } else if (r) { 20288c2ecf20Sopenharmony_ci DRM_ERROR("early_init of IP block <%s> failed %d\n", 20298c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 20308c2ecf20Sopenharmony_ci return r; 20318c2ecf20Sopenharmony_ci } else { 20328c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.valid = true; 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci } else { 20358c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.valid = true; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci /* get the vbios after the asic_funcs are set up */ 20398c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) { 20408c2ecf20Sopenharmony_ci r = amdgpu_device_parse_gpu_info_fw(adev); 20418c2ecf20Sopenharmony_ci if (r) 20428c2ecf20Sopenharmony_ci return r; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci /* Read BIOS */ 20458c2ecf20Sopenharmony_ci if (!amdgpu_get_bios(adev)) 20468c2ecf20Sopenharmony_ci return -EINVAL; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci r = amdgpu_atombios_init(adev); 20498c2ecf20Sopenharmony_ci if (r) { 20508c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu_atombios_init failed\n"); 20518c2ecf20Sopenharmony_ci amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_ATOMBIOS_INIT_FAIL, 0, 0); 20528c2ecf20Sopenharmony_ci return r; 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci /*get pf2vf msg info at it's earliest time*/ 20568c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 20578c2ecf20Sopenharmony_ci amdgpu_virt_init_data_exchange(adev); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci } 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci adev->cg_flags &= amdgpu_cg_mask; 20638c2ecf20Sopenharmony_ci adev->pg_flags &= amdgpu_pg_mask; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci return 0; 20668c2ecf20Sopenharmony_ci} 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_hw_init_phase1(struct amdgpu_device *adev) 20698c2ecf20Sopenharmony_ci{ 20708c2ecf20Sopenharmony_ci int i, r; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 20738c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.sw) 20748c2ecf20Sopenharmony_ci continue; 20758c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].status.hw) 20768c2ecf20Sopenharmony_ci continue; 20778c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || 20788c2ecf20Sopenharmony_ci (amdgpu_sriov_vf(adev) && (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)) || 20798c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) { 20808c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->hw_init(adev); 20818c2ecf20Sopenharmony_ci if (r) { 20828c2ecf20Sopenharmony_ci DRM_ERROR("hw_init of IP block <%s> failed %d\n", 20838c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 20848c2ecf20Sopenharmony_ci return r; 20858c2ecf20Sopenharmony_ci } 20868c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = true; 20878c2ecf20Sopenharmony_ci } 20888c2ecf20Sopenharmony_ci } 20898c2ecf20Sopenharmony_ci 20908c2ecf20Sopenharmony_ci return 0; 20918c2ecf20Sopenharmony_ci} 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_hw_init_phase2(struct amdgpu_device *adev) 20948c2ecf20Sopenharmony_ci{ 20958c2ecf20Sopenharmony_ci int i, r; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 20988c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.sw) 20998c2ecf20Sopenharmony_ci continue; 21008c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].status.hw) 21018c2ecf20Sopenharmony_ci continue; 21028c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->hw_init(adev); 21038c2ecf20Sopenharmony_ci if (r) { 21048c2ecf20Sopenharmony_ci DRM_ERROR("hw_init of IP block <%s> failed %d\n", 21058c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 21068c2ecf20Sopenharmony_ci return r; 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = true; 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci return 0; 21128c2ecf20Sopenharmony_ci} 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_cistatic int amdgpu_device_fw_loading(struct amdgpu_device *adev) 21158c2ecf20Sopenharmony_ci{ 21168c2ecf20Sopenharmony_ci int r = 0; 21178c2ecf20Sopenharmony_ci int i; 21188c2ecf20Sopenharmony_ci uint32_t smu_version; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (adev->asic_type >= CHIP_VEGA10) { 21218c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 21228c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_PSP) 21238c2ecf20Sopenharmony_ci continue; 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci /* no need to do the fw loading again if already done*/ 21268c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].status.hw == true) 21278c2ecf20Sopenharmony_ci break; 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci if (amdgpu_in_reset(adev) || adev->in_suspend) { 21308c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->resume(adev); 21318c2ecf20Sopenharmony_ci if (r) { 21328c2ecf20Sopenharmony_ci DRM_ERROR("resume of IP block <%s> failed %d\n", 21338c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 21348c2ecf20Sopenharmony_ci return r; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci } else { 21378c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->hw_init(adev); 21388c2ecf20Sopenharmony_ci if (r) { 21398c2ecf20Sopenharmony_ci DRM_ERROR("hw_init of IP block <%s> failed %d\n", 21408c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 21418c2ecf20Sopenharmony_ci return r; 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = true; 21468c2ecf20Sopenharmony_ci break; 21478c2ecf20Sopenharmony_ci } 21488c2ecf20Sopenharmony_ci } 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci if (!amdgpu_sriov_vf(adev) || adev->asic_type == CHIP_TONGA) 21518c2ecf20Sopenharmony_ci r = amdgpu_pm_load_smu_firmware(adev, &smu_version); 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci return r; 21548c2ecf20Sopenharmony_ci} 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci/** 21578c2ecf20Sopenharmony_ci * amdgpu_device_ip_init - run init for hardware IPs 21588c2ecf20Sopenharmony_ci * 21598c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 21608c2ecf20Sopenharmony_ci * 21618c2ecf20Sopenharmony_ci * Main initialization pass for hardware IPs. The list of all the hardware 21628c2ecf20Sopenharmony_ci * IPs that make up the asic is walked and the sw_init and hw_init callbacks 21638c2ecf20Sopenharmony_ci * are run. sw_init initializes the software state associated with each IP 21648c2ecf20Sopenharmony_ci * and hw_init initializes the hardware associated with each IP. 21658c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 21668c2ecf20Sopenharmony_ci */ 21678c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_init(struct amdgpu_device *adev) 21688c2ecf20Sopenharmony_ci{ 21698c2ecf20Sopenharmony_ci int i, r; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci r = amdgpu_ras_init(adev); 21728c2ecf20Sopenharmony_ci if (r) 21738c2ecf20Sopenharmony_ci return r; 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 21768c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 21778c2ecf20Sopenharmony_ci continue; 21788c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->sw_init((void *)adev); 21798c2ecf20Sopenharmony_ci if (r) { 21808c2ecf20Sopenharmony_ci DRM_ERROR("sw_init of IP block <%s> failed %d\n", 21818c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 21828c2ecf20Sopenharmony_ci goto init_failed; 21838c2ecf20Sopenharmony_ci } 21848c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.sw = true; 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci /* need to do gmc hw init early so we can allocate gpu mem */ 21878c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { 21888c2ecf20Sopenharmony_ci /* Try to reserve bad pages early */ 21898c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 21908c2ecf20Sopenharmony_ci amdgpu_virt_exchange_data(adev); 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci r = amdgpu_device_vram_scratch_init(adev); 21938c2ecf20Sopenharmony_ci if (r) { 21948c2ecf20Sopenharmony_ci DRM_ERROR("amdgpu_vram_scratch_init failed %d\n", r); 21958c2ecf20Sopenharmony_ci goto init_failed; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->hw_init((void *)adev); 21988c2ecf20Sopenharmony_ci if (r) { 21998c2ecf20Sopenharmony_ci DRM_ERROR("hw_init %d failed %d\n", i, r); 22008c2ecf20Sopenharmony_ci goto init_failed; 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci r = amdgpu_device_wb_init(adev); 22038c2ecf20Sopenharmony_ci if (r) { 22048c2ecf20Sopenharmony_ci DRM_ERROR("amdgpu_device_wb_init failed %d\n", r); 22058c2ecf20Sopenharmony_ci goto init_failed; 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = true; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci /* right after GMC hw init, we create CSA */ 22108c2ecf20Sopenharmony_ci if (amdgpu_mcbp || amdgpu_sriov_vf(adev)) { 22118c2ecf20Sopenharmony_ci r = amdgpu_allocate_static_csa(adev, &adev->virt.csa_obj, 22128c2ecf20Sopenharmony_ci AMDGPU_GEM_DOMAIN_VRAM, 22138c2ecf20Sopenharmony_ci AMDGPU_CSA_SIZE); 22148c2ecf20Sopenharmony_ci if (r) { 22158c2ecf20Sopenharmony_ci DRM_ERROR("allocate CSA failed %d\n", r); 22168c2ecf20Sopenharmony_ci goto init_failed; 22178c2ecf20Sopenharmony_ci } 22188c2ecf20Sopenharmony_ci } 22198c2ecf20Sopenharmony_ci } 22208c2ecf20Sopenharmony_ci } 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 22238c2ecf20Sopenharmony_ci amdgpu_virt_init_data_exchange(adev); 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci r = amdgpu_ib_pool_init(adev); 22268c2ecf20Sopenharmony_ci if (r) { 22278c2ecf20Sopenharmony_ci dev_err(adev->dev, "IB initialization failed (%d).\n", r); 22288c2ecf20Sopenharmony_ci amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_IB_INIT_FAIL, 0, r); 22298c2ecf20Sopenharmony_ci goto init_failed; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci r = amdgpu_ucode_create_bo(adev); /* create ucode bo when sw_init complete*/ 22338c2ecf20Sopenharmony_ci if (r) 22348c2ecf20Sopenharmony_ci goto init_failed; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci r = amdgpu_device_ip_hw_init_phase1(adev); 22378c2ecf20Sopenharmony_ci if (r) 22388c2ecf20Sopenharmony_ci goto init_failed; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci r = amdgpu_device_fw_loading(adev); 22418c2ecf20Sopenharmony_ci if (r) 22428c2ecf20Sopenharmony_ci goto init_failed; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci r = amdgpu_device_ip_hw_init_phase2(adev); 22458c2ecf20Sopenharmony_ci if (r) 22468c2ecf20Sopenharmony_ci goto init_failed; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci /* 22498c2ecf20Sopenharmony_ci * retired pages will be loaded from eeprom and reserved here, 22508c2ecf20Sopenharmony_ci * it should be called after amdgpu_device_ip_hw_init_phase2 since 22518c2ecf20Sopenharmony_ci * for some ASICs the RAS EEPROM code relies on SMU fully functioning 22528c2ecf20Sopenharmony_ci * for I2C communication which only true at this point. 22538c2ecf20Sopenharmony_ci * 22548c2ecf20Sopenharmony_ci * amdgpu_ras_recovery_init may fail, but the upper only cares the 22558c2ecf20Sopenharmony_ci * failure from bad gpu situation and stop amdgpu init process 22568c2ecf20Sopenharmony_ci * accordingly. For other failed cases, it will still release all 22578c2ecf20Sopenharmony_ci * the resource and print error message, rather than returning one 22588c2ecf20Sopenharmony_ci * negative value to upper level. 22598c2ecf20Sopenharmony_ci * 22608c2ecf20Sopenharmony_ci * Note: theoretically, this should be called before all vram allocations 22618c2ecf20Sopenharmony_ci * to protect retired page from abusing 22628c2ecf20Sopenharmony_ci */ 22638c2ecf20Sopenharmony_ci r = amdgpu_ras_recovery_init(adev); 22648c2ecf20Sopenharmony_ci if (r) 22658c2ecf20Sopenharmony_ci goto init_failed; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci if (adev->gmc.xgmi.num_physical_nodes > 1) 22688c2ecf20Sopenharmony_ci amdgpu_xgmi_add_device(adev); 22698c2ecf20Sopenharmony_ci amdgpu_amdkfd_device_init(adev); 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci amdgpu_fru_get_product_info(adev); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ciinit_failed: 22748c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 22758c2ecf20Sopenharmony_ci amdgpu_virt_release_full_gpu(adev, true); 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci return r; 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci/** 22818c2ecf20Sopenharmony_ci * amdgpu_device_fill_reset_magic - writes reset magic to gart pointer 22828c2ecf20Sopenharmony_ci * 22838c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 22848c2ecf20Sopenharmony_ci * 22858c2ecf20Sopenharmony_ci * Writes a reset magic value to the gart pointer in VRAM. The driver calls 22868c2ecf20Sopenharmony_ci * this function before a GPU reset. If the value is retained after a 22878c2ecf20Sopenharmony_ci * GPU reset, VRAM has not been lost. Some GPU resets may destry VRAM contents. 22888c2ecf20Sopenharmony_ci */ 22898c2ecf20Sopenharmony_cistatic void amdgpu_device_fill_reset_magic(struct amdgpu_device *adev) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci memcpy(adev->reset_magic, adev->gart.ptr, AMDGPU_RESET_MAGIC_NUM); 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci/** 22958c2ecf20Sopenharmony_ci * amdgpu_device_check_vram_lost - check if vram is valid 22968c2ecf20Sopenharmony_ci * 22978c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 22988c2ecf20Sopenharmony_ci * 22998c2ecf20Sopenharmony_ci * Checks the reset magic value written to the gart pointer in VRAM. 23008c2ecf20Sopenharmony_ci * The driver calls this after a GPU reset to see if the contents of 23018c2ecf20Sopenharmony_ci * VRAM is lost or now. 23028c2ecf20Sopenharmony_ci * returns true if vram is lost, false if not. 23038c2ecf20Sopenharmony_ci */ 23048c2ecf20Sopenharmony_cistatic bool amdgpu_device_check_vram_lost(struct amdgpu_device *adev) 23058c2ecf20Sopenharmony_ci{ 23068c2ecf20Sopenharmony_ci if (memcmp(adev->gart.ptr, adev->reset_magic, 23078c2ecf20Sopenharmony_ci AMDGPU_RESET_MAGIC_NUM)) 23088c2ecf20Sopenharmony_ci return true; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci if (!amdgpu_in_reset(adev)) 23118c2ecf20Sopenharmony_ci return false; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci /* 23148c2ecf20Sopenharmony_ci * For all ASICs with baco/mode1 reset, the VRAM is 23158c2ecf20Sopenharmony_ci * always assumed to be lost. 23168c2ecf20Sopenharmony_ci */ 23178c2ecf20Sopenharmony_ci switch (amdgpu_asic_reset_method(adev)) { 23188c2ecf20Sopenharmony_ci case AMD_RESET_METHOD_BACO: 23198c2ecf20Sopenharmony_ci case AMD_RESET_METHOD_MODE1: 23208c2ecf20Sopenharmony_ci return true; 23218c2ecf20Sopenharmony_ci default: 23228c2ecf20Sopenharmony_ci return false; 23238c2ecf20Sopenharmony_ci } 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci/** 23278c2ecf20Sopenharmony_ci * amdgpu_device_set_cg_state - set clockgating for amdgpu device 23288c2ecf20Sopenharmony_ci * 23298c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 23308c2ecf20Sopenharmony_ci * @state: clockgating state (gate or ungate) 23318c2ecf20Sopenharmony_ci * 23328c2ecf20Sopenharmony_ci * The list of all the hardware IPs that make up the asic is walked and the 23338c2ecf20Sopenharmony_ci * set_clockgating_state callbacks are run. 23348c2ecf20Sopenharmony_ci * Late initialization pass enabling clockgating for hardware IPs. 23358c2ecf20Sopenharmony_ci * Fini or suspend, pass disabling clockgating for hardware IPs. 23368c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 23378c2ecf20Sopenharmony_ci */ 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_cistatic int amdgpu_device_set_cg_state(struct amdgpu_device *adev, 23408c2ecf20Sopenharmony_ci enum amd_clockgating_state state) 23418c2ecf20Sopenharmony_ci{ 23428c2ecf20Sopenharmony_ci int i, j, r; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci if (amdgpu_emu_mode == 1) 23458c2ecf20Sopenharmony_ci return 0; 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci for (j = 0; j < adev->num_ip_blocks; j++) { 23488c2ecf20Sopenharmony_ci i = state == AMD_CG_STATE_GATE ? j : adev->num_ip_blocks - j - 1; 23498c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.late_initialized) 23508c2ecf20Sopenharmony_ci continue; 23518c2ecf20Sopenharmony_ci /* skip CG for VCE/UVD, it's handled specially */ 23528c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && 23538c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && 23548c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN && 23558c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG && 23568c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->set_clockgating_state) { 23578c2ecf20Sopenharmony_ci /* enable clockgating to save power */ 23588c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->set_clockgating_state((void *)adev, 23598c2ecf20Sopenharmony_ci state); 23608c2ecf20Sopenharmony_ci if (r) { 23618c2ecf20Sopenharmony_ci DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n", 23628c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 23638c2ecf20Sopenharmony_ci return r; 23648c2ecf20Sopenharmony_ci } 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci return 0; 23698c2ecf20Sopenharmony_ci} 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_cistatic int amdgpu_device_set_pg_state(struct amdgpu_device *adev, enum amd_powergating_state state) 23728c2ecf20Sopenharmony_ci{ 23738c2ecf20Sopenharmony_ci int i, j, r; 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci if (amdgpu_emu_mode == 1) 23768c2ecf20Sopenharmony_ci return 0; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci for (j = 0; j < adev->num_ip_blocks; j++) { 23798c2ecf20Sopenharmony_ci i = state == AMD_PG_STATE_GATE ? j : adev->num_ip_blocks - j - 1; 23808c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.late_initialized) 23818c2ecf20Sopenharmony_ci continue; 23828c2ecf20Sopenharmony_ci /* skip CG for VCE/UVD, it's handled specially */ 23838c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD && 23848c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE && 23858c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN && 23868c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG && 23878c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->set_powergating_state) { 23888c2ecf20Sopenharmony_ci /* enable powergating to save power */ 23898c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->set_powergating_state((void *)adev, 23908c2ecf20Sopenharmony_ci state); 23918c2ecf20Sopenharmony_ci if (r) { 23928c2ecf20Sopenharmony_ci DRM_ERROR("set_powergating_state(gate) of IP block <%s> failed %d\n", 23938c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 23948c2ecf20Sopenharmony_ci return r; 23958c2ecf20Sopenharmony_ci } 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci } 23988c2ecf20Sopenharmony_ci return 0; 23998c2ecf20Sopenharmony_ci} 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_cistatic int amdgpu_device_enable_mgpu_fan_boost(void) 24028c2ecf20Sopenharmony_ci{ 24038c2ecf20Sopenharmony_ci struct amdgpu_gpu_instance *gpu_ins; 24048c2ecf20Sopenharmony_ci struct amdgpu_device *adev; 24058c2ecf20Sopenharmony_ci int i, ret = 0; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci mutex_lock(&mgpu_info.mutex); 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci /* 24108c2ecf20Sopenharmony_ci * MGPU fan boost feature should be enabled 24118c2ecf20Sopenharmony_ci * only when there are two or more dGPUs in 24128c2ecf20Sopenharmony_ci * the system 24138c2ecf20Sopenharmony_ci */ 24148c2ecf20Sopenharmony_ci if (mgpu_info.num_dgpu < 2) 24158c2ecf20Sopenharmony_ci goto out; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci for (i = 0; i < mgpu_info.num_dgpu; i++) { 24188c2ecf20Sopenharmony_ci gpu_ins = &(mgpu_info.gpu_ins[i]); 24198c2ecf20Sopenharmony_ci adev = gpu_ins->adev; 24208c2ecf20Sopenharmony_ci if (!(adev->flags & AMD_IS_APU) && 24218c2ecf20Sopenharmony_ci !gpu_ins->mgpu_fan_enabled) { 24228c2ecf20Sopenharmony_ci ret = amdgpu_dpm_enable_mgpu_fan_boost(adev); 24238c2ecf20Sopenharmony_ci if (ret) 24248c2ecf20Sopenharmony_ci break; 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_ci gpu_ins->mgpu_fan_enabled = 1; 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ciout: 24318c2ecf20Sopenharmony_ci mutex_unlock(&mgpu_info.mutex); 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci return ret; 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci/** 24378c2ecf20Sopenharmony_ci * amdgpu_device_ip_late_init - run late init for hardware IPs 24388c2ecf20Sopenharmony_ci * 24398c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 24408c2ecf20Sopenharmony_ci * 24418c2ecf20Sopenharmony_ci * Late initialization pass for hardware IPs. The list of all the hardware 24428c2ecf20Sopenharmony_ci * IPs that make up the asic is walked and the late_init callbacks are run. 24438c2ecf20Sopenharmony_ci * late_init covers any special initialization that an IP requires 24448c2ecf20Sopenharmony_ci * after all of the have been initialized or something that needs to happen 24458c2ecf20Sopenharmony_ci * late in the init process. 24468c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 24478c2ecf20Sopenharmony_ci */ 24488c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_late_init(struct amdgpu_device *adev) 24498c2ecf20Sopenharmony_ci{ 24508c2ecf20Sopenharmony_ci struct amdgpu_gpu_instance *gpu_instance; 24518c2ecf20Sopenharmony_ci int i = 0, r; 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 24548c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.hw) 24558c2ecf20Sopenharmony_ci continue; 24568c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->funcs->late_init) { 24578c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->late_init((void *)adev); 24588c2ecf20Sopenharmony_ci if (r) { 24598c2ecf20Sopenharmony_ci DRM_ERROR("late_init of IP block <%s> failed %d\n", 24608c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 24618c2ecf20Sopenharmony_ci return r; 24628c2ecf20Sopenharmony_ci } 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.late_initialized = true; 24658c2ecf20Sopenharmony_ci } 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci amdgpu_ras_set_error_query_ready(adev, true); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci amdgpu_device_set_cg_state(adev, AMD_CG_STATE_GATE); 24708c2ecf20Sopenharmony_ci amdgpu_device_set_pg_state(adev, AMD_PG_STATE_GATE); 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci amdgpu_device_fill_reset_magic(adev); 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci r = amdgpu_device_enable_mgpu_fan_boost(); 24758c2ecf20Sopenharmony_ci if (r) 24768c2ecf20Sopenharmony_ci DRM_ERROR("enable mgpu fan boost failed (%d).\n", r); 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci if (adev->gmc.xgmi.num_physical_nodes > 1) { 24808c2ecf20Sopenharmony_ci mutex_lock(&mgpu_info.mutex); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci /* 24838c2ecf20Sopenharmony_ci * Reset device p-state to low as this was booted with high. 24848c2ecf20Sopenharmony_ci * 24858c2ecf20Sopenharmony_ci * This should be performed only after all devices from the same 24868c2ecf20Sopenharmony_ci * hive get initialized. 24878c2ecf20Sopenharmony_ci * 24888c2ecf20Sopenharmony_ci * However, it's unknown how many device in the hive in advance. 24898c2ecf20Sopenharmony_ci * As this is counted one by one during devices initializations. 24908c2ecf20Sopenharmony_ci * 24918c2ecf20Sopenharmony_ci * So, we wait for all XGMI interlinked devices initialized. 24928c2ecf20Sopenharmony_ci * This may bring some delays as those devices may come from 24938c2ecf20Sopenharmony_ci * different hives. But that should be OK. 24948c2ecf20Sopenharmony_ci */ 24958c2ecf20Sopenharmony_ci if (mgpu_info.num_dgpu == adev->gmc.xgmi.num_physical_nodes) { 24968c2ecf20Sopenharmony_ci for (i = 0; i < mgpu_info.num_gpu; i++) { 24978c2ecf20Sopenharmony_ci gpu_instance = &(mgpu_info.gpu_ins[i]); 24988c2ecf20Sopenharmony_ci if (gpu_instance->adev->flags & AMD_IS_APU) 24998c2ecf20Sopenharmony_ci continue; 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci r = amdgpu_xgmi_set_pstate(gpu_instance->adev, 25028c2ecf20Sopenharmony_ci AMDGPU_XGMI_PSTATE_MIN); 25038c2ecf20Sopenharmony_ci if (r) { 25048c2ecf20Sopenharmony_ci DRM_ERROR("pstate setting failed (%d).\n", r); 25058c2ecf20Sopenharmony_ci break; 25068c2ecf20Sopenharmony_ci } 25078c2ecf20Sopenharmony_ci } 25088c2ecf20Sopenharmony_ci } 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci mutex_unlock(&mgpu_info.mutex); 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci return 0; 25148c2ecf20Sopenharmony_ci} 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci/** 25178c2ecf20Sopenharmony_ci * amdgpu_device_ip_fini - run fini for hardware IPs 25188c2ecf20Sopenharmony_ci * 25198c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 25208c2ecf20Sopenharmony_ci * 25218c2ecf20Sopenharmony_ci * Main teardown pass for hardware IPs. The list of all the hardware 25228c2ecf20Sopenharmony_ci * IPs that make up the asic is walked and the hw_fini and sw_fini callbacks 25238c2ecf20Sopenharmony_ci * are run. hw_fini tears down the hardware associated with each IP 25248c2ecf20Sopenharmony_ci * and sw_fini tears down any software state associated with each IP. 25258c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 25268c2ecf20Sopenharmony_ci */ 25278c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_fini(struct amdgpu_device *adev) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci int i, r; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev) && adev->virt.ras_init_done) 25328c2ecf20Sopenharmony_ci amdgpu_virt_release_ras_err_handler_data(adev); 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci amdgpu_ras_pre_fini(adev); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci if (adev->gmc.xgmi.num_physical_nodes > 1) 25378c2ecf20Sopenharmony_ci amdgpu_xgmi_remove_device(adev); 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); 25408c2ecf20Sopenharmony_ci amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci amdgpu_amdkfd_device_fini(adev); 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci /* need to disable SMC first */ 25458c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 25468c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.hw) 25478c2ecf20Sopenharmony_ci continue; 25488c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) { 25498c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev); 25508c2ecf20Sopenharmony_ci /* XXX handle errors */ 25518c2ecf20Sopenharmony_ci if (r) { 25528c2ecf20Sopenharmony_ci DRM_DEBUG("hw_fini of IP block <%s> failed %d\n", 25538c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 25548c2ecf20Sopenharmony_ci } 25558c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = false; 25568c2ecf20Sopenharmony_ci break; 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci for (i = adev->num_ip_blocks - 1; i >= 0; i--) { 25618c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.hw) 25628c2ecf20Sopenharmony_ci continue; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->hw_fini((void *)adev); 25658c2ecf20Sopenharmony_ci /* XXX handle errors */ 25668c2ecf20Sopenharmony_ci if (r) { 25678c2ecf20Sopenharmony_ci DRM_DEBUG("hw_fini of IP block <%s> failed %d\n", 25688c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 25698c2ecf20Sopenharmony_ci } 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = false; 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci for (i = adev->num_ip_blocks - 1; i >= 0; i--) { 25768c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.sw) 25778c2ecf20Sopenharmony_ci continue; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { 25808c2ecf20Sopenharmony_ci amdgpu_ucode_free_bo(adev); 25818c2ecf20Sopenharmony_ci amdgpu_free_static_csa(&adev->virt.csa_obj); 25828c2ecf20Sopenharmony_ci amdgpu_device_wb_fini(adev); 25838c2ecf20Sopenharmony_ci amdgpu_device_vram_scratch_fini(adev); 25848c2ecf20Sopenharmony_ci amdgpu_ib_pool_fini(adev); 25858c2ecf20Sopenharmony_ci } 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->sw_fini((void *)adev); 25888c2ecf20Sopenharmony_ci /* XXX handle errors */ 25898c2ecf20Sopenharmony_ci if (r) { 25908c2ecf20Sopenharmony_ci DRM_DEBUG("sw_fini of IP block <%s> failed %d\n", 25918c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 25928c2ecf20Sopenharmony_ci } 25938c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.sw = false; 25948c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.valid = false; 25958c2ecf20Sopenharmony_ci } 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci for (i = adev->num_ip_blocks - 1; i >= 0; i--) { 25988c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.late_initialized) 25998c2ecf20Sopenharmony_ci continue; 26008c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->funcs->late_fini) 26018c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->late_fini((void *)adev); 26028c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.late_initialized = false; 26038c2ecf20Sopenharmony_ci } 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci amdgpu_ras_fini(adev); 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 26088c2ecf20Sopenharmony_ci if (amdgpu_virt_release_full_gpu(adev, false)) 26098c2ecf20Sopenharmony_ci DRM_ERROR("failed to release exclusive mode on fini\n"); 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci return 0; 26128c2ecf20Sopenharmony_ci} 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci/** 26158c2ecf20Sopenharmony_ci * amdgpu_device_delayed_init_work_handler - work handler for IB tests 26168c2ecf20Sopenharmony_ci * 26178c2ecf20Sopenharmony_ci * @work: work_struct. 26188c2ecf20Sopenharmony_ci */ 26198c2ecf20Sopenharmony_cistatic void amdgpu_device_delayed_init_work_handler(struct work_struct *work) 26208c2ecf20Sopenharmony_ci{ 26218c2ecf20Sopenharmony_ci struct amdgpu_device *adev = 26228c2ecf20Sopenharmony_ci container_of(work, struct amdgpu_device, delayed_init_work.work); 26238c2ecf20Sopenharmony_ci int r; 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci r = amdgpu_ib_ring_tests(adev); 26268c2ecf20Sopenharmony_ci if (r) 26278c2ecf20Sopenharmony_ci DRM_ERROR("ib ring test failed (%d).\n", r); 26288c2ecf20Sopenharmony_ci} 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_cistatic void amdgpu_device_delay_enable_gfx_off(struct work_struct *work) 26318c2ecf20Sopenharmony_ci{ 26328c2ecf20Sopenharmony_ci struct amdgpu_device *adev = 26338c2ecf20Sopenharmony_ci container_of(work, struct amdgpu_device, gfx.gfx_off_delay_work.work); 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_ci WARN_ON_ONCE(adev->gfx.gfx_off_state); 26368c2ecf20Sopenharmony_ci WARN_ON_ONCE(adev->gfx.gfx_off_req_count); 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true)) 26398c2ecf20Sopenharmony_ci adev->gfx.gfx_off_state = true; 26408c2ecf20Sopenharmony_ci} 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci/** 26438c2ecf20Sopenharmony_ci * amdgpu_device_ip_suspend_phase1 - run suspend for hardware IPs (phase 1) 26448c2ecf20Sopenharmony_ci * 26458c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 26468c2ecf20Sopenharmony_ci * 26478c2ecf20Sopenharmony_ci * Main suspend function for hardware IPs. The list of all the hardware 26488c2ecf20Sopenharmony_ci * IPs that make up the asic is walked, clockgating is disabled and the 26498c2ecf20Sopenharmony_ci * suspend callbacks are run. suspend puts the hardware and software state 26508c2ecf20Sopenharmony_ci * in each IP into a state suitable for suspend. 26518c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 26528c2ecf20Sopenharmony_ci */ 26538c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev) 26548c2ecf20Sopenharmony_ci{ 26558c2ecf20Sopenharmony_ci int i, r; 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE); 26588c2ecf20Sopenharmony_ci amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE); 26598c2ecf20Sopenharmony_ci 26608c2ecf20Sopenharmony_ci for (i = adev->num_ip_blocks - 1; i >= 0; i--) { 26618c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 26628c2ecf20Sopenharmony_ci continue; 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci /* displays are handled separately */ 26658c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_DCE) 26668c2ecf20Sopenharmony_ci continue; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci /* XXX handle errors */ 26698c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->suspend(adev); 26708c2ecf20Sopenharmony_ci /* XXX handle errors */ 26718c2ecf20Sopenharmony_ci if (r) { 26728c2ecf20Sopenharmony_ci DRM_ERROR("suspend of IP block <%s> failed %d\n", 26738c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 26748c2ecf20Sopenharmony_ci return r; 26758c2ecf20Sopenharmony_ci } 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = false; 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci return 0; 26818c2ecf20Sopenharmony_ci} 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci/** 26848c2ecf20Sopenharmony_ci * amdgpu_device_ip_suspend_phase2 - run suspend for hardware IPs (phase 2) 26858c2ecf20Sopenharmony_ci * 26868c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 26878c2ecf20Sopenharmony_ci * 26888c2ecf20Sopenharmony_ci * Main suspend function for hardware IPs. The list of all the hardware 26898c2ecf20Sopenharmony_ci * IPs that make up the asic is walked, clockgating is disabled and the 26908c2ecf20Sopenharmony_ci * suspend callbacks are run. suspend puts the hardware and software state 26918c2ecf20Sopenharmony_ci * in each IP into a state suitable for suspend. 26928c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 26938c2ecf20Sopenharmony_ci */ 26948c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev) 26958c2ecf20Sopenharmony_ci{ 26968c2ecf20Sopenharmony_ci int i, r; 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci for (i = adev->num_ip_blocks - 1; i >= 0; i--) { 26998c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 27008c2ecf20Sopenharmony_ci continue; 27018c2ecf20Sopenharmony_ci /* displays are handled in phase1 */ 27028c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) 27038c2ecf20Sopenharmony_ci continue; 27048c2ecf20Sopenharmony_ci /* PSP lost connection when err_event_athub occurs */ 27058c2ecf20Sopenharmony_ci if (amdgpu_ras_intr_triggered() && 27068c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) { 27078c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = false; 27088c2ecf20Sopenharmony_ci continue; 27098c2ecf20Sopenharmony_ci } 27108c2ecf20Sopenharmony_ci /* XXX handle errors */ 27118c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->suspend(adev); 27128c2ecf20Sopenharmony_ci /* XXX handle errors */ 27138c2ecf20Sopenharmony_ci if (r) { 27148c2ecf20Sopenharmony_ci DRM_ERROR("suspend of IP block <%s> failed %d\n", 27158c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = false; 27188c2ecf20Sopenharmony_ci /* handle putting the SMC in the appropriate state */ 27198c2ecf20Sopenharmony_ci if(!amdgpu_sriov_vf(adev)){ 27208c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) { 27218c2ecf20Sopenharmony_ci r = amdgpu_dpm_set_mp1_state(adev, adev->mp1_state); 27228c2ecf20Sopenharmony_ci if (r) { 27238c2ecf20Sopenharmony_ci DRM_ERROR("SMC failed to set mp1 state %d, %d\n", 27248c2ecf20Sopenharmony_ci adev->mp1_state, r); 27258c2ecf20Sopenharmony_ci return r; 27268c2ecf20Sopenharmony_ci } 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci } 27298c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = false; 27308c2ecf20Sopenharmony_ci } 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci return 0; 27338c2ecf20Sopenharmony_ci} 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci/** 27368c2ecf20Sopenharmony_ci * amdgpu_device_ip_suspend - run suspend for hardware IPs 27378c2ecf20Sopenharmony_ci * 27388c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 27398c2ecf20Sopenharmony_ci * 27408c2ecf20Sopenharmony_ci * Main suspend function for hardware IPs. The list of all the hardware 27418c2ecf20Sopenharmony_ci * IPs that make up the asic is walked, clockgating is disabled and the 27428c2ecf20Sopenharmony_ci * suspend callbacks are run. suspend puts the hardware and software state 27438c2ecf20Sopenharmony_ci * in each IP into a state suitable for suspend. 27448c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 27458c2ecf20Sopenharmony_ci */ 27468c2ecf20Sopenharmony_ciint amdgpu_device_ip_suspend(struct amdgpu_device *adev) 27478c2ecf20Sopenharmony_ci{ 27488c2ecf20Sopenharmony_ci int r; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 27518c2ecf20Sopenharmony_ci amdgpu_virt_request_full_gpu(adev, false); 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci r = amdgpu_device_ip_suspend_phase1(adev); 27548c2ecf20Sopenharmony_ci if (r) 27558c2ecf20Sopenharmony_ci return r; 27568c2ecf20Sopenharmony_ci r = amdgpu_device_ip_suspend_phase2(adev); 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 27598c2ecf20Sopenharmony_ci amdgpu_virt_release_full_gpu(adev, false); 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci return r; 27628c2ecf20Sopenharmony_ci} 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev) 27658c2ecf20Sopenharmony_ci{ 27668c2ecf20Sopenharmony_ci int i, r; 27678c2ecf20Sopenharmony_ci 27688c2ecf20Sopenharmony_ci static enum amd_ip_block_type ip_order[] = { 27698c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_GMC, 27708c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_COMMON, 27718c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_PSP, 27728c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_IH, 27738c2ecf20Sopenharmony_ci }; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 27768c2ecf20Sopenharmony_ci int j; 27778c2ecf20Sopenharmony_ci struct amdgpu_ip_block *block; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci block = &adev->ip_blocks[i]; 27808c2ecf20Sopenharmony_ci block->status.hw = false; 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(ip_order); j++) { 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (block->version->type != ip_order[j] || 27858c2ecf20Sopenharmony_ci !block->status.valid) 27868c2ecf20Sopenharmony_ci continue; 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci r = block->version->funcs->hw_init(adev); 27898c2ecf20Sopenharmony_ci DRM_INFO("RE-INIT-early: %s %s\n", block->version->funcs->name, r?"failed":"succeeded"); 27908c2ecf20Sopenharmony_ci if (r) 27918c2ecf20Sopenharmony_ci return r; 27928c2ecf20Sopenharmony_ci block->status.hw = true; 27938c2ecf20Sopenharmony_ci } 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci return 0; 27978c2ecf20Sopenharmony_ci} 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev) 28008c2ecf20Sopenharmony_ci{ 28018c2ecf20Sopenharmony_ci int i, r; 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci static enum amd_ip_block_type ip_order[] = { 28048c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_SMC, 28058c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_DCE, 28068c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_GFX, 28078c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_SDMA, 28088c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_UVD, 28098c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_VCE, 28108c2ecf20Sopenharmony_ci AMD_IP_BLOCK_TYPE_VCN 28118c2ecf20Sopenharmony_ci }; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ip_order); i++) { 28148c2ecf20Sopenharmony_ci int j; 28158c2ecf20Sopenharmony_ci struct amdgpu_ip_block *block; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci for (j = 0; j < adev->num_ip_blocks; j++) { 28188c2ecf20Sopenharmony_ci block = &adev->ip_blocks[j]; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci if (block->version->type != ip_order[i] || 28218c2ecf20Sopenharmony_ci !block->status.valid || 28228c2ecf20Sopenharmony_ci block->status.hw) 28238c2ecf20Sopenharmony_ci continue; 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci if (block->version->type == AMD_IP_BLOCK_TYPE_SMC) 28268c2ecf20Sopenharmony_ci r = block->version->funcs->resume(adev); 28278c2ecf20Sopenharmony_ci else 28288c2ecf20Sopenharmony_ci r = block->version->funcs->hw_init(adev); 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci DRM_INFO("RE-INIT-late: %s %s\n", block->version->funcs->name, r?"failed":"succeeded"); 28318c2ecf20Sopenharmony_ci if (r) 28328c2ecf20Sopenharmony_ci return r; 28338c2ecf20Sopenharmony_ci block->status.hw = true; 28348c2ecf20Sopenharmony_ci } 28358c2ecf20Sopenharmony_ci } 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci return 0; 28388c2ecf20Sopenharmony_ci} 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci/** 28418c2ecf20Sopenharmony_ci * amdgpu_device_ip_resume_phase1 - run resume for hardware IPs 28428c2ecf20Sopenharmony_ci * 28438c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 28448c2ecf20Sopenharmony_ci * 28458c2ecf20Sopenharmony_ci * First resume function for hardware IPs. The list of all the hardware 28468c2ecf20Sopenharmony_ci * IPs that make up the asic is walked and the resume callbacks are run for 28478c2ecf20Sopenharmony_ci * COMMON, GMC, and IH. resume puts the hardware into a functional state 28488c2ecf20Sopenharmony_ci * after a suspend and updates the software state as necessary. This 28498c2ecf20Sopenharmony_ci * function is also used for restoring the GPU after a GPU reset. 28508c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 28518c2ecf20Sopenharmony_ci */ 28528c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev) 28538c2ecf20Sopenharmony_ci{ 28548c2ecf20Sopenharmony_ci int i, r; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 28578c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw) 28588c2ecf20Sopenharmony_ci continue; 28598c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || 28608c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC || 28618c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) { 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->resume(adev); 28648c2ecf20Sopenharmony_ci if (r) { 28658c2ecf20Sopenharmony_ci DRM_ERROR("resume of IP block <%s> failed %d\n", 28668c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 28678c2ecf20Sopenharmony_ci return r; 28688c2ecf20Sopenharmony_ci } 28698c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = true; 28708c2ecf20Sopenharmony_ci } 28718c2ecf20Sopenharmony_ci } 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci return 0; 28748c2ecf20Sopenharmony_ci} 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_ci/** 28778c2ecf20Sopenharmony_ci * amdgpu_device_ip_resume_phase2 - run resume for hardware IPs 28788c2ecf20Sopenharmony_ci * 28798c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 28808c2ecf20Sopenharmony_ci * 28818c2ecf20Sopenharmony_ci * First resume function for hardware IPs. The list of all the hardware 28828c2ecf20Sopenharmony_ci * IPs that make up the asic is walked and the resume callbacks are run for 28838c2ecf20Sopenharmony_ci * all blocks except COMMON, GMC, and IH. resume puts the hardware into a 28848c2ecf20Sopenharmony_ci * functional state after a suspend and updates the software state as 28858c2ecf20Sopenharmony_ci * necessary. This function is also used for restoring the GPU after a GPU 28868c2ecf20Sopenharmony_ci * reset. 28878c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 28888c2ecf20Sopenharmony_ci */ 28898c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev) 28908c2ecf20Sopenharmony_ci{ 28918c2ecf20Sopenharmony_ci int i, r; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 28948c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw) 28958c2ecf20Sopenharmony_ci continue; 28968c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON || 28978c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC || 28988c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH || 28998c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) 29008c2ecf20Sopenharmony_ci continue; 29018c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->resume(adev); 29028c2ecf20Sopenharmony_ci if (r) { 29038c2ecf20Sopenharmony_ci DRM_ERROR("resume of IP block <%s> failed %d\n", 29048c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->name, r); 29058c2ecf20Sopenharmony_ci return r; 29068c2ecf20Sopenharmony_ci } 29078c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hw = true; 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci return 0; 29118c2ecf20Sopenharmony_ci} 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci/** 29148c2ecf20Sopenharmony_ci * amdgpu_device_ip_resume - run resume for hardware IPs 29158c2ecf20Sopenharmony_ci * 29168c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 29178c2ecf20Sopenharmony_ci * 29188c2ecf20Sopenharmony_ci * Main resume function for hardware IPs. The hardware IPs 29198c2ecf20Sopenharmony_ci * are split into two resume functions because they are 29208c2ecf20Sopenharmony_ci * are also used in in recovering from a GPU reset and some additional 29218c2ecf20Sopenharmony_ci * steps need to be take between them. In this case (S3/S4) they are 29228c2ecf20Sopenharmony_ci * run sequentially. 29238c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 29248c2ecf20Sopenharmony_ci */ 29258c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_resume(struct amdgpu_device *adev) 29268c2ecf20Sopenharmony_ci{ 29278c2ecf20Sopenharmony_ci int r; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci r = amdgpu_amdkfd_resume_iommu(adev); 29308c2ecf20Sopenharmony_ci if (r) 29318c2ecf20Sopenharmony_ci return r; 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci r = amdgpu_device_ip_resume_phase1(adev); 29348c2ecf20Sopenharmony_ci if (r) 29358c2ecf20Sopenharmony_ci return r; 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci r = amdgpu_device_fw_loading(adev); 29388c2ecf20Sopenharmony_ci if (r) 29398c2ecf20Sopenharmony_ci return r; 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_ci r = amdgpu_device_ip_resume_phase2(adev); 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci return r; 29448c2ecf20Sopenharmony_ci} 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci/** 29478c2ecf20Sopenharmony_ci * amdgpu_device_detect_sriov_bios - determine if the board supports SR-IOV 29488c2ecf20Sopenharmony_ci * 29498c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 29508c2ecf20Sopenharmony_ci * 29518c2ecf20Sopenharmony_ci * Query the VBIOS data tables to determine if the board supports SR-IOV. 29528c2ecf20Sopenharmony_ci */ 29538c2ecf20Sopenharmony_cistatic void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev) 29548c2ecf20Sopenharmony_ci{ 29558c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) { 29568c2ecf20Sopenharmony_ci if (adev->is_atom_fw) { 29578c2ecf20Sopenharmony_ci if (amdgpu_atomfirmware_gpu_supports_virtualization(adev)) 29588c2ecf20Sopenharmony_ci adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS; 29598c2ecf20Sopenharmony_ci } else { 29608c2ecf20Sopenharmony_ci if (amdgpu_atombios_has_gpu_virtualization_table(adev)) 29618c2ecf20Sopenharmony_ci adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS; 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci if (!(adev->virt.caps & AMDGPU_SRIOV_CAPS_SRIOV_VBIOS)) 29658c2ecf20Sopenharmony_ci amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_NO_VBIOS, 0, 0); 29668c2ecf20Sopenharmony_ci } 29678c2ecf20Sopenharmony_ci} 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci/** 29708c2ecf20Sopenharmony_ci * amdgpu_device_asic_has_dc_support - determine if DC supports the asic 29718c2ecf20Sopenharmony_ci * 29728c2ecf20Sopenharmony_ci * @asic_type: AMD asic type 29738c2ecf20Sopenharmony_ci * 29748c2ecf20Sopenharmony_ci * Check if there is DC (new modesetting infrastructre) support for an asic. 29758c2ecf20Sopenharmony_ci * returns true if DC has support, false if not. 29768c2ecf20Sopenharmony_ci */ 29778c2ecf20Sopenharmony_cibool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) 29788c2ecf20Sopenharmony_ci{ 29798c2ecf20Sopenharmony_ci switch (asic_type) { 29808c2ecf20Sopenharmony_ci#if defined(CONFIG_DRM_AMD_DC) 29818c2ecf20Sopenharmony_ci#if defined(CONFIG_DRM_AMD_DC_SI) 29828c2ecf20Sopenharmony_ci case CHIP_TAHITI: 29838c2ecf20Sopenharmony_ci case CHIP_PITCAIRN: 29848c2ecf20Sopenharmony_ci case CHIP_VERDE: 29858c2ecf20Sopenharmony_ci case CHIP_OLAND: 29868c2ecf20Sopenharmony_ci#endif 29878c2ecf20Sopenharmony_ci case CHIP_BONAIRE: 29888c2ecf20Sopenharmony_ci case CHIP_KAVERI: 29898c2ecf20Sopenharmony_ci case CHIP_KABINI: 29908c2ecf20Sopenharmony_ci case CHIP_MULLINS: 29918c2ecf20Sopenharmony_ci /* 29928c2ecf20Sopenharmony_ci * We have systems in the wild with these ASICs that require 29938c2ecf20Sopenharmony_ci * LVDS and VGA support which is not supported with DC. 29948c2ecf20Sopenharmony_ci * 29958c2ecf20Sopenharmony_ci * Fallback to the non-DC driver here by default so as not to 29968c2ecf20Sopenharmony_ci * cause regressions. 29978c2ecf20Sopenharmony_ci */ 29988c2ecf20Sopenharmony_ci return amdgpu_dc > 0; 29998c2ecf20Sopenharmony_ci case CHIP_HAWAII: 30008c2ecf20Sopenharmony_ci case CHIP_CARRIZO: 30018c2ecf20Sopenharmony_ci case CHIP_STONEY: 30028c2ecf20Sopenharmony_ci case CHIP_POLARIS10: 30038c2ecf20Sopenharmony_ci case CHIP_POLARIS11: 30048c2ecf20Sopenharmony_ci case CHIP_POLARIS12: 30058c2ecf20Sopenharmony_ci case CHIP_VEGAM: 30068c2ecf20Sopenharmony_ci case CHIP_TONGA: 30078c2ecf20Sopenharmony_ci case CHIP_FIJI: 30088c2ecf20Sopenharmony_ci case CHIP_VEGA10: 30098c2ecf20Sopenharmony_ci case CHIP_VEGA12: 30108c2ecf20Sopenharmony_ci case CHIP_VEGA20: 30118c2ecf20Sopenharmony_ci#if defined(CONFIG_DRM_AMD_DC_DCN) 30128c2ecf20Sopenharmony_ci case CHIP_RAVEN: 30138c2ecf20Sopenharmony_ci case CHIP_NAVI10: 30148c2ecf20Sopenharmony_ci case CHIP_NAVI14: 30158c2ecf20Sopenharmony_ci case CHIP_NAVI12: 30168c2ecf20Sopenharmony_ci case CHIP_RENOIR: 30178c2ecf20Sopenharmony_ci#endif 30188c2ecf20Sopenharmony_ci#if defined(CONFIG_DRM_AMD_DC_DCN3_0) 30198c2ecf20Sopenharmony_ci case CHIP_SIENNA_CICHLID: 30208c2ecf20Sopenharmony_ci case CHIP_NAVY_FLOUNDER: 30218c2ecf20Sopenharmony_ci#endif 30228c2ecf20Sopenharmony_ci return amdgpu_dc != 0; 30238c2ecf20Sopenharmony_ci#endif 30248c2ecf20Sopenharmony_ci default: 30258c2ecf20Sopenharmony_ci if (amdgpu_dc > 0) 30268c2ecf20Sopenharmony_ci DRM_INFO_ONCE("Display Core has been requested via kernel parameter " 30278c2ecf20Sopenharmony_ci "but isn't supported by ASIC, ignoring\n"); 30288c2ecf20Sopenharmony_ci return false; 30298c2ecf20Sopenharmony_ci } 30308c2ecf20Sopenharmony_ci} 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci/** 30338c2ecf20Sopenharmony_ci * amdgpu_device_has_dc_support - check if dc is supported 30348c2ecf20Sopenharmony_ci * 30358c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 30368c2ecf20Sopenharmony_ci * 30378c2ecf20Sopenharmony_ci * Returns true for supported, false for not supported 30388c2ecf20Sopenharmony_ci */ 30398c2ecf20Sopenharmony_cibool amdgpu_device_has_dc_support(struct amdgpu_device *adev) 30408c2ecf20Sopenharmony_ci{ 30418c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev) || adev->enable_virtual_display) 30428c2ecf20Sopenharmony_ci return false; 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci return amdgpu_device_asic_has_dc_support(adev->asic_type); 30458c2ecf20Sopenharmony_ci} 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_cistatic void amdgpu_device_xgmi_reset_func(struct work_struct *__work) 30498c2ecf20Sopenharmony_ci{ 30508c2ecf20Sopenharmony_ci struct amdgpu_device *adev = 30518c2ecf20Sopenharmony_ci container_of(__work, struct amdgpu_device, xgmi_reset_work); 30528c2ecf20Sopenharmony_ci struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci /* It's a bug to not have a hive within this function */ 30558c2ecf20Sopenharmony_ci if (WARN_ON(!hive)) 30568c2ecf20Sopenharmony_ci return; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci /* 30598c2ecf20Sopenharmony_ci * Use task barrier to synchronize all xgmi reset works across the 30608c2ecf20Sopenharmony_ci * hive. task_barrier_enter and task_barrier_exit will block 30618c2ecf20Sopenharmony_ci * until all the threads running the xgmi reset works reach 30628c2ecf20Sopenharmony_ci * those points. task_barrier_full will do both blocks. 30638c2ecf20Sopenharmony_ci */ 30648c2ecf20Sopenharmony_ci if (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) { 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci task_barrier_enter(&hive->tb); 30678c2ecf20Sopenharmony_ci adev->asic_reset_res = amdgpu_device_baco_enter(adev_to_drm(adev)); 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci if (adev->asic_reset_res) 30708c2ecf20Sopenharmony_ci goto fail; 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci task_barrier_exit(&hive->tb); 30738c2ecf20Sopenharmony_ci adev->asic_reset_res = amdgpu_device_baco_exit(adev_to_drm(adev)); 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci if (adev->asic_reset_res) 30768c2ecf20Sopenharmony_ci goto fail; 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci if (adev->mmhub.funcs && adev->mmhub.funcs->reset_ras_error_count) 30798c2ecf20Sopenharmony_ci adev->mmhub.funcs->reset_ras_error_count(adev); 30808c2ecf20Sopenharmony_ci } else { 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci task_barrier_full(&hive->tb); 30838c2ecf20Sopenharmony_ci adev->asic_reset_res = amdgpu_asic_reset(adev); 30848c2ecf20Sopenharmony_ci } 30858c2ecf20Sopenharmony_ci 30868c2ecf20Sopenharmony_cifail: 30878c2ecf20Sopenharmony_ci if (adev->asic_reset_res) 30888c2ecf20Sopenharmony_ci DRM_WARN("ASIC reset failed with error, %d for drm dev, %s", 30898c2ecf20Sopenharmony_ci adev->asic_reset_res, adev_to_drm(adev)->unique); 30908c2ecf20Sopenharmony_ci amdgpu_put_xgmi_hive(hive); 30918c2ecf20Sopenharmony_ci} 30928c2ecf20Sopenharmony_ci 30938c2ecf20Sopenharmony_cistatic int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev) 30948c2ecf20Sopenharmony_ci{ 30958c2ecf20Sopenharmony_ci char *input = amdgpu_lockup_timeout; 30968c2ecf20Sopenharmony_ci char *timeout_setting = NULL; 30978c2ecf20Sopenharmony_ci int index = 0; 30988c2ecf20Sopenharmony_ci long timeout; 30998c2ecf20Sopenharmony_ci int ret = 0; 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci /* 31028c2ecf20Sopenharmony_ci * By default timeout for non compute jobs is 10000. 31038c2ecf20Sopenharmony_ci * And there is no timeout enforced on compute jobs. 31048c2ecf20Sopenharmony_ci * In SR-IOV or passthrough mode, timeout for compute 31058c2ecf20Sopenharmony_ci * jobs are 60000 by default. 31068c2ecf20Sopenharmony_ci */ 31078c2ecf20Sopenharmony_ci adev->gfx_timeout = msecs_to_jiffies(10000); 31088c2ecf20Sopenharmony_ci adev->sdma_timeout = adev->video_timeout = adev->gfx_timeout; 31098c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev) || amdgpu_passthrough(adev)) 31108c2ecf20Sopenharmony_ci adev->compute_timeout = msecs_to_jiffies(60000); 31118c2ecf20Sopenharmony_ci else 31128c2ecf20Sopenharmony_ci adev->compute_timeout = MAX_SCHEDULE_TIMEOUT; 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_ci if (strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) { 31158c2ecf20Sopenharmony_ci while ((timeout_setting = strsep(&input, ",")) && 31168c2ecf20Sopenharmony_ci strnlen(timeout_setting, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) { 31178c2ecf20Sopenharmony_ci ret = kstrtol(timeout_setting, 0, &timeout); 31188c2ecf20Sopenharmony_ci if (ret) 31198c2ecf20Sopenharmony_ci return ret; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci if (timeout == 0) { 31228c2ecf20Sopenharmony_ci index++; 31238c2ecf20Sopenharmony_ci continue; 31248c2ecf20Sopenharmony_ci } else if (timeout < 0) { 31258c2ecf20Sopenharmony_ci timeout = MAX_SCHEDULE_TIMEOUT; 31268c2ecf20Sopenharmony_ci } else { 31278c2ecf20Sopenharmony_ci timeout = msecs_to_jiffies(timeout); 31288c2ecf20Sopenharmony_ci } 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci switch (index++) { 31318c2ecf20Sopenharmony_ci case 0: 31328c2ecf20Sopenharmony_ci adev->gfx_timeout = timeout; 31338c2ecf20Sopenharmony_ci break; 31348c2ecf20Sopenharmony_ci case 1: 31358c2ecf20Sopenharmony_ci adev->compute_timeout = timeout; 31368c2ecf20Sopenharmony_ci break; 31378c2ecf20Sopenharmony_ci case 2: 31388c2ecf20Sopenharmony_ci adev->sdma_timeout = timeout; 31398c2ecf20Sopenharmony_ci break; 31408c2ecf20Sopenharmony_ci case 3: 31418c2ecf20Sopenharmony_ci adev->video_timeout = timeout; 31428c2ecf20Sopenharmony_ci break; 31438c2ecf20Sopenharmony_ci default: 31448c2ecf20Sopenharmony_ci break; 31458c2ecf20Sopenharmony_ci } 31468c2ecf20Sopenharmony_ci } 31478c2ecf20Sopenharmony_ci /* 31488c2ecf20Sopenharmony_ci * There is only one value specified and 31498c2ecf20Sopenharmony_ci * it should apply to all non-compute jobs. 31508c2ecf20Sopenharmony_ci */ 31518c2ecf20Sopenharmony_ci if (index == 1) { 31528c2ecf20Sopenharmony_ci adev->sdma_timeout = adev->video_timeout = adev->gfx_timeout; 31538c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev) || amdgpu_passthrough(adev)) 31548c2ecf20Sopenharmony_ci adev->compute_timeout = adev->gfx_timeout; 31558c2ecf20Sopenharmony_ci } 31568c2ecf20Sopenharmony_ci } 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_ci return ret; 31598c2ecf20Sopenharmony_ci} 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_cistatic const struct attribute *amdgpu_dev_attributes[] = { 31628c2ecf20Sopenharmony_ci &dev_attr_product_name.attr, 31638c2ecf20Sopenharmony_ci &dev_attr_product_number.attr, 31648c2ecf20Sopenharmony_ci &dev_attr_serial_number.attr, 31658c2ecf20Sopenharmony_ci &dev_attr_pcie_replay_count.attr, 31668c2ecf20Sopenharmony_ci NULL 31678c2ecf20Sopenharmony_ci}; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci/** 31718c2ecf20Sopenharmony_ci * amdgpu_device_init - initialize the driver 31728c2ecf20Sopenharmony_ci * 31738c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 31748c2ecf20Sopenharmony_ci * @flags: driver flags 31758c2ecf20Sopenharmony_ci * 31768c2ecf20Sopenharmony_ci * Initializes the driver info and hw (all asics). 31778c2ecf20Sopenharmony_ci * Returns 0 for success or an error on failure. 31788c2ecf20Sopenharmony_ci * Called at driver startup. 31798c2ecf20Sopenharmony_ci */ 31808c2ecf20Sopenharmony_ciint amdgpu_device_init(struct amdgpu_device *adev, 31818c2ecf20Sopenharmony_ci uint32_t flags) 31828c2ecf20Sopenharmony_ci{ 31838c2ecf20Sopenharmony_ci struct drm_device *ddev = adev_to_drm(adev); 31848c2ecf20Sopenharmony_ci struct pci_dev *pdev = adev->pdev; 31858c2ecf20Sopenharmony_ci int r, i; 31868c2ecf20Sopenharmony_ci bool boco = false; 31878c2ecf20Sopenharmony_ci u32 max_MBps; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci adev->shutdown = false; 31908c2ecf20Sopenharmony_ci adev->flags = flags; 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci if (amdgpu_force_asic_type >= 0 && amdgpu_force_asic_type < CHIP_LAST) 31938c2ecf20Sopenharmony_ci adev->asic_type = amdgpu_force_asic_type; 31948c2ecf20Sopenharmony_ci else 31958c2ecf20Sopenharmony_ci adev->asic_type = flags & AMD_ASIC_MASK; 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci adev->usec_timeout = AMDGPU_MAX_USEC_TIMEOUT; 31988c2ecf20Sopenharmony_ci if (amdgpu_emu_mode == 1) 31998c2ecf20Sopenharmony_ci adev->usec_timeout *= 10; 32008c2ecf20Sopenharmony_ci adev->gmc.gart_size = 512 * 1024 * 1024; 32018c2ecf20Sopenharmony_ci adev->accel_working = false; 32028c2ecf20Sopenharmony_ci adev->num_rings = 0; 32038c2ecf20Sopenharmony_ci adev->mman.buffer_funcs = NULL; 32048c2ecf20Sopenharmony_ci adev->mman.buffer_funcs_ring = NULL; 32058c2ecf20Sopenharmony_ci adev->vm_manager.vm_pte_funcs = NULL; 32068c2ecf20Sopenharmony_ci adev->vm_manager.vm_pte_num_scheds = 0; 32078c2ecf20Sopenharmony_ci adev->gmc.gmc_funcs = NULL; 32088c2ecf20Sopenharmony_ci adev->fence_context = dma_fence_context_alloc(AMDGPU_MAX_RINGS); 32098c2ecf20Sopenharmony_ci bitmap_zero(adev->gfx.pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES); 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci adev->smc_rreg = &amdgpu_invalid_rreg; 32128c2ecf20Sopenharmony_ci adev->smc_wreg = &amdgpu_invalid_wreg; 32138c2ecf20Sopenharmony_ci adev->pcie_rreg = &amdgpu_invalid_rreg; 32148c2ecf20Sopenharmony_ci adev->pcie_wreg = &amdgpu_invalid_wreg; 32158c2ecf20Sopenharmony_ci adev->pciep_rreg = &amdgpu_invalid_rreg; 32168c2ecf20Sopenharmony_ci adev->pciep_wreg = &amdgpu_invalid_wreg; 32178c2ecf20Sopenharmony_ci adev->pcie_rreg64 = &amdgpu_invalid_rreg64; 32188c2ecf20Sopenharmony_ci adev->pcie_wreg64 = &amdgpu_invalid_wreg64; 32198c2ecf20Sopenharmony_ci adev->uvd_ctx_rreg = &amdgpu_invalid_rreg; 32208c2ecf20Sopenharmony_ci adev->uvd_ctx_wreg = &amdgpu_invalid_wreg; 32218c2ecf20Sopenharmony_ci adev->didt_rreg = &amdgpu_invalid_rreg; 32228c2ecf20Sopenharmony_ci adev->didt_wreg = &amdgpu_invalid_wreg; 32238c2ecf20Sopenharmony_ci adev->gc_cac_rreg = &amdgpu_invalid_rreg; 32248c2ecf20Sopenharmony_ci adev->gc_cac_wreg = &amdgpu_invalid_wreg; 32258c2ecf20Sopenharmony_ci adev->audio_endpt_rreg = &amdgpu_block_invalid_rreg; 32268c2ecf20Sopenharmony_ci adev->audio_endpt_wreg = &amdgpu_block_invalid_wreg; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X 0x%02X).\n", 32298c2ecf20Sopenharmony_ci amdgpu_asic_name[adev->asic_type], pdev->vendor, pdev->device, 32308c2ecf20Sopenharmony_ci pdev->subsystem_vendor, pdev->subsystem_device, pdev->revision); 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ci /* mutex initialization are all done here so we 32338c2ecf20Sopenharmony_ci * can recall function without having locking issues */ 32348c2ecf20Sopenharmony_ci atomic_set(&adev->irq.ih.lock, 0); 32358c2ecf20Sopenharmony_ci mutex_init(&adev->firmware.mutex); 32368c2ecf20Sopenharmony_ci mutex_init(&adev->pm.mutex); 32378c2ecf20Sopenharmony_ci mutex_init(&adev->gfx.gpu_clock_mutex); 32388c2ecf20Sopenharmony_ci mutex_init(&adev->srbm_mutex); 32398c2ecf20Sopenharmony_ci mutex_init(&adev->gfx.pipe_reserve_mutex); 32408c2ecf20Sopenharmony_ci mutex_init(&adev->gfx.gfx_off_mutex); 32418c2ecf20Sopenharmony_ci mutex_init(&adev->grbm_idx_mutex); 32428c2ecf20Sopenharmony_ci mutex_init(&adev->mn_lock); 32438c2ecf20Sopenharmony_ci mutex_init(&adev->virt.vf_errors.lock); 32448c2ecf20Sopenharmony_ci hash_init(adev->mn_hash); 32458c2ecf20Sopenharmony_ci atomic_set(&adev->in_gpu_reset, 0); 32468c2ecf20Sopenharmony_ci init_rwsem(&adev->reset_sem); 32478c2ecf20Sopenharmony_ci mutex_init(&adev->psp.mutex); 32488c2ecf20Sopenharmony_ci mutex_init(&adev->notifier_lock); 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci r = amdgpu_device_check_arguments(adev); 32518c2ecf20Sopenharmony_ci if (r) 32528c2ecf20Sopenharmony_ci return r; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci spin_lock_init(&adev->mmio_idx_lock); 32558c2ecf20Sopenharmony_ci spin_lock_init(&adev->smc_idx_lock); 32568c2ecf20Sopenharmony_ci spin_lock_init(&adev->pcie_idx_lock); 32578c2ecf20Sopenharmony_ci spin_lock_init(&adev->uvd_ctx_idx_lock); 32588c2ecf20Sopenharmony_ci spin_lock_init(&adev->didt_idx_lock); 32598c2ecf20Sopenharmony_ci spin_lock_init(&adev->gc_cac_idx_lock); 32608c2ecf20Sopenharmony_ci spin_lock_init(&adev->se_cac_idx_lock); 32618c2ecf20Sopenharmony_ci spin_lock_init(&adev->audio_endpt_idx_lock); 32628c2ecf20Sopenharmony_ci spin_lock_init(&adev->mm_stats.lock); 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&adev->shadow_list); 32658c2ecf20Sopenharmony_ci mutex_init(&adev->shadow_list_lock); 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&adev->delayed_init_work, 32688c2ecf20Sopenharmony_ci amdgpu_device_delayed_init_work_handler); 32698c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&adev->gfx.gfx_off_delay_work, 32708c2ecf20Sopenharmony_ci amdgpu_device_delay_enable_gfx_off); 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func); 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_ci adev->gfx.gfx_off_req_count = 1; 32758c2ecf20Sopenharmony_ci adev->pm.ac_power = power_supply_is_system_supplied() > 0; 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci atomic_set(&adev->throttling_logging_enabled, 1); 32788c2ecf20Sopenharmony_ci /* 32798c2ecf20Sopenharmony_ci * If throttling continues, logging will be performed every minute 32808c2ecf20Sopenharmony_ci * to avoid log flooding. "-1" is subtracted since the thermal 32818c2ecf20Sopenharmony_ci * throttling interrupt comes every second. Thus, the total logging 32828c2ecf20Sopenharmony_ci * interval is 59 seconds(retelimited printk interval) + 1(waiting 32838c2ecf20Sopenharmony_ci * for throttling interrupt) = 60 seconds. 32848c2ecf20Sopenharmony_ci */ 32858c2ecf20Sopenharmony_ci ratelimit_state_init(&adev->throttling_logging_rs, (60 - 1) * HZ, 1); 32868c2ecf20Sopenharmony_ci ratelimit_set_flags(&adev->throttling_logging_rs, RATELIMIT_MSG_ON_RELEASE); 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci /* Registers mapping */ 32898c2ecf20Sopenharmony_ci /* TODO: block userspace mapping of io register */ 32908c2ecf20Sopenharmony_ci if (adev->asic_type >= CHIP_BONAIRE) { 32918c2ecf20Sopenharmony_ci adev->rmmio_base = pci_resource_start(adev->pdev, 5); 32928c2ecf20Sopenharmony_ci adev->rmmio_size = pci_resource_len(adev->pdev, 5); 32938c2ecf20Sopenharmony_ci } else { 32948c2ecf20Sopenharmony_ci adev->rmmio_base = pci_resource_start(adev->pdev, 2); 32958c2ecf20Sopenharmony_ci adev->rmmio_size = pci_resource_len(adev->pdev, 2); 32968c2ecf20Sopenharmony_ci } 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size); 32998c2ecf20Sopenharmony_ci if (adev->rmmio == NULL) { 33008c2ecf20Sopenharmony_ci return -ENOMEM; 33018c2ecf20Sopenharmony_ci } 33028c2ecf20Sopenharmony_ci DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)adev->rmmio_base); 33038c2ecf20Sopenharmony_ci DRM_INFO("register mmio size: %u\n", (unsigned)adev->rmmio_size); 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci /* io port mapping */ 33068c2ecf20Sopenharmony_ci for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { 33078c2ecf20Sopenharmony_ci if (pci_resource_flags(adev->pdev, i) & IORESOURCE_IO) { 33088c2ecf20Sopenharmony_ci adev->rio_mem_size = pci_resource_len(adev->pdev, i); 33098c2ecf20Sopenharmony_ci adev->rio_mem = pci_iomap(adev->pdev, i, adev->rio_mem_size); 33108c2ecf20Sopenharmony_ci break; 33118c2ecf20Sopenharmony_ci } 33128c2ecf20Sopenharmony_ci } 33138c2ecf20Sopenharmony_ci if (adev->rio_mem == NULL) 33148c2ecf20Sopenharmony_ci DRM_INFO("PCI I/O BAR is not found.\n"); 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci /* enable PCIE atomic ops */ 33178c2ecf20Sopenharmony_ci r = pci_enable_atomic_ops_to_root(adev->pdev, 33188c2ecf20Sopenharmony_ci PCI_EXP_DEVCAP2_ATOMIC_COMP32 | 33198c2ecf20Sopenharmony_ci PCI_EXP_DEVCAP2_ATOMIC_COMP64); 33208c2ecf20Sopenharmony_ci if (r) { 33218c2ecf20Sopenharmony_ci adev->have_atomics_support = false; 33228c2ecf20Sopenharmony_ci DRM_INFO("PCIE atomic ops is not supported\n"); 33238c2ecf20Sopenharmony_ci } else { 33248c2ecf20Sopenharmony_ci adev->have_atomics_support = true; 33258c2ecf20Sopenharmony_ci } 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci amdgpu_device_get_pcie_info(adev); 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci if (amdgpu_mcbp) 33308c2ecf20Sopenharmony_ci DRM_INFO("MCBP is enabled\n"); 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci if (amdgpu_mes && adev->asic_type >= CHIP_NAVI10) 33338c2ecf20Sopenharmony_ci adev->enable_mes = true; 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci /* detect hw virtualization here */ 33368c2ecf20Sopenharmony_ci amdgpu_detect_virtualization(adev); 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci r = amdgpu_device_get_job_timeout_settings(adev); 33398c2ecf20Sopenharmony_ci if (r) { 33408c2ecf20Sopenharmony_ci dev_err(adev->dev, "invalid lockup_timeout parameter syntax\n"); 33418c2ecf20Sopenharmony_ci return r; 33428c2ecf20Sopenharmony_ci } 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci /* early init functions */ 33458c2ecf20Sopenharmony_ci r = amdgpu_device_ip_early_init(adev); 33468c2ecf20Sopenharmony_ci if (r) 33478c2ecf20Sopenharmony_ci return r; 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci /* doorbell bar mapping and doorbell index init*/ 33508c2ecf20Sopenharmony_ci amdgpu_device_doorbell_init(adev); 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci /* if we have > 1 VGA cards, then disable the amdgpu VGA resources */ 33538c2ecf20Sopenharmony_ci /* this will fail for cards that aren't VGA class devices, just 33548c2ecf20Sopenharmony_ci * ignore it */ 33558c2ecf20Sopenharmony_ci vga_client_register(adev->pdev, adev, NULL, amdgpu_device_vga_set_decode); 33568c2ecf20Sopenharmony_ci 33578c2ecf20Sopenharmony_ci if (amdgpu_device_supports_boco(ddev)) 33588c2ecf20Sopenharmony_ci boco = true; 33598c2ecf20Sopenharmony_ci if (amdgpu_has_atpx() && 33608c2ecf20Sopenharmony_ci (amdgpu_is_atpx_hybrid() || 33618c2ecf20Sopenharmony_ci amdgpu_has_atpx_dgpu_power_cntl()) && 33628c2ecf20Sopenharmony_ci !pci_is_thunderbolt_attached(adev->pdev)) 33638c2ecf20Sopenharmony_ci vga_switcheroo_register_client(adev->pdev, 33648c2ecf20Sopenharmony_ci &amdgpu_switcheroo_ops, boco); 33658c2ecf20Sopenharmony_ci if (boco) 33668c2ecf20Sopenharmony_ci vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain); 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci if (amdgpu_emu_mode == 1) { 33698c2ecf20Sopenharmony_ci /* post the asic on emulation mode */ 33708c2ecf20Sopenharmony_ci emu_soc_asic_init(adev); 33718c2ecf20Sopenharmony_ci goto fence_driver_init; 33728c2ecf20Sopenharmony_ci } 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_ci /* detect if we are with an SRIOV vbios */ 33758c2ecf20Sopenharmony_ci amdgpu_device_detect_sriov_bios(adev); 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci /* check if we need to reset the asic 33788c2ecf20Sopenharmony_ci * E.g., driver was not cleanly unloaded previously, etc. 33798c2ecf20Sopenharmony_ci */ 33808c2ecf20Sopenharmony_ci if (!amdgpu_sriov_vf(adev) && amdgpu_asic_need_reset_on_init(adev)) { 33818c2ecf20Sopenharmony_ci r = amdgpu_asic_reset(adev); 33828c2ecf20Sopenharmony_ci if (r) { 33838c2ecf20Sopenharmony_ci dev_err(adev->dev, "asic reset on init failed\n"); 33848c2ecf20Sopenharmony_ci goto failed; 33858c2ecf20Sopenharmony_ci } 33868c2ecf20Sopenharmony_ci } 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci pci_enable_pcie_error_reporting(adev->ddev.pdev); 33898c2ecf20Sopenharmony_ci 33908c2ecf20Sopenharmony_ci /* Post card if necessary */ 33918c2ecf20Sopenharmony_ci if (amdgpu_device_need_post(adev)) { 33928c2ecf20Sopenharmony_ci if (!adev->bios) { 33938c2ecf20Sopenharmony_ci dev_err(adev->dev, "no vBIOS found\n"); 33948c2ecf20Sopenharmony_ci r = -EINVAL; 33958c2ecf20Sopenharmony_ci goto failed; 33968c2ecf20Sopenharmony_ci } 33978c2ecf20Sopenharmony_ci DRM_INFO("GPU posting now...\n"); 33988c2ecf20Sopenharmony_ci r = amdgpu_device_asic_init(adev); 33998c2ecf20Sopenharmony_ci if (r) { 34008c2ecf20Sopenharmony_ci dev_err(adev->dev, "gpu post error!\n"); 34018c2ecf20Sopenharmony_ci goto failed; 34028c2ecf20Sopenharmony_ci } 34038c2ecf20Sopenharmony_ci } 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci if (adev->is_atom_fw) { 34068c2ecf20Sopenharmony_ci /* Initialize clocks */ 34078c2ecf20Sopenharmony_ci r = amdgpu_atomfirmware_get_clock_info(adev); 34088c2ecf20Sopenharmony_ci if (r) { 34098c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu_atomfirmware_get_clock_info failed\n"); 34108c2ecf20Sopenharmony_ci amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_ATOMBIOS_GET_CLOCK_FAIL, 0, 0); 34118c2ecf20Sopenharmony_ci goto failed; 34128c2ecf20Sopenharmony_ci } 34138c2ecf20Sopenharmony_ci } else { 34148c2ecf20Sopenharmony_ci /* Initialize clocks */ 34158c2ecf20Sopenharmony_ci r = amdgpu_atombios_get_clock_info(adev); 34168c2ecf20Sopenharmony_ci if (r) { 34178c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu_atombios_get_clock_info failed\n"); 34188c2ecf20Sopenharmony_ci amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_ATOMBIOS_GET_CLOCK_FAIL, 0, 0); 34198c2ecf20Sopenharmony_ci goto failed; 34208c2ecf20Sopenharmony_ci } 34218c2ecf20Sopenharmony_ci /* init i2c buses */ 34228c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(adev)) 34238c2ecf20Sopenharmony_ci amdgpu_atombios_i2c_init(adev); 34248c2ecf20Sopenharmony_ci } 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_cifence_driver_init: 34278c2ecf20Sopenharmony_ci /* Fence driver */ 34288c2ecf20Sopenharmony_ci r = amdgpu_fence_driver_init(adev); 34298c2ecf20Sopenharmony_ci if (r) { 34308c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu_fence_driver_init failed\n"); 34318c2ecf20Sopenharmony_ci amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_FENCE_INIT_FAIL, 0, 0); 34328c2ecf20Sopenharmony_ci goto failed; 34338c2ecf20Sopenharmony_ci } 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci /* init the mode config */ 34368c2ecf20Sopenharmony_ci drm_mode_config_init(adev_to_drm(adev)); 34378c2ecf20Sopenharmony_ci 34388c2ecf20Sopenharmony_ci r = amdgpu_device_ip_init(adev); 34398c2ecf20Sopenharmony_ci if (r) { 34408c2ecf20Sopenharmony_ci /* failed in exclusive mode due to timeout */ 34418c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev) && 34428c2ecf20Sopenharmony_ci !amdgpu_sriov_runtime(adev) && 34438c2ecf20Sopenharmony_ci amdgpu_virt_mmio_blocked(adev) && 34448c2ecf20Sopenharmony_ci !amdgpu_virt_wait_reset(adev)) { 34458c2ecf20Sopenharmony_ci dev_err(adev->dev, "VF exclusive mode timeout\n"); 34468c2ecf20Sopenharmony_ci /* Don't send request since VF is inactive. */ 34478c2ecf20Sopenharmony_ci adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME; 34488c2ecf20Sopenharmony_ci adev->virt.ops = NULL; 34498c2ecf20Sopenharmony_ci r = -EAGAIN; 34508c2ecf20Sopenharmony_ci goto failed; 34518c2ecf20Sopenharmony_ci } 34528c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu_device_ip_init failed\n"); 34538c2ecf20Sopenharmony_ci amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 0); 34548c2ecf20Sopenharmony_ci goto failed; 34558c2ecf20Sopenharmony_ci } 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci dev_info(adev->dev, 34588c2ecf20Sopenharmony_ci "SE %d, SH per SE %d, CU per SH %d, active_cu_number %d\n", 34598c2ecf20Sopenharmony_ci adev->gfx.config.max_shader_engines, 34608c2ecf20Sopenharmony_ci adev->gfx.config.max_sh_per_se, 34618c2ecf20Sopenharmony_ci adev->gfx.config.max_cu_per_sh, 34628c2ecf20Sopenharmony_ci adev->gfx.cu_info.number); 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_ci adev->accel_working = true; 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_ci amdgpu_vm_check_compute_bug(adev); 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci /* Initialize the buffer migration limit. */ 34698c2ecf20Sopenharmony_ci if (amdgpu_moverate >= 0) 34708c2ecf20Sopenharmony_ci max_MBps = amdgpu_moverate; 34718c2ecf20Sopenharmony_ci else 34728c2ecf20Sopenharmony_ci max_MBps = 8; /* Allow 8 MB/s. */ 34738c2ecf20Sopenharmony_ci /* Get a log2 for easy divisions. */ 34748c2ecf20Sopenharmony_ci adev->mm_stats.log2_max_MBps = ilog2(max(1u, max_MBps)); 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci amdgpu_fbdev_init(adev); 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci r = amdgpu_pm_sysfs_init(adev); 34798c2ecf20Sopenharmony_ci if (r) { 34808c2ecf20Sopenharmony_ci adev->pm_sysfs_en = false; 34818c2ecf20Sopenharmony_ci DRM_ERROR("registering pm debugfs failed (%d).\n", r); 34828c2ecf20Sopenharmony_ci } else 34838c2ecf20Sopenharmony_ci adev->pm_sysfs_en = true; 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci r = amdgpu_ucode_sysfs_init(adev); 34868c2ecf20Sopenharmony_ci if (r) { 34878c2ecf20Sopenharmony_ci adev->ucode_sysfs_en = false; 34888c2ecf20Sopenharmony_ci DRM_ERROR("Creating firmware sysfs failed (%d).\n", r); 34898c2ecf20Sopenharmony_ci } else 34908c2ecf20Sopenharmony_ci adev->ucode_sysfs_en = true; 34918c2ecf20Sopenharmony_ci 34928c2ecf20Sopenharmony_ci if ((amdgpu_testing & 1)) { 34938c2ecf20Sopenharmony_ci if (adev->accel_working) 34948c2ecf20Sopenharmony_ci amdgpu_test_moves(adev); 34958c2ecf20Sopenharmony_ci else 34968c2ecf20Sopenharmony_ci DRM_INFO("amdgpu: acceleration disabled, skipping move tests\n"); 34978c2ecf20Sopenharmony_ci } 34988c2ecf20Sopenharmony_ci if (amdgpu_benchmarking) { 34998c2ecf20Sopenharmony_ci if (adev->accel_working) 35008c2ecf20Sopenharmony_ci amdgpu_benchmark(adev, amdgpu_benchmarking); 35018c2ecf20Sopenharmony_ci else 35028c2ecf20Sopenharmony_ci DRM_INFO("amdgpu: acceleration disabled, skipping benchmarks\n"); 35038c2ecf20Sopenharmony_ci } 35048c2ecf20Sopenharmony_ci 35058c2ecf20Sopenharmony_ci /* 35068c2ecf20Sopenharmony_ci * Register gpu instance before amdgpu_device_enable_mgpu_fan_boost. 35078c2ecf20Sopenharmony_ci * Otherwise the mgpu fan boost feature will be skipped due to the 35088c2ecf20Sopenharmony_ci * gpu instance is counted less. 35098c2ecf20Sopenharmony_ci */ 35108c2ecf20Sopenharmony_ci amdgpu_register_gpu_instance(adev); 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_ci /* enable clockgating, etc. after ib tests, etc. since some blocks require 35138c2ecf20Sopenharmony_ci * explicit gating rather than handling it automatically. 35148c2ecf20Sopenharmony_ci */ 35158c2ecf20Sopenharmony_ci r = amdgpu_device_ip_late_init(adev); 35168c2ecf20Sopenharmony_ci if (r) { 35178c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu_device_ip_late_init failed\n"); 35188c2ecf20Sopenharmony_ci amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_LATE_INIT_FAIL, 0, r); 35198c2ecf20Sopenharmony_ci goto failed; 35208c2ecf20Sopenharmony_ci } 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci /* must succeed. */ 35238c2ecf20Sopenharmony_ci amdgpu_ras_resume(adev); 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci queue_delayed_work(system_wq, &adev->delayed_init_work, 35268c2ecf20Sopenharmony_ci msecs_to_jiffies(AMDGPU_RESUME_MS)); 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 35298c2ecf20Sopenharmony_ci flush_delayed_work(&adev->delayed_init_work); 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci r = sysfs_create_files(&adev->dev->kobj, amdgpu_dev_attributes); 35328c2ecf20Sopenharmony_ci if (r) 35338c2ecf20Sopenharmony_ci dev_err(adev->dev, "Could not create amdgpu device attr\n"); 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PERF_EVENTS)) 35368c2ecf20Sopenharmony_ci r = amdgpu_pmu_init(adev); 35378c2ecf20Sopenharmony_ci if (r) 35388c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu_pmu_init failed\n"); 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci /* Have stored pci confspace at hand for restore in sudden PCI error */ 35418c2ecf20Sopenharmony_ci if (amdgpu_device_cache_pci_state(adev->pdev)) 35428c2ecf20Sopenharmony_ci pci_restore_state(pdev); 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci return 0; 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_cifailed: 35478c2ecf20Sopenharmony_ci amdgpu_vf_error_trans_all(adev); 35488c2ecf20Sopenharmony_ci if (boco) 35498c2ecf20Sopenharmony_ci vga_switcheroo_fini_domain_pm_ops(adev->dev); 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_ci return r; 35528c2ecf20Sopenharmony_ci} 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci/** 35558c2ecf20Sopenharmony_ci * amdgpu_device_fini - tear down the driver 35568c2ecf20Sopenharmony_ci * 35578c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 35588c2ecf20Sopenharmony_ci * 35598c2ecf20Sopenharmony_ci * Tear down the driver info (all asics). 35608c2ecf20Sopenharmony_ci * Called at driver shutdown. 35618c2ecf20Sopenharmony_ci */ 35628c2ecf20Sopenharmony_civoid amdgpu_device_fini(struct amdgpu_device *adev) 35638c2ecf20Sopenharmony_ci{ 35648c2ecf20Sopenharmony_ci dev_info(adev->dev, "amdgpu: finishing device.\n"); 35658c2ecf20Sopenharmony_ci flush_delayed_work(&adev->delayed_init_work); 35668c2ecf20Sopenharmony_ci ttm_bo_lock_delayed_workqueue(&adev->mman.bdev); 35678c2ecf20Sopenharmony_ci adev->shutdown = true; 35688c2ecf20Sopenharmony_ci 35698c2ecf20Sopenharmony_ci kfree(adev->pci_state); 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci /* make sure IB test finished before entering exclusive mode 35728c2ecf20Sopenharmony_ci * to avoid preemption on IB test 35738c2ecf20Sopenharmony_ci * */ 35748c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) { 35758c2ecf20Sopenharmony_ci amdgpu_virt_request_full_gpu(adev, false); 35768c2ecf20Sopenharmony_ci amdgpu_virt_fini_data_exchange(adev); 35778c2ecf20Sopenharmony_ci } 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci /* disable all interrupts */ 35808c2ecf20Sopenharmony_ci amdgpu_irq_disable_all(adev); 35818c2ecf20Sopenharmony_ci if (adev->mode_info.mode_config_initialized){ 35828c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(adev)) 35838c2ecf20Sopenharmony_ci drm_helper_force_disable_all(adev_to_drm(adev)); 35848c2ecf20Sopenharmony_ci else 35858c2ecf20Sopenharmony_ci drm_atomic_helper_shutdown(adev_to_drm(adev)); 35868c2ecf20Sopenharmony_ci } 35878c2ecf20Sopenharmony_ci amdgpu_fence_driver_fini(adev); 35888c2ecf20Sopenharmony_ci if (adev->pm_sysfs_en) 35898c2ecf20Sopenharmony_ci amdgpu_pm_sysfs_fini(adev); 35908c2ecf20Sopenharmony_ci amdgpu_fbdev_fini(adev); 35918c2ecf20Sopenharmony_ci amdgpu_device_ip_fini(adev); 35928c2ecf20Sopenharmony_ci release_firmware(adev->firmware.gpu_info_fw); 35938c2ecf20Sopenharmony_ci adev->firmware.gpu_info_fw = NULL; 35948c2ecf20Sopenharmony_ci adev->accel_working = false; 35958c2ecf20Sopenharmony_ci /* free i2c buses */ 35968c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(adev)) 35978c2ecf20Sopenharmony_ci amdgpu_i2c_fini(adev); 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci if (amdgpu_emu_mode != 1) 36008c2ecf20Sopenharmony_ci amdgpu_atombios_fini(adev); 36018c2ecf20Sopenharmony_ci 36028c2ecf20Sopenharmony_ci kfree(adev->bios); 36038c2ecf20Sopenharmony_ci adev->bios = NULL; 36048c2ecf20Sopenharmony_ci if (amdgpu_has_atpx() && 36058c2ecf20Sopenharmony_ci (amdgpu_is_atpx_hybrid() || 36068c2ecf20Sopenharmony_ci amdgpu_has_atpx_dgpu_power_cntl()) && 36078c2ecf20Sopenharmony_ci !pci_is_thunderbolt_attached(adev->pdev)) 36088c2ecf20Sopenharmony_ci vga_switcheroo_unregister_client(adev->pdev); 36098c2ecf20Sopenharmony_ci if (amdgpu_device_supports_boco(adev_to_drm(adev))) 36108c2ecf20Sopenharmony_ci vga_switcheroo_fini_domain_pm_ops(adev->dev); 36118c2ecf20Sopenharmony_ci vga_client_register(adev->pdev, NULL, NULL, NULL); 36128c2ecf20Sopenharmony_ci if (adev->rio_mem) 36138c2ecf20Sopenharmony_ci pci_iounmap(adev->pdev, adev->rio_mem); 36148c2ecf20Sopenharmony_ci adev->rio_mem = NULL; 36158c2ecf20Sopenharmony_ci iounmap(adev->rmmio); 36168c2ecf20Sopenharmony_ci adev->rmmio = NULL; 36178c2ecf20Sopenharmony_ci amdgpu_device_doorbell_fini(adev); 36188c2ecf20Sopenharmony_ci 36198c2ecf20Sopenharmony_ci if (adev->ucode_sysfs_en) 36208c2ecf20Sopenharmony_ci amdgpu_ucode_sysfs_fini(adev); 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci sysfs_remove_files(&adev->dev->kobj, amdgpu_dev_attributes); 36238c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_PERF_EVENTS)) 36248c2ecf20Sopenharmony_ci amdgpu_pmu_fini(adev); 36258c2ecf20Sopenharmony_ci if (adev->mman.discovery_bin) 36268c2ecf20Sopenharmony_ci amdgpu_discovery_fini(adev); 36278c2ecf20Sopenharmony_ci} 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci/* 36318c2ecf20Sopenharmony_ci * Suspend & resume. 36328c2ecf20Sopenharmony_ci */ 36338c2ecf20Sopenharmony_ci/** 36348c2ecf20Sopenharmony_ci * amdgpu_device_suspend - initiate device suspend 36358c2ecf20Sopenharmony_ci * 36368c2ecf20Sopenharmony_ci * @dev: drm dev pointer 36378c2ecf20Sopenharmony_ci * @fbcon : notify the fbdev of suspend 36388c2ecf20Sopenharmony_ci * 36398c2ecf20Sopenharmony_ci * Puts the hw in the suspend state (all asics). 36408c2ecf20Sopenharmony_ci * Returns 0 for success or an error on failure. 36418c2ecf20Sopenharmony_ci * Called at driver suspend. 36428c2ecf20Sopenharmony_ci */ 36438c2ecf20Sopenharmony_ciint amdgpu_device_suspend(struct drm_device *dev, bool fbcon) 36448c2ecf20Sopenharmony_ci{ 36458c2ecf20Sopenharmony_ci struct amdgpu_device *adev; 36468c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 36478c2ecf20Sopenharmony_ci struct drm_connector *connector; 36488c2ecf20Sopenharmony_ci struct drm_connector_list_iter iter; 36498c2ecf20Sopenharmony_ci int r; 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci adev = drm_to_adev(dev); 36528c2ecf20Sopenharmony_ci 36538c2ecf20Sopenharmony_ci if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 36548c2ecf20Sopenharmony_ci return 0; 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci adev->in_suspend = true; 36578c2ecf20Sopenharmony_ci drm_kms_helper_poll_disable(dev); 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci if (fbcon) 36608c2ecf20Sopenharmony_ci amdgpu_fbdev_set_suspend(adev, 1); 36618c2ecf20Sopenharmony_ci 36628c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adev->delayed_init_work); 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(adev)) { 36658c2ecf20Sopenharmony_ci /* turn off display hw */ 36668c2ecf20Sopenharmony_ci drm_modeset_lock_all(dev); 36678c2ecf20Sopenharmony_ci drm_connector_list_iter_begin(dev, &iter); 36688c2ecf20Sopenharmony_ci drm_for_each_connector_iter(connector, &iter) 36698c2ecf20Sopenharmony_ci drm_helper_connector_dpms(connector, 36708c2ecf20Sopenharmony_ci DRM_MODE_DPMS_OFF); 36718c2ecf20Sopenharmony_ci drm_connector_list_iter_end(&iter); 36728c2ecf20Sopenharmony_ci drm_modeset_unlock_all(dev); 36738c2ecf20Sopenharmony_ci /* unpin the front buffers and cursors */ 36748c2ecf20Sopenharmony_ci list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 36758c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 36768c2ecf20Sopenharmony_ci struct drm_framebuffer *fb = crtc->primary->fb; 36778c2ecf20Sopenharmony_ci struct amdgpu_bo *robj; 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_ci if (amdgpu_crtc->cursor_bo && !adev->enable_virtual_display) { 36808c2ecf20Sopenharmony_ci struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); 36818c2ecf20Sopenharmony_ci r = amdgpu_bo_reserve(aobj, true); 36828c2ecf20Sopenharmony_ci if (r == 0) { 36838c2ecf20Sopenharmony_ci amdgpu_bo_unpin(aobj); 36848c2ecf20Sopenharmony_ci amdgpu_bo_unreserve(aobj); 36858c2ecf20Sopenharmony_ci } 36868c2ecf20Sopenharmony_ci } 36878c2ecf20Sopenharmony_ci 36888c2ecf20Sopenharmony_ci if (fb == NULL || fb->obj[0] == NULL) { 36898c2ecf20Sopenharmony_ci continue; 36908c2ecf20Sopenharmony_ci } 36918c2ecf20Sopenharmony_ci robj = gem_to_amdgpu_bo(fb->obj[0]); 36928c2ecf20Sopenharmony_ci /* don't unpin kernel fb objects */ 36938c2ecf20Sopenharmony_ci if (!amdgpu_fbdev_robj_is_fb(adev, robj)) { 36948c2ecf20Sopenharmony_ci r = amdgpu_bo_reserve(robj, true); 36958c2ecf20Sopenharmony_ci if (r == 0) { 36968c2ecf20Sopenharmony_ci amdgpu_bo_unpin(robj); 36978c2ecf20Sopenharmony_ci amdgpu_bo_unreserve(robj); 36988c2ecf20Sopenharmony_ci } 36998c2ecf20Sopenharmony_ci } 37008c2ecf20Sopenharmony_ci } 37018c2ecf20Sopenharmony_ci } 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci amdgpu_ras_suspend(adev); 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci r = amdgpu_device_ip_suspend_phase1(adev); 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_ci amdgpu_amdkfd_suspend(adev, !fbcon); 37088c2ecf20Sopenharmony_ci 37098c2ecf20Sopenharmony_ci /* evict vram memory */ 37108c2ecf20Sopenharmony_ci amdgpu_bo_evict_vram(adev); 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci amdgpu_fence_driver_suspend(adev); 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci r = amdgpu_device_ip_suspend_phase2(adev); 37158c2ecf20Sopenharmony_ci 37168c2ecf20Sopenharmony_ci /* evict remaining vram memory 37178c2ecf20Sopenharmony_ci * This second call to evict vram is to evict the gart page table 37188c2ecf20Sopenharmony_ci * using the CPU. 37198c2ecf20Sopenharmony_ci */ 37208c2ecf20Sopenharmony_ci amdgpu_bo_evict_vram(adev); 37218c2ecf20Sopenharmony_ci 37228c2ecf20Sopenharmony_ci return 0; 37238c2ecf20Sopenharmony_ci} 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci/** 37268c2ecf20Sopenharmony_ci * amdgpu_device_resume - initiate device resume 37278c2ecf20Sopenharmony_ci * 37288c2ecf20Sopenharmony_ci * @dev: drm dev pointer 37298c2ecf20Sopenharmony_ci * @fbcon : notify the fbdev of resume 37308c2ecf20Sopenharmony_ci * 37318c2ecf20Sopenharmony_ci * Bring the hw back to operating state (all asics). 37328c2ecf20Sopenharmony_ci * Returns 0 for success or an error on failure. 37338c2ecf20Sopenharmony_ci * Called at driver resume. 37348c2ecf20Sopenharmony_ci */ 37358c2ecf20Sopenharmony_ciint amdgpu_device_resume(struct drm_device *dev, bool fbcon) 37368c2ecf20Sopenharmony_ci{ 37378c2ecf20Sopenharmony_ci struct drm_connector *connector; 37388c2ecf20Sopenharmony_ci struct drm_connector_list_iter iter; 37398c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 37408c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 37418c2ecf20Sopenharmony_ci int r = 0; 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) 37448c2ecf20Sopenharmony_ci return 0; 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci /* post card */ 37478c2ecf20Sopenharmony_ci if (amdgpu_device_need_post(adev)) { 37488c2ecf20Sopenharmony_ci r = amdgpu_device_asic_init(adev); 37498c2ecf20Sopenharmony_ci if (r) 37508c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu asic init failed\n"); 37518c2ecf20Sopenharmony_ci } 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci r = amdgpu_device_ip_resume(adev); 37548c2ecf20Sopenharmony_ci if (r) { 37558c2ecf20Sopenharmony_ci dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r); 37568c2ecf20Sopenharmony_ci return r; 37578c2ecf20Sopenharmony_ci } 37588c2ecf20Sopenharmony_ci amdgpu_fence_driver_resume(adev); 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ci r = amdgpu_device_ip_late_init(adev); 37628c2ecf20Sopenharmony_ci if (r) 37638c2ecf20Sopenharmony_ci return r; 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci queue_delayed_work(system_wq, &adev->delayed_init_work, 37668c2ecf20Sopenharmony_ci msecs_to_jiffies(AMDGPU_RESUME_MS)); 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(adev)) { 37698c2ecf20Sopenharmony_ci /* pin cursors */ 37708c2ecf20Sopenharmony_ci list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 37718c2ecf20Sopenharmony_ci struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci if (amdgpu_crtc->cursor_bo && !adev->enable_virtual_display) { 37748c2ecf20Sopenharmony_ci struct amdgpu_bo *aobj = gem_to_amdgpu_bo(amdgpu_crtc->cursor_bo); 37758c2ecf20Sopenharmony_ci r = amdgpu_bo_reserve(aobj, true); 37768c2ecf20Sopenharmony_ci if (r == 0) { 37778c2ecf20Sopenharmony_ci r = amdgpu_bo_pin(aobj, AMDGPU_GEM_DOMAIN_VRAM); 37788c2ecf20Sopenharmony_ci if (r != 0) 37798c2ecf20Sopenharmony_ci dev_err(adev->dev, "Failed to pin cursor BO (%d)\n", r); 37808c2ecf20Sopenharmony_ci amdgpu_crtc->cursor_addr = amdgpu_bo_gpu_offset(aobj); 37818c2ecf20Sopenharmony_ci amdgpu_bo_unreserve(aobj); 37828c2ecf20Sopenharmony_ci } 37838c2ecf20Sopenharmony_ci } 37848c2ecf20Sopenharmony_ci } 37858c2ecf20Sopenharmony_ci } 37868c2ecf20Sopenharmony_ci r = amdgpu_amdkfd_resume(adev, !fbcon); 37878c2ecf20Sopenharmony_ci if (r) 37888c2ecf20Sopenharmony_ci return r; 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci /* Make sure IB tests flushed */ 37918c2ecf20Sopenharmony_ci flush_delayed_work(&adev->delayed_init_work); 37928c2ecf20Sopenharmony_ci 37938c2ecf20Sopenharmony_ci /* blat the mode back in */ 37948c2ecf20Sopenharmony_ci if (fbcon) { 37958c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(adev)) { 37968c2ecf20Sopenharmony_ci /* pre DCE11 */ 37978c2ecf20Sopenharmony_ci drm_helper_resume_force_mode(dev); 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci /* turn on display hw */ 38008c2ecf20Sopenharmony_ci drm_modeset_lock_all(dev); 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci drm_connector_list_iter_begin(dev, &iter); 38038c2ecf20Sopenharmony_ci drm_for_each_connector_iter(connector, &iter) 38048c2ecf20Sopenharmony_ci drm_helper_connector_dpms(connector, 38058c2ecf20Sopenharmony_ci DRM_MODE_DPMS_ON); 38068c2ecf20Sopenharmony_ci drm_connector_list_iter_end(&iter); 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci drm_modeset_unlock_all(dev); 38098c2ecf20Sopenharmony_ci } 38108c2ecf20Sopenharmony_ci amdgpu_fbdev_set_suspend(adev, 0); 38118c2ecf20Sopenharmony_ci } 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci drm_kms_helper_poll_enable(dev); 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci amdgpu_ras_resume(adev); 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ci /* 38188c2ecf20Sopenharmony_ci * Most of the connector probing functions try to acquire runtime pm 38198c2ecf20Sopenharmony_ci * refs to ensure that the GPU is powered on when connector polling is 38208c2ecf20Sopenharmony_ci * performed. Since we're calling this from a runtime PM callback, 38218c2ecf20Sopenharmony_ci * trying to acquire rpm refs will cause us to deadlock. 38228c2ecf20Sopenharmony_ci * 38238c2ecf20Sopenharmony_ci * Since we're guaranteed to be holding the rpm lock, it's safe to 38248c2ecf20Sopenharmony_ci * temporarily disable the rpm helpers so this doesn't deadlock us. 38258c2ecf20Sopenharmony_ci */ 38268c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 38278c2ecf20Sopenharmony_ci dev->dev->power.disable_depth++; 38288c2ecf20Sopenharmony_ci#endif 38298c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(adev)) 38308c2ecf20Sopenharmony_ci drm_helper_hpd_irq_event(dev); 38318c2ecf20Sopenharmony_ci else 38328c2ecf20Sopenharmony_ci drm_kms_helper_hotplug_event(dev); 38338c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 38348c2ecf20Sopenharmony_ci dev->dev->power.disable_depth--; 38358c2ecf20Sopenharmony_ci#endif 38368c2ecf20Sopenharmony_ci adev->in_suspend = false; 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci return 0; 38398c2ecf20Sopenharmony_ci} 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci/** 38428c2ecf20Sopenharmony_ci * amdgpu_device_ip_check_soft_reset - did soft reset succeed 38438c2ecf20Sopenharmony_ci * 38448c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 38458c2ecf20Sopenharmony_ci * 38468c2ecf20Sopenharmony_ci * The list of all the hardware IPs that make up the asic is walked and 38478c2ecf20Sopenharmony_ci * the check_soft_reset callbacks are run. check_soft_reset determines 38488c2ecf20Sopenharmony_ci * if the asic is still hung or not. 38498c2ecf20Sopenharmony_ci * Returns true if any of the IPs are still in a hung state, false if not. 38508c2ecf20Sopenharmony_ci */ 38518c2ecf20Sopenharmony_cistatic bool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev) 38528c2ecf20Sopenharmony_ci{ 38538c2ecf20Sopenharmony_ci int i; 38548c2ecf20Sopenharmony_ci bool asic_hang = false; 38558c2ecf20Sopenharmony_ci 38568c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 38578c2ecf20Sopenharmony_ci return true; 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci if (amdgpu_asic_need_full_reset(adev)) 38608c2ecf20Sopenharmony_ci return true; 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 38638c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 38648c2ecf20Sopenharmony_ci continue; 38658c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].version->funcs->check_soft_reset) 38668c2ecf20Sopenharmony_ci adev->ip_blocks[i].status.hang = 38678c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->check_soft_reset(adev); 38688c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].status.hang) { 38698c2ecf20Sopenharmony_ci dev_info(adev->dev, "IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name); 38708c2ecf20Sopenharmony_ci asic_hang = true; 38718c2ecf20Sopenharmony_ci } 38728c2ecf20Sopenharmony_ci } 38738c2ecf20Sopenharmony_ci return asic_hang; 38748c2ecf20Sopenharmony_ci} 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci/** 38778c2ecf20Sopenharmony_ci * amdgpu_device_ip_pre_soft_reset - prepare for soft reset 38788c2ecf20Sopenharmony_ci * 38798c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 38808c2ecf20Sopenharmony_ci * 38818c2ecf20Sopenharmony_ci * The list of all the hardware IPs that make up the asic is walked and the 38828c2ecf20Sopenharmony_ci * pre_soft_reset callbacks are run if the block is hung. pre_soft_reset 38838c2ecf20Sopenharmony_ci * handles any IP specific hardware or software state changes that are 38848c2ecf20Sopenharmony_ci * necessary for a soft reset to succeed. 38858c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 38868c2ecf20Sopenharmony_ci */ 38878c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_pre_soft_reset(struct amdgpu_device *adev) 38888c2ecf20Sopenharmony_ci{ 38898c2ecf20Sopenharmony_ci int i, r = 0; 38908c2ecf20Sopenharmony_ci 38918c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 38928c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 38938c2ecf20Sopenharmony_ci continue; 38948c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].status.hang && 38958c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->pre_soft_reset) { 38968c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->pre_soft_reset(adev); 38978c2ecf20Sopenharmony_ci if (r) 38988c2ecf20Sopenharmony_ci return r; 38998c2ecf20Sopenharmony_ci } 39008c2ecf20Sopenharmony_ci } 39018c2ecf20Sopenharmony_ci 39028c2ecf20Sopenharmony_ci return 0; 39038c2ecf20Sopenharmony_ci} 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_ci/** 39068c2ecf20Sopenharmony_ci * amdgpu_device_ip_need_full_reset - check if a full asic reset is needed 39078c2ecf20Sopenharmony_ci * 39088c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 39098c2ecf20Sopenharmony_ci * 39108c2ecf20Sopenharmony_ci * Some hardware IPs cannot be soft reset. If they are hung, a full gpu 39118c2ecf20Sopenharmony_ci * reset is necessary to recover. 39128c2ecf20Sopenharmony_ci * Returns true if a full asic reset is required, false if not. 39138c2ecf20Sopenharmony_ci */ 39148c2ecf20Sopenharmony_cistatic bool amdgpu_device_ip_need_full_reset(struct amdgpu_device *adev) 39158c2ecf20Sopenharmony_ci{ 39168c2ecf20Sopenharmony_ci int i; 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_ci if (amdgpu_asic_need_full_reset(adev)) 39198c2ecf20Sopenharmony_ci return true; 39208c2ecf20Sopenharmony_ci 39218c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 39228c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 39238c2ecf20Sopenharmony_ci continue; 39248c2ecf20Sopenharmony_ci if ((adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) || 39258c2ecf20Sopenharmony_ci (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) || 39268c2ecf20Sopenharmony_ci (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_ACP) || 39278c2ecf20Sopenharmony_ci (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) || 39288c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) { 39298c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].status.hang) { 39308c2ecf20Sopenharmony_ci dev_info(adev->dev, "Some block need full reset!\n"); 39318c2ecf20Sopenharmony_ci return true; 39328c2ecf20Sopenharmony_ci } 39338c2ecf20Sopenharmony_ci } 39348c2ecf20Sopenharmony_ci } 39358c2ecf20Sopenharmony_ci return false; 39368c2ecf20Sopenharmony_ci} 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci/** 39398c2ecf20Sopenharmony_ci * amdgpu_device_ip_soft_reset - do a soft reset 39408c2ecf20Sopenharmony_ci * 39418c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 39428c2ecf20Sopenharmony_ci * 39438c2ecf20Sopenharmony_ci * The list of all the hardware IPs that make up the asic is walked and the 39448c2ecf20Sopenharmony_ci * soft_reset callbacks are run if the block is hung. soft_reset handles any 39458c2ecf20Sopenharmony_ci * IP specific hardware or software state changes that are necessary to soft 39468c2ecf20Sopenharmony_ci * reset the IP. 39478c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 39488c2ecf20Sopenharmony_ci */ 39498c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_soft_reset(struct amdgpu_device *adev) 39508c2ecf20Sopenharmony_ci{ 39518c2ecf20Sopenharmony_ci int i, r = 0; 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 39548c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 39558c2ecf20Sopenharmony_ci continue; 39568c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].status.hang && 39578c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->soft_reset) { 39588c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->soft_reset(adev); 39598c2ecf20Sopenharmony_ci if (r) 39608c2ecf20Sopenharmony_ci return r; 39618c2ecf20Sopenharmony_ci } 39628c2ecf20Sopenharmony_ci } 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_ci return 0; 39658c2ecf20Sopenharmony_ci} 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci/** 39688c2ecf20Sopenharmony_ci * amdgpu_device_ip_post_soft_reset - clean up from soft reset 39698c2ecf20Sopenharmony_ci * 39708c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 39718c2ecf20Sopenharmony_ci * 39728c2ecf20Sopenharmony_ci * The list of all the hardware IPs that make up the asic is walked and the 39738c2ecf20Sopenharmony_ci * post_soft_reset callbacks are run if the asic was hung. post_soft_reset 39748c2ecf20Sopenharmony_ci * handles any IP specific hardware or software state changes that are 39758c2ecf20Sopenharmony_ci * necessary after the IP has been soft reset. 39768c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. 39778c2ecf20Sopenharmony_ci */ 39788c2ecf20Sopenharmony_cistatic int amdgpu_device_ip_post_soft_reset(struct amdgpu_device *adev) 39798c2ecf20Sopenharmony_ci{ 39808c2ecf20Sopenharmony_ci int i, r = 0; 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_ci for (i = 0; i < adev->num_ip_blocks; i++) { 39838c2ecf20Sopenharmony_ci if (!adev->ip_blocks[i].status.valid) 39848c2ecf20Sopenharmony_ci continue; 39858c2ecf20Sopenharmony_ci if (adev->ip_blocks[i].status.hang && 39868c2ecf20Sopenharmony_ci adev->ip_blocks[i].version->funcs->post_soft_reset) 39878c2ecf20Sopenharmony_ci r = adev->ip_blocks[i].version->funcs->post_soft_reset(adev); 39888c2ecf20Sopenharmony_ci if (r) 39898c2ecf20Sopenharmony_ci return r; 39908c2ecf20Sopenharmony_ci } 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci return 0; 39938c2ecf20Sopenharmony_ci} 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci/** 39968c2ecf20Sopenharmony_ci * amdgpu_device_recover_vram - Recover some VRAM contents 39978c2ecf20Sopenharmony_ci * 39988c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 39998c2ecf20Sopenharmony_ci * 40008c2ecf20Sopenharmony_ci * Restores the contents of VRAM buffers from the shadows in GTT. Used to 40018c2ecf20Sopenharmony_ci * restore things like GPUVM page tables after a GPU reset where 40028c2ecf20Sopenharmony_ci * the contents of VRAM might be lost. 40038c2ecf20Sopenharmony_ci * 40048c2ecf20Sopenharmony_ci * Returns: 40058c2ecf20Sopenharmony_ci * 0 on success, negative error code on failure. 40068c2ecf20Sopenharmony_ci */ 40078c2ecf20Sopenharmony_cistatic int amdgpu_device_recover_vram(struct amdgpu_device *adev) 40088c2ecf20Sopenharmony_ci{ 40098c2ecf20Sopenharmony_ci struct dma_fence *fence = NULL, *next = NULL; 40108c2ecf20Sopenharmony_ci struct amdgpu_bo *shadow; 40118c2ecf20Sopenharmony_ci long r = 1, tmo; 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_ci if (amdgpu_sriov_runtime(adev)) 40148c2ecf20Sopenharmony_ci tmo = msecs_to_jiffies(8000); 40158c2ecf20Sopenharmony_ci else 40168c2ecf20Sopenharmony_ci tmo = msecs_to_jiffies(100); 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci dev_info(adev->dev, "recover vram bo from shadow start\n"); 40198c2ecf20Sopenharmony_ci mutex_lock(&adev->shadow_list_lock); 40208c2ecf20Sopenharmony_ci list_for_each_entry(shadow, &adev->shadow_list, shadow_list) { 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci /* No need to recover an evicted BO */ 40238c2ecf20Sopenharmony_ci if (shadow->tbo.mem.mem_type != TTM_PL_TT || 40248c2ecf20Sopenharmony_ci shadow->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET || 40258c2ecf20Sopenharmony_ci shadow->parent->tbo.mem.mem_type != TTM_PL_VRAM) 40268c2ecf20Sopenharmony_ci continue; 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci r = amdgpu_bo_restore_shadow(shadow, &next); 40298c2ecf20Sopenharmony_ci if (r) 40308c2ecf20Sopenharmony_ci break; 40318c2ecf20Sopenharmony_ci 40328c2ecf20Sopenharmony_ci if (fence) { 40338c2ecf20Sopenharmony_ci tmo = dma_fence_wait_timeout(fence, false, tmo); 40348c2ecf20Sopenharmony_ci dma_fence_put(fence); 40358c2ecf20Sopenharmony_ci fence = next; 40368c2ecf20Sopenharmony_ci if (tmo == 0) { 40378c2ecf20Sopenharmony_ci r = -ETIMEDOUT; 40388c2ecf20Sopenharmony_ci break; 40398c2ecf20Sopenharmony_ci } else if (tmo < 0) { 40408c2ecf20Sopenharmony_ci r = tmo; 40418c2ecf20Sopenharmony_ci break; 40428c2ecf20Sopenharmony_ci } 40438c2ecf20Sopenharmony_ci } else { 40448c2ecf20Sopenharmony_ci fence = next; 40458c2ecf20Sopenharmony_ci } 40468c2ecf20Sopenharmony_ci } 40478c2ecf20Sopenharmony_ci mutex_unlock(&adev->shadow_list_lock); 40488c2ecf20Sopenharmony_ci 40498c2ecf20Sopenharmony_ci if (fence) 40508c2ecf20Sopenharmony_ci tmo = dma_fence_wait_timeout(fence, false, tmo); 40518c2ecf20Sopenharmony_ci dma_fence_put(fence); 40528c2ecf20Sopenharmony_ci 40538c2ecf20Sopenharmony_ci if (r < 0 || tmo <= 0) { 40548c2ecf20Sopenharmony_ci dev_err(adev->dev, "recover vram bo from shadow failed, r is %ld, tmo is %ld\n", r, tmo); 40558c2ecf20Sopenharmony_ci return -EIO; 40568c2ecf20Sopenharmony_ci } 40578c2ecf20Sopenharmony_ci 40588c2ecf20Sopenharmony_ci dev_info(adev->dev, "recover vram bo from shadow done\n"); 40598c2ecf20Sopenharmony_ci return 0; 40608c2ecf20Sopenharmony_ci} 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci/** 40648c2ecf20Sopenharmony_ci * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf 40658c2ecf20Sopenharmony_ci * 40668c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 40678c2ecf20Sopenharmony_ci * @from_hypervisor: request from hypervisor 40688c2ecf20Sopenharmony_ci * 40698c2ecf20Sopenharmony_ci * do VF FLR and reinitialize Asic 40708c2ecf20Sopenharmony_ci * return 0 means succeeded otherwise failed 40718c2ecf20Sopenharmony_ci */ 40728c2ecf20Sopenharmony_cistatic int amdgpu_device_reset_sriov(struct amdgpu_device *adev, 40738c2ecf20Sopenharmony_ci bool from_hypervisor) 40748c2ecf20Sopenharmony_ci{ 40758c2ecf20Sopenharmony_ci int r; 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_ci if (from_hypervisor) 40788c2ecf20Sopenharmony_ci r = amdgpu_virt_request_full_gpu(adev, true); 40798c2ecf20Sopenharmony_ci else 40808c2ecf20Sopenharmony_ci r = amdgpu_virt_reset_gpu(adev); 40818c2ecf20Sopenharmony_ci if (r) 40828c2ecf20Sopenharmony_ci return r; 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_ci amdgpu_amdkfd_pre_reset(adev); 40858c2ecf20Sopenharmony_ci 40868c2ecf20Sopenharmony_ci /* Resume IP prior to SMC */ 40878c2ecf20Sopenharmony_ci r = amdgpu_device_ip_reinit_early_sriov(adev); 40888c2ecf20Sopenharmony_ci if (r) 40898c2ecf20Sopenharmony_ci goto error; 40908c2ecf20Sopenharmony_ci 40918c2ecf20Sopenharmony_ci amdgpu_virt_init_data_exchange(adev); 40928c2ecf20Sopenharmony_ci /* we need recover gart prior to run SMC/CP/SDMA resume */ 40938c2ecf20Sopenharmony_ci amdgpu_gtt_mgr_recover(ttm_manager_type(&adev->mman.bdev, TTM_PL_TT)); 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_ci r = amdgpu_device_fw_loading(adev); 40968c2ecf20Sopenharmony_ci if (r) 40978c2ecf20Sopenharmony_ci return r; 40988c2ecf20Sopenharmony_ci 40998c2ecf20Sopenharmony_ci /* now we are okay to resume SMC/CP/SDMA */ 41008c2ecf20Sopenharmony_ci r = amdgpu_device_ip_reinit_late_sriov(adev); 41018c2ecf20Sopenharmony_ci if (r) 41028c2ecf20Sopenharmony_ci goto error; 41038c2ecf20Sopenharmony_ci 41048c2ecf20Sopenharmony_ci amdgpu_irq_gpu_reset_resume_helper(adev); 41058c2ecf20Sopenharmony_ci r = amdgpu_ib_ring_tests(adev); 41068c2ecf20Sopenharmony_ci amdgpu_amdkfd_post_reset(adev); 41078c2ecf20Sopenharmony_ci 41088c2ecf20Sopenharmony_cierror: 41098c2ecf20Sopenharmony_ci amdgpu_virt_release_full_gpu(adev, true); 41108c2ecf20Sopenharmony_ci if (!r && adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST) { 41118c2ecf20Sopenharmony_ci amdgpu_inc_vram_lost(adev); 41128c2ecf20Sopenharmony_ci r = amdgpu_device_recover_vram(adev); 41138c2ecf20Sopenharmony_ci } 41148c2ecf20Sopenharmony_ci 41158c2ecf20Sopenharmony_ci return r; 41168c2ecf20Sopenharmony_ci} 41178c2ecf20Sopenharmony_ci 41188c2ecf20Sopenharmony_ci/** 41198c2ecf20Sopenharmony_ci * amdgpu_device_has_job_running - check if there is any job in mirror list 41208c2ecf20Sopenharmony_ci * 41218c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 41228c2ecf20Sopenharmony_ci * 41238c2ecf20Sopenharmony_ci * check if there is any job in mirror list 41248c2ecf20Sopenharmony_ci */ 41258c2ecf20Sopenharmony_cibool amdgpu_device_has_job_running(struct amdgpu_device *adev) 41268c2ecf20Sopenharmony_ci{ 41278c2ecf20Sopenharmony_ci int i; 41288c2ecf20Sopenharmony_ci struct drm_sched_job *job; 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 41318c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci if (!ring || !ring->sched.thread) 41348c2ecf20Sopenharmony_ci continue; 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci spin_lock(&ring->sched.job_list_lock); 41378c2ecf20Sopenharmony_ci job = list_first_entry_or_null(&ring->sched.ring_mirror_list, 41388c2ecf20Sopenharmony_ci struct drm_sched_job, node); 41398c2ecf20Sopenharmony_ci spin_unlock(&ring->sched.job_list_lock); 41408c2ecf20Sopenharmony_ci if (job) 41418c2ecf20Sopenharmony_ci return true; 41428c2ecf20Sopenharmony_ci } 41438c2ecf20Sopenharmony_ci return false; 41448c2ecf20Sopenharmony_ci} 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci/** 41478c2ecf20Sopenharmony_ci * amdgpu_device_should_recover_gpu - check if we should try GPU recovery 41488c2ecf20Sopenharmony_ci * 41498c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 41508c2ecf20Sopenharmony_ci * 41518c2ecf20Sopenharmony_ci * Check amdgpu_gpu_recovery and SRIOV status to see if we should try to recover 41528c2ecf20Sopenharmony_ci * a hung GPU. 41538c2ecf20Sopenharmony_ci */ 41548c2ecf20Sopenharmony_cibool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev) 41558c2ecf20Sopenharmony_ci{ 41568c2ecf20Sopenharmony_ci if (!amdgpu_device_ip_check_soft_reset(adev)) { 41578c2ecf20Sopenharmony_ci dev_info(adev->dev, "Timeout, but no hardware hang detected.\n"); 41588c2ecf20Sopenharmony_ci return false; 41598c2ecf20Sopenharmony_ci } 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci if (amdgpu_gpu_recovery == 0) 41628c2ecf20Sopenharmony_ci goto disabled; 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) 41658c2ecf20Sopenharmony_ci return true; 41668c2ecf20Sopenharmony_ci 41678c2ecf20Sopenharmony_ci if (amdgpu_gpu_recovery == -1) { 41688c2ecf20Sopenharmony_ci switch (adev->asic_type) { 41698c2ecf20Sopenharmony_ci case CHIP_BONAIRE: 41708c2ecf20Sopenharmony_ci case CHIP_HAWAII: 41718c2ecf20Sopenharmony_ci case CHIP_TOPAZ: 41728c2ecf20Sopenharmony_ci case CHIP_TONGA: 41738c2ecf20Sopenharmony_ci case CHIP_FIJI: 41748c2ecf20Sopenharmony_ci case CHIP_POLARIS10: 41758c2ecf20Sopenharmony_ci case CHIP_POLARIS11: 41768c2ecf20Sopenharmony_ci case CHIP_POLARIS12: 41778c2ecf20Sopenharmony_ci case CHIP_VEGAM: 41788c2ecf20Sopenharmony_ci case CHIP_VEGA20: 41798c2ecf20Sopenharmony_ci case CHIP_VEGA10: 41808c2ecf20Sopenharmony_ci case CHIP_VEGA12: 41818c2ecf20Sopenharmony_ci case CHIP_RAVEN: 41828c2ecf20Sopenharmony_ci case CHIP_ARCTURUS: 41838c2ecf20Sopenharmony_ci case CHIP_RENOIR: 41848c2ecf20Sopenharmony_ci case CHIP_NAVI10: 41858c2ecf20Sopenharmony_ci case CHIP_NAVI14: 41868c2ecf20Sopenharmony_ci case CHIP_NAVI12: 41878c2ecf20Sopenharmony_ci case CHIP_SIENNA_CICHLID: 41888c2ecf20Sopenharmony_ci break; 41898c2ecf20Sopenharmony_ci default: 41908c2ecf20Sopenharmony_ci goto disabled; 41918c2ecf20Sopenharmony_ci } 41928c2ecf20Sopenharmony_ci } 41938c2ecf20Sopenharmony_ci 41948c2ecf20Sopenharmony_ci return true; 41958c2ecf20Sopenharmony_ci 41968c2ecf20Sopenharmony_cidisabled: 41978c2ecf20Sopenharmony_ci dev_info(adev->dev, "GPU recovery disabled.\n"); 41988c2ecf20Sopenharmony_ci return false; 41998c2ecf20Sopenharmony_ci} 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_cistatic int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, 42038c2ecf20Sopenharmony_ci struct amdgpu_job *job, 42048c2ecf20Sopenharmony_ci bool *need_full_reset_arg) 42058c2ecf20Sopenharmony_ci{ 42068c2ecf20Sopenharmony_ci int i, r = 0; 42078c2ecf20Sopenharmony_ci bool need_full_reset = *need_full_reset_arg; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci amdgpu_debugfs_wait_dump(adev); 42108c2ecf20Sopenharmony_ci 42118c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) { 42128c2ecf20Sopenharmony_ci /* stop the data exchange thread */ 42138c2ecf20Sopenharmony_ci amdgpu_virt_fini_data_exchange(adev); 42148c2ecf20Sopenharmony_ci } 42158c2ecf20Sopenharmony_ci 42168c2ecf20Sopenharmony_ci /* block all schedulers and reset given job's ring */ 42178c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 42188c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci if (!ring || !ring->sched.thread) 42218c2ecf20Sopenharmony_ci continue; 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_ci /* after all hw jobs are reset, hw fence is meaningless, so force_completion */ 42248c2ecf20Sopenharmony_ci amdgpu_fence_driver_force_completion(ring); 42258c2ecf20Sopenharmony_ci } 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci if(job) 42288c2ecf20Sopenharmony_ci drm_sched_increase_karma(&job->base); 42298c2ecf20Sopenharmony_ci 42308c2ecf20Sopenharmony_ci /* Don't suspend on bare metal if we are not going to HW reset the ASIC */ 42318c2ecf20Sopenharmony_ci if (!amdgpu_sriov_vf(adev)) { 42328c2ecf20Sopenharmony_ci 42338c2ecf20Sopenharmony_ci if (!need_full_reset) 42348c2ecf20Sopenharmony_ci need_full_reset = amdgpu_device_ip_need_full_reset(adev); 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci if (!need_full_reset) { 42378c2ecf20Sopenharmony_ci amdgpu_device_ip_pre_soft_reset(adev); 42388c2ecf20Sopenharmony_ci r = amdgpu_device_ip_soft_reset(adev); 42398c2ecf20Sopenharmony_ci amdgpu_device_ip_post_soft_reset(adev); 42408c2ecf20Sopenharmony_ci if (r || amdgpu_device_ip_check_soft_reset(adev)) { 42418c2ecf20Sopenharmony_ci dev_info(adev->dev, "soft reset failed, will fallback to full reset!\n"); 42428c2ecf20Sopenharmony_ci need_full_reset = true; 42438c2ecf20Sopenharmony_ci } 42448c2ecf20Sopenharmony_ci } 42458c2ecf20Sopenharmony_ci 42468c2ecf20Sopenharmony_ci if (need_full_reset) 42478c2ecf20Sopenharmony_ci r = amdgpu_device_ip_suspend(adev); 42488c2ecf20Sopenharmony_ci 42498c2ecf20Sopenharmony_ci *need_full_reset_arg = need_full_reset; 42508c2ecf20Sopenharmony_ci } 42518c2ecf20Sopenharmony_ci 42528c2ecf20Sopenharmony_ci return r; 42538c2ecf20Sopenharmony_ci} 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_cistatic int amdgpu_do_asic_reset(struct amdgpu_hive_info *hive, 42568c2ecf20Sopenharmony_ci struct list_head *device_list_handle, 42578c2ecf20Sopenharmony_ci bool *need_full_reset_arg, 42588c2ecf20Sopenharmony_ci bool skip_hw_reset) 42598c2ecf20Sopenharmony_ci{ 42608c2ecf20Sopenharmony_ci struct amdgpu_device *tmp_adev = NULL; 42618c2ecf20Sopenharmony_ci bool need_full_reset = *need_full_reset_arg, vram_lost = false; 42628c2ecf20Sopenharmony_ci int r = 0; 42638c2ecf20Sopenharmony_ci 42648c2ecf20Sopenharmony_ci /* 42658c2ecf20Sopenharmony_ci * ASIC reset has to be done on all HGMI hive nodes ASAP 42668c2ecf20Sopenharmony_ci * to allow proper links negotiation in FW (within 1 sec) 42678c2ecf20Sopenharmony_ci */ 42688c2ecf20Sopenharmony_ci if (!skip_hw_reset && need_full_reset) { 42698c2ecf20Sopenharmony_ci list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { 42708c2ecf20Sopenharmony_ci /* For XGMI run all resets in parallel to speed up the process */ 42718c2ecf20Sopenharmony_ci if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { 42728c2ecf20Sopenharmony_ci if (!queue_work(system_unbound_wq, &tmp_adev->xgmi_reset_work)) 42738c2ecf20Sopenharmony_ci r = -EALREADY; 42748c2ecf20Sopenharmony_ci } else 42758c2ecf20Sopenharmony_ci r = amdgpu_asic_reset(tmp_adev); 42768c2ecf20Sopenharmony_ci 42778c2ecf20Sopenharmony_ci if (r) { 42788c2ecf20Sopenharmony_ci dev_err(tmp_adev->dev, "ASIC reset failed with error, %d for drm dev, %s", 42798c2ecf20Sopenharmony_ci r, adev_to_drm(tmp_adev)->unique); 42808c2ecf20Sopenharmony_ci break; 42818c2ecf20Sopenharmony_ci } 42828c2ecf20Sopenharmony_ci } 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_ci /* For XGMI wait for all resets to complete before proceed */ 42858c2ecf20Sopenharmony_ci if (!r) { 42868c2ecf20Sopenharmony_ci list_for_each_entry(tmp_adev, device_list_handle, 42878c2ecf20Sopenharmony_ci gmc.xgmi.head) { 42888c2ecf20Sopenharmony_ci if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { 42898c2ecf20Sopenharmony_ci flush_work(&tmp_adev->xgmi_reset_work); 42908c2ecf20Sopenharmony_ci r = tmp_adev->asic_reset_res; 42918c2ecf20Sopenharmony_ci if (r) 42928c2ecf20Sopenharmony_ci break; 42938c2ecf20Sopenharmony_ci } 42948c2ecf20Sopenharmony_ci } 42958c2ecf20Sopenharmony_ci } 42968c2ecf20Sopenharmony_ci } 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci if (!r && amdgpu_ras_intr_triggered()) { 42998c2ecf20Sopenharmony_ci list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { 43008c2ecf20Sopenharmony_ci if (tmp_adev->mmhub.funcs && 43018c2ecf20Sopenharmony_ci tmp_adev->mmhub.funcs->reset_ras_error_count) 43028c2ecf20Sopenharmony_ci tmp_adev->mmhub.funcs->reset_ras_error_count(tmp_adev); 43038c2ecf20Sopenharmony_ci } 43048c2ecf20Sopenharmony_ci 43058c2ecf20Sopenharmony_ci amdgpu_ras_intr_cleared(); 43068c2ecf20Sopenharmony_ci } 43078c2ecf20Sopenharmony_ci 43088c2ecf20Sopenharmony_ci list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { 43098c2ecf20Sopenharmony_ci if (need_full_reset) { 43108c2ecf20Sopenharmony_ci /* post card */ 43118c2ecf20Sopenharmony_ci if (amdgpu_device_asic_init(tmp_adev)) 43128c2ecf20Sopenharmony_ci dev_warn(tmp_adev->dev, "asic atom init failed!"); 43138c2ecf20Sopenharmony_ci 43148c2ecf20Sopenharmony_ci if (!r) { 43158c2ecf20Sopenharmony_ci dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n"); 43168c2ecf20Sopenharmony_ci r = amdgpu_amdkfd_resume_iommu(tmp_adev); 43178c2ecf20Sopenharmony_ci if (r) 43188c2ecf20Sopenharmony_ci goto out; 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci r = amdgpu_device_ip_resume_phase1(tmp_adev); 43218c2ecf20Sopenharmony_ci if (r) 43228c2ecf20Sopenharmony_ci goto out; 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_ci vram_lost = amdgpu_device_check_vram_lost(tmp_adev); 43258c2ecf20Sopenharmony_ci if (vram_lost) { 43268c2ecf20Sopenharmony_ci DRM_INFO("VRAM is lost due to GPU reset!\n"); 43278c2ecf20Sopenharmony_ci amdgpu_inc_vram_lost(tmp_adev); 43288c2ecf20Sopenharmony_ci } 43298c2ecf20Sopenharmony_ci 43308c2ecf20Sopenharmony_ci r = amdgpu_gtt_mgr_recover(ttm_manager_type(&tmp_adev->mman.bdev, TTM_PL_TT)); 43318c2ecf20Sopenharmony_ci if (r) 43328c2ecf20Sopenharmony_ci goto out; 43338c2ecf20Sopenharmony_ci 43348c2ecf20Sopenharmony_ci r = amdgpu_device_fw_loading(tmp_adev); 43358c2ecf20Sopenharmony_ci if (r) 43368c2ecf20Sopenharmony_ci return r; 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci r = amdgpu_device_ip_resume_phase2(tmp_adev); 43398c2ecf20Sopenharmony_ci if (r) 43408c2ecf20Sopenharmony_ci goto out; 43418c2ecf20Sopenharmony_ci 43428c2ecf20Sopenharmony_ci if (vram_lost) 43438c2ecf20Sopenharmony_ci amdgpu_device_fill_reset_magic(tmp_adev); 43448c2ecf20Sopenharmony_ci 43458c2ecf20Sopenharmony_ci /* 43468c2ecf20Sopenharmony_ci * Add this ASIC as tracked as reset was already 43478c2ecf20Sopenharmony_ci * complete successfully. 43488c2ecf20Sopenharmony_ci */ 43498c2ecf20Sopenharmony_ci amdgpu_register_gpu_instance(tmp_adev); 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ci r = amdgpu_device_ip_late_init(tmp_adev); 43528c2ecf20Sopenharmony_ci if (r) 43538c2ecf20Sopenharmony_ci goto out; 43548c2ecf20Sopenharmony_ci 43558c2ecf20Sopenharmony_ci amdgpu_fbdev_set_suspend(tmp_adev, 0); 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci /* 43588c2ecf20Sopenharmony_ci * The GPU enters bad state once faulty pages 43598c2ecf20Sopenharmony_ci * by ECC has reached the threshold, and ras 43608c2ecf20Sopenharmony_ci * recovery is scheduled next. So add one check 43618c2ecf20Sopenharmony_ci * here to break recovery if it indeed exceeds 43628c2ecf20Sopenharmony_ci * bad page threshold, and remind user to 43638c2ecf20Sopenharmony_ci * retire this GPU or setting one bigger 43648c2ecf20Sopenharmony_ci * bad_page_threshold value to fix this once 43658c2ecf20Sopenharmony_ci * probing driver again. 43668c2ecf20Sopenharmony_ci */ 43678c2ecf20Sopenharmony_ci if (!amdgpu_ras_check_err_threshold(tmp_adev)) { 43688c2ecf20Sopenharmony_ci /* must succeed. */ 43698c2ecf20Sopenharmony_ci amdgpu_ras_resume(tmp_adev); 43708c2ecf20Sopenharmony_ci } else { 43718c2ecf20Sopenharmony_ci r = -EINVAL; 43728c2ecf20Sopenharmony_ci goto out; 43738c2ecf20Sopenharmony_ci } 43748c2ecf20Sopenharmony_ci 43758c2ecf20Sopenharmony_ci /* Update PSP FW topology after reset */ 43768c2ecf20Sopenharmony_ci if (hive && tmp_adev->gmc.xgmi.num_physical_nodes > 1) 43778c2ecf20Sopenharmony_ci r = amdgpu_xgmi_update_topology(hive, tmp_adev); 43788c2ecf20Sopenharmony_ci } 43798c2ecf20Sopenharmony_ci } 43808c2ecf20Sopenharmony_ci 43818c2ecf20Sopenharmony_ciout: 43828c2ecf20Sopenharmony_ci if (!r) { 43838c2ecf20Sopenharmony_ci amdgpu_irq_gpu_reset_resume_helper(tmp_adev); 43848c2ecf20Sopenharmony_ci r = amdgpu_ib_ring_tests(tmp_adev); 43858c2ecf20Sopenharmony_ci if (r) { 43868c2ecf20Sopenharmony_ci dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r); 43878c2ecf20Sopenharmony_ci need_full_reset = true; 43888c2ecf20Sopenharmony_ci r = -EAGAIN; 43898c2ecf20Sopenharmony_ci goto end; 43908c2ecf20Sopenharmony_ci } 43918c2ecf20Sopenharmony_ci } 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_ci if (!r) 43948c2ecf20Sopenharmony_ci r = amdgpu_device_recover_vram(tmp_adev); 43958c2ecf20Sopenharmony_ci else 43968c2ecf20Sopenharmony_ci tmp_adev->asic_reset_res = r; 43978c2ecf20Sopenharmony_ci } 43988c2ecf20Sopenharmony_ci 43998c2ecf20Sopenharmony_ciend: 44008c2ecf20Sopenharmony_ci *need_full_reset_arg = need_full_reset; 44018c2ecf20Sopenharmony_ci return r; 44028c2ecf20Sopenharmony_ci} 44038c2ecf20Sopenharmony_ci 44048c2ecf20Sopenharmony_cistatic bool amdgpu_device_lock_adev(struct amdgpu_device *adev, 44058c2ecf20Sopenharmony_ci struct amdgpu_hive_info *hive) 44068c2ecf20Sopenharmony_ci{ 44078c2ecf20Sopenharmony_ci if (atomic_cmpxchg(&adev->in_gpu_reset, 0, 1) != 0) 44088c2ecf20Sopenharmony_ci return false; 44098c2ecf20Sopenharmony_ci 44108c2ecf20Sopenharmony_ci if (hive) { 44118c2ecf20Sopenharmony_ci down_write_nest_lock(&adev->reset_sem, &hive->hive_lock); 44128c2ecf20Sopenharmony_ci } else { 44138c2ecf20Sopenharmony_ci down_write(&adev->reset_sem); 44148c2ecf20Sopenharmony_ci } 44158c2ecf20Sopenharmony_ci 44168c2ecf20Sopenharmony_ci atomic_inc(&adev->gpu_reset_counter); 44178c2ecf20Sopenharmony_ci switch (amdgpu_asic_reset_method(adev)) { 44188c2ecf20Sopenharmony_ci case AMD_RESET_METHOD_MODE1: 44198c2ecf20Sopenharmony_ci adev->mp1_state = PP_MP1_STATE_SHUTDOWN; 44208c2ecf20Sopenharmony_ci break; 44218c2ecf20Sopenharmony_ci case AMD_RESET_METHOD_MODE2: 44228c2ecf20Sopenharmony_ci adev->mp1_state = PP_MP1_STATE_RESET; 44238c2ecf20Sopenharmony_ci break; 44248c2ecf20Sopenharmony_ci default: 44258c2ecf20Sopenharmony_ci adev->mp1_state = PP_MP1_STATE_NONE; 44268c2ecf20Sopenharmony_ci break; 44278c2ecf20Sopenharmony_ci } 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci return true; 44308c2ecf20Sopenharmony_ci} 44318c2ecf20Sopenharmony_ci 44328c2ecf20Sopenharmony_cistatic void amdgpu_device_unlock_adev(struct amdgpu_device *adev) 44338c2ecf20Sopenharmony_ci{ 44348c2ecf20Sopenharmony_ci amdgpu_vf_error_trans_all(adev); 44358c2ecf20Sopenharmony_ci adev->mp1_state = PP_MP1_STATE_NONE; 44368c2ecf20Sopenharmony_ci atomic_set(&adev->in_gpu_reset, 0); 44378c2ecf20Sopenharmony_ci up_write(&adev->reset_sem); 44388c2ecf20Sopenharmony_ci} 44398c2ecf20Sopenharmony_ci 44408c2ecf20Sopenharmony_cistatic void amdgpu_device_resume_display_audio(struct amdgpu_device *adev) 44418c2ecf20Sopenharmony_ci{ 44428c2ecf20Sopenharmony_ci struct pci_dev *p = NULL; 44438c2ecf20Sopenharmony_ci 44448c2ecf20Sopenharmony_ci p = pci_get_domain_bus_and_slot(pci_domain_nr(adev->pdev->bus), 44458c2ecf20Sopenharmony_ci adev->pdev->bus->number, 1); 44468c2ecf20Sopenharmony_ci if (p) { 44478c2ecf20Sopenharmony_ci pm_runtime_enable(&(p->dev)); 44488c2ecf20Sopenharmony_ci pm_runtime_resume(&(p->dev)); 44498c2ecf20Sopenharmony_ci } 44508c2ecf20Sopenharmony_ci 44518c2ecf20Sopenharmony_ci pci_dev_put(p); 44528c2ecf20Sopenharmony_ci} 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_cistatic int amdgpu_device_suspend_display_audio(struct amdgpu_device *adev) 44558c2ecf20Sopenharmony_ci{ 44568c2ecf20Sopenharmony_ci enum amd_reset_method reset_method; 44578c2ecf20Sopenharmony_ci struct pci_dev *p = NULL; 44588c2ecf20Sopenharmony_ci u64 expires; 44598c2ecf20Sopenharmony_ci 44608c2ecf20Sopenharmony_ci /* 44618c2ecf20Sopenharmony_ci * For now, only BACO and mode1 reset are confirmed 44628c2ecf20Sopenharmony_ci * to suffer the audio issue without proper suspended. 44638c2ecf20Sopenharmony_ci */ 44648c2ecf20Sopenharmony_ci reset_method = amdgpu_asic_reset_method(adev); 44658c2ecf20Sopenharmony_ci if ((reset_method != AMD_RESET_METHOD_BACO) && 44668c2ecf20Sopenharmony_ci (reset_method != AMD_RESET_METHOD_MODE1)) 44678c2ecf20Sopenharmony_ci return -EINVAL; 44688c2ecf20Sopenharmony_ci 44698c2ecf20Sopenharmony_ci p = pci_get_domain_bus_and_slot(pci_domain_nr(adev->pdev->bus), 44708c2ecf20Sopenharmony_ci adev->pdev->bus->number, 1); 44718c2ecf20Sopenharmony_ci if (!p) 44728c2ecf20Sopenharmony_ci return -ENODEV; 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci expires = pm_runtime_autosuspend_expiration(&(p->dev)); 44758c2ecf20Sopenharmony_ci if (!expires) 44768c2ecf20Sopenharmony_ci /* 44778c2ecf20Sopenharmony_ci * If we cannot get the audio device autosuspend delay, 44788c2ecf20Sopenharmony_ci * a fixed 4S interval will be used. Considering 3S is 44798c2ecf20Sopenharmony_ci * the audio controller default autosuspend delay setting. 44808c2ecf20Sopenharmony_ci * 4S used here is guaranteed to cover that. 44818c2ecf20Sopenharmony_ci */ 44828c2ecf20Sopenharmony_ci expires = ktime_get_mono_fast_ns() + NSEC_PER_SEC * 4ULL; 44838c2ecf20Sopenharmony_ci 44848c2ecf20Sopenharmony_ci while (!pm_runtime_status_suspended(&(p->dev))) { 44858c2ecf20Sopenharmony_ci if (!pm_runtime_suspend(&(p->dev))) 44868c2ecf20Sopenharmony_ci break; 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci if (expires < ktime_get_mono_fast_ns()) { 44898c2ecf20Sopenharmony_ci dev_warn(adev->dev, "failed to suspend display audio\n"); 44908c2ecf20Sopenharmony_ci pci_dev_put(p); 44918c2ecf20Sopenharmony_ci /* TODO: abort the succeeding gpu reset? */ 44928c2ecf20Sopenharmony_ci return -ETIMEDOUT; 44938c2ecf20Sopenharmony_ci } 44948c2ecf20Sopenharmony_ci } 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci pm_runtime_disable(&(p->dev)); 44978c2ecf20Sopenharmony_ci 44988c2ecf20Sopenharmony_ci pci_dev_put(p); 44998c2ecf20Sopenharmony_ci return 0; 45008c2ecf20Sopenharmony_ci} 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci/** 45038c2ecf20Sopenharmony_ci * amdgpu_device_gpu_recover - reset the asic and recover scheduler 45048c2ecf20Sopenharmony_ci * 45058c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 45068c2ecf20Sopenharmony_ci * @job: which job trigger hang 45078c2ecf20Sopenharmony_ci * 45088c2ecf20Sopenharmony_ci * Attempt to reset the GPU if it has hung (all asics). 45098c2ecf20Sopenharmony_ci * Attempt to do soft-reset or full-reset and reinitialize Asic 45108c2ecf20Sopenharmony_ci * Returns 0 for success or an error on failure. 45118c2ecf20Sopenharmony_ci */ 45128c2ecf20Sopenharmony_ci 45138c2ecf20Sopenharmony_ciint amdgpu_device_gpu_recover(struct amdgpu_device *adev, 45148c2ecf20Sopenharmony_ci struct amdgpu_job *job) 45158c2ecf20Sopenharmony_ci{ 45168c2ecf20Sopenharmony_ci struct list_head device_list, *device_list_handle = NULL; 45178c2ecf20Sopenharmony_ci bool need_full_reset = false; 45188c2ecf20Sopenharmony_ci bool job_signaled = false; 45198c2ecf20Sopenharmony_ci struct amdgpu_hive_info *hive = NULL; 45208c2ecf20Sopenharmony_ci struct amdgpu_device *tmp_adev = NULL; 45218c2ecf20Sopenharmony_ci int i, r = 0; 45228c2ecf20Sopenharmony_ci bool need_emergency_restart = false; 45238c2ecf20Sopenharmony_ci bool audio_suspended = false; 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_ci /* 45268c2ecf20Sopenharmony_ci * Special case: RAS triggered and full reset isn't supported 45278c2ecf20Sopenharmony_ci */ 45288c2ecf20Sopenharmony_ci need_emergency_restart = amdgpu_ras_need_emergency_restart(adev); 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci /* 45318c2ecf20Sopenharmony_ci * Flush RAM to disk so that after reboot 45328c2ecf20Sopenharmony_ci * the user can read log and see why the system rebooted. 45338c2ecf20Sopenharmony_ci */ 45348c2ecf20Sopenharmony_ci if (need_emergency_restart && amdgpu_ras_get_context(adev) && 45358c2ecf20Sopenharmony_ci amdgpu_ras_get_context(adev)->reboot) { 45368c2ecf20Sopenharmony_ci DRM_WARN("Emergency reboot."); 45378c2ecf20Sopenharmony_ci 45388c2ecf20Sopenharmony_ci ksys_sync_helper(); 45398c2ecf20Sopenharmony_ci emergency_restart(); 45408c2ecf20Sopenharmony_ci } 45418c2ecf20Sopenharmony_ci 45428c2ecf20Sopenharmony_ci dev_info(adev->dev, "GPU %s begin!\n", 45438c2ecf20Sopenharmony_ci need_emergency_restart ? "jobs stop":"reset"); 45448c2ecf20Sopenharmony_ci 45458c2ecf20Sopenharmony_ci /* 45468c2ecf20Sopenharmony_ci * Here we trylock to avoid chain of resets executing from 45478c2ecf20Sopenharmony_ci * either trigger by jobs on different adevs in XGMI hive or jobs on 45488c2ecf20Sopenharmony_ci * different schedulers for same device while this TO handler is running. 45498c2ecf20Sopenharmony_ci * We always reset all schedulers for device and all devices for XGMI 45508c2ecf20Sopenharmony_ci * hive so that should take care of them too. 45518c2ecf20Sopenharmony_ci */ 45528c2ecf20Sopenharmony_ci hive = amdgpu_get_xgmi_hive(adev); 45538c2ecf20Sopenharmony_ci if (hive) { 45548c2ecf20Sopenharmony_ci if (atomic_cmpxchg(&hive->in_reset, 0, 1) != 0) { 45558c2ecf20Sopenharmony_ci DRM_INFO("Bailing on TDR for s_job:%llx, hive: %llx as another already in progress", 45568c2ecf20Sopenharmony_ci job ? job->base.id : -1, hive->hive_id); 45578c2ecf20Sopenharmony_ci amdgpu_put_xgmi_hive(hive); 45588c2ecf20Sopenharmony_ci return 0; 45598c2ecf20Sopenharmony_ci } 45608c2ecf20Sopenharmony_ci mutex_lock(&hive->hive_lock); 45618c2ecf20Sopenharmony_ci } 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_ci /* 45648c2ecf20Sopenharmony_ci * Build list of devices to reset. 45658c2ecf20Sopenharmony_ci * In case we are in XGMI hive mode, resort the device list 45668c2ecf20Sopenharmony_ci * to put adev in the 1st position. 45678c2ecf20Sopenharmony_ci */ 45688c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device_list); 45698c2ecf20Sopenharmony_ci if (adev->gmc.xgmi.num_physical_nodes > 1) { 45708c2ecf20Sopenharmony_ci if (!hive) 45718c2ecf20Sopenharmony_ci return -ENODEV; 45728c2ecf20Sopenharmony_ci if (!list_is_first(&adev->gmc.xgmi.head, &hive->device_list)) 45738c2ecf20Sopenharmony_ci list_rotate_to_front(&adev->gmc.xgmi.head, &hive->device_list); 45748c2ecf20Sopenharmony_ci device_list_handle = &hive->device_list; 45758c2ecf20Sopenharmony_ci } else { 45768c2ecf20Sopenharmony_ci list_add_tail(&adev->gmc.xgmi.head, &device_list); 45778c2ecf20Sopenharmony_ci device_list_handle = &device_list; 45788c2ecf20Sopenharmony_ci } 45798c2ecf20Sopenharmony_ci 45808c2ecf20Sopenharmony_ci /* block all schedulers and reset given job's ring */ 45818c2ecf20Sopenharmony_ci list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { 45828c2ecf20Sopenharmony_ci if (!amdgpu_device_lock_adev(tmp_adev, hive)) { 45838c2ecf20Sopenharmony_ci dev_info(tmp_adev->dev, "Bailing on TDR for s_job:%llx, as another already in progress", 45848c2ecf20Sopenharmony_ci job ? job->base.id : -1); 45858c2ecf20Sopenharmony_ci r = 0; 45868c2ecf20Sopenharmony_ci goto skip_recovery; 45878c2ecf20Sopenharmony_ci } 45888c2ecf20Sopenharmony_ci 45898c2ecf20Sopenharmony_ci /* 45908c2ecf20Sopenharmony_ci * Try to put the audio codec into suspend state 45918c2ecf20Sopenharmony_ci * before gpu reset started. 45928c2ecf20Sopenharmony_ci * 45938c2ecf20Sopenharmony_ci * Due to the power domain of the graphics device 45948c2ecf20Sopenharmony_ci * is shared with AZ power domain. Without this, 45958c2ecf20Sopenharmony_ci * we may change the audio hardware from behind 45968c2ecf20Sopenharmony_ci * the audio driver's back. That will trigger 45978c2ecf20Sopenharmony_ci * some audio codec errors. 45988c2ecf20Sopenharmony_ci */ 45998c2ecf20Sopenharmony_ci if (!amdgpu_device_suspend_display_audio(tmp_adev)) 46008c2ecf20Sopenharmony_ci audio_suspended = true; 46018c2ecf20Sopenharmony_ci 46028c2ecf20Sopenharmony_ci amdgpu_ras_set_error_query_ready(tmp_adev, false); 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&tmp_adev->delayed_init_work); 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci if (!amdgpu_sriov_vf(tmp_adev)) 46078c2ecf20Sopenharmony_ci amdgpu_amdkfd_pre_reset(tmp_adev); 46088c2ecf20Sopenharmony_ci 46098c2ecf20Sopenharmony_ci /* 46108c2ecf20Sopenharmony_ci * Mark these ASICs to be reseted as untracked first 46118c2ecf20Sopenharmony_ci * And add them back after reset completed 46128c2ecf20Sopenharmony_ci */ 46138c2ecf20Sopenharmony_ci amdgpu_unregister_gpu_instance(tmp_adev); 46148c2ecf20Sopenharmony_ci 46158c2ecf20Sopenharmony_ci amdgpu_fbdev_set_suspend(tmp_adev, 1); 46168c2ecf20Sopenharmony_ci 46178c2ecf20Sopenharmony_ci /* disable ras on ALL IPs */ 46188c2ecf20Sopenharmony_ci if (!need_emergency_restart && 46198c2ecf20Sopenharmony_ci amdgpu_device_ip_need_full_reset(tmp_adev)) 46208c2ecf20Sopenharmony_ci amdgpu_ras_suspend(tmp_adev); 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 46238c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = tmp_adev->rings[i]; 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci if (!ring || !ring->sched.thread) 46268c2ecf20Sopenharmony_ci continue; 46278c2ecf20Sopenharmony_ci 46288c2ecf20Sopenharmony_ci drm_sched_stop(&ring->sched, job ? &job->base : NULL); 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_ci if (need_emergency_restart) 46318c2ecf20Sopenharmony_ci amdgpu_job_stop_all_jobs_on_sched(&ring->sched); 46328c2ecf20Sopenharmony_ci } 46338c2ecf20Sopenharmony_ci } 46348c2ecf20Sopenharmony_ci 46358c2ecf20Sopenharmony_ci if (need_emergency_restart) 46368c2ecf20Sopenharmony_ci goto skip_sched_resume; 46378c2ecf20Sopenharmony_ci 46388c2ecf20Sopenharmony_ci /* 46398c2ecf20Sopenharmony_ci * Must check guilty signal here since after this point all old 46408c2ecf20Sopenharmony_ci * HW fences are force signaled. 46418c2ecf20Sopenharmony_ci * 46428c2ecf20Sopenharmony_ci * job->base holds a reference to parent fence 46438c2ecf20Sopenharmony_ci */ 46448c2ecf20Sopenharmony_ci if (job && job->base.s_fence->parent && 46458c2ecf20Sopenharmony_ci dma_fence_is_signaled(job->base.s_fence->parent)) { 46468c2ecf20Sopenharmony_ci job_signaled = true; 46478c2ecf20Sopenharmony_ci dev_info(adev->dev, "Guilty job already signaled, skipping HW reset"); 46488c2ecf20Sopenharmony_ci goto skip_hw_reset; 46498c2ecf20Sopenharmony_ci } 46508c2ecf20Sopenharmony_ci 46518c2ecf20Sopenharmony_ciretry: /* Rest of adevs pre asic reset from XGMI hive. */ 46528c2ecf20Sopenharmony_ci list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { 46538c2ecf20Sopenharmony_ci r = amdgpu_device_pre_asic_reset(tmp_adev, 46548c2ecf20Sopenharmony_ci (tmp_adev == adev) ? job : NULL, 46558c2ecf20Sopenharmony_ci &need_full_reset); 46568c2ecf20Sopenharmony_ci /*TODO Should we stop ?*/ 46578c2ecf20Sopenharmony_ci if (r) { 46588c2ecf20Sopenharmony_ci dev_err(tmp_adev->dev, "GPU pre asic reset failed with err, %d for drm dev, %s ", 46598c2ecf20Sopenharmony_ci r, adev_to_drm(tmp_adev)->unique); 46608c2ecf20Sopenharmony_ci tmp_adev->asic_reset_res = r; 46618c2ecf20Sopenharmony_ci } 46628c2ecf20Sopenharmony_ci } 46638c2ecf20Sopenharmony_ci 46648c2ecf20Sopenharmony_ci /* Actual ASIC resets if needed.*/ 46658c2ecf20Sopenharmony_ci /* TODO Implement XGMI hive reset logic for SRIOV */ 46668c2ecf20Sopenharmony_ci if (amdgpu_sriov_vf(adev)) { 46678c2ecf20Sopenharmony_ci r = amdgpu_device_reset_sriov(adev, job ? false : true); 46688c2ecf20Sopenharmony_ci if (r) 46698c2ecf20Sopenharmony_ci adev->asic_reset_res = r; 46708c2ecf20Sopenharmony_ci } else { 46718c2ecf20Sopenharmony_ci r = amdgpu_do_asic_reset(hive, device_list_handle, &need_full_reset, false); 46728c2ecf20Sopenharmony_ci if (r && r == -EAGAIN) 46738c2ecf20Sopenharmony_ci goto retry; 46748c2ecf20Sopenharmony_ci } 46758c2ecf20Sopenharmony_ci 46768c2ecf20Sopenharmony_ciskip_hw_reset: 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci /* Post ASIC reset for all devs .*/ 46798c2ecf20Sopenharmony_ci list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { 46808c2ecf20Sopenharmony_ci 46818c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 46828c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = tmp_adev->rings[i]; 46838c2ecf20Sopenharmony_ci 46848c2ecf20Sopenharmony_ci if (!ring || !ring->sched.thread) 46858c2ecf20Sopenharmony_ci continue; 46868c2ecf20Sopenharmony_ci 46878c2ecf20Sopenharmony_ci /* No point to resubmit jobs if we didn't HW reset*/ 46888c2ecf20Sopenharmony_ci if (!tmp_adev->asic_reset_res && !job_signaled) 46898c2ecf20Sopenharmony_ci drm_sched_resubmit_jobs(&ring->sched); 46908c2ecf20Sopenharmony_ci 46918c2ecf20Sopenharmony_ci drm_sched_start(&ring->sched, !tmp_adev->asic_reset_res); 46928c2ecf20Sopenharmony_ci } 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci if (!amdgpu_device_has_dc_support(tmp_adev) && !job_signaled) { 46958c2ecf20Sopenharmony_ci drm_helper_resume_force_mode(adev_to_drm(tmp_adev)); 46968c2ecf20Sopenharmony_ci } 46978c2ecf20Sopenharmony_ci 46988c2ecf20Sopenharmony_ci tmp_adev->asic_reset_res = 0; 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci if (r) { 47018c2ecf20Sopenharmony_ci /* bad news, how to tell it to userspace ? */ 47028c2ecf20Sopenharmony_ci dev_info(tmp_adev->dev, "GPU reset(%d) failed\n", atomic_read(&tmp_adev->gpu_reset_counter)); 47038c2ecf20Sopenharmony_ci amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r); 47048c2ecf20Sopenharmony_ci } else { 47058c2ecf20Sopenharmony_ci dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&tmp_adev->gpu_reset_counter)); 47068c2ecf20Sopenharmony_ci } 47078c2ecf20Sopenharmony_ci } 47088c2ecf20Sopenharmony_ci 47098c2ecf20Sopenharmony_ciskip_sched_resume: 47108c2ecf20Sopenharmony_ci list_for_each_entry(tmp_adev, device_list_handle, gmc.xgmi.head) { 47118c2ecf20Sopenharmony_ci /*unlock kfd: SRIOV would do it separately */ 47128c2ecf20Sopenharmony_ci if (!need_emergency_restart && !amdgpu_sriov_vf(tmp_adev)) 47138c2ecf20Sopenharmony_ci amdgpu_amdkfd_post_reset(tmp_adev); 47148c2ecf20Sopenharmony_ci if (audio_suspended) 47158c2ecf20Sopenharmony_ci amdgpu_device_resume_display_audio(tmp_adev); 47168c2ecf20Sopenharmony_ci amdgpu_device_unlock_adev(tmp_adev); 47178c2ecf20Sopenharmony_ci } 47188c2ecf20Sopenharmony_ci 47198c2ecf20Sopenharmony_ciskip_recovery: 47208c2ecf20Sopenharmony_ci if (hive) { 47218c2ecf20Sopenharmony_ci atomic_set(&hive->in_reset, 0); 47228c2ecf20Sopenharmony_ci mutex_unlock(&hive->hive_lock); 47238c2ecf20Sopenharmony_ci amdgpu_put_xgmi_hive(hive); 47248c2ecf20Sopenharmony_ci } 47258c2ecf20Sopenharmony_ci 47268c2ecf20Sopenharmony_ci if (r) 47278c2ecf20Sopenharmony_ci dev_info(adev->dev, "GPU reset end with ret = %d\n", r); 47288c2ecf20Sopenharmony_ci return r; 47298c2ecf20Sopenharmony_ci} 47308c2ecf20Sopenharmony_ci 47318c2ecf20Sopenharmony_ci/** 47328c2ecf20Sopenharmony_ci * amdgpu_device_get_pcie_info - fence pcie info about the PCIE slot 47338c2ecf20Sopenharmony_ci * 47348c2ecf20Sopenharmony_ci * @adev: amdgpu_device pointer 47358c2ecf20Sopenharmony_ci * 47368c2ecf20Sopenharmony_ci * Fetchs and stores in the driver the PCIE capabilities (gen speed 47378c2ecf20Sopenharmony_ci * and lanes) of the slot the device is in. Handles APUs and 47388c2ecf20Sopenharmony_ci * virtualized environments where PCIE config space may not be available. 47398c2ecf20Sopenharmony_ci */ 47408c2ecf20Sopenharmony_cistatic void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) 47418c2ecf20Sopenharmony_ci{ 47428c2ecf20Sopenharmony_ci struct pci_dev *pdev; 47438c2ecf20Sopenharmony_ci enum pci_bus_speed speed_cap, platform_speed_cap; 47448c2ecf20Sopenharmony_ci enum pcie_link_width platform_link_width; 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci if (amdgpu_pcie_gen_cap) 47478c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask = amdgpu_pcie_gen_cap; 47488c2ecf20Sopenharmony_ci 47498c2ecf20Sopenharmony_ci if (amdgpu_pcie_lane_cap) 47508c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = amdgpu_pcie_lane_cap; 47518c2ecf20Sopenharmony_ci 47528c2ecf20Sopenharmony_ci /* covers APUs as well */ 47538c2ecf20Sopenharmony_ci if (pci_is_root_bus(adev->pdev->bus)) { 47548c2ecf20Sopenharmony_ci if (adev->pm.pcie_gen_mask == 0) 47558c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK; 47568c2ecf20Sopenharmony_ci if (adev->pm.pcie_mlw_mask == 0) 47578c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK; 47588c2ecf20Sopenharmony_ci return; 47598c2ecf20Sopenharmony_ci } 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci if (adev->pm.pcie_gen_mask && adev->pm.pcie_mlw_mask) 47628c2ecf20Sopenharmony_ci return; 47638c2ecf20Sopenharmony_ci 47648c2ecf20Sopenharmony_ci pcie_bandwidth_available(adev->pdev, NULL, 47658c2ecf20Sopenharmony_ci &platform_speed_cap, &platform_link_width); 47668c2ecf20Sopenharmony_ci 47678c2ecf20Sopenharmony_ci if (adev->pm.pcie_gen_mask == 0) { 47688c2ecf20Sopenharmony_ci /* asic caps */ 47698c2ecf20Sopenharmony_ci pdev = adev->pdev; 47708c2ecf20Sopenharmony_ci speed_cap = pcie_get_speed_cap(pdev); 47718c2ecf20Sopenharmony_ci if (speed_cap == PCI_SPEED_UNKNOWN) { 47728c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | 47738c2ecf20Sopenharmony_ci CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | 47748c2ecf20Sopenharmony_ci CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3); 47758c2ecf20Sopenharmony_ci } else { 47768c2ecf20Sopenharmony_ci if (speed_cap == PCIE_SPEED_16_0GT) 47778c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | 47788c2ecf20Sopenharmony_ci CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | 47798c2ecf20Sopenharmony_ci CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 | 47808c2ecf20Sopenharmony_ci CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN4); 47818c2ecf20Sopenharmony_ci else if (speed_cap == PCIE_SPEED_8_0GT) 47828c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | 47838c2ecf20Sopenharmony_ci CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 | 47848c2ecf20Sopenharmony_ci CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3); 47858c2ecf20Sopenharmony_ci else if (speed_cap == PCIE_SPEED_5_0GT) 47868c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 | 47878c2ecf20Sopenharmony_ci CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2); 47888c2ecf20Sopenharmony_ci else 47898c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1; 47908c2ecf20Sopenharmony_ci } 47918c2ecf20Sopenharmony_ci /* platform caps */ 47928c2ecf20Sopenharmony_ci if (platform_speed_cap == PCI_SPEED_UNKNOWN) { 47938c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | 47948c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2); 47958c2ecf20Sopenharmony_ci } else { 47968c2ecf20Sopenharmony_ci if (platform_speed_cap == PCIE_SPEED_16_0GT) 47978c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | 47988c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | 47998c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 | 48008c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4); 48018c2ecf20Sopenharmony_ci else if (platform_speed_cap == PCIE_SPEED_8_0GT) 48028c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | 48038c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 | 48048c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3); 48058c2ecf20Sopenharmony_ci else if (platform_speed_cap == PCIE_SPEED_5_0GT) 48068c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 | 48078c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2); 48088c2ecf20Sopenharmony_ci else 48098c2ecf20Sopenharmony_ci adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1; 48108c2ecf20Sopenharmony_ci 48118c2ecf20Sopenharmony_ci } 48128c2ecf20Sopenharmony_ci } 48138c2ecf20Sopenharmony_ci if (adev->pm.pcie_mlw_mask == 0) { 48148c2ecf20Sopenharmony_ci if (platform_link_width == PCIE_LNK_WIDTH_UNKNOWN) { 48158c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask |= AMDGPU_DEFAULT_PCIE_MLW_MASK; 48168c2ecf20Sopenharmony_ci } else { 48178c2ecf20Sopenharmony_ci switch (platform_link_width) { 48188c2ecf20Sopenharmony_ci case PCIE_LNK_X32: 48198c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 | 48208c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 | 48218c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | 48228c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | 48238c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | 48248c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | 48258c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); 48268c2ecf20Sopenharmony_ci break; 48278c2ecf20Sopenharmony_ci case PCIE_LNK_X16: 48288c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 | 48298c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | 48308c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | 48318c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | 48328c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | 48338c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); 48348c2ecf20Sopenharmony_ci break; 48358c2ecf20Sopenharmony_ci case PCIE_LNK_X12: 48368c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 | 48378c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | 48388c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | 48398c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | 48408c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); 48418c2ecf20Sopenharmony_ci break; 48428c2ecf20Sopenharmony_ci case PCIE_LNK_X8: 48438c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 | 48448c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | 48458c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | 48468c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); 48478c2ecf20Sopenharmony_ci break; 48488c2ecf20Sopenharmony_ci case PCIE_LNK_X4: 48498c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 | 48508c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | 48518c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); 48528c2ecf20Sopenharmony_ci break; 48538c2ecf20Sopenharmony_ci case PCIE_LNK_X2: 48548c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 | 48558c2ecf20Sopenharmony_ci CAIL_PCIE_LINK_WIDTH_SUPPORT_X1); 48568c2ecf20Sopenharmony_ci break; 48578c2ecf20Sopenharmony_ci case PCIE_LNK_X1: 48588c2ecf20Sopenharmony_ci adev->pm.pcie_mlw_mask = CAIL_PCIE_LINK_WIDTH_SUPPORT_X1; 48598c2ecf20Sopenharmony_ci break; 48608c2ecf20Sopenharmony_ci default: 48618c2ecf20Sopenharmony_ci break; 48628c2ecf20Sopenharmony_ci } 48638c2ecf20Sopenharmony_ci } 48648c2ecf20Sopenharmony_ci } 48658c2ecf20Sopenharmony_ci} 48668c2ecf20Sopenharmony_ci 48678c2ecf20Sopenharmony_ciint amdgpu_device_baco_enter(struct drm_device *dev) 48688c2ecf20Sopenharmony_ci{ 48698c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 48708c2ecf20Sopenharmony_ci struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); 48718c2ecf20Sopenharmony_ci 48728c2ecf20Sopenharmony_ci if (!amdgpu_device_supports_baco(adev_to_drm(adev))) 48738c2ecf20Sopenharmony_ci return -ENOTSUPP; 48748c2ecf20Sopenharmony_ci 48758c2ecf20Sopenharmony_ci if (ras && ras->supported && adev->nbio.funcs->enable_doorbell_interrupt) 48768c2ecf20Sopenharmony_ci adev->nbio.funcs->enable_doorbell_interrupt(adev, false); 48778c2ecf20Sopenharmony_ci 48788c2ecf20Sopenharmony_ci return amdgpu_dpm_baco_enter(adev); 48798c2ecf20Sopenharmony_ci} 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ciint amdgpu_device_baco_exit(struct drm_device *dev) 48828c2ecf20Sopenharmony_ci{ 48838c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 48848c2ecf20Sopenharmony_ci struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); 48858c2ecf20Sopenharmony_ci int ret = 0; 48868c2ecf20Sopenharmony_ci 48878c2ecf20Sopenharmony_ci if (!amdgpu_device_supports_baco(adev_to_drm(adev))) 48888c2ecf20Sopenharmony_ci return -ENOTSUPP; 48898c2ecf20Sopenharmony_ci 48908c2ecf20Sopenharmony_ci ret = amdgpu_dpm_baco_exit(adev); 48918c2ecf20Sopenharmony_ci if (ret) 48928c2ecf20Sopenharmony_ci return ret; 48938c2ecf20Sopenharmony_ci 48948c2ecf20Sopenharmony_ci if (ras && ras->supported && adev->nbio.funcs->enable_doorbell_interrupt) 48958c2ecf20Sopenharmony_ci adev->nbio.funcs->enable_doorbell_interrupt(adev, true); 48968c2ecf20Sopenharmony_ci 48978c2ecf20Sopenharmony_ci return 0; 48988c2ecf20Sopenharmony_ci} 48998c2ecf20Sopenharmony_ci 49008c2ecf20Sopenharmony_cistatic void amdgpu_cancel_all_tdr(struct amdgpu_device *adev) 49018c2ecf20Sopenharmony_ci{ 49028c2ecf20Sopenharmony_ci int i; 49038c2ecf20Sopenharmony_ci 49048c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 49058c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 49068c2ecf20Sopenharmony_ci 49078c2ecf20Sopenharmony_ci if (!ring || !ring->sched.thread) 49088c2ecf20Sopenharmony_ci continue; 49098c2ecf20Sopenharmony_ci 49108c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&ring->sched.work_tdr); 49118c2ecf20Sopenharmony_ci } 49128c2ecf20Sopenharmony_ci} 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci/** 49158c2ecf20Sopenharmony_ci * amdgpu_pci_error_detected - Called when a PCI error is detected. 49168c2ecf20Sopenharmony_ci * @pdev: PCI device struct 49178c2ecf20Sopenharmony_ci * @state: PCI channel state 49188c2ecf20Sopenharmony_ci * 49198c2ecf20Sopenharmony_ci * Description: Called when a PCI error is detected. 49208c2ecf20Sopenharmony_ci * 49218c2ecf20Sopenharmony_ci * Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT. 49228c2ecf20Sopenharmony_ci */ 49238c2ecf20Sopenharmony_cipci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) 49248c2ecf20Sopenharmony_ci{ 49258c2ecf20Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 49268c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 49278c2ecf20Sopenharmony_ci int i; 49288c2ecf20Sopenharmony_ci 49298c2ecf20Sopenharmony_ci DRM_INFO("PCI error: detected callback, state(%d)!!\n", state); 49308c2ecf20Sopenharmony_ci 49318c2ecf20Sopenharmony_ci if (adev->gmc.xgmi.num_physical_nodes > 1) { 49328c2ecf20Sopenharmony_ci DRM_WARN("No support for XGMI hive yet..."); 49338c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 49348c2ecf20Sopenharmony_ci } 49358c2ecf20Sopenharmony_ci 49368c2ecf20Sopenharmony_ci switch (state) { 49378c2ecf20Sopenharmony_ci case pci_channel_io_normal: 49388c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_CAN_RECOVER; 49398c2ecf20Sopenharmony_ci /* Fatal error, prepare for slot reset */ 49408c2ecf20Sopenharmony_ci case pci_channel_io_frozen: 49418c2ecf20Sopenharmony_ci /* 49428c2ecf20Sopenharmony_ci * Cancel and wait for all TDRs in progress if failing to 49438c2ecf20Sopenharmony_ci * set adev->in_gpu_reset in amdgpu_device_lock_adev 49448c2ecf20Sopenharmony_ci * 49458c2ecf20Sopenharmony_ci * Locking adev->reset_sem will prevent any external access 49468c2ecf20Sopenharmony_ci * to GPU during PCI error recovery 49478c2ecf20Sopenharmony_ci */ 49488c2ecf20Sopenharmony_ci while (!amdgpu_device_lock_adev(adev, NULL)) 49498c2ecf20Sopenharmony_ci amdgpu_cancel_all_tdr(adev); 49508c2ecf20Sopenharmony_ci 49518c2ecf20Sopenharmony_ci /* 49528c2ecf20Sopenharmony_ci * Block any work scheduling as we do for regular GPU reset 49538c2ecf20Sopenharmony_ci * for the duration of the recovery 49548c2ecf20Sopenharmony_ci */ 49558c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 49568c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 49578c2ecf20Sopenharmony_ci 49588c2ecf20Sopenharmony_ci if (!ring || !ring->sched.thread) 49598c2ecf20Sopenharmony_ci continue; 49608c2ecf20Sopenharmony_ci 49618c2ecf20Sopenharmony_ci drm_sched_stop(&ring->sched, NULL); 49628c2ecf20Sopenharmony_ci } 49638c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 49648c2ecf20Sopenharmony_ci case pci_channel_io_perm_failure: 49658c2ecf20Sopenharmony_ci /* Permanent error, prepare for device removal */ 49668c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 49678c2ecf20Sopenharmony_ci } 49688c2ecf20Sopenharmony_ci 49698c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 49708c2ecf20Sopenharmony_ci} 49718c2ecf20Sopenharmony_ci 49728c2ecf20Sopenharmony_ci/** 49738c2ecf20Sopenharmony_ci * amdgpu_pci_mmio_enabled - Enable MMIO and dump debug registers 49748c2ecf20Sopenharmony_ci * @pdev: pointer to PCI device 49758c2ecf20Sopenharmony_ci */ 49768c2ecf20Sopenharmony_cipci_ers_result_t amdgpu_pci_mmio_enabled(struct pci_dev *pdev) 49778c2ecf20Sopenharmony_ci{ 49788c2ecf20Sopenharmony_ci 49798c2ecf20Sopenharmony_ci DRM_INFO("PCI error: mmio enabled callback!!\n"); 49808c2ecf20Sopenharmony_ci 49818c2ecf20Sopenharmony_ci /* TODO - dump whatever for debugging purposes */ 49828c2ecf20Sopenharmony_ci 49838c2ecf20Sopenharmony_ci /* This called only if amdgpu_pci_error_detected returns 49848c2ecf20Sopenharmony_ci * PCI_ERS_RESULT_CAN_RECOVER. Read/write to the device still 49858c2ecf20Sopenharmony_ci * works, no need to reset slot. 49868c2ecf20Sopenharmony_ci */ 49878c2ecf20Sopenharmony_ci 49888c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 49898c2ecf20Sopenharmony_ci} 49908c2ecf20Sopenharmony_ci 49918c2ecf20Sopenharmony_ci/** 49928c2ecf20Sopenharmony_ci * amdgpu_pci_slot_reset - Called when PCI slot has been reset. 49938c2ecf20Sopenharmony_ci * @pdev: PCI device struct 49948c2ecf20Sopenharmony_ci * 49958c2ecf20Sopenharmony_ci * Description: This routine is called by the pci error recovery 49968c2ecf20Sopenharmony_ci * code after the PCI slot has been reset, just before we 49978c2ecf20Sopenharmony_ci * should resume normal operations. 49988c2ecf20Sopenharmony_ci */ 49998c2ecf20Sopenharmony_cipci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev) 50008c2ecf20Sopenharmony_ci{ 50018c2ecf20Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 50028c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 50038c2ecf20Sopenharmony_ci int r, i; 50048c2ecf20Sopenharmony_ci bool need_full_reset = true; 50058c2ecf20Sopenharmony_ci u32 memsize; 50068c2ecf20Sopenharmony_ci struct list_head device_list; 50078c2ecf20Sopenharmony_ci 50088c2ecf20Sopenharmony_ci DRM_INFO("PCI error: slot reset callback!!\n"); 50098c2ecf20Sopenharmony_ci 50108c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&device_list); 50118c2ecf20Sopenharmony_ci list_add_tail(&adev->gmc.xgmi.head, &device_list); 50128c2ecf20Sopenharmony_ci 50138c2ecf20Sopenharmony_ci /* wait for asic to come out of reset */ 50148c2ecf20Sopenharmony_ci msleep(500); 50158c2ecf20Sopenharmony_ci 50168c2ecf20Sopenharmony_ci /* Restore PCI confspace */ 50178c2ecf20Sopenharmony_ci amdgpu_device_load_pci_state(pdev); 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_ci /* confirm ASIC came out of reset */ 50208c2ecf20Sopenharmony_ci for (i = 0; i < adev->usec_timeout; i++) { 50218c2ecf20Sopenharmony_ci memsize = amdgpu_asic_get_config_memsize(adev); 50228c2ecf20Sopenharmony_ci 50238c2ecf20Sopenharmony_ci if (memsize != 0xffffffff) 50248c2ecf20Sopenharmony_ci break; 50258c2ecf20Sopenharmony_ci udelay(1); 50268c2ecf20Sopenharmony_ci } 50278c2ecf20Sopenharmony_ci if (memsize == 0xffffffff) { 50288c2ecf20Sopenharmony_ci r = -ETIME; 50298c2ecf20Sopenharmony_ci goto out; 50308c2ecf20Sopenharmony_ci } 50318c2ecf20Sopenharmony_ci 50328c2ecf20Sopenharmony_ci adev->in_pci_err_recovery = true; 50338c2ecf20Sopenharmony_ci r = amdgpu_device_pre_asic_reset(adev, NULL, &need_full_reset); 50348c2ecf20Sopenharmony_ci adev->in_pci_err_recovery = false; 50358c2ecf20Sopenharmony_ci if (r) 50368c2ecf20Sopenharmony_ci goto out; 50378c2ecf20Sopenharmony_ci 50388c2ecf20Sopenharmony_ci r = amdgpu_do_asic_reset(NULL, &device_list, &need_full_reset, true); 50398c2ecf20Sopenharmony_ci 50408c2ecf20Sopenharmony_ciout: 50418c2ecf20Sopenharmony_ci if (!r) { 50428c2ecf20Sopenharmony_ci if (amdgpu_device_cache_pci_state(adev->pdev)) 50438c2ecf20Sopenharmony_ci pci_restore_state(adev->pdev); 50448c2ecf20Sopenharmony_ci 50458c2ecf20Sopenharmony_ci DRM_INFO("PCIe error recovery succeeded\n"); 50468c2ecf20Sopenharmony_ci } else { 50478c2ecf20Sopenharmony_ci DRM_ERROR("PCIe error recovery failed, err:%d", r); 50488c2ecf20Sopenharmony_ci amdgpu_device_unlock_adev(adev); 50498c2ecf20Sopenharmony_ci } 50508c2ecf20Sopenharmony_ci 50518c2ecf20Sopenharmony_ci return r ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; 50528c2ecf20Sopenharmony_ci} 50538c2ecf20Sopenharmony_ci 50548c2ecf20Sopenharmony_ci/** 50558c2ecf20Sopenharmony_ci * amdgpu_pci_resume() - resume normal ops after PCI reset 50568c2ecf20Sopenharmony_ci * @pdev: pointer to PCI device 50578c2ecf20Sopenharmony_ci * 50588c2ecf20Sopenharmony_ci * Called when the error recovery driver tells us that its 50598c2ecf20Sopenharmony_ci * OK to resume normal operation. Use completion to allow 50608c2ecf20Sopenharmony_ci * halted scsi ops to resume. 50618c2ecf20Sopenharmony_ci */ 50628c2ecf20Sopenharmony_civoid amdgpu_pci_resume(struct pci_dev *pdev) 50638c2ecf20Sopenharmony_ci{ 50648c2ecf20Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 50658c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 50668c2ecf20Sopenharmony_ci int i; 50678c2ecf20Sopenharmony_ci 50688c2ecf20Sopenharmony_ci 50698c2ecf20Sopenharmony_ci DRM_INFO("PCI error: resume callback!!\n"); 50708c2ecf20Sopenharmony_ci 50718c2ecf20Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 50728c2ecf20Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 50738c2ecf20Sopenharmony_ci 50748c2ecf20Sopenharmony_ci if (!ring || !ring->sched.thread) 50758c2ecf20Sopenharmony_ci continue; 50768c2ecf20Sopenharmony_ci 50778c2ecf20Sopenharmony_ci 50788c2ecf20Sopenharmony_ci drm_sched_resubmit_jobs(&ring->sched); 50798c2ecf20Sopenharmony_ci drm_sched_start(&ring->sched, true); 50808c2ecf20Sopenharmony_ci } 50818c2ecf20Sopenharmony_ci 50828c2ecf20Sopenharmony_ci amdgpu_device_unlock_adev(adev); 50838c2ecf20Sopenharmony_ci} 50848c2ecf20Sopenharmony_ci 50858c2ecf20Sopenharmony_cibool amdgpu_device_cache_pci_state(struct pci_dev *pdev) 50868c2ecf20Sopenharmony_ci{ 50878c2ecf20Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 50888c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 50898c2ecf20Sopenharmony_ci int r; 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_ci r = pci_save_state(pdev); 50928c2ecf20Sopenharmony_ci if (!r) { 50938c2ecf20Sopenharmony_ci kfree(adev->pci_state); 50948c2ecf20Sopenharmony_ci 50958c2ecf20Sopenharmony_ci adev->pci_state = pci_store_saved_state(pdev); 50968c2ecf20Sopenharmony_ci 50978c2ecf20Sopenharmony_ci if (!adev->pci_state) { 50988c2ecf20Sopenharmony_ci DRM_ERROR("Failed to store PCI saved state"); 50998c2ecf20Sopenharmony_ci return false; 51008c2ecf20Sopenharmony_ci } 51018c2ecf20Sopenharmony_ci } else { 51028c2ecf20Sopenharmony_ci DRM_WARN("Failed to save PCI state, err:%d\n", r); 51038c2ecf20Sopenharmony_ci return false; 51048c2ecf20Sopenharmony_ci } 51058c2ecf20Sopenharmony_ci 51068c2ecf20Sopenharmony_ci return true; 51078c2ecf20Sopenharmony_ci} 51088c2ecf20Sopenharmony_ci 51098c2ecf20Sopenharmony_cibool amdgpu_device_load_pci_state(struct pci_dev *pdev) 51108c2ecf20Sopenharmony_ci{ 51118c2ecf20Sopenharmony_ci struct drm_device *dev = pci_get_drvdata(pdev); 51128c2ecf20Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(dev); 51138c2ecf20Sopenharmony_ci int r; 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_ci if (!adev->pci_state) 51168c2ecf20Sopenharmony_ci return false; 51178c2ecf20Sopenharmony_ci 51188c2ecf20Sopenharmony_ci r = pci_load_saved_state(pdev, adev->pci_state); 51198c2ecf20Sopenharmony_ci 51208c2ecf20Sopenharmony_ci if (!r) { 51218c2ecf20Sopenharmony_ci pci_restore_state(pdev); 51228c2ecf20Sopenharmony_ci } else { 51238c2ecf20Sopenharmony_ci DRM_WARN("Failed to load PCI state, err:%d\n", r); 51248c2ecf20Sopenharmony_ci return false; 51258c2ecf20Sopenharmony_ci } 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_ci return true; 51288c2ecf20Sopenharmony_ci} 51298c2ecf20Sopenharmony_ci 51308c2ecf20Sopenharmony_ci 5131