/* * Copyright 2008 Advanced Micro Devices, Inc. * Copyright 2008 Red Hat Inc. * Copyright 2009 Jerome Glisse. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Authors: Dave Airlie * Alex Deucher * Jerome Glisse
*/
#define AMDGPU_IP_BLK_MASK_ALL GENMASK(AMD_IP_BLOCK_TYPE_NUM - 1, 0) /* * Default init level where all blocks are expected to be initialized. This is * the level of initialization expected by default and also after a full reset * of the device.
*/ struct amdgpu_init_level amdgpu_init_default = {
.level = AMDGPU_INIT_LEVEL_DEFAULT,
.hwini_ip_block_mask = AMDGPU_IP_BLK_MASK_ALL,
};
/* * Minimal blocks needed to be initialized before a XGMI hive can be reset. This * is used for cases like reset on initialization where the entire hive needs to * be reset before first use.
*/ struct amdgpu_init_level amdgpu_init_minimal_xgmi = {
.level = AMDGPU_INIT_LEVEL_MINIMAL_XGMI,
.hwini_ip_block_mask =
BIT(AMD_IP_BLOCK_TYPE_GMC) | BIT(AMD_IP_BLOCK_TYPE_SMC) |
BIT(AMD_IP_BLOCK_TYPE_COMMON) | BIT(AMD_IP_BLOCK_TYPE_IH) |
BIT(AMD_IP_BLOCK_TYPE_PSP)
};
/** * DOC: pcie_replay_count * * The amdgpu driver provides a sysfs API for reporting the total number * of PCIe replays (NAKs). * The file pcie_replay_count is used for this and returns the total * number of replays as a sum of the NAKs generated and NAKs received.
*/
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; return 0;
}
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;
}
}
ip_block->status.hw = true; return 0;
}
/** * DOC: board_info * * The amdgpu driver provides a sysfs API for giving board related information. * It provides the form factor information in the format * * type : form factor * * Possible form factor values * * - "cem" - PCIE CEM card * - "oam" - Open Compute Accelerator Module * - "unknown" - Not known *
*/
/** * amdgpu_device_supports_px - Is the device a dGPU with ATPX power control * * @adev: amdgpu device pointer * * Returns true if the device is a dGPU with ATPX power control, * otherwise return false.
*/ bool amdgpu_device_supports_px(struct amdgpu_device *adev)
{ if ((adev->flags & AMD_IS_PX) && !amdgpu_is_atpx_hybrid()) returntrue; returnfalse;
}
/** * amdgpu_device_supports_boco - Is the device a dGPU with ACPI power resources * * @adev: amdgpu device pointer * * Returns true if the device is a dGPU with ACPI power control, * otherwise return false.
*/ bool amdgpu_device_supports_boco(struct amdgpu_device *adev)
{ if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE)) returnfalse;
/** * amdgpu_device_supports_baco - Does the device support BACO * * @adev: amdgpu device pointer * * Return: * 1 if the device supports BACO; * 3 if the device supports MACO (only works if BACO is supported) * otherwise return 0.
*/ int amdgpu_device_supports_baco(struct amdgpu_device *adev)
{ return amdgpu_asic_supports_baco(adev);
}
void amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device *adev)
{ int bamaco_support;
switch (amdgpu_runtime_pm) { case 2: 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; case 1: 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; case 0:
dev_info(adev->dev, "runtime pm is manually disabled\n"); break; default: break;
}
no_runtime_pm: if (adev->pm.rpm_mode == AMDGPU_RUNPM_NONE)
dev_info(adev->dev, "Runtime PM not available\n");
} /** * amdgpu_device_supports_smart_shift - Is the device dGPU with * smart shift support * * @adev: amdgpu device pointer * * Returns true if the device is a dGPU with Smart Shift support, * otherwise returns false.
*/ bool amdgpu_device_supports_smart_shift(struct amdgpu_device *adev)
{ return (amdgpu_device_supports_boco(adev) &&
amdgpu_acpi_is_power_shift_control_supported());
}
/* * VRAM access helper functions
*/
/** * amdgpu_device_mm_access - access vram by MM_INDEX/MM_DATA * * @adev: amdgpu_device pointer * @pos: offset of the buffer in vram * @buf: virtual address of the buffer in system memory * @size: read/write size, sizeof(@buf) must > @size * @write: true - write to vram, otherwise - read from vram
*/ void amdgpu_device_mm_access(struct amdgpu_device *adev, loff_t pos, void *buf, size_t size, bool write)
{ unsignedlong flags;
uint32_t hi = ~0, tmp = 0;
uint32_t *data = buf;
uint64_t last; int idx;
if (!drm_dev_enter(adev_to_drm(adev), &idx)) return;
/** * amdgpu_device_aper_access - access vram by vram aperture * * @adev: amdgpu_device pointer * @pos: offset of the buffer in vram * @buf: virtual address of the buffer in system memory * @size: read/write size, sizeof(@buf) must > @size * @write: true - write to vram, otherwise - read from vram * * The return value means how many bytes have been transferred.
*/
size_t amdgpu_device_aper_access(struct amdgpu_device *adev, loff_t pos, void *buf, size_t size, bool write)
{ #ifdef CONFIG_64BIT void __iomem *addr;
size_t count = 0;
uint64_t last;
if (!adev->mman.aper_base_kaddr) return 0;
last = min(pos + size, adev->gmc.visible_vram_size); if (last > pos) {
addr = adev->mman.aper_base_kaddr + pos;
count = last - pos;
if (write) {
memcpy_toio(addr, buf, count); /* Make sure HDP write cache flush happens without any reordering * after the system memory contents are sent over PCIe device
*/
mb();
amdgpu_device_flush_hdp(adev, NULL);
} else {
amdgpu_device_invalidate_hdp(adev, NULL); /* Make sure HDP read cache is invalidated before issuing a read * to the PCIe device
*/
mb();
memcpy_fromio(buf, addr, count);
}
}
return count; #else return 0; #endif
}
/** * amdgpu_device_vram_access - read/write a buffer in vram * * @adev: amdgpu_device pointer * @pos: offset of the buffer in vram * @buf: virtual address of the buffer in system memory * @size: read/write size, sizeof(@buf) must > @size * @write: true - write to vram, otherwise - read from vram
*/ void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos, void *buf, size_t size, bool write)
{
size_t count;
/* 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);
}
}
/* * register access helper functions.
*/
/* 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;
#ifdef CONFIG_LOCKDEP /* * This is a bit complicated to understand, so worth a comment. What we assert * here is that the GPU reset is not running on another thread in parallel. * * For this we trylock the read side of the reset semaphore, if that succeeds * we know that the reset is not running in parallel. * * If the trylock fails we assert that we are either already holding the read * side of the lock or are the reset thread itself and hold the write side of * the lock.
*/ if (in_task()) { if (down_read_trylock(&adev->reset_domain->sem))
up_read(&adev->reset_domain->sem); else
lockdep_assert_held(&adev->reset_domain->sem);
} #endif returnfalse;
}
/** * amdgpu_device_rreg - read a memory mapped IO or indirect register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @acc_flags: access flags which require special behavior * * Returns the 32 bit value from the offset specified.
*/
uint32_t amdgpu_device_rreg(struct amdgpu_device *adev,
uint32_t reg, uint32_t acc_flags)
{
uint32_t ret;
if (amdgpu_device_skip_hw_access(adev)) return 0;
if ((reg * 4) < adev->rmmio_size) { if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
amdgpu_sriov_runtime(adev) &&
down_read_trylock(&adev->reset_domain->sem)) {
ret = amdgpu_kiq_rreg(adev, reg, 0);
up_read(&adev->reset_domain->sem);
} else {
ret = readl(((void __iomem *)adev->rmmio) + (reg * 4));
}
} else {
ret = adev->pcie_rreg(adev, reg * 4);
}
/** * amdgpu_device_wreg - write to a memory mapped IO or indirect register * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @v: 32 bit value to write to the register * @acc_flags: access flags which require special behavior * * Writes the value specified to the offset specified.
*/ void amdgpu_device_wreg(struct amdgpu_device *adev,
uint32_t reg, uint32_t v,
uint32_t acc_flags)
{ if (amdgpu_device_skip_hw_access(adev)) return;
/** * amdgpu_mm_wreg_mmio_rlc - write register either with direct/indirect mmio or with RLC path if in range * * @adev: amdgpu_device pointer * @reg: mmio/rlc register * @v: value to write * @xcc_id: xcc accelerated compute core id * * this function is invoked only for the debugfs register access
*/ void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
uint32_t reg, uint32_t v,
uint32_t xcc_id)
{ if (amdgpu_device_skip_hw_access(adev)) return;
/** * amdgpu_device_xcc_wreg - write to a memory mapped IO or indirect register with specific XCC * * @adev: amdgpu_device pointer * @reg: dword aligned register offset * @v: 32 bit value to write to the register * @acc_flags: access flags which require special behavior * @xcc_id: xcc accelerated compute core id * * Writes the value specified to the offset specified.
*/ void amdgpu_device_xcc_wreg(struct amdgpu_device *adev,
uint32_t reg, uint32_t v,
uint32_t acc_flags, uint32_t xcc_id)
{
uint32_t rlcg_flag;
/** * amdgpu_invalid_rreg64 - dummy 64 bit reg read function * * @adev: amdgpu_device pointer * @reg: offset of register * * Dummy register read function. Used for register blocks * that certain asics don't have (all asics). * Returns the value in the register.
*/ static uint64_t amdgpu_invalid_rreg64(struct amdgpu_device *adev, uint32_t reg)
{
dev_err(adev->dev, "Invalid callback to read 64 bit register 0x%04X\n",
reg);
BUG(); return 0;
}
/** * amdgpu_invalid_wreg64 - dummy reg write function * * @adev: amdgpu_device pointer * @reg: offset of register * @v: value to write to the register * * Dummy register read function. Used for register blocks * that certain asics don't have (all asics).
*/ staticvoid amdgpu_invalid_wreg64(struct amdgpu_device *adev, uint32_t reg, uint64_t v)
{
dev_err(adev->dev, "Invalid callback to write 64 bit register 0x%04X with 0x%08llX\n",
reg, v);
BUG();
}
staticvoid amdgpu_invalid_wreg64_ext(struct amdgpu_device *adev, uint64_t reg, uint64_t v)
{
dev_err(adev->dev, "Invalid callback to write 64 bit register 0x%llX with 0x%08llX\n",
reg, v);
BUG();
}
/** * amdgpu_block_invalid_rreg - dummy reg read function * * @adev: amdgpu_device pointer * @block: offset of instance * @reg: offset of register * * Dummy register read function. Used for register blocks * that certain asics don't have (all asics). * Returns the value in the register.
*/ static uint32_t amdgpu_block_invalid_rreg(struct amdgpu_device *adev,
uint32_t block, uint32_t reg)
{
dev_err(adev->dev, "Invalid callback to read register 0x%04X in block 0x%04X\n",
reg, block);
BUG(); return 0;
}
/** * amdgpu_block_invalid_wreg - dummy reg write function * * @adev: amdgpu_device pointer * @block: offset of instance * @reg: offset of register * @v: value to write to the register * * Dummy register read function. Used for register blocks * that certain asics don't have (all asics).
*/ staticvoid amdgpu_block_invalid_wreg(struct amdgpu_device *adev,
uint32_t block,
uint32_t reg, uint32_t v)
{
dev_err(adev->dev, "Invalid block callback to write register 0x%04X in block 0x%04X with 0x%08X\n",
reg, block, v);
BUG();
}
if (hweight32(adev->aid_mask) && amdgpu_passthrough(adev)) return AMDGPU_VBIOS_OPTIONAL;
return 0;
}
/** * amdgpu_device_asic_init - Wrapper for atom asic_init * * @adev: amdgpu_device pointer * * Does any asic specific work and then calls atom asic init.
*/ staticint amdgpu_device_asic_init(struct amdgpu_device *adev)
{
uint32_t flags; bool optional; int ret;
/** * amdgpu_device_mem_scratch_init - allocate the VRAM scratch page * * @adev: amdgpu_device pointer * * Allocates a scratch page of VRAM for use by various things in the * driver.
*/ staticint amdgpu_device_mem_scratch_init(struct amdgpu_device *adev)
{ return amdgpu_bo_create_kernel(adev, AMDGPU_GPU_PAGE_SIZE, PAGE_SIZE,
AMDGPU_GEM_DOMAIN_VRAM |
AMDGPU_GEM_DOMAIN_GTT,
&adev->mem_scratch.robj,
&adev->mem_scratch.gpu_addr,
(void **)&adev->mem_scratch.ptr);
}
/** * amdgpu_device_program_register_sequence - program an array of registers. * * @adev: amdgpu_device pointer * @registers: pointer to the register array * @array_size: size of the register array * * Programs an array or registers with and or masks. * This is a helper for setting golden registers.
*/ void amdgpu_device_program_register_sequence(struct amdgpu_device *adev, const u32 *registers, const u32 array_size)
{
u32 tmp, reg, and_mask, or_mask; int i;
if (array_size % 3) return;
for (i = 0; i < array_size; i += 3) {
reg = registers[i + 0];
and_mask = registers[i + 1];
or_mask = registers[i + 2];
/** * amdgpu_device_pci_config_reset - reset the GPU * * @adev: amdgpu_device pointer * * Resets the GPU using the pci config reset sequence. * Only applicable to asics prior to vega10.
*/ void amdgpu_device_pci_config_reset(struct amdgpu_device *adev)
{
pci_write_config_dword(adev->pdev, 0x7c, AMDGPU_ASIC_RESET_DATA);
}
/** * amdgpu_device_pci_reset - reset the GPU using generic PCI means * * @adev: amdgpu_device pointer * * Resets the GPU using generic pci reset interfaces (FLR, SBR, etc.).
*/ 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.
*/ staticvoid 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.
*/ staticint amdgpu_device_wb_init(struct amdgpu_device *adev)
{ int r;
/** * 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)
{ unsignedlong flags, offset;
/** * amdgpu_device_resize_fb_bar - try to resize FB BAR * * @adev: amdgpu_device pointer * * Try to resize FB BAR to make all VRAM CPU accessible. We try very hard not * to fail, but if any of the BARs is not accessible after the size we abort * driver loading by returning -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)) return 0;
/* Bypass for VF */ if (amdgpu_sriov_vf(adev)) return 0;
if (!amdgpu_rebar) return 0;
/* 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) return 0;
/* 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)) return 0;
/* 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) return 0;
/* 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 * using the device.
*/
r = amdgpu_doorbell_init(adev); if (r || (pci_resource_flags(adev->pdev, 0) & IORESOURCE_UNSET)) return -ENODEV;
/* * GPU helpers function.
*/ /** * amdgpu_device_need_post - check if the hw need post or not * * @adev: amdgpu_device pointer * * Check if the asic has been initialized (all asics) at driver startup * or post is needed if hw reset is performed. * Returns true if need or false if not.
*/ bool amdgpu_device_need_post(struct amdgpu_device *adev)
{
uint32_t reg, flags;
if (amdgpu_sriov_vf(adev)) returnfalse;
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 * some old smc fw still need driver do vPost otherwise gpu hang, while * those smc fw version above 22.15 doesn't have this flaw, so we force * vpost executed for smc version below 22.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;
/* Don't post if we need to reset whole hive on init */ if (adev->init_lvl->level == AMDGPU_INIT_LEVEL_MINIMAL_XGMI) returnfalse;
if (adev->has_hw_reset) {
adev->has_hw_reset = false; returntrue;
}
/* bios scratch used on CIK+ */ if (adev->asic_type >= CHIP_BONAIRE) return amdgpu_atombios_scratch_need_asic_init(adev);
/* check MEM_SIZE for older asics */
reg = amdgpu_asic_get_config_memsize(adev);
if ((reg != 0) && (reg != 0xffffffff)) returnfalse;
returntrue;
}
/* * Check whether seamless boot is supported. * * So far we only support seamless boot on DCE 3.0 or later. * If users report that it works on older ASICS as well, we may * loosen this.
*/ bool amdgpu_device_seamless_boot_supported(struct amdgpu_device *adev)
{ switch (amdgpu_seamless) { case -1: break; case 1: returntrue; case 0: returnfalse; default:
dev_err(adev->dev, "Invalid value for amdgpu.seamless: %d\n",
amdgpu_seamless); returnfalse;
}
if (!(adev->flags & AMD_IS_APU)) returnfalse;
if (adev->mman.keep_stolen_vga_memory) returnfalse;
/* eGPU change speeds based on USB4 fabric conditions */ if (dev_is_removable(adev->dev)) returntrue;
if (c->x86_vendor == X86_VENDOR_INTEL) returnfalse; #endif returntrue;
}
staticbool amdgpu_device_aspm_support_quirk(struct amdgpu_device *adev)
{ /* Enabling ASPM causes randoms hangs on Tahiti and Oland on Zen4. * It's unclear if this is a platform-specific or GPU-specific issue. * Disable ASPM on SI for the time being.
*/ if (adev->family == AMDGPU_FAMILY_SI) returntrue;
if (c->x86 == 6 &&
adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN5) { switch (c->x86_model) { case VFM_MODEL(INTEL_ALDERLAKE): case VFM_MODEL(INTEL_ALDERLAKE_L): case VFM_MODEL(INTEL_RAPTORLAKE): case VFM_MODEL(INTEL_RAPTORLAKE_P): case VFM_MODEL(INTEL_RAPTORLAKE_S): returntrue; default: returnfalse;
}
} else { returnfalse;
} #else returnfalse; #endif
}
/** * amdgpu_device_should_use_aspm - check if the device should program ASPM * * @adev: amdgpu_device pointer * * Confirm whether the module parameter and pcie bridge agree that ASPM should * be set for this device. * * Returns true if it should be used or false if not.
*/ bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
{ switch (amdgpu_aspm) { case -1: break; case 0: returnfalse; case 1: returntrue; default: returnfalse;
} if (adev->flags & AMD_IS_APU) returnfalse; if (amdgpu_device_aspm_support_quirk(adev)) returnfalse; return pcie_aspm_enabled(adev->pdev);
}
/* if we get transitioned to only one device, take VGA back */ /** * amdgpu_device_vga_set_decode - enable/disable vga decode * * @pdev: PCI device pointer * @state: enable/disable vga decode * * Enable/disable vga decode (all asics). * Returns VGA resource flags.
*/ 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 - validate the vm block size * * @adev: amdgpu_device pointer * * Validates the vm block size specified via module parameter. * The vm block size defines number of bits in page table versus page directory, * a page is 4KB so we have 12 bits offset, minimum 9 bits in the * page table and the remaining bits are in the page directory.
*/ staticvoid amdgpu_device_check_block_size(struct amdgpu_device *adev)
{ /* defines number of bits in page table versus page directory, * a page is 4KB so we have 12 bits offset, minimum 9 bits in the * page table and the remaining bits are in the page directory
*/ 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 - validate the vm size * * @adev: amdgpu_device pointer * * Validates the vm size in GB specified via module parameter. * The VM size is the size of the GPU virtual memory space in GB.
*/ 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;
}
}
switch (adev->asic_type) { case CHIP_RAVEN: if (adev->pdev->device == 0x15dd)
adev->apu_flags |= AMD_APU_IS_RAVEN; if (adev->pdev->device == 0x15d8)
adev->apu_flags |= AMD_APU_IS_PICASSO; break; case CHIP_RENOIR: if ((adev->pdev->device == 0x1636) ||
(adev->pdev->device == 0x164c))
adev->apu_flags |= AMD_APU_IS_RENOIR; else
adev->apu_flags |= AMD_APU_IS_GREEN_SARDINE; break; case CHIP_VANGOGH:
adev->apu_flags |= AMD_APU_IS_VANGOGH; break; case CHIP_YELLOW_CARP: break; case CHIP_CYAN_SKILLFISH: if ((adev->pdev->device == 0x13FE) ||
(adev->pdev->device == 0x143F))
adev->apu_flags |= AMD_APU_IS_CYAN_SKILLFISH2; break; default: break;
}
return 0;
}
/** * amdgpu_device_check_arguments - validate module params * * @adev: amdgpu_device pointer * * Validates certain module parameters and updates * the associated values used by the driver (all asics).
*/ staticint amdgpu_device_check_arguments(struct amdgpu_device *adev)
{ int i;
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;
}
for (i = 0; i < MAX_XCP; i++) { switch (amdgpu_enforce_isolation) { case -1: case 0: default: /* disable */
adev->enforce_isolation[i] = AMDGPU_ENFORCE_ISOLATION_DISABLE; break; case 1: /* enable */
adev->enforce_isolation[i] =
AMDGPU_ENFORCE_ISOLATION_ENABLE; break; case 2: /* enable legacy mode */
adev->enforce_isolation[i] =
AMDGPU_ENFORCE_ISOLATION_ENABLE_LEGACY; break; case 3: /* enable only process isolation without submitting cleaner shader */
adev->enforce_isolation[i] =
AMDGPU_ENFORCE_ISOLATION_NO_CLEANER_SHADER; break;
}
}
return 0;
}
/** * amdgpu_switcheroo_set_state - set switcheroo state * * @pdev: pci dev pointer * @state: vga_switcheroo state * * Callback for the switcheroo driver. Suspends or resumes * the asics before or after it is powered up using ACPI methods.
*/ staticvoid amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
{ struct drm_device *dev = pci_get_drvdata(pdev); int r;
if (amdgpu_device_supports_px(drm_to_adev(dev)) &&
state == VGA_SWITCHEROO_OFF) return;
if (state == VGA_SWITCHEROO_ON) {
pr_info("switched on\n"); /* don't suspend or resume card normally */
dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
pci_set_power_state(pdev, PCI_D0);
amdgpu_device_load_pci_state(pdev);
r = pci_enable_device(pdev); if (r)
dev_warn(&pdev->dev, "pci_enable_device failed (%d)\n",
r);
amdgpu_device_resume(dev, true);
/** * amdgpu_switcheroo_can_switch - see if switcheroo state can change * * @pdev: pci dev pointer * * Callback for the switcheroo driver. Check of the switcheroo * state can be changed. * Returns true if the state can be changed, false if not.
*/ staticbool amdgpu_switcheroo_can_switch(struct pci_dev *pdev)
{ struct drm_device *dev = pci_get_drvdata(pdev);
/* * FIXME: open_count is protected by drm_global_mutex but that would lead to * locking inversion with the driver load path. And the access here is * completely racy anyway. So don't bother with locking for now.
*/ return atomic_read(&dev->open_count) == 0;
}
/** * amdgpu_device_ip_set_clockgating_state - set the CG state * * @dev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * @state: clockgating state (gate or ungate) * * Sets the requested clockgating state for all instances of * the hardware IP specified. * Returns the error code from the last instance.
*/ 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 - set the PG state * * @dev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * @state: powergating state (gate or ungate) * * Sets the requested powergating state for all instances of * the hardware IP specified. * Returns the error code from the last instance.
*/ 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;
}
/** * amdgpu_device_ip_get_clockgating_state - get the CG state * * @adev: amdgpu_device pointer * @flags: clockgating feature flags * * Walks the list of IPs on the device and updates the clockgating * flags for each IP. * Updates @flags with the feature flags for each hardware IP where * clockgating is enabled.
*/ void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
u64 *flags)
{ int i;
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 - wait for idle * * @adev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * * Waits for the request hardware IP to be idle. * Returns 0 for success or a negative error code on failure.
*/ 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;
}
} return 0;
}
/** * amdgpu_device_ip_is_valid - is the hardware IP enabled * * @adev: amdgpu_device pointer * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) * * Check if the hardware IP is enable or not. * Returns true if it the IP is enable, false if not.
*/ bool amdgpu_device_ip_is_valid(struct amdgpu_device *adev, enum amd_ip_block_type block_type)
{ int i;
for (i = 0; i < adev->num_ip_blocks; i++) { if (adev->ip_blocks[i].version->type == block_type) return adev->ip_blocks[i].status.valid;
} returnfalse;
}
/** * amdgpu_device_ip_get_ip_block - get a hw IP pointer * * @adev: amdgpu_device pointer * @type: Type of hardware IP (SMU, GFX, UVD, etc.) * * Returns a pointer to the hardware IP block structure * if it exists for the asic, otherwise NULL.
*/ struct amdgpu_ip_block *
amdgpu_device_ip_get_ip_block(struct amdgpu_device *adev, enum amd_ip_block_type type)
{ int i;
for (i = 0; i < adev->num_ip_blocks; i++) if (adev->ip_blocks[i].version->type == type) return &adev->ip_blocks[i];
return NULL;
}
/** * amdgpu_device_ip_block_version_cmp * * @adev: amdgpu_device pointer * @type: enum amd_ip_block_type * @major: major version * @minor: minor version * * return 0 if equal or greater * return 1 if smaller or the ip_block doesn't exist
*/ int amdgpu_device_ip_block_version_cmp(struct amdgpu_device *adev, enum amd_ip_block_type type,
u32 major, u32 minor)
{ struct amdgpu_ip_block *ip_block = amdgpu_device_ip_get_ip_block(adev, type);
/** * amdgpu_device_ip_block_add * * @adev: amdgpu_device pointer * @ip_block_version: pointer to the IP to add * * Adds the IP block driver information to the collection of IPs * on the asic.
*/ int amdgpu_device_ip_block_add(struct amdgpu_device *adev, conststruct amdgpu_ip_block_version *ip_block_version)
{ if (!ip_block_version) return -EINVAL;
switch (ip_block_version->type) { case AMD_IP_BLOCK_TYPE_VCN: if (adev->harvest_ip_mask & AMD_HARVEST_IP_VCN_MASK) return 0; break; case AMD_IP_BLOCK_TYPE_JPEG: if (adev->harvest_ip_mask & AMD_HARVEST_IP_JPEG_MASK) return 0; break; default: break;
}
dev_info(adev->dev, "detected ip block number %d <%s>\n",
adev->num_ip_blocks, ip_block_version->funcs->name);
/** * amdgpu_device_enable_virtual_display - enable virtual display feature * * @adev: amdgpu_device pointer * * Enabled the virtual display feature if the user has enabled it via * the module parameter virtual_display. This feature provides a virtual * display hardware on headless boards or in virtualized environments. * This function parses and validates the configuration string specified by * the user and configures the virtual display configuration (number of * virtual connectors, crtcs, etc.) specified.
*/ staticvoid amdgpu_device_enable_virtual_display(struct amdgpu_device *adev)
{
adev->enable_virtual_display = false;
/** * amdgpu_device_parse_gpu_info_fw - parse gpu info firmware * * @adev: amdgpu_device pointer * * Parses the asic configuration parameters specified in the gpu info * firmware and makes them available to the driver for use in configuring * the asic. * Returns 0 on success, -EINVAL on failure.
*/ staticint amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
{ constchar *chip_name; int err; conststruct gpu_info_firmware_header_v1_0 *hdr;
adev->firmware.gpu_info_fw = NULL;
switch (adev->asic_type) { default: return 0; case CHIP_VEGA10:
chip_name = "vega10"; break; case CHIP_VEGA12:
chip_name = "vega12"; break; case CHIP_RAVEN: if (adev->apu_flags & AMD_APU_IS_RAVEN2)
chip_name = "raven2"; elseif (adev->apu_flags & AMD_APU_IS_PICASSO)
chip_name = "picasso"; else
chip_name = "raven"; break; case CHIP_ARCTURUS:
chip_name = "arcturus"; break; case CHIP_NAVI12: if (adev->mman.discovery_bin) return 0;
chip_name = "navi12"; break; case CHIP_CYAN_SKILLFISH:
chip_name = "cyan_skillfish"; break;
}
err = amdgpu_ucode_request(adev, &adev->firmware.gpu_info_fw,
AMDGPU_UCODE_OPTIONAL, "amdgpu/%s_gpu_info.bin", chip_name); if (err) {
dev_err(adev->dev, "Failed to get gpu_info firmware \"%s_gpu_info.bin\"\n",
chip_name); goto out;
}
parse_soc_bounding_box: /* * soc bounding box info is not integrated in disocovery table, * we always need to parse it from gpu info firmware if needed.
*/ if (hdr->version_minor == 2) { conststruct gpu_info_firmware_v1_2 *gpu_info_fw =
(conststruct gpu_info_firmware_v1_2 *)(adev->firmware.gpu_info_fw->data +
le32_to_cpu(hdr->header.ucode_array_offset_bytes));
adev->dm.soc_bounding_box = &gpu_info_fw->soc_bounding_box;
} break;
} default:
dev_err(adev->dev, "Unsupported gpu_info table %d\n", hdr->header.ucode_version);
err = -EINVAL; goto out;
}
out: return err;
}
/** * amdgpu_device_ip_early_init - run early init for hardware IPs * * @adev: amdgpu_device pointer * * Early initialization pass for hardware IPs. The hardware IPs that make * up each asic are discovered each IP's early_init callback is run. This * is the first stage in initializing the asic. * Returns 0 on success, negative error code on failure.
*/ staticint amdgpu_device_ip_early_init(struct amdgpu_device *adev)
{ struct amdgpu_ip_block *ip_block; struct pci_dev *parent; bool total, skip_bios;
uint32_t bios_flags; int i, r;
amdgpu_device_enable_virtual_display(adev);
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;
}
}
return 0;
}
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;
}
return 0;
}
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);
return 0;
}
/** * amdgpu_device_ip_init - run init for hardware IPs * * @adev: amdgpu_device pointer * * Main initialization pass for hardware IPs. The list of all the hardware * IPs that make up the asic is walked and the sw_init and hw_init callbacks * are run. sw_init initializes the software state associated with each IP * and hw_init initializes the hardware associated with each IP. * Returns 0 on success, negative error code on failure.
*/ staticint amdgpu_device_ip_init(struct amdgpu_device *adev)
{ bool init_badpage; int i, r;
r = amdgpu_ras_init(adev); 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->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;
/* * retired pages will be loaded from eeprom and reserved here, * it should be called after amdgpu_device_ip_hw_init_phase2 since * for some ASICs the RAS EEPROM code relies on SMU fully functioning * for I2C communication which only true at this point. * * amdgpu_ras_recovery_init may fail, but the upper only cares the * failure from bad gpu situation and stop amdgpu init process * accordingly. For other failed cases, it will still release all * the resource and print error message, rather than returning one * negative value to upper level. * * Note: theoretically, this should be called before all vram allocations * to protect retired page from abusing
*/
init_badpage = (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI);
r = amdgpu_ras_recovery_init(adev, init_badpage); if (r) goto init_failed;
/** * In case of XGMI grab extra reference for reset domain for this device
*/ 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);
init_failed:
return r;
}
/** * amdgpu_device_fill_reset_magic - writes reset magic to gart pointer * * @adev: amdgpu_device pointer * * Writes a reset magic value to the gart pointer in VRAM. The driver calls * this function before a GPU reset. If the value is retained after a * GPU reset, VRAM has not been lost. Some GPU resets may destroy VRAM contents.
*/ staticvoid amdgpu_device_fill_reset_magic(struct amdgpu_device *adev)
{
memcpy(adev->reset_magic, adev->gart.ptr, AMDGPU_RESET_MAGIC_NUM);
}
/** * amdgpu_device_check_vram_lost - check if vram is valid * * @adev: amdgpu_device pointer * * Checks the reset magic value written to the gart pointer in VRAM. * The driver calls this after a GPU reset to see if the contents of * VRAM is lost or now. * returns true if vram is lost, false if not.
*/ staticbool amdgpu_device_check_vram_lost(struct amdgpu_device *adev)
{ if (memcmp(adev->gart.ptr, adev->reset_magic,
AMDGPU_RESET_MAGIC_NUM)) returntrue;
if (!amdgpu_in_reset(adev)) returnfalse;
/* * For all ASICs with baco/mode1 reset, the VRAM is * always assumed to be lost.
*/ 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;
}
}
/** * amdgpu_device_set_cg_state - set clockgating for amdgpu device * * @adev: amdgpu_device pointer * @state: clockgating state (gate or ungate) * * The list of all the hardware IPs that make up the asic is walked and the * set_clockgating_state callbacks are run. * Late initialization pass enabling clockgating for hardware IPs. * Fini or suspend, pass disabling clockgating for hardware IPs. * Returns 0 on success, negative error code on failure.
*/
int amdgpu_device_set_cg_state(struct amdgpu_device *adev, enum amd_clockgating_state state)
{ int i, j, r;
if (amdgpu_emu_mode == 1) return 0;
for (j = 0; j < adev->num_ip_blocks; j++) {
i = state == AMD_CG_STATE_GATE ? j : adev->num_ip_blocks - j - 1; if (!adev->ip_blocks[i].status.late_initialized) continue; /* skip CG for GFX, SDMA on S0ix */ if (adev->in_s0ix &&
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; /* skip CG for VCE/UVD, it's handled specially */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE &&
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN &&
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG &&
adev->ip_blocks[i].version->funcs->set_clockgating_state) { /* enable clockgating to save power */
r = adev->ip_blocks[i].version->funcs->set_clockgating_state(&adev->ip_blocks[i],
state); if (r) {
dev_err(adev->dev, "set_clockgating_state(gate) of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name,
r); return r;
}
}
}
return 0;
}
int amdgpu_device_set_pg_state(struct amdgpu_device *adev, enum amd_powergating_state state)
{ int i, j, r;
if (amdgpu_emu_mode == 1) return 0;
for (j = 0; j < adev->num_ip_blocks; j++) {
i = state == AMD_PG_STATE_GATE ? j : adev->num_ip_blocks - j - 1; if (!adev->ip_blocks[i].status.late_initialized) continue; /* skip PG for GFX, SDMA on S0ix */ if (adev->in_s0ix &&
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA)) continue; /* skip CG for VCE/UVD, it's handled specially */ if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE &&
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN &&
adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG &&
adev->ip_blocks[i].version->funcs->set_powergating_state) { /* enable powergating to save power */
r = adev->ip_blocks[i].version->funcs->set_powergating_state(&adev->ip_blocks[i],
state); if (r) {
dev_err(adev->dev, "set_powergating_state(gate) of IP block <%s> failed %d\n",
adev->ip_blocks[i].version->funcs->name,
r); return r;
}
}
} return 0;
}
staticint amdgpu_device_enable_mgpu_fan_boost(void)
{ struct amdgpu_gpu_instance *gpu_ins; struct amdgpu_device *adev; int i, ret = 0;
mutex_lock(&mgpu_info.mutex);
/* * MGPU fan boost feature should be enabled * only when there are two or more dGPUs in * the system
*/ if (mgpu_info.num_dgpu < 2) goto out;
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;
gpu_ins->mgpu_fan_enabled = 1;
}
}
out:
mutex_unlock(&mgpu_info.mutex);
return ret;
}
/** * amdgpu_device_ip_late_init - run late init for hardware IPs * * @adev: amdgpu_device pointer * * Late initialization pass for hardware IPs. The list of all the hardware * IPs that make up the asic is walked and the late_init callbacks are run. * late_init covers any special initialization that an IP requires * after all of the have been initialized or something that needs to happen * late in the init process. * Returns 0 on success, negative error code on failure.
*/ staticint amdgpu_device_ip_late_init(struct amdgpu_device *adev)
{ struct amdgpu_gpu_instance *gpu_instance; int i = 0, r;
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);
r = amdgpu_device_enable_mgpu_fan_boost(); if (r)
dev_err(adev->dev, "enable mgpu fan boost failed (%d).\n", r);
/* For passthrough configuration on arcturus and aldebaran, enable special handling SBR */ if (amdgpu_passthrough(adev) &&
((adev->asic_type == CHIP_ARCTURUS && adev->gmc.xgmi.num_physical_nodes > 1) ||
adev->asic_type == CHIP_ALDEBARAN))
amdgpu_dpm_handle_passthrough_sbr(adev, true);
if (adev->gmc.xgmi.num_physical_nodes > 1) {
mutex_lock(&mgpu_info.mutex);
/* * Reset device p-state to low as this was booted with high. * * This should be performed only after all devices from the same * hive get initialized. * * However, it's unknown how many device in the hive in advance. * As this is counted one by one during devices initializations. * * So, we wait for all XGMI interlinked devices initialized. * This may bring some delays as those devices may come from * different hives. But that should be OK.
*/ if (mgpu_info.num_dgpu == adev->gmc.xgmi.num_physical_nodes) { for (i = 0; i < mgpu_info.num_gpu; i++) {
gpu_instance = &(mgpu_info.gpu_ins[i]); if (gpu_instance->adev->flags & AMD_IS_APU) continue;
r = amdgpu_xgmi_set_pstate(gpu_instance->adev,
AMDGPU_XGMI_PSTATE_MIN); if (r) {
dev_err(adev->dev, "pstate setting failed (%d).\n",
r); break;
}
}
}
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);
}
}
ip_block->status.hw = false;
}
/** * amdgpu_device_smu_fini_early - smu hw_fini wrapper * * @adev: amdgpu_device pointer * * For ASICs need to disable SMC first
*/ staticvoid amdgpu_device_smu_fini_early(struct amdgpu_device *adev)
{ int i;
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");
}
return 0;
}
/** * amdgpu_device_ip_fini - run fini for hardware IPs * * @adev: amdgpu_device pointer * * Main teardown pass for hardware IPs. The list of all the hardware * IPs that make up the asic is walked and the hw_fini and sw_fini callbacks * are run. hw_fini tears down the hardware associated with each IP * and sw_fini tears down any software state associated with each IP. * Returns 0 on success, negative error code on failure.
*/ 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;
}
amdgpu_ras_fini(adev);
return 0;
}
/** * amdgpu_device_delayed_init_work_handler - work handler for IB tests * * @work: work_struct.
*/ staticvoid amdgpu_device_delayed_init_work_handler(struct work_struct *work)
{ struct amdgpu_device *adev =
container_of(work, struct amdgpu_device, delayed_init_work.work); int r;
r = amdgpu_ib_ring_tests(adev); if (r)
dev_err(adev->dev, "ib ring test failed (%d).\n", r);
}
if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true, 0))
adev->gfx.gfx_off_state = true;
}
/** * amdgpu_device_ip_suspend_phase1 - run suspend for hardware IPs (phase 1) * * @adev: amdgpu_device pointer * * Main suspend function for hardware IPs. The list of all the hardware * IPs that make up the asic is walked, clockgating is disabled and the * suspend callbacks are run. suspend puts the hardware and software state * in each IP into a state suitable for suspend. * Returns 0 on success, negative error code on failure.
*/ staticint amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev)
{ int i, r;
/* * Per PMFW team's suggestion, driver needs to handle gfxoff * and df cstate features disablement for gpu reset(e.g. Mode1Reset) * scenario. Add the missing df cstate disablement here.
*/ 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;
}
return 0;
}
/** * amdgpu_device_ip_suspend_phase2 - run suspend for hardware IPs (phase 2) * * @adev: amdgpu_device pointer * * Main suspend function for hardware IPs. The list of all the hardware * IPs that make up the asic is walked, clockgating is disabled and the * suspend callbacks are run. suspend puts the hardware and software state * in each IP into a state suitable for suspend. * Returns 0 on success, negative error code on failure.
*/ 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 * idle work here as the suspend callback never gets called.
*/ 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 * gfx is in gfxoff state, so on resume it will exit gfxoff just * like at runtime. PSP is also part of the always on hardware * so no need to suspend it.
*/ 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. * These are in TMR, hence are expected to be reused by PSP-TOS to reload * from this location and RLC Autoload automatically also gets loaded * from here based on PMFW -> PSP message during re-init sequence. * Therefore, the psp suspend & resume should be skipped to avoid destroy * the TMR and reload FWs again for IMU enabled APU ASICs.
*/ 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;
}
}
}
}
return 0;
}
/** * amdgpu_device_ip_suspend - run suspend for hardware IPs * * @adev: amdgpu_device pointer * * Main suspend function for hardware IPs. The list of all the hardware * IPs that make up the asic is walked, clockgating is disabled and the * suspend callbacks are run. suspend puts the hardware and software state * in each IP into a state suitable for suspend. * Returns 0 on success, negative error code on failure.
*/ 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);
}
/** * amdgpu_device_ip_resume_phase1 - run resume for hardware IPs * * @adev: amdgpu_device pointer * * First resume function for hardware IPs. The list of all the hardware * IPs that make up the asic is walked and the resume callbacks are run for * COMMON, GMC, and IH. resume puts the hardware into a functional state * after a suspend and updates the software state as necessary. This * function is also used for restoring the GPU after a GPU reset. * Returns 0 on success, negative error code on failure.
*/ staticint amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev)
{ int i, r;
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_COMMON ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH ||
(adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP && amdgpu_sriov_vf(adev))) {
r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); if (r) return r;
}
}
return 0;
}
/** * amdgpu_device_ip_resume_phase2 - run resume for hardware IPs * * @adev: amdgpu_device pointer * * Second resume function for hardware IPs. The list of all the hardware * IPs that make up the asic is walked and the resume callbacks are run for * all blocks except COMMON, GMC, and IH. resume puts the hardware into a * functional state after a suspend and updates the software state as * necessary. This function is also used for restoring the GPU after a GPU * reset. * Returns 0 on success, negative error code on failure.
*/ staticint amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev)
{ int i, r;
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_COMMON ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE ||
adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) continue;
r = amdgpu_ip_block_resume(&adev->ip_blocks[i]); if (r) return r;
}
return 0;
}
/** * amdgpu_device_ip_resume_phase3 - run resume for hardware IPs * * @adev: amdgpu_device pointer * * Third resume function for hardware IPs. The list of all the hardware * IPs that make up the asic is walked and the resume callbacks are run for * all DCE. resume puts the hardware into a functional state after a suspend * and updates the software state as necessary. This function is also used * for restoring the GPU after a GPU reset. * * Returns 0 on success, negative error code on failure.
*/ staticint amdgpu_device_ip_resume_phase3(struct amdgpu_device *adev)
{ int i, r;
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;
}
}
return 0;
}
/** * amdgpu_device_ip_resume - run resume for hardware IPs * * @adev: amdgpu_device pointer * * Main resume function for hardware IPs. The hardware IPs * are split into two resume functions because they are * also used in recovering from a GPU reset and some additional * steps need to be take between them. In this case (S3/S4) they are * run sequentially. * Returns 0 on success, negative error code on failure.
*/ staticint amdgpu_device_ip_resume(struct amdgpu_device *adev)
{ int r;
r = amdgpu_device_ip_resume_phase1(adev); if (r) return r;
r = amdgpu_device_fw_loading(adev); if (r) return r;
r = amdgpu_device_ip_resume_phase2(adev);
if (adev->mman.buffer_funcs_ring->sched.ready)
amdgpu_ttm_set_buffer_funcs_status(adev, true);
if (r) return r;
amdgpu_fence_driver_hw_init(adev);
r = amdgpu_device_ip_resume_phase3(adev);
return r;
}
/** * amdgpu_device_detect_sriov_bios - determine if the board supports SR-IOV * * @adev: amdgpu_device pointer * * Query the VBIOS data tables to determine if the board supports SR-IOV.
*/ staticvoid amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
{ if (amdgpu_sriov_vf(adev)) { if (adev->is_atom_fw) { if (amdgpu_atomfirmware_gpu_virtualization_supported(adev))
adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
} else { if (amdgpu_atombios_has_gpu_virtualization_table(adev))
adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
}
if (!(adev->virt.caps & AMDGPU_SRIOV_CAPS_SRIOV_VBIOS))
amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_NO_VBIOS, 0, 0);
}
}
/** * amdgpu_device_asic_has_dc_support - determine if DC supports the asic * * @pdev : pci device context * @asic_type: AMD asic type * * Check if there is DC (new modesetting infrastructre) support for an asic. * returns true if DC has support, false if not.
*/ bool amdgpu_device_asic_has_dc_support(struct pci_dev *pdev, enum amd_asic_type asic_type)
{ switch (asic_type) { #ifdef CONFIG_DRM_AMDGPU_SI case CHIP_HAINAN: #endif case CHIP_TOPAZ: /* chips with no display hardware */ returnfalse; #ifdefined(CONFIG_DRM_AMD_DC) case CHIP_TAHITI: case CHIP_PITCAIRN: case CHIP_VERDE: case CHIP_OLAND: /* * We have systems in the wild with these ASICs that require * LVDS and VGA support which is not supported with DC. * * Fallback to the non-DC driver here by default so as not to * cause regressions.
*/ #ifdefined(CONFIG_DRM_AMD_DC_SI) return amdgpu_dc > 0; #else returnfalse; #endif case CHIP_BONAIRE: case CHIP_KAVERI: case CHIP_KABINI: case CHIP_MULLINS: /* * We have systems in the wild with these ASICs that require * VGA support which is not supported with DC. * * Fallback to the non-DC driver here by default so as not to * cause regressions.
*/ return amdgpu_dc > 0; default: return amdgpu_dc != 0; #else default: if (amdgpu_dc > 0)
dev_info_once(
&pdev->dev, "Display Core has been requested via kernel parameter but isn't supported by ASIC, ignoring\n"); returnfalse; #endif
}
}
/** * amdgpu_device_has_dc_support - check if dc is supported * * @adev: amdgpu_device pointer * * Returns true for supported, false for not supported
*/ bool amdgpu_device_has_dc_support(struct amdgpu_device *adev)
{ if (adev->enable_virtual_display ||
(adev->harvest_ip_mask & AMD_HARVEST_IP_DMU_MASK)) returnfalse;
/* It's a bug to not have a hive within this function */ if (WARN_ON(!hive)) return;
/* * Use task barrier to synchronize all xgmi reset works across the * hive. task_barrier_enter and task_barrier_exit will block * until all the threads running the xgmi reset works reach * those points. task_barrier_full will do both blocks.
*/ if (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) {
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;
/* * By default timeout for jobs is 10 sec
*/
adev->compute_timeout = adev->gfx_timeout = msecs_to_jiffies(10000);
adev->sdma_timeout = adev->video_timeout = adev->gfx_timeout;
if (strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) { while ((timeout_setting = strsep(&input, ",")) &&
strnlen(timeout_setting, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) {
ret = kstrtol(timeout_setting, 0, &timeout); if (ret) return ret;
switch (index++) { case 0:
adev->gfx_timeout = timeout; break; case 1:
adev->compute_timeout = timeout; break; case 2:
adev->sdma_timeout = timeout; break; case 3:
adev->video_timeout = timeout; break; default: break;
}
} /* * There is only one value specified and * it should apply to all non-compute jobs.
*/ if (index == 1) {
adev->sdma_timeout = adev->video_timeout = adev->gfx_timeout; if (amdgpu_sriov_vf(adev) || amdgpu_passthrough(adev))
adev->compute_timeout = adev->gfx_timeout;
}
}
return ret;
}
/** * amdgpu_device_check_iommu_direct_map - check if RAM direct mapped to GPU * * @adev: amdgpu_device pointer * * RAM direct mapped to GPU if IOMMU is not enabled or is pass through mode
*/ staticvoid amdgpu_device_check_iommu_direct_map(struct amdgpu_device *adev)
{ struct iommu_domain *domain;
if (adev->gfx.mcbp)
dev_info(adev->dev, "MCBP is enabled\n");
}
/** * amdgpu_device_init - initialize the driver * * @adev: amdgpu_device pointer * @flags: driver flags * * Initializes the driver info and hw (all asics). * Returns 0 for success or an error on failure. * Called at driver startup.
*/ int amdgpu_device_init(struct amdgpu_device *adev,
uint32_t flags)
{ struct pci_dev *pdev = adev->pdev; int r, i; bool px = false;
u32 max_MBps; int tmp;
/* mutex initialization are all done here so we * can recall function without having locking issues
*/
mutex_init(&adev->firmware.mutex);
mutex_init(&adev->pm.mutex);
mutex_init(&adev->gfx.gpu_clock_mutex);
mutex_init(&adev->srbm_mutex);
mutex_init(&adev->gfx.pipe_reserve_mutex);
mutex_init(&adev->gfx.gfx_off_mutex);
mutex_init(&adev->gfx.partition_mutex);
mutex_init(&adev->grbm_idx_mutex);
mutex_init(&adev->mn_lock);
mutex_init(&adev->virt.vf_errors.lock);
hash_init(adev->mn_hash);
mutex_init(&adev->psp.mutex);
mutex_init(&adev->notifier_lock);
mutex_init(&adev->pm.stable_pstate_ctx_lock);
mutex_init(&adev->benchmark_mutex);
mutex_init(&adev->gfx.reset_sem_mutex); /* Initialize the mutex for cleaner shader isolation between GFX and compute processes */
mutex_init(&adev->enforce_isolation_mutex); for (i = 0; i < MAX_XCP; ++i) {
adev->isolation[i].spearhead = dma_fence_get_stub();
amdgpu_sync_create(&adev->isolation[i].active);
amdgpu_sync_create(&adev->isolation[i].prev);
}
mutex_init(&adev->gfx.userq_sch_mutex);
mutex_init(&adev->gfx.workload_profile_mutex);
mutex_init(&adev->vcn.workload_profile_mutex);
mutex_init(&adev->userq_mutex);
amdgpu_device_init_apu_flags(adev);
r = amdgpu_device_check_arguments(adev); if (r) return r;
INIT_DELAYED_WORK(&adev->delayed_init_work,
amdgpu_device_delayed_init_work_handler);
INIT_DELAYED_WORK(&adev->gfx.gfx_off_delay_work,
amdgpu_device_delay_enable_gfx_off); /* * Initialize the enforce_isolation work structures for each XCP * partition. This work handler is responsible for enforcing shader * isolation on AMD GPUs. It counts the number of emitted fences for * each GFX and compute ring. If there are any fences, it schedules * the `enforce_isolation_work` to be run after a delay. If there are * no fences, it signals the Kernel Fusion Driver (KFD) to resume the * runqueue.
*/ for (i = 0; i < MAX_XCP; i++) {
INIT_DELAYED_WORK(&adev->gfx.enforce_isolation[i].work,
amdgpu_gfx_enforce_isolation_handler);
adev->gfx.enforce_isolation[i].adev = adev;
adev->gfx.enforce_isolation[i].xcp_id = i;
}
atomic_set(&adev->throttling_logging_enabled, 1); /* * If throttling continues, logging will be performed every minute * to avoid log flooding. "-1" is subtracted since the thermal * throttling interrupt comes every second. Thus, the total logging * interval is 59 seconds(retelimited printk interval) + 1(waiting * for throttling interrupt) = 60 seconds.
*/
ratelimit_state_init(&adev->throttling_logging_rs, (60 - 1) * HZ, 1);
/* * Reset domain needs to be present early, before XGMI hive discovered * (if any) and initialized to use reset sem and in_gpu reset flag * early on during init and before calling to RREG32.
*/
adev->reset_domain = amdgpu_reset_create_reset_domain(SINGLE_DEVICE, "amdgpu-reset-dev"); if (!adev->reset_domain) return -ENOMEM;
/* 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);
/* * By default, use default mode where all blocks are expected to be * initialized. At present a 'swinit' of blocks is required to be * completed before the need for a different level is detected.
*/
amdgpu_set_init_level(adev, AMDGPU_INIT_LEVEL_DEFAULT); /* early init functions */
r = amdgpu_device_ip_early_init(adev); if (r) return r;
/* * No need to remove conflicting FBs for non-display class devices. * This prevents the sysfb from being freed accidently.
*/ 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 * will be blocked during sriov runtime
*/
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 * internal path natively support atomics, set have_atomics_support to true.
*/
} 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., driver was not cleanly unloaded previously, 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, * regardless of the module parameter reset_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));
/* * Register gpu instance before amdgpu_device_enable_mgpu_fan_boost. * Otherwise the mgpu fan boost feature will be skipped due to the * gpu instance is counted less.
*/
amdgpu_register_gpu_instance(adev);
/* enable clockgating, etc. after ib tests, etc. since some blocks require * explicit gating rather than handling it automatically.
*/ 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);
}
/* * Place those sysfs registering after `late_init`. As some of those * operations performed in `late_init` might affect the sysfs * interfaces creating.
*/
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 * ignore it
*/ 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;
return 0;
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);
/* Clear all CPU mappings pointing to this device */
unmap_mapping_range(adev->ddev.anon_inode->i_mapping, 0, 0, 1);
/* Unmap all mapped bars - Doorbell, registers and VRAM */
amdgpu_doorbell_fini(adev);
iounmap(adev->rmmio);
adev->rmmio = NULL; if (adev->mman.aper_base_kaddr)
iounmap(adev->mman.aper_base_kaddr);
adev->mman.aper_base_kaddr = NULL;
/* Memory manager related */ if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
arch_phys_wc_del(adev->gmc.vram_mtrr);
arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size);
}
}
/** * amdgpu_device_fini_hw - tear down the driver * * @adev: amdgpu_device pointer * * Tear down the driver info (all asics). * Called at driver shutdown.
*/ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
{
dev_info(adev->dev, "amdgpu: finishing device.\n");
flush_delayed_work(&adev->delayed_init_work);
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 * to avoid preemption on IB test
*/ 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);
/** * amdgpu_device_evict_resources - evict device resources * @adev: amdgpu device object * * Evicts all ttm device resources(vram BOs, gart table) from the lru list * of the vram memory type. Mainly used for evicting device resources * at suspend time. *
*/ staticint amdgpu_device_evict_resources(struct amdgpu_device *adev)
{ int ret;
/* No need to evict vram on APUs unless going to S4 */ if (!adev->in_s4 && (adev->flags & AMD_IS_APU)) return 0;
/* No need to evict when going to S5 through S4 callbacks */ if (system_state == SYSTEM_POWER_OFF) return 0;
ret = amdgpu_ttm_evict_resources(adev, TTM_PL_VRAM); if (ret) {
dev_warn(adev->dev, "evicting device resources failed\n"); return ret;
}
if (adev->in_s4) {
ret = ttm_device_prepare_hibernation(&adev->mman.bdev); if (ret)
dev_err(adev->dev, "prepare hibernation failed, %d\n", ret);
} return ret;
}
/* * Suspend & resume.
*/ /** * amdgpu_device_pm_notifier - Notification block for Suspend/Hibernate events * @nb: notifier block * @mode: suspend mode * @data: data * * This function is called when the system is about to suspend or hibernate. * It is used to set the appropriate flags so that eviction can be optimized * in the pm prepare callback.
*/ staticint amdgpu_device_pm_notifier(struct notifier_block *nb, unsignedlong mode, void *data)
{ struct amdgpu_device *adev = container_of(nb, struct amdgpu_device, pm_nb);
switch (mode) { case PM_HIBERNATION_PREPARE:
adev->in_s4 = true; break; case PM_POST_HIBERNATION:
adev->in_s4 = false; break;
}
return NOTIFY_DONE;
}
/** * amdgpu_device_prepare - prepare for device suspend * * @dev: drm dev pointer * * Prepare to put the hw in the suspend state (all asics). * Returns 0 for success or an error on failure. * Called at driver suspend.
*/ int amdgpu_device_prepare(struct drm_device *dev)
{ struct amdgpu_device *adev = drm_to_adev(dev); int i, r;
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0;
/* Evict the majority of BOs before starting suspend sequence */
r = amdgpu_device_evict_resources(adev); 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->prepare_suspend) continue;
r = adev->ip_blocks[i].version->funcs->prepare_suspend(&adev->ip_blocks[i]); if (r) return r;
}
return 0;
}
/** * amdgpu_device_complete - complete power state transition * * @dev: drm dev pointer * * Undo the changes from amdgpu_device_prepare. This will be * called on all resume transitions, including those that failed.
*/ void amdgpu_device_complete(struct drm_device *dev)
{ struct amdgpu_device *adev = drm_to_adev(dev); int i;
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 - initiate device suspend * * @dev: drm dev pointer * @notify_clients: notify in-kernel DRM clients * * Puts the hw in the suspend state (all asics). * Returns 0 for success or an error on failure. * Called at driver suspend.
*/ 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) return 0;
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);
/* During VM resume, QEMU programming of VF MSIX table (register GFXMSIX_VECT0_ADDR_LO) * may not work. The access could be blocked by nBIF protection as VF isn't in * exclusive access mode. Exclusive access is enabled now, disable/enable MSIX * so that QEMU reprograms MSIX table.
*/
amdgpu_restore_msix(adev);
r = adev->gfxhub.funcs->get_xgmi_info(adev); if (r) return r;
dev_info(adev->dev, "xgmi node, old id %d, new id %d\n",
prev_physical_node_id, adev->gmc.xgmi.physical_node_id);
/** * amdgpu_device_resume - initiate device resume * * @dev: drm dev pointer * @notify_clients: notify in-kernel DRM clients * * Bring the hw back to operating state (all asics). * Returns 0 for success or an error on failure. * Called at driver resume.
*/ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients)
{ struct amdgpu_device *adev = drm_to_adev(dev); int r = 0;
if (amdgpu_sriov_vf(adev)) {
r = amdgpu_virt_request_full_gpu(adev, true); if (r) return r;
}
if (amdgpu_virt_xgmi_migrate_enabled(adev)) {
r = amdgpu_virt_resume(adev); if (r) gotoexit;
}
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0;
if (adev->in_s0ix)
amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D0Entry);
/* post card */ if (amdgpu_device_need_post(adev)) {
r = amdgpu_device_asic_init(adev); if (r)
dev_err(adev->dev, "amdgpu asic init failed\n");
}
r = amdgpu_device_ip_resume(adev);
if (r) {
dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r); gotoexit;
}
r = amdgpu_amdkfd_resume(adev, !amdgpu_sriov_vf(adev) && !adev->in_runpm); if (r) gotoexit;
r = amdgpu_userq_resume(adev); if (r) gotoexit;
r = amdgpu_device_ip_late_init(adev); if (r) gotoexit;
queue_delayed_work(system_wq, &adev->delayed_init_work,
msecs_to_jiffies(AMDGPU_RESUME_MS)); exit: if (amdgpu_sriov_vf(adev)) {
amdgpu_virt_init_data_exchange(adev);
amdgpu_virt_release_full_gpu(adev, true);
if (!r && !adev->in_runpm)
r = amdgpu_amdkfd_resume_process(adev);
}
if (r) return r;
/* Make sure IB tests flushed */
flush_delayed_work(&adev->delayed_init_work);
if (notify_clients)
drm_client_dev_resume(adev_to_drm(adev), false);
amdgpu_ras_resume(adev);
if (adev->mode_info.num_crtc) { /* * Most of the connector probing functions try to acquire runtime pm * refs to ensure that the GPU is powered on when connector polling is * performed. Since we're calling this from a runtime PM callback, * trying to acquire rpm refs will cause us to deadlock. * * Since we're guaranteed to be holding the rpm lock, it's safe to * temporarily disable the rpm helpers so this doesn't deadlock us.
*/ #ifdef CONFIG_PM
dev->dev->power.disable_depth++; #endif if (!adev->dc_enabled)
drm_helper_hpd_irq_event(dev); else
drm_kms_helper_hotplug_event(dev); #ifdef CONFIG_PM
dev->dev->power.disable_depth--; #endif
}
if (amdgpu_acpi_smart_shift_update(adev, AMDGPU_SS_DEV_D0))
dev_warn(adev->dev, "smart shift update failed\n");
return 0;
}
/** * 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.
*/ staticbool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev)
{ int i; bool asic_hang = false;
if (amdgpu_sriov_vf(adev)) returntrue;
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 - 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.
*/ 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;
}
}
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.
*/ staticbool amdgpu_device_ip_need_full_reset(struct amdgpu_device *adev)
{ int i;
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 - 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.
*/ 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;
}
}
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.
*/ 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-metal does.
*/
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);
amdgpu_virt_ras_telemetry_post_reset(adev);
return 0;
}
/** * amdgpu_device_has_job_running - check if there is any unfinished job * * @adev: amdgpu_device pointer * * check if there is any job running on the device when guest driver receives * FLR notification from host driver. If there are still jobs running, then * the guest driver will not respond the FLR reset. Instead, let the job hit * the timeout and guest driver then issue the reset request.
*/ bool amdgpu_device_has_job_running(struct amdgpu_device *adev)
{ int i;
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i];
if (!amdgpu_ring_sched_ready(ring)) continue;
if (amdgpu_fence_count_emitted(ring)) returntrue;
} returnfalse;
}
/** * amdgpu_device_should_recover_gpu - check if we should try GPU recovery * * @adev: amdgpu_device pointer * * Check amdgpu_gpu_recovery and SRIOV status to see if we should try to recover * a hung GPU.
*/ bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
{
if (amdgpu_gpu_recovery == 0) goto disabled;
/* 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 * values are used in other cases like restore after mode-2 reset.
*/
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;
return 0;
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 * leave NULL and vm flush fence in fence drv
*/
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;
/* * The GPU enters bad state once faulty pages * by ECC has reached the threshold, and ras * recovery is scheduled next. So add one check * here to break recovery if it indeed exceeds * bad page threshold, and remind user to * retire this GPU or setting one bigger * bad_page_threshold value to fix this once * probing driver again.
*/ 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);
/* * ASIC reset has to be done on all XGMI hive nodes ASAP * to allow proper links negotiation in FW (within 1 sec)
*/ 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;
}
}
}
}
/* * For now, only BACO and mode1 reset are confirmed * to suffer the audio issue without proper suspended.
*/
reset_method = amdgpu_asic_reset_method(adev); if ((reset_method != AMD_RESET_METHOD_BACO) &&
(reset_method != AMD_RESET_METHOD_MODE1)) return -EINVAL;
p = pci_get_domain_bus_and_slot(pci_domain_nr(adev->pdev->bus),
adev->pdev->bus->number, 1); if (!p) return -ENODEV;
expires = pm_runtime_autosuspend_expiration(&(p->dev)); if (!expires) /* * If we cannot get the audio device autosuspend delay, * a fixed 4S interval will be used. Considering 3S is * the audio controller default autosuspend delay setting. * 4S used here is guaranteed to cover that.
*/
expires = ktime_get_mono_fast_ns() + NSEC_PER_SEC * 4ULL;
while (!pm_runtime_status_suspended(&(p->dev))) { if (!pm_runtime_suspend(&(p->dev))) break;
if (expires < ktime_get_mono_fast_ns()) {
dev_warn(adev->dev, "failed to suspend display audio\n");
pci_dev_put(p); /* TODO: abort the succeeding gpu reset? */ return -ETIMEDOUT;
}
}
/* * Build list of devices to reset. * In case we are in XGMI hive mode, resort the device list * to put adev in the 1st position.
*/ if (!amdgpu_sriov_vf(adev) && (adev->gmc.xgmi.num_physical_nodes > 1) && hive) {
list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
list_add_tail(&tmp_adev->reset_list, device_list); if (adev->shutdown)
tmp_adev->shutdown = true; if (adev->pcie_reset_ctx.occurs_dpc)
tmp_adev->pcie_reset_ctx.in_link_reset = true;
} if (!list_is_first(&adev->reset_list, device_list))
list_rotate_to_front(&adev->reset_list, device_list);
} else {
list_add_tail(&adev->reset_list, device_list);
}
}
/* block all schedulers and reset given job's ring */
list_for_each_entry(tmp_adev, device_list, reset_list) {
amdgpu_device_set_mp1_state(tmp_adev);
/* * Try to put the audio codec into suspend state * before gpu reset started. * * Due to the power domain of the graphics device * is shared with AZ power domain. Without this, * we may change the audio hardware from behind * the audio driver's back. That will trigger * some audio codec errors.
*/ if (!amdgpu_device_suspend_display_audio(tmp_adev))
tmp_adev->pcie_reset_ctx.audio_suspended = true;
/* 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) { /* * Drop any pending non scheduler resets queued before reset is done. * Any reset scheduled after this point would be valid. Scheduler resets * were already dropped during drm_sched_stop and no new ones can come * in before drm_sched_start.
*/
amdgpu_device_stop_pending_resets(tmp_adev);
}
return r;
}
staticint amdgpu_device_sched_resume(struct list_head *device_list, struct amdgpu_reset_context *reset_context, bool job_signaled)
{ struct amdgpu_device *tmp_adev = NULL; int i, r = 0;
/* Post ASIC reset for all devs .*/
list_for_each_entry(tmp_adev, device_list, reset_list) {
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = tmp_adev->rings[i];
if (!amdgpu_ring_sched_ready(ring)) continue;
drm_sched_start(&ring->sched, 0);
}
if (!drm_drv_uses_atomic_modeset(adev_to_drm(tmp_adev)) && !job_signaled)
drm_helper_resume_force_mode(adev_to_drm(tmp_adev));
if (tmp_adev->asic_reset_res) { /* bad news, how to tell it to userspace ? * for ras error, we should report GPU bad status instead of * reset failure
*/ if (reset_context->src != AMDGPU_RESET_SRC_RAS ||
!amdgpu_ras_eeprom_check_err_threshold(tmp_adev))
dev_info(
tmp_adev->dev, "GPU reset(%d) failed with error %d \n",
atomic_read(
&tmp_adev->gpu_reset_counter),
tmp_adev->asic_reset_res);
amdgpu_vf_error_put(tmp_adev,
AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0,
tmp_adev->asic_reset_res); if (!r)
r = tmp_adev->asic_reset_res;
tmp_adev->asic_reset_res = 0;
} else {
dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n",
atomic_read(&tmp_adev->gpu_reset_counter)); if (amdgpu_acpi_smart_shift_update(tmp_adev,
AMDGPU_SS_DEV_D0))
dev_warn(tmp_adev->dev, "smart shift update failed\n");
}
}
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, * need to bring up kfd here if it's not be initialized before
*/ 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);
amdgpu_device_unset_mp1_state(tmp_adev);
amdgpu_ras_set_error_query_ready(tmp_adev, true);
}
}
/** * amdgpu_device_gpu_recover - reset the asic and recover scheduler * * @adev: amdgpu_device pointer * @job: which job trigger hang * @reset_context: amdgpu reset context pointer * * Attempt to reset the GPU if it has hung (all asics). * Attempt to do soft-reset or full-reset and reinitialize Asic * Returns 0 for success or an error on failure.
*/
/* * If it reaches here because of hang/timeout and a RAS error is * detected at the same time, let RAS recovery take care of it.
*/ if (amdgpu_ras_is_err_state(adev, AMDGPU_RAS_BLOCK__ANY) &&
!amdgpu_sriov_vf(adev) &&
reset_context->src != AMDGPU_RESET_SRC_RAS) {
dev_dbg(adev->dev, "Gpu recovery from source: %d yielding to RAS error recovery handling",
reset_context->src); return 0;
}
/* * Special case: RAS triggered and full reset isn't supported
*/
need_emergency_restart = amdgpu_ras_need_emergency_restart(adev);
/* * Flush RAM to disk so that after reboot * the user can read log and see why the system rebooted.
*/ if (need_emergency_restart && amdgpu_ras_get_context(adev) &&
amdgpu_ras_get_context(adev)->reboot) {
dev_warn(adev->dev, "Emergency reboot.");
if (!amdgpu_sriov_vf(adev)) {
r = amdgpu_device_health_check(&device_list); if (r) goto end_reset;
}
/* We need to lock reset domain only once both for XGMI and single device */
amdgpu_device_recovery_get_reset_lock(adev, &device_list);
amdgpu_device_halt_activities(adev, job, reset_context, &device_list,
hive, need_emergency_restart); if (need_emergency_restart) goto skip_sched_resume; /* * Must check guilty signal here since after this point all old * HW fences are force signaled. * * job->base holds a reference to parent fence
*/ if (job && dma_fence_is_signaled(&job->hw_fence.base)) {
job_signaled = true;
dev_info(adev->dev, "Guilty job already signaled, skipping HW reset"); goto skip_hw_reset;
}
r = amdgpu_device_asic_reset(adev, &device_list, reset_context); if (r) goto reset_unlock;
skip_hw_reset:
r = amdgpu_device_sched_resume(&device_list, reset_context, job_signaled); if (r) goto reset_unlock;
skip_sched_resume:
amdgpu_device_gpu_resume(adev, &device_list, need_emergency_restart);
reset_unlock:
amdgpu_device_recovery_put_reset_lock(adev, &device_list);
end_reset: if (hive) {
mutex_unlock(&hive->hive_lock);
amdgpu_put_xgmi_hive(hive);
}
if (r)
dev_info(adev->dev, "GPU reset end with ret = %d\n", r);
atomic_set(&adev->reset_domain->reset_res, r);
if (!r) { struct amdgpu_task_info *ti = NULL;
if (job)
ti = amdgpu_vm_get_task_info_pasid(adev, job->pasid);
drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE,
ti ? &ti->task : NULL);
amdgpu_vm_put_task_info(ti);
}
return r;
}
/** * amdgpu_device_partner_bandwidth - find the bandwidth of appropriate partner * * @adev: amdgpu_device pointer * @speed: pointer to the speed of the link * @width: pointer to the width of the link * * Evaluate the hierarchy to find the speed and bandwidth capabilities of the * first physical partner to an AMD dGPU. * This will exclude any virtual switches and links.
*/ staticvoid amdgpu_device_partner_bandwidth(struct amdgpu_device *adev, enum pci_bus_speed *speed, enum pcie_link_width *width)
{ struct pci_dev *parent = adev->pdev;
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);
}
}
/** * amdgpu_device_gpu_bandwidth - find the bandwidth of the GPU * * @adev: amdgpu_device pointer * @speed: pointer to the speed of the link * @width: pointer to the width of the link * * Evaluate the hierarchy to find the speed and bandwidth capabilities of the * AMD dGPU which may be a virtual upstream bridge.
*/ staticvoid amdgpu_device_gpu_bandwidth(struct amdgpu_device *adev, enum pci_bus_speed *speed, enum pcie_link_width *width)
{ struct pci_dev *parent = adev->pdev;
if (!speed || !width) return;
parent = pci_upstream_bridge(parent); if (parent && parent->vendor == PCI_VENDOR_ID_ATI) { /* use the upstream/downstream switches internal to dGPU */
*speed = pcie_get_speed_cap(parent);
*width = pcie_get_width_cap(parent); while ((parent = pci_upstream_bridge(parent))) { if (parent->vendor == PCI_VENDOR_ID_ATI) { /* use the upstream/downstream switches internal to dGPU */
*speed = pcie_get_speed_cap(parent);
*width = pcie_get_width_cap(parent);
}
}
} else { /* use the device itself */
*speed = pcie_get_speed_cap(adev->pdev);
*width = pcie_get_width_cap(adev->pdev);
}
}
/** * amdgpu_device_get_pcie_info - fence pcie info about the PCIE slot * * @adev: amdgpu_device pointer * * Fetches and stores in the driver the PCIE capabilities (gen speed * and lanes) of the slot the device is in. Handles APUs and * virtualized environments where PCIE config space may not be available.
*/ staticvoid amdgpu_device_get_pcie_info(struct amdgpu_device *adev)
{ enum pci_bus_speed speed_cap, platform_speed_cap; enum pcie_link_width platform_link_width, link_width;
if (amdgpu_pcie_gen_cap)
adev->pm.pcie_gen_mask = amdgpu_pcie_gen_cap;
if (amdgpu_pcie_lane_cap)
adev->pm.pcie_mlw_mask = amdgpu_pcie_lane_cap;
/* covers APUs as well */ if (pci_is_root_bus(adev->pdev->bus) && !amdgpu_passthrough(adev)) { if (adev->pm.pcie_gen_mask == 0)
adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK; if (adev->pm.pcie_mlw_mask == 0)
adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK; return;
}
if (adev->pm.pcie_gen_mask && adev->pm.pcie_mlw_mask) return;
/** * amdgpu_device_is_peer_accessible - Check peer access through PCIe BAR * * @adev: amdgpu_device pointer * @peer_adev: amdgpu_device pointer for peer device trying to access @adev * * Return true if @peer_adev can access (DMA) @adev through the PCIe * BAR, i.e. @adev is "large BAR" and the BAR matches the DMA mask of * @peer_adev.
*/ bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, struct amdgpu_device *peer_adev)
{ #ifdef CONFIG_HSA_AMD_P2P bool p2p_access =
!adev->gmc.xgmi.connected_to_cpu &&
!(pci_p2pdma_distance(adev->pdev, peer_adev->dev, false) < 0); if (!p2p_access)
dev_info(adev->dev, "PCIe P2P access from peer device %s is not supported by the chipset\n",
pci_name(peer_adev->pdev));
/* This called only if amdgpu_pci_error_detected returns * PCI_ERS_RESULT_CAN_RECOVER. Read/write to the device still * works, no need to reset slot.
*/
return PCI_ERS_RESULT_RECOVERED;
}
/** * amdgpu_pci_slot_reset - Called when PCI slot has been reset. * @pdev: PCI device struct * * Description: This routine is called by the pci error recovery * code after the PCI slot has been reset, just before we * should resume normal operations.
*/
pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev)
{ struct drm_device *dev = pci_get_drvdata(pdev); struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_reset_context reset_context; struct amdgpu_device *tmp_adev; struct amdgpu_hive_info *hive; struct list_head device_list; int r = 0, i;
u32 memsize;
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;
}
int amdgpu_in_reset(struct amdgpu_device *adev)
{ return atomic_read(&adev->reset_domain->in_gpu_reset);
}
/** * amdgpu_device_halt() - bring hardware to some kind of halt state * * @adev: amdgpu_device pointer * * Bring hardware to some kind of halt state so that no one can touch it * any more. It will help to maintain error context when error occurred. * Compare to a simple hang, the system will keep stable at least for SSH * access. Then it should be trivial to inspect the hardware state and * see what's going on. Implemented as following: * * 1. drm_dev_unplug() makes device inaccessible to user space(IOCTLs, etc), * clears all CPU mappings to device, disallows remappings through page faults * 2. amdgpu_irq_disable_all() disables all interrupts * 3. amdgpu_fence_driver_hw_fini() signals all HW fences * 4. set adev->no_hw_access to avoid potential crashes after setp 5 * 5. amdgpu_device_unmap_mmio() clears all MMIO mappings * 6. pci_disable_device() and pci_wait_for_pending_transaction() * flush any in flight DMA operations
*/ void amdgpu_device_halt(struct amdgpu_device *adev)
{ struct pci_dev *pdev = adev->pdev; struct drm_device *ddev = adev_to_drm(adev);
/** * amdgpu_device_get_gang - return a reference to the current gang * @adev: amdgpu_device pointer * * Returns: A new reference to the current gang leader.
*/ struct dma_fence *amdgpu_device_get_gang(struct amdgpu_device *adev)
{ struct dma_fence *fence;
/** * amdgpu_device_switch_gang - switch to a new gang * @adev: amdgpu_device pointer * @gang: the gang to switch to * * Try to switch to a new gang. * Returns: NULL if we switched to the new gang or a reference to the current * gang leader.
*/ struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev, struct dma_fence *gang)
{ struct dma_fence *old = NULL;
dma_fence_get(gang); do {
dma_fence_put(old);
old = amdgpu_device_get_gang(adev); if (old == gang) break;
if (!dma_fence_is_signaled(old)) {
dma_fence_put(gang); return old;
}
} while (cmpxchg((struct dma_fence __force **)&adev->gang_submit,
old, gang) != old);
/* * Drop it once for the exchanged reference in adev and once for the * thread local reference acquired in amdgpu_device_get_gang().
*/
dma_fence_put(old);
dma_fence_put(old); return NULL;
}
/** * amdgpu_device_enforce_isolation - enforce HW isolation * @adev: the amdgpu device pointer * @ring: the HW ring the job is supposed to run on * @job: the job which is about to be pushed to the HW ring * * Makes sure that only one client at a time can use the GFX block. * Returns: The dependency to wait on before the job can be pushed to the HW. * The function is called multiple times until NULL is returned.
*/ struct dma_fence *amdgpu_device_enforce_isolation(struct amdgpu_device *adev, struct amdgpu_ring *ring, struct amdgpu_job *job)
{ struct amdgpu_isolation *isolation = &adev->isolation[ring->xcp_id]; struct drm_sched_fence *f = job->base.s_fence; struct dma_fence *dep; void *owner; int r;
/* * For now enforce isolation only for the GFX block since we only need * the cleaner shader on those rings.
*/ if (ring->funcs->type != AMDGPU_RING_TYPE_GFX &&
ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE) return NULL;
/* * All submissions where enforce isolation is false are handled as if * they come from a single client. Use ~0l as the owner to distinct it * from kernel submissions where the owner is NULL.
*/
owner = job->enforce_isolation ? f->owner : (void *)~0l;
mutex_lock(&adev->enforce_isolation_mutex);
/* * The "spearhead" submission is the first one which changes the * ownership to its client. We always need to wait for it to be * pushed to the HW before proceeding with anything.
*/ if (&f->scheduled != isolation->spearhead &&
!dma_fence_is_signaled(isolation->spearhead)) {
dep = isolation->spearhead; goto out_grab_ref;
}
if (isolation->owner != owner) {
/* * Wait for any gang to be assembled before switching to a * different owner or otherwise we could deadlock the * submissions.
*/ if (!job->gang_submit) {
dep = amdgpu_device_get_gang(adev); if (!dma_fence_is_signaled(dep)) goto out_return_dep;
dma_fence_put(dep);
}
/* * Specifying the ring here helps to pipeline submissions even when * isolation is enabled. If that is not desired for testing NULL can be * used instead of the ring to enforce a CPU round trip while switching * between clients.
*/
dep = amdgpu_sync_peek_fence(&isolation->prev, ring);
r = amdgpu_sync_fence(&isolation->active, &f->finished, GFP_NOWAIT); if (r)
dev_warn(adev->dev, "OOM tracking isolation\n");
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.