diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_device.c')
| -rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 347 |
1 files changed, 46 insertions, 301 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e5f26e5892ba..472e96ae884e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -72,8 +72,10 @@ #include "amdgpu_xgmi.h" #include "amdgpu_ras.h" +#include "amdgpu_wb.h" #include "amdgpu_ras_mgr.h" #include "amdgpu_pmu.h" +#include "amdgpu_smu.h" #include "amdgpu_fru_eeprom.h" #include "amdgpu_reset.h" #include "amdgpu_virt.h" @@ -1005,109 +1007,6 @@ int amdgpu_device_pci_reset(struct amdgpu_device *adev) return pci_reset_function(adev->pdev); } -/* - * amdgpu_device_wb_*() - * Writeback is the method by which the GPU updates special pages in memory - * with the status of certain GPU events (fences, ring pointers,etc.). - */ - -/** - * amdgpu_device_wb_fini - Disable Writeback and free memory - * - * @adev: amdgpu_device pointer - * - * Disables Writeback and frees the Writeback memory (all asics). - * Used at driver shutdown. - */ -static void amdgpu_device_wb_fini(struct amdgpu_device *adev) -{ - if (adev->wb.wb_obj) { - amdgpu_bo_free_kernel(&adev->wb.wb_obj, - &adev->wb.gpu_addr, - (void **)&adev->wb.wb); - adev->wb.wb_obj = NULL; - } -} - -/** - * amdgpu_device_wb_init - Init Writeback driver info and allocate memory - * - * @adev: amdgpu_device pointer - * - * Initializes writeback and allocates writeback memory (all asics). - * Used at driver startup. - * Returns 0 on success or an -error on failure. - */ -static int amdgpu_device_wb_init(struct amdgpu_device *adev) -{ - int r; - - if (adev->wb.wb_obj == NULL) { - /* AMDGPU_MAX_WB * sizeof(uint32_t) * 8 = AMDGPU_MAX_WB 256bit slots */ - r = amdgpu_bo_create_kernel(adev, AMDGPU_MAX_WB * sizeof(uint32_t) * 8, - PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT, - &adev->wb.wb_obj, &adev->wb.gpu_addr, - (void **)&adev->wb.wb); - if (r) { - dev_warn(adev->dev, "(%d) create WB bo failed\n", r); - return r; - } - - adev->wb.num_wb = AMDGPU_MAX_WB; - memset(&adev->wb.used, 0, sizeof(adev->wb.used)); - - /* clear wb memory */ - memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t) * 8); - } - - return 0; -} - -/** - * amdgpu_device_wb_get - Allocate a wb entry - * - * @adev: amdgpu_device pointer - * @wb: wb index - * - * Allocate a wb slot for use by the driver (all asics). - * Returns 0 on success or -EINVAL on failure. - */ -int amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb) -{ - unsigned long flags, offset; - - spin_lock_irqsave(&adev->wb.lock, flags); - offset = find_first_zero_bit(adev->wb.used, adev->wb.num_wb); - if (offset < adev->wb.num_wb) { - __set_bit(offset, adev->wb.used); - spin_unlock_irqrestore(&adev->wb.lock, flags); - *wb = offset << 3; /* convert to dw offset */ - return 0; - } else { - spin_unlock_irqrestore(&adev->wb.lock, flags); - return -EINVAL; - } -} - -/** - * amdgpu_device_wb_free - Free a wb entry - * - * @adev: amdgpu_device pointer - * @wb: wb index - * - * Free a wb slot allocated for use by the driver (all asics) - */ -void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb) -{ - unsigned long flags; - - wb >>= 3; - spin_lock_irqsave(&adev->wb.lock, flags); - if (wb < adev->wb.num_wb) - __clear_bit(wb, adev->wb.used); - spin_unlock_irqrestore(&adev->wb.lock, flags); -} - /** * amdgpu_device_resize_fb_bar - try to resize FB BAR * @@ -1304,37 +1203,44 @@ bool amdgpu_device_seamless_boot_supported(struct amdgpu_device *adev) return amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0); } -/* - * Intel hosts such as Rocket Lake, Alder Lake, Raptor Lake and Sapphire Rapids - * don't support dynamic speed switching. Until we have confirmation from Intel - * that a specific host supports it, it's safer that we keep it disabled for all. - * - * https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/005/pci-express-support/ - * https://gitlab.freedesktop.org/drm/amd/-/issues/2663 - */ -static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev) -{ #if IS_ENABLED(CONFIG_X86) - struct cpuinfo_x86 *c = &cpu_data(0); +static const struct x86_cpu_id amdgpu_pcie_dynamic_switching_quirks[] = { + /* + * Intel hosts such as Rocket Lake, Alder Lake, Raptor Lake and Sapphire Rapids + * don't support dynamic speed switching. Until we have confirmation from Intel + * that a specific host supports it, it's safer that we keep it disabled for all. + * + * https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/005/pci-express-support/ + * https://gitlab.freedesktop.org/drm/amd/-/issues/2663 + */ + X86_MATCH_VENDOR_FAM(INTEL, X86_FAMILY_ANY, NULL), + /* + * AMD Ryzen Pinnacle Ridge (Zen+, family 0x17 model 0x08) CPUs don't + * support PCIe dynamic speed switching. + * https://gitlab.freedesktop.org/drm/amd/-/work_items/5436 + */ + X86_MATCH_VENDOR_FAM_MODEL(AMD, 0x17, 0x08, NULL), + {} +}; +static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev) +{ /* eGPU change speeds based on USB4 fabric conditions */ if (dev_is_removable(adev->dev)) return true; - if (c->x86_vendor == X86_VENDOR_INTEL) + /* Hosts have problems with dynamic speed switching */ + if (x86_match_cpu(amdgpu_pcie_dynamic_switching_quirks)) return false; - /* - * AMD Ryzen Pinnacle Ridge (Zen+, family 0x17 model 0x08) CPUs don't - * support PCIe dynamic speed switching. - * https://gitlab.freedesktop.org/drm/amd/-/work_items/5436 - */ - if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 0x17 && - c->x86_model == 0x08) - return false; -#endif return true; } +#else +static inline bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev) +{ + return true; +} +#endif static bool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev) { @@ -2140,6 +2046,8 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) adev->cg_flags &= amdgpu_cg_mask; adev->pg_flags &= amdgpu_pg_mask; + amdgpu_smu_early_init(adev); + return 0; } @@ -2380,10 +2288,10 @@ static int amdgpu_device_ip_init(struct amdgpu_device *adev) r); goto init_failed; } - r = amdgpu_device_wb_init(adev); + r = amdgpu_wb_init(adev); if (r) { dev_err(adev->dev, - "amdgpu_device_wb_init failed %d\n", r); + "amdgpu_wb_init failed %d\n", r); goto init_failed; } adev->ip_blocks[i].status.hw = true; @@ -2915,7 +2823,7 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev) if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { amdgpu_ucode_free_bo(adev); amdgpu_free_static_csa(&adev->virt.csa_obj); - amdgpu_device_wb_fini(adev); + amdgpu_wb_fini(adev); amdgpu_device_mem_scratch_fini(adev); amdgpu_ib_pool_fini(adev); amdgpu_seq64_fini(adev); @@ -3687,6 +3595,10 @@ static void amdgpu_device_sys_interface_fini(struct amdgpu_device *adev) amdgpu_pm_sysfs_fini(adev); if (adev->ucode_sysfs_en) amdgpu_ucode_sysfs_fini(adev); + + amdgpu_discovery_sysfs_fini(adev); + amdgpu_preempt_mgr_sysfs_fini(adev); + amdgpu_device_attr_sysfs_fini(adev); amdgpu_fru_sysfs_fini(adev); @@ -3783,6 +3695,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, spin_lock_init(&adev->irq.lock); + amdgpu_early_init_rlc_reg_funcs(adev); amdgpu_device_init_apu_flags(adev); r = amdgpu_device_check_arguments(adev); @@ -4218,6 +4131,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) if (adev->mman.initialized) drain_workqueue(adev->mman.bdev.wq); + adev->shutdown = true; unregister_pm_notifier(&adev->pm_nb); @@ -4717,161 +4631,6 @@ exit: } /** - * amdgpu_device_ip_check_soft_reset - did soft reset succeed - * - * @adev: amdgpu_device pointer - * - * The list of all the hardware IPs that make up the asic is walked and - * the check_soft_reset callbacks are run. check_soft_reset determines - * if the asic is still hung or not. - * Returns true if any of the IPs are still in a hung state, false if not. - */ -static bool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev) -{ - int i; - bool asic_hang = false; - - if (amdgpu_sriov_vf(adev)) - return true; - - if (amdgpu_asic_need_full_reset(adev)) - return true; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (adev->ip_blocks[i].version->funcs->check_soft_reset) - adev->ip_blocks[i].status.hang = - adev->ip_blocks[i].version->funcs->check_soft_reset( - &adev->ip_blocks[i]); - if (adev->ip_blocks[i].status.hang) { - dev_info(adev->dev, "IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name); - asic_hang = true; - } - } - return asic_hang; -} - -/** - * amdgpu_device_ip_pre_soft_reset - prepare for soft reset - * - * @adev: amdgpu_device pointer - * - * The list of all the hardware IPs that make up the asic is walked and the - * pre_soft_reset callbacks are run if the block is hung. pre_soft_reset - * handles any IP specific hardware or software state changes that are - * necessary for a soft reset to succeed. - * Returns 0 on success, negative error code on failure. - */ -static int amdgpu_device_ip_pre_soft_reset(struct amdgpu_device *adev) -{ - int i, r = 0; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (adev->ip_blocks[i].status.hang && - adev->ip_blocks[i].version->funcs->pre_soft_reset) { - r = adev->ip_blocks[i].version->funcs->pre_soft_reset(&adev->ip_blocks[i]); - if (r) - return r; - } - } - - return 0; -} - -/** - * amdgpu_device_ip_need_full_reset - check if a full asic reset is needed - * - * @adev: amdgpu_device pointer - * - * Some hardware IPs cannot be soft reset. If they are hung, a full gpu - * reset is necessary to recover. - * Returns true if a full asic reset is required, false if not. - */ -static bool amdgpu_device_ip_need_full_reset(struct amdgpu_device *adev) -{ - int i; - - if (amdgpu_asic_need_full_reset(adev)) - return true; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if ((adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) || - (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) || - (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_ACP) || - (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) { - if (adev->ip_blocks[i].status.hang) { - dev_info(adev->dev, "Some block need full reset!\n"); - return true; - } - } - } - return false; -} - -/** - * amdgpu_device_ip_soft_reset - do a soft reset - * - * @adev: amdgpu_device pointer - * - * The list of all the hardware IPs that make up the asic is walked and the - * soft_reset callbacks are run if the block is hung. soft_reset handles any - * IP specific hardware or software state changes that are necessary to soft - * reset the IP. - * Returns 0 on success, negative error code on failure. - */ -static int amdgpu_device_ip_soft_reset(struct amdgpu_device *adev) -{ - int i, r = 0; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (adev->ip_blocks[i].status.hang && - adev->ip_blocks[i].version->funcs->soft_reset) { - r = adev->ip_blocks[i].version->funcs->soft_reset(&adev->ip_blocks[i]); - if (r) - return r; - } - } - - return 0; -} - -/** - * amdgpu_device_ip_post_soft_reset - clean up from soft reset - * - * @adev: amdgpu_device pointer - * - * The list of all the hardware IPs that make up the asic is walked and the - * post_soft_reset callbacks are run if the asic was hung. post_soft_reset - * handles any IP specific hardware or software state changes that are - * necessary after the IP has been soft reset. - * Returns 0 on success, negative error code on failure. - */ -static int amdgpu_device_ip_post_soft_reset(struct amdgpu_device *adev) -{ - int i, r = 0; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (adev->ip_blocks[i].status.hang && - adev->ip_blocks[i].version->funcs->post_soft_reset) - r = adev->ip_blocks[i].version->funcs->post_soft_reset(&adev->ip_blocks[i]); - if (r) - return r; - } - - return 0; -} - -/** * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf * * @adev: amdgpu_device pointer @@ -5162,20 +4921,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, /* Don't suspend on bare metal if we are not going to HW reset the ASIC */ if (!amdgpu_sriov_vf(adev)) { - - if (!need_full_reset) - need_full_reset = amdgpu_device_ip_need_full_reset(adev); - - if (!need_full_reset && amdgpu_gpu_recovery && - amdgpu_device_ip_check_soft_reset(adev)) { - amdgpu_device_ip_pre_soft_reset(adev); - r = amdgpu_device_ip_soft_reset(adev); - amdgpu_device_ip_post_soft_reset(adev); - if (r || amdgpu_device_ip_check_soft_reset(adev)) { - dev_info(adev->dev, "soft reset failed, will fallback to full reset!\n"); - need_full_reset = true; - } - } + need_full_reset = true; if (!test_bit(AMDGPU_SKIP_COREDUMP, &reset_context->flags)) { dev_info(tmp_adev->dev, "Dumping IP State\n"); @@ -5628,8 +5374,7 @@ static void amdgpu_device_halt_activities(struct amdgpu_device *adev, drm_client_dev_suspend(adev_to_drm(tmp_adev)); /* disable ras on ALL IPs */ - if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev) && - amdgpu_device_ip_need_full_reset(tmp_adev)) + if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev)) amdgpu_ras_suspend(tmp_adev); amdgpu_userq_pre_reset(tmp_adev); @@ -6901,7 +6646,7 @@ ssize_t amdgpu_get_soft_full_reset_mask(struct amdgpu_ring *ring) if (unlikely(!ring->adev->debug_disable_soft_recovery) && !amdgpu_sriov_vf(ring->adev) && ring->funcs->soft_recovery) - size |= AMDGPU_RESET_TYPE_SOFT_RESET; + size |= AMDGPU_RESET_TYPE_SOFT_RECOVERY; return size; } @@ -6917,8 +6662,8 @@ ssize_t amdgpu_show_reset_mask(char *buf, uint32_t supported_reset) } - if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RESET) - size += sysfs_emit_at(buf, size, "soft "); + if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RECOVERY) + size += sysfs_emit_at(buf, size, "soft_recovery "); if (supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE) size += sysfs_emit_at(buf, size, "queue "); |
