int amdgpu_ip_block_suspend(struct amdgpu_ip_block *ip_block)
{ int r;
if (ip_block->version->funcs->suspend) {
r = ip_block->version->funcs->suspend(ip_block); if (r) {
dev_err(ip_block->adev->dev, "suspend of IP block <%s> failed %d\n",
ip_block->version->funcs->name, r); return r;
}
}
ip_block->status.hw = false; return0;
}
int amdgpu_ip_block_resume(struct amdgpu_ip_block *ip_block)
{ int r;
if (ip_block->version->funcs->resume) {
r = ip_block->version->funcs->resume(ip_block); if (r) {
dev_err(ip_block->adev->dev, "resume of IP block <%s> failed %d\n",
ip_block->version->funcs->name, r); return r;
}
}
switch (amdgpu_runtime_pm) { case2: if (bamaco_support & MACO_SUPPORT) {
adev->pm.rpm_mode = AMDGPU_RUNPM_BAMACO;
dev_info(adev->dev, "Forcing BAMACO for runtime pm\n");
} elseif (bamaco_support == BACO_SUPPORT) {
adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
dev_info(adev->dev, "Requested mode BAMACO not available,fallback to use BACO\n");
} break; case1: if (bamaco_support & BACO_SUPPORT) {
adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
dev_info(adev->dev, "Forcing BACO for runtime pm\n");
} break; case -1: case -2: if (amdgpu_device_supports_px(adev)) { /* enable PX as runtime mode */
adev->pm.rpm_mode = AMDGPU_RUNPM_PX;
dev_info(adev->dev, "Using ATPX for runtime pm\n");
} elseif (amdgpu_device_supports_boco(adev)) { /* enable boco as runtime mode */
adev->pm.rpm_mode = AMDGPU_RUNPM_BOCO;
dev_info(adev->dev, "Using BOCO for runtime pm\n");
} else { if (!bamaco_support) goto no_runtime_pm;
switch (adev->asic_type) { case CHIP_VEGA20: case CHIP_ARCTURUS: /* BACO are not supported on vega20 and arctrus */ break; case CHIP_VEGA10: /* enable BACO as runpm mode if noretry=0 */ if (!adev->gmc.noretry && !amdgpu_passthrough(adev))
adev->pm.rpm_mode = AMDGPU_RUNPM_BACO; break; default: /* enable BACO as runpm mode on CI+ */ if (!amdgpu_passthrough(adev))
adev->pm.rpm_mode = AMDGPU_RUNPM_BACO; break;
}
if (adev->pm.rpm_mode == AMDGPU_RUNPM_BACO) { if (bamaco_support & MACO_SUPPORT) {
adev->pm.rpm_mode = AMDGPU_RUNPM_BAMACO;
dev_info(adev->dev, "Using BAMACO for runtime pm\n");
} else {
dev_info(adev->dev, "Using BACO for runtime pm\n");
}
}
} break; case0:
dev_info(adev->dev, "runtime pm is manually disabled\n"); break; default: break;
}
/* try to using vram apreature to access vram first */
count = amdgpu_device_aper_access(adev, pos, buf, size, write);
size -= count; if (size) { /* using MM to access rest vram */
pos += count;
buf += count;
amdgpu_device_mm_access(adev, pos, buf, size, write);
}
}
/* *registeraccesshelperfunctions.
*/
/* Check if hw access should be skipped because of hotplug or device error */ bool amdgpu_device_skip_hw_access(struct amdgpu_device *adev)
{ if (adev->no_hw_access) returntrue;
/** *amdgpu_device_resize_fb_bar-trytoresizeFBBAR * *@adev:amdgpu_devicepointer * *TrytoresizeFBBARtomakeallVRAMCPUaccessible.Wetryveryhardnot *tofail,butifanyoftheBARsisnotaccessibleafterthesizeweabort *driverloadingbyreturning-ENODEV.
*/ int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev)
{ int rbar_size = pci_rebar_bytes_to_size(adev->gmc.real_vram_size); struct pci_bus *root; struct resource *res; unsignedint i;
u16 cmd; int r;
if (!IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT)) return0;
/* Bypass for VF */ if (amdgpu_sriov_vf(adev)) return0;
if (!amdgpu_rebar) return0;
/* resizing on Dell G5 SE platforms causes problems with runtime pm */ if ((amdgpu_runtime_pm != 0) &&
adev->pdev->vendor == PCI_VENDOR_ID_ATI &&
adev->pdev->device == 0x731f &&
adev->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL) return0;
/* PCI_EXT_CAP_ID_VNDR extended capability is located at 0x100 */ if (!pci_find_ext_capability(adev->pdev, PCI_EXT_CAP_ID_VNDR))
dev_warn(
adev->dev, "System can't access extended configuration space, please check!!\n");
/* skip if the bios has already enabled large BAR */ if (adev->gmc.real_vram_size &&
(pci_resource_len(adev->pdev, 0) >= adev->gmc.real_vram_size)) return0;
/* Check if the root BUS has 64bit memory resources */
root = adev->pdev->bus; while (root->parent)
root = root->parent;
/* Trying to resize is pointless without a root hub window above 4GB */ if (!res) return0;
/* Limit the BAR size to what is available */
rbar_size = min(fls(pci_rebar_get_possible_sizes(adev->pdev, 0)) - 1,
rbar_size);
/* Disable memory decoding while we change the BAR addresses and size */
pci_read_config_word(adev->pdev, PCI_COMMAND, &cmd);
pci_write_config_word(adev->pdev, PCI_COMMAND,
cmd & ~PCI_COMMAND_MEMORY);
/* Free the VRAM and doorbell BAR, we most likely need to move both. */
amdgpu_doorbell_fini(adev); if (adev->asic_type >= CHIP_BONAIRE)
pci_release_resource(adev->pdev, 2);
pci_release_resource(adev->pdev, 0);
r = pci_resize_resource(adev->pdev, 0, rbar_size); if (r == -ENOSPC)
dev_info(adev->dev, "Not enough PCI address space for a large BAR."); elseif (r && r != -ENOTSUPP)
dev_err(adev->dev, "Problem resizing BAR0 (%d).", r);
/* When the doorbell or fb BAR isn't available we have no chance of *usingthedevice.
*/
r = amdgpu_doorbell_init(adev); if (r || (pci_resource_flags(adev->pdev, 0) & IORESOURCE_UNSET)) return -ENODEV;
flags = amdgpu_device_get_vbios_flags(adev); if (flags & AMDGPU_VBIOS_SKIP) returnfalse; if ((flags & AMDGPU_VBIOS_OPTIONAL) && !adev->bios) returnfalse;
if (amdgpu_passthrough(adev)) { /* for FIJI: In whole GPU pass-through virtualization case, after VM reboot *someoldsmcfwstillneeddriverdovPostotherwisegpuhang,while *thosesmcfwversionabove22.15doesn'thavethisflaw,soweforce *vpostexecutedforsmcversionbelow22.15
*/ if (adev->asic_type == CHIP_FIJI) { int err;
uint32_t fw_ver;
err = request_firmware(&adev->pm.fw, "amdgpu/fiji_smc.bin", adev->dev); /* force vPost if error occurred */ if (err) returntrue;
/* if we get transitioned to only one device, take VGA back */ /** *amdgpu_device_vga_set_decode-enable/disablevgadecode * *@pdev:PCIdevicepointer *@state:enable/disablevgadecode * *Enable/disablevgadecode(allasics). *ReturnsVGAresourceflags.
*/ staticunsignedint amdgpu_device_vga_set_decode(struct pci_dev *pdev, bool state)
{ struct amdgpu_device *adev = drm_to_adev(pci_get_drvdata(pdev));
/** *amdgpu_device_check_block_size-validatethevmblocksize * *@adev:amdgpu_devicepointer * *Validatesthevmblocksizespecifiedviamoduleparameter. *Thevmblocksizedefinesnumberofbitsinpagetableversuspagedirectory, *apageis4KBsowehave12bitsoffset,minimum9bitsinthe *pagetableandtheremainingbitsareinthepagedirectory.
*/ staticvoid amdgpu_device_check_block_size(struct amdgpu_device *adev)
{ /* defines number of bits in page table versus page directory, *apageis4KBsowehave12bitsoffset,minimum9bitsinthe *pagetableandtheremainingbitsareinthepagedirectory
*/ if (amdgpu_vm_block_size == -1) return;
if (amdgpu_vm_block_size < 9) {
dev_warn(adev->dev, "VM page table size (%d) too small\n",
amdgpu_vm_block_size);
amdgpu_vm_block_size = -1;
}
}
/** *amdgpu_device_check_vm_size-validatethevmsize * *@adev:amdgpu_devicepointer * *ValidatesthevmsizeinGBspecifiedviamoduleparameter. *TheVMsizeisthesizeoftheGPUvirtualmemoryspaceinGB.
*/ staticvoid amdgpu_device_check_vm_size(struct amdgpu_device *adev)
{ /* no need to check the default value */ if (amdgpu_vm_size == -1) return;
if (amdgpu_vm_size < 1) {
dev_warn(adev->dev, "VM size (%d) too small, min is 1GB\n",
amdgpu_vm_size);
amdgpu_vm_size = -1;
}
}
if (amdgpu_sched_jobs < 4) {
dev_warn(adev->dev, "sched jobs (%d) must be at least 4\n",
amdgpu_sched_jobs);
amdgpu_sched_jobs = 4;
} elseif (!is_power_of_2(amdgpu_sched_jobs)) {
dev_warn(adev->dev, "sched jobs (%d) must be a power of 2\n",
amdgpu_sched_jobs);
amdgpu_sched_jobs = roundup_pow_of_two(amdgpu_sched_jobs);
}
if (amdgpu_gart_size != -1 && amdgpu_gart_size < 32) { /* gart size must be greater or equal to 32M */
dev_warn(adev->dev, "gart size (%d) too small\n",
amdgpu_gart_size);
amdgpu_gart_size = -1;
}
if (amdgpu_gtt_size != -1 && amdgpu_gtt_size < 32) { /* gtt size must be greater or equal to 32M */
dev_warn(adev->dev, "gtt size (%d) too small\n",
amdgpu_gtt_size);
amdgpu_gtt_size = -1;
}
/* valid range is between 4 and 9 inclusive */ if (amdgpu_vm_fragment_size != -1 &&
(amdgpu_vm_fragment_size > 9 || amdgpu_vm_fragment_size < 4)) {
dev_warn(adev->dev, "valid range is between 4 and 9\n");
amdgpu_vm_fragment_size = -1;
}
if (amdgpu_sched_hw_submission < 2) {
dev_warn(adev->dev, "sched hw submission jobs (%d) must be at least 2\n",
amdgpu_sched_hw_submission);
amdgpu_sched_hw_submission = 2;
} elseif (!is_power_of_2(amdgpu_sched_hw_submission)) {
dev_warn(adev->dev, "sched hw submission jobs (%d) must be a power of 2\n",
amdgpu_sched_hw_submission);
amdgpu_sched_hw_submission = roundup_pow_of_two(amdgpu_sched_hw_submission);
}
if (amdgpu_reset_method < -1 || amdgpu_reset_method > 4) {
dev_warn(adev->dev, "invalid option for reset method, reverting to default\n");
amdgpu_reset_method = -1;
}
/** *amdgpu_device_ip_set_clockgating_state-settheCGstate * *@dev:amdgpu_devicepointer *@block_type:TypeofhardwareIP(SMU,GFX,UVD,etc.) *@state:clockgatingstate(gateorungate) * *Setstherequestedclockgatingstateforallinstancesof *thehardwareIPspecified. *Returnstheerrorcodefromthelastinstance.
*/ int amdgpu_device_ip_set_clockgating_state(void *dev, enum amd_ip_block_type block_type, enum amd_clockgating_state state)
{ struct amdgpu_device *adev = dev; 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].version->type != block_type) continue; if (!adev->ip_blocks[i].version->funcs->set_clockgating_state) continue;
r = adev->ip_blocks[i].version->funcs->set_clockgating_state(
&adev->ip_blocks[i], state); if (r)
dev_err(adev->dev, "set_clockgating_state of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
} return r;
}
/** *amdgpu_device_ip_set_powergating_state-setthePGstate * *@dev:amdgpu_devicepointer *@block_type:TypeofhardwareIP(SMU,GFX,UVD,etc.) *@state:powergatingstate(gateorungate) * *Setstherequestedpowergatingstateforallinstancesof *thehardwareIPspecified. *Returnstheerrorcodefromthelastinstance.
*/ int amdgpu_device_ip_set_powergating_state(void *dev, enum amd_ip_block_type block_type, enum amd_powergating_state state)
{ struct amdgpu_device *adev = dev; 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].version->type != block_type) continue; if (!adev->ip_blocks[i].version->funcs->set_powergating_state) continue;
r = adev->ip_blocks[i].version->funcs->set_powergating_state(
&adev->ip_blocks[i], state); if (r)
dev_err(adev->dev, "set_powergating_state of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
} return r;
}
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; if (adev->ip_blocks[i].version->funcs->get_clockgating_state)
adev->ip_blocks[i].version->funcs->get_clockgating_state(
&adev->ip_blocks[i], flags);
}
}
/** *amdgpu_device_ip_wait_for_idle-waitforidle * *@adev:amdgpu_devicepointer *@block_type:TypeofhardwareIP(SMU,GFX,UVD,etc.) * *WaitsfortherequesthardwareIPtobeidle. *Returns0forsuccessoranegativeerrorcodeonfailure.
*/ int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev, enum amd_ip_block_type block_type)
{ int i, r;
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; if (adev->ip_blocks[i].version->type == block_type) { if (adev->ip_blocks[i].version->funcs->wait_for_idle) {
r = adev->ip_blocks[i].version->funcs->wait_for_idle(
&adev->ip_blocks[i]); if (r) return r;
} break;
}
} return0;
if (amdgpu_sriov_vf(adev)) {
r = amdgpu_virt_request_full_gpu(adev, true); if (r) return r;
}
switch (adev->asic_type) { #ifdef CONFIG_DRM_AMDGPU_SI case CHIP_VERDE: case CHIP_TAHITI: case CHIP_PITCAIRN: case CHIP_OLAND: case CHIP_HAINAN:
adev->family = AMDGPU_FAMILY_SI;
r = si_set_ip_blocks(adev); if (r) return r; break; #endif #ifdef CONFIG_DRM_AMDGPU_CIK case CHIP_BONAIRE: case CHIP_HAWAII: case CHIP_KAVERI: case CHIP_KABINI: case CHIP_MULLINS: if (adev->flags & AMD_IS_APU)
adev->family = AMDGPU_FAMILY_KV; else
adev->family = AMDGPU_FAMILY_CI;
r = cik_set_ip_blocks(adev); if (r) return r; break; #endif case CHIP_TOPAZ: case CHIP_TONGA: case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: case CHIP_POLARIS12: case CHIP_VEGAM: case CHIP_CARRIZO: case CHIP_STONEY: if (adev->flags & AMD_IS_APU)
adev->family = AMDGPU_FAMILY_CZ; else
adev->family = AMDGPU_FAMILY_VI;
r = vi_set_ip_blocks(adev); if (r) return r; break; default:
r = amdgpu_discovery_set_ip_blocks(adev); if (r) return r; break;
}
/* Check for IP version 9.4.3 with A0 hardware */ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) &&
!amdgpu_device_get_rev_id(adev)) {
dev_err(adev->dev, "Unsupported A0 hardware\n"); return -ENODEV; /* device unsupported - no device error */
}
total = true; for (i = 0; i < adev->num_ip_blocks; i++) {
ip_block = &adev->ip_blocks[i];
if ((amdgpu_ip_block_mask & (1 << i)) == 0) {
dev_warn(adev->dev, "disabled ip block: %d <%s>\n", i,
adev->ip_blocks[i].version->funcs->name);
adev->ip_blocks[i].status.valid = false;
} elseif (ip_block->version->funcs->early_init) {
r = ip_block->version->funcs->early_init(ip_block); if (r == -ENOENT) {
adev->ip_blocks[i].status.valid = false;
} elseif (r) {
dev_err(adev->dev, "early_init of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name,
r);
total = false;
} else {
adev->ip_blocks[i].status.valid = true;
}
} else {
adev->ip_blocks[i].status.valid = true;
} /* get the vbios after the asic_funcs are set up */ if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) {
r = amdgpu_device_parse_gpu_info_fw(adev); if (r) return r;
staticint amdgpu_device_ip_hw_init_phase1(struct amdgpu_device *adev)
{ int i, r;
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.sw) continue; if (adev->ip_blocks[i].status.hw) continue; if (!amdgpu_ip_member_of_hwini(
adev, adev->ip_blocks[i].version->type)) continue; if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
(amdgpu_sriov_vf(adev) && (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)) ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) {
r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) {
dev_err(adev->dev, "hw_init of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name,
r); return r;
}
adev->ip_blocks[i].status.hw = true;
}
}
return0;
}
staticint amdgpu_device_ip_hw_init_phase2(struct amdgpu_device *adev)
{ int i, r;
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.sw) continue; if (adev->ip_blocks[i].status.hw) continue; if (!amdgpu_ip_member_of_hwini(
adev, adev->ip_blocks[i].version->type)) continue;
r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) {
dev_err(adev->dev, "hw_init of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r); return r;
}
adev->ip_blocks[i].status.hw = true;
}
return0;
}
staticint amdgpu_device_fw_loading(struct amdgpu_device *adev)
{ int r = 0; int i;
uint32_t smu_version;
if (adev->asic_type >= CHIP_VEGA10) { for (i = 0; i < adev->num_ip_blocks; i++) { if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_PSP) continue;
if (!amdgpu_ip_member_of_hwini(adev,
AMD_IP_BLOCK_TYPE_PSP)) break;
if (!adev->ip_blocks[i].status.sw) continue;
/* no need to do the fw loading again if already done*/ if (adev->ip_blocks[i].status.hw == true) break;
if (amdgpu_in_reset(adev) || adev->in_suspend) {
r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); if (r) return r;
} else {
r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) {
dev_err(adev->dev, "hw_init of IP block <%s> failed %d\n",
adev->ip_blocks[i]
.version->funcs->name,
r); return r;
}
adev->ip_blocks[i].status.hw = true;
} break;
}
}
if (!amdgpu_sriov_vf(adev) || adev->asic_type == CHIP_TONGA)
r = amdgpu_pm_load_smu_firmware(adev, &smu_version);
r = drm_sched_init(&ring->sched, &args); if (r) {
dev_err(adev->dev, "Failed to create scheduler on ring %s.\n",
ring->name); return r;
}
r = amdgpu_uvd_entity_init(adev, ring); if (r) {
dev_err(adev->dev, "Failed to create UVD scheduling entity on ring %s.\n",
ring->name); return r;
}
r = amdgpu_vce_entity_init(adev, ring); if (r) {
dev_err(adev->dev, "Failed to create VCE scheduling entity on ring %s.\n",
ring->name); return r;
}
}
if (adev->xcp_mgr)
amdgpu_xcp_update_partition_sched_list(adev);
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; if (adev->ip_blocks[i].version->funcs->sw_init) {
r = adev->ip_blocks[i].version->funcs->sw_init(&adev->ip_blocks[i]); if (r) {
dev_err(adev->dev, "sw_init of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name,
r); goto init_failed;
}
}
adev->ip_blocks[i].status.sw = true;
if (!amdgpu_ip_member_of_hwini(
adev, adev->ip_blocks[i].version->type)) continue;
if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) { /* need to do common hw init early so everything is set up for gmc */
r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) {
dev_err(adev->dev, "hw_init %d failed %d\n", i,
r); goto init_failed;
}
adev->ip_blocks[i].status.hw = true;
} elseif (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) { /* need to do gmc hw init early so we can allocate gpu mem */ /* Try to reserve bad pages early */ if (amdgpu_sriov_vf(adev))
amdgpu_virt_exchange_data(adev);
r = amdgpu_device_mem_scratch_init(adev); if (r) {
dev_err(adev->dev, "amdgpu_mem_scratch_init failed %d\n",
r); goto init_failed;
}
r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]); if (r) {
dev_err(adev->dev, "hw_init %d failed %d\n", i,
r); goto init_failed;
}
r = amdgpu_device_wb_init(adev); if (r) {
dev_err(adev->dev, "amdgpu_device_wb_init failed %d\n", r); goto init_failed;
}
adev->ip_blocks[i].status.hw = true;
/* right after GMC hw init, we create CSA */ if (adev->gfx.mcbp) {
r = amdgpu_allocate_static_csa(adev, &adev->virt.csa_obj,
AMDGPU_GEM_DOMAIN_VRAM |
AMDGPU_GEM_DOMAIN_GTT,
AMDGPU_CSA_SIZE); if (r) {
dev_err(adev->dev, "allocate CSA failed %d\n", r); goto init_failed;
}
}
r = amdgpu_seq64_init(adev); if (r) {
dev_err(adev->dev, "allocate seq64 failed %d\n",
r); goto init_failed;
}
}
}
if (amdgpu_sriov_vf(adev))
amdgpu_virt_init_data_exchange(adev);
r = amdgpu_ib_pool_init(adev); if (r) {
dev_err(adev->dev, "IB initialization failed (%d).\n", r);
amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_IB_INIT_FAIL, 0, r); goto init_failed;
}
r = amdgpu_ucode_create_bo(adev); /* create ucode bo when sw_init complete*/ if (r) goto init_failed;
r = amdgpu_device_ip_hw_init_phase1(adev); if (r) goto init_failed;
r = amdgpu_device_fw_loading(adev); if (r) goto init_failed;
r = amdgpu_device_ip_hw_init_phase2(adev); if (r) goto init_failed;
/** *IncaseofXGMIgrabextrareferenceforresetdomainforthisdevice
*/ if (adev->gmc.xgmi.num_physical_nodes > 1) { if (amdgpu_xgmi_add_device(adev) == 0) { if (!amdgpu_sriov_vf(adev)) { struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev);
if (WARN_ON(!hive)) {
r = -ENOENT; goto init_failed;
}
if (!hive->reset_domain ||
!amdgpu_reset_get_reset_domain(hive->reset_domain)) {
r = -ENOENT;
amdgpu_put_xgmi_hive(hive); goto init_failed;
}
/* Drop the early temporary reset domain we created for device */
amdgpu_reset_put_reset_domain(adev->reset_domain);
adev->reset_domain = hive->reset_domain;
amdgpu_put_xgmi_hive(hive);
}
}
}
r = amdgpu_device_init_schedulers(adev); if (r) goto init_failed;
if (adev->mman.buffer_funcs_ring->sched.ready)
amdgpu_ttm_set_buffer_funcs_status(adev, true);
/* Don't init kfd if whole hive need to be reset during init */ if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) {
kgd2kfd_init_zone_device(adev);
amdgpu_amdkfd_device_init(adev);
}
amdgpu_fru_get_product_info(adev);
if (!amdgpu_sriov_vf(adev) || amdgpu_sriov_ras_cper_en(adev))
r = amdgpu_cper_init(adev);
/* *ForallASICswithbaco/mode1reset,theVRAMis *alwaysassumedtobelost.
*/ switch (amdgpu_asic_reset_method(adev)) { case AMD_RESET_METHOD_LEGACY: case AMD_RESET_METHOD_LINK: case AMD_RESET_METHOD_BACO: case AMD_RESET_METHOD_MODE1: returntrue; default: returnfalse;
}
}
for (i = 0; i < mgpu_info.num_dgpu; i++) {
gpu_ins = &(mgpu_info.gpu_ins[i]);
adev = gpu_ins->adev; if (!(adev->flags & AMD_IS_APU || amdgpu_sriov_multi_vf_mode(adev)) &&
!gpu_ins->mgpu_fan_enabled) {
ret = amdgpu_dpm_enable_mgpu_fan_boost(adev); if (ret) break;
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.hw) continue; if (adev->ip_blocks[i].version->funcs->late_init) {
r = adev->ip_blocks[i].version->funcs->late_init(&adev->ip_blocks[i]); if (r) {
dev_err(adev->dev, "late_init of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name,
r); return r;
}
}
adev->ip_blocks[i].status.late_initialized = true;
}
r = amdgpu_ras_late_init(adev); if (r) {
dev_err(adev->dev, "amdgpu_ras_late_init failed %d", r); return r;
}
if (!amdgpu_reset_in_recovery(adev))
amdgpu_ras_set_error_query_ready(adev, true);
if (!ip_block->version->funcs->hw_fini) {
dev_err(adev->dev, "hw_fini of IP block <%s> not defined\n",
ip_block->version->funcs->name);
} else {
r = ip_block->version->funcs->hw_fini(ip_block); /* XXX handle errors */ if (r) {
dev_dbg(adev->dev, "hw_fini of IP block <%s> failed %d\n",
ip_block->version->funcs->name, r);
}
}
if (amdgpu_ip_version(adev, GC_HWIP, 0) > IP_VERSION(9, 0, 0)) return;
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.hw) continue; if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) {
amdgpu_ip_block_hw_fini(&adev->ip_blocks[i]); break;
}
}
}
staticint amdgpu_device_ip_fini_early(struct amdgpu_device *adev)
{ int i, r;
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].version->funcs->early_fini) continue;
r = adev->ip_blocks[i].version->funcs->early_fini(&adev->ip_blocks[i]); if (r) {
dev_dbg(adev->dev, "early_fini of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name, r);
}
}
/* Workaround for ASICs need to disable SMC first */
amdgpu_device_smu_fini_early(adev);
for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.hw) continue;
amdgpu_ip_block_hw_fini(&adev->ip_blocks[i]);
}
if (amdgpu_sriov_vf(adev)) { if (amdgpu_virt_release_full_gpu(adev, false))
dev_err(adev->dev, "failed to release exclusive mode on fini\n");
}
return0;
}
/** *amdgpu_device_ip_fini-runfiniforhardwareIPs * *@adev:amdgpu_devicepointer * *MainteardownpassforhardwareIPs.Thelistofallthehardware *IPsthatmakeuptheasiciswalkedandthehw_finiandsw_finicallbacks *arerun.hw_finitearsdownthehardwareassociatedwitheachIP *andsw_finitearsdownanysoftwarestateassociatedwitheachIP. *Returns0onsuccess,negativeerrorcodeonfailure.
*/ staticint amdgpu_device_ip_fini(struct amdgpu_device *adev)
{ int i, r;
amdgpu_cper_fini(adev);
if (amdgpu_sriov_vf(adev) && adev->virt.ras_init_done)
amdgpu_virt_release_ras_err_handler_data(adev);
if (adev->gmc.xgmi.num_physical_nodes > 1)
amdgpu_xgmi_remove_device(adev);
amdgpu_amdkfd_device_fini_sw(adev);
for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.sw) continue;
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_device_mem_scratch_fini(adev);
amdgpu_ib_pool_fini(adev);
amdgpu_seq64_fini(adev);
amdgpu_doorbell_fini(adev);
} if (adev->ip_blocks[i].version->funcs->sw_fini) {
r = adev->ip_blocks[i].version->funcs->sw_fini(&adev->ip_blocks[i]); /* XXX handle errors */ if (r) {
dev_dbg(adev->dev, "sw_fini of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name,
r);
}
}
adev->ip_blocks[i].status.sw = false;
adev->ip_blocks[i].status.valid = false;
}
for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.late_initialized) continue; if (adev->ip_blocks[i].version->funcs->late_fini)
adev->ip_blocks[i].version->funcs->late_fini(&adev->ip_blocks[i]);
adev->ip_blocks[i].status.late_initialized = false;
}
/* *PerPMFWteam'ssuggestion,driverneedstohandlegfxoff *anddfcstatefeaturesdisablementforgpureset(e.g.Mode1Reset) *scenario.Addthemissingdfcstatedisablementhere.
*/ if (amdgpu_dpm_set_df_cstate(adev, DF_CSTATE_DISALLOW))
dev_warn(adev->dev, "Failed to disallow df cstate");
for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.valid) continue;
/* displays are handled separately */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_DCE) continue;
/* XXX handle errors */
r = amdgpu_ip_block_suspend(&adev->ip_blocks[i]); if (r) return r;
}
return0;
}
/** *amdgpu_device_ip_suspend_phase2-runsuspendforhardwareIPs(phase2) * *@adev:amdgpu_devicepointer * *MainsuspendfunctionforhardwareIPs.Thelistofallthehardware *IPsthatmakeuptheasiciswalked,clockgatingisdisabledandthe *suspendcallbacksarerun.suspendputsthehardwareandsoftwarestate *ineachIPintoastatesuitableforsuspend. *Returns0onsuccess,negativeerrorcodeonfailure.
*/ staticint amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev)
{ int i, r;
if (adev->in_s0ix)
amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D3Entry);
for (i = adev->num_ip_blocks - 1; i >= 0; i--) { if (!adev->ip_blocks[i].status.valid) continue; /* displays are handled in phase1 */ if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) continue; /* PSP lost connection when err_event_athub occurs */ if (amdgpu_ras_intr_triggered() &&
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) {
adev->ip_blocks[i].status.hw = false; continue;
}
/* skip unnecessary suspend if we do not initialize them yet */ if (!amdgpu_ip_member_of_hwini(
adev, adev->ip_blocks[i].version->type)) continue;
/* Since we skip suspend for S0i3, we need to cancel the delayed *idleworkhereasthesuspendcallbacknevergetscalled.
*/ if (adev->in_s0ix &&
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX &&
amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 0, 0))
cancel_delayed_work_sync(&adev->gfx.idle_work); /* skip suspend of gfx/mes and psp for S0ix *gfxisingfxoffstate,soonresumeitwillexitgfxoffjust *likeatruntime.PSPisalsopartofthealwaysonhardware *sononeedtosuspendit.
*/ if (adev->in_s0ix &&
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_MES)) continue;
/* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */ if (adev->in_s0ix &&
(amdgpu_ip_version(adev, SDMA0_HWIP, 0) >=
IP_VERSION(5, 0, 0)) &&
(adev->ip_blocks[i].version->type ==
AMD_IP_BLOCK_TYPE_SDMA)) continue;
/* Once swPSP provides the IMU, RLC FW binaries to TOS during cold-boot. *TheseareinTMR,henceareexpectedtobereusedbyPSP-TOStoreload *fromthislocationandRLCAutoloadautomaticallyalsogetsloaded *fromherebasedonPMFW->PSPmessageduringre-initsequence. *Therefore,thepspsuspend&resumeshouldbeskippedtoavoiddestroy *theTMRandreloadFWsagainforIMUenabledAPUASICs.
*/ if (amdgpu_in_reset(adev) &&
(adev->flags & AMD_IS_APU) && adev->gfx.imu.funcs &&
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) continue;
/* handle putting the SMC in the appropriate state */ if (!amdgpu_sriov_vf(adev)) { if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) {
r = amdgpu_dpm_set_mp1_state(adev, adev->mp1_state); if (r) {
dev_err(adev->dev, "SMC failed to set mp1 state %d, %d\n",
adev->mp1_state, r); return r;
}
}
}
}
return0;
}
/** *amdgpu_device_ip_suspend-runsuspendforhardwareIPs * *@adev:amdgpu_devicepointer * *MainsuspendfunctionforhardwareIPs.Thelistofallthehardware *IPsthatmakeuptheasiciswalked,clockgatingisdisabledandthe *suspendcallbacksarerun.suspendputsthehardwareandsoftwarestate *ineachIPintoastatesuitableforsuspend. *Returns0onsuccess,negativeerrorcodeonfailure.
*/ int amdgpu_device_ip_suspend(struct amdgpu_device *adev)
{ int r;
if (amdgpu_sriov_vf(adev)) {
amdgpu_virt_fini_data_exchange(adev);
amdgpu_virt_request_full_gpu(adev, false);
}
amdgpu_ttm_set_buffer_funcs_status(adev, false);
r = amdgpu_device_ip_suspend_phase1(adev); if (r) return r;
r = amdgpu_device_ip_suspend_phase2(adev);
if (amdgpu_sriov_vf(adev))
amdgpu_virt_release_full_gpu(adev, false);
return r;
}
staticint amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev)
{ int i, r;
for (i = 0; i < ARRAY_SIZE(ip_order); i++) {
block = amdgpu_device_ip_get_ip_block(adev, ip_order[i]);
if (!block) continue;
if (block->status.valid && !block->status.hw) { if (block->version->type == AMD_IP_BLOCK_TYPE_SMC) {
r = amdgpu_ip_block_resume(block);
} else {
r = block->version->funcs->hw_init(block);
}
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw) continue; if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) {
r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); if (r) return r;
}
}
fail: if (adev->asic_reset_res)
dev_warn(adev->dev, "ASIC reset failed with error, %d for drm dev, %s",
adev->asic_reset_res, adev_to_drm(adev)->unique);
amdgpu_put_xgmi_hive(hive);
}
staticint amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
{ char *input = amdgpu_lockup_timeout; char *timeout_setting = NULL; int index = 0; long timeout; int ret = 0;
/* detect hw virtualization here */
amdgpu_virt_init(adev);
amdgpu_device_get_pcie_info(adev);
r = amdgpu_device_get_job_timeout_settings(adev); if (r) {
dev_err(adev->dev, "invalid lockup_timeout parameter syntax\n"); return r;
}
amdgpu_device_set_mcbp(adev);
/* *Bydefault,usedefaultmodewhereallblocksareexpectedtobe *initialized.Atpresenta'swinit'ofblocksisrequiredtobe *completedbeforetheneedforadifferentlevelisdetected.
*/
amdgpu_set_init_level(adev, AMDGPU_INIT_LEVEL_DEFAULT); /* early init functions */
r = amdgpu_device_ip_early_init(adev); if (r) return r;
/* *NoneedtoremoveconflictingFBsfornon-displayclassdevices. *Thispreventsthesysfbfrombeingfreedaccidently.
*/ if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA ||
(pdev->class >> 8) == PCI_CLASS_DISPLAY_OTHER) { /* Get rid of things like offb */
r = aperture_remove_conflicting_pci_devices(adev->pdev, amdgpu_kms_driver.name); if (r) return r;
}
/* Enable TMZ based on IP_VERSION */
amdgpu_gmc_tmz_set(adev);
if (amdgpu_sriov_vf(adev) &&
amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 3, 0)) /* VF MMIO access (except mailbox range) from CPU *willbeblockedduringsriovruntime
*/
adev->virt.caps |= AMDGPU_VF_MMIO_ACCESS_PROTECT;
amdgpu_gmc_noretry_set(adev); /* Need to get xgmi info early to decide the reset behavior*/ if (adev->gmc.xgmi.supported) {
r = adev->gfxhub.funcs->get_xgmi_info(adev); if (r) return r;
}
/* enable PCIE atomic ops */ if (amdgpu_sriov_vf(adev)) { if (adev->virt.fw_reserve.p_pf2vf)
adev->have_atomics_support = ((struct amd_sriov_msg_pf2vf_info *)
adev->virt.fw_reserve.p_pf2vf)->pcie_atomic_ops_support_flags ==
(PCI_EXP_DEVCAP2_ATOMIC_COMP32 | PCI_EXP_DEVCAP2_ATOMIC_COMP64); /* APUs w/ gfx9 onwards doesn't reply on PCIe atomics, rather it is a *internalpathnativelysupportatomics,sethave_atomics_supporttotrue.
*/
} elseif ((adev->flags & AMD_IS_APU) &&
(amdgpu_ip_version(adev, GC_HWIP, 0) >
IP_VERSION(9, 0, 0))) {
adev->have_atomics_support = true;
} else {
adev->have_atomics_support =
!pci_enable_atomic_ops_to_root(adev->pdev,
PCI_EXP_DEVCAP2_ATOMIC_COMP32 |
PCI_EXP_DEVCAP2_ATOMIC_COMP64);
}
if (!adev->have_atomics_support)
dev_info(adev->dev, "PCIE atomic ops is not supported\n");
/* doorbell bar mapping and doorbell index init*/
amdgpu_doorbell_init(adev);
if (amdgpu_emu_mode == 1) { /* post the asic on emulation mode */
emu_soc_asic_init(adev); goto fence_driver_init;
}
amdgpu_reset_init(adev);
/* detect if we are with an SRIOV vbios */ if (adev->bios)
amdgpu_device_detect_sriov_bios(adev);
/* check if we need to reset the asic *E.g.,driverwasnotcleanlyunloadedpreviously,etc.
*/ if (!amdgpu_sriov_vf(adev) && amdgpu_asic_need_reset_on_init(adev)) { if (adev->gmc.xgmi.num_physical_nodes) {
dev_info(adev->dev, "Pending hive reset.\n");
amdgpu_set_init_level(adev,
AMDGPU_INIT_LEVEL_MINIMAL_XGMI);
} elseif (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) &&
!amdgpu_device_has_display_hardware(adev)) {
r = psp_gpu_reset(adev);
} else {
tmp = amdgpu_reset_method; /* It should do a default reset when loading or reloading the driver, *regardlessofthemoduleparameterreset_method.
*/
amdgpu_reset_method = AMD_RESET_METHOD_NONE;
r = amdgpu_asic_reset(adev);
amdgpu_reset_method = tmp;
}
if (r) {
dev_err(adev->dev, "asic reset on init failed\n"); goto failed;
}
}
/* Post card if necessary */ if (amdgpu_device_need_post(adev)) { if (!adev->bios) {
dev_err(adev->dev, "no vBIOS found\n");
r = -EINVAL; goto failed;
}
dev_info(adev->dev, "GPU posting now...\n");
r = amdgpu_device_asic_init(adev); if (r) {
dev_err(adev->dev, "gpu post error!\n"); goto failed;
}
}
if (adev->bios) { if (adev->is_atom_fw) { /* Initialize clocks */
r = amdgpu_atomfirmware_get_clock_info(adev); if (r) {
dev_err(adev->dev, "amdgpu_atomfirmware_get_clock_info failed\n");
amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_ATOMBIOS_GET_CLOCK_FAIL, 0, 0); goto failed;
}
} else { /* Initialize clocks */
r = amdgpu_atombios_get_clock_info(adev); if (r) {
dev_err(adev->dev, "amdgpu_atombios_get_clock_info failed\n");
amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_ATOMBIOS_GET_CLOCK_FAIL, 0, 0); goto failed;
} /* init i2c buses */
amdgpu_i2c_init(adev);
}
}
/* init the mode config */
drm_mode_config_init(adev_to_drm(adev));
r = amdgpu_device_ip_init(adev); if (r) {
dev_err(adev->dev, "amdgpu_device_ip_init failed\n");
amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 0); goto release_ras_con;
}
amdgpu_fence_driver_hw_init(adev);
dev_info(adev->dev, "SE %d, SH per SE %d, CU per SH %d, active_cu_number %d\n",
adev->gfx.config.max_shader_engines,
adev->gfx.config.max_sh_per_se,
adev->gfx.config.max_cu_per_sh,
adev->gfx.cu_info.number);
adev->accel_working = true;
amdgpu_vm_check_compute_bug(adev);
/* Initialize the buffer migration limit. */ if (amdgpu_moverate >= 0)
max_MBps = amdgpu_moverate; else
max_MBps = 8; /* Allow 8 MB/s. */ /* Get a log2 for easy divisions. */
adev->mm_stats.log2_max_MBps = ilog2(max(1u, max_MBps));
/* enable clockgating, etc. after ib tests, etc. since some blocks require *explicitgatingratherthanhandlingitautomatically.
*/ if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) {
r = amdgpu_device_ip_late_init(adev); if (r) {
dev_err(adev->dev, "amdgpu_device_ip_late_init failed\n");
amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_LATE_INIT_FAIL, 0, r); goto release_ras_con;
} /* must succeed. */
amdgpu_ras_resume(adev);
queue_delayed_work(system_wq, &adev->delayed_init_work,
msecs_to_jiffies(AMDGPU_RESUME_MS));
}
if (amdgpu_sriov_vf(adev)) {
amdgpu_virt_release_full_gpu(adev, true);
flush_delayed_work(&adev->delayed_init_work);
}
/* *Placethosesysfsregisteringafter`late_init`.Assomeofthose *operationsperformedin`late_init`mightaffectthesysfs *interfacescreating.
*/
r = amdgpu_atombios_sysfs_init(adev); if (r)
drm_err(&adev->ddev, "registering atombios sysfs failed (%d).\n", r);
r = amdgpu_pm_sysfs_init(adev); if (r)
dev_err(adev->dev, "registering pm sysfs failed (%d).\n", r);
if (IS_ENABLED(CONFIG_PERF_EVENTS))
r = amdgpu_pmu_init(adev); if (r)
dev_err(adev->dev, "amdgpu_pmu_init failed\n");
/* Have stored pci confspace at hand for restore in sudden PCI error */ if (amdgpu_device_cache_pci_state(adev->pdev))
pci_restore_state(pdev);
/* if we have > 1 VGA cards, then disable the amdgpu VGA resources */ /* this will fail for cards that aren't VGA class devices, just *ignoreit
*/ if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
vga_client_register(adev->pdev, amdgpu_device_vga_set_decode);
px = amdgpu_device_supports_px(adev);
if (px || (!dev_is_removable(&adev->pdev->dev) &&
apple_gmux_detect(NULL, NULL)))
vga_switcheroo_register_client(adev->pdev,
&amdgpu_switcheroo_ops, px);
if (px)
vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain);
if (adev->init_lvl->level == AMDGPU_INIT_LEVEL_MINIMAL_XGMI)
amdgpu_xgmi_reset_on_init(adev);
amdgpu_device_check_iommu_direct_map(adev);
adev->pm_nb.notifier_call = amdgpu_device_pm_notifier;
r = register_pm_notifier(&adev->pm_nb); if (r) goto failed;
return0;
release_ras_con: if (amdgpu_sriov_vf(adev))
amdgpu_virt_release_full_gpu(adev, true);
/* failed in exclusive mode due to timeout */ if (amdgpu_sriov_vf(adev) &&
!amdgpu_sriov_runtime(adev) &&
amdgpu_virt_mmio_blocked(adev) &&
!amdgpu_virt_wait_reset(adev)) {
dev_err(adev->dev, "VF exclusive mode timeout\n"); /* Don't send request since VF is inactive. */
adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME;
adev->virt.ops = NULL;
r = -EAGAIN;
}
amdgpu_release_ras_context(adev);
if (adev->mman.initialized)
drain_workqueue(adev->mman.bdev.wq);
adev->shutdown = true;
unregister_pm_notifier(&adev->pm_nb);
/* make sure IB test finished before entering exclusive mode *toavoidpreemptiononIBtest
*/ if (amdgpu_sriov_vf(adev)) {
amdgpu_virt_request_full_gpu(adev, false);
amdgpu_virt_fini_data_exchange(adev);
}
/* disable all interrupts */
amdgpu_irq_disable_all(adev); if (adev->mode_info.mode_config_initialized) { if (!drm_drv_uses_atomic_modeset(adev_to_drm(adev)))
drm_helper_force_disable_all(adev_to_drm(adev)); else
drm_atomic_helper_shutdown(adev_to_drm(adev));
}
amdgpu_fence_driver_hw_fini(adev);
if (adev->pm.sysfs_initialized)
amdgpu_pm_sysfs_fini(adev); if (adev->ucode_sysfs_en)
amdgpu_ucode_sysfs_fini(adev);
amdgpu_device_attr_sysfs_fini(adev);
amdgpu_fru_sysfs_fini(adev);
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; if (!adev->ip_blocks[i].version->funcs->prepare_suspend) continue;
r = adev->ip_blocks[i].version->funcs->prepare_suspend(&adev->ip_blocks[i]); if (r) return r;
}
for (i = 0; i < adev->num_ip_blocks; i++) { if (!adev->ip_blocks[i].status.valid) continue; if (!adev->ip_blocks[i].version->funcs->complete) continue;
adev->ip_blocks[i].version->funcs->complete(&adev->ip_blocks[i]);
}
}
/** *amdgpu_device_suspend-initiatedevicesuspend * *@dev:drmdevpointer *@notify_clients:notifyin-kernelDRMclients * *Putsthehwinthesuspendstate(allasics). *Returns0forsuccessoranerroronfailure. *Calledatdriversuspend.
*/ int amdgpu_device_suspend(struct drm_device *dev, bool notify_clients)
{ struct amdgpu_device *adev = drm_to_adev(dev); int r = 0;
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return0;
adev->in_suspend = true;
if (amdgpu_sriov_vf(adev)) { if (!adev->in_runpm)
amdgpu_amdkfd_suspend_process(adev);
amdgpu_virt_fini_data_exchange(adev);
r = amdgpu_virt_request_full_gpu(adev, false); if (r) return r;
}
if (amdgpu_acpi_smart_shift_update(adev, AMDGPU_SS_DEV_D3))
dev_warn(adev->dev, "smart shift update failed\n");
if (notify_clients)
drm_client_dev_suspend(adev_to_drm(adev), false);
if (amdgpu_asic_need_full_reset(adev)) returntrue;
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-prepareforsoftreset * *@adev:amdgpu_devicepointer * *ThelistofallthehardwareIPsthatmakeuptheasiciswalkedandthe *pre_soft_resetcallbacksareruniftheblockishung.pre_soft_reset *handlesanyIPspecifichardwareorsoftwarestatechangesthatare *necessaryforasoftresettosucceed. *Returns0onsuccess,negativeerrorcodeonfailure.
*/ staticint 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;
}
}
if (amdgpu_asic_need_full_reset(adev)) returntrue;
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"); returntrue;
}
}
} returnfalse;
}
/** *amdgpu_device_ip_soft_reset-doasoftreset * *@adev:amdgpu_devicepointer * *ThelistofallthehardwareIPsthatmakeuptheasiciswalkedandthe *soft_resetcallbacksareruniftheblockishung.soft_resethandlesany *IPspecifichardwareorsoftwarestatechangesthatarenecessarytosoft *resettheIP. *Returns0onsuccess,negativeerrorcodeonfailure.
*/ staticint 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;
}
}
return0;
}
/** *amdgpu_device_ip_post_soft_reset-cleanupfromsoftreset * *@adev:amdgpu_devicepointer * *ThelistofallthehardwareIPsthatmakeuptheasiciswalkedandthe *post_soft_resetcallbacksareruniftheasicwashung.post_soft_reset *handlesanyIPspecifichardwareorsoftwarestatechangesthatare *necessaryaftertheIPhasbeensoftreset. *Returns0onsuccess,negativeerrorcodeonfailure.
*/ staticint 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;
}
if (test_bit(AMDGPU_HOST_FLR, &reset_context->flags)) { if (!amdgpu_ras_get_fed_status(adev))
amdgpu_virt_ready_to_reset(adev);
amdgpu_virt_wait_reset(adev);
clear_bit(AMDGPU_HOST_FLR, &reset_context->flags);
r = amdgpu_virt_request_full_gpu(adev, true);
} else {
r = amdgpu_virt_reset_gpu(adev);
} if (r) return r;
/* some sw clean up VF needs to do before recover */
amdgpu_virt_post_reset(adev);
/* Resume IP prior to SMC */
r = amdgpu_device_ip_reinit_early_sriov(adev); if (r) return r;
amdgpu_virt_init_data_exchange(adev);
r = amdgpu_device_fw_loading(adev); if (r) return r;
/* now we are okay to resume SMC/CP/SDMA */
r = amdgpu_device_ip_reinit_late_sriov(adev); if (r) return r;
hive = amdgpu_get_xgmi_hive(adev); /* Update PSP FW topology after reset */ if (hive && adev->gmc.xgmi.num_physical_nodes > 1)
r = amdgpu_xgmi_update_topology(hive, adev); if (hive)
amdgpu_put_xgmi_hive(hive); if (r) return r;
r = amdgpu_ib_ring_tests(adev); if (r) return r;
if (adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST)
amdgpu_inc_vram_lost(adev);
/* need to be called during full access so we can't do it later like *bare-metaldoes.
*/
amdgpu_amdkfd_post_reset(adev);
amdgpu_virt_release_full_gpu(adev, true);
/* Aldebaran and gfx_11_0_3 support ras in SRIOV, so need resume ras during reset */ if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 2) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0) ||
amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 0, 3))
amdgpu_ras_resume(adev);
/* Skip soft reset check in fatal error mode */ if (!amdgpu_ras_is_poison_mode_supported(adev)) returntrue;
if (amdgpu_sriov_vf(adev)) returntrue;
if (amdgpu_gpu_recovery == -1) { switch (adev->asic_type) { #ifdef CONFIG_DRM_AMDGPU_SI case CHIP_VERDE: case CHIP_TAHITI: case CHIP_PITCAIRN: case CHIP_OLAND: case CHIP_HAINAN: #endif #ifdef CONFIG_DRM_AMDGPU_CIK case CHIP_KAVERI: case CHIP_KABINI: case CHIP_MULLINS: #endif case CHIP_CARRIZO: case CHIP_STONEY: case CHIP_CYAN_SKILLFISH: goto disabled; default: break;
}
}
int amdgpu_device_mode1_reset(struct amdgpu_device *adev)
{
u32 i; int ret = 0;
if (adev->bios)
amdgpu_atombios_scratch_regs_engine_hung(adev, true);
dev_info(adev->dev, "GPU mode1 reset\n");
/* Cache the state before bus master disable. The saved config space *valuesareusedinothercaseslikerestoreaftermode-2reset.
*/
amdgpu_device_cache_pci_state(adev->pdev);
/* disable BM */
pci_clear_master(adev->pdev);
if (amdgpu_dpm_is_mode1_reset_supported(adev)) {
dev_info(adev->dev, "GPU smu mode1 reset\n");
ret = amdgpu_dpm_mode1_reset(adev);
} else {
dev_info(adev->dev, "GPU psp mode1 reset\n");
ret = psp_gpu_reset(adev);
}
if (ret) goto mode1_reset_failed;
amdgpu_device_load_pci_state(adev->pdev);
ret = amdgpu_psp_wait_for_bootloader(adev); if (ret) goto mode1_reset_failed;
/* wait for asic to come out of reset */ for (i = 0; i < adev->usec_timeout; i++) {
u32 memsize = adev->nbio.funcs->get_memsize(adev);
if (memsize != 0xffffffff) break;
udelay(1);
}
if (i >= adev->usec_timeout) {
ret = -ETIMEDOUT; goto mode1_reset_failed;
}
if (adev->bios)
amdgpu_atombios_scratch_regs_engine_hung(adev, false);
int amdgpu_device_link_reset(struct amdgpu_device *adev)
{ int ret = 0;
dev_info(adev->dev, "GPU link reset\n");
if (!adev->pcie_reset_ctx.occurs_dpc)
ret = amdgpu_dpm_link_reset(adev);
if (ret) goto link_reset_failed;
ret = amdgpu_psp_wait_for_bootloader(adev); if (ret) goto link_reset_failed;
return0;
link_reset_failed:
dev_err(adev->dev, "GPU link reset failed\n"); return ret;
}
int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, struct amdgpu_reset_context *reset_context)
{ int i, r = 0; struct amdgpu_job *job = NULL; struct amdgpu_device *tmp_adev = reset_context->reset_req_dev; bool need_full_reset =
test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
if (reset_context->reset_req_dev == adev)
job = reset_context->job;
if (amdgpu_sriov_vf(adev))
amdgpu_virt_pre_reset(adev);
amdgpu_fence_driver_isr_toggle(adev, true);
/* block all schedulers and reset given job's ring */ for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i];
if (!amdgpu_ring_sched_ready(ring)) continue;
/* Clear job fence from fence drv to avoid force_completion *leaveNULLandvmflushfenceinfencedrv
*/
amdgpu_fence_driver_clear_job_fences(ring);
/* after all hw jobs are reset, hw fence is meaningless, so force_completion */
amdgpu_fence_driver_force_completion(ring);
}
amdgpu_fence_driver_isr_toggle(adev, false);
if (job && job->vm)
drm_sched_increase_karma(&job->base);
r = amdgpu_reset_prepare_hwcontext(adev, reset_context); /* If reset handler not implemented, continue; otherwise return */ if (r == -EOPNOTSUPP)
r = 0; else return r;
/* 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;
}
}
if (!test_bit(AMDGPU_SKIP_COREDUMP, &reset_context->flags)) {
dev_info(tmp_adev->dev, "Dumping IP State\n"); /* Trigger ip dump before we reset the asic */ for (i = 0; i < tmp_adev->num_ip_blocks; i++) if (tmp_adev->ip_blocks[i].version->funcs->dump_ip_state)
tmp_adev->ip_blocks[i].version->funcs
->dump_ip_state((void *)&tmp_adev->ip_blocks[i]);
dev_info(tmp_adev->dev, "Dumping IP State Completed\n");
}
if (need_full_reset)
r = amdgpu_device_ip_suspend(adev); if (need_full_reset)
set_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags); else
clear_bit(AMDGPU_NEED_FULL_RESET,
&reset_context->flags);
}
return r;
}
int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context)
{ struct list_head *device_list_handle; bool full_reset, vram_lost = false; struct amdgpu_device *tmp_adev; int r, init_level;
/* *TheGPUentersbadstateoncefaultypages *byECChasreachedthethreshold,andras *recoveryisschedulednext.Soaddonecheck *heretobreakrecoveryifitindeedexceeds *badpagethreshold,andreminduserto *retirethisGPUorsettingonebigger *bad_page_thresholdvaluetofixthisonce *probingdriveragain.
*/ if (!amdgpu_ras_is_rma(tmp_adev)) { /* must succeed. */
amdgpu_ras_resume(tmp_adev);
} else {
r = -EINVAL; goto out;
}
/* Update PSP FW topology after reset */ if (reset_context->hive &&
tmp_adev->gmc.xgmi.num_physical_nodes > 1)
r = amdgpu_xgmi_update_topology(
reset_context->hive, tmp_adev);
}
}
out: if (!r) { /* IP init is complete now, set level as default */
amdgpu_set_init_level(tmp_adev,
AMDGPU_INIT_LEVEL_DEFAULT);
amdgpu_irq_gpu_reset_resume_helper(tmp_adev);
r = amdgpu_ib_ring_tests(tmp_adev); if (r) {
dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r);
r = -EAGAIN; goto end;
}
}
if (r)
tmp_adev->asic_reset_res = r;
}
end: return r;
}
int amdgpu_do_asic_reset(struct list_head *device_list_handle, struct amdgpu_reset_context *reset_context)
{ struct amdgpu_device *tmp_adev = NULL; bool need_full_reset, skip_hw_reset; int r = 0;
reset_context->reset_device_list = device_list_handle;
r = amdgpu_reset_perform_reset(tmp_adev, reset_context); /* If reset handler not implemented, continue; otherwise return */ if (r == -EOPNOTSUPP)
r = 0; else return r;
/* Reset handler not implemented, use the default method */
need_full_reset =
test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
skip_hw_reset = test_bit(AMDGPU_SKIP_HW_RESET, &reset_context->flags);
/* *ASICresethastobedoneonallXGMIhivenodesASAP *toallowproperlinksnegotiationinFW(within1sec)
*/ if (!skip_hw_reset && need_full_reset) {
list_for_each_entry(tmp_adev, device_list_handle, reset_list) { /* For XGMI run all resets in parallel to speed up the process */ if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) { if (!queue_work(system_unbound_wq,
&tmp_adev->xgmi_reset_work))
r = -EALREADY;
} else
r = amdgpu_asic_reset(tmp_adev);
if (r) {
dev_err(tmp_adev->dev, "ASIC reset failed with error, %d for drm dev, %s",
r, adev_to_drm(tmp_adev)->unique); goto out;
}
}
/* For XGMI wait for all resets to complete before proceed */ if (!r) {
list_for_each_entry(tmp_adev, device_list_handle,
reset_list) { if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
flush_work(&tmp_adev->xgmi_reset_work);
r = tmp_adev->asic_reset_res; if (r) break;
}
}
}
}
/* disable ras on ALL IPs */ if (!need_emergency_restart &&
(!adev->pcie_reset_ctx.occurs_dpc) &&
amdgpu_device_ip_need_full_reset(tmp_adev))
amdgpu_ras_suspend(tmp_adev);
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = tmp_adev->rings[i];
if (need_emergency_restart)
amdgpu_job_stop_all_jobs_on_sched(&ring->sched);
}
atomic_inc(&tmp_adev->gpu_reset_counter);
}
}
staticint amdgpu_device_asic_reset(struct amdgpu_device *adev, struct list_head *device_list, struct amdgpu_reset_context *reset_context)
{ struct amdgpu_device *tmp_adev = NULL; int retry_limit = AMDGPU_MAX_RETRY_LIMIT; int r = 0;
retry: /* Rest of adevs pre asic reset from XGMI hive. */
list_for_each_entry(tmp_adev, device_list, reset_list) { if (adev->pcie_reset_ctx.occurs_dpc)
tmp_adev->no_hw_access = true;
r = amdgpu_device_pre_asic_reset(tmp_adev, reset_context); if (adev->pcie_reset_ctx.occurs_dpc)
tmp_adev->no_hw_access = false; /*TODO Should we stop ?*/ if (r) {
dev_err(tmp_adev->dev, "GPU pre asic reset failed with err, %d for drm dev, %s ",
r, adev_to_drm(tmp_adev)->unique);
tmp_adev->asic_reset_res = r;
}
}
/* Actual ASIC resets if needed.*/ /* Host driver will handle XGMI hive reset for SRIOV */ if (amdgpu_sriov_vf(adev)) {
/* Bail out of reset early */ if (amdgpu_ras_is_rma(adev)) return -ENODEV;
if (amdgpu_ras_get_fed_status(adev) || amdgpu_virt_rcvd_ras_interrupt(adev)) {
dev_dbg(adev->dev, "Detected RAS error, wait for FLR completion\n");
amdgpu_ras_set_fed(adev, true);
set_bit(AMDGPU_HOST_FLR, &reset_context->flags);
}
r = amdgpu_device_reset_sriov(adev, reset_context); if (AMDGPU_RETRY_SRIOV_RESET(r) && (retry_limit--) > 0) {
amdgpu_virt_release_full_gpu(adev, true); goto retry;
} if (r)
adev->asic_reset_res = r;
} else {
r = amdgpu_do_asic_reset(device_list, reset_context); if (r && r == -EAGAIN) goto retry;
}
list_for_each_entry(tmp_adev, device_list, reset_list) { /* unlock kfd: SRIOV would do it separately */ if (!need_emergency_restart && !amdgpu_sriov_vf(tmp_adev))
amdgpu_amdkfd_post_reset(tmp_adev);
/* kfd_post_reset will do nothing if kfd device is not initialized, *needtobringupkfdhereifit'snotbeinitializedbefore
*/ if (!adev->kfd.init_complete)
amdgpu_amdkfd_device_init(adev);
if (tmp_adev->pcie_reset_ctx.audio_suspended)
amdgpu_device_resume_display_audio(tmp_adev);
if (amdgpu_device_pcie_dynamic_switching_supported(adev)) { while ((parent = pci_upstream_bridge(parent))) { /* skip upstream/downstream switches internal to dGPU*/ if (parent->vendor == PCI_VENDOR_ID_ATI) continue;
*speed = pcie_get_speed_cap(parent);
*width = pcie_get_width_cap(parent); break;
}
} else { /* use the current speeds rather than max if switching is not supported */
pcie_bandwidth_available(adev->pdev, NULL, speed, width);
}
}
r = pci_save_state(pdev); if (!r) {
kfree(adev->pci_state);
adev->pci_state = pci_store_saved_state(pdev);
if (!adev->pci_state) {
dev_err(adev->dev, "Failed to store PCI saved state"); returnfalse;
}
} else {
dev_warn(adev->dev, "Failed to save PCI state, err:%d\n", r); returnfalse;
}
bool amdgpu_device_has_display_hardware(struct amdgpu_device *adev)
{ switch (adev->asic_type) { #ifdef CONFIG_DRM_AMDGPU_SI case CHIP_HAINAN: #endif case CHIP_TOPAZ: /* chips with no display hardware */ returnfalse; #ifdef CONFIG_DRM_AMDGPU_SI case CHIP_TAHITI: case CHIP_PITCAIRN: case CHIP_VERDE: case CHIP_OLAND: #endif #ifdef CONFIG_DRM_AMDGPU_CIK case CHIP_BONAIRE: case CHIP_HAWAII: case CHIP_KAVERI: case CHIP_KABINI: case CHIP_MULLINS: #endif case CHIP_TONGA: case CHIP_FIJI: case CHIP_POLARIS10: case CHIP_POLARIS11: case CHIP_POLARIS12: case CHIP_VEGAM: case CHIP_CARRIZO: case CHIP_STONEY: /* chips with display hardware */ returntrue; default: /* IP discovery */ if (!amdgpu_ip_version(adev, DCE_HWIP, 0) ||
(adev->harvest_ip_mask & AMD_HARVEST_IP_DMU_MASK)) returnfalse; returntrue;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.