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