1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher * Copyright 2008 Advanced Micro Devices, Inc.
3d38ceaf9SAlex Deucher * Copyright 2008 Red Hat Inc.
4d38ceaf9SAlex Deucher * Copyright 2009 Jerome Glisse.
5d38ceaf9SAlex Deucher *
6d38ceaf9SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a
7d38ceaf9SAlex Deucher * copy of this software and associated documentation files (the "Software"),
8d38ceaf9SAlex Deucher * to deal in the Software without restriction, including without limitation
9d38ceaf9SAlex Deucher * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10d38ceaf9SAlex Deucher * and/or sell copies of the Software, and to permit persons to whom the
11d38ceaf9SAlex Deucher * Software is furnished to do so, subject to the following conditions:
12d38ceaf9SAlex Deucher *
13d38ceaf9SAlex Deucher * The above copyright notice and this permission notice shall be included in
14d38ceaf9SAlex Deucher * all copies or substantial portions of the Software.
15d38ceaf9SAlex Deucher *
16d38ceaf9SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17d38ceaf9SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18d38ceaf9SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19d38ceaf9SAlex Deucher * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20d38ceaf9SAlex Deucher * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21d38ceaf9SAlex Deucher * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22d38ceaf9SAlex Deucher * OTHER DEALINGS IN THE SOFTWARE.
23d38ceaf9SAlex Deucher *
24d38ceaf9SAlex Deucher * Authors: Dave Airlie
25d38ceaf9SAlex Deucher * Alex Deucher
26d38ceaf9SAlex Deucher * Jerome Glisse
27d38ceaf9SAlex Deucher */
28ea1d2a38SThomas Zimmermann
29ea1d2a38SThomas Zimmermann #include <linux/aperture.h>
30b1ddf548SRex Zhu #include <linux/power_supply.h>
310875dc9eSChunming Zhou #include <linux/kthread.h>
32fdf2f6c5SSam Ravnborg #include <linux/module.h>
33d38ceaf9SAlex Deucher #include <linux/console.h>
34d38ceaf9SAlex Deucher #include <linux/slab.h>
354a74c38cSPhilip Yang #include <linux/iommu.h>
36901e2be2SAlex Deucher #include <linux/pci.h>
3708a2fd23SRamesh Errabolu #include <linux/pci-p2pdma.h>
38d37a3929SOrlando Chamberlain #include <linux/apple-gmux.h>
39fdf2f6c5SSam Ravnborg
404562236bSHarry Wentland #include <drm/drm_atomic_helper.h>
414cf50baeSThomas Zimmermann #include <drm/drm_client_event.h>
42973ad627SThomas Zimmermann #include <drm/drm_crtc_helper.h>
43fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
44d38ceaf9SAlex Deucher #include <drm/amdgpu_drm.h>
457b1c6263SAlex Deucher #include <linux/device.h>
46d38ceaf9SAlex Deucher #include <linux/vgaarb.h>
47d38ceaf9SAlex Deucher #include <linux/vga_switcheroo.h>
48d38ceaf9SAlex Deucher #include <linux/efi.h>
49d38ceaf9SAlex Deucher #include "amdgpu.h"
50f4b373f4STom St Denis #include "amdgpu_trace.h"
51d38ceaf9SAlex Deucher #include "amdgpu_i2c.h"
52d38ceaf9SAlex Deucher #include "atom.h"
53d38ceaf9SAlex Deucher #include "amdgpu_atombios.h"
54a5bde2f9SAlex Deucher #include "amdgpu_atomfirmware.h"
55d0dd7f0cSAlex Deucher #include "amd_pcie.h"
5633f34802SKen Wang #ifdef CONFIG_DRM_AMDGPU_SI
5733f34802SKen Wang #include "si.h"
5833f34802SKen Wang #endif
59a2e73f56SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_CIK
60a2e73f56SAlex Deucher #include "cik.h"
61a2e73f56SAlex Deucher #endif
62aaa36a97SAlex Deucher #include "vi.h"
63460826e6SKen Wang #include "soc15.h"
640a5b8c7bSHuang Rui #include "nv.h"
65d38ceaf9SAlex Deucher #include "bif/bif_4_1_d.h"
66bec86378SMonk Liu #include <linux/firmware.h>
6789041940SGavin Wan #include "amdgpu_vf_error.h"
68d38ceaf9SAlex Deucher
69ba997709SYong Zhao #include "amdgpu_amdkfd.h"
70d2f52ac8SRex Zhu #include "amdgpu_pm.h"
71d38ceaf9SAlex Deucher
725183411bSAndrey Grodzovsky #include "amdgpu_xgmi.h"
73c030f2e4Sxinhui pan #include "amdgpu_ras.h"
749c7c85f7SJonathan Kim #include "amdgpu_pmu.h"
75bd607166SKent Russell #include "amdgpu_fru_eeprom.h"
7604442bf7SLijo Lazar #include "amdgpu_reset.h"
7785150626SVictor Lu #include "amdgpu_virt.h"
789022f01bSSunil Khatri #include "amdgpu_dev_coredump.h"
795183411bSAndrey Grodzovsky
80d5ea093eSAndrey Grodzovsky #include <linux/suspend.h>
81c6a6e2dbSAndrey Grodzovsky #include <drm/task_barrier.h>
823f12acc8SEvan Quan #include <linux/pm_runtime.h>
83d5ea093eSAndrey Grodzovsky
84f89f8c6bSAndrey Grodzovsky #include <drm/drm_drv.h>
85f89f8c6bSAndrey Grodzovsky
863ad5dcfeSKai-Heng Feng #if IS_ENABLED(CONFIG_X86)
873ad5dcfeSKai-Heng Feng #include <asm/intel-family.h>
883ad5dcfeSKai-Heng Feng #endif
893ad5dcfeSKai-Heng Feng
90e2a75f88SAlex Deucher MODULE_FIRMWARE("amdgpu/vega10_gpu_info.bin");
913f76dcedSAlex Deucher MODULE_FIRMWARE("amdgpu/vega12_gpu_info.bin");
922d2e5e7eSAlex Deucher MODULE_FIRMWARE("amdgpu/raven_gpu_info.bin");
93ad5a67a7SLikun Gao MODULE_FIRMWARE("amdgpu/picasso_gpu_info.bin");
9454c4d17eSFeifei Xu MODULE_FIRMWARE("amdgpu/raven2_gpu_info.bin");
9565e60f6eSLe Ma MODULE_FIRMWARE("amdgpu/arcturus_gpu_info.bin");
9642b325e5SXiaojie Yuan MODULE_FIRMWARE("amdgpu/navi12_gpu_info.bin");
97e2a75f88SAlex Deucher
982dc80b00SShirish S #define AMDGPU_RESUME_MS 2000
997258fa31SSurbhi Kakarya #define AMDGPU_MAX_RETRY_LIMIT 2
1007258fa31SSurbhi Kakarya #define AMDGPU_RETRY_SRIOV_RESET(r) ((r) == -EBUSY || (r) == -ETIMEDOUT || (r) == -EINVAL)
101ad390542SHawking Zhang #define AMDGPU_PCIE_INDEX_FALLBACK (0x38 >> 2)
102ad390542SHawking Zhang #define AMDGPU_PCIE_INDEX_HI_FALLBACK (0x44 >> 2)
103ad390542SHawking Zhang #define AMDGPU_PCIE_DATA_FALLBACK (0x3C >> 2)
1042dc80b00SShirish S
1057e0aa706SLijo Lazar #define AMDGPU_VBIOS_SKIP (1U << 0)
1066e8ca38eSLijo Lazar #define AMDGPU_VBIOS_OPTIONAL (1U << 1)
1077e0aa706SLijo Lazar
108b7cdb41eSMario Limonciello static const struct drm_driver amdgpu_kms_driver;
109b7cdb41eSMario Limonciello
110050091abSYong Zhao const char *amdgpu_asic_name[] = {
111da69c161SKen Wang "TAHITI",
112da69c161SKen Wang "PITCAIRN",
113da69c161SKen Wang "VERDE",
114da69c161SKen Wang "OLAND",
115da69c161SKen Wang "HAINAN",
116d38ceaf9SAlex Deucher "BONAIRE",
117d38ceaf9SAlex Deucher "KAVERI",
118d38ceaf9SAlex Deucher "KABINI",
119d38ceaf9SAlex Deucher "HAWAII",
120d38ceaf9SAlex Deucher "MULLINS",
121d38ceaf9SAlex Deucher "TOPAZ",
122d38ceaf9SAlex Deucher "TONGA",
12348299f95SDavid Zhang "FIJI",
124d38ceaf9SAlex Deucher "CARRIZO",
125139f4917SSamuel Li "STONEY",
1262cc0c0b5SFlora Cui "POLARIS10",
1272cc0c0b5SFlora Cui "POLARIS11",
128c4642a47SJunwei Zhang "POLARIS12",
12948ff108dSLeo Liu "VEGAM",
130d4196f01SKen Wang "VEGA10",
1318fab806aSFeifei Xu "VEGA12",
132956fcddcSFeifei Xu "VEGA20",
1332ca8a5d2SChunming Zhou "RAVEN",
134d6c3b24eSLe Ma "ARCTURUS",
1351eee4228SHuang Rui "RENOIR",
136d46b417aSLe Ma "ALDEBARAN",
137852a6626SHuang Rui "NAVI10",
138d0f56dc2STao Zhou "CYAN_SKILLFISH",
13987dbad02SXiaojie Yuan "NAVI14",
1409802f5d7SXiaojie Yuan "NAVI12",
141ccaf72d3SLikun Gao "SIENNA_CICHLID",
142ddd8fbe7SJiansong Chen "NAVY_FLOUNDER",
1434f1e9a76SHuang Rui "VANGOGH",
144a2468e04STao Zhou "DIMGREY_CAVEFISH",
1456f169591SChengming Gui "BEIGE_GOBY",
146ee9236b7SAaron Liu "YELLOW_CARP",
1473ae695d6SAlex Deucher "IP DISCOVERY",
148d38ceaf9SAlex Deucher "LAST",
149d38ceaf9SAlex Deucher };
150d38ceaf9SAlex Deucher
151ee2003d5SPratap Nirujogi #define AMDGPU_IP_BLK_MASK_ALL GENMASK(AMD_IP_BLOCK_TYPE_NUM - 1, 0)
15214f2fe34SLijo Lazar /*
15314f2fe34SLijo Lazar * Default init level where all blocks are expected to be initialized. This is
15414f2fe34SLijo Lazar * the level of initialization expected by default and also after a full reset
15514f2fe34SLijo Lazar * of the device.
15614f2fe34SLijo Lazar */
15714f2fe34SLijo Lazar struct amdgpu_init_level amdgpu_init_default = {
15814f2fe34SLijo Lazar .level = AMDGPU_INIT_LEVEL_DEFAULT,
15914f2fe34SLijo Lazar .hwini_ip_block_mask = AMDGPU_IP_BLK_MASK_ALL,
16014f2fe34SLijo Lazar };
16114f2fe34SLijo Lazar
162a86e0c0eSLijo Lazar struct amdgpu_init_level amdgpu_init_recovery = {
163a86e0c0eSLijo Lazar .level = AMDGPU_INIT_LEVEL_RESET_RECOVERY,
164a86e0c0eSLijo Lazar .hwini_ip_block_mask = AMDGPU_IP_BLK_MASK_ALL,
165a86e0c0eSLijo Lazar };
166a86e0c0eSLijo Lazar
16714f2fe34SLijo Lazar /*
16814f2fe34SLijo Lazar * Minimal blocks needed to be initialized before a XGMI hive can be reset. This
16914f2fe34SLijo Lazar * is used for cases like reset on initialization where the entire hive needs to
17014f2fe34SLijo Lazar * be reset before first use.
17114f2fe34SLijo Lazar */
17214f2fe34SLijo Lazar struct amdgpu_init_level amdgpu_init_minimal_xgmi = {
17314f2fe34SLijo Lazar .level = AMDGPU_INIT_LEVEL_MINIMAL_XGMI,
17414f2fe34SLijo Lazar .hwini_ip_block_mask =
17514f2fe34SLijo Lazar BIT(AMD_IP_BLOCK_TYPE_GMC) | BIT(AMD_IP_BLOCK_TYPE_SMC) |
176631af731SLijo Lazar BIT(AMD_IP_BLOCK_TYPE_COMMON) | BIT(AMD_IP_BLOCK_TYPE_IH) |
177631af731SLijo Lazar BIT(AMD_IP_BLOCK_TYPE_PSP)
17814f2fe34SLijo Lazar };
17914f2fe34SLijo Lazar
amdgpu_ip_member_of_hwini(struct amdgpu_device * adev,enum amd_ip_block_type block)18014f2fe34SLijo Lazar static inline bool amdgpu_ip_member_of_hwini(struct amdgpu_device *adev,
18114f2fe34SLijo Lazar enum amd_ip_block_type block)
18214f2fe34SLijo Lazar {
18314f2fe34SLijo Lazar return (adev->init_lvl->hwini_ip_block_mask & (1U << block)) != 0;
18414f2fe34SLijo Lazar }
18514f2fe34SLijo Lazar
amdgpu_set_init_level(struct amdgpu_device * adev,enum amdgpu_init_lvl_id lvl)18614f2fe34SLijo Lazar void amdgpu_set_init_level(struct amdgpu_device *adev,
18714f2fe34SLijo Lazar enum amdgpu_init_lvl_id lvl)
18814f2fe34SLijo Lazar {
18914f2fe34SLijo Lazar switch (lvl) {
19014f2fe34SLijo Lazar case AMDGPU_INIT_LEVEL_MINIMAL_XGMI:
19114f2fe34SLijo Lazar adev->init_lvl = &amdgpu_init_minimal_xgmi;
19214f2fe34SLijo Lazar break;
193a86e0c0eSLijo Lazar case AMDGPU_INIT_LEVEL_RESET_RECOVERY:
194a86e0c0eSLijo Lazar adev->init_lvl = &amdgpu_init_recovery;
195a86e0c0eSLijo Lazar break;
19614f2fe34SLijo Lazar case AMDGPU_INIT_LEVEL_DEFAULT:
19714f2fe34SLijo Lazar fallthrough;
19814f2fe34SLijo Lazar default:
19914f2fe34SLijo Lazar adev->init_lvl = &amdgpu_init_default;
20014f2fe34SLijo Lazar break;
20114f2fe34SLijo Lazar }
20214f2fe34SLijo Lazar }
20314f2fe34SLijo Lazar
204ab66c832SZhigang Luo static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev);
2052965e635SMario Limonciello static int amdgpu_device_pm_notifier(struct notifier_block *nb, unsigned long mode,
2062965e635SMario Limonciello void *data);
207ab66c832SZhigang Luo
208dcea6e65SKent Russell /**
209dcea6e65SKent Russell * DOC: pcie_replay_count
210dcea6e65SKent Russell *
211dcea6e65SKent Russell * The amdgpu driver provides a sysfs API for reporting the total number
212a567db80SRandy Dunlap * of PCIe replays (NAKs).
213dcea6e65SKent Russell * The file pcie_replay_count is used for this and returns the total
214a567db80SRandy Dunlap * number of replays as a sum of the NAKs generated and NAKs received.
215dcea6e65SKent Russell */
216dcea6e65SKent Russell
amdgpu_device_get_pcie_replay_count(struct device * dev,struct device_attribute * attr,char * buf)217dcea6e65SKent Russell static ssize_t amdgpu_device_get_pcie_replay_count(struct device *dev,
218dcea6e65SKent Russell struct device_attribute *attr, char *buf)
219dcea6e65SKent Russell {
220dcea6e65SKent Russell struct drm_device *ddev = dev_get_drvdata(dev);
2211348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(ddev);
222dcea6e65SKent Russell uint64_t cnt = amdgpu_asic_get_pcie_replay_count(adev);
223dcea6e65SKent Russell
22436000c7aSTian Tao return sysfs_emit(buf, "%llu\n", cnt);
225dcea6e65SKent Russell }
226dcea6e65SKent Russell
227b8920e1eSSrinivasan Shanmugam static DEVICE_ATTR(pcie_replay_count, 0444,
228dcea6e65SKent Russell amdgpu_device_get_pcie_replay_count, NULL);
229dcea6e65SKent Russell
amdgpu_device_attr_sysfs_init(struct amdgpu_device * adev)2309c05636cSVictor Skvortsov static int amdgpu_device_attr_sysfs_init(struct amdgpu_device *adev)
2319c05636cSVictor Skvortsov {
2329c05636cSVictor Skvortsov int ret = 0;
2339c05636cSVictor Skvortsov
2349c05636cSVictor Skvortsov if (!amdgpu_sriov_vf(adev))
2359c05636cSVictor Skvortsov ret = sysfs_create_file(&adev->dev->kobj,
2369c05636cSVictor Skvortsov &dev_attr_pcie_replay_count.attr);
2379c05636cSVictor Skvortsov
2389c05636cSVictor Skvortsov return ret;
2399c05636cSVictor Skvortsov }
2409c05636cSVictor Skvortsov
amdgpu_device_attr_sysfs_fini(struct amdgpu_device * adev)2419c05636cSVictor Skvortsov static void amdgpu_device_attr_sysfs_fini(struct amdgpu_device *adev)
2429c05636cSVictor Skvortsov {
2439c05636cSVictor Skvortsov if (!amdgpu_sriov_vf(adev))
2449c05636cSVictor Skvortsov sysfs_remove_file(&adev->dev->kobj,
2459c05636cSVictor Skvortsov &dev_attr_pcie_replay_count.attr);
2469c05636cSVictor Skvortsov }
2479c05636cSVictor Skvortsov
amdgpu_sysfs_reg_state_get(struct file * f,struct kobject * kobj,const struct bin_attribute * attr,char * buf,loff_t ppos,size_t count)248af39e6f4SLijo Lazar static ssize_t amdgpu_sysfs_reg_state_get(struct file *f, struct kobject *kobj,
2492d0f5001SThomas Weißschuh const struct bin_attribute *attr, char *buf,
250af39e6f4SLijo Lazar loff_t ppos, size_t count)
251af39e6f4SLijo Lazar {
252af39e6f4SLijo Lazar struct device *dev = kobj_to_dev(kobj);
253af39e6f4SLijo Lazar struct drm_device *ddev = dev_get_drvdata(dev);
254af39e6f4SLijo Lazar struct amdgpu_device *adev = drm_to_adev(ddev);
255af39e6f4SLijo Lazar ssize_t bytes_read;
256af39e6f4SLijo Lazar
257af39e6f4SLijo Lazar switch (ppos) {
258af39e6f4SLijo Lazar case AMDGPU_SYS_REG_STATE_XGMI:
259af39e6f4SLijo Lazar bytes_read = amdgpu_asic_get_reg_state(
260af39e6f4SLijo Lazar adev, AMDGPU_REG_STATE_TYPE_XGMI, buf, count);
261af39e6f4SLijo Lazar break;
262af39e6f4SLijo Lazar case AMDGPU_SYS_REG_STATE_WAFL:
263af39e6f4SLijo Lazar bytes_read = amdgpu_asic_get_reg_state(
264af39e6f4SLijo Lazar adev, AMDGPU_REG_STATE_TYPE_WAFL, buf, count);
265af39e6f4SLijo Lazar break;
266af39e6f4SLijo Lazar case AMDGPU_SYS_REG_STATE_PCIE:
267af39e6f4SLijo Lazar bytes_read = amdgpu_asic_get_reg_state(
268af39e6f4SLijo Lazar adev, AMDGPU_REG_STATE_TYPE_PCIE, buf, count);
269af39e6f4SLijo Lazar break;
270af39e6f4SLijo Lazar case AMDGPU_SYS_REG_STATE_USR:
271af39e6f4SLijo Lazar bytes_read = amdgpu_asic_get_reg_state(
272af39e6f4SLijo Lazar adev, AMDGPU_REG_STATE_TYPE_USR, buf, count);
273af39e6f4SLijo Lazar break;
274af39e6f4SLijo Lazar case AMDGPU_SYS_REG_STATE_USR_1:
275af39e6f4SLijo Lazar bytes_read = amdgpu_asic_get_reg_state(
276af39e6f4SLijo Lazar adev, AMDGPU_REG_STATE_TYPE_USR_1, buf, count);
277af39e6f4SLijo Lazar break;
278af39e6f4SLijo Lazar default:
279af39e6f4SLijo Lazar return -EINVAL;
280af39e6f4SLijo Lazar }
281af39e6f4SLijo Lazar
282af39e6f4SLijo Lazar return bytes_read;
283af39e6f4SLijo Lazar }
284af39e6f4SLijo Lazar
2852d0f5001SThomas Weißschuh static const BIN_ATTR(reg_state, 0444, amdgpu_sysfs_reg_state_get, NULL,
286af39e6f4SLijo Lazar AMDGPU_SYS_REG_STATE_END);
287af39e6f4SLijo Lazar
amdgpu_reg_state_sysfs_init(struct amdgpu_device * adev)288af39e6f4SLijo Lazar int amdgpu_reg_state_sysfs_init(struct amdgpu_device *adev)
289af39e6f4SLijo Lazar {
290af39e6f4SLijo Lazar int ret;
291af39e6f4SLijo Lazar
292af39e6f4SLijo Lazar if (!amdgpu_asic_get_reg_state_supported(adev))
293af39e6f4SLijo Lazar return 0;
294af39e6f4SLijo Lazar
295af39e6f4SLijo Lazar ret = sysfs_create_bin_file(&adev->dev->kobj, &bin_attr_reg_state);
296af39e6f4SLijo Lazar
297af39e6f4SLijo Lazar return ret;
298af39e6f4SLijo Lazar }
299af39e6f4SLijo Lazar
amdgpu_reg_state_sysfs_fini(struct amdgpu_device * adev)300af39e6f4SLijo Lazar void amdgpu_reg_state_sysfs_fini(struct amdgpu_device *adev)
301af39e6f4SLijo Lazar {
302af39e6f4SLijo Lazar if (!amdgpu_asic_get_reg_state_supported(adev))
303af39e6f4SLijo Lazar return;
304af39e6f4SLijo Lazar sysfs_remove_bin_file(&adev->dev->kobj, &bin_attr_reg_state);
305af39e6f4SLijo Lazar }
306af39e6f4SLijo Lazar
amdgpu_ip_block_suspend(struct amdgpu_ip_block * ip_block)307e095026fSSunil Khatri int amdgpu_ip_block_suspend(struct amdgpu_ip_block *ip_block)
308e095026fSSunil Khatri {
309e095026fSSunil Khatri int r;
310e095026fSSunil Khatri
311e095026fSSunil Khatri if (ip_block->version->funcs->suspend) {
312e095026fSSunil Khatri r = ip_block->version->funcs->suspend(ip_block);
313e095026fSSunil Khatri if (r) {
314e095026fSSunil Khatri dev_err(ip_block->adev->dev,
315e095026fSSunil Khatri "suspend of IP block <%s> failed %d\n",
316e095026fSSunil Khatri ip_block->version->funcs->name, r);
317e095026fSSunil Khatri return r;
318e095026fSSunil Khatri }
319e095026fSSunil Khatri }
320e095026fSSunil Khatri
321e095026fSSunil Khatri ip_block->status.hw = false;
322e095026fSSunil Khatri return 0;
323e095026fSSunil Khatri }
324e095026fSSunil Khatri
amdgpu_ip_block_resume(struct amdgpu_ip_block * ip_block)325502d7630SSunil Khatri int amdgpu_ip_block_resume(struct amdgpu_ip_block *ip_block)
326502d7630SSunil Khatri {
327502d7630SSunil Khatri int r;
328502d7630SSunil Khatri
329502d7630SSunil Khatri if (ip_block->version->funcs->resume) {
330502d7630SSunil Khatri r = ip_block->version->funcs->resume(ip_block);
331502d7630SSunil Khatri if (r) {
332502d7630SSunil Khatri dev_err(ip_block->adev->dev,
333502d7630SSunil Khatri "resume of IP block <%s> failed %d\n",
334502d7630SSunil Khatri ip_block->version->funcs->name, r);
335502d7630SSunil Khatri return r;
336502d7630SSunil Khatri }
337502d7630SSunil Khatri }
338502d7630SSunil Khatri
339502d7630SSunil Khatri ip_block->status.hw = true;
340502d7630SSunil Khatri return 0;
341502d7630SSunil Khatri }
342502d7630SSunil Khatri
3434798db85SLijo Lazar /**
3444798db85SLijo Lazar * DOC: board_info
3454798db85SLijo Lazar *
3464798db85SLijo Lazar * The amdgpu driver provides a sysfs API for giving board related information.
3474798db85SLijo Lazar * It provides the form factor information in the format
3484798db85SLijo Lazar *
3494798db85SLijo Lazar * type : form factor
3504798db85SLijo Lazar *
3514798db85SLijo Lazar * Possible form factor values
3524798db85SLijo Lazar *
3534798db85SLijo Lazar * - "cem" - PCIE CEM card
3544798db85SLijo Lazar * - "oam" - Open Compute Accelerator Module
3554798db85SLijo Lazar * - "unknown" - Not known
3564798db85SLijo Lazar *
3574798db85SLijo Lazar */
3584798db85SLijo Lazar
amdgpu_device_get_board_info(struct device * dev,struct device_attribute * attr,char * buf)35976da73f0SLijo Lazar static ssize_t amdgpu_device_get_board_info(struct device *dev,
36076da73f0SLijo Lazar struct device_attribute *attr,
36176da73f0SLijo Lazar char *buf)
36276da73f0SLijo Lazar {
36376da73f0SLijo Lazar struct drm_device *ddev = dev_get_drvdata(dev);
36476da73f0SLijo Lazar struct amdgpu_device *adev = drm_to_adev(ddev);
36576da73f0SLijo Lazar enum amdgpu_pkg_type pkg_type = AMDGPU_PKG_TYPE_CEM;
36676da73f0SLijo Lazar const char *pkg;
36776da73f0SLijo Lazar
36876da73f0SLijo Lazar if (adev->smuio.funcs && adev->smuio.funcs->get_pkg_type)
36976da73f0SLijo Lazar pkg_type = adev->smuio.funcs->get_pkg_type(adev);
37076da73f0SLijo Lazar
37176da73f0SLijo Lazar switch (pkg_type) {
37276da73f0SLijo Lazar case AMDGPU_PKG_TYPE_CEM:
37376da73f0SLijo Lazar pkg = "cem";
37476da73f0SLijo Lazar break;
37576da73f0SLijo Lazar case AMDGPU_PKG_TYPE_OAM:
37676da73f0SLijo Lazar pkg = "oam";
37776da73f0SLijo Lazar break;
37876da73f0SLijo Lazar default:
37976da73f0SLijo Lazar pkg = "unknown";
38076da73f0SLijo Lazar break;
38176da73f0SLijo Lazar }
38276da73f0SLijo Lazar
38376da73f0SLijo Lazar return sysfs_emit(buf, "%s : %s\n", "type", pkg);
38476da73f0SLijo Lazar }
38576da73f0SLijo Lazar
38676da73f0SLijo Lazar static DEVICE_ATTR(board_info, 0444, amdgpu_device_get_board_info, NULL);
38776da73f0SLijo Lazar
38876da73f0SLijo Lazar static struct attribute *amdgpu_board_attrs[] = {
38976da73f0SLijo Lazar &dev_attr_board_info.attr,
39076da73f0SLijo Lazar NULL,
39176da73f0SLijo Lazar };
39276da73f0SLijo Lazar
amdgpu_board_attrs_is_visible(struct kobject * kobj,struct attribute * attr,int n)39376da73f0SLijo Lazar static umode_t amdgpu_board_attrs_is_visible(struct kobject *kobj,
39476da73f0SLijo Lazar struct attribute *attr, int n)
39576da73f0SLijo Lazar {
39676da73f0SLijo Lazar struct device *dev = kobj_to_dev(kobj);
39776da73f0SLijo Lazar struct drm_device *ddev = dev_get_drvdata(dev);
39876da73f0SLijo Lazar struct amdgpu_device *adev = drm_to_adev(ddev);
39976da73f0SLijo Lazar
40076da73f0SLijo Lazar if (adev->flags & AMD_IS_APU)
40176da73f0SLijo Lazar return 0;
40276da73f0SLijo Lazar
40376da73f0SLijo Lazar return attr->mode;
40476da73f0SLijo Lazar }
40576da73f0SLijo Lazar
40676da73f0SLijo Lazar static const struct attribute_group amdgpu_board_attrs_group = {
40776da73f0SLijo Lazar .attrs = amdgpu_board_attrs,
40876da73f0SLijo Lazar .is_visible = amdgpu_board_attrs_is_visible
40976da73f0SLijo Lazar };
41076da73f0SLijo Lazar
4115494d864SAlex Deucher static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev);
4125494d864SAlex Deucher
413bd607166SKent Russell
414bd607166SKent Russell /**
415b98c6299SAlex Deucher * amdgpu_device_supports_px - Is the device a dGPU with ATPX power control
416fd496ca8SAlex Deucher *
417fd496ca8SAlex Deucher * @dev: drm_device pointer
418fd496ca8SAlex Deucher *
419b98c6299SAlex Deucher * Returns true if the device is a dGPU with ATPX power control,
420fd496ca8SAlex Deucher * otherwise return false.
421fd496ca8SAlex Deucher */
amdgpu_device_supports_px(struct drm_device * dev)422b98c6299SAlex Deucher bool amdgpu_device_supports_px(struct drm_device *dev)
423fd496ca8SAlex Deucher {
424fd496ca8SAlex Deucher struct amdgpu_device *adev = drm_to_adev(dev);
425fd496ca8SAlex Deucher
426b98c6299SAlex Deucher if ((adev->flags & AMD_IS_PX) && !amdgpu_is_atpx_hybrid())
427fd496ca8SAlex Deucher return true;
428fd496ca8SAlex Deucher return false;
429fd496ca8SAlex Deucher }
430fd496ca8SAlex Deucher
431fd496ca8SAlex Deucher /**
4320330b848SAlex Deucher * amdgpu_device_supports_boco - Is the device a dGPU with ACPI power resources
433e3ecdffaSAlex Deucher *
434e3ecdffaSAlex Deucher * @dev: drm_device pointer
435e3ecdffaSAlex Deucher *
436b98c6299SAlex Deucher * Returns true if the device is a dGPU with ACPI power control,
437e3ecdffaSAlex Deucher * otherwise return false.
438e3ecdffaSAlex Deucher */
amdgpu_device_supports_boco(struct drm_device * dev)43931af062aSAlex Deucher bool amdgpu_device_supports_boco(struct drm_device *dev)
440d38ceaf9SAlex Deucher {
4411348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(dev);
442d38ceaf9SAlex Deucher
4431ad5bdc2SMario Limonciello if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
4441ad5bdc2SMario Limonciello return false;
4451ad5bdc2SMario Limonciello
446b98c6299SAlex Deucher if (adev->has_pr3 ||
447b98c6299SAlex Deucher ((adev->flags & AMD_IS_PX) && amdgpu_is_atpx_hybrid()))
448d38ceaf9SAlex Deucher return true;
449d38ceaf9SAlex Deucher return false;
450d38ceaf9SAlex Deucher }
451d38ceaf9SAlex Deucher
452e35e2b11STianci.Yin /**
453a69cba42SAlex Deucher * amdgpu_device_supports_baco - Does the device support BACO
454a69cba42SAlex Deucher *
455a69cba42SAlex Deucher * @dev: drm_device pointer
456a69cba42SAlex Deucher *
457b2207dc6SMa Jun * Return:
458a567db80SRandy Dunlap * 1 if the device supports BACO;
459a567db80SRandy Dunlap * 3 if the device supports MACO (only works if BACO is supported)
460b2207dc6SMa Jun * otherwise return 0.
461a69cba42SAlex Deucher */
amdgpu_device_supports_baco(struct drm_device * dev)462b2207dc6SMa Jun int amdgpu_device_supports_baco(struct drm_device *dev)
463a69cba42SAlex Deucher {
4641348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(dev);
465a69cba42SAlex Deucher
466a69cba42SAlex Deucher return amdgpu_asic_supports_baco(adev);
467a69cba42SAlex Deucher }
468a69cba42SAlex Deucher
amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device * adev)46913478532SMa Jun void amdgpu_device_detect_runtime_pm_mode(struct amdgpu_device *adev)
47013478532SMa Jun {
47113478532SMa Jun struct drm_device *dev;
47213478532SMa Jun int bamaco_support;
47313478532SMa Jun
47413478532SMa Jun dev = adev_to_drm(adev);
47513478532SMa Jun
47613478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_NONE;
47713478532SMa Jun bamaco_support = amdgpu_device_supports_baco(dev);
47813478532SMa Jun
47913478532SMa Jun switch (amdgpu_runtime_pm) {
48013478532SMa Jun case 2:
48113478532SMa Jun if (bamaco_support & MACO_SUPPORT) {
48213478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_BAMACO;
48313478532SMa Jun dev_info(adev->dev, "Forcing BAMACO for runtime pm\n");
48413478532SMa Jun } else if (bamaco_support == BACO_SUPPORT) {
48513478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
48613478532SMa Jun dev_info(adev->dev, "Requested mode BAMACO not available,fallback to use BACO\n");
48713478532SMa Jun }
48813478532SMa Jun break;
48913478532SMa Jun case 1:
49013478532SMa Jun if (bamaco_support & BACO_SUPPORT) {
49113478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
49213478532SMa Jun dev_info(adev->dev, "Forcing BACO for runtime pm\n");
49313478532SMa Jun }
49413478532SMa Jun break;
49513478532SMa Jun case -1:
49613478532SMa Jun case -2:
49713478532SMa Jun if (amdgpu_device_supports_px(dev)) { /* enable PX as runtime mode */
49813478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_PX;
49913478532SMa Jun dev_info(adev->dev, "Using ATPX for runtime pm\n");
50013478532SMa Jun } else if (amdgpu_device_supports_boco(dev)) { /* enable boco as runtime mode */
50113478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_BOCO;
50213478532SMa Jun dev_info(adev->dev, "Using BOCO for runtime pm\n");
50313478532SMa Jun } else {
50413478532SMa Jun if (!bamaco_support)
50513478532SMa Jun goto no_runtime_pm;
50613478532SMa Jun
50713478532SMa Jun switch (adev->asic_type) {
50813478532SMa Jun case CHIP_VEGA20:
50913478532SMa Jun case CHIP_ARCTURUS:
51013478532SMa Jun /* BACO are not supported on vega20 and arctrus */
51113478532SMa Jun break;
51213478532SMa Jun case CHIP_VEGA10:
51313478532SMa Jun /* enable BACO as runpm mode if noretry=0 */
51413478532SMa Jun if (!adev->gmc.noretry)
51513478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
51613478532SMa Jun break;
51713478532SMa Jun default:
51813478532SMa Jun /* enable BACO as runpm mode on CI+ */
51913478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_BACO;
52013478532SMa Jun break;
52113478532SMa Jun }
52213478532SMa Jun
52313478532SMa Jun if (adev->pm.rpm_mode == AMDGPU_RUNPM_BACO) {
52413478532SMa Jun if (bamaco_support & MACO_SUPPORT) {
52513478532SMa Jun adev->pm.rpm_mode = AMDGPU_RUNPM_BAMACO;
52613478532SMa Jun dev_info(adev->dev, "Using BAMACO for runtime pm\n");
52713478532SMa Jun } else {
52813478532SMa Jun dev_info(adev->dev, "Using BACO for runtime pm\n");
52913478532SMa Jun }
53013478532SMa Jun }
53113478532SMa Jun }
53213478532SMa Jun break;
53313478532SMa Jun case 0:
53413478532SMa Jun dev_info(adev->dev, "runtime pm is manually disabled\n");
53513478532SMa Jun break;
53613478532SMa Jun default:
53713478532SMa Jun break;
53813478532SMa Jun }
53913478532SMa Jun
54013478532SMa Jun no_runtime_pm:
54113478532SMa Jun if (adev->pm.rpm_mode == AMDGPU_RUNPM_NONE)
54213478532SMa Jun dev_info(adev->dev, "Runtime PM not available\n");
54313478532SMa Jun }
5443fa8f89dSSathishkumar S /**
5453fa8f89dSSathishkumar S * amdgpu_device_supports_smart_shift - Is the device dGPU with
5463fa8f89dSSathishkumar S * smart shift support
5473fa8f89dSSathishkumar S *
5483fa8f89dSSathishkumar S * @dev: drm_device pointer
5493fa8f89dSSathishkumar S *
5503fa8f89dSSathishkumar S * Returns true if the device is a dGPU with Smart Shift support,
5513fa8f89dSSathishkumar S * otherwise returns false.
5523fa8f89dSSathishkumar S */
amdgpu_device_supports_smart_shift(struct drm_device * dev)5533fa8f89dSSathishkumar S bool amdgpu_device_supports_smart_shift(struct drm_device *dev)
5543fa8f89dSSathishkumar S {
5553fa8f89dSSathishkumar S return (amdgpu_device_supports_boco(dev) &&
5563fa8f89dSSathishkumar S amdgpu_acpi_is_power_shift_control_supported());
5573fa8f89dSSathishkumar S }
5583fa8f89dSSathishkumar S
5596e3cd2a9SMauro Carvalho Chehab /*
5606e3cd2a9SMauro Carvalho Chehab * VRAM access helper functions
5616e3cd2a9SMauro Carvalho Chehab */
5626e3cd2a9SMauro Carvalho Chehab
563a69cba42SAlex Deucher /**
564048af66bSKevin Wang * amdgpu_device_mm_access - access vram by MM_INDEX/MM_DATA
565e35e2b11STianci.Yin *
566e35e2b11STianci.Yin * @adev: amdgpu_device pointer
567e35e2b11STianci.Yin * @pos: offset of the buffer in vram
568e35e2b11STianci.Yin * @buf: virtual address of the buffer in system memory
569e35e2b11STianci.Yin * @size: read/write size, sizeof(@buf) must > @size
570e35e2b11STianci.Yin * @write: true - write to vram, otherwise - read from vram
571e35e2b11STianci.Yin */
amdgpu_device_mm_access(struct amdgpu_device * adev,loff_t pos,void * buf,size_t size,bool write)572048af66bSKevin Wang void amdgpu_device_mm_access(struct amdgpu_device *adev, loff_t pos,
573048af66bSKevin Wang void *buf, size_t size, bool write)
574e35e2b11STianci.Yin {
575e35e2b11STianci.Yin unsigned long flags;
576048af66bSKevin Wang uint32_t hi = ~0, tmp = 0;
577048af66bSKevin Wang uint32_t *data = buf;
578ce05ac56SChristian König uint64_t last;
579f89f8c6bSAndrey Grodzovsky int idx;
580e35e2b11STianci.Yin
581c58a863bSGuchun Chen if (!drm_dev_enter(adev_to_drm(adev), &idx))
582f89f8c6bSAndrey Grodzovsky return;
5839d11eb0dSChristian König
584048af66bSKevin Wang BUG_ON(!IS_ALIGNED(pos, 4) || !IS_ALIGNED(size, 4));
585048af66bSKevin Wang
586048af66bSKevin Wang spin_lock_irqsave(&adev->mmio_idx_lock, flags);
587048af66bSKevin Wang for (last = pos + size; pos < last; pos += 4) {
588048af66bSKevin Wang tmp = pos >> 31;
589048af66bSKevin Wang
590048af66bSKevin Wang WREG32_NO_KIQ(mmMM_INDEX, ((uint32_t)pos) | 0x80000000);
591048af66bSKevin Wang if (tmp != hi) {
592048af66bSKevin Wang WREG32_NO_KIQ(mmMM_INDEX_HI, tmp);
593048af66bSKevin Wang hi = tmp;
594048af66bSKevin Wang }
595048af66bSKevin Wang if (write)
596048af66bSKevin Wang WREG32_NO_KIQ(mmMM_DATA, *data++);
597048af66bSKevin Wang else
598048af66bSKevin Wang *data++ = RREG32_NO_KIQ(mmMM_DATA);
599048af66bSKevin Wang }
600048af66bSKevin Wang
601048af66bSKevin Wang spin_unlock_irqrestore(&adev->mmio_idx_lock, flags);
602048af66bSKevin Wang drm_dev_exit(idx);
603048af66bSKevin Wang }
604048af66bSKevin Wang
605048af66bSKevin Wang /**
606a567db80SRandy Dunlap * amdgpu_device_aper_access - access vram by vram aperture
607048af66bSKevin Wang *
608048af66bSKevin Wang * @adev: amdgpu_device pointer
609048af66bSKevin Wang * @pos: offset of the buffer in vram
610048af66bSKevin Wang * @buf: virtual address of the buffer in system memory
611048af66bSKevin Wang * @size: read/write size, sizeof(@buf) must > @size
612048af66bSKevin Wang * @write: true - write to vram, otherwise - read from vram
613048af66bSKevin Wang *
614048af66bSKevin Wang * The return value means how many bytes have been transferred.
615048af66bSKevin Wang */
amdgpu_device_aper_access(struct amdgpu_device * adev,loff_t pos,void * buf,size_t size,bool write)616048af66bSKevin Wang size_t amdgpu_device_aper_access(struct amdgpu_device *adev, loff_t pos,
617048af66bSKevin Wang void *buf, size_t size, bool write)
618048af66bSKevin Wang {
6199d11eb0dSChristian König #ifdef CONFIG_64BIT
620048af66bSKevin Wang void __iomem *addr;
621048af66bSKevin Wang size_t count = 0;
622048af66bSKevin Wang uint64_t last;
623048af66bSKevin Wang
624048af66bSKevin Wang if (!adev->mman.aper_base_kaddr)
625048af66bSKevin Wang return 0;
626048af66bSKevin Wang
6279d11eb0dSChristian König last = min(pos + size, adev->gmc.visible_vram_size);
6289d11eb0dSChristian König if (last > pos) {
629048af66bSKevin Wang addr = adev->mman.aper_base_kaddr + pos;
630048af66bSKevin Wang count = last - pos;
6319d11eb0dSChristian König
6329d11eb0dSChristian König if (write) {
6339d11eb0dSChristian König memcpy_toio(addr, buf, count);
6344c452b5cSSrinivasan Shanmugam /* Make sure HDP write cache flush happens without any reordering
6354c452b5cSSrinivasan Shanmugam * after the system memory contents are sent over PCIe device
6364c452b5cSSrinivasan Shanmugam */
6379d11eb0dSChristian König mb();
638810085ddSEric Huang amdgpu_device_flush_hdp(adev, NULL);
6399d11eb0dSChristian König } else {
640810085ddSEric Huang amdgpu_device_invalidate_hdp(adev, NULL);
6414c452b5cSSrinivasan Shanmugam /* Make sure HDP read cache is invalidated before issuing a read
6424c452b5cSSrinivasan Shanmugam * to the PCIe device
6434c452b5cSSrinivasan Shanmugam */
6449d11eb0dSChristian König mb();
6459d11eb0dSChristian König memcpy_fromio(buf, addr, count);
6469d11eb0dSChristian König }
6479d11eb0dSChristian König
648048af66bSKevin Wang }
6499d11eb0dSChristian König
650048af66bSKevin Wang return count;
651048af66bSKevin Wang #else
652048af66bSKevin Wang return 0;
653048af66bSKevin Wang #endif
654048af66bSKevin Wang }
655048af66bSKevin Wang
656048af66bSKevin Wang /**
657048af66bSKevin Wang * amdgpu_device_vram_access - read/write a buffer in vram
658048af66bSKevin Wang *
659048af66bSKevin Wang * @adev: amdgpu_device pointer
660048af66bSKevin Wang * @pos: offset of the buffer in vram
661048af66bSKevin Wang * @buf: virtual address of the buffer in system memory
662048af66bSKevin Wang * @size: read/write size, sizeof(@buf) must > @size
663048af66bSKevin Wang * @write: true - write to vram, otherwise - read from vram
664048af66bSKevin Wang */
amdgpu_device_vram_access(struct amdgpu_device * adev,loff_t pos,void * buf,size_t size,bool write)665048af66bSKevin Wang void amdgpu_device_vram_access(struct amdgpu_device *adev, loff_t pos,
666048af66bSKevin Wang void *buf, size_t size, bool write)
667048af66bSKevin Wang {
668048af66bSKevin Wang size_t count;
669048af66bSKevin Wang
670048af66bSKevin Wang /* try to using vram apreature to access vram first */
671048af66bSKevin Wang count = amdgpu_device_aper_access(adev, pos, buf, size, write);
6729d11eb0dSChristian König size -= count;
673048af66bSKevin Wang if (size) {
674048af66bSKevin Wang /* using MM to access rest vram */
675048af66bSKevin Wang pos += count;
676048af66bSKevin Wang buf += count;
677048af66bSKevin Wang amdgpu_device_mm_access(adev, pos, buf, size, write);
6789d11eb0dSChristian König }
679e35e2b11STianci.Yin }
680e35e2b11STianci.Yin
681d38ceaf9SAlex Deucher /*
682f7ee1874SHawking Zhang * register access helper functions.
683d38ceaf9SAlex Deucher */
68456b53c0bSDennis Li
68556b53c0bSDennis Li /* Check if hw access should be skipped because of hotplug or device error */
amdgpu_device_skip_hw_access(struct amdgpu_device * adev)68656b53c0bSDennis Li bool amdgpu_device_skip_hw_access(struct amdgpu_device *adev)
68756b53c0bSDennis Li {
6887afefb81SAndrey Grodzovsky if (adev->no_hw_access)
68956b53c0bSDennis Li return true;
69056b53c0bSDennis Li
69156b53c0bSDennis Li #ifdef CONFIG_LOCKDEP
69256b53c0bSDennis Li /*
69356b53c0bSDennis Li * This is a bit complicated to understand, so worth a comment. What we assert
69456b53c0bSDennis Li * here is that the GPU reset is not running on another thread in parallel.
69556b53c0bSDennis Li *
69656b53c0bSDennis Li * For this we trylock the read side of the reset semaphore, if that succeeds
697a567db80SRandy Dunlap * we know that the reset is not running in parallel.
69856b53c0bSDennis Li *
69956b53c0bSDennis Li * If the trylock fails we assert that we are either already holding the read
70056b53c0bSDennis Li * side of the lock or are the reset thread itself and hold the write side of
70156b53c0bSDennis Li * the lock.
70256b53c0bSDennis Li */
70356b53c0bSDennis Li if (in_task()) {
704d0fb18b5SAndrey Grodzovsky if (down_read_trylock(&adev->reset_domain->sem))
705d0fb18b5SAndrey Grodzovsky up_read(&adev->reset_domain->sem);
70656b53c0bSDennis Li else
707d0fb18b5SAndrey Grodzovsky lockdep_assert_held(&adev->reset_domain->sem);
70856b53c0bSDennis Li }
70956b53c0bSDennis Li #endif
71056b53c0bSDennis Li return false;
71156b53c0bSDennis Li }
71256b53c0bSDennis Li
713e3ecdffaSAlex Deucher /**
714f7ee1874SHawking Zhang * amdgpu_device_rreg - read a memory mapped IO or indirect register
715e3ecdffaSAlex Deucher *
716e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
717e3ecdffaSAlex Deucher * @reg: dword aligned register offset
718e3ecdffaSAlex Deucher * @acc_flags: access flags which require special behavior
719e3ecdffaSAlex Deucher *
720e3ecdffaSAlex Deucher * Returns the 32 bit value from the offset specified.
721e3ecdffaSAlex Deucher */
amdgpu_device_rreg(struct amdgpu_device * adev,uint32_t reg,uint32_t acc_flags)722f7ee1874SHawking Zhang uint32_t amdgpu_device_rreg(struct amdgpu_device *adev,
723f7ee1874SHawking Zhang uint32_t reg, uint32_t acc_flags)
724d38ceaf9SAlex Deucher {
725f4b373f4STom St Denis uint32_t ret;
726f4b373f4STom St Denis
72756b53c0bSDennis Li if (amdgpu_device_skip_hw_access(adev))
728bf36b52eSAndrey Grodzovsky return 0;
729bf36b52eSAndrey Grodzovsky
730f7ee1874SHawking Zhang if ((reg * 4) < adev->rmmio_size) {
731f7ee1874SHawking Zhang if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
732f7ee1874SHawking Zhang amdgpu_sriov_runtime(adev) &&
733d0fb18b5SAndrey Grodzovsky down_read_trylock(&adev->reset_domain->sem)) {
73485150626SVictor Lu ret = amdgpu_kiq_rreg(adev, reg, 0);
735d0fb18b5SAndrey Grodzovsky up_read(&adev->reset_domain->sem);
736f7ee1874SHawking Zhang } else {
737f4b373f4STom St Denis ret = readl(((void __iomem *)adev->rmmio) + (reg * 4));
738f7ee1874SHawking Zhang }
739f7ee1874SHawking Zhang } else {
740f7ee1874SHawking Zhang ret = adev->pcie_rreg(adev, reg * 4);
741e78b579dSHawking Zhang }
74281202807SDennis Li
743f7ee1874SHawking Zhang trace_amdgpu_device_rreg(adev->pdev->device, reg, ret);
744f7ee1874SHawking Zhang
745f4b373f4STom St Denis return ret;
746d38ceaf9SAlex Deucher }
747d38ceaf9SAlex Deucher
748421a2a30SMonk Liu /*
749421a2a30SMonk Liu * MMIO register read with bytes helper functions
750421a2a30SMonk Liu * @offset:bytes offset from MMIO start
751421a2a30SMonk Liu */
752421a2a30SMonk Liu
753e3ecdffaSAlex Deucher /**
754e3ecdffaSAlex Deucher * amdgpu_mm_rreg8 - read a memory mapped IO register
755e3ecdffaSAlex Deucher *
756e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
757e3ecdffaSAlex Deucher * @offset: byte aligned register offset
758e3ecdffaSAlex Deucher *
759e3ecdffaSAlex Deucher * Returns the 8 bit value from the offset specified.
760e3ecdffaSAlex Deucher */
amdgpu_mm_rreg8(struct amdgpu_device * adev,uint32_t offset)7617cbbc745SAndrey Grodzovsky uint8_t amdgpu_mm_rreg8(struct amdgpu_device *adev, uint32_t offset)
7627cbbc745SAndrey Grodzovsky {
76356b53c0bSDennis Li if (amdgpu_device_skip_hw_access(adev))
764bf36b52eSAndrey Grodzovsky return 0;
765bf36b52eSAndrey Grodzovsky
766421a2a30SMonk Liu if (offset < adev->rmmio_size)
767421a2a30SMonk Liu return (readb(adev->rmmio + offset));
768421a2a30SMonk Liu BUG();
769421a2a30SMonk Liu }
770421a2a30SMonk Liu
77185150626SVictor Lu
77285150626SVictor Lu /**
77385150626SVictor Lu * amdgpu_device_xcc_rreg - read a memory mapped IO or indirect register with specific XCC
77485150626SVictor Lu *
77585150626SVictor Lu * @adev: amdgpu_device pointer
77685150626SVictor Lu * @reg: dword aligned register offset
77785150626SVictor Lu * @acc_flags: access flags which require special behavior
77885150626SVictor Lu * @xcc_id: xcc accelerated compute core id
77985150626SVictor Lu *
78085150626SVictor Lu * Returns the 32 bit value from the offset specified.
78185150626SVictor Lu */
amdgpu_device_xcc_rreg(struct amdgpu_device * adev,uint32_t reg,uint32_t acc_flags,uint32_t xcc_id)78285150626SVictor Lu uint32_t amdgpu_device_xcc_rreg(struct amdgpu_device *adev,
78385150626SVictor Lu uint32_t reg, uint32_t acc_flags,
78485150626SVictor Lu uint32_t xcc_id)
78585150626SVictor Lu {
78685150626SVictor Lu uint32_t ret, rlcg_flag;
78785150626SVictor Lu
78885150626SVictor Lu if (amdgpu_device_skip_hw_access(adev))
78985150626SVictor Lu return 0;
79085150626SVictor Lu
79185150626SVictor Lu if ((reg * 4) < adev->rmmio_size) {
79285150626SVictor Lu if (amdgpu_sriov_vf(adev) &&
79385150626SVictor Lu !amdgpu_sriov_runtime(adev) &&
79485150626SVictor Lu adev->gfx.rlc.rlcg_reg_access_supported &&
79585150626SVictor Lu amdgpu_virt_get_rlcg_reg_access_flag(adev, acc_flags,
79685150626SVictor Lu GC_HWIP, false,
79785150626SVictor Lu &rlcg_flag)) {
798e21e0b78SVictor Zhao ret = amdgpu_virt_rlcg_reg_rw(adev, reg, 0, rlcg_flag, GET_INST(GC, xcc_id));
79985150626SVictor Lu } else if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
80085150626SVictor Lu amdgpu_sriov_runtime(adev) &&
80185150626SVictor Lu down_read_trylock(&adev->reset_domain->sem)) {
80285150626SVictor Lu ret = amdgpu_kiq_rreg(adev, reg, xcc_id);
80385150626SVictor Lu up_read(&adev->reset_domain->sem);
80485150626SVictor Lu } else {
80585150626SVictor Lu ret = readl(((void __iomem *)adev->rmmio) + (reg * 4));
80685150626SVictor Lu }
80785150626SVictor Lu } else {
80885150626SVictor Lu ret = adev->pcie_rreg(adev, reg * 4);
80985150626SVictor Lu }
81085150626SVictor Lu
81185150626SVictor Lu return ret;
81285150626SVictor Lu }
81385150626SVictor Lu
814421a2a30SMonk Liu /*
815421a2a30SMonk Liu * MMIO register write with bytes helper functions
816421a2a30SMonk Liu * @offset:bytes offset from MMIO start
817421a2a30SMonk Liu * @value: the value want to be written to the register
818421a2a30SMonk Liu */
819b8920e1eSSrinivasan Shanmugam
820e3ecdffaSAlex Deucher /**
821e3ecdffaSAlex Deucher * amdgpu_mm_wreg8 - read a memory mapped IO register
822e3ecdffaSAlex Deucher *
823e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
824e3ecdffaSAlex Deucher * @offset: byte aligned register offset
825e3ecdffaSAlex Deucher * @value: 8 bit value to write
826e3ecdffaSAlex Deucher *
827e3ecdffaSAlex Deucher * Writes the value specified to the offset specified.
828e3ecdffaSAlex Deucher */
amdgpu_mm_wreg8(struct amdgpu_device * adev,uint32_t offset,uint8_t value)8297cbbc745SAndrey Grodzovsky void amdgpu_mm_wreg8(struct amdgpu_device *adev, uint32_t offset, uint8_t value)
8307cbbc745SAndrey Grodzovsky {
83156b53c0bSDennis Li if (amdgpu_device_skip_hw_access(adev))
832bf36b52eSAndrey Grodzovsky return;
833bf36b52eSAndrey Grodzovsky
834421a2a30SMonk Liu if (offset < adev->rmmio_size)
835421a2a30SMonk Liu writeb(value, adev->rmmio + offset);
836421a2a30SMonk Liu else
837421a2a30SMonk Liu BUG();
838421a2a30SMonk Liu }
839421a2a30SMonk Liu
840e3ecdffaSAlex Deucher /**
841f7ee1874SHawking Zhang * amdgpu_device_wreg - write to a memory mapped IO or indirect register
8422e0cc4d4SMonk Liu *
8432e0cc4d4SMonk Liu * @adev: amdgpu_device pointer
8442e0cc4d4SMonk Liu * @reg: dword aligned register offset
8452e0cc4d4SMonk Liu * @v: 32 bit value to write to the register
8462e0cc4d4SMonk Liu * @acc_flags: access flags which require special behavior
8472e0cc4d4SMonk Liu *
8482e0cc4d4SMonk Liu * Writes the value specified to the offset specified.
8492e0cc4d4SMonk Liu */
amdgpu_device_wreg(struct amdgpu_device * adev,uint32_t reg,uint32_t v,uint32_t acc_flags)850f7ee1874SHawking Zhang void amdgpu_device_wreg(struct amdgpu_device *adev,
851f7ee1874SHawking Zhang uint32_t reg, uint32_t v,
8522e0cc4d4SMonk Liu uint32_t acc_flags)
8532e0cc4d4SMonk Liu {
85456b53c0bSDennis Li if (amdgpu_device_skip_hw_access(adev))
855bf36b52eSAndrey Grodzovsky return;
856bf36b52eSAndrey Grodzovsky
857f7ee1874SHawking Zhang if ((reg * 4) < adev->rmmio_size) {
858f7ee1874SHawking Zhang if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
859f7ee1874SHawking Zhang amdgpu_sriov_runtime(adev) &&
860d0fb18b5SAndrey Grodzovsky down_read_trylock(&adev->reset_domain->sem)) {
86185150626SVictor Lu amdgpu_kiq_wreg(adev, reg, v, 0);
862d0fb18b5SAndrey Grodzovsky up_read(&adev->reset_domain->sem);
863f7ee1874SHawking Zhang } else {
864f7ee1874SHawking Zhang writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
865f7ee1874SHawking Zhang }
866f7ee1874SHawking Zhang } else {
867f7ee1874SHawking Zhang adev->pcie_wreg(adev, reg * 4, v);
86881202807SDennis Li }
8692e0cc4d4SMonk Liu
870f7ee1874SHawking Zhang trace_amdgpu_device_wreg(adev->pdev->device, reg, v);
8712e0cc4d4SMonk Liu }
8722e0cc4d4SMonk Liu
87303f2abb0SYann Dirson /**
8744cc9f86fSTom St Denis * amdgpu_mm_wreg_mmio_rlc - write register either with direct/indirect mmio or with RLC path if in range
8752e0cc4d4SMonk Liu *
87671579346SRajneesh Bhardwaj * @adev: amdgpu_device pointer
87771579346SRajneesh Bhardwaj * @reg: mmio/rlc register
87871579346SRajneesh Bhardwaj * @v: value to write
8798057a9d6SLee Jones * @xcc_id: xcc accelerated compute core id
88071579346SRajneesh Bhardwaj *
88171579346SRajneesh Bhardwaj * this function is invoked only for the debugfs register access
88203f2abb0SYann Dirson */
amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device * adev,uint32_t reg,uint32_t v,uint32_t xcc_id)883f7ee1874SHawking Zhang void amdgpu_mm_wreg_mmio_rlc(struct amdgpu_device *adev,
8848ed49dd1SVictor Lu uint32_t reg, uint32_t v,
8858ed49dd1SVictor Lu uint32_t xcc_id)
8862e0cc4d4SMonk Liu {
88756b53c0bSDennis Li if (amdgpu_device_skip_hw_access(adev))
888bf36b52eSAndrey Grodzovsky return;
889bf36b52eSAndrey Grodzovsky
8902e0cc4d4SMonk Liu if (amdgpu_sriov_fullaccess(adev) &&
8912e0cc4d4SMonk Liu adev->gfx.rlc.funcs &&
8922e0cc4d4SMonk Liu adev->gfx.rlc.funcs->is_rlcg_access_range) {
8932e0cc4d4SMonk Liu if (adev->gfx.rlc.funcs->is_rlcg_access_range(adev, reg))
8948ed49dd1SVictor Lu return amdgpu_sriov_wreg(adev, reg, v, 0, 0, xcc_id);
8954cc9f86fSTom St Denis } else if ((reg * 4) >= adev->rmmio_size) {
8964cc9f86fSTom St Denis adev->pcie_wreg(adev, reg * 4, v);
897f7ee1874SHawking Zhang } else {
898f7ee1874SHawking Zhang writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
8992e0cc4d4SMonk Liu }
9002e0cc4d4SMonk Liu }
9012e0cc4d4SMonk Liu
9022e0cc4d4SMonk Liu /**
90385150626SVictor Lu * amdgpu_device_xcc_wreg - write to a memory mapped IO or indirect register with specific XCC
90485150626SVictor Lu *
90585150626SVictor Lu * @adev: amdgpu_device pointer
90685150626SVictor Lu * @reg: dword aligned register offset
90785150626SVictor Lu * @v: 32 bit value to write to the register
90885150626SVictor Lu * @acc_flags: access flags which require special behavior
90985150626SVictor Lu * @xcc_id: xcc accelerated compute core id
91085150626SVictor Lu *
91185150626SVictor Lu * Writes the value specified to the offset specified.
91285150626SVictor Lu */
amdgpu_device_xcc_wreg(struct amdgpu_device * adev,uint32_t reg,uint32_t v,uint32_t acc_flags,uint32_t xcc_id)91385150626SVictor Lu void amdgpu_device_xcc_wreg(struct amdgpu_device *adev,
91485150626SVictor Lu uint32_t reg, uint32_t v,
91585150626SVictor Lu uint32_t acc_flags, uint32_t xcc_id)
91685150626SVictor Lu {
91785150626SVictor Lu uint32_t rlcg_flag;
91885150626SVictor Lu
91985150626SVictor Lu if (amdgpu_device_skip_hw_access(adev))
92085150626SVictor Lu return;
92185150626SVictor Lu
92285150626SVictor Lu if ((reg * 4) < adev->rmmio_size) {
92385150626SVictor Lu if (amdgpu_sriov_vf(adev) &&
92485150626SVictor Lu !amdgpu_sriov_runtime(adev) &&
92585150626SVictor Lu adev->gfx.rlc.rlcg_reg_access_supported &&
92685150626SVictor Lu amdgpu_virt_get_rlcg_reg_access_flag(adev, acc_flags,
92785150626SVictor Lu GC_HWIP, true,
92885150626SVictor Lu &rlcg_flag)) {
929e21e0b78SVictor Zhao amdgpu_virt_rlcg_reg_rw(adev, reg, v, rlcg_flag, GET_INST(GC, xcc_id));
93085150626SVictor Lu } else if (!(acc_flags & AMDGPU_REGS_NO_KIQ) &&
93185150626SVictor Lu amdgpu_sriov_runtime(adev) &&
93285150626SVictor Lu down_read_trylock(&adev->reset_domain->sem)) {
93385150626SVictor Lu amdgpu_kiq_wreg(adev, reg, v, xcc_id);
93485150626SVictor Lu up_read(&adev->reset_domain->sem);
93585150626SVictor Lu } else {
93685150626SVictor Lu writel(v, ((void __iomem *)adev->rmmio) + (reg * 4));
93785150626SVictor Lu }
93885150626SVictor Lu } else {
93985150626SVictor Lu adev->pcie_wreg(adev, reg * 4, v);
94085150626SVictor Lu }
94185150626SVictor Lu }
94285150626SVictor Lu
94385150626SVictor Lu /**
9441bba3683SHawking Zhang * amdgpu_device_indirect_rreg - read an indirect register
9451bba3683SHawking Zhang *
9461bba3683SHawking Zhang * @adev: amdgpu_device pointer
94722f453fbSLee Jones * @reg_addr: indirect register address to read from
9481bba3683SHawking Zhang *
9491bba3683SHawking Zhang * Returns the value of indirect register @reg_addr
9501bba3683SHawking Zhang */
amdgpu_device_indirect_rreg(struct amdgpu_device * adev,u32 reg_addr)9511bba3683SHawking Zhang u32 amdgpu_device_indirect_rreg(struct amdgpu_device *adev,
9521bba3683SHawking Zhang u32 reg_addr)
9531bba3683SHawking Zhang {
95465ba96e9SHawking Zhang unsigned long flags, pcie_index, pcie_data;
9551bba3683SHawking Zhang void __iomem *pcie_index_offset;
9561bba3683SHawking Zhang void __iomem *pcie_data_offset;
95765ba96e9SHawking Zhang u32 r;
95865ba96e9SHawking Zhang
95965ba96e9SHawking Zhang pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev);
96065ba96e9SHawking Zhang pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev);
9611bba3683SHawking Zhang
9621bba3683SHawking Zhang spin_lock_irqsave(&adev->pcie_idx_lock, flags);
9631bba3683SHawking Zhang pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
9641bba3683SHawking Zhang pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4;
9651bba3683SHawking Zhang
9661bba3683SHawking Zhang writel(reg_addr, pcie_index_offset);
9671bba3683SHawking Zhang readl(pcie_index_offset);
9681bba3683SHawking Zhang r = readl(pcie_data_offset);
9691bba3683SHawking Zhang spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
9701bba3683SHawking Zhang
9711bba3683SHawking Zhang return r;
9721bba3683SHawking Zhang }
9731bba3683SHawking Zhang
amdgpu_device_indirect_rreg_ext(struct amdgpu_device * adev,u64 reg_addr)9740c552ed3SLe Ma u32 amdgpu_device_indirect_rreg_ext(struct amdgpu_device *adev,
9750c552ed3SLe Ma u64 reg_addr)
9760c552ed3SLe Ma {
9770c552ed3SLe Ma unsigned long flags, pcie_index, pcie_index_hi, pcie_data;
9780c552ed3SLe Ma u32 r;
9790c552ed3SLe Ma void __iomem *pcie_index_offset;
9800c552ed3SLe Ma void __iomem *pcie_index_hi_offset;
9810c552ed3SLe Ma void __iomem *pcie_data_offset;
9820c552ed3SLe Ma
983ad390542SHawking Zhang if (unlikely(!adev->nbio.funcs)) {
984ad390542SHawking Zhang pcie_index = AMDGPU_PCIE_INDEX_FALLBACK;
985ad390542SHawking Zhang pcie_data = AMDGPU_PCIE_DATA_FALLBACK;
986ad390542SHawking Zhang } else {
9870c552ed3SLe Ma pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev);
9880c552ed3SLe Ma pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev);
989ad390542SHawking Zhang }
990ad390542SHawking Zhang
991ad390542SHawking Zhang if (reg_addr >> 32) {
992ad390542SHawking Zhang if (unlikely(!adev->nbio.funcs))
993ad390542SHawking Zhang pcie_index_hi = AMDGPU_PCIE_INDEX_HI_FALLBACK;
9940c552ed3SLe Ma else
995ad390542SHawking Zhang pcie_index_hi = adev->nbio.funcs->get_pcie_index_hi_offset(adev);
996ad390542SHawking Zhang } else {
9970c552ed3SLe Ma pcie_index_hi = 0;
998ad390542SHawking Zhang }
9990c552ed3SLe Ma
10000c552ed3SLe Ma spin_lock_irqsave(&adev->pcie_idx_lock, flags);
10010c552ed3SLe Ma pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
10020c552ed3SLe Ma pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4;
10030c552ed3SLe Ma if (pcie_index_hi != 0)
10040c552ed3SLe Ma pcie_index_hi_offset = (void __iomem *)adev->rmmio +
10050c552ed3SLe Ma pcie_index_hi * 4;
10060c552ed3SLe Ma
10070c552ed3SLe Ma writel(reg_addr, pcie_index_offset);
10080c552ed3SLe Ma readl(pcie_index_offset);
10090c552ed3SLe Ma if (pcie_index_hi != 0) {
10100c552ed3SLe Ma writel((reg_addr >> 32) & 0xff, pcie_index_hi_offset);
10110c552ed3SLe Ma readl(pcie_index_hi_offset);
10120c552ed3SLe Ma }
10130c552ed3SLe Ma r = readl(pcie_data_offset);
10140c552ed3SLe Ma
10150c552ed3SLe Ma /* clear the high bits */
10160c552ed3SLe Ma if (pcie_index_hi != 0) {
10170c552ed3SLe Ma writel(0, pcie_index_hi_offset);
10180c552ed3SLe Ma readl(pcie_index_hi_offset);
10190c552ed3SLe Ma }
10200c552ed3SLe Ma
10210c552ed3SLe Ma spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
10220c552ed3SLe Ma
10230c552ed3SLe Ma return r;
10240c552ed3SLe Ma }
10250c552ed3SLe Ma
10261bba3683SHawking Zhang /**
10271bba3683SHawking Zhang * amdgpu_device_indirect_rreg64 - read a 64bits indirect register
10281bba3683SHawking Zhang *
10291bba3683SHawking Zhang * @adev: amdgpu_device pointer
103022f453fbSLee Jones * @reg_addr: indirect register address to read from
10311bba3683SHawking Zhang *
10321bba3683SHawking Zhang * Returns the value of indirect register @reg_addr
10331bba3683SHawking Zhang */
amdgpu_device_indirect_rreg64(struct amdgpu_device * adev,u32 reg_addr)10341bba3683SHawking Zhang u64 amdgpu_device_indirect_rreg64(struct amdgpu_device *adev,
10351bba3683SHawking Zhang u32 reg_addr)
10361bba3683SHawking Zhang {
103765ba96e9SHawking Zhang unsigned long flags, pcie_index, pcie_data;
10381bba3683SHawking Zhang void __iomem *pcie_index_offset;
10391bba3683SHawking Zhang void __iomem *pcie_data_offset;
104065ba96e9SHawking Zhang u64 r;
104165ba96e9SHawking Zhang
104265ba96e9SHawking Zhang pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev);
104365ba96e9SHawking Zhang pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev);
10441bba3683SHawking Zhang
10451bba3683SHawking Zhang spin_lock_irqsave(&adev->pcie_idx_lock, flags);
10461bba3683SHawking Zhang pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
10471bba3683SHawking Zhang pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4;
10481bba3683SHawking Zhang
10491bba3683SHawking Zhang /* read low 32 bits */
10501bba3683SHawking Zhang writel(reg_addr, pcie_index_offset);
10511bba3683SHawking Zhang readl(pcie_index_offset);
10521bba3683SHawking Zhang r = readl(pcie_data_offset);
10531bba3683SHawking Zhang /* read high 32 bits */
10541bba3683SHawking Zhang writel(reg_addr + 4, pcie_index_offset);
10551bba3683SHawking Zhang readl(pcie_index_offset);
10561bba3683SHawking Zhang r |= ((u64)readl(pcie_data_offset) << 32);
10571bba3683SHawking Zhang spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
10581bba3683SHawking Zhang
10591bba3683SHawking Zhang return r;
10601bba3683SHawking Zhang }
10611bba3683SHawking Zhang
amdgpu_device_indirect_rreg64_ext(struct amdgpu_device * adev,u64 reg_addr)1062a76b2870SCandice Li u64 amdgpu_device_indirect_rreg64_ext(struct amdgpu_device *adev,
1063a76b2870SCandice Li u64 reg_addr)
1064a76b2870SCandice Li {
1065a76b2870SCandice Li unsigned long flags, pcie_index, pcie_data;
1066a76b2870SCandice Li unsigned long pcie_index_hi = 0;
1067a76b2870SCandice Li void __iomem *pcie_index_offset;
1068a76b2870SCandice Li void __iomem *pcie_index_hi_offset;
1069a76b2870SCandice Li void __iomem *pcie_data_offset;
1070a76b2870SCandice Li u64 r;
1071a76b2870SCandice Li
1072a76b2870SCandice Li pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev);
1073a76b2870SCandice Li pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev);
1074a76b2870SCandice Li if ((reg_addr >> 32) && (adev->nbio.funcs->get_pcie_index_hi_offset))
1075a76b2870SCandice Li pcie_index_hi = adev->nbio.funcs->get_pcie_index_hi_offset(adev);
1076a76b2870SCandice Li
1077a76b2870SCandice Li spin_lock_irqsave(&adev->pcie_idx_lock, flags);
1078a76b2870SCandice Li pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
1079a76b2870SCandice Li pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4;
1080a76b2870SCandice Li if (pcie_index_hi != 0)
1081a76b2870SCandice Li pcie_index_hi_offset = (void __iomem *)adev->rmmio +
1082a76b2870SCandice Li pcie_index_hi * 4;
1083a76b2870SCandice Li
1084a76b2870SCandice Li /* read low 32 bits */
1085a76b2870SCandice Li writel(reg_addr, pcie_index_offset);
1086a76b2870SCandice Li readl(pcie_index_offset);
1087a76b2870SCandice Li if (pcie_index_hi != 0) {
1088a76b2870SCandice Li writel((reg_addr >> 32) & 0xff, pcie_index_hi_offset);
1089a76b2870SCandice Li readl(pcie_index_hi_offset);
1090a76b2870SCandice Li }
1091a76b2870SCandice Li r = readl(pcie_data_offset);
1092a76b2870SCandice Li /* read high 32 bits */
1093a76b2870SCandice Li writel(reg_addr + 4, pcie_index_offset);
1094a76b2870SCandice Li readl(pcie_index_offset);
1095a76b2870SCandice Li if (pcie_index_hi != 0) {
1096a76b2870SCandice Li writel((reg_addr >> 32) & 0xff, pcie_index_hi_offset);
1097a76b2870SCandice Li readl(pcie_index_hi_offset);
1098a76b2870SCandice Li }
1099a76b2870SCandice Li r |= ((u64)readl(pcie_data_offset) << 32);
1100a76b2870SCandice Li
1101a76b2870SCandice Li /* clear the high bits */
1102a76b2870SCandice Li if (pcie_index_hi != 0) {
1103a76b2870SCandice Li writel(0, pcie_index_hi_offset);
1104a76b2870SCandice Li readl(pcie_index_hi_offset);
1105a76b2870SCandice Li }
1106a76b2870SCandice Li
1107a76b2870SCandice Li spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
1108a76b2870SCandice Li
1109a76b2870SCandice Li return r;
1110a76b2870SCandice Li }
1111a76b2870SCandice Li
11121bba3683SHawking Zhang /**
11131bba3683SHawking Zhang * amdgpu_device_indirect_wreg - write an indirect register address
11141bba3683SHawking Zhang *
11151bba3683SHawking Zhang * @adev: amdgpu_device pointer
11161bba3683SHawking Zhang * @reg_addr: indirect register offset
11171bba3683SHawking Zhang * @reg_data: indirect register data
11181bba3683SHawking Zhang *
11191bba3683SHawking Zhang */
amdgpu_device_indirect_wreg(struct amdgpu_device * adev,u32 reg_addr,u32 reg_data)11201bba3683SHawking Zhang void amdgpu_device_indirect_wreg(struct amdgpu_device *adev,
11211bba3683SHawking Zhang u32 reg_addr, u32 reg_data)
11221bba3683SHawking Zhang {
112365ba96e9SHawking Zhang unsigned long flags, pcie_index, pcie_data;
11241bba3683SHawking Zhang void __iomem *pcie_index_offset;
11251bba3683SHawking Zhang void __iomem *pcie_data_offset;
11261bba3683SHawking Zhang
112765ba96e9SHawking Zhang pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev);
112865ba96e9SHawking Zhang pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev);
112965ba96e9SHawking Zhang
11301bba3683SHawking Zhang spin_lock_irqsave(&adev->pcie_idx_lock, flags);
11311bba3683SHawking Zhang pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
11321bba3683SHawking Zhang pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4;
11331bba3683SHawking Zhang
11341bba3683SHawking Zhang writel(reg_addr, pcie_index_offset);
11351bba3683SHawking Zhang readl(pcie_index_offset);
11361bba3683SHawking Zhang writel(reg_data, pcie_data_offset);
11371bba3683SHawking Zhang readl(pcie_data_offset);
11381bba3683SHawking Zhang spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
11391bba3683SHawking Zhang }
11401bba3683SHawking Zhang
amdgpu_device_indirect_wreg_ext(struct amdgpu_device * adev,u64 reg_addr,u32 reg_data)11410c552ed3SLe Ma void amdgpu_device_indirect_wreg_ext(struct amdgpu_device *adev,
11420c552ed3SLe Ma u64 reg_addr, u32 reg_data)
11430c552ed3SLe Ma {
11440c552ed3SLe Ma unsigned long flags, pcie_index, pcie_index_hi, pcie_data;
11450c552ed3SLe Ma void __iomem *pcie_index_offset;
11460c552ed3SLe Ma void __iomem *pcie_index_hi_offset;
11470c552ed3SLe Ma void __iomem *pcie_data_offset;
11480c552ed3SLe Ma
11490c552ed3SLe Ma pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev);
11500c552ed3SLe Ma pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev);
1151d57e24aaSCandice Li if ((reg_addr >> 32) && (adev->nbio.funcs->get_pcie_index_hi_offset))
11520c552ed3SLe Ma pcie_index_hi = adev->nbio.funcs->get_pcie_index_hi_offset(adev);
11530c552ed3SLe Ma else
11540c552ed3SLe Ma pcie_index_hi = 0;
11550c552ed3SLe Ma
11560c552ed3SLe Ma spin_lock_irqsave(&adev->pcie_idx_lock, flags);
11570c552ed3SLe Ma pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
11580c552ed3SLe Ma pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4;
11590c552ed3SLe Ma if (pcie_index_hi != 0)
11600c552ed3SLe Ma pcie_index_hi_offset = (void __iomem *)adev->rmmio +
11610c552ed3SLe Ma pcie_index_hi * 4;
11620c552ed3SLe Ma
11630c552ed3SLe Ma writel(reg_addr, pcie_index_offset);
11640c552ed3SLe Ma readl(pcie_index_offset);
11650c552ed3SLe Ma if (pcie_index_hi != 0) {
11660c552ed3SLe Ma writel((reg_addr >> 32) & 0xff, pcie_index_hi_offset);
11670c552ed3SLe Ma readl(pcie_index_hi_offset);
11680c552ed3SLe Ma }
11690c552ed3SLe Ma writel(reg_data, pcie_data_offset);
11700c552ed3SLe Ma readl(pcie_data_offset);
11710c552ed3SLe Ma
11720c552ed3SLe Ma /* clear the high bits */
11730c552ed3SLe Ma if (pcie_index_hi != 0) {
11740c552ed3SLe Ma writel(0, pcie_index_hi_offset);
11750c552ed3SLe Ma readl(pcie_index_hi_offset);
11760c552ed3SLe Ma }
11770c552ed3SLe Ma
11780c552ed3SLe Ma spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
11790c552ed3SLe Ma }
11800c552ed3SLe Ma
11811bba3683SHawking Zhang /**
11821bba3683SHawking Zhang * amdgpu_device_indirect_wreg64 - write a 64bits indirect register address
11831bba3683SHawking Zhang *
11841bba3683SHawking Zhang * @adev: amdgpu_device pointer
11851bba3683SHawking Zhang * @reg_addr: indirect register offset
11861bba3683SHawking Zhang * @reg_data: indirect register data
11871bba3683SHawking Zhang *
11881bba3683SHawking Zhang */
amdgpu_device_indirect_wreg64(struct amdgpu_device * adev,u32 reg_addr,u64 reg_data)11891bba3683SHawking Zhang void amdgpu_device_indirect_wreg64(struct amdgpu_device *adev,
11901bba3683SHawking Zhang u32 reg_addr, u64 reg_data)
11911bba3683SHawking Zhang {
119265ba96e9SHawking Zhang unsigned long flags, pcie_index, pcie_data;
11931bba3683SHawking Zhang void __iomem *pcie_index_offset;
11941bba3683SHawking Zhang void __iomem *pcie_data_offset;
11951bba3683SHawking Zhang
119665ba96e9SHawking Zhang pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev);
119765ba96e9SHawking Zhang pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev);
119865ba96e9SHawking Zhang
11991bba3683SHawking Zhang spin_lock_irqsave(&adev->pcie_idx_lock, flags);
12001bba3683SHawking Zhang pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
12011bba3683SHawking Zhang pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4;
12021bba3683SHawking Zhang
12031bba3683SHawking Zhang /* write low 32 bits */
12041bba3683SHawking Zhang writel(reg_addr, pcie_index_offset);
12051bba3683SHawking Zhang readl(pcie_index_offset);
12061bba3683SHawking Zhang writel((u32)(reg_data & 0xffffffffULL), pcie_data_offset);
12071bba3683SHawking Zhang readl(pcie_data_offset);
12081bba3683SHawking Zhang /* write high 32 bits */
12091bba3683SHawking Zhang writel(reg_addr + 4, pcie_index_offset);
12101bba3683SHawking Zhang readl(pcie_index_offset);
12111bba3683SHawking Zhang writel((u32)(reg_data >> 32), pcie_data_offset);
12121bba3683SHawking Zhang readl(pcie_data_offset);
12131bba3683SHawking Zhang spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
12141bba3683SHawking Zhang }
12151bba3683SHawking Zhang
amdgpu_device_indirect_wreg64_ext(struct amdgpu_device * adev,u64 reg_addr,u64 reg_data)1216a76b2870SCandice Li void amdgpu_device_indirect_wreg64_ext(struct amdgpu_device *adev,
1217a76b2870SCandice Li u64 reg_addr, u64 reg_data)
1218a76b2870SCandice Li {
1219a76b2870SCandice Li unsigned long flags, pcie_index, pcie_data;
1220a76b2870SCandice Li unsigned long pcie_index_hi = 0;
1221a76b2870SCandice Li void __iomem *pcie_index_offset;
1222a76b2870SCandice Li void __iomem *pcie_index_hi_offset;
1223a76b2870SCandice Li void __iomem *pcie_data_offset;
1224a76b2870SCandice Li
1225a76b2870SCandice Li pcie_index = adev->nbio.funcs->get_pcie_index_offset(adev);
1226a76b2870SCandice Li pcie_data = adev->nbio.funcs->get_pcie_data_offset(adev);
1227a76b2870SCandice Li if ((reg_addr >> 32) && (adev->nbio.funcs->get_pcie_index_hi_offset))
1228a76b2870SCandice Li pcie_index_hi = adev->nbio.funcs->get_pcie_index_hi_offset(adev);
1229a76b2870SCandice Li
1230a76b2870SCandice Li spin_lock_irqsave(&adev->pcie_idx_lock, flags);
1231a76b2870SCandice Li pcie_index_offset = (void __iomem *)adev->rmmio + pcie_index * 4;
1232a76b2870SCandice Li pcie_data_offset = (void __iomem *)adev->rmmio + pcie_data * 4;
1233a76b2870SCandice Li if (pcie_index_hi != 0)
1234a76b2870SCandice Li pcie_index_hi_offset = (void __iomem *)adev->rmmio +
1235a76b2870SCandice Li pcie_index_hi * 4;
1236a76b2870SCandice Li
1237a76b2870SCandice Li /* write low 32 bits */
1238a76b2870SCandice Li writel(reg_addr, pcie_index_offset);
1239a76b2870SCandice Li readl(pcie_index_offset);
1240a76b2870SCandice Li if (pcie_index_hi != 0) {
1241a76b2870SCandice Li writel((reg_addr >> 32) & 0xff, pcie_index_hi_offset);
1242a76b2870SCandice Li readl(pcie_index_hi_offset);
1243a76b2870SCandice Li }
1244a76b2870SCandice Li writel((u32)(reg_data & 0xffffffffULL), pcie_data_offset);
1245a76b2870SCandice Li readl(pcie_data_offset);
1246a76b2870SCandice Li /* write high 32 bits */
1247a76b2870SCandice Li writel(reg_addr + 4, pcie_index_offset);
1248a76b2870SCandice Li readl(pcie_index_offset);
1249a76b2870SCandice Li if (pcie_index_hi != 0) {
1250a76b2870SCandice Li writel((reg_addr >> 32) & 0xff, pcie_index_hi_offset);
1251a76b2870SCandice Li readl(pcie_index_hi_offset);
1252a76b2870SCandice Li }
1253a76b2870SCandice Li writel((u32)(reg_data >> 32), pcie_data_offset);
1254a76b2870SCandice Li readl(pcie_data_offset);
1255a76b2870SCandice Li
1256a76b2870SCandice Li /* clear the high bits */
1257a76b2870SCandice Li if (pcie_index_hi != 0) {
1258a76b2870SCandice Li writel(0, pcie_index_hi_offset);
1259a76b2870SCandice Li readl(pcie_index_hi_offset);
1260a76b2870SCandice Li }
1261a76b2870SCandice Li
1262a76b2870SCandice Li spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
1263a76b2870SCandice Li }
1264a76b2870SCandice Li
12651bba3683SHawking Zhang /**
1266dabc114eSHawking Zhang * amdgpu_device_get_rev_id - query device rev_id
1267dabc114eSHawking Zhang *
1268dabc114eSHawking Zhang * @adev: amdgpu_device pointer
1269dabc114eSHawking Zhang *
1270dabc114eSHawking Zhang * Return device rev_id
1271dabc114eSHawking Zhang */
amdgpu_device_get_rev_id(struct amdgpu_device * adev)1272dabc114eSHawking Zhang u32 amdgpu_device_get_rev_id(struct amdgpu_device *adev)
1273dabc114eSHawking Zhang {
1274dabc114eSHawking Zhang return adev->nbio.funcs->get_rev_id(adev);
1275dabc114eSHawking Zhang }
1276dabc114eSHawking Zhang
1277dabc114eSHawking Zhang /**
1278d38ceaf9SAlex Deucher * amdgpu_invalid_rreg - dummy reg read function
1279d38ceaf9SAlex Deucher *
1280982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
1281d38ceaf9SAlex Deucher * @reg: offset of register
1282d38ceaf9SAlex Deucher *
1283d38ceaf9SAlex Deucher * Dummy register read function. Used for register blocks
1284d38ceaf9SAlex Deucher * that certain asics don't have (all asics).
1285d38ceaf9SAlex Deucher * Returns the value in the register.
1286d38ceaf9SAlex Deucher */
amdgpu_invalid_rreg(struct amdgpu_device * adev,uint32_t reg)1287d38ceaf9SAlex Deucher static uint32_t amdgpu_invalid_rreg(struct amdgpu_device *adev, uint32_t reg)
1288d38ceaf9SAlex Deucher {
1289d38ceaf9SAlex Deucher DRM_ERROR("Invalid callback to read register 0x%04X\n", reg);
1290d38ceaf9SAlex Deucher BUG();
1291d38ceaf9SAlex Deucher return 0;
1292d38ceaf9SAlex Deucher }
1293d38ceaf9SAlex Deucher
amdgpu_invalid_rreg_ext(struct amdgpu_device * adev,uint64_t reg)12940c552ed3SLe Ma static uint32_t amdgpu_invalid_rreg_ext(struct amdgpu_device *adev, uint64_t reg)
12950c552ed3SLe Ma {
12960c552ed3SLe Ma DRM_ERROR("Invalid callback to read register 0x%llX\n", reg);
12970c552ed3SLe Ma BUG();
12980c552ed3SLe Ma return 0;
12990c552ed3SLe Ma }
13000c552ed3SLe Ma
1301d38ceaf9SAlex Deucher /**
1302d38ceaf9SAlex Deucher * amdgpu_invalid_wreg - dummy reg write function
1303d38ceaf9SAlex Deucher *
1304982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
1305d38ceaf9SAlex Deucher * @reg: offset of register
1306d38ceaf9SAlex Deucher * @v: value to write to the register
1307d38ceaf9SAlex Deucher *
1308d38ceaf9SAlex Deucher * Dummy register read function. Used for register blocks
1309d38ceaf9SAlex Deucher * that certain asics don't have (all asics).
1310d38ceaf9SAlex Deucher */
amdgpu_invalid_wreg(struct amdgpu_device * adev,uint32_t reg,uint32_t v)1311d38ceaf9SAlex Deucher static void amdgpu_invalid_wreg(struct amdgpu_device *adev, uint32_t reg, uint32_t v)
1312d38ceaf9SAlex Deucher {
1313d38ceaf9SAlex Deucher DRM_ERROR("Invalid callback to write register 0x%04X with 0x%08X\n",
1314d38ceaf9SAlex Deucher reg, v);
1315d38ceaf9SAlex Deucher BUG();
1316d38ceaf9SAlex Deucher }
1317d38ceaf9SAlex Deucher
amdgpu_invalid_wreg_ext(struct amdgpu_device * adev,uint64_t reg,uint32_t v)13180c552ed3SLe Ma static void amdgpu_invalid_wreg_ext(struct amdgpu_device *adev, uint64_t reg, uint32_t v)
13190c552ed3SLe Ma {
13200c552ed3SLe Ma DRM_ERROR("Invalid callback to write register 0x%llX with 0x%08X\n",
13210c552ed3SLe Ma reg, v);
13220c552ed3SLe Ma BUG();
13230c552ed3SLe Ma }
13240c552ed3SLe Ma
1325d38ceaf9SAlex Deucher /**
13264fa1c6a6STao Zhou * amdgpu_invalid_rreg64 - dummy 64 bit reg read function
13274fa1c6a6STao Zhou *
1328982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
13294fa1c6a6STao Zhou * @reg: offset of register
13304fa1c6a6STao Zhou *
13314fa1c6a6STao Zhou * Dummy register read function. Used for register blocks
13324fa1c6a6STao Zhou * that certain asics don't have (all asics).
13334fa1c6a6STao Zhou * Returns the value in the register.
13344fa1c6a6STao Zhou */
amdgpu_invalid_rreg64(struct amdgpu_device * adev,uint32_t reg)13354fa1c6a6STao Zhou static uint64_t amdgpu_invalid_rreg64(struct amdgpu_device *adev, uint32_t reg)
13364fa1c6a6STao Zhou {
13374fa1c6a6STao Zhou DRM_ERROR("Invalid callback to read 64 bit register 0x%04X\n", reg);
13384fa1c6a6STao Zhou BUG();
13394fa1c6a6STao Zhou return 0;
13404fa1c6a6STao Zhou }
13414fa1c6a6STao Zhou
amdgpu_invalid_rreg64_ext(struct amdgpu_device * adev,uint64_t reg)1342a76b2870SCandice Li static uint64_t amdgpu_invalid_rreg64_ext(struct amdgpu_device *adev, uint64_t reg)
1343a76b2870SCandice Li {
1344a76b2870SCandice Li DRM_ERROR("Invalid callback to read register 0x%llX\n", reg);
1345a76b2870SCandice Li BUG();
1346a76b2870SCandice Li return 0;
1347a76b2870SCandice Li }
1348a76b2870SCandice Li
13494fa1c6a6STao Zhou /**
13504fa1c6a6STao Zhou * amdgpu_invalid_wreg64 - dummy reg write function
13514fa1c6a6STao Zhou *
1352982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
13534fa1c6a6STao Zhou * @reg: offset of register
13544fa1c6a6STao Zhou * @v: value to write to the register
13554fa1c6a6STao Zhou *
13564fa1c6a6STao Zhou * Dummy register read function. Used for register blocks
13574fa1c6a6STao Zhou * that certain asics don't have (all asics).
13584fa1c6a6STao Zhou */
amdgpu_invalid_wreg64(struct amdgpu_device * adev,uint32_t reg,uint64_t v)13594fa1c6a6STao Zhou static void amdgpu_invalid_wreg64(struct amdgpu_device *adev, uint32_t reg, uint64_t v)
13604fa1c6a6STao Zhou {
13614fa1c6a6STao Zhou DRM_ERROR("Invalid callback to write 64 bit register 0x%04X with 0x%08llX\n",
13624fa1c6a6STao Zhou reg, v);
13634fa1c6a6STao Zhou BUG();
13644fa1c6a6STao Zhou }
13654fa1c6a6STao Zhou
amdgpu_invalid_wreg64_ext(struct amdgpu_device * adev,uint64_t reg,uint64_t v)1366a76b2870SCandice Li static void amdgpu_invalid_wreg64_ext(struct amdgpu_device *adev, uint64_t reg, uint64_t v)
1367a76b2870SCandice Li {
1368a76b2870SCandice Li DRM_ERROR("Invalid callback to write 64 bit register 0x%llX with 0x%08llX\n",
1369a76b2870SCandice Li reg, v);
1370a76b2870SCandice Li BUG();
1371a76b2870SCandice Li }
1372a76b2870SCandice Li
13734fa1c6a6STao Zhou /**
1374d38ceaf9SAlex Deucher * amdgpu_block_invalid_rreg - dummy reg read function
1375d38ceaf9SAlex Deucher *
1376982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
1377d38ceaf9SAlex Deucher * @block: offset of instance
1378d38ceaf9SAlex Deucher * @reg: offset of register
1379d38ceaf9SAlex Deucher *
1380d38ceaf9SAlex Deucher * Dummy register read function. Used for register blocks
1381d38ceaf9SAlex Deucher * that certain asics don't have (all asics).
1382d38ceaf9SAlex Deucher * Returns the value in the register.
1383d38ceaf9SAlex Deucher */
amdgpu_block_invalid_rreg(struct amdgpu_device * adev,uint32_t block,uint32_t reg)1384d38ceaf9SAlex Deucher static uint32_t amdgpu_block_invalid_rreg(struct amdgpu_device *adev,
1385d38ceaf9SAlex Deucher uint32_t block, uint32_t reg)
1386d38ceaf9SAlex Deucher {
1387d38ceaf9SAlex Deucher DRM_ERROR("Invalid callback to read register 0x%04X in block 0x%04X\n",
1388d38ceaf9SAlex Deucher reg, block);
1389d38ceaf9SAlex Deucher BUG();
1390d38ceaf9SAlex Deucher return 0;
1391d38ceaf9SAlex Deucher }
1392d38ceaf9SAlex Deucher
1393d38ceaf9SAlex Deucher /**
1394d38ceaf9SAlex Deucher * amdgpu_block_invalid_wreg - dummy reg write function
1395d38ceaf9SAlex Deucher *
1396982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
1397d38ceaf9SAlex Deucher * @block: offset of instance
1398d38ceaf9SAlex Deucher * @reg: offset of register
1399d38ceaf9SAlex Deucher * @v: value to write to the register
1400d38ceaf9SAlex Deucher *
1401d38ceaf9SAlex Deucher * Dummy register read function. Used for register blocks
1402d38ceaf9SAlex Deucher * that certain asics don't have (all asics).
1403d38ceaf9SAlex Deucher */
amdgpu_block_invalid_wreg(struct amdgpu_device * adev,uint32_t block,uint32_t reg,uint32_t v)1404d38ceaf9SAlex Deucher static void amdgpu_block_invalid_wreg(struct amdgpu_device *adev,
1405d38ceaf9SAlex Deucher uint32_t block,
1406d38ceaf9SAlex Deucher uint32_t reg, uint32_t v)
1407d38ceaf9SAlex Deucher {
1408d38ceaf9SAlex Deucher DRM_ERROR("Invalid block callback to write register 0x%04X in block 0x%04X with 0x%08X\n",
1409d38ceaf9SAlex Deucher reg, block, v);
1410d38ceaf9SAlex Deucher BUG();
1411d38ceaf9SAlex Deucher }
1412d38ceaf9SAlex Deucher
amdgpu_device_get_vbios_flags(struct amdgpu_device * adev)14136e8ca38eSLijo Lazar static uint32_t amdgpu_device_get_vbios_flags(struct amdgpu_device *adev)
14146e8ca38eSLijo Lazar {
14156e8ca38eSLijo Lazar if (hweight32(adev->aid_mask) && (adev->flags & AMD_IS_APU))
14166e8ca38eSLijo Lazar return AMDGPU_VBIOS_SKIP;
14176e8ca38eSLijo Lazar
1418cc0e91a7SLijo Lazar if (hweight32(adev->aid_mask) && amdgpu_passthrough(adev))
1419cc0e91a7SLijo Lazar return AMDGPU_VBIOS_OPTIONAL;
1420cc0e91a7SLijo Lazar
14216e8ca38eSLijo Lazar return 0;
14226e8ca38eSLijo Lazar }
14236e8ca38eSLijo Lazar
1424e3ecdffaSAlex Deucher /**
14254d2997abSAlex Deucher * amdgpu_device_asic_init - Wrapper for atom asic_init
14264d2997abSAlex Deucher *
1427982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
14284d2997abSAlex Deucher *
14294d2997abSAlex Deucher * Does any asic specific work and then calls atom asic init.
14304d2997abSAlex Deucher */
amdgpu_device_asic_init(struct amdgpu_device * adev)14314d2997abSAlex Deucher static int amdgpu_device_asic_init(struct amdgpu_device *adev)
14324d2997abSAlex Deucher {
14336e8ca38eSLijo Lazar uint32_t flags;
14346e8ca38eSLijo Lazar bool optional;
14357656168aSLijo Lazar int ret;
14367656168aSLijo Lazar
14374d2997abSAlex Deucher amdgpu_asic_pre_asic_init(adev);
14386e8ca38eSLijo Lazar flags = amdgpu_device_get_vbios_flags(adev);
14396e8ca38eSLijo Lazar optional = !!(flags & (AMDGPU_VBIOS_OPTIONAL | AMDGPU_VBIOS_SKIP));
14404d2997abSAlex Deucher
14414e8303cfSLijo Lazar if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
14425f571c61SHawking Zhang amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) ||
14430b58a55aSLe Ma amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0) ||
14444e8303cfSLijo Lazar amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(11, 0, 0)) {
14457656168aSLijo Lazar amdgpu_psp_wait_for_bootloader(adev);
14466e8ca38eSLijo Lazar if (optional && !adev->bios)
14476e8ca38eSLijo Lazar return 0;
14486e8ca38eSLijo Lazar
14497656168aSLijo Lazar ret = amdgpu_atomfirmware_asic_init(adev, true);
14507656168aSLijo Lazar return ret;
14517656168aSLijo Lazar } else {
14526e8ca38eSLijo Lazar if (optional && !adev->bios)
14536e8ca38eSLijo Lazar return 0;
14546e8ca38eSLijo Lazar
14554d2997abSAlex Deucher return amdgpu_atom_asic_init(adev->mode_info.atom_context);
14564d2997abSAlex Deucher }
14574d2997abSAlex Deucher
14587656168aSLijo Lazar return 0;
14597656168aSLijo Lazar }
14607656168aSLijo Lazar
14614d2997abSAlex Deucher /**
14627ccfd79fSChristian König * amdgpu_device_mem_scratch_init - allocate the VRAM scratch page
1463e3ecdffaSAlex Deucher *
1464982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
1465e3ecdffaSAlex Deucher *
1466e3ecdffaSAlex Deucher * Allocates a scratch page of VRAM for use by various things in the
1467e3ecdffaSAlex Deucher * driver.
1468e3ecdffaSAlex Deucher */
amdgpu_device_mem_scratch_init(struct amdgpu_device * adev)14697ccfd79fSChristian König static int amdgpu_device_mem_scratch_init(struct amdgpu_device *adev)
1470d38ceaf9SAlex Deucher {
14717ccfd79fSChristian König return amdgpu_bo_create_kernel(adev, AMDGPU_GPU_PAGE_SIZE, PAGE_SIZE,
14727ccfd79fSChristian König AMDGPU_GEM_DOMAIN_VRAM |
14737ccfd79fSChristian König AMDGPU_GEM_DOMAIN_GTT,
14747ccfd79fSChristian König &adev->mem_scratch.robj,
14757ccfd79fSChristian König &adev->mem_scratch.gpu_addr,
14767ccfd79fSChristian König (void **)&adev->mem_scratch.ptr);
1477d38ceaf9SAlex Deucher }
1478d38ceaf9SAlex Deucher
1479e3ecdffaSAlex Deucher /**
14807ccfd79fSChristian König * amdgpu_device_mem_scratch_fini - Free the VRAM scratch page
1481e3ecdffaSAlex Deucher *
1482982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
1483e3ecdffaSAlex Deucher *
1484e3ecdffaSAlex Deucher * Frees the VRAM scratch page.
1485e3ecdffaSAlex Deucher */
amdgpu_device_mem_scratch_fini(struct amdgpu_device * adev)14867ccfd79fSChristian König static void amdgpu_device_mem_scratch_fini(struct amdgpu_device *adev)
1487d38ceaf9SAlex Deucher {
14887ccfd79fSChristian König amdgpu_bo_free_kernel(&adev->mem_scratch.robj, NULL, NULL);
1489d38ceaf9SAlex Deucher }
1490d38ceaf9SAlex Deucher
1491d38ceaf9SAlex Deucher /**
14929c3f2b54SAlex Deucher * amdgpu_device_program_register_sequence - program an array of registers.
1493d38ceaf9SAlex Deucher *
1494d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
1495d38ceaf9SAlex Deucher * @registers: pointer to the register array
1496d38ceaf9SAlex Deucher * @array_size: size of the register array
1497d38ceaf9SAlex Deucher *
1498b8920e1eSSrinivasan Shanmugam * Programs an array or registers with and or masks.
1499d38ceaf9SAlex Deucher * This is a helper for setting golden registers.
1500d38ceaf9SAlex Deucher */
amdgpu_device_program_register_sequence(struct amdgpu_device * adev,const u32 * registers,const u32 array_size)15019c3f2b54SAlex Deucher void amdgpu_device_program_register_sequence(struct amdgpu_device *adev,
1502d38ceaf9SAlex Deucher const u32 *registers,
1503d38ceaf9SAlex Deucher const u32 array_size)
1504d38ceaf9SAlex Deucher {
1505d38ceaf9SAlex Deucher u32 tmp, reg, and_mask, or_mask;
1506d38ceaf9SAlex Deucher int i;
1507d38ceaf9SAlex Deucher
1508d38ceaf9SAlex Deucher if (array_size % 3)
1509d38ceaf9SAlex Deucher return;
1510d38ceaf9SAlex Deucher
1511d38ceaf9SAlex Deucher for (i = 0; i < array_size; i += 3) {
1512d38ceaf9SAlex Deucher reg = registers[i + 0];
1513d38ceaf9SAlex Deucher and_mask = registers[i + 1];
1514d38ceaf9SAlex Deucher or_mask = registers[i + 2];
1515d38ceaf9SAlex Deucher
1516d38ceaf9SAlex Deucher if (and_mask == 0xffffffff) {
1517d38ceaf9SAlex Deucher tmp = or_mask;
1518d38ceaf9SAlex Deucher } else {
1519d38ceaf9SAlex Deucher tmp = RREG32(reg);
1520d38ceaf9SAlex Deucher tmp &= ~and_mask;
1521e0d07657SHawking Zhang if (adev->family >= AMDGPU_FAMILY_AI)
1522e0d07657SHawking Zhang tmp |= (or_mask & and_mask);
1523e0d07657SHawking Zhang else
1524d38ceaf9SAlex Deucher tmp |= or_mask;
1525d38ceaf9SAlex Deucher }
1526d38ceaf9SAlex Deucher WREG32(reg, tmp);
1527d38ceaf9SAlex Deucher }
1528d38ceaf9SAlex Deucher }
1529d38ceaf9SAlex Deucher
1530e3ecdffaSAlex Deucher /**
1531e3ecdffaSAlex Deucher * amdgpu_device_pci_config_reset - reset the GPU
1532e3ecdffaSAlex Deucher *
1533e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
1534e3ecdffaSAlex Deucher *
1535e3ecdffaSAlex Deucher * Resets the GPU using the pci config reset sequence.
1536e3ecdffaSAlex Deucher * Only applicable to asics prior to vega10.
1537e3ecdffaSAlex Deucher */
amdgpu_device_pci_config_reset(struct amdgpu_device * adev)15388111c387SAlex Deucher void amdgpu_device_pci_config_reset(struct amdgpu_device *adev)
1539d38ceaf9SAlex Deucher {
1540d38ceaf9SAlex Deucher pci_write_config_dword(adev->pdev, 0x7c, AMDGPU_ASIC_RESET_DATA);
1541d38ceaf9SAlex Deucher }
1542d38ceaf9SAlex Deucher
1543af484df8SAlex Deucher /**
1544af484df8SAlex Deucher * amdgpu_device_pci_reset - reset the GPU using generic PCI means
1545af484df8SAlex Deucher *
1546af484df8SAlex Deucher * @adev: amdgpu_device pointer
1547af484df8SAlex Deucher *
1548af484df8SAlex Deucher * Resets the GPU using generic pci reset interfaces (FLR, SBR, etc.).
1549af484df8SAlex Deucher */
amdgpu_device_pci_reset(struct amdgpu_device * adev)1550af484df8SAlex Deucher int amdgpu_device_pci_reset(struct amdgpu_device *adev)
1551af484df8SAlex Deucher {
1552af484df8SAlex Deucher return pci_reset_function(adev->pdev);
1553af484df8SAlex Deucher }
1554af484df8SAlex Deucher
1555d38ceaf9SAlex Deucher /*
155606ec9070SAlex Deucher * amdgpu_device_wb_*()
1557455a7bc2SAlex Xie * Writeback is the method by which the GPU updates special pages in memory
1558ea81a173SAlex Xie * with the status of certain GPU events (fences, ring pointers,etc.).
1559d38ceaf9SAlex Deucher */
1560d38ceaf9SAlex Deucher
1561d38ceaf9SAlex Deucher /**
156206ec9070SAlex Deucher * amdgpu_device_wb_fini - Disable Writeback and free memory
1563d38ceaf9SAlex Deucher *
1564d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
1565d38ceaf9SAlex Deucher *
1566d38ceaf9SAlex Deucher * Disables Writeback and frees the Writeback memory (all asics).
1567d38ceaf9SAlex Deucher * Used at driver shutdown.
1568d38ceaf9SAlex Deucher */
amdgpu_device_wb_fini(struct amdgpu_device * adev)156906ec9070SAlex Deucher static void amdgpu_device_wb_fini(struct amdgpu_device *adev)
1570d38ceaf9SAlex Deucher {
1571d38ceaf9SAlex Deucher if (adev->wb.wb_obj) {
1572a76ed485SAlex Deucher amdgpu_bo_free_kernel(&adev->wb.wb_obj,
1573a76ed485SAlex Deucher &adev->wb.gpu_addr,
1574a76ed485SAlex Deucher (void **)&adev->wb.wb);
1575d38ceaf9SAlex Deucher adev->wb.wb_obj = NULL;
1576d38ceaf9SAlex Deucher }
1577d38ceaf9SAlex Deucher }
1578d38ceaf9SAlex Deucher
1579d38ceaf9SAlex Deucher /**
158006ec9070SAlex Deucher * amdgpu_device_wb_init - Init Writeback driver info and allocate memory
1581d38ceaf9SAlex Deucher *
1582d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
1583d38ceaf9SAlex Deucher *
1584455a7bc2SAlex Xie * Initializes writeback and allocates writeback memory (all asics).
1585d38ceaf9SAlex Deucher * Used at driver startup.
1586d38ceaf9SAlex Deucher * Returns 0 on success or an -error on failure.
1587d38ceaf9SAlex Deucher */
amdgpu_device_wb_init(struct amdgpu_device * adev)158806ec9070SAlex Deucher static int amdgpu_device_wb_init(struct amdgpu_device *adev)
1589d38ceaf9SAlex Deucher {
1590d38ceaf9SAlex Deucher int r;
1591d38ceaf9SAlex Deucher
1592d38ceaf9SAlex Deucher if (adev->wb.wb_obj == NULL) {
159397407b63SAlex Deucher /* AMDGPU_MAX_WB * sizeof(uint32_t) * 8 = AMDGPU_MAX_WB 256bit slots */
159497407b63SAlex Deucher r = amdgpu_bo_create_kernel(adev, AMDGPU_MAX_WB * sizeof(uint32_t) * 8,
1595a76ed485SAlex Deucher PAGE_SIZE, AMDGPU_GEM_DOMAIN_GTT,
1596a76ed485SAlex Deucher &adev->wb.wb_obj, &adev->wb.gpu_addr,
1597a76ed485SAlex Deucher (void **)&adev->wb.wb);
1598d38ceaf9SAlex Deucher if (r) {
1599d38ceaf9SAlex Deucher dev_warn(adev->dev, "(%d) create WB bo failed\n", r);
1600d38ceaf9SAlex Deucher return r;
1601d38ceaf9SAlex Deucher }
1602d38ceaf9SAlex Deucher
1603d38ceaf9SAlex Deucher adev->wb.num_wb = AMDGPU_MAX_WB;
1604d38ceaf9SAlex Deucher memset(&adev->wb.used, 0, sizeof(adev->wb.used));
1605d38ceaf9SAlex Deucher
1606d38ceaf9SAlex Deucher /* clear wb memory */
160773469585SMonk Liu memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t) * 8);
1608d38ceaf9SAlex Deucher }
1609d38ceaf9SAlex Deucher
1610d38ceaf9SAlex Deucher return 0;
1611d38ceaf9SAlex Deucher }
1612d38ceaf9SAlex Deucher
1613d38ceaf9SAlex Deucher /**
1614131b4b36SAlex Deucher * amdgpu_device_wb_get - Allocate a wb entry
1615d38ceaf9SAlex Deucher *
1616d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
1617d38ceaf9SAlex Deucher * @wb: wb index
1618d38ceaf9SAlex Deucher *
1619d38ceaf9SAlex Deucher * Allocate a wb slot for use by the driver (all asics).
1620d38ceaf9SAlex Deucher * Returns 0 on success or -EINVAL on failure.
1621d38ceaf9SAlex Deucher */
amdgpu_device_wb_get(struct amdgpu_device * adev,u32 * wb)1622131b4b36SAlex Deucher int amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb)
1623d38ceaf9SAlex Deucher {
1624497d7ceeSAlex Deucher unsigned long flags, offset;
162597407b63SAlex Deucher
1626497d7ceeSAlex Deucher spin_lock_irqsave(&adev->wb.lock, flags);
1627497d7ceeSAlex Deucher offset = find_first_zero_bit(adev->wb.used, adev->wb.num_wb);
1628d38ceaf9SAlex Deucher if (offset < adev->wb.num_wb) {
1629d38ceaf9SAlex Deucher __set_bit(offset, adev->wb.used);
1630497d7ceeSAlex Deucher spin_unlock_irqrestore(&adev->wb.lock, flags);
163163ae07caSMonk Liu *wb = offset << 3; /* convert to dw offset */
16320915fdbcSMonk Liu return 0;
16330915fdbcSMonk Liu } else {
1634497d7ceeSAlex Deucher spin_unlock_irqrestore(&adev->wb.lock, flags);
16350915fdbcSMonk Liu return -EINVAL;
16360915fdbcSMonk Liu }
16370915fdbcSMonk Liu }
16380915fdbcSMonk Liu
16397014285aSKen Wang /**
1640131b4b36SAlex Deucher * amdgpu_device_wb_free - Free a wb entry
1641d38ceaf9SAlex Deucher *
1642d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
1643d38ceaf9SAlex Deucher * @wb: wb index
1644d38ceaf9SAlex Deucher *
1645d38ceaf9SAlex Deucher * Free a wb slot allocated for use by the driver (all asics)
1646d38ceaf9SAlex Deucher */
amdgpu_device_wb_free(struct amdgpu_device * adev,u32 wb)1647131b4b36SAlex Deucher void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb)
1648d38ceaf9SAlex Deucher {
1649497d7ceeSAlex Deucher unsigned long flags;
1650497d7ceeSAlex Deucher
165173469585SMonk Liu wb >>= 3;
1652497d7ceeSAlex Deucher spin_lock_irqsave(&adev->wb.lock, flags);
1653d38ceaf9SAlex Deucher if (wb < adev->wb.num_wb)
165473469585SMonk Liu __clear_bit(wb, adev->wb.used);
1655497d7ceeSAlex Deucher spin_unlock_irqrestore(&adev->wb.lock, flags);
1656d38ceaf9SAlex Deucher }
1657d38ceaf9SAlex Deucher
1658d38ceaf9SAlex Deucher /**
1659d6895ad3SChristian König * amdgpu_device_resize_fb_bar - try to resize FB BAR
1660d6895ad3SChristian König *
1661d6895ad3SChristian König * @adev: amdgpu_device pointer
1662d6895ad3SChristian König *
1663d6895ad3SChristian König * Try to resize FB BAR to make all VRAM CPU accessible. We try very hard not
1664d6895ad3SChristian König * to fail, but if any of the BARs is not accessible after the size we abort
1665d6895ad3SChristian König * driver loading by returning -ENODEV.
1666d6895ad3SChristian König */
amdgpu_device_resize_fb_bar(struct amdgpu_device * adev)1667d6895ad3SChristian König int amdgpu_device_resize_fb_bar(struct amdgpu_device *adev)
1668d6895ad3SChristian König {
1669453f617aSNirmoy Das int rbar_size = pci_rebar_bytes_to_size(adev->gmc.real_vram_size);
167031b8adabSChristian König struct pci_bus *root;
167131b8adabSChristian König struct resource *res;
1672b8920e1eSSrinivasan Shanmugam unsigned int i;
1673d6895ad3SChristian König u16 cmd;
1674d6895ad3SChristian König int r;
1675d6895ad3SChristian König
1676822130b5SArnd Bergmann if (!IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
1677822130b5SArnd Bergmann return 0;
1678822130b5SArnd Bergmann
16790c03b912Spding /* Bypass for VF */
16800c03b912Spding if (amdgpu_sriov_vf(adev))
16810c03b912Spding return 0;
16820c03b912Spding
16835235053fSAlex Deucher /* resizing on Dell G5 SE platforms causes problems with runtime pm */
16845235053fSAlex Deucher if ((amdgpu_runtime_pm != 0) &&
16855235053fSAlex Deucher adev->pdev->vendor == PCI_VENDOR_ID_ATI &&
16865235053fSAlex Deucher adev->pdev->device == 0x731f &&
16875235053fSAlex Deucher adev->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
16885235053fSAlex Deucher return 0;
16895235053fSAlex Deucher
1690e372baebSMa Jun /* PCI_EXT_CAP_ID_VNDR extended capability is located at 0x100 */
1691e372baebSMa Jun if (!pci_find_ext_capability(adev->pdev, PCI_EXT_CAP_ID_VNDR))
1692e372baebSMa Jun DRM_WARN("System can't access extended configuration space, please check!!\n");
1693e372baebSMa Jun
1694b7221f2bSAlex Deucher /* skip if the bios has already enabled large BAR */
1695b7221f2bSAlex Deucher if (adev->gmc.real_vram_size &&
1696b7221f2bSAlex Deucher (pci_resource_len(adev->pdev, 0) >= adev->gmc.real_vram_size))
1697b7221f2bSAlex Deucher return 0;
1698b7221f2bSAlex Deucher
169931b8adabSChristian König /* Check if the root BUS has 64bit memory resources */
170031b8adabSChristian König root = adev->pdev->bus;
170131b8adabSChristian König while (root->parent)
170231b8adabSChristian König root = root->parent;
170331b8adabSChristian König
170431b8adabSChristian König pci_bus_for_each_resource(root, res, i) {
17050ebb7c54SChristian König if (res && res->flags & (IORESOURCE_MEM | IORESOURCE_MEM_64) &&
170631b8adabSChristian König res->start > 0x100000000ull)
170731b8adabSChristian König break;
170831b8adabSChristian König }
170931b8adabSChristian König
171031b8adabSChristian König /* Trying to resize is pointless without a root hub window above 4GB */
171131b8adabSChristian König if (!res)
171231b8adabSChristian König return 0;
171331b8adabSChristian König
1714453f617aSNirmoy Das /* Limit the BAR size to what is available */
1715453f617aSNirmoy Das rbar_size = min(fls(pci_rebar_get_possible_sizes(adev->pdev, 0)) - 1,
1716453f617aSNirmoy Das rbar_size);
1717453f617aSNirmoy Das
1718d6895ad3SChristian König /* Disable memory decoding while we change the BAR addresses and size */
1719d6895ad3SChristian König pci_read_config_word(adev->pdev, PCI_COMMAND, &cmd);
1720d6895ad3SChristian König pci_write_config_word(adev->pdev, PCI_COMMAND,
1721d6895ad3SChristian König cmd & ~PCI_COMMAND_MEMORY);
1722d6895ad3SChristian König
1723d6895ad3SChristian König /* Free the VRAM and doorbell BAR, we most likely need to move both. */
172443c064dbSShashank Sharma amdgpu_doorbell_fini(adev);
1725d6895ad3SChristian König if (adev->asic_type >= CHIP_BONAIRE)
1726d6895ad3SChristian König pci_release_resource(adev->pdev, 2);
1727d6895ad3SChristian König
1728d6895ad3SChristian König pci_release_resource(adev->pdev, 0);
1729d6895ad3SChristian König
1730d6895ad3SChristian König r = pci_resize_resource(adev->pdev, 0, rbar_size);
1731d6895ad3SChristian König if (r == -ENOSPC)
1732d6895ad3SChristian König DRM_INFO("Not enough PCI address space for a large BAR.");
1733d6895ad3SChristian König else if (r && r != -ENOTSUPP)
1734d6895ad3SChristian König DRM_ERROR("Problem resizing BAR0 (%d).", r);
1735d6895ad3SChristian König
1736d6895ad3SChristian König pci_assign_unassigned_bus_resources(adev->pdev->bus);
1737d6895ad3SChristian König
1738d6895ad3SChristian König /* When the doorbell or fb BAR isn't available we have no chance of
1739d6895ad3SChristian König * using the device.
1740d6895ad3SChristian König */
174143c064dbSShashank Sharma r = amdgpu_doorbell_init(adev);
1742d6895ad3SChristian König if (r || (pci_resource_flags(adev->pdev, 0) & IORESOURCE_UNSET))
1743d6895ad3SChristian König return -ENODEV;
1744d6895ad3SChristian König
1745d6895ad3SChristian König pci_write_config_word(adev->pdev, PCI_COMMAND, cmd);
1746d6895ad3SChristian König
1747d6895ad3SChristian König return 0;
1748d6895ad3SChristian König }
1749a05502e5SHorace Chen
1750a05502e5SHorace Chen /*
1751d38ceaf9SAlex Deucher * GPU helpers function.
1752d38ceaf9SAlex Deucher */
1753d38ceaf9SAlex Deucher /**
175439c640c0SAlex Deucher * amdgpu_device_need_post - check if the hw need post or not
1755d38ceaf9SAlex Deucher *
1756d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
1757d38ceaf9SAlex Deucher *
1758c836fec5SJim Qu * Check if the asic has been initialized (all asics) at driver startup
1759c836fec5SJim Qu * or post is needed if hw reset is performed.
1760c836fec5SJim Qu * Returns true if need or false if not.
1761d38ceaf9SAlex Deucher */
amdgpu_device_need_post(struct amdgpu_device * adev)176239c640c0SAlex Deucher bool amdgpu_device_need_post(struct amdgpu_device *adev)
1763d38ceaf9SAlex Deucher {
17647e0aa706SLijo Lazar uint32_t reg, flags;
1765d38ceaf9SAlex Deucher
1766bec86378SMonk Liu if (amdgpu_sriov_vf(adev))
1767bec86378SMonk Liu return false;
1768bec86378SMonk Liu
17697e0aa706SLijo Lazar flags = amdgpu_device_get_vbios_flags(adev);
17707e0aa706SLijo Lazar if (flags & AMDGPU_VBIOS_SKIP)
17719535a86aSShiwu Zhang return false;
17726e8ca38eSLijo Lazar if ((flags & AMDGPU_VBIOS_OPTIONAL) && !adev->bios)
17739535a86aSShiwu Zhang return false;
17749535a86aSShiwu Zhang
1775bec86378SMonk Liu if (amdgpu_passthrough(adev)) {
17761da2c326SMonk Liu /* for FIJI: In whole GPU pass-through virtualization case, after VM reboot
17771da2c326SMonk Liu * some old smc fw still need driver do vPost otherwise gpu hang, while
17781da2c326SMonk Liu * those smc fw version above 22.15 doesn't have this flaw, so we force
17791da2c326SMonk Liu * vpost executed for smc version below 22.15
1780bec86378SMonk Liu */
1781bec86378SMonk Liu if (adev->asic_type == CHIP_FIJI) {
1782bec86378SMonk Liu int err;
1783bec86378SMonk Liu uint32_t fw_ver;
1784b8920e1eSSrinivasan Shanmugam
1785bec86378SMonk Liu err = request_firmware(&adev->pm.fw, "amdgpu/fiji_smc.bin", adev->dev);
1786a567db80SRandy Dunlap /* force vPost if error occurred */
1787bec86378SMonk Liu if (err)
1788bec86378SMonk Liu return true;
1789bec86378SMonk Liu
1790bec86378SMonk Liu fw_ver = *((uint32_t *)adev->pm.fw->data + 69);
17918a44fdd3SSrinivasan Shanmugam release_firmware(adev->pm.fw);
17921da2c326SMonk Liu if (fw_ver < 0x00160e00)
1793bec86378SMonk Liu return true;
1794bec86378SMonk Liu }
17951da2c326SMonk Liu }
179691fe77ebSpding
1797e3c1b071Sshaoyunl /* Don't post if we need to reset whole hive on init */
17985839d27dSLijo Lazar if (adev->init_lvl->level == AMDGPU_INIT_LEVEL_MINIMAL_XGMI)
1799e3c1b071Sshaoyunl return false;
1800e3c1b071Sshaoyunl
180191fe77ebSpding if (adev->has_hw_reset) {
180291fe77ebSpding adev->has_hw_reset = false;
180391fe77ebSpding return true;
180491fe77ebSpding }
180591fe77ebSpding
180691fe77ebSpding /* bios scratch used on CIK+ */
180791fe77ebSpding if (adev->asic_type >= CHIP_BONAIRE)
180891fe77ebSpding return amdgpu_atombios_scratch_need_asic_init(adev);
180991fe77ebSpding
181091fe77ebSpding /* check MEM_SIZE for older asics */
181191fe77ebSpding reg = amdgpu_asic_get_config_memsize(adev);
181291fe77ebSpding
181391fe77ebSpding if ((reg != 0) && (reg != 0xffffffff))
181491fe77ebSpding return false;
181591fe77ebSpding
181691fe77ebSpding return true;
18171da2c326SMonk Liu }
1818bec86378SMonk Liu
18195d1eb4c4SMario Limonciello /*
1820bb0f8429SMario Limonciello * Check whether seamless boot is supported.
1821bb0f8429SMario Limonciello *
18227f4ce7b5SMario Limonciello * So far we only support seamless boot on DCE 3.0 or later.
18237f4ce7b5SMario Limonciello * If users report that it works on older ASICS as well, we may
18247f4ce7b5SMario Limonciello * loosen this.
1825bb0f8429SMario Limonciello */
amdgpu_device_seamless_boot_supported(struct amdgpu_device * adev)1826bb0f8429SMario Limonciello bool amdgpu_device_seamless_boot_supported(struct amdgpu_device *adev)
1827bb0f8429SMario Limonciello {
18285dc270d3SMario Limonciello switch (amdgpu_seamless) {
18295dc270d3SMario Limonciello case -1:
18305dc270d3SMario Limonciello break;
18315dc270d3SMario Limonciello case 1:
18325dc270d3SMario Limonciello return true;
18335dc270d3SMario Limonciello case 0:
18345dc270d3SMario Limonciello return false;
18355dc270d3SMario Limonciello default:
18365dc270d3SMario Limonciello DRM_ERROR("Invalid value for amdgpu.seamless: %d\n",
18375dc270d3SMario Limonciello amdgpu_seamless);
18385dc270d3SMario Limonciello return false;
18395dc270d3SMario Limonciello }
18405dc270d3SMario Limonciello
18413657a1d5SMario Limonciello if (!(adev->flags & AMD_IS_APU))
18423657a1d5SMario Limonciello return false;
18433657a1d5SMario Limonciello
18445dc270d3SMario Limonciello if (adev->mman.keep_stolen_vga_memory)
18455dc270d3SMario Limonciello return false;
18465dc270d3SMario Limonciello
1847ed342a2eSLijo Lazar return amdgpu_ip_version(adev, DCE_HWIP, 0) >= IP_VERSION(3, 0, 0);
1848bb0f8429SMario Limonciello }
1849bb0f8429SMario Limonciello
1850bb0f8429SMario Limonciello /*
18512757a848SMario Limonciello * Intel hosts such as Rocket Lake, Alder Lake, Raptor Lake and Sapphire Rapids
18522757a848SMario Limonciello * don't support dynamic speed switching. Until we have confirmation from Intel
18532757a848SMario Limonciello * that a specific host supports it, it's safer that we keep it disabled for all.
18545d1eb4c4SMario Limonciello *
18555d1eb4c4SMario Limonciello * https://edc.intel.com/content/www/us/en/design/products/platforms/details/raptor-lake-s/13th-generation-core-processors-datasheet-volume-1-of-2/005/pci-express-support/
18565d1eb4c4SMario Limonciello * https://gitlab.freedesktop.org/drm/amd/-/issues/2663
18575d1eb4c4SMario Limonciello */
amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device * adev)1858d9b3a066SMario Limonciello static bool amdgpu_device_pcie_dynamic_switching_supported(struct amdgpu_device *adev)
18595d1eb4c4SMario Limonciello {
18605d1eb4c4SMario Limonciello #if IS_ENABLED(CONFIG_X86)
18615d1eb4c4SMario Limonciello struct cpuinfo_x86 *c = &cpu_data(0);
18625d1eb4c4SMario Limonciello
1863d9b3a066SMario Limonciello /* eGPU change speeds based on USB4 fabric conditions */
1864d9b3a066SMario Limonciello if (dev_is_removable(adev->dev))
1865d9b3a066SMario Limonciello return true;
1866d9b3a066SMario Limonciello
18675d1eb4c4SMario Limonciello if (c->x86_vendor == X86_VENDOR_INTEL)
18685d1eb4c4SMario Limonciello return false;
18695d1eb4c4SMario Limonciello #endif
18705d1eb4c4SMario Limonciello return true;
18715d1eb4c4SMario Limonciello }
18725d1eb4c4SMario Limonciello
18730ab5d711SMario Limonciello /**
18740ab5d711SMario Limonciello * amdgpu_device_should_use_aspm - check if the device should program ASPM
18750ab5d711SMario Limonciello *
18760ab5d711SMario Limonciello * @adev: amdgpu_device pointer
18770ab5d711SMario Limonciello *
18780ab5d711SMario Limonciello * Confirm whether the module parameter and pcie bridge agree that ASPM should
18790ab5d711SMario Limonciello * be set for this device.
18800ab5d711SMario Limonciello *
18810ab5d711SMario Limonciello * Returns true if it should be used or false if not.
18820ab5d711SMario Limonciello */
amdgpu_device_should_use_aspm(struct amdgpu_device * adev)18830ab5d711SMario Limonciello bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev)
18840ab5d711SMario Limonciello {
18850ab5d711SMario Limonciello switch (amdgpu_aspm) {
18860ab5d711SMario Limonciello case -1:
18870ab5d711SMario Limonciello break;
18880ab5d711SMario Limonciello case 0:
18890ab5d711SMario Limonciello return false;
18900ab5d711SMario Limonciello case 1:
18910ab5d711SMario Limonciello return true;
18920ab5d711SMario Limonciello default:
18930ab5d711SMario Limonciello return false;
18940ab5d711SMario Limonciello }
18951a6513deSMario Limonciello if (adev->flags & AMD_IS_APU)
18961a6513deSMario Limonciello return false;
18972757a848SMario Limonciello if (!(adev->pm.pp_feature & PP_PCIE_DPM_MASK))
18982757a848SMario Limonciello return false;
18990ab5d711SMario Limonciello return pcie_aspm_enabled(adev->pdev);
19000ab5d711SMario Limonciello }
19010ab5d711SMario Limonciello
1902d38ceaf9SAlex Deucher /* if we get transitioned to only one device, take VGA back */
1903d38ceaf9SAlex Deucher /**
190406ec9070SAlex Deucher * amdgpu_device_vga_set_decode - enable/disable vga decode
1905d38ceaf9SAlex Deucher *
1906bf44e8ceSChristoph Hellwig * @pdev: PCI device pointer
1907d38ceaf9SAlex Deucher * @state: enable/disable vga decode
1908d38ceaf9SAlex Deucher *
1909d38ceaf9SAlex Deucher * Enable/disable vga decode (all asics).
1910d38ceaf9SAlex Deucher * Returns VGA resource flags.
1911d38ceaf9SAlex Deucher */
amdgpu_device_vga_set_decode(struct pci_dev * pdev,bool state)1912bf44e8ceSChristoph Hellwig static unsigned int amdgpu_device_vga_set_decode(struct pci_dev *pdev,
1913bf44e8ceSChristoph Hellwig bool state)
1914d38ceaf9SAlex Deucher {
1915bf44e8ceSChristoph Hellwig struct amdgpu_device *adev = drm_to_adev(pci_get_drvdata(pdev));
1916b8920e1eSSrinivasan Shanmugam
1917d38ceaf9SAlex Deucher amdgpu_asic_set_vga_state(adev, state);
1918d38ceaf9SAlex Deucher if (state)
1919d38ceaf9SAlex Deucher return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
1920d38ceaf9SAlex Deucher VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
1921d38ceaf9SAlex Deucher else
1922d38ceaf9SAlex Deucher return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
1923d38ceaf9SAlex Deucher }
1924d38ceaf9SAlex Deucher
1925e3ecdffaSAlex Deucher /**
1926e3ecdffaSAlex Deucher * amdgpu_device_check_block_size - validate the vm block size
1927e3ecdffaSAlex Deucher *
1928e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
1929e3ecdffaSAlex Deucher *
1930e3ecdffaSAlex Deucher * Validates the vm block size specified via module parameter.
1931e3ecdffaSAlex Deucher * The vm block size defines number of bits in page table versus page directory,
1932e3ecdffaSAlex Deucher * a page is 4KB so we have 12 bits offset, minimum 9 bits in the
1933e3ecdffaSAlex Deucher * page table and the remaining bits are in the page directory.
1934e3ecdffaSAlex Deucher */
amdgpu_device_check_block_size(struct amdgpu_device * adev)193506ec9070SAlex Deucher static void amdgpu_device_check_block_size(struct amdgpu_device *adev)
1936a1adf8beSChunming Zhou {
1937a1adf8beSChunming Zhou /* defines number of bits in page table versus page directory,
1938a1adf8beSChunming Zhou * a page is 4KB so we have 12 bits offset, minimum 9 bits in the
1939b8920e1eSSrinivasan Shanmugam * page table and the remaining bits are in the page directory
1940b8920e1eSSrinivasan Shanmugam */
1941bab4fee7SJunwei Zhang if (amdgpu_vm_block_size == -1)
1942bab4fee7SJunwei Zhang return;
1943a1adf8beSChunming Zhou
1944bab4fee7SJunwei Zhang if (amdgpu_vm_block_size < 9) {
1945a1adf8beSChunming Zhou dev_warn(adev->dev, "VM page table size (%d) too small\n",
1946a1adf8beSChunming Zhou amdgpu_vm_block_size);
1947bab4fee7SJunwei Zhang amdgpu_vm_block_size = -1;
1948a1adf8beSChunming Zhou }
194997489129SChristian König }
1950a1adf8beSChunming Zhou
1951e3ecdffaSAlex Deucher /**
1952e3ecdffaSAlex Deucher * amdgpu_device_check_vm_size - validate the vm size
1953e3ecdffaSAlex Deucher *
1954e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
1955e3ecdffaSAlex Deucher *
1956e3ecdffaSAlex Deucher * Validates the vm size in GB specified via module parameter.
1957e3ecdffaSAlex Deucher * The VM size is the size of the GPU virtual memory space in GB.
1958e3ecdffaSAlex Deucher */
amdgpu_device_check_vm_size(struct amdgpu_device * adev)195906ec9070SAlex Deucher static void amdgpu_device_check_vm_size(struct amdgpu_device *adev)
196083ca145dSZhang, Jerry {
196164dab074SAlex Deucher /* no need to check the default value */
196264dab074SAlex Deucher if (amdgpu_vm_size == -1)
196364dab074SAlex Deucher return;
196464dab074SAlex Deucher
196583ca145dSZhang, Jerry if (amdgpu_vm_size < 1) {
196683ca145dSZhang, Jerry dev_warn(adev->dev, "VM size (%d) too small, min is 1GB\n",
196783ca145dSZhang, Jerry amdgpu_vm_size);
1968bab4fee7SJunwei Zhang amdgpu_vm_size = -1;
196983ca145dSZhang, Jerry }
1970f3368128SChristian König }
197183ca145dSZhang, Jerry
amdgpu_device_check_smu_prv_buffer_size(struct amdgpu_device * adev)19727951e376SRex Zhu static void amdgpu_device_check_smu_prv_buffer_size(struct amdgpu_device *adev)
19737951e376SRex Zhu {
19747951e376SRex Zhu struct sysinfo si;
1975a9d4fe2fSNirmoy Das bool is_os_64 = (sizeof(void *) == 8);
19767951e376SRex Zhu uint64_t total_memory;
19777951e376SRex Zhu uint64_t dram_size_seven_GB = 0x1B8000000;
19787951e376SRex Zhu uint64_t dram_size_three_GB = 0xB8000000;
19797951e376SRex Zhu
19807951e376SRex Zhu if (amdgpu_smu_memory_pool_size == 0)
19817951e376SRex Zhu return;
19827951e376SRex Zhu
19837951e376SRex Zhu if (!is_os_64) {
19847951e376SRex Zhu DRM_WARN("Not 64-bit OS, feature not supported\n");
19857951e376SRex Zhu goto def_value;
19867951e376SRex Zhu }
19877951e376SRex Zhu si_meminfo(&si);
19887951e376SRex Zhu total_memory = (uint64_t)si.totalram * si.mem_unit;
19897951e376SRex Zhu
19907951e376SRex Zhu if ((amdgpu_smu_memory_pool_size == 1) ||
19917951e376SRex Zhu (amdgpu_smu_memory_pool_size == 2)) {
19927951e376SRex Zhu if (total_memory < dram_size_three_GB)
19937951e376SRex Zhu goto def_value1;
19947951e376SRex Zhu } else if ((amdgpu_smu_memory_pool_size == 4) ||
19957951e376SRex Zhu (amdgpu_smu_memory_pool_size == 8)) {
19967951e376SRex Zhu if (total_memory < dram_size_seven_GB)
19977951e376SRex Zhu goto def_value1;
19987951e376SRex Zhu } else {
19997951e376SRex Zhu DRM_WARN("Smu memory pool size not supported\n");
20007951e376SRex Zhu goto def_value;
20017951e376SRex Zhu }
20027951e376SRex Zhu adev->pm.smu_prv_buffer_size = amdgpu_smu_memory_pool_size << 28;
20037951e376SRex Zhu
20047951e376SRex Zhu return;
20057951e376SRex Zhu
20067951e376SRex Zhu def_value1:
20077951e376SRex Zhu DRM_WARN("No enough system memory\n");
20087951e376SRex Zhu def_value:
20097951e376SRex Zhu adev->pm.smu_prv_buffer_size = 0;
20107951e376SRex Zhu }
20117951e376SRex Zhu
amdgpu_device_init_apu_flags(struct amdgpu_device * adev)20129f6a7857SHuang Rui static int amdgpu_device_init_apu_flags(struct amdgpu_device *adev)
20139f6a7857SHuang Rui {
20149f6a7857SHuang Rui if (!(adev->flags & AMD_IS_APU) ||
20159f6a7857SHuang Rui adev->asic_type < CHIP_RAVEN)
20169f6a7857SHuang Rui return 0;
20179f6a7857SHuang Rui
20189f6a7857SHuang Rui switch (adev->asic_type) {
20199f6a7857SHuang Rui case CHIP_RAVEN:
20209f6a7857SHuang Rui if (adev->pdev->device == 0x15dd)
20219f6a7857SHuang Rui adev->apu_flags |= AMD_APU_IS_RAVEN;
20229f6a7857SHuang Rui if (adev->pdev->device == 0x15d8)
20239f6a7857SHuang Rui adev->apu_flags |= AMD_APU_IS_PICASSO;
20249f6a7857SHuang Rui break;
20259f6a7857SHuang Rui case CHIP_RENOIR:
20269f6a7857SHuang Rui if ((adev->pdev->device == 0x1636) ||
20279f6a7857SHuang Rui (adev->pdev->device == 0x164c))
20289f6a7857SHuang Rui adev->apu_flags |= AMD_APU_IS_RENOIR;
20299f6a7857SHuang Rui else
20309f6a7857SHuang Rui adev->apu_flags |= AMD_APU_IS_GREEN_SARDINE;
20319f6a7857SHuang Rui break;
20329f6a7857SHuang Rui case CHIP_VANGOGH:
20339f6a7857SHuang Rui adev->apu_flags |= AMD_APU_IS_VANGOGH;
20349f6a7857SHuang Rui break;
20359f6a7857SHuang Rui case CHIP_YELLOW_CARP:
20369f6a7857SHuang Rui break;
2037d0f56dc2STao Zhou case CHIP_CYAN_SKILLFISH:
2038dfcc3e8cSAlex Deucher if ((adev->pdev->device == 0x13FE) ||
2039dfcc3e8cSAlex Deucher (adev->pdev->device == 0x143F))
2040d0f56dc2STao Zhou adev->apu_flags |= AMD_APU_IS_CYAN_SKILLFISH2;
2041d0f56dc2STao Zhou break;
20429f6a7857SHuang Rui default:
20434eaf21b7SPrike Liang break;
20449f6a7857SHuang Rui }
20459f6a7857SHuang Rui
20469f6a7857SHuang Rui return 0;
20479f6a7857SHuang Rui }
20489f6a7857SHuang Rui
2049d38ceaf9SAlex Deucher /**
205006ec9070SAlex Deucher * amdgpu_device_check_arguments - validate module params
2051d38ceaf9SAlex Deucher *
2052d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
2053d38ceaf9SAlex Deucher *
2054d38ceaf9SAlex Deucher * Validates certain module parameters and updates
2055d38ceaf9SAlex Deucher * the associated values used by the driver (all asics).
2056d38ceaf9SAlex Deucher */
amdgpu_device_check_arguments(struct amdgpu_device * adev)2057912dfc84SEvan Quan static int amdgpu_device_check_arguments(struct amdgpu_device *adev)
2058d38ceaf9SAlex Deucher {
205996595204SSrinivasan Shanmugam int i;
206096595204SSrinivasan Shanmugam
20615b011235SChunming Zhou if (amdgpu_sched_jobs < 4) {
20625b011235SChunming Zhou dev_warn(adev->dev, "sched jobs (%d) must be at least 4\n",
20635b011235SChunming Zhou amdgpu_sched_jobs);
20645b011235SChunming Zhou amdgpu_sched_jobs = 4;
206576117507SAlex Deucher } else if (!is_power_of_2(amdgpu_sched_jobs)) {
20665b011235SChunming Zhou dev_warn(adev->dev, "sched jobs (%d) must be a power of 2\n",
20675b011235SChunming Zhou amdgpu_sched_jobs);
20685b011235SChunming Zhou amdgpu_sched_jobs = roundup_pow_of_two(amdgpu_sched_jobs);
20695b011235SChunming Zhou }
2070d38ceaf9SAlex Deucher
207183e74db6SAlex Deucher if (amdgpu_gart_size != -1 && amdgpu_gart_size < 32) {
2072f9321cc4SChristian König /* gart size must be greater or equal to 32M */
2073d38ceaf9SAlex Deucher dev_warn(adev->dev, "gart size (%d) too small\n",
2074d38ceaf9SAlex Deucher amdgpu_gart_size);
207583e74db6SAlex Deucher amdgpu_gart_size = -1;
2076d38ceaf9SAlex Deucher }
2077d38ceaf9SAlex Deucher
207836d38372SChristian König if (amdgpu_gtt_size != -1 && amdgpu_gtt_size < 32) {
207936d38372SChristian König /* gtt size must be greater or equal to 32M */
208036d38372SChristian König dev_warn(adev->dev, "gtt size (%d) too small\n",
208136d38372SChristian König amdgpu_gtt_size);
208236d38372SChristian König amdgpu_gtt_size = -1;
2083d38ceaf9SAlex Deucher }
2084d38ceaf9SAlex Deucher
2085d07f14beSRoger He /* valid range is between 4 and 9 inclusive */
2086d07f14beSRoger He if (amdgpu_vm_fragment_size != -1 &&
2087d07f14beSRoger He (amdgpu_vm_fragment_size > 9 || amdgpu_vm_fragment_size < 4)) {
2088d07f14beSRoger He dev_warn(adev->dev, "valid range is between 4 and 9\n");
2089d07f14beSRoger He amdgpu_vm_fragment_size = -1;
2090d07f14beSRoger He }
2091d07f14beSRoger He
20925d5bd5e3SKevin Wang if (amdgpu_sched_hw_submission < 2) {
20935d5bd5e3SKevin Wang dev_warn(adev->dev, "sched hw submission jobs (%d) must be at least 2\n",
20945d5bd5e3SKevin Wang amdgpu_sched_hw_submission);
20955d5bd5e3SKevin Wang amdgpu_sched_hw_submission = 2;
20965d5bd5e3SKevin Wang } else if (!is_power_of_2(amdgpu_sched_hw_submission)) {
20975d5bd5e3SKevin Wang dev_warn(adev->dev, "sched hw submission jobs (%d) must be a power of 2\n",
20985d5bd5e3SKevin Wang amdgpu_sched_hw_submission);
20995d5bd5e3SKevin Wang amdgpu_sched_hw_submission = roundup_pow_of_two(amdgpu_sched_hw_submission);
21005d5bd5e3SKevin Wang }
21015d5bd5e3SKevin Wang
21022656fd23SAndrey Grodzovsky if (amdgpu_reset_method < -1 || amdgpu_reset_method > 4) {
21032656fd23SAndrey Grodzovsky dev_warn(adev->dev, "invalid option for reset method, reverting to default\n");
21042656fd23SAndrey Grodzovsky amdgpu_reset_method = -1;
21052656fd23SAndrey Grodzovsky }
21062656fd23SAndrey Grodzovsky
21077951e376SRex Zhu amdgpu_device_check_smu_prv_buffer_size(adev);
21087951e376SRex Zhu
210906ec9070SAlex Deucher amdgpu_device_check_vm_size(adev);
2110d38ceaf9SAlex Deucher
211106ec9070SAlex Deucher amdgpu_device_check_block_size(adev);
21126a7f76e7SChristian König
211319aede77SAlex Deucher adev->firmware.load_type = amdgpu_ucode_get_load_type(adev, amdgpu_fw_load_type);
2114912dfc84SEvan Quan
211596595204SSrinivasan Shanmugam for (i = 0; i < MAX_XCP; i++)
211696595204SSrinivasan Shanmugam adev->enforce_isolation[i] = !!enforce_isolation;
211796595204SSrinivasan Shanmugam
2118e3c00faaSMa Feng return 0;
2119d38ceaf9SAlex Deucher }
2120d38ceaf9SAlex Deucher
2121d38ceaf9SAlex Deucher /**
2122d38ceaf9SAlex Deucher * amdgpu_switcheroo_set_state - set switcheroo state
2123d38ceaf9SAlex Deucher *
2124d38ceaf9SAlex Deucher * @pdev: pci dev pointer
21251694467bSLukas Wunner * @state: vga_switcheroo state
2126d38ceaf9SAlex Deucher *
212712024b17Swangjianli * Callback for the switcheroo driver. Suspends or resumes
2128d38ceaf9SAlex Deucher * the asics before or after it is powered up using ACPI methods.
2129d38ceaf9SAlex Deucher */
amdgpu_switcheroo_set_state(struct pci_dev * pdev,enum vga_switcheroo_state state)21308aba21b7SLuben Tuikov static void amdgpu_switcheroo_set_state(struct pci_dev *pdev,
21318aba21b7SLuben Tuikov enum vga_switcheroo_state state)
2132d38ceaf9SAlex Deucher {
2133d38ceaf9SAlex Deucher struct drm_device *dev = pci_get_drvdata(pdev);
2134de185019SAlex Deucher int r;
2135d38ceaf9SAlex Deucher
2136b98c6299SAlex Deucher if (amdgpu_device_supports_px(dev) && state == VGA_SWITCHEROO_OFF)
2137d38ceaf9SAlex Deucher return;
2138d38ceaf9SAlex Deucher
2139d38ceaf9SAlex Deucher if (state == VGA_SWITCHEROO_ON) {
2140dd4fa6c1SAurabindo Pillai pr_info("switched on\n");
2141d38ceaf9SAlex Deucher /* don't suspend or resume card normally */
2142d38ceaf9SAlex Deucher dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
2143d38ceaf9SAlex Deucher
21448f66090bSThomas Zimmermann pci_set_power_state(pdev, PCI_D0);
21458f66090bSThomas Zimmermann amdgpu_device_load_pci_state(pdev);
21468f66090bSThomas Zimmermann r = pci_enable_device(pdev);
2147de185019SAlex Deucher if (r)
2148de185019SAlex Deucher DRM_WARN("pci_enable_device failed (%d)\n", r);
2149de185019SAlex Deucher amdgpu_device_resume(dev, true);
2150d38ceaf9SAlex Deucher
2151d38ceaf9SAlex Deucher dev->switch_power_state = DRM_SWITCH_POWER_ON;
2152d38ceaf9SAlex Deucher } else {
2153dd4fa6c1SAurabindo Pillai pr_info("switched off\n");
2154d38ceaf9SAlex Deucher dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
21555095d541SMario Limonciello amdgpu_device_prepare(dev);
2156de185019SAlex Deucher amdgpu_device_suspend(dev, true);
21578f66090bSThomas Zimmermann amdgpu_device_cache_pci_state(pdev);
2158de185019SAlex Deucher /* Shut down the device */
21598f66090bSThomas Zimmermann pci_disable_device(pdev);
21608f66090bSThomas Zimmermann pci_set_power_state(pdev, PCI_D3cold);
2161d38ceaf9SAlex Deucher dev->switch_power_state = DRM_SWITCH_POWER_OFF;
2162d38ceaf9SAlex Deucher }
2163d38ceaf9SAlex Deucher }
2164d38ceaf9SAlex Deucher
2165d38ceaf9SAlex Deucher /**
2166d38ceaf9SAlex Deucher * amdgpu_switcheroo_can_switch - see if switcheroo state can change
2167d38ceaf9SAlex Deucher *
2168d38ceaf9SAlex Deucher * @pdev: pci dev pointer
2169d38ceaf9SAlex Deucher *
2170d38ceaf9SAlex Deucher * Callback for the switcheroo driver. Check of the switcheroo
2171d38ceaf9SAlex Deucher * state can be changed.
2172d38ceaf9SAlex Deucher * Returns true if the state can be changed, false if not.
2173d38ceaf9SAlex Deucher */
amdgpu_switcheroo_can_switch(struct pci_dev * pdev)2174d38ceaf9SAlex Deucher static bool amdgpu_switcheroo_can_switch(struct pci_dev *pdev)
2175d38ceaf9SAlex Deucher {
2176d38ceaf9SAlex Deucher struct drm_device *dev = pci_get_drvdata(pdev);
2177d38ceaf9SAlex Deucher
2178d38ceaf9SAlex Deucher /*
2179d38ceaf9SAlex Deucher * FIXME: open_count is protected by drm_global_mutex but that would lead to
2180d38ceaf9SAlex Deucher * locking inversion with the driver load path. And the access here is
2181d38ceaf9SAlex Deucher * completely racy anyway. So don't bother with locking for now.
2182d38ceaf9SAlex Deucher */
21837e13ad89SChris Wilson return atomic_read(&dev->open_count) == 0;
2184d38ceaf9SAlex Deucher }
2185d38ceaf9SAlex Deucher
2186d38ceaf9SAlex Deucher static const struct vga_switcheroo_client_ops amdgpu_switcheroo_ops = {
2187d38ceaf9SAlex Deucher .set_gpu_state = amdgpu_switcheroo_set_state,
2188d38ceaf9SAlex Deucher .reprobe = NULL,
2189d38ceaf9SAlex Deucher .can_switch = amdgpu_switcheroo_can_switch,
2190d38ceaf9SAlex Deucher };
2191d38ceaf9SAlex Deucher
2192e3ecdffaSAlex Deucher /**
2193e3ecdffaSAlex Deucher * amdgpu_device_ip_set_clockgating_state - set the CG state
2194e3ecdffaSAlex Deucher *
219587e3f136SDarren Powell * @dev: amdgpu_device pointer
2196e3ecdffaSAlex Deucher * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.)
2197e3ecdffaSAlex Deucher * @state: clockgating state (gate or ungate)
2198e3ecdffaSAlex Deucher *
2199e3ecdffaSAlex Deucher * Sets the requested clockgating state for all instances of
2200e3ecdffaSAlex Deucher * the hardware IP specified.
2201e3ecdffaSAlex Deucher * Returns the error code from the last instance.
2202e3ecdffaSAlex Deucher */
amdgpu_device_ip_set_clockgating_state(void * dev,enum amd_ip_block_type block_type,enum amd_clockgating_state state)220343fa561fSRex Zhu int amdgpu_device_ip_set_clockgating_state(void *dev,
22045fc3aeebSyanyang1 enum amd_ip_block_type block_type,
22055fc3aeebSyanyang1 enum amd_clockgating_state state)
2206d38ceaf9SAlex Deucher {
220743fa561fSRex Zhu struct amdgpu_device *adev = dev;
2208d38ceaf9SAlex Deucher int i, r = 0;
2209d38ceaf9SAlex Deucher
2210d38ceaf9SAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
2211a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
22129ecbe7f5SAlex Deucher continue;
2213c722865aSRex Zhu if (adev->ip_blocks[i].version->type != block_type)
2214c722865aSRex Zhu continue;
2215c722865aSRex Zhu if (!adev->ip_blocks[i].version->funcs->set_clockgating_state)
2216c722865aSRex Zhu continue;
2217c722865aSRex Zhu r = adev->ip_blocks[i].version->funcs->set_clockgating_state(
2218f2ba8c3dSBoyuan Zhang &adev->ip_blocks[i], state);
2219d38ceaf9SAlex Deucher if (r)
2220c722865aSRex Zhu DRM_ERROR("set_clockgating_state of IP block <%s> failed %d\n",
2221c722865aSRex Zhu adev->ip_blocks[i].version->funcs->name, r);
2222d38ceaf9SAlex Deucher }
2223d38ceaf9SAlex Deucher return r;
2224d38ceaf9SAlex Deucher }
2225d38ceaf9SAlex Deucher
2226e3ecdffaSAlex Deucher /**
2227e3ecdffaSAlex Deucher * amdgpu_device_ip_set_powergating_state - set the PG state
2228e3ecdffaSAlex Deucher *
222987e3f136SDarren Powell * @dev: amdgpu_device pointer
2230e3ecdffaSAlex Deucher * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.)
2231e3ecdffaSAlex Deucher * @state: powergating state (gate or ungate)
2232e3ecdffaSAlex Deucher *
2233e3ecdffaSAlex Deucher * Sets the requested powergating state for all instances of
2234e3ecdffaSAlex Deucher * the hardware IP specified.
2235e3ecdffaSAlex Deucher * Returns the error code from the last instance.
2236e3ecdffaSAlex Deucher */
amdgpu_device_ip_set_powergating_state(void * dev,enum amd_ip_block_type block_type,enum amd_powergating_state state)223743fa561fSRex Zhu int amdgpu_device_ip_set_powergating_state(void *dev,
22385fc3aeebSyanyang1 enum amd_ip_block_type block_type,
22395fc3aeebSyanyang1 enum amd_powergating_state state)
2240d38ceaf9SAlex Deucher {
224143fa561fSRex Zhu struct amdgpu_device *adev = dev;
2242d38ceaf9SAlex Deucher int i, r = 0;
2243d38ceaf9SAlex Deucher
2244d38ceaf9SAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
2245a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
22469ecbe7f5SAlex Deucher continue;
2247c722865aSRex Zhu if (adev->ip_blocks[i].version->type != block_type)
2248c722865aSRex Zhu continue;
2249c722865aSRex Zhu if (!adev->ip_blocks[i].version->funcs->set_powergating_state)
2250c722865aSRex Zhu continue;
2251c722865aSRex Zhu r = adev->ip_blocks[i].version->funcs->set_powergating_state(
225280d80511SBoyuan Zhang &adev->ip_blocks[i], state);
2253d38ceaf9SAlex Deucher if (r)
2254c722865aSRex Zhu DRM_ERROR("set_powergating_state of IP block <%s> failed %d\n",
2255c722865aSRex Zhu adev->ip_blocks[i].version->funcs->name, r);
2256d38ceaf9SAlex Deucher }
2257d38ceaf9SAlex Deucher return r;
2258d38ceaf9SAlex Deucher }
2259d38ceaf9SAlex Deucher
2260e3ecdffaSAlex Deucher /**
2261e3ecdffaSAlex Deucher * amdgpu_device_ip_get_clockgating_state - get the CG state
2262e3ecdffaSAlex Deucher *
2263e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
2264e3ecdffaSAlex Deucher * @flags: clockgating feature flags
2265e3ecdffaSAlex Deucher *
2266e3ecdffaSAlex Deucher * Walks the list of IPs on the device and updates the clockgating
2267e3ecdffaSAlex Deucher * flags for each IP.
2268e3ecdffaSAlex Deucher * Updates @flags with the feature flags for each hardware IP where
2269e3ecdffaSAlex Deucher * clockgating is enabled.
2270e3ecdffaSAlex Deucher */
amdgpu_device_ip_get_clockgating_state(struct amdgpu_device * adev,u64 * flags)22712990a1fcSAlex Deucher void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev,
227225faeddcSEvan Quan u64 *flags)
22736cb2d4e4SHuang Rui {
22746cb2d4e4SHuang Rui int i;
22756cb2d4e4SHuang Rui
22766cb2d4e4SHuang Rui for (i = 0; i < adev->num_ip_blocks; i++) {
22776cb2d4e4SHuang Rui if (!adev->ip_blocks[i].status.valid)
22786cb2d4e4SHuang Rui continue;
22796cb2d4e4SHuang Rui if (adev->ip_blocks[i].version->funcs->get_clockgating_state)
22803521276aSSunil Khatri adev->ip_blocks[i].version->funcs->get_clockgating_state(
22813521276aSSunil Khatri &adev->ip_blocks[i], flags);
22826cb2d4e4SHuang Rui }
22836cb2d4e4SHuang Rui }
22846cb2d4e4SHuang Rui
2285e3ecdffaSAlex Deucher /**
2286e3ecdffaSAlex Deucher * amdgpu_device_ip_wait_for_idle - wait for idle
2287e3ecdffaSAlex Deucher *
2288e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
2289e3ecdffaSAlex Deucher * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.)
2290e3ecdffaSAlex Deucher *
2291e3ecdffaSAlex Deucher * Waits for the request hardware IP to be idle.
2292e3ecdffaSAlex Deucher * Returns 0 for success or a negative error code on failure.
2293e3ecdffaSAlex Deucher */
amdgpu_device_ip_wait_for_idle(struct amdgpu_device * adev,enum amd_ip_block_type block_type)22942990a1fcSAlex Deucher int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev,
22955dbbb60bSAlex Deucher enum amd_ip_block_type block_type)
22965dbbb60bSAlex Deucher {
22975dbbb60bSAlex Deucher int i, r;
22985dbbb60bSAlex Deucher
22995dbbb60bSAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
2300a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
23019ecbe7f5SAlex Deucher continue;
2302a1255107SAlex Deucher if (adev->ip_blocks[i].version->type == block_type) {
2303780002b6SSunil Khatri if (adev->ip_blocks[i].version->funcs->wait_for_idle) {
2304780002b6SSunil Khatri r = adev->ip_blocks[i].version->funcs->wait_for_idle(
2305780002b6SSunil Khatri &adev->ip_blocks[i]);
23065dbbb60bSAlex Deucher if (r)
23075dbbb60bSAlex Deucher return r;
2308780002b6SSunil Khatri }
23095dbbb60bSAlex Deucher break;
23105dbbb60bSAlex Deucher }
23115dbbb60bSAlex Deucher }
23125dbbb60bSAlex Deucher return 0;
23135dbbb60bSAlex Deucher
23145dbbb60bSAlex Deucher }
23155dbbb60bSAlex Deucher
2316e3ecdffaSAlex Deucher /**
2317dc443aa4SAsad Kamal * amdgpu_device_ip_is_valid - is the hardware IP enabled
2318e3ecdffaSAlex Deucher *
2319e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
2320e3ecdffaSAlex Deucher * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.)
2321e3ecdffaSAlex Deucher *
2322dc443aa4SAsad Kamal * Check if the hardware IP is enable or not.
2323dc443aa4SAsad Kamal * Returns true if it the IP is enable, false if not.
2324e3ecdffaSAlex Deucher */
amdgpu_device_ip_is_valid(struct amdgpu_device * adev,enum amd_ip_block_type block_type)2325dc443aa4SAsad Kamal bool amdgpu_device_ip_is_valid(struct amdgpu_device *adev,
23265dbbb60bSAlex Deucher enum amd_ip_block_type block_type)
23275dbbb60bSAlex Deucher {
23285dbbb60bSAlex Deucher int i;
23295dbbb60bSAlex Deucher
23305dbbb60bSAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
2331a1255107SAlex Deucher if (adev->ip_blocks[i].version->type == block_type)
2332dc443aa4SAsad Kamal return adev->ip_blocks[i].status.valid;
23335dbbb60bSAlex Deucher }
2334dc443aa4SAsad Kamal return false;
23355dbbb60bSAlex Deucher
23365dbbb60bSAlex Deucher }
23375dbbb60bSAlex Deucher
2338e3ecdffaSAlex Deucher /**
2339e3ecdffaSAlex Deucher * amdgpu_device_ip_get_ip_block - get a hw IP pointer
2340e3ecdffaSAlex Deucher *
2341e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
234287e3f136SDarren Powell * @type: Type of hardware IP (SMU, GFX, UVD, etc.)
2343e3ecdffaSAlex Deucher *
2344e3ecdffaSAlex Deucher * Returns a pointer to the hardware IP block structure
2345e3ecdffaSAlex Deucher * if it exists for the asic, otherwise NULL.
2346e3ecdffaSAlex Deucher */
23472990a1fcSAlex Deucher struct amdgpu_ip_block *
amdgpu_device_ip_get_ip_block(struct amdgpu_device * adev,enum amd_ip_block_type type)23482990a1fcSAlex Deucher amdgpu_device_ip_get_ip_block(struct amdgpu_device *adev,
23495fc3aeebSyanyang1 enum amd_ip_block_type type)
2350d38ceaf9SAlex Deucher {
2351d38ceaf9SAlex Deucher int i;
2352d38ceaf9SAlex Deucher
2353d38ceaf9SAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++)
2354a1255107SAlex Deucher if (adev->ip_blocks[i].version->type == type)
2355d38ceaf9SAlex Deucher return &adev->ip_blocks[i];
2356d38ceaf9SAlex Deucher
2357d38ceaf9SAlex Deucher return NULL;
2358d38ceaf9SAlex Deucher }
2359d38ceaf9SAlex Deucher
2360d38ceaf9SAlex Deucher /**
23612990a1fcSAlex Deucher * amdgpu_device_ip_block_version_cmp
2362d38ceaf9SAlex Deucher *
2363d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
23645fc3aeebSyanyang1 * @type: enum amd_ip_block_type
2365d38ceaf9SAlex Deucher * @major: major version
2366d38ceaf9SAlex Deucher * @minor: minor version
2367d38ceaf9SAlex Deucher *
2368d38ceaf9SAlex Deucher * return 0 if equal or greater
2369d38ceaf9SAlex Deucher * return 1 if smaller or the ip_block doesn't exist
2370d38ceaf9SAlex Deucher */
amdgpu_device_ip_block_version_cmp(struct amdgpu_device * adev,enum amd_ip_block_type type,u32 major,u32 minor)23712990a1fcSAlex Deucher int amdgpu_device_ip_block_version_cmp(struct amdgpu_device *adev,
23725fc3aeebSyanyang1 enum amd_ip_block_type type,
2373d38ceaf9SAlex Deucher u32 major, u32 minor)
2374d38ceaf9SAlex Deucher {
23752990a1fcSAlex Deucher struct amdgpu_ip_block *ip_block = amdgpu_device_ip_get_ip_block(adev, type);
2376d38ceaf9SAlex Deucher
2377a1255107SAlex Deucher if (ip_block && ((ip_block->version->major > major) ||
2378a1255107SAlex Deucher ((ip_block->version->major == major) &&
2379a1255107SAlex Deucher (ip_block->version->minor >= minor))))
2380d38ceaf9SAlex Deucher return 0;
2381d38ceaf9SAlex Deucher
2382d38ceaf9SAlex Deucher return 1;
2383d38ceaf9SAlex Deucher }
2384d38ceaf9SAlex Deucher
2385a1255107SAlex Deucher /**
23862990a1fcSAlex Deucher * amdgpu_device_ip_block_add
2387a1255107SAlex Deucher *
2388a1255107SAlex Deucher * @adev: amdgpu_device pointer
2389a1255107SAlex Deucher * @ip_block_version: pointer to the IP to add
2390a1255107SAlex Deucher *
2391a1255107SAlex Deucher * Adds the IP block driver information to the collection of IPs
2392a1255107SAlex Deucher * on the asic.
2393a1255107SAlex Deucher */
amdgpu_device_ip_block_add(struct amdgpu_device * adev,const struct amdgpu_ip_block_version * ip_block_version)23942990a1fcSAlex Deucher int amdgpu_device_ip_block_add(struct amdgpu_device *adev,
2395a1255107SAlex Deucher const struct amdgpu_ip_block_version *ip_block_version)
2396a1255107SAlex Deucher {
2397a1255107SAlex Deucher if (!ip_block_version)
2398a1255107SAlex Deucher return -EINVAL;
2399a1255107SAlex Deucher
24007bd939d0SLikun GAO switch (ip_block_version->type) {
24017bd939d0SLikun GAO case AMD_IP_BLOCK_TYPE_VCN:
24027bd939d0SLikun GAO if (adev->harvest_ip_mask & AMD_HARVEST_IP_VCN_MASK)
24037bd939d0SLikun GAO return 0;
24047bd939d0SLikun GAO break;
24057bd939d0SLikun GAO case AMD_IP_BLOCK_TYPE_JPEG:
24067bd939d0SLikun GAO if (adev->harvest_ip_mask & AMD_HARVEST_IP_JPEG_MASK)
24077bd939d0SLikun GAO return 0;
24087bd939d0SLikun GAO break;
24097bd939d0SLikun GAO default:
24107bd939d0SLikun GAO break;
24117bd939d0SLikun GAO }
24127bd939d0SLikun GAO
2413a0db1ea0SLijo Lazar dev_info(adev->dev, "detected ip block number %d <%s>\n",
2414a0db1ea0SLijo Lazar adev->num_ip_blocks, ip_block_version->funcs->name);
2415a0bae357SHuang Rui
241637b99322SSunil Khatri adev->ip_blocks[adev->num_ip_blocks].adev = adev;
241737b99322SSunil Khatri
2418a1255107SAlex Deucher adev->ip_blocks[adev->num_ip_blocks++].version = ip_block_version;
2419a1255107SAlex Deucher
2420a1255107SAlex Deucher return 0;
2421a1255107SAlex Deucher }
2422a1255107SAlex Deucher
2423e3ecdffaSAlex Deucher /**
2424e3ecdffaSAlex Deucher * amdgpu_device_enable_virtual_display - enable virtual display feature
2425e3ecdffaSAlex Deucher *
2426e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
2427e3ecdffaSAlex Deucher *
2428e3ecdffaSAlex Deucher * Enabled the virtual display feature if the user has enabled it via
2429e3ecdffaSAlex Deucher * the module parameter virtual_display. This feature provides a virtual
2430e3ecdffaSAlex Deucher * display hardware on headless boards or in virtualized environments.
2431e3ecdffaSAlex Deucher * This function parses and validates the configuration string specified by
2432a567db80SRandy Dunlap * the user and configures the virtual display configuration (number of
2433e3ecdffaSAlex Deucher * virtual connectors, crtcs, etc.) specified.
2434e3ecdffaSAlex Deucher */
amdgpu_device_enable_virtual_display(struct amdgpu_device * adev)2435483ef985SAlex Deucher static void amdgpu_device_enable_virtual_display(struct amdgpu_device *adev)
24369accf2fdSEmily Deng {
24379accf2fdSEmily Deng adev->enable_virtual_display = false;
24389accf2fdSEmily Deng
24399accf2fdSEmily Deng if (amdgpu_virtual_display) {
24408f66090bSThomas Zimmermann const char *pci_address_name = pci_name(adev->pdev);
24410f66356dSEmily Deng char *pciaddstr, *pciaddstr_tmp, *pciaddname_tmp, *pciaddname;
24429accf2fdSEmily Deng
24439accf2fdSEmily Deng pciaddstr = kstrdup(amdgpu_virtual_display, GFP_KERNEL);
24449accf2fdSEmily Deng pciaddstr_tmp = pciaddstr;
24450f66356dSEmily Deng while ((pciaddname_tmp = strsep(&pciaddstr_tmp, ";"))) {
24460f66356dSEmily Deng pciaddname = strsep(&pciaddname_tmp, ",");
2447967de2a9SYintian Tao if (!strcmp("all", pciaddname)
2448967de2a9SYintian Tao || !strcmp(pci_address_name, pciaddname)) {
24490f66356dSEmily Deng long num_crtc;
24500f66356dSEmily Deng int res = -1;
24510f66356dSEmily Deng
24529accf2fdSEmily Deng adev->enable_virtual_display = true;
24530f66356dSEmily Deng
24540f66356dSEmily Deng if (pciaddname_tmp)
24550f66356dSEmily Deng res = kstrtol(pciaddname_tmp, 10,
24560f66356dSEmily Deng &num_crtc);
24570f66356dSEmily Deng
24580f66356dSEmily Deng if (!res) {
24590f66356dSEmily Deng if (num_crtc < 1)
24600f66356dSEmily Deng num_crtc = 1;
24610f66356dSEmily Deng if (num_crtc > 6)
24620f66356dSEmily Deng num_crtc = 6;
24630f66356dSEmily Deng adev->mode_info.num_crtc = num_crtc;
24640f66356dSEmily Deng } else {
24650f66356dSEmily Deng adev->mode_info.num_crtc = 1;
24660f66356dSEmily Deng }
24679accf2fdSEmily Deng break;
24689accf2fdSEmily Deng }
24699accf2fdSEmily Deng }
24709accf2fdSEmily Deng
24710f66356dSEmily Deng DRM_INFO("virtual display string:%s, %s:virtual_display:%d, num_crtc:%d\n",
24729accf2fdSEmily Deng amdgpu_virtual_display, pci_address_name,
24730f66356dSEmily Deng adev->enable_virtual_display, adev->mode_info.num_crtc);
24749accf2fdSEmily Deng
24759accf2fdSEmily Deng kfree(pciaddstr);
24769accf2fdSEmily Deng }
24779accf2fdSEmily Deng }
24789accf2fdSEmily Deng
amdgpu_device_set_sriov_virtual_display(struct amdgpu_device * adev)247925263da3SAlex Deucher void amdgpu_device_set_sriov_virtual_display(struct amdgpu_device *adev)
248025263da3SAlex Deucher {
248125263da3SAlex Deucher if (amdgpu_sriov_vf(adev) && !adev->enable_virtual_display) {
248225263da3SAlex Deucher adev->mode_info.num_crtc = 1;
248325263da3SAlex Deucher adev->enable_virtual_display = true;
248425263da3SAlex Deucher DRM_INFO("virtual_display:%d, num_crtc:%d\n",
248525263da3SAlex Deucher adev->enable_virtual_display, adev->mode_info.num_crtc);
248625263da3SAlex Deucher }
248725263da3SAlex Deucher }
248825263da3SAlex Deucher
2489e3ecdffaSAlex Deucher /**
2490e3ecdffaSAlex Deucher * amdgpu_device_parse_gpu_info_fw - parse gpu info firmware
2491e3ecdffaSAlex Deucher *
2492e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
2493e3ecdffaSAlex Deucher *
2494e3ecdffaSAlex Deucher * Parses the asic configuration parameters specified in the gpu info
2495a567db80SRandy Dunlap * firmware and makes them available to the driver for use in configuring
2496e3ecdffaSAlex Deucher * the asic.
2497e3ecdffaSAlex Deucher * Returns 0 on success, -EINVAL on failure.
2498e3ecdffaSAlex Deucher */
amdgpu_device_parse_gpu_info_fw(struct amdgpu_device * adev)2499e2a75f88SAlex Deucher static int amdgpu_device_parse_gpu_info_fw(struct amdgpu_device *adev)
2500e2a75f88SAlex Deucher {
2501e2a75f88SAlex Deucher const char *chip_name;
2502e2a75f88SAlex Deucher int err;
2503e2a75f88SAlex Deucher const struct gpu_info_firmware_header_v1_0 *hdr;
2504e2a75f88SAlex Deucher
2505ab4fe3e1SHuang Rui adev->firmware.gpu_info_fw = NULL;
2506ab4fe3e1SHuang Rui
2507fb915c87SAlex Deucher if (adev->mman.discovery_bin)
2508258620d0SAlex Deucher return 0;
2509258620d0SAlex Deucher
2510e2a75f88SAlex Deucher switch (adev->asic_type) {
2511e2a75f88SAlex Deucher default:
2512e2a75f88SAlex Deucher return 0;
2513e2a75f88SAlex Deucher case CHIP_VEGA10:
2514e2a75f88SAlex Deucher chip_name = "vega10";
2515e2a75f88SAlex Deucher break;
25163f76dcedSAlex Deucher case CHIP_VEGA12:
25173f76dcedSAlex Deucher chip_name = "vega12";
25183f76dcedSAlex Deucher break;
25192d2e5e7eSAlex Deucher case CHIP_RAVEN:
252054f78a76SAlex Deucher if (adev->apu_flags & AMD_APU_IS_RAVEN2)
252154c4d17eSFeifei Xu chip_name = "raven2";
252254f78a76SAlex Deucher else if (adev->apu_flags & AMD_APU_IS_PICASSO)
2523741deadeSAlex Deucher chip_name = "picasso";
252454c4d17eSFeifei Xu else
25252d2e5e7eSAlex Deucher chip_name = "raven";
25262d2e5e7eSAlex Deucher break;
252765e60f6eSLe Ma case CHIP_ARCTURUS:
252865e60f6eSLe Ma chip_name = "arcturus";
252965e60f6eSLe Ma break;
253042b325e5SXiaojie Yuan case CHIP_NAVI12:
253142b325e5SXiaojie Yuan chip_name = "navi12";
253242b325e5SXiaojie Yuan break;
2533e2a75f88SAlex Deucher }
2534e2a75f88SAlex Deucher
2535a777c9d7SYang Wang err = amdgpu_ucode_request(adev, &adev->firmware.gpu_info_fw,
2536ea5d4934SMario Limonciello AMDGPU_UCODE_OPTIONAL,
2537a777c9d7SYang Wang "amdgpu/%s_gpu_info.bin", chip_name);
2538e2a75f88SAlex Deucher if (err) {
2539e2a75f88SAlex Deucher dev_err(adev->dev,
2540a777c9d7SYang Wang "Failed to get gpu_info firmware \"%s_gpu_info.bin\"\n",
2541a777c9d7SYang Wang chip_name);
2542e2a75f88SAlex Deucher goto out;
2543e2a75f88SAlex Deucher }
2544e2a75f88SAlex Deucher
2545ab4fe3e1SHuang Rui hdr = (const struct gpu_info_firmware_header_v1_0 *)adev->firmware.gpu_info_fw->data;
2546e2a75f88SAlex Deucher amdgpu_ucode_print_gpu_info_hdr(&hdr->header);
2547e2a75f88SAlex Deucher
2548e2a75f88SAlex Deucher switch (hdr->version_major) {
2549e2a75f88SAlex Deucher case 1:
2550e2a75f88SAlex Deucher {
2551e2a75f88SAlex Deucher const struct gpu_info_firmware_v1_0 *gpu_info_fw =
2552ab4fe3e1SHuang Rui (const struct gpu_info_firmware_v1_0 *)(adev->firmware.gpu_info_fw->data +
2553e2a75f88SAlex Deucher le32_to_cpu(hdr->header.ucode_array_offset_bytes));
2554e2a75f88SAlex Deucher
2555cc375d8cSTianci.Yin /*
2556a567db80SRandy Dunlap * Should be dropped when DAL no longer needs it.
2557cc375d8cSTianci.Yin */
2558cc375d8cSTianci.Yin if (adev->asic_type == CHIP_NAVI12)
2559ec51d3faSXiaojie Yuan goto parse_soc_bounding_box;
2560ec51d3faSXiaojie Yuan
2561b5ab16bfSAlex Deucher adev->gfx.config.max_shader_engines = le32_to_cpu(gpu_info_fw->gc_num_se);
2562b5ab16bfSAlex Deucher adev->gfx.config.max_cu_per_sh = le32_to_cpu(gpu_info_fw->gc_num_cu_per_sh);
2563b5ab16bfSAlex Deucher adev->gfx.config.max_sh_per_se = le32_to_cpu(gpu_info_fw->gc_num_sh_per_se);
2564b5ab16bfSAlex Deucher adev->gfx.config.max_backends_per_se = le32_to_cpu(gpu_info_fw->gc_num_rb_per_se);
2565e2a75f88SAlex Deucher adev->gfx.config.max_texture_channel_caches =
2566b5ab16bfSAlex Deucher le32_to_cpu(gpu_info_fw->gc_num_tccs);
2567b5ab16bfSAlex Deucher adev->gfx.config.max_gprs = le32_to_cpu(gpu_info_fw->gc_num_gprs);
2568b5ab16bfSAlex Deucher adev->gfx.config.max_gs_threads = le32_to_cpu(gpu_info_fw->gc_num_max_gs_thds);
2569b5ab16bfSAlex Deucher adev->gfx.config.gs_vgt_table_depth = le32_to_cpu(gpu_info_fw->gc_gs_table_depth);
2570b5ab16bfSAlex Deucher adev->gfx.config.gs_prim_buffer_depth = le32_to_cpu(gpu_info_fw->gc_gsprim_buff_depth);
2571e2a75f88SAlex Deucher adev->gfx.config.double_offchip_lds_buf =
2572b5ab16bfSAlex Deucher le32_to_cpu(gpu_info_fw->gc_double_offchip_lds_buffer);
2573b5ab16bfSAlex Deucher adev->gfx.cu_info.wave_front_size = le32_to_cpu(gpu_info_fw->gc_wave_size);
257451fd0370SHawking Zhang adev->gfx.cu_info.max_waves_per_simd =
257551fd0370SHawking Zhang le32_to_cpu(gpu_info_fw->gc_max_waves_per_simd);
257651fd0370SHawking Zhang adev->gfx.cu_info.max_scratch_slots_per_cu =
257751fd0370SHawking Zhang le32_to_cpu(gpu_info_fw->gc_max_scratch_slots_per_cu);
257851fd0370SHawking Zhang adev->gfx.cu_info.lds_size = le32_to_cpu(gpu_info_fw->gc_lds_size);
257948321c3dSHarry Wentland if (hdr->version_minor >= 1) {
258035c2e910SHawking Zhang const struct gpu_info_firmware_v1_1 *gpu_info_fw =
258135c2e910SHawking Zhang (const struct gpu_info_firmware_v1_1 *)(adev->firmware.gpu_info_fw->data +
258235c2e910SHawking Zhang le32_to_cpu(hdr->header.ucode_array_offset_bytes));
258335c2e910SHawking Zhang adev->gfx.config.num_sc_per_sh =
258435c2e910SHawking Zhang le32_to_cpu(gpu_info_fw->num_sc_per_sh);
258535c2e910SHawking Zhang adev->gfx.config.num_packer_per_sc =
258635c2e910SHawking Zhang le32_to_cpu(gpu_info_fw->num_packer_per_sc);
258735c2e910SHawking Zhang }
2588ec51d3faSXiaojie Yuan
2589ec51d3faSXiaojie Yuan parse_soc_bounding_box:
2590ec51d3faSXiaojie Yuan /*
2591ec51d3faSXiaojie Yuan * soc bounding box info is not integrated in disocovery table,
2592258620d0SAlex Deucher * we always need to parse it from gpu info firmware if needed.
2593ec51d3faSXiaojie Yuan */
259448321c3dSHarry Wentland if (hdr->version_minor == 2) {
259548321c3dSHarry Wentland const struct gpu_info_firmware_v1_2 *gpu_info_fw =
259648321c3dSHarry Wentland (const struct gpu_info_firmware_v1_2 *)(adev->firmware.gpu_info_fw->data +
259748321c3dSHarry Wentland le32_to_cpu(hdr->header.ucode_array_offset_bytes));
259848321c3dSHarry Wentland adev->dm.soc_bounding_box = &gpu_info_fw->soc_bounding_box;
259948321c3dSHarry Wentland }
2600e2a75f88SAlex Deucher break;
2601e2a75f88SAlex Deucher }
2602e2a75f88SAlex Deucher default:
2603e2a75f88SAlex Deucher dev_err(adev->dev,
2604e2a75f88SAlex Deucher "Unsupported gpu_info table %d\n", hdr->header.ucode_version);
2605e2a75f88SAlex Deucher err = -EINVAL;
2606e2a75f88SAlex Deucher goto out;
2607e2a75f88SAlex Deucher }
2608e2a75f88SAlex Deucher out:
2609e2a75f88SAlex Deucher return err;
2610e2a75f88SAlex Deucher }
2611e2a75f88SAlex Deucher
2612e3ecdffaSAlex Deucher /**
2613e3ecdffaSAlex Deucher * amdgpu_device_ip_early_init - run early init for hardware IPs
2614e3ecdffaSAlex Deucher *
2615e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
2616e3ecdffaSAlex Deucher *
2617e3ecdffaSAlex Deucher * Early initialization pass for hardware IPs. The hardware IPs that make
2618e3ecdffaSAlex Deucher * up each asic are discovered each IP's early_init callback is run. This
2619e3ecdffaSAlex Deucher * is the first stage in initializing the asic.
2620e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
2621e3ecdffaSAlex Deucher */
amdgpu_device_ip_early_init(struct amdgpu_device * adev)262206ec9070SAlex Deucher static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
2623d38ceaf9SAlex Deucher {
26243b37e272SYifan Zhang struct amdgpu_ip_block *ip_block;
2625901e2be2SAlex Deucher struct pci_dev *parent;
26267e0aa706SLijo Lazar bool total, skip_bios;
26277e0aa706SLijo Lazar uint32_t bios_flags;
2628aaa36a97SAlex Deucher int i, r;
2629d38ceaf9SAlex Deucher
2630483ef985SAlex Deucher amdgpu_device_enable_virtual_display(adev);
2631a6be7570SEmily Deng
263200a979f3SWenhui Sheng if (amdgpu_sriov_vf(adev)) {
263300a979f3SWenhui Sheng r = amdgpu_virt_request_full_gpu(adev, true);
2634aaa36a97SAlex Deucher if (r)
2635aaa36a97SAlex Deucher return r;
263600a979f3SWenhui Sheng }
263700a979f3SWenhui Sheng
2638aaa36a97SAlex Deucher switch (adev->asic_type) {
263933f34802SKen Wang #ifdef CONFIG_DRM_AMDGPU_SI
264033f34802SKen Wang case CHIP_VERDE:
264133f34802SKen Wang case CHIP_TAHITI:
264233f34802SKen Wang case CHIP_PITCAIRN:
264333f34802SKen Wang case CHIP_OLAND:
264433f34802SKen Wang case CHIP_HAINAN:
2645295d0dafSKen Wang adev->family = AMDGPU_FAMILY_SI;
264633f34802SKen Wang r = si_set_ip_blocks(adev);
264733f34802SKen Wang if (r)
264833f34802SKen Wang return r;
264933f34802SKen Wang break;
265033f34802SKen Wang #endif
2651a2e73f56SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_CIK
2652a2e73f56SAlex Deucher case CHIP_BONAIRE:
2653a2e73f56SAlex Deucher case CHIP_HAWAII:
2654a2e73f56SAlex Deucher case CHIP_KAVERI:
2655a2e73f56SAlex Deucher case CHIP_KABINI:
2656a2e73f56SAlex Deucher case CHIP_MULLINS:
2657e1ad2d53SAlex Deucher if (adev->flags & AMD_IS_APU)
2658a2e73f56SAlex Deucher adev->family = AMDGPU_FAMILY_KV;
2659e1ad2d53SAlex Deucher else
2660e1ad2d53SAlex Deucher adev->family = AMDGPU_FAMILY_CI;
2661a2e73f56SAlex Deucher
2662a2e73f56SAlex Deucher r = cik_set_ip_blocks(adev);
2663a2e73f56SAlex Deucher if (r)
2664a2e73f56SAlex Deucher return r;
2665a2e73f56SAlex Deucher break;
2666a2e73f56SAlex Deucher #endif
2667da87c30bSAlex Deucher case CHIP_TOPAZ:
2668da87c30bSAlex Deucher case CHIP_TONGA:
2669da87c30bSAlex Deucher case CHIP_FIJI:
2670da87c30bSAlex Deucher case CHIP_POLARIS10:
2671da87c30bSAlex Deucher case CHIP_POLARIS11:
2672da87c30bSAlex Deucher case CHIP_POLARIS12:
2673da87c30bSAlex Deucher case CHIP_VEGAM:
2674da87c30bSAlex Deucher case CHIP_CARRIZO:
2675da87c30bSAlex Deucher case CHIP_STONEY:
2676da87c30bSAlex Deucher if (adev->flags & AMD_IS_APU)
2677da87c30bSAlex Deucher adev->family = AMDGPU_FAMILY_CZ;
2678da87c30bSAlex Deucher else
2679da87c30bSAlex Deucher adev->family = AMDGPU_FAMILY_VI;
2680da87c30bSAlex Deucher
2681da87c30bSAlex Deucher r = vi_set_ip_blocks(adev);
2682da87c30bSAlex Deucher if (r)
2683da87c30bSAlex Deucher return r;
2684da87c30bSAlex Deucher break;
2685d38ceaf9SAlex Deucher default:
268663352b7fSAlex Deucher r = amdgpu_discovery_set_ip_blocks(adev);
268763352b7fSAlex Deucher if (r)
268863352b7fSAlex Deucher return r;
268963352b7fSAlex Deucher break;
2690d38ceaf9SAlex Deucher }
2691d38ceaf9SAlex Deucher
2692901e2be2SAlex Deucher if (amdgpu_has_atpx() &&
2693901e2be2SAlex Deucher (amdgpu_is_atpx_hybrid() ||
2694901e2be2SAlex Deucher amdgpu_has_atpx_dgpu_power_cntl()) &&
2695901e2be2SAlex Deucher ((adev->flags & AMD_IS_APU) == 0) &&
26967b1c6263SAlex Deucher !dev_is_removable(&adev->pdev->dev))
2697901e2be2SAlex Deucher adev->flags |= AMD_IS_PX;
2698901e2be2SAlex Deucher
269985ac2021SAlex Deucher if (!(adev->flags & AMD_IS_APU)) {
2700c4c8955bSMario Limonciello parent = pcie_find_root_port(adev->pdev);
2701901e2be2SAlex Deucher adev->has_pr3 = parent ? pci_pr3_present(parent) : false;
270285ac2021SAlex Deucher }
2703901e2be2SAlex Deucher
27041884734aSpding
27053b94fb10SLikun Gao adev->pm.pp_feature = amdgpu_pp_feature_mask;
2706a35ad98bSShirish S if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS)
270700544006SHuang Rui adev->pm.pp_feature &= ~PP_GFXOFF_MASK;
27084215a119SHorace Chen if (amdgpu_sriov_vf(adev) && adev->asic_type == CHIP_SIENNA_CICHLID)
27094215a119SHorace Chen adev->pm.pp_feature &= ~PP_OVERDRIVE_MASK;
2710d9b3a066SMario Limonciello if (!amdgpu_device_pcie_dynamic_switching_supported(adev))
2711fbf1035bSMario Limonciello adev->pm.pp_feature &= ~PP_PCIE_DPM_MASK;
271200f54b97SHuang Rui
2713ced69502SMario Limonciello total = true;
2714d38ceaf9SAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
2715146b085eSSunil Khatri ip_block = &adev->ip_blocks[i];
2716146b085eSSunil Khatri
2717d38ceaf9SAlex Deucher if ((amdgpu_ip_block_mask & (1 << i)) == 0) {
27180c451bafSLe Ma DRM_WARN("disabled ip block: %d <%s>\n",
2719ed8cf00cSHuang Rui i, adev->ip_blocks[i].version->funcs->name);
2720a1255107SAlex Deucher adev->ip_blocks[i].status.valid = false;
2721146b085eSSunil Khatri } else if (ip_block->version->funcs->early_init) {
2722146b085eSSunil Khatri r = ip_block->version->funcs->early_init(ip_block);
27232c1a2784SAlex Deucher if (r == -ENOENT) {
2724a1255107SAlex Deucher adev->ip_blocks[i].status.valid = false;
27252c1a2784SAlex Deucher } else if (r) {
2726a1255107SAlex Deucher DRM_ERROR("early_init of IP block <%s> failed %d\n",
2727a1255107SAlex Deucher adev->ip_blocks[i].version->funcs->name, r);
2728ced69502SMario Limonciello total = false;
27292c1a2784SAlex Deucher } else {
2730a1255107SAlex Deucher adev->ip_blocks[i].status.valid = true;
27312c1a2784SAlex Deucher }
2732974e6b64SAlex Deucher } else {
2733a1255107SAlex Deucher adev->ip_blocks[i].status.valid = true;
2734974e6b64SAlex Deucher }
273521a249caSAlex Deucher /* get the vbios after the asic_funcs are set up */
273621a249caSAlex Deucher if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) {
27376e29c227SAlex Deucher r = amdgpu_device_parse_gpu_info_fw(adev);
27386e29c227SAlex Deucher if (r)
27396e29c227SAlex Deucher return r;
27406e29c227SAlex Deucher
27417e0aa706SLijo Lazar bios_flags = amdgpu_device_get_vbios_flags(adev);
27427e0aa706SLijo Lazar skip_bios = !!(bios_flags & AMDGPU_VBIOS_SKIP);
274321a249caSAlex Deucher /* Read BIOS */
27447e0aa706SLijo Lazar if (!skip_bios) {
27456e8ca38eSLijo Lazar bool optional =
27466e8ca38eSLijo Lazar !!(bios_flags & AMDGPU_VBIOS_OPTIONAL);
27476e8ca38eSLijo Lazar if (!amdgpu_get_bios(adev) && !optional)
274821a249caSAlex Deucher return -EINVAL;
274921a249caSAlex Deucher
27506e8ca38eSLijo Lazar if (optional && !adev->bios)
27516e8ca38eSLijo Lazar dev_info(
27526e8ca38eSLijo Lazar adev->dev,
27536e8ca38eSLijo Lazar "VBIOS image optional, proceeding without VBIOS image");
27546e8ca38eSLijo Lazar
27556e8ca38eSLijo Lazar if (adev->bios) {
275621a249caSAlex Deucher r = amdgpu_atombios_init(adev);
275721a249caSAlex Deucher if (r) {
27586e8ca38eSLijo Lazar dev_err(adev->dev,
27596e8ca38eSLijo Lazar "amdgpu_atombios_init failed\n");
27606e8ca38eSLijo Lazar amdgpu_vf_error_put(
27616e8ca38eSLijo Lazar adev,
27626e8ca38eSLijo Lazar AMDGIM_ERROR_VF_ATOMBIOS_INIT_FAIL,
27636e8ca38eSLijo Lazar 0, 0);
276421a249caSAlex Deucher return r;
276521a249caSAlex Deucher }
27669535a86aSShiwu Zhang }
27676e8ca38eSLijo Lazar }
276877eabc6fSPeng Ju Zhou
276977eabc6fSPeng Ju Zhou /*get pf2vf msg info at it's earliest time*/
277077eabc6fSPeng Ju Zhou if (amdgpu_sriov_vf(adev))
277177eabc6fSPeng Ju Zhou amdgpu_virt_init_data_exchange(adev);
277277eabc6fSPeng Ju Zhou
277321a249caSAlex Deucher }
2774d38ceaf9SAlex Deucher }
2775ced69502SMario Limonciello if (!total)
2776ced69502SMario Limonciello return -ENODEV;
2777d38ceaf9SAlex Deucher
277835750679SLijo Lazar if (adev->gmc.xgmi.supported)
277935750679SLijo Lazar amdgpu_xgmi_early_init(adev);
278035750679SLijo Lazar
27813b37e272SYifan Zhang ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GFX);
27823b37e272SYifan Zhang if (ip_block->status.valid != false)
278300fa4035SSreekant Somasekharan amdgpu_amdkfd_device_probe(adev);
27843b37e272SYifan Zhang
2785395d1fb9SNicolai Hähnle adev->cg_flags &= amdgpu_cg_mask;
2786395d1fb9SNicolai Hähnle adev->pg_flags &= amdgpu_pg_mask;
2787395d1fb9SNicolai Hähnle
2788d38ceaf9SAlex Deucher return 0;
2789d38ceaf9SAlex Deucher }
2790d38ceaf9SAlex Deucher
amdgpu_device_ip_hw_init_phase1(struct amdgpu_device * adev)27910a4f2520SRex Zhu static int amdgpu_device_ip_hw_init_phase1(struct amdgpu_device *adev)
27920a4f2520SRex Zhu {
27930a4f2520SRex Zhu int i, r;
27940a4f2520SRex Zhu
27950a4f2520SRex Zhu for (i = 0; i < adev->num_ip_blocks; i++) {
27960a4f2520SRex Zhu if (!adev->ip_blocks[i].status.sw)
27970a4f2520SRex Zhu continue;
27980a4f2520SRex Zhu if (adev->ip_blocks[i].status.hw)
27990a4f2520SRex Zhu continue;
280014f2fe34SLijo Lazar if (!amdgpu_ip_member_of_hwini(
280114f2fe34SLijo Lazar adev, adev->ip_blocks[i].version->type))
280214f2fe34SLijo Lazar continue;
28030a4f2520SRex Zhu if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
28042d11fd3fSTrigger Huang (amdgpu_sriov_vf(adev) && (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)) ||
28050a4f2520SRex Zhu adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH) {
280658608034SSunil Khatri r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]);
28070a4f2520SRex Zhu if (r) {
28080a4f2520SRex Zhu DRM_ERROR("hw_init of IP block <%s> failed %d\n",
28090a4f2520SRex Zhu adev->ip_blocks[i].version->funcs->name, r);
28100a4f2520SRex Zhu return r;
28110a4f2520SRex Zhu }
28120a4f2520SRex Zhu adev->ip_blocks[i].status.hw = true;
28130a4f2520SRex Zhu }
28140a4f2520SRex Zhu }
28150a4f2520SRex Zhu
28160a4f2520SRex Zhu return 0;
28170a4f2520SRex Zhu }
28180a4f2520SRex Zhu
amdgpu_device_ip_hw_init_phase2(struct amdgpu_device * adev)28190a4f2520SRex Zhu static int amdgpu_device_ip_hw_init_phase2(struct amdgpu_device *adev)
28200a4f2520SRex Zhu {
28210a4f2520SRex Zhu int i, r;
28220a4f2520SRex Zhu
28230a4f2520SRex Zhu for (i = 0; i < adev->num_ip_blocks; i++) {
28240a4f2520SRex Zhu if (!adev->ip_blocks[i].status.sw)
28250a4f2520SRex Zhu continue;
28260a4f2520SRex Zhu if (adev->ip_blocks[i].status.hw)
28270a4f2520SRex Zhu continue;
282814f2fe34SLijo Lazar if (!amdgpu_ip_member_of_hwini(
282914f2fe34SLijo Lazar adev, adev->ip_blocks[i].version->type))
283014f2fe34SLijo Lazar continue;
283158608034SSunil Khatri r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]);
28320a4f2520SRex Zhu if (r) {
28330a4f2520SRex Zhu DRM_ERROR("hw_init of IP block <%s> failed %d\n",
28340a4f2520SRex Zhu adev->ip_blocks[i].version->funcs->name, r);
28350a4f2520SRex Zhu return r;
28360a4f2520SRex Zhu }
28370a4f2520SRex Zhu adev->ip_blocks[i].status.hw = true;
28380a4f2520SRex Zhu }
28390a4f2520SRex Zhu
28400a4f2520SRex Zhu return 0;
28410a4f2520SRex Zhu }
28420a4f2520SRex Zhu
amdgpu_device_fw_loading(struct amdgpu_device * adev)28437a3e0bb2SRex Zhu static int amdgpu_device_fw_loading(struct amdgpu_device *adev)
28447a3e0bb2SRex Zhu {
28457a3e0bb2SRex Zhu int r = 0;
28467a3e0bb2SRex Zhu int i;
284780f41f84SPrike Liang uint32_t smu_version;
28487a3e0bb2SRex Zhu
28497a3e0bb2SRex Zhu if (adev->asic_type >= CHIP_VEGA10) {
28507a3e0bb2SRex Zhu for (i = 0; i < adev->num_ip_blocks; i++) {
2851482f0e53SMonk Liu if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_PSP)
2852482f0e53SMonk Liu continue;
2853482f0e53SMonk Liu
285414f2fe34SLijo Lazar if (!amdgpu_ip_member_of_hwini(adev,
285514f2fe34SLijo Lazar AMD_IP_BLOCK_TYPE_PSP))
285614f2fe34SLijo Lazar break;
285714f2fe34SLijo Lazar
2858e3c1b071Sshaoyunl if (!adev->ip_blocks[i].status.sw)
2859e3c1b071Sshaoyunl continue;
2860e3c1b071Sshaoyunl
2861482f0e53SMonk Liu /* no need to do the fw loading again if already done*/
2862482f0e53SMonk Liu if (adev->ip_blocks[i].status.hw == true)
2863482f0e53SMonk Liu break;
2864482f0e53SMonk Liu
286553b3f8f4SDennis Li if (amdgpu_in_reset(adev) || adev->in_suspend) {
2866502d7630SSunil Khatri r = amdgpu_ip_block_resume(&adev->ip_blocks[i]);
2867502d7630SSunil Khatri if (r)
28687a3e0bb2SRex Zhu return r;
28697a3e0bb2SRex Zhu } else {
287058608034SSunil Khatri r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]);
28717a3e0bb2SRex Zhu if (r) {
28727a3e0bb2SRex Zhu DRM_ERROR("hw_init of IP block <%s> failed %d\n",
28737a3e0bb2SRex Zhu adev->ip_blocks[i].version->funcs->name, r);
28747a3e0bb2SRex Zhu return r;
28757a3e0bb2SRex Zhu }
28767a3e0bb2SRex Zhu adev->ip_blocks[i].status.hw = true;
2877502d7630SSunil Khatri }
2878482f0e53SMonk Liu break;
28797a3e0bb2SRex Zhu }
28807a3e0bb2SRex Zhu }
2881482f0e53SMonk Liu
28828973d9ecSEmily Deng if (!amdgpu_sriov_vf(adev) || adev->asic_type == CHIP_TONGA)
288380f41f84SPrike Liang r = amdgpu_pm_load_smu_firmware(adev, &smu_version);
28847a3e0bb2SRex Zhu
28857a3e0bb2SRex Zhu return r;
28867a3e0bb2SRex Zhu }
28877a3e0bb2SRex Zhu
amdgpu_device_init_schedulers(struct amdgpu_device * adev)28885fd8518dSAndrey Grodzovsky static int amdgpu_device_init_schedulers(struct amdgpu_device *adev)
28895fd8518dSAndrey Grodzovsky {
2890796a9f55SPhilipp Stanner struct drm_sched_init_args args = {
2891796a9f55SPhilipp Stanner .ops = &amdgpu_sched_ops,
2892796a9f55SPhilipp Stanner .num_rqs = DRM_SCHED_PRIORITY_COUNT,
2893796a9f55SPhilipp Stanner .timeout_wq = adev->reset_domain->wq,
2894796a9f55SPhilipp Stanner .dev = adev->dev,
2895796a9f55SPhilipp Stanner };
28965fd8518dSAndrey Grodzovsky long timeout;
28975fd8518dSAndrey Grodzovsky int r, i;
28985fd8518dSAndrey Grodzovsky
28995fd8518dSAndrey Grodzovsky for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
29005fd8518dSAndrey Grodzovsky struct amdgpu_ring *ring = adev->rings[i];
29015fd8518dSAndrey Grodzovsky
29025fd8518dSAndrey Grodzovsky /* No need to setup the GPU scheduler for rings that don't need it */
29035fd8518dSAndrey Grodzovsky if (!ring || ring->no_scheduler)
29045fd8518dSAndrey Grodzovsky continue;
29055fd8518dSAndrey Grodzovsky
29065fd8518dSAndrey Grodzovsky switch (ring->funcs->type) {
29075fd8518dSAndrey Grodzovsky case AMDGPU_RING_TYPE_GFX:
29085fd8518dSAndrey Grodzovsky timeout = adev->gfx_timeout;
29095fd8518dSAndrey Grodzovsky break;
29105fd8518dSAndrey Grodzovsky case AMDGPU_RING_TYPE_COMPUTE:
29115fd8518dSAndrey Grodzovsky timeout = adev->compute_timeout;
29125fd8518dSAndrey Grodzovsky break;
29135fd8518dSAndrey Grodzovsky case AMDGPU_RING_TYPE_SDMA:
29145fd8518dSAndrey Grodzovsky timeout = adev->sdma_timeout;
29155fd8518dSAndrey Grodzovsky break;
29165fd8518dSAndrey Grodzovsky default:
29175fd8518dSAndrey Grodzovsky timeout = adev->video_timeout;
29185fd8518dSAndrey Grodzovsky break;
29195fd8518dSAndrey Grodzovsky }
29205fd8518dSAndrey Grodzovsky
2921796a9f55SPhilipp Stanner args.timeout = timeout;
2922796a9f55SPhilipp Stanner args.credit_limit = ring->num_hw_submission;
2923796a9f55SPhilipp Stanner args.score = ring->sched_score;
2924796a9f55SPhilipp Stanner args.name = ring->name;
2925796a9f55SPhilipp Stanner
2926796a9f55SPhilipp Stanner r = drm_sched_init(&ring->sched, &args);
29275fd8518dSAndrey Grodzovsky if (r) {
29285fd8518dSAndrey Grodzovsky DRM_ERROR("Failed to create scheduler on ring %s.\n",
29295fd8518dSAndrey Grodzovsky ring->name);
29305fd8518dSAndrey Grodzovsky return r;
29315fd8518dSAndrey Grodzovsky }
2932037b98a2SAlex Deucher r = amdgpu_uvd_entity_init(adev, ring);
2933037b98a2SAlex Deucher if (r) {
2934037b98a2SAlex Deucher DRM_ERROR("Failed to create UVD scheduling entity on ring %s.\n",
2935037b98a2SAlex Deucher ring->name);
2936037b98a2SAlex Deucher return r;
2937037b98a2SAlex Deucher }
2938037b98a2SAlex Deucher r = amdgpu_vce_entity_init(adev, ring);
2939037b98a2SAlex Deucher if (r) {
2940037b98a2SAlex Deucher DRM_ERROR("Failed to create VCE scheduling entity on ring %s.\n",
2941037b98a2SAlex Deucher ring->name);
2942037b98a2SAlex Deucher return r;
2943037b98a2SAlex Deucher }
29445fd8518dSAndrey Grodzovsky }
29455fd8518dSAndrey Grodzovsky
2946d425c6f4SJames Zhu amdgpu_xcp_update_partition_sched_list(adev);
2947d425c6f4SJames Zhu
29485fd8518dSAndrey Grodzovsky return 0;
29495fd8518dSAndrey Grodzovsky }
29505fd8518dSAndrey Grodzovsky
29515fd8518dSAndrey Grodzovsky
2952e3ecdffaSAlex Deucher /**
2953e3ecdffaSAlex Deucher * amdgpu_device_ip_init - run init for hardware IPs
2954e3ecdffaSAlex Deucher *
2955e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
2956e3ecdffaSAlex Deucher *
2957e3ecdffaSAlex Deucher * Main initialization pass for hardware IPs. The list of all the hardware
2958e3ecdffaSAlex Deucher * IPs that make up the asic is walked and the sw_init and hw_init callbacks
2959e3ecdffaSAlex Deucher * are run. sw_init initializes the software state associated with each IP
2960e3ecdffaSAlex Deucher * and hw_init initializes the hardware associated with each IP.
2961e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
2962e3ecdffaSAlex Deucher */
amdgpu_device_ip_init(struct amdgpu_device * adev)296306ec9070SAlex Deucher static int amdgpu_device_ip_init(struct amdgpu_device *adev)
2964d38ceaf9SAlex Deucher {
2965631af731SLijo Lazar bool init_badpage;
2966d38ceaf9SAlex Deucher int i, r;
2967d38ceaf9SAlex Deucher
2968c030f2e4Sxinhui pan r = amdgpu_ras_init(adev);
2969c030f2e4Sxinhui pan if (r)
2970c030f2e4Sxinhui pan return r;
2971c030f2e4Sxinhui pan
2972d38ceaf9SAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
2973a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
2974d38ceaf9SAlex Deucher continue;
2975df6e463dSSunil Khatri if (adev->ip_blocks[i].version->funcs->sw_init) {
2976d5347e8dSSunil Khatri r = adev->ip_blocks[i].version->funcs->sw_init(&adev->ip_blocks[i]);
29772c1a2784SAlex Deucher if (r) {
2978a1255107SAlex Deucher DRM_ERROR("sw_init of IP block <%s> failed %d\n",
2979a1255107SAlex Deucher adev->ip_blocks[i].version->funcs->name, r);
298072d3f592SEmily Deng goto init_failed;
29812c1a2784SAlex Deucher }
2982df6e463dSSunil Khatri }
2983a1255107SAlex Deucher adev->ip_blocks[i].status.sw = true;
2984bfca0289SShaoyun Liu
298514f2fe34SLijo Lazar if (!amdgpu_ip_member_of_hwini(
298614f2fe34SLijo Lazar adev, adev->ip_blocks[i].version->type))
298714f2fe34SLijo Lazar continue;
298814f2fe34SLijo Lazar
2989c1c39032SAlex Deucher if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON) {
2990c1c39032SAlex Deucher /* need to do common hw init early so everything is set up for gmc */
299158608034SSunil Khatri r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]);
2992c1c39032SAlex Deucher if (r) {
2993c1c39032SAlex Deucher DRM_ERROR("hw_init %d failed %d\n", i, r);
2994c1c39032SAlex Deucher goto init_failed;
2995c1c39032SAlex Deucher }
2996c1c39032SAlex Deucher adev->ip_blocks[i].status.hw = true;
2997c1c39032SAlex Deucher } else if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
2998d38ceaf9SAlex Deucher /* need to do gmc hw init early so we can allocate gpu mem */
2999892deb48SVictor Skvortsov /* Try to reserve bad pages early */
3000892deb48SVictor Skvortsov if (amdgpu_sriov_vf(adev))
3001892deb48SVictor Skvortsov amdgpu_virt_exchange_data(adev);
3002892deb48SVictor Skvortsov
30037ccfd79fSChristian König r = amdgpu_device_mem_scratch_init(adev);
30042c1a2784SAlex Deucher if (r) {
30057ccfd79fSChristian König DRM_ERROR("amdgpu_mem_scratch_init failed %d\n", r);
300672d3f592SEmily Deng goto init_failed;
30072c1a2784SAlex Deucher }
300858608034SSunil Khatri r = adev->ip_blocks[i].version->funcs->hw_init(&adev->ip_blocks[i]);
30092c1a2784SAlex Deucher if (r) {
30102c1a2784SAlex Deucher DRM_ERROR("hw_init %d failed %d\n", i, r);
301172d3f592SEmily Deng goto init_failed;
30122c1a2784SAlex Deucher }
301306ec9070SAlex Deucher r = amdgpu_device_wb_init(adev);
30142c1a2784SAlex Deucher if (r) {
301506ec9070SAlex Deucher DRM_ERROR("amdgpu_device_wb_init failed %d\n", r);
301672d3f592SEmily Deng goto init_failed;
30172c1a2784SAlex Deucher }
3018a1255107SAlex Deucher adev->ip_blocks[i].status.hw = true;
30192493664fSMonk Liu
30202493664fSMonk Liu /* right after GMC hw init, we create CSA */
302102ff519eSAlex Deucher if (adev->gfx.mcbp) {
30221e256e27SRex Zhu r = amdgpu_allocate_static_csa(adev, &adev->virt.csa_obj,
302358ab2c08SChristian König AMDGPU_GEM_DOMAIN_VRAM |
302458ab2c08SChristian König AMDGPU_GEM_DOMAIN_GTT,
30251e256e27SRex Zhu AMDGPU_CSA_SIZE);
30262493664fSMonk Liu if (r) {
30272493664fSMonk Liu DRM_ERROR("allocate CSA failed %d\n", r);
302872d3f592SEmily Deng goto init_failed;
30292493664fSMonk Liu }
30302493664fSMonk Liu }
3031c8031019SArunpravin Paneer Selvam
3032c8031019SArunpravin Paneer Selvam r = amdgpu_seq64_init(adev);
3033c8031019SArunpravin Paneer Selvam if (r) {
3034c8031019SArunpravin Paneer Selvam DRM_ERROR("allocate seq64 failed %d\n", r);
3035c8031019SArunpravin Paneer Selvam goto init_failed;
3036c8031019SArunpravin Paneer Selvam }
3037d38ceaf9SAlex Deucher }
3038d38ceaf9SAlex Deucher }
3039d38ceaf9SAlex Deucher
3040c9ffa427SYintian Tao if (amdgpu_sriov_vf(adev))
304122c16d25SJingwen Chen amdgpu_virt_init_data_exchange(adev);
3042c9ffa427SYintian Tao
3043533aed27SAndrey Grodzovsky r = amdgpu_ib_pool_init(adev);
3044533aed27SAndrey Grodzovsky if (r) {
3045533aed27SAndrey Grodzovsky dev_err(adev->dev, "IB initialization failed (%d).\n", r);
3046533aed27SAndrey Grodzovsky amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_IB_INIT_FAIL, 0, r);
3047533aed27SAndrey Grodzovsky goto init_failed;
3048533aed27SAndrey Grodzovsky }
3049533aed27SAndrey Grodzovsky
3050c8963ea4SRex Zhu r = amdgpu_ucode_create_bo(adev); /* create ucode bo when sw_init complete*/
3051c8963ea4SRex Zhu if (r)
305272d3f592SEmily Deng goto init_failed;
30530a4f2520SRex Zhu
30540a4f2520SRex Zhu r = amdgpu_device_ip_hw_init_phase1(adev);
30550a4f2520SRex Zhu if (r)
305672d3f592SEmily Deng goto init_failed;
30570a4f2520SRex Zhu
30587a3e0bb2SRex Zhu r = amdgpu_device_fw_loading(adev);
30597a3e0bb2SRex Zhu if (r)
306072d3f592SEmily Deng goto init_failed;
30617a3e0bb2SRex Zhu
30620a4f2520SRex Zhu r = amdgpu_device_ip_hw_init_phase2(adev);
30630a4f2520SRex Zhu if (r)
306472d3f592SEmily Deng goto init_failed;
3065d38ceaf9SAlex Deucher
3066121a2bc6SAndrey Grodzovsky /*
3067121a2bc6SAndrey Grodzovsky * retired pages will be loaded from eeprom and reserved here,
3068121a2bc6SAndrey Grodzovsky * it should be called after amdgpu_device_ip_hw_init_phase2 since
3069121a2bc6SAndrey Grodzovsky * for some ASICs the RAS EEPROM code relies on SMU fully functioning
3070121a2bc6SAndrey Grodzovsky * for I2C communication which only true at this point.
3071b82e65a9SGuchun Chen *
3072b82e65a9SGuchun Chen * amdgpu_ras_recovery_init may fail, but the upper only cares the
3073b82e65a9SGuchun Chen * failure from bad gpu situation and stop amdgpu init process
3074b82e65a9SGuchun Chen * accordingly. For other failed cases, it will still release all
3075b82e65a9SGuchun Chen * the resource and print error message, rather than returning one
3076b82e65a9SGuchun Chen * negative value to upper level.
3077121a2bc6SAndrey Grodzovsky *
3078121a2bc6SAndrey Grodzovsky * Note: theoretically, this should be called before all vram allocations
3079121a2bc6SAndrey Grodzovsky * to protect retired page from abusing
3080121a2bc6SAndrey Grodzovsky */
3081631af731SLijo Lazar init_badpage = (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI);
3082631af731SLijo Lazar r = amdgpu_ras_recovery_init(adev, init_badpage);
3083b82e65a9SGuchun Chen if (r)
3084b82e65a9SGuchun Chen goto init_failed;
3085121a2bc6SAndrey Grodzovsky
3086cfbb6b00SAndrey Grodzovsky /**
3087cfbb6b00SAndrey Grodzovsky * In case of XGMI grab extra reference for reset domain for this device
3088cfbb6b00SAndrey Grodzovsky */
3089a4c63cafSAndrey Grodzovsky if (adev->gmc.xgmi.num_physical_nodes > 1) {
3090cfbb6b00SAndrey Grodzovsky if (amdgpu_xgmi_add_device(adev) == 0) {
30912efc30f0SVignesh Chander if (!amdgpu_sriov_vf(adev)) {
3092cfbb6b00SAndrey Grodzovsky struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev);
3093a4c63cafSAndrey Grodzovsky
3094dfd0287bSLiang He if (WARN_ON(!hive)) {
3095dfd0287bSLiang He r = -ENOENT;
3096dfd0287bSLiang He goto init_failed;
3097dfd0287bSLiang He }
3098dfd0287bSLiang He
3099cfbb6b00SAndrey Grodzovsky if (!hive->reset_domain ||
3100cfbb6b00SAndrey Grodzovsky !amdgpu_reset_get_reset_domain(hive->reset_domain)) {
3101cfbb6b00SAndrey Grodzovsky r = -ENOENT;
31029dfa4860SYiPeng Chai amdgpu_put_xgmi_hive(hive);
3103a4c63cafSAndrey Grodzovsky goto init_failed;
3104a4c63cafSAndrey Grodzovsky }
3105a4c63cafSAndrey Grodzovsky
3106cfbb6b00SAndrey Grodzovsky /* Drop the early temporary reset domain we created for device */
3107cfbb6b00SAndrey Grodzovsky amdgpu_reset_put_reset_domain(adev->reset_domain);
3108cfbb6b00SAndrey Grodzovsky adev->reset_domain = hive->reset_domain;
31099dfa4860SYiPeng Chai amdgpu_put_xgmi_hive(hive);
3110a4c63cafSAndrey Grodzovsky }
3111a4c63cafSAndrey Grodzovsky }
311246c67660Sshaoyunl }
3113a4c63cafSAndrey Grodzovsky
31145fd8518dSAndrey Grodzovsky r = amdgpu_device_init_schedulers(adev);
31155fd8518dSAndrey Grodzovsky if (r)
31165fd8518dSAndrey Grodzovsky goto init_failed;
3117e3c1b071Sshaoyunl
3118b7043800SAlex Deucher if (adev->mman.buffer_funcs_ring->sched.ready)
3119b7043800SAlex Deucher amdgpu_ttm_set_buffer_funcs_status(adev, true);
3120b7043800SAlex Deucher
3121e3c1b071Sshaoyunl /* Don't init kfd if whole hive need to be reset during init */
31225839d27dSLijo Lazar if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) {
312384b4dd3fSPhilip Yang kgd2kfd_init_zone_device(adev);
31241884734aSpding amdgpu_amdkfd_device_init(adev);
312584b4dd3fSPhilip Yang }
3126c6332b97Spding
3127bd607166SKent Russell amdgpu_fru_get_product_info(adev);
3128bd607166SKent Russell
3129a91d91b6STony Yi if (!amdgpu_sriov_vf(adev) || amdgpu_sriov_ras_cper_en(adev))
313092d5d2a0SHawking Zhang r = amdgpu_cper_init(adev);
313192d5d2a0SHawking Zhang
313272d3f592SEmily Deng init_failed:
3133c6332b97Spding
313472d3f592SEmily Deng return r;
3135d38ceaf9SAlex Deucher }
3136d38ceaf9SAlex Deucher
3137e3ecdffaSAlex Deucher /**
3138e3ecdffaSAlex Deucher * amdgpu_device_fill_reset_magic - writes reset magic to gart pointer
3139e3ecdffaSAlex Deucher *
3140e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3141e3ecdffaSAlex Deucher *
3142e3ecdffaSAlex Deucher * Writes a reset magic value to the gart pointer in VRAM. The driver calls
3143e3ecdffaSAlex Deucher * this function before a GPU reset. If the value is retained after a
3144a567db80SRandy Dunlap * GPU reset, VRAM has not been lost. Some GPU resets may destroy VRAM contents.
3145e3ecdffaSAlex Deucher */
amdgpu_device_fill_reset_magic(struct amdgpu_device * adev)314606ec9070SAlex Deucher static void amdgpu_device_fill_reset_magic(struct amdgpu_device *adev)
31470c49e0b8SChunming Zhou {
31480c49e0b8SChunming Zhou memcpy(adev->reset_magic, adev->gart.ptr, AMDGPU_RESET_MAGIC_NUM);
31490c49e0b8SChunming Zhou }
31500c49e0b8SChunming Zhou
3151e3ecdffaSAlex Deucher /**
3152e3ecdffaSAlex Deucher * amdgpu_device_check_vram_lost - check if vram is valid
3153e3ecdffaSAlex Deucher *
3154e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3155e3ecdffaSAlex Deucher *
3156e3ecdffaSAlex Deucher * Checks the reset magic value written to the gart pointer in VRAM.
3157e3ecdffaSAlex Deucher * The driver calls this after a GPU reset to see if the contents of
3158e3ecdffaSAlex Deucher * VRAM is lost or now.
3159e3ecdffaSAlex Deucher * returns true if vram is lost, false if not.
3160e3ecdffaSAlex Deucher */
amdgpu_device_check_vram_lost(struct amdgpu_device * adev)316106ec9070SAlex Deucher static bool amdgpu_device_check_vram_lost(struct amdgpu_device *adev)
31620c49e0b8SChunming Zhou {
3163dadce777SEvan Quan if (memcmp(adev->gart.ptr, adev->reset_magic,
3164dadce777SEvan Quan AMDGPU_RESET_MAGIC_NUM))
3165dadce777SEvan Quan return true;
3166dadce777SEvan Quan
316753b3f8f4SDennis Li if (!amdgpu_in_reset(adev))
3168dadce777SEvan Quan return false;
3169dadce777SEvan Quan
3170dadce777SEvan Quan /*
3171dadce777SEvan Quan * For all ASICs with baco/mode1 reset, the VRAM is
3172dadce777SEvan Quan * always assumed to be lost.
3173dadce777SEvan Quan */
3174dadce777SEvan Quan switch (amdgpu_asic_reset_method(adev)) {
3175dadce777SEvan Quan case AMD_RESET_METHOD_BACO:
3176dadce777SEvan Quan case AMD_RESET_METHOD_MODE1:
3177dadce777SEvan Quan return true;
3178dadce777SEvan Quan default:
3179dadce777SEvan Quan return false;
3180dadce777SEvan Quan }
31810c49e0b8SChunming Zhou }
31820c49e0b8SChunming Zhou
3183e3ecdffaSAlex Deucher /**
31841112a46bSRex Zhu * amdgpu_device_set_cg_state - set clockgating for amdgpu device
3185e3ecdffaSAlex Deucher *
3186e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3187b8b72130Syu kuai * @state: clockgating state (gate or ungate)
3188e3ecdffaSAlex Deucher *
3189e3ecdffaSAlex Deucher * The list of all the hardware IPs that make up the asic is walked and the
31901112a46bSRex Zhu * set_clockgating_state callbacks are run.
31911112a46bSRex Zhu * Late initialization pass enabling clockgating for hardware IPs.
31921112a46bSRex Zhu * Fini or suspend, pass disabling clockgating for hardware IPs.
3193e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
3194e3ecdffaSAlex Deucher */
3195fdd34271SRex Zhu
amdgpu_device_set_cg_state(struct amdgpu_device * adev,enum amd_clockgating_state state)31965d89bb2dSLijo Lazar int amdgpu_device_set_cg_state(struct amdgpu_device *adev,
31971112a46bSRex Zhu enum amd_clockgating_state state)
31982dc80b00SShirish S {
31991112a46bSRex Zhu int i, j, r;
32002dc80b00SShirish S
32014a2ba394SShaoyun Liu if (amdgpu_emu_mode == 1)
32024a2ba394SShaoyun Liu return 0;
32034a2ba394SShaoyun Liu
32041112a46bSRex Zhu for (j = 0; j < adev->num_ip_blocks; j++) {
32051112a46bSRex Zhu i = state == AMD_CG_STATE_GATE ? j : adev->num_ip_blocks - j - 1;
3206a2d31dc3SRex Zhu if (!adev->ip_blocks[i].status.late_initialized)
32072dc80b00SShirish S continue;
320847198eb7SAlex Deucher /* skip CG for GFX, SDMA on S0ix */
32095d70a549SPratik Vishwakarma if (adev->in_s0ix &&
321047198eb7SAlex Deucher (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
321147198eb7SAlex Deucher adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA))
32125d70a549SPratik Vishwakarma continue;
32132dc80b00SShirish S /* skip CG for VCE/UVD, it's handled specially */
32142dc80b00SShirish S if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
321557716327SRex Zhu adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE &&
321634319b32SRex Zhu adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN &&
321752f2e779SLeo Liu adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG &&
321857716327SRex Zhu adev->ip_blocks[i].version->funcs->set_clockgating_state) {
32192dc80b00SShirish S /* enable clockgating to save power */
3220f2ba8c3dSBoyuan Zhang r = adev->ip_blocks[i].version->funcs->set_clockgating_state(&adev->ip_blocks[i],
32211112a46bSRex Zhu state);
32222dc80b00SShirish S if (r) {
32232dc80b00SShirish S DRM_ERROR("set_clockgating_state(gate) of IP block <%s> failed %d\n",
32242dc80b00SShirish S adev->ip_blocks[i].version->funcs->name, r);
32252dc80b00SShirish S return r;
32262dc80b00SShirish S }
32272dc80b00SShirish S }
32282dc80b00SShirish S }
322906b18f61SHuang Rui
3230c9f96fd5SRex Zhu return 0;
3231c9f96fd5SRex Zhu }
323206b18f61SHuang Rui
amdgpu_device_set_pg_state(struct amdgpu_device * adev,enum amd_powergating_state state)32335d89bb2dSLijo Lazar int amdgpu_device_set_pg_state(struct amdgpu_device *adev,
32345d89bb2dSLijo Lazar enum amd_powergating_state state)
3235c9f96fd5SRex Zhu {
32361112a46bSRex Zhu int i, j, r;
3237c9f96fd5SRex Zhu
3238c9f96fd5SRex Zhu if (amdgpu_emu_mode == 1)
3239c9f96fd5SRex Zhu return 0;
3240c9f96fd5SRex Zhu
32411112a46bSRex Zhu for (j = 0; j < adev->num_ip_blocks; j++) {
32421112a46bSRex Zhu i = state == AMD_PG_STATE_GATE ? j : adev->num_ip_blocks - j - 1;
3243a2d31dc3SRex Zhu if (!adev->ip_blocks[i].status.late_initialized)
3244c9f96fd5SRex Zhu continue;
324547198eb7SAlex Deucher /* skip PG for GFX, SDMA on S0ix */
32465d70a549SPratik Vishwakarma if (adev->in_s0ix &&
324747198eb7SAlex Deucher (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
324847198eb7SAlex Deucher adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SDMA))
32495d70a549SPratik Vishwakarma continue;
3250c9f96fd5SRex Zhu /* skip CG for VCE/UVD, it's handled specially */
3251c9f96fd5SRex Zhu if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
3252c9f96fd5SRex Zhu adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE &&
3253c9f96fd5SRex Zhu adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCN &&
325452f2e779SLeo Liu adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_JPEG &&
3255c9f96fd5SRex Zhu adev->ip_blocks[i].version->funcs->set_powergating_state) {
3256c9f96fd5SRex Zhu /* enable powergating to save power */
325780d80511SBoyuan Zhang r = adev->ip_blocks[i].version->funcs->set_powergating_state(&adev->ip_blocks[i],
32581112a46bSRex Zhu state);
3259c9f96fd5SRex Zhu if (r) {
3260c9f96fd5SRex Zhu DRM_ERROR("set_powergating_state(gate) of IP block <%s> failed %d\n",
3261c9f96fd5SRex Zhu adev->ip_blocks[i].version->funcs->name, r);
3262c9f96fd5SRex Zhu return r;
3263c9f96fd5SRex Zhu }
3264c9f96fd5SRex Zhu }
3265c9f96fd5SRex Zhu }
32662dc80b00SShirish S return 0;
32672dc80b00SShirish S }
32682dc80b00SShirish S
amdgpu_device_enable_mgpu_fan_boost(void)3269beff74bcSAlex Deucher static int amdgpu_device_enable_mgpu_fan_boost(void)
3270beff74bcSAlex Deucher {
3271beff74bcSAlex Deucher struct amdgpu_gpu_instance *gpu_ins;
3272beff74bcSAlex Deucher struct amdgpu_device *adev;
3273beff74bcSAlex Deucher int i, ret = 0;
3274beff74bcSAlex Deucher
3275beff74bcSAlex Deucher mutex_lock(&mgpu_info.mutex);
3276beff74bcSAlex Deucher
3277beff74bcSAlex Deucher /*
3278beff74bcSAlex Deucher * MGPU fan boost feature should be enabled
3279beff74bcSAlex Deucher * only when there are two or more dGPUs in
3280beff74bcSAlex Deucher * the system
3281beff74bcSAlex Deucher */
3282beff74bcSAlex Deucher if (mgpu_info.num_dgpu < 2)
3283beff74bcSAlex Deucher goto out;
3284beff74bcSAlex Deucher
3285beff74bcSAlex Deucher for (i = 0; i < mgpu_info.num_dgpu; i++) {
3286beff74bcSAlex Deucher gpu_ins = &(mgpu_info.gpu_ins[i]);
3287beff74bcSAlex Deucher adev = gpu_ins->adev;
3288beff74bcSAlex Deucher if (!(adev->flags & AMD_IS_APU) &&
3289f10bb940SEvan Quan !gpu_ins->mgpu_fan_enabled) {
3290beff74bcSAlex Deucher ret = amdgpu_dpm_enable_mgpu_fan_boost(adev);
3291beff74bcSAlex Deucher if (ret)
3292beff74bcSAlex Deucher break;
3293beff74bcSAlex Deucher
3294beff74bcSAlex Deucher gpu_ins->mgpu_fan_enabled = 1;
3295beff74bcSAlex Deucher }
3296beff74bcSAlex Deucher }
3297beff74bcSAlex Deucher
3298beff74bcSAlex Deucher out:
3299beff74bcSAlex Deucher mutex_unlock(&mgpu_info.mutex);
3300beff74bcSAlex Deucher
3301beff74bcSAlex Deucher return ret;
3302beff74bcSAlex Deucher }
3303beff74bcSAlex Deucher
3304e3ecdffaSAlex Deucher /**
3305e3ecdffaSAlex Deucher * amdgpu_device_ip_late_init - run late init for hardware IPs
3306e3ecdffaSAlex Deucher *
3307e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3308e3ecdffaSAlex Deucher *
3309e3ecdffaSAlex Deucher * Late initialization pass for hardware IPs. The list of all the hardware
3310e3ecdffaSAlex Deucher * IPs that make up the asic is walked and the late_init callbacks are run.
3311e3ecdffaSAlex Deucher * late_init covers any special initialization that an IP requires
3312e3ecdffaSAlex Deucher * after all of the have been initialized or something that needs to happen
3313e3ecdffaSAlex Deucher * late in the init process.
3314e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
3315e3ecdffaSAlex Deucher */
amdgpu_device_ip_late_init(struct amdgpu_device * adev)331606ec9070SAlex Deucher static int amdgpu_device_ip_late_init(struct amdgpu_device *adev)
3317d38ceaf9SAlex Deucher {
331860599a03SEvan Quan struct amdgpu_gpu_instance *gpu_instance;
3319d38ceaf9SAlex Deucher int i = 0, r;
3320d38ceaf9SAlex Deucher
3321d38ceaf9SAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
332273f847dbSRex Zhu if (!adev->ip_blocks[i].status.hw)
3323d38ceaf9SAlex Deucher continue;
3324a1255107SAlex Deucher if (adev->ip_blocks[i].version->funcs->late_init) {
33253138ab2cSSunil Khatri r = adev->ip_blocks[i].version->funcs->late_init(&adev->ip_blocks[i]);
33262c1a2784SAlex Deucher if (r) {
3327a1255107SAlex Deucher DRM_ERROR("late_init of IP block <%s> failed %d\n",
3328a1255107SAlex Deucher adev->ip_blocks[i].version->funcs->name, r);
3329d38ceaf9SAlex Deucher return r;
3330d38ceaf9SAlex Deucher }
3331d38ceaf9SAlex Deucher }
333273f847dbSRex Zhu adev->ip_blocks[i].status.late_initialized = true;
3333b0b00ff1SArindam Nath }
33342dc80b00SShirish S
3335867e24caSyipechai r = amdgpu_ras_late_init(adev);
3336867e24caSyipechai if (r) {
3337867e24caSyipechai DRM_ERROR("amdgpu_ras_late_init failed %d", r);
3338867e24caSyipechai return r;
3339867e24caSyipechai }
3340867e24caSyipechai
3341e283f4fbSLijo Lazar if (!amdgpu_reset_in_recovery(adev))
3342a891d239SDennis Li amdgpu_ras_set_error_query_ready(adev, true);
3343a891d239SDennis Li
33441112a46bSRex Zhu amdgpu_device_set_cg_state(adev, AMD_CG_STATE_GATE);
33451112a46bSRex Zhu amdgpu_device_set_pg_state(adev, AMD_PG_STATE_GATE);
3346916ac57fSRex Zhu
334706ec9070SAlex Deucher amdgpu_device_fill_reset_magic(adev);
3348d38ceaf9SAlex Deucher
3349beff74bcSAlex Deucher r = amdgpu_device_enable_mgpu_fan_boost();
3350beff74bcSAlex Deucher if (r)
3351beff74bcSAlex Deucher DRM_ERROR("enable mgpu fan boost failed (%d).\n", r);
3352beff74bcSAlex Deucher
33534da8b639Ssashank saye /* For passthrough configuration on arcturus and aldebaran, enable special handling SBR */
335447fc644fSSrinivasan Shanmugam if (amdgpu_passthrough(adev) &&
335547fc644fSSrinivasan Shanmugam ((adev->asic_type == CHIP_ARCTURUS && adev->gmc.xgmi.num_physical_nodes > 1) ||
33564da8b639Ssashank saye adev->asic_type == CHIP_ALDEBARAN))
3357bc143d8bSEvan Quan amdgpu_dpm_handle_passthrough_sbr(adev, true);
335860599a03SEvan Quan
335960599a03SEvan Quan if (adev->gmc.xgmi.num_physical_nodes > 1) {
336060599a03SEvan Quan mutex_lock(&mgpu_info.mutex);
336160599a03SEvan Quan
336260599a03SEvan Quan /*
336360599a03SEvan Quan * Reset device p-state to low as this was booted with high.
336460599a03SEvan Quan *
336560599a03SEvan Quan * This should be performed only after all devices from the same
336660599a03SEvan Quan * hive get initialized.
336760599a03SEvan Quan *
336860599a03SEvan Quan * However, it's unknown how many device in the hive in advance.
336960599a03SEvan Quan * As this is counted one by one during devices initializations.
337060599a03SEvan Quan *
337160599a03SEvan Quan * So, we wait for all XGMI interlinked devices initialized.
337260599a03SEvan Quan * This may bring some delays as those devices may come from
337360599a03SEvan Quan * different hives. But that should be OK.
337460599a03SEvan Quan */
337560599a03SEvan Quan if (mgpu_info.num_dgpu == adev->gmc.xgmi.num_physical_nodes) {
337660599a03SEvan Quan for (i = 0; i < mgpu_info.num_gpu; i++) {
337760599a03SEvan Quan gpu_instance = &(mgpu_info.gpu_ins[i]);
337860599a03SEvan Quan if (gpu_instance->adev->flags & AMD_IS_APU)
337960599a03SEvan Quan continue;
338060599a03SEvan Quan
3381d84a430dSJonathan Kim r = amdgpu_xgmi_set_pstate(gpu_instance->adev,
3382d84a430dSJonathan Kim AMDGPU_XGMI_PSTATE_MIN);
338360599a03SEvan Quan if (r) {
338460599a03SEvan Quan DRM_ERROR("pstate setting failed (%d).\n", r);
338560599a03SEvan Quan break;
338660599a03SEvan Quan }
338760599a03SEvan Quan }
338860599a03SEvan Quan }
338960599a03SEvan Quan
339060599a03SEvan Quan mutex_unlock(&mgpu_info.mutex);
339160599a03SEvan Quan }
339260599a03SEvan Quan
3393d38ceaf9SAlex Deucher return 0;
3394d38ceaf9SAlex Deucher }
3395d38ceaf9SAlex Deucher
amdgpu_ip_block_hw_fini(struct amdgpu_ip_block * ip_block)3396dad01f93SSunil Khatri static void amdgpu_ip_block_hw_fini(struct amdgpu_ip_block *ip_block)
3397dad01f93SSunil Khatri {
3398dad01f93SSunil Khatri int r;
3399dad01f93SSunil Khatri
3400dac64cb3SDan Carpenter if (!ip_block->version->funcs->hw_fini) {
3401dad01f93SSunil Khatri DRM_ERROR("hw_fini of IP block <%s> not defined\n",
3402dad01f93SSunil Khatri ip_block->version->funcs->name);
3403dad01f93SSunil Khatri } else {
3404dad01f93SSunil Khatri r = ip_block->version->funcs->hw_fini(ip_block);
3405dad01f93SSunil Khatri /* XXX handle errors */
3406dad01f93SSunil Khatri if (r) {
3407dad01f93SSunil Khatri DRM_DEBUG("hw_fini of IP block <%s> failed %d\n",
3408dad01f93SSunil Khatri ip_block->version->funcs->name, r);
3409dad01f93SSunil Khatri }
3410dad01f93SSunil Khatri }
3411dad01f93SSunil Khatri
3412dad01f93SSunil Khatri ip_block->status.hw = false;
3413dad01f93SSunil Khatri }
3414dad01f93SSunil Khatri
3415613aa3eaSLang Yu /**
3416613aa3eaSLang Yu * amdgpu_device_smu_fini_early - smu hw_fini wrapper
3417613aa3eaSLang Yu *
3418613aa3eaSLang Yu * @adev: amdgpu_device pointer
3419613aa3eaSLang Yu *
3420613aa3eaSLang Yu * For ASICs need to disable SMC first
3421613aa3eaSLang Yu */
amdgpu_device_smu_fini_early(struct amdgpu_device * adev)3422613aa3eaSLang Yu static void amdgpu_device_smu_fini_early(struct amdgpu_device *adev)
3423613aa3eaSLang Yu {
3424dad01f93SSunil Khatri int i;
3425613aa3eaSLang Yu
34264e8303cfSLijo Lazar if (amdgpu_ip_version(adev, GC_HWIP, 0) > IP_VERSION(9, 0, 0))
3427613aa3eaSLang Yu return;
3428613aa3eaSLang Yu
3429613aa3eaSLang Yu for (i = 0; i < adev->num_ip_blocks; i++) {
3430613aa3eaSLang Yu if (!adev->ip_blocks[i].status.hw)
3431613aa3eaSLang Yu continue;
3432613aa3eaSLang Yu if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) {
3433dad01f93SSunil Khatri amdgpu_ip_block_hw_fini(&adev->ip_blocks[i]);
3434613aa3eaSLang Yu break;
3435613aa3eaSLang Yu }
3436613aa3eaSLang Yu }
3437613aa3eaSLang Yu }
3438613aa3eaSLang Yu
amdgpu_device_ip_fini_early(struct amdgpu_device * adev)3439e9669fb7SAndrey Grodzovsky static int amdgpu_device_ip_fini_early(struct amdgpu_device *adev)
3440d38ceaf9SAlex Deucher {
3441d38ceaf9SAlex Deucher int i, r;
3442d38ceaf9SAlex Deucher
3443e9669fb7SAndrey Grodzovsky for (i = 0; i < adev->num_ip_blocks; i++) {
3444e9669fb7SAndrey Grodzovsky if (!adev->ip_blocks[i].version->funcs->early_fini)
3445e9669fb7SAndrey Grodzovsky continue;
34465278a159SStanley.Yang
344790410d39SSunil Khatri r = adev->ip_blocks[i].version->funcs->early_fini(&adev->ip_blocks[i]);
3448e9669fb7SAndrey Grodzovsky if (r) {
3449e9669fb7SAndrey Grodzovsky DRM_DEBUG("early_fini of IP block <%s> failed %d\n",
3450e9669fb7SAndrey Grodzovsky adev->ip_blocks[i].version->funcs->name, r);
3451e9669fb7SAndrey Grodzovsky }
3452e9669fb7SAndrey Grodzovsky }
3453c030f2e4Sxinhui pan
345405df1f01SRex Zhu amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
3455fdd34271SRex Zhu amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
3456fdd34271SRex Zhu
34577270e895STianci.Yin amdgpu_amdkfd_suspend(adev, false);
34587270e895STianci.Yin
3459a567db80SRandy Dunlap /* Workaround for ASICs need to disable SMC first */
3460613aa3eaSLang Yu amdgpu_device_smu_fini_early(adev);
34613e96dbfdSAlex Deucher
3462d38ceaf9SAlex Deucher for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
3463a1255107SAlex Deucher if (!adev->ip_blocks[i].status.hw)
3464d38ceaf9SAlex Deucher continue;
34658201a67aSRex Zhu
3466dad01f93SSunil Khatri amdgpu_ip_block_hw_fini(&adev->ip_blocks[i]);
3467d38ceaf9SAlex Deucher }
3468d38ceaf9SAlex Deucher
34696effad8aSGuchun Chen if (amdgpu_sriov_vf(adev)) {
34706effad8aSGuchun Chen if (amdgpu_virt_release_full_gpu(adev, false))
34716effad8aSGuchun Chen DRM_ERROR("failed to release exclusive mode on fini\n");
34726effad8aSGuchun Chen }
34736effad8aSGuchun Chen
3474e9669fb7SAndrey Grodzovsky return 0;
3475e9669fb7SAndrey Grodzovsky }
3476e9669fb7SAndrey Grodzovsky
3477e9669fb7SAndrey Grodzovsky /**
3478e9669fb7SAndrey Grodzovsky * amdgpu_device_ip_fini - run fini for hardware IPs
3479e9669fb7SAndrey Grodzovsky *
3480e9669fb7SAndrey Grodzovsky * @adev: amdgpu_device pointer
3481e9669fb7SAndrey Grodzovsky *
3482e9669fb7SAndrey Grodzovsky * Main teardown pass for hardware IPs. The list of all the hardware
3483e9669fb7SAndrey Grodzovsky * IPs that make up the asic is walked and the hw_fini and sw_fini callbacks
3484e9669fb7SAndrey Grodzovsky * are run. hw_fini tears down the hardware associated with each IP
3485e9669fb7SAndrey Grodzovsky * and sw_fini tears down any software state associated with each IP.
3486e9669fb7SAndrey Grodzovsky * Returns 0 on success, negative error code on failure.
3487e9669fb7SAndrey Grodzovsky */
amdgpu_device_ip_fini(struct amdgpu_device * adev)3488e9669fb7SAndrey Grodzovsky static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
3489e9669fb7SAndrey Grodzovsky {
3490e9669fb7SAndrey Grodzovsky int i, r;
3491e9669fb7SAndrey Grodzovsky
349292d5d2a0SHawking Zhang amdgpu_cper_fini(adev);
349392d5d2a0SHawking Zhang
3494e9669fb7SAndrey Grodzovsky if (amdgpu_sriov_vf(adev) && adev->virt.ras_init_done)
3495e9669fb7SAndrey Grodzovsky amdgpu_virt_release_ras_err_handler_data(adev);
3496e9669fb7SAndrey Grodzovsky
3497e9669fb7SAndrey Grodzovsky if (adev->gmc.xgmi.num_physical_nodes > 1)
3498e9669fb7SAndrey Grodzovsky amdgpu_xgmi_remove_device(adev);
3499e9669fb7SAndrey Grodzovsky
3500e9669fb7SAndrey Grodzovsky amdgpu_amdkfd_device_fini_sw(adev);
35019950cda2SAlex Deucher
3502d38ceaf9SAlex Deucher for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
3503a1255107SAlex Deucher if (!adev->ip_blocks[i].status.sw)
3504d38ceaf9SAlex Deucher continue;
3505c12aba3aSMonk Liu
3506c12aba3aSMonk Liu if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
3507c8963ea4SRex Zhu amdgpu_ucode_free_bo(adev);
35081e256e27SRex Zhu amdgpu_free_static_csa(&adev->virt.csa_obj);
3509c12aba3aSMonk Liu amdgpu_device_wb_fini(adev);
35107ccfd79fSChristian König amdgpu_device_mem_scratch_fini(adev);
3511533aed27SAndrey Grodzovsky amdgpu_ib_pool_fini(adev);
3512c8031019SArunpravin Paneer Selvam amdgpu_seq64_fini(adev);
3513e7afa85aSZhenGuo Yin amdgpu_doorbell_fini(adev);
3514c12aba3aSMonk Liu }
3515278b8fbfSSunil Khatri if (adev->ip_blocks[i].version->funcs->sw_fini) {
351636aa9ab9SSunil Khatri r = adev->ip_blocks[i].version->funcs->sw_fini(&adev->ip_blocks[i]);
3517d38ceaf9SAlex Deucher /* XXX handle errors */
35182c1a2784SAlex Deucher if (r) {
3519a1255107SAlex Deucher DRM_DEBUG("sw_fini of IP block <%s> failed %d\n",
3520a1255107SAlex Deucher adev->ip_blocks[i].version->funcs->name, r);
35212c1a2784SAlex Deucher }
3522278b8fbfSSunil Khatri }
3523a1255107SAlex Deucher adev->ip_blocks[i].status.sw = false;
3524a1255107SAlex Deucher adev->ip_blocks[i].status.valid = false;
3525d38ceaf9SAlex Deucher }
3526d38ceaf9SAlex Deucher
3527a6dcfd9cSMonk Liu for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
3528a1255107SAlex Deucher if (!adev->ip_blocks[i].status.late_initialized)
35298a2eef1dSGrazvydas Ignotas continue;
3530a1255107SAlex Deucher if (adev->ip_blocks[i].version->funcs->late_fini)
353147d827f9SSunil Khatri adev->ip_blocks[i].version->funcs->late_fini(&adev->ip_blocks[i]);
3532a1255107SAlex Deucher adev->ip_blocks[i].status.late_initialized = false;
3533a6dcfd9cSMonk Liu }
3534a6dcfd9cSMonk Liu
3535c030f2e4Sxinhui pan amdgpu_ras_fini(adev);
3536c030f2e4Sxinhui pan
3537d38ceaf9SAlex Deucher return 0;
3538d38ceaf9SAlex Deucher }
3539d38ceaf9SAlex Deucher
3540e3ecdffaSAlex Deucher /**
3541beff74bcSAlex Deucher * amdgpu_device_delayed_init_work_handler - work handler for IB tests
3542e3ecdffaSAlex Deucher *
35431112a46bSRex Zhu * @work: work_struct.
3544e3ecdffaSAlex Deucher */
amdgpu_device_delayed_init_work_handler(struct work_struct * work)3545beff74bcSAlex Deucher static void amdgpu_device_delayed_init_work_handler(struct work_struct *work)
35462dc80b00SShirish S {
35472dc80b00SShirish S struct amdgpu_device *adev =
3548beff74bcSAlex Deucher container_of(work, struct amdgpu_device, delayed_init_work.work);
3549916ac57fSRex Zhu int r;
3550916ac57fSRex Zhu
3551916ac57fSRex Zhu r = amdgpu_ib_ring_tests(adev);
3552916ac57fSRex Zhu if (r)
3553916ac57fSRex Zhu DRM_ERROR("ib ring test failed (%d).\n", r);
35542dc80b00SShirish S }
35552dc80b00SShirish S
amdgpu_device_delay_enable_gfx_off(struct work_struct * work)35561e317b99SRex Zhu static void amdgpu_device_delay_enable_gfx_off(struct work_struct *work)
35571e317b99SRex Zhu {
35581e317b99SRex Zhu struct amdgpu_device *adev =
35591e317b99SRex Zhu container_of(work, struct amdgpu_device, gfx.gfx_off_delay_work.work);
35601e317b99SRex Zhu
356190a92662SMichel Dänzer WARN_ON_ONCE(adev->gfx.gfx_off_state);
356290a92662SMichel Dänzer WARN_ON_ONCE(adev->gfx.gfx_off_req_count);
356390a92662SMichel Dänzer
3564ff69bba0SBoyuan Zhang if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true, 0))
35651e317b99SRex Zhu adev->gfx.gfx_off_state = true;
35661e317b99SRex Zhu }
35671e317b99SRex Zhu
3568e3ecdffaSAlex Deucher /**
3569e7854a03SAlex Deucher * amdgpu_device_ip_suspend_phase1 - run suspend for hardware IPs (phase 1)
3570e3ecdffaSAlex Deucher *
3571e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3572e3ecdffaSAlex Deucher *
3573e3ecdffaSAlex Deucher * Main suspend function for hardware IPs. The list of all the hardware
3574e3ecdffaSAlex Deucher * IPs that make up the asic is walked, clockgating is disabled and the
3575e3ecdffaSAlex Deucher * suspend callbacks are run. suspend puts the hardware and software state
3576e3ecdffaSAlex Deucher * in each IP into a state suitable for suspend.
3577e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
3578e3ecdffaSAlex Deucher */
amdgpu_device_ip_suspend_phase1(struct amdgpu_device * adev)3579e7854a03SAlex Deucher static int amdgpu_device_ip_suspend_phase1(struct amdgpu_device *adev)
3580e7854a03SAlex Deucher {
3581e7854a03SAlex Deucher int i, r;
3582e7854a03SAlex Deucher
3583ced1ba97SPrike Liang amdgpu_device_set_pg_state(adev, AMD_PG_STATE_UNGATE);
3584ced1ba97SPrike Liang amdgpu_device_set_cg_state(adev, AMD_CG_STATE_UNGATE);
358505df1f01SRex Zhu
3586b31d6adaSEvan Quan /*
3587b31d6adaSEvan Quan * Per PMFW team's suggestion, driver needs to handle gfxoff
3588b31d6adaSEvan Quan * and df cstate features disablement for gpu reset(e.g. Mode1Reset)
3589b31d6adaSEvan Quan * scenario. Add the missing df cstate disablement here.
3590b31d6adaSEvan Quan */
3591b31d6adaSEvan Quan if (amdgpu_dpm_set_df_cstate(adev, DF_CSTATE_DISALLOW))
3592b31d6adaSEvan Quan dev_warn(adev->dev, "Failed to disallow df cstate");
3593b31d6adaSEvan Quan
3594e7854a03SAlex Deucher for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
3595e7854a03SAlex Deucher if (!adev->ip_blocks[i].status.valid)
3596e7854a03SAlex Deucher continue;
35972b9f7848SNirmoy Das
3598e7854a03SAlex Deucher /* displays are handled separately */
35992b9f7848SNirmoy Das if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_DCE)
36002b9f7848SNirmoy Das continue;
36012b9f7848SNirmoy Das
3602e7854a03SAlex Deucher /* XXX handle errors */
3603e095026fSSunil Khatri r = amdgpu_ip_block_suspend(&adev->ip_blocks[i]);
3604e095026fSSunil Khatri if (r)
3605482f0e53SMonk Liu return r;
3606e7854a03SAlex Deucher }
36072b9f7848SNirmoy Das
3608e7854a03SAlex Deucher return 0;
3609e7854a03SAlex Deucher }
3610e7854a03SAlex Deucher
3611e7854a03SAlex Deucher /**
3612e7854a03SAlex Deucher * amdgpu_device_ip_suspend_phase2 - run suspend for hardware IPs (phase 2)
3613e7854a03SAlex Deucher *
3614e7854a03SAlex Deucher * @adev: amdgpu_device pointer
3615e7854a03SAlex Deucher *
3616e7854a03SAlex Deucher * Main suspend function for hardware IPs. The list of all the hardware
3617e7854a03SAlex Deucher * IPs that make up the asic is walked, clockgating is disabled and the
3618e7854a03SAlex Deucher * suspend callbacks are run. suspend puts the hardware and software state
3619e7854a03SAlex Deucher * in each IP into a state suitable for suspend.
3620e7854a03SAlex Deucher * Returns 0 on success, negative error code on failure.
3621e7854a03SAlex Deucher */
amdgpu_device_ip_suspend_phase2(struct amdgpu_device * adev)3622e7854a03SAlex Deucher static int amdgpu_device_ip_suspend_phase2(struct amdgpu_device *adev)
3623d38ceaf9SAlex Deucher {
3624d38ceaf9SAlex Deucher int i, r;
3625d38ceaf9SAlex Deucher
3626557f42a2SAlex Deucher if (adev->in_s0ix)
3627bc143d8bSEvan Quan amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D3Entry);
362834416931SAlex Deucher
3629d38ceaf9SAlex Deucher for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
3630a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
3631d38ceaf9SAlex Deucher continue;
3632e7854a03SAlex Deucher /* displays are handled in phase1 */
3633e7854a03SAlex Deucher if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE)
3634e7854a03SAlex Deucher continue;
3635bff77e86SLe Ma /* PSP lost connection when err_event_athub occurs */
3636bff77e86SLe Ma if (amdgpu_ras_intr_triggered() &&
3637bff77e86SLe Ma adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) {
3638bff77e86SLe Ma adev->ip_blocks[i].status.hw = false;
3639bff77e86SLe Ma continue;
3640bff77e86SLe Ma }
3641e3c1b071Sshaoyunl
3642e3c1b071Sshaoyunl /* skip unnecessary suspend if we do not initialize them yet */
36435839d27dSLijo Lazar if (!amdgpu_ip_member_of_hwini(
36445839d27dSLijo Lazar adev, adev->ip_blocks[i].version->type))
3645e3c1b071Sshaoyunl continue;
3646557f42a2SAlex Deucher
364735a54408SAlex Deucher /* Since we skip suspend for S0i3, we need to cancel the delayed
364835a54408SAlex Deucher * idle work here as the suspend callback never gets called.
364935a54408SAlex Deucher */
365035a54408SAlex Deucher if (adev->in_s0ix &&
365135a54408SAlex Deucher adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX &&
365235a54408SAlex Deucher amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 0, 0))
365335a54408SAlex Deucher cancel_delayed_work_sync(&adev->gfx.idle_work);
3654afa6646bSAlex Deucher /* skip suspend of gfx/mes and psp for S0ix
365532ff160dSAlex Deucher * gfx is in gfxoff state, so on resume it will exit gfxoff just
365632ff160dSAlex Deucher * like at runtime. PSP is also part of the always on hardware
365732ff160dSAlex Deucher * so no need to suspend it.
365832ff160dSAlex Deucher */
3659557f42a2SAlex Deucher if (adev->in_s0ix &&
366032ff160dSAlex Deucher (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP ||
3661afa6646bSAlex Deucher adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GFX ||
3662afa6646bSAlex Deucher adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_MES))
3663557f42a2SAlex Deucher continue;
3664557f42a2SAlex Deucher
36652a7798eaSAlex Deucher /* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */
36662a7798eaSAlex Deucher if (adev->in_s0ix &&
36674e8303cfSLijo Lazar (amdgpu_ip_version(adev, SDMA0_HWIP, 0) >=
36684e8303cfSLijo Lazar IP_VERSION(5, 0, 0)) &&
36694e8303cfSLijo Lazar (adev->ip_blocks[i].version->type ==
36704e8303cfSLijo Lazar AMD_IP_BLOCK_TYPE_SDMA))
36712a7798eaSAlex Deucher continue;
36722a7798eaSAlex Deucher
3673e11c7750STim Huang /* Once swPSP provides the IMU, RLC FW binaries to TOS during cold-boot.
3674e11c7750STim Huang * These are in TMR, hence are expected to be reused by PSP-TOS to reload
3675e11c7750STim Huang * from this location and RLC Autoload automatically also gets loaded
3676e11c7750STim Huang * from here based on PMFW -> PSP message during re-init sequence.
3677e11c7750STim Huang * Therefore, the psp suspend & resume should be skipped to avoid destroy
3678e11c7750STim Huang * the TMR and reload FWs again for IMU enabled APU ASICs.
3679e11c7750STim Huang */
3680e11c7750STim Huang if (amdgpu_in_reset(adev) &&
3681e11c7750STim Huang (adev->flags & AMD_IS_APU) && adev->gfx.imu.funcs &&
3682e11c7750STim Huang adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)
3683e11c7750STim Huang continue;
3684e11c7750STim Huang
3685d38ceaf9SAlex Deucher /* XXX handle errors */
3686e095026fSSunil Khatri r = amdgpu_ip_block_suspend(&adev->ip_blocks[i]);
3687876923fbSxinhui pan adev->ip_blocks[i].status.hw = false;
3688e095026fSSunil Khatri
3689a3a09142SAlex Deucher /* handle putting the SMC in the appropriate state */
369086b93fd6SJack Zhang if (!amdgpu_sriov_vf(adev)) {
3691a3a09142SAlex Deucher if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) {
36929530273eSEvan Quan r = amdgpu_dpm_set_mp1_state(adev, adev->mp1_state);
3693a3a09142SAlex Deucher if (r) {
3694a3a09142SAlex Deucher DRM_ERROR("SMC failed to set mp1 state %d, %d\n",
3695a3a09142SAlex Deucher adev->mp1_state, r);
3696482f0e53SMonk Liu return r;
3697a3a09142SAlex Deucher }
3698a3a09142SAlex Deucher }
369986b93fd6SJack Zhang }
3700d38ceaf9SAlex Deucher }
3701d38ceaf9SAlex Deucher
3702d38ceaf9SAlex Deucher return 0;
3703d38ceaf9SAlex Deucher }
3704d38ceaf9SAlex Deucher
3705e7854a03SAlex Deucher /**
3706e7854a03SAlex Deucher * amdgpu_device_ip_suspend - run suspend for hardware IPs
3707e7854a03SAlex Deucher *
3708e7854a03SAlex Deucher * @adev: amdgpu_device pointer
3709e7854a03SAlex Deucher *
3710e7854a03SAlex Deucher * Main suspend function for hardware IPs. The list of all the hardware
3711e7854a03SAlex Deucher * IPs that make up the asic is walked, clockgating is disabled and the
3712e7854a03SAlex Deucher * suspend callbacks are run. suspend puts the hardware and software state
3713e7854a03SAlex Deucher * in each IP into a state suitable for suspend.
3714e7854a03SAlex Deucher * Returns 0 on success, negative error code on failure.
3715e7854a03SAlex Deucher */
amdgpu_device_ip_suspend(struct amdgpu_device * adev)3716e7854a03SAlex Deucher int amdgpu_device_ip_suspend(struct amdgpu_device *adev)
3717e7854a03SAlex Deucher {
3718e7854a03SAlex Deucher int r;
3719e7854a03SAlex Deucher
37203c73683cSJingwen Chen if (amdgpu_sriov_vf(adev)) {
37213c73683cSJingwen Chen amdgpu_virt_fini_data_exchange(adev);
3722e7819644SYintian Tao amdgpu_virt_request_full_gpu(adev, false);
37233c73683cSJingwen Chen }
3724e7819644SYintian Tao
3725b7043800SAlex Deucher amdgpu_ttm_set_buffer_funcs_status(adev, false);
3726b7043800SAlex Deucher
3727e7854a03SAlex Deucher r = amdgpu_device_ip_suspend_phase1(adev);
3728e7854a03SAlex Deucher if (r)
3729e7854a03SAlex Deucher return r;
3730e7854a03SAlex Deucher r = amdgpu_device_ip_suspend_phase2(adev);
3731e7854a03SAlex Deucher
3732e7819644SYintian Tao if (amdgpu_sriov_vf(adev))
3733e7819644SYintian Tao amdgpu_virt_release_full_gpu(adev, false);
3734e7819644SYintian Tao
3735e7854a03SAlex Deucher return r;
3736e7854a03SAlex Deucher }
3737e7854a03SAlex Deucher
amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device * adev)373806ec9070SAlex Deucher static int amdgpu_device_ip_reinit_early_sriov(struct amdgpu_device *adev)
3739a90ad3c2SMonk Liu {
3740a90ad3c2SMonk Liu int i, r;
3741a90ad3c2SMonk Liu
37422cb681b6SMonk Liu static enum amd_ip_block_type ip_order[] = {
37432cb681b6SMonk Liu AMD_IP_BLOCK_TYPE_COMMON,
3744c1c39032SAlex Deucher AMD_IP_BLOCK_TYPE_GMC,
374539186aefSEmily Deng AMD_IP_BLOCK_TYPE_PSP,
37462cb681b6SMonk Liu AMD_IP_BLOCK_TYPE_IH,
37472cb681b6SMonk Liu };
37482cb681b6SMonk Liu
374995ea3dbcSJack Zhang for (i = 0; i < adev->num_ip_blocks; i++) {
37502cb681b6SMonk Liu int j;
37512cb681b6SMonk Liu struct amdgpu_ip_block *block;
37522cb681b6SMonk Liu
37534cd2a96dSJiawei block = &adev->ip_blocks[i];
37544cd2a96dSJiawei block->status.hw = false;
37552cb681b6SMonk Liu
37564cd2a96dSJiawei for (j = 0; j < ARRAY_SIZE(ip_order); j++) {
37574cd2a96dSJiawei
37584cd2a96dSJiawei if (block->version->type != ip_order[j] ||
37592cb681b6SMonk Liu !block->status.valid)
3760a90ad3c2SMonk Liu continue;
3761a90ad3c2SMonk Liu
376258608034SSunil Khatri r = block->version->funcs->hw_init(&adev->ip_blocks[i]);
3763f3bb57b6SYiqing Yao if (r) {
3764f3bb57b6SYiqing Yao dev_err(adev->dev, "RE-INIT-early: %s failed\n",
3765f3bb57b6SYiqing Yao block->version->funcs->name);
3766c41d1cf6SMonk Liu return r;
3767f3bb57b6SYiqing Yao }
3768482f0e53SMonk Liu block->status.hw = true;
3769a90ad3c2SMonk Liu }
3770a90ad3c2SMonk Liu }
3771a90ad3c2SMonk Liu
3772a90ad3c2SMonk Liu return 0;
3773a90ad3c2SMonk Liu }
3774a90ad3c2SMonk Liu
amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device * adev)377506ec9070SAlex Deucher static int amdgpu_device_ip_reinit_late_sriov(struct amdgpu_device *adev)
3776a90ad3c2SMonk Liu {
3777f3bb57b6SYiqing Yao struct amdgpu_ip_block *block;
3778f3bb57b6SYiqing Yao int i, r = 0;
3779a90ad3c2SMonk Liu
37802cb681b6SMonk Liu static enum amd_ip_block_type ip_order[] = {
37812cb681b6SMonk Liu AMD_IP_BLOCK_TYPE_SMC,
37822cb681b6SMonk Liu AMD_IP_BLOCK_TYPE_DCE,
37832cb681b6SMonk Liu AMD_IP_BLOCK_TYPE_GFX,
37842cb681b6SMonk Liu AMD_IP_BLOCK_TYPE_SDMA,
3785ec64350dSYiPeng Chai AMD_IP_BLOCK_TYPE_MES,
3786257deb8cSFrank Min AMD_IP_BLOCK_TYPE_UVD,
3787d83c7a07SJane Jian AMD_IP_BLOCK_TYPE_VCE,
3788d2cdc014SYifan Zha AMD_IP_BLOCK_TYPE_VCN,
3789d2cdc014SYifan Zha AMD_IP_BLOCK_TYPE_JPEG
37902cb681b6SMonk Liu };
37912cb681b6SMonk Liu
37922cb681b6SMonk Liu for (i = 0; i < ARRAY_SIZE(ip_order); i++) {
3793f3bb57b6SYiqing Yao block = amdgpu_device_ip_get_ip_block(adev, ip_order[i]);
37942cb681b6SMonk Liu
3795f3bb57b6SYiqing Yao if (!block)
3796a90ad3c2SMonk Liu continue;
3797a90ad3c2SMonk Liu
3798f3bb57b6SYiqing Yao if (block->status.valid && !block->status.hw) {
3799502d7630SSunil Khatri if (block->version->type == AMD_IP_BLOCK_TYPE_SMC) {
3800f3bb57b6SYiqing Yao r = amdgpu_ip_block_resume(block);
3801502d7630SSunil Khatri } else {
3802f3bb57b6SYiqing Yao r = block->version->funcs->hw_init(block);
3803f3bb57b6SYiqing Yao }
3804f3bb57b6SYiqing Yao
3805502d7630SSunil Khatri if (r) {
3806f3bb57b6SYiqing Yao dev_err(adev->dev, "RE-INIT-late: %s failed\n",
3807f3bb57b6SYiqing Yao block->version->funcs->name);
3808f3bb57b6SYiqing Yao break;
3809502d7630SSunil Khatri }
3810482f0e53SMonk Liu block->status.hw = true;
3811a90ad3c2SMonk Liu }
3812a90ad3c2SMonk Liu }
3813a90ad3c2SMonk Liu
3814f3bb57b6SYiqing Yao return r;
3815a90ad3c2SMonk Liu }
3816a90ad3c2SMonk Liu
3817e3ecdffaSAlex Deucher /**
3818e3ecdffaSAlex Deucher * amdgpu_device_ip_resume_phase1 - run resume for hardware IPs
3819e3ecdffaSAlex Deucher *
3820e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3821e3ecdffaSAlex Deucher *
3822e3ecdffaSAlex Deucher * First resume function for hardware IPs. The list of all the hardware
3823e3ecdffaSAlex Deucher * IPs that make up the asic is walked and the resume callbacks are run for
3824e3ecdffaSAlex Deucher * COMMON, GMC, and IH. resume puts the hardware into a functional state
3825e3ecdffaSAlex Deucher * after a suspend and updates the software state as necessary. This
3826e3ecdffaSAlex Deucher * function is also used for restoring the GPU after a GPU reset.
3827e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
3828e3ecdffaSAlex Deucher */
amdgpu_device_ip_resume_phase1(struct amdgpu_device * adev)382906ec9070SAlex Deucher static int amdgpu_device_ip_resume_phase1(struct amdgpu_device *adev)
3830d38ceaf9SAlex Deucher {
3831d38ceaf9SAlex Deucher int i, r;
3832d38ceaf9SAlex Deucher
3833d38ceaf9SAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
3834482f0e53SMonk Liu if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw)
3835d38ceaf9SAlex Deucher continue;
3836fcf0649fSChunming Zhou if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
3837fcf0649fSChunming Zhou adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
3838d7274ec7SBokun Zhang adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH ||
3839d7274ec7SBokun Zhang (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP && amdgpu_sriov_vf(adev))) {
3840482f0e53SMonk Liu
3841502d7630SSunil Khatri r = amdgpu_ip_block_resume(&adev->ip_blocks[i]);
3842502d7630SSunil Khatri if (r)
3843fcf0649fSChunming Zhou return r;
3844fcf0649fSChunming Zhou }
3845fcf0649fSChunming Zhou }
3846d38ceaf9SAlex Deucher
3847fcf0649fSChunming Zhou return 0;
3848fcf0649fSChunming Zhou }
3849fcf0649fSChunming Zhou
3850e3ecdffaSAlex Deucher /**
3851e3ecdffaSAlex Deucher * amdgpu_device_ip_resume_phase2 - run resume for hardware IPs
3852e3ecdffaSAlex Deucher *
3853e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3854e3ecdffaSAlex Deucher *
385573dae652SAlex Deucher * Second resume function for hardware IPs. The list of all the hardware
3856e3ecdffaSAlex Deucher * IPs that make up the asic is walked and the resume callbacks are run for
3857e3ecdffaSAlex Deucher * all blocks except COMMON, GMC, and IH. resume puts the hardware into a
3858e3ecdffaSAlex Deucher * functional state after a suspend and updates the software state as
3859e3ecdffaSAlex Deucher * necessary. This function is also used for restoring the GPU after a GPU
3860e3ecdffaSAlex Deucher * reset.
3861e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
3862e3ecdffaSAlex Deucher */
amdgpu_device_ip_resume_phase2(struct amdgpu_device * adev)386306ec9070SAlex Deucher static int amdgpu_device_ip_resume_phase2(struct amdgpu_device *adev)
3864fcf0649fSChunming Zhou {
3865fcf0649fSChunming Zhou int i, r;
3866fcf0649fSChunming Zhou
3867fcf0649fSChunming Zhou for (i = 0; i < adev->num_ip_blocks; i++) {
3868482f0e53SMonk Liu if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw)
3869fcf0649fSChunming Zhou continue;
3870d38ceaf9SAlex Deucher if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_COMMON ||
3871d38ceaf9SAlex Deucher adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC ||
38727a3e0bb2SRex Zhu adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_IH ||
387373dae652SAlex Deucher adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE ||
38747a3e0bb2SRex Zhu adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP)
3875d38ceaf9SAlex Deucher continue;
3876502d7630SSunil Khatri r = amdgpu_ip_block_resume(&adev->ip_blocks[i]);
3877502d7630SSunil Khatri if (r)
3878d38ceaf9SAlex Deucher return r;
3879d38ceaf9SAlex Deucher }
3880d38ceaf9SAlex Deucher
3881d38ceaf9SAlex Deucher return 0;
3882d38ceaf9SAlex Deucher }
3883d38ceaf9SAlex Deucher
3884e3ecdffaSAlex Deucher /**
388573dae652SAlex Deucher * amdgpu_device_ip_resume_phase3 - run resume for hardware IPs
388673dae652SAlex Deucher *
388773dae652SAlex Deucher * @adev: amdgpu_device pointer
388873dae652SAlex Deucher *
388973dae652SAlex Deucher * Third resume function for hardware IPs. The list of all the hardware
389073dae652SAlex Deucher * IPs that make up the asic is walked and the resume callbacks are run for
389173dae652SAlex Deucher * all DCE. resume puts the hardware into a functional state after a suspend
389273dae652SAlex Deucher * and updates the software state as necessary. This function is also used
389373dae652SAlex Deucher * for restoring the GPU after a GPU reset.
389473dae652SAlex Deucher *
389573dae652SAlex Deucher * Returns 0 on success, negative error code on failure.
389673dae652SAlex Deucher */
amdgpu_device_ip_resume_phase3(struct amdgpu_device * adev)389773dae652SAlex Deucher static int amdgpu_device_ip_resume_phase3(struct amdgpu_device *adev)
389873dae652SAlex Deucher {
389973dae652SAlex Deucher int i, r;
390073dae652SAlex Deucher
390173dae652SAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
390273dae652SAlex Deucher if (!adev->ip_blocks[i].status.valid || adev->ip_blocks[i].status.hw)
390373dae652SAlex Deucher continue;
390473dae652SAlex Deucher if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) {
390573dae652SAlex Deucher r = amdgpu_ip_block_resume(&adev->ip_blocks[i]);
390673dae652SAlex Deucher if (r)
390773dae652SAlex Deucher return r;
390873dae652SAlex Deucher }
390973dae652SAlex Deucher }
391073dae652SAlex Deucher
391173dae652SAlex Deucher return 0;
391273dae652SAlex Deucher }
391373dae652SAlex Deucher
391473dae652SAlex Deucher /**
3915e3ecdffaSAlex Deucher * amdgpu_device_ip_resume - run resume for hardware IPs
3916e3ecdffaSAlex Deucher *
3917e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3918e3ecdffaSAlex Deucher *
3919e3ecdffaSAlex Deucher * Main resume function for hardware IPs. The hardware IPs
3920e3ecdffaSAlex Deucher * are split into two resume functions because they are
3921b8920e1eSSrinivasan Shanmugam * also used in recovering from a GPU reset and some additional
3922e3ecdffaSAlex Deucher * steps need to be take between them. In this case (S3/S4) they are
3923e3ecdffaSAlex Deucher * run sequentially.
3924e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
3925e3ecdffaSAlex Deucher */
amdgpu_device_ip_resume(struct amdgpu_device * adev)392606ec9070SAlex Deucher static int amdgpu_device_ip_resume(struct amdgpu_device *adev)
3927d38ceaf9SAlex Deucher {
3928fcf0649fSChunming Zhou int r;
3929d38ceaf9SAlex Deucher
393006ec9070SAlex Deucher r = amdgpu_device_ip_resume_phase1(adev);
3931fcf0649fSChunming Zhou if (r)
3932d38ceaf9SAlex Deucher return r;
39337a3e0bb2SRex Zhu
39347a3e0bb2SRex Zhu r = amdgpu_device_fw_loading(adev);
39357a3e0bb2SRex Zhu if (r)
39367a3e0bb2SRex Zhu return r;
39377a3e0bb2SRex Zhu
393806ec9070SAlex Deucher r = amdgpu_device_ip_resume_phase2(adev);
3939d38ceaf9SAlex Deucher
3940b7043800SAlex Deucher if (adev->mman.buffer_funcs_ring->sched.ready)
3941b7043800SAlex Deucher amdgpu_ttm_set_buffer_funcs_status(adev, true);
3942b7043800SAlex Deucher
394373dae652SAlex Deucher if (r)
394473dae652SAlex Deucher return r;
394573dae652SAlex Deucher
394673dae652SAlex Deucher amdgpu_fence_driver_hw_init(adev);
394773dae652SAlex Deucher
394873dae652SAlex Deucher r = amdgpu_device_ip_resume_phase3(adev);
394973dae652SAlex Deucher
3950fcf0649fSChunming Zhou return r;
3951d38ceaf9SAlex Deucher }
3952d38ceaf9SAlex Deucher
3953e3ecdffaSAlex Deucher /**
3954e3ecdffaSAlex Deucher * amdgpu_device_detect_sriov_bios - determine if the board supports SR-IOV
3955e3ecdffaSAlex Deucher *
3956e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
3957e3ecdffaSAlex Deucher *
3958e3ecdffaSAlex Deucher * Query the VBIOS data tables to determine if the board supports SR-IOV.
3959e3ecdffaSAlex Deucher */
amdgpu_device_detect_sriov_bios(struct amdgpu_device * adev)39604e99a44eSMonk Liu static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
3961048765adSAndres Rodriguez {
39626867e1b5SMonk Liu if (amdgpu_sriov_vf(adev)) {
3963a5bde2f9SAlex Deucher if (adev->is_atom_fw) {
396458ff791aSHawking Zhang if (amdgpu_atomfirmware_gpu_virtualization_supported(adev))
3965a5bde2f9SAlex Deucher adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
3966a5bde2f9SAlex Deucher } else {
39674e99a44eSMonk Liu if (amdgpu_atombios_has_gpu_virtualization_table(adev))
39685a5099cbSXiangliang Yu adev->virt.caps |= AMDGPU_SRIOV_CAPS_SRIOV_VBIOS;
3969048765adSAndres Rodriguez }
39706867e1b5SMonk Liu
39716867e1b5SMonk Liu if (!(adev->virt.caps & AMDGPU_SRIOV_CAPS_SRIOV_VBIOS))
39726867e1b5SMonk Liu amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_NO_VBIOS, 0, 0);
39736867e1b5SMonk Liu }
3974a5bde2f9SAlex Deucher }
3975048765adSAndres Rodriguez
3976e3ecdffaSAlex Deucher /**
3977e3ecdffaSAlex Deucher * amdgpu_device_asic_has_dc_support - determine if DC supports the asic
3978e3ecdffaSAlex Deucher *
3979e3ecdffaSAlex Deucher * @asic_type: AMD asic type
3980e3ecdffaSAlex Deucher *
3981e3ecdffaSAlex Deucher * Check if there is DC (new modesetting infrastructre) support for an asic.
3982e3ecdffaSAlex Deucher * returns true if DC has support, false if not.
3983e3ecdffaSAlex Deucher */
amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)39844562236bSHarry Wentland bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
39854562236bSHarry Wentland {
39864562236bSHarry Wentland switch (asic_type) {
39870637d417SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_SI
39880637d417SAlex Deucher case CHIP_HAINAN:
39890637d417SAlex Deucher #endif
39900637d417SAlex Deucher case CHIP_TOPAZ:
39910637d417SAlex Deucher /* chips with no display hardware */
39920637d417SAlex Deucher return false;
39934562236bSHarry Wentland #if defined(CONFIG_DRM_AMD_DC)
399464200c46SMauro Rossi case CHIP_TAHITI:
399564200c46SMauro Rossi case CHIP_PITCAIRN:
399664200c46SMauro Rossi case CHIP_VERDE:
399764200c46SMauro Rossi case CHIP_OLAND:
39982d32ffd6SAlex Deucher /*
39992d32ffd6SAlex Deucher * We have systems in the wild with these ASICs that require
40002d32ffd6SAlex Deucher * LVDS and VGA support which is not supported with DC.
40012d32ffd6SAlex Deucher *
40022d32ffd6SAlex Deucher * Fallback to the non-DC driver here by default so as not to
40032d32ffd6SAlex Deucher * cause regressions.
40042d32ffd6SAlex Deucher */
40052d32ffd6SAlex Deucher #if defined(CONFIG_DRM_AMD_DC_SI)
40062d32ffd6SAlex Deucher return amdgpu_dc > 0;
40072d32ffd6SAlex Deucher #else
40082d32ffd6SAlex Deucher return false;
400964200c46SMauro Rossi #endif
40104562236bSHarry Wentland case CHIP_BONAIRE:
40110d6fbccbSAlex Deucher case CHIP_KAVERI:
4012367e6687SAlex Deucher case CHIP_KABINI:
4013367e6687SAlex Deucher case CHIP_MULLINS:
4014d9fda248SHarry Wentland /*
4015d9fda248SHarry Wentland * We have systems in the wild with these ASICs that require
4016b5a0168eSAlex Deucher * VGA support which is not supported with DC.
4017d9fda248SHarry Wentland *
4018d9fda248SHarry Wentland * Fallback to the non-DC driver here by default so as not to
4019d9fda248SHarry Wentland * cause regressions.
4020d9fda248SHarry Wentland */
4021d9fda248SHarry Wentland return amdgpu_dc > 0;
4022f7f12b25SAlex Deucher default:
4023fd187853SHawking Zhang return amdgpu_dc != 0;
4024f7f12b25SAlex Deucher #else
40254562236bSHarry Wentland default:
402693b09a9aSSimon Ser if (amdgpu_dc > 0)
4027b8920e1eSSrinivasan Shanmugam DRM_INFO_ONCE("Display Core has been requested via kernel parameter but isn't supported by ASIC, ignoring\n");
40284562236bSHarry Wentland return false;
4029f7f12b25SAlex Deucher #endif
40304562236bSHarry Wentland }
40314562236bSHarry Wentland }
40324562236bSHarry Wentland
40334562236bSHarry Wentland /**
40344562236bSHarry Wentland * amdgpu_device_has_dc_support - check if dc is supported
40354562236bSHarry Wentland *
4036982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
40374562236bSHarry Wentland *
40384562236bSHarry Wentland * Returns true for supported, false for not supported
40394562236bSHarry Wentland */
amdgpu_device_has_dc_support(struct amdgpu_device * adev)40404562236bSHarry Wentland bool amdgpu_device_has_dc_support(struct amdgpu_device *adev)
40414562236bSHarry Wentland {
404225263da3SAlex Deucher if (adev->enable_virtual_display ||
4043abaf210cSAsher Song (adev->harvest_ip_mask & AMD_HARVEST_IP_DMU_MASK))
40442555039dSXiangliang Yu return false;
40452555039dSXiangliang Yu
40464562236bSHarry Wentland return amdgpu_device_asic_has_dc_support(adev->asic_type);
40474562236bSHarry Wentland }
40484562236bSHarry Wentland
amdgpu_device_xgmi_reset_func(struct work_struct * __work)4049d4535e2cSAndrey Grodzovsky static void amdgpu_device_xgmi_reset_func(struct work_struct *__work)
4050d4535e2cSAndrey Grodzovsky {
4051d4535e2cSAndrey Grodzovsky struct amdgpu_device *adev =
4052d4535e2cSAndrey Grodzovsky container_of(__work, struct amdgpu_device, xgmi_reset_work);
4053d95e8e97SDennis Li struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(adev);
4054d4535e2cSAndrey Grodzovsky
4055c6a6e2dbSAndrey Grodzovsky /* It's a bug to not have a hive within this function */
4056c6a6e2dbSAndrey Grodzovsky if (WARN_ON(!hive))
4057c6a6e2dbSAndrey Grodzovsky return;
4058c6a6e2dbSAndrey Grodzovsky
4059c6a6e2dbSAndrey Grodzovsky /*
4060c6a6e2dbSAndrey Grodzovsky * Use task barrier to synchronize all xgmi reset works across the
4061c6a6e2dbSAndrey Grodzovsky * hive. task_barrier_enter and task_barrier_exit will block
4062c6a6e2dbSAndrey Grodzovsky * until all the threads running the xgmi reset works reach
4063c6a6e2dbSAndrey Grodzovsky * those points. task_barrier_full will do both blocks.
4064c6a6e2dbSAndrey Grodzovsky */
4065c6a6e2dbSAndrey Grodzovsky if (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) {
4066c6a6e2dbSAndrey Grodzovsky
4067c6a6e2dbSAndrey Grodzovsky task_barrier_enter(&hive->tb);
40684a580877SLuben Tuikov adev->asic_reset_res = amdgpu_device_baco_enter(adev_to_drm(adev));
4069c6a6e2dbSAndrey Grodzovsky
4070c6a6e2dbSAndrey Grodzovsky if (adev->asic_reset_res)
4071c6a6e2dbSAndrey Grodzovsky goto fail;
4072c6a6e2dbSAndrey Grodzovsky
4073c6a6e2dbSAndrey Grodzovsky task_barrier_exit(&hive->tb);
40744a580877SLuben Tuikov adev->asic_reset_res = amdgpu_device_baco_exit(adev_to_drm(adev));
4075c6a6e2dbSAndrey Grodzovsky
4076c6a6e2dbSAndrey Grodzovsky if (adev->asic_reset_res)
4077c6a6e2dbSAndrey Grodzovsky goto fail;
407843c4d576SJohn Clements
407921226f02STao Zhou amdgpu_ras_reset_error_count(adev, AMDGPU_RAS_BLOCK__MMHUB);
4080c6a6e2dbSAndrey Grodzovsky } else {
4081c6a6e2dbSAndrey Grodzovsky
4082c6a6e2dbSAndrey Grodzovsky task_barrier_full(&hive->tb);
4083d4535e2cSAndrey Grodzovsky adev->asic_reset_res = amdgpu_asic_reset(adev);
4084c6a6e2dbSAndrey Grodzovsky }
4085ce316fa5SLe Ma
4086c6a6e2dbSAndrey Grodzovsky fail:
4087d4535e2cSAndrey Grodzovsky if (adev->asic_reset_res)
4088fed184e9SEvan Quan DRM_WARN("ASIC reset failed with error, %d for drm dev, %s",
40894a580877SLuben Tuikov adev->asic_reset_res, adev_to_drm(adev)->unique);
4090d95e8e97SDennis Li amdgpu_put_xgmi_hive(hive);
4091d4535e2cSAndrey Grodzovsky }
4092d4535e2cSAndrey Grodzovsky
amdgpu_device_get_job_timeout_settings(struct amdgpu_device * adev)409371f98027SAlex Deucher static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev)
409471f98027SAlex Deucher {
409571f98027SAlex Deucher char *input = amdgpu_lockup_timeout;
409671f98027SAlex Deucher char *timeout_setting = NULL;
409771f98027SAlex Deucher int index = 0;
409871f98027SAlex Deucher long timeout;
409971f98027SAlex Deucher int ret = 0;
410071f98027SAlex Deucher
410171f98027SAlex Deucher /*
410267387dfeSAlex Deucher * By default timeout for non compute jobs is 10000
410367387dfeSAlex Deucher * and 60000 for compute jobs.
410471f98027SAlex Deucher * In SR-IOV or passthrough mode, timeout for compute
4105b7b2a316SJiawei * jobs are 60000 by default.
410671f98027SAlex Deucher */
410771f98027SAlex Deucher adev->gfx_timeout = msecs_to_jiffies(10000);
410871f98027SAlex Deucher adev->sdma_timeout = adev->video_timeout = adev->gfx_timeout;
41099882e278SEmily.Deng if (amdgpu_sriov_vf(adev))
41109882e278SEmily.Deng adev->compute_timeout = amdgpu_sriov_is_pp_one_vf(adev) ?
41119882e278SEmily.Deng msecs_to_jiffies(60000) : msecs_to_jiffies(10000);
411271f98027SAlex Deucher else
411367387dfeSAlex Deucher adev->compute_timeout = msecs_to_jiffies(60000);
411471f98027SAlex Deucher
4115f440ff44SWambui Karuga if (strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) {
411671f98027SAlex Deucher while ((timeout_setting = strsep(&input, ",")) &&
4117f440ff44SWambui Karuga strnlen(timeout_setting, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) {
411871f98027SAlex Deucher ret = kstrtol(timeout_setting, 0, &timeout);
411971f98027SAlex Deucher if (ret)
412071f98027SAlex Deucher return ret;
412171f98027SAlex Deucher
412271f98027SAlex Deucher if (timeout == 0) {
412371f98027SAlex Deucher index++;
412471f98027SAlex Deucher continue;
412571f98027SAlex Deucher } else if (timeout < 0) {
412671f98027SAlex Deucher timeout = MAX_SCHEDULE_TIMEOUT;
4127127aedf9SChristian König dev_warn(adev->dev, "lockup timeout disabled");
4128127aedf9SChristian König add_taint(TAINT_SOFTLOCKUP, LOCKDEP_STILL_OK);
412971f98027SAlex Deucher } else {
413071f98027SAlex Deucher timeout = msecs_to_jiffies(timeout);
413171f98027SAlex Deucher }
413271f98027SAlex Deucher
413371f98027SAlex Deucher switch (index++) {
413471f98027SAlex Deucher case 0:
413571f98027SAlex Deucher adev->gfx_timeout = timeout;
413671f98027SAlex Deucher break;
413771f98027SAlex Deucher case 1:
413871f98027SAlex Deucher adev->compute_timeout = timeout;
413971f98027SAlex Deucher break;
414071f98027SAlex Deucher case 2:
414171f98027SAlex Deucher adev->sdma_timeout = timeout;
414271f98027SAlex Deucher break;
414371f98027SAlex Deucher case 3:
414471f98027SAlex Deucher adev->video_timeout = timeout;
414571f98027SAlex Deucher break;
414671f98027SAlex Deucher default:
414771f98027SAlex Deucher break;
414871f98027SAlex Deucher }
414971f98027SAlex Deucher }
415071f98027SAlex Deucher /*
415171f98027SAlex Deucher * There is only one value specified and
415271f98027SAlex Deucher * it should apply to all non-compute jobs.
415371f98027SAlex Deucher */
4154bcccee89SEmily Deng if (index == 1) {
415571f98027SAlex Deucher adev->sdma_timeout = adev->video_timeout = adev->gfx_timeout;
4156bcccee89SEmily Deng if (amdgpu_sriov_vf(adev) || amdgpu_passthrough(adev))
4157bcccee89SEmily Deng adev->compute_timeout = adev->gfx_timeout;
4158bcccee89SEmily Deng }
415971f98027SAlex Deucher }
416071f98027SAlex Deucher
416171f98027SAlex Deucher return ret;
416271f98027SAlex Deucher }
4163d4535e2cSAndrey Grodzovsky
41644a74c38cSPhilip Yang /**
41654a74c38cSPhilip Yang * amdgpu_device_check_iommu_direct_map - check if RAM direct mapped to GPU
41664a74c38cSPhilip Yang *
41674a74c38cSPhilip Yang * @adev: amdgpu_device pointer
41684a74c38cSPhilip Yang *
41694a74c38cSPhilip Yang * RAM direct mapped to GPU if IOMMU is not enabled or is pass through mode
41704a74c38cSPhilip Yang */
amdgpu_device_check_iommu_direct_map(struct amdgpu_device * adev)41714a74c38cSPhilip Yang static void amdgpu_device_check_iommu_direct_map(struct amdgpu_device *adev)
41724a74c38cSPhilip Yang {
41734a74c38cSPhilip Yang struct iommu_domain *domain;
41744a74c38cSPhilip Yang
41754a74c38cSPhilip Yang domain = iommu_get_domain_for_dev(adev->dev);
41764a74c38cSPhilip Yang if (!domain || domain->type == IOMMU_DOMAIN_IDENTITY)
41774a74c38cSPhilip Yang adev->ram_is_direct_mapped = true;
41784a74c38cSPhilip Yang }
41794a74c38cSPhilip Yang
418075f0efbcSRahul Jain #if defined(CONFIG_HSA_AMD_P2P)
418175f0efbcSRahul Jain /**
418275f0efbcSRahul Jain * amdgpu_device_check_iommu_remap - Check if DMA remapping is enabled.
418375f0efbcSRahul Jain *
418475f0efbcSRahul Jain * @adev: amdgpu_device pointer
418575f0efbcSRahul Jain *
418675f0efbcSRahul Jain * return if IOMMU remapping bar address
418775f0efbcSRahul Jain */
amdgpu_device_check_iommu_remap(struct amdgpu_device * adev)418875f0efbcSRahul Jain static bool amdgpu_device_check_iommu_remap(struct amdgpu_device *adev)
418975f0efbcSRahul Jain {
419075f0efbcSRahul Jain struct iommu_domain *domain;
419175f0efbcSRahul Jain
419275f0efbcSRahul Jain domain = iommu_get_domain_for_dev(adev->dev);
419375f0efbcSRahul Jain if (domain && (domain->type == IOMMU_DOMAIN_DMA ||
419475f0efbcSRahul Jain domain->type == IOMMU_DOMAIN_DMA_FQ))
419575f0efbcSRahul Jain return true;
419675f0efbcSRahul Jain
419775f0efbcSRahul Jain return false;
419875f0efbcSRahul Jain }
419975f0efbcSRahul Jain #endif
420075f0efbcSRahul Jain
amdgpu_device_set_mcbp(struct amdgpu_device * adev)420102ff519eSAlex Deucher static void amdgpu_device_set_mcbp(struct amdgpu_device *adev)
420202ff519eSAlex Deucher {
420302ff519eSAlex Deucher if (amdgpu_mcbp == 1)
420402ff519eSAlex Deucher adev->gfx.mcbp = true;
42051e9e15dcSJiadong Zhu else if (amdgpu_mcbp == 0)
42061e9e15dcSJiadong Zhu adev->gfx.mcbp = false;
420750a7c876SAlex Deucher
420802ff519eSAlex Deucher if (amdgpu_sriov_vf(adev))
420902ff519eSAlex Deucher adev->gfx.mcbp = true;
421002ff519eSAlex Deucher
421102ff519eSAlex Deucher if (adev->gfx.mcbp)
421202ff519eSAlex Deucher DRM_INFO("MCBP is enabled\n");
421302ff519eSAlex Deucher }
421402ff519eSAlex Deucher
4215d38ceaf9SAlex Deucher /**
4216d38ceaf9SAlex Deucher * amdgpu_device_init - initialize the driver
4217d38ceaf9SAlex Deucher *
4218d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
4219d38ceaf9SAlex Deucher * @flags: driver flags
4220d38ceaf9SAlex Deucher *
4221d38ceaf9SAlex Deucher * Initializes the driver info and hw (all asics).
4222d38ceaf9SAlex Deucher * Returns 0 for success or an error on failure.
4223d38ceaf9SAlex Deucher * Called at driver startup.
4224d38ceaf9SAlex Deucher */
amdgpu_device_init(struct amdgpu_device * adev,uint32_t flags)4225d38ceaf9SAlex Deucher int amdgpu_device_init(struct amdgpu_device *adev,
4226d38ceaf9SAlex Deucher uint32_t flags)
4227d38ceaf9SAlex Deucher {
42288aba21b7SLuben Tuikov struct drm_device *ddev = adev_to_drm(adev);
42298aba21b7SLuben Tuikov struct pci_dev *pdev = adev->pdev;
4230d38ceaf9SAlex Deucher int r, i;
4231b98c6299SAlex Deucher bool px = false;
423295844d20SMarek Olšák u32 max_MBps;
423359e9fff1Slyndonli int tmp;
4234d38ceaf9SAlex Deucher
4235d38ceaf9SAlex Deucher adev->shutdown = false;
4236d38ceaf9SAlex Deucher adev->flags = flags;
42374e66d7d2SYong Zhao
42384e66d7d2SYong Zhao if (amdgpu_force_asic_type >= 0 && amdgpu_force_asic_type < CHIP_LAST)
42394e66d7d2SYong Zhao adev->asic_type = amdgpu_force_asic_type;
42404e66d7d2SYong Zhao else
42412f7d10b3SJammy Zhou adev->asic_type = flags & AMD_ASIC_MASK;
42424e66d7d2SYong Zhao
4243d38ceaf9SAlex Deucher adev->usec_timeout = AMDGPU_MAX_USEC_TIMEOUT;
4244593aa2d2SShaoyun Liu if (amdgpu_emu_mode == 1)
42458bdab6bbSYong Zhao adev->usec_timeout *= 10;
4246770d13b1SChristian König adev->gmc.gart_size = 512 * 1024 * 1024;
4247d38ceaf9SAlex Deucher adev->accel_working = false;
4248d38ceaf9SAlex Deucher adev->num_rings = 0;
424968ce8b24SChristian König RCU_INIT_POINTER(adev->gang_submit, dma_fence_get_stub());
4250d38ceaf9SAlex Deucher adev->mman.buffer_funcs = NULL;
4251d38ceaf9SAlex Deucher adev->mman.buffer_funcs_ring = NULL;
4252d38ceaf9SAlex Deucher adev->vm_manager.vm_pte_funcs = NULL;
42530c88b430SNirmoy Das adev->vm_manager.vm_pte_num_scheds = 0;
4254132f34e4SChristian König adev->gmc.gmc_funcs = NULL;
42557bd939d0SLikun GAO adev->harvest_ip_mask = 0x0;
4256f54d1867SChris Wilson adev->fence_context = dma_fence_context_alloc(AMDGPU_MAX_RINGS);
4257b8866c26SAndres Rodriguez bitmap_zero(adev->gfx.pipe_reserve_bitmap, AMDGPU_MAX_COMPUTE_QUEUES);
4258d38ceaf9SAlex Deucher
4259d38ceaf9SAlex Deucher adev->smc_rreg = &amdgpu_invalid_rreg;
4260d38ceaf9SAlex Deucher adev->smc_wreg = &amdgpu_invalid_wreg;
4261d38ceaf9SAlex Deucher adev->pcie_rreg = &amdgpu_invalid_rreg;
4262d38ceaf9SAlex Deucher adev->pcie_wreg = &amdgpu_invalid_wreg;
42630c552ed3SLe Ma adev->pcie_rreg_ext = &amdgpu_invalid_rreg_ext;
42640c552ed3SLe Ma adev->pcie_wreg_ext = &amdgpu_invalid_wreg_ext;
426536b9a952SHuang Rui adev->pciep_rreg = &amdgpu_invalid_rreg;
426636b9a952SHuang Rui adev->pciep_wreg = &amdgpu_invalid_wreg;
42674fa1c6a6STao Zhou adev->pcie_rreg64 = &amdgpu_invalid_rreg64;
42684fa1c6a6STao Zhou adev->pcie_wreg64 = &amdgpu_invalid_wreg64;
4269a76b2870SCandice Li adev->pcie_rreg64_ext = &amdgpu_invalid_rreg64_ext;
4270a76b2870SCandice Li adev->pcie_wreg64_ext = &amdgpu_invalid_wreg64_ext;
4271d38ceaf9SAlex Deucher adev->uvd_ctx_rreg = &amdgpu_invalid_rreg;
4272d38ceaf9SAlex Deucher adev->uvd_ctx_wreg = &amdgpu_invalid_wreg;
4273d38ceaf9SAlex Deucher adev->didt_rreg = &amdgpu_invalid_rreg;
4274d38ceaf9SAlex Deucher adev->didt_wreg = &amdgpu_invalid_wreg;
4275ccdbb20aSRex Zhu adev->gc_cac_rreg = &amdgpu_invalid_rreg;
4276ccdbb20aSRex Zhu adev->gc_cac_wreg = &amdgpu_invalid_wreg;
4277d38ceaf9SAlex Deucher adev->audio_endpt_rreg = &amdgpu_block_invalid_rreg;
4278d38ceaf9SAlex Deucher adev->audio_endpt_wreg = &amdgpu_block_invalid_wreg;
4279d38ceaf9SAlex Deucher
42803e39ab90SAlex Deucher DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X 0x%02X).\n",
4281d38ceaf9SAlex Deucher amdgpu_asic_name[adev->asic_type], pdev->vendor, pdev->device,
42823e39ab90SAlex Deucher pdev->subsystem_vendor, pdev->subsystem_device, pdev->revision);
4283d38ceaf9SAlex Deucher
4284d38ceaf9SAlex Deucher /* mutex initialization are all done here so we
4285b8920e1eSSrinivasan Shanmugam * can recall function without having locking issues
4286b8920e1eSSrinivasan Shanmugam */
42870e5ca0d1SHuang Rui mutex_init(&adev->firmware.mutex);
4288d38ceaf9SAlex Deucher mutex_init(&adev->pm.mutex);
4289d38ceaf9SAlex Deucher mutex_init(&adev->gfx.gpu_clock_mutex);
4290d38ceaf9SAlex Deucher mutex_init(&adev->srbm_mutex);
4291b8866c26SAndres Rodriguez mutex_init(&adev->gfx.pipe_reserve_mutex);
4292d23ee13fSRex Zhu mutex_init(&adev->gfx.gfx_off_mutex);
429398a54e88SLe Ma mutex_init(&adev->gfx.partition_mutex);
4294d38ceaf9SAlex Deucher mutex_init(&adev->grbm_idx_mutex);
4295d38ceaf9SAlex Deucher mutex_init(&adev->mn_lock);
4296e23b74aaSAlex Deucher mutex_init(&adev->virt.vf_errors.lock);
4297d38ceaf9SAlex Deucher hash_init(adev->mn_hash);
429832eaeae0SAlex Deucher mutex_init(&adev->psp.mutex);
4299bd052211SPan, Xinhui mutex_init(&adev->notifier_lock);
43008cda7a4fSAlex Deucher mutex_init(&adev->pm.stable_pstate_ctx_lock);
4301f113cc32SAlex Deucher mutex_init(&adev->benchmark_mutex);
430276acba7bSAlex Deucher mutex_init(&adev->gfx.reset_sem_mutex);
4303e189be9bSSrinivasan Shanmugam /* Initialize the mutex for cleaner shader isolation between GFX and compute processes */
4304e189be9bSSrinivasan Shanmugam mutex_init(&adev->enforce_isolation_mutex);
4305bd22e44aSChristian König for (i = 0; i < MAX_XCP; ++i) {
4306bd22e44aSChristian König adev->isolation[i].spearhead = dma_fence_get_stub();
4307bd22e44aSChristian König amdgpu_sync_create(&adev->isolation[i].active);
4308bd22e44aSChristian König amdgpu_sync_create(&adev->isolation[i].prev);
4309bd22e44aSChristian König }
4310afefd6f2SSrinivasan Shanmugam mutex_init(&adev->gfx.kfd_sch_mutex);
4311553673a3SAlex Deucher mutex_init(&adev->gfx.workload_profile_mutex);
4312ca6575a3SAlex Deucher mutex_init(&adev->vcn.workload_profile_mutex);
4313d38ceaf9SAlex Deucher
43144eaf21b7SPrike Liang amdgpu_device_init_apu_flags(adev);
43159f6a7857SHuang Rui
4316912dfc84SEvan Quan r = amdgpu_device_check_arguments(adev);
4317912dfc84SEvan Quan if (r)
4318912dfc84SEvan Quan return r;
4319d38ceaf9SAlex Deucher
4320d38ceaf9SAlex Deucher spin_lock_init(&adev->mmio_idx_lock);
4321d38ceaf9SAlex Deucher spin_lock_init(&adev->smc_idx_lock);
4322d38ceaf9SAlex Deucher spin_lock_init(&adev->pcie_idx_lock);
4323d38ceaf9SAlex Deucher spin_lock_init(&adev->uvd_ctx_idx_lock);
4324d38ceaf9SAlex Deucher spin_lock_init(&adev->didt_idx_lock);
4325ccdbb20aSRex Zhu spin_lock_init(&adev->gc_cac_idx_lock);
432616abb5d2SEvan Quan spin_lock_init(&adev->se_cac_idx_lock);
4327d38ceaf9SAlex Deucher spin_lock_init(&adev->audio_endpt_idx_lock);
432895844d20SMarek Olšák spin_lock_init(&adev->mm_stats.lock);
4329dc0297f3SSrinivasan Shanmugam spin_lock_init(&adev->virt.rlcg_reg_lock);
4330497d7ceeSAlex Deucher spin_lock_init(&adev->wb.lock);
4331d38ceaf9SAlex Deucher
4332655ce9cbSshaoyunl INIT_LIST_HEAD(&adev->reset_list);
4333655ce9cbSshaoyunl
43346492e1b0Syipechai INIT_LIST_HEAD(&adev->ras_list);
43356492e1b0Syipechai
43363e38b634SEvan Quan INIT_LIST_HEAD(&adev->pm.od_kobj_list);
43373e38b634SEvan Quan
4338beff74bcSAlex Deucher INIT_DELAYED_WORK(&adev->delayed_init_work,
4339beff74bcSAlex Deucher amdgpu_device_delayed_init_work_handler);
43401e317b99SRex Zhu INIT_DELAYED_WORK(&adev->gfx.gfx_off_delay_work,
43411e317b99SRex Zhu amdgpu_device_delay_enable_gfx_off);
4342afefd6f2SSrinivasan Shanmugam /*
4343afefd6f2SSrinivasan Shanmugam * Initialize the enforce_isolation work structures for each XCP
4344afefd6f2SSrinivasan Shanmugam * partition. This work handler is responsible for enforcing shader
4345afefd6f2SSrinivasan Shanmugam * isolation on AMD GPUs. It counts the number of emitted fences for
4346afefd6f2SSrinivasan Shanmugam * each GFX and compute ring. If there are any fences, it schedules
4347afefd6f2SSrinivasan Shanmugam * the `enforce_isolation_work` to be run after a delay. If there are
4348afefd6f2SSrinivasan Shanmugam * no fences, it signals the Kernel Fusion Driver (KFD) to resume the
4349afefd6f2SSrinivasan Shanmugam * runqueue.
4350afefd6f2SSrinivasan Shanmugam */
4351afefd6f2SSrinivasan Shanmugam for (i = 0; i < MAX_XCP; i++) {
4352afefd6f2SSrinivasan Shanmugam INIT_DELAYED_WORK(&adev->gfx.enforce_isolation[i].work,
4353afefd6f2SSrinivasan Shanmugam amdgpu_gfx_enforce_isolation_handler);
4354afefd6f2SSrinivasan Shanmugam adev->gfx.enforce_isolation[i].adev = adev;
4355afefd6f2SSrinivasan Shanmugam adev->gfx.enforce_isolation[i].xcp_id = i;
4356afefd6f2SSrinivasan Shanmugam }
43572dc80b00SShirish S
4358d4535e2cSAndrey Grodzovsky INIT_WORK(&adev->xgmi_reset_work, amdgpu_device_xgmi_reset_func);
4359d4535e2cSAndrey Grodzovsky
4360d23ee13fSRex Zhu adev->gfx.gfx_off_req_count = 1;
43610ad7347aSAndré Almeida adev->gfx.gfx_off_residency = 0;
43620ad7347aSAndré Almeida adev->gfx.gfx_off_entrycount = 0;
4363b6e79d9aSJason Yan adev->pm.ac_power = power_supply_is_system_supplied() > 0;
4364b1ddf548SRex Zhu
4365b265bdbdSEvan Quan atomic_set(&adev->throttling_logging_enabled, 1);
4366b265bdbdSEvan Quan /*
4367b265bdbdSEvan Quan * If throttling continues, logging will be performed every minute
4368b265bdbdSEvan Quan * to avoid log flooding. "-1" is subtracted since the thermal
4369b265bdbdSEvan Quan * throttling interrupt comes every second. Thus, the total logging
4370b265bdbdSEvan Quan * interval is 59 seconds(retelimited printk interval) + 1(waiting
4371b265bdbdSEvan Quan * for throttling interrupt) = 60 seconds.
4372b265bdbdSEvan Quan */
4373b265bdbdSEvan Quan ratelimit_state_init(&adev->throttling_logging_rs, (60 - 1) * HZ, 1);
437484a2947eSVictor Skvortsov
4375b265bdbdSEvan Quan ratelimit_set_flags(&adev->throttling_logging_rs, RATELIMIT_MSG_ON_RELEASE);
4376b265bdbdSEvan Quan
43770fa49558SAlex Xie /* Registers mapping */
43780fa49558SAlex Xie /* TODO: block userspace mapping of io register */
4379da69c161SKen Wang if (adev->asic_type >= CHIP_BONAIRE) {
4380d38ceaf9SAlex Deucher adev->rmmio_base = pci_resource_start(adev->pdev, 5);
4381d38ceaf9SAlex Deucher adev->rmmio_size = pci_resource_len(adev->pdev, 5);
4382da69c161SKen Wang } else {
4383da69c161SKen Wang adev->rmmio_base = pci_resource_start(adev->pdev, 2);
4384da69c161SKen Wang adev->rmmio_size = pci_resource_len(adev->pdev, 2);
4385da69c161SKen Wang }
43865c1354bdSChunming Zhou
43876c08e0efSEvan Quan for (i = 0; i < AMD_IP_BLOCK_TYPE_NUM; i++)
43886c08e0efSEvan Quan atomic_set(&adev->pm.pwr_state[i], POWER_STATE_UNKNOWN);
43896c08e0efSEvan Quan
4390d38ceaf9SAlex Deucher adev->rmmio = ioremap(adev->rmmio_base, adev->rmmio_size);
4391b8920e1eSSrinivasan Shanmugam if (!adev->rmmio)
4392d38ceaf9SAlex Deucher return -ENOMEM;
4393b8920e1eSSrinivasan Shanmugam
4394d38ceaf9SAlex Deucher DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)adev->rmmio_base);
4395b8920e1eSSrinivasan Shanmugam DRM_INFO("register mmio size: %u\n", (unsigned int)adev->rmmio_size);
4396d38ceaf9SAlex Deucher
4397436afdfaSPhilip Yang /*
4398436afdfaSPhilip Yang * Reset domain needs to be present early, before XGMI hive discovered
4399a567db80SRandy Dunlap * (if any) and initialized to use reset sem and in_gpu reset flag
4400436afdfaSPhilip Yang * early on during init and before calling to RREG32.
4401436afdfaSPhilip Yang */
4402436afdfaSPhilip Yang adev->reset_domain = amdgpu_reset_create_reset_domain(SINGLE_DEVICE, "amdgpu-reset-dev");
440303c6284dSMa Jun if (!adev->reset_domain)
440403c6284dSMa Jun return -ENOMEM;
4405436afdfaSPhilip Yang
44063aa0115dSMonk Liu /* detect hw virtualization here */
4407a91d91b6STony Yi amdgpu_virt_init(adev);
44083aa0115dSMonk Liu
440904e85958STong Liu01 amdgpu_device_get_pcie_info(adev);
441004e85958STong Liu01
4411dffa11b4SMonk Liu r = amdgpu_device_get_job_timeout_settings(adev);
4412a190d1c7SXiaojie Yuan if (r) {
4413dffa11b4SMonk Liu dev_err(adev->dev, "invalid lockup_timeout parameter syntax\n");
441403c6284dSMa Jun return r;
4415a190d1c7SXiaojie Yuan }
4416a190d1c7SXiaojie Yuan
4417bf909454SPierre-Eric Pelloux-Prayer amdgpu_device_set_mcbp(adev);
4418bf909454SPierre-Eric Pelloux-Prayer
441914f2fe34SLijo Lazar /*
442014f2fe34SLijo Lazar * By default, use default mode where all blocks are expected to be
442114f2fe34SLijo Lazar * initialized. At present a 'swinit' of blocks is required to be
442214f2fe34SLijo Lazar * completed before the need for a different level is detected.
442314f2fe34SLijo Lazar */
442414f2fe34SLijo Lazar amdgpu_set_init_level(adev, AMDGPU_INIT_LEVEL_DEFAULT);
4425d38ceaf9SAlex Deucher /* early init functions */
442606ec9070SAlex Deucher r = amdgpu_device_ip_early_init(adev);
4427d38ceaf9SAlex Deucher if (r)
442803c6284dSMa Jun return r;
4429d38ceaf9SAlex Deucher
44309deacd6cSAlex Deucher /*
44319deacd6cSAlex Deucher * No need to remove conflicting FBs for non-display class devices.
44329deacd6cSAlex Deucher * This prevents the sysfb from being freed accidently.
44339deacd6cSAlex Deucher */
44349deacd6cSAlex Deucher if ((pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA ||
44359deacd6cSAlex Deucher (pdev->class >> 8) == PCI_CLASS_DISPLAY_OTHER) {
4436b7cdb41eSMario Limonciello /* Get rid of things like offb */
4437ea1d2a38SThomas Zimmermann r = aperture_remove_conflicting_pci_devices(adev->pdev, amdgpu_kms_driver.name);
4438b7cdb41eSMario Limonciello if (r)
443903c6284dSMa Jun return r;
44409deacd6cSAlex Deucher }
4441b7cdb41eSMario Limonciello
44424d33e704SSunil Khatri /* Enable TMZ based on IP_VERSION */
44434d33e704SSunil Khatri amdgpu_gmc_tmz_set(adev);
44444d33e704SSunil Khatri
44453e2daccaSDanijel Slivka if (amdgpu_sriov_vf(adev) &&
44463e2daccaSDanijel Slivka amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 3, 0))
44473e2daccaSDanijel Slivka /* VF MMIO access (except mailbox range) from CPU
44483e2daccaSDanijel Slivka * will be blocked during sriov runtime
44493e2daccaSDanijel Slivka */
44503e2daccaSDanijel Slivka adev->virt.caps |= AMDGPU_VF_MMIO_ACCESS_PROTECT;
44513e2daccaSDanijel Slivka
4452957b0787SYifan Zhang amdgpu_gmc_noretry_set(adev);
44534a0165f0SVictor Skvortsov /* Need to get xgmi info early to decide the reset behavior*/
44544a0165f0SVictor Skvortsov if (adev->gmc.xgmi.supported) {
44554a0165f0SVictor Skvortsov r = adev->gfxhub.funcs->get_xgmi_info(adev);
44564a0165f0SVictor Skvortsov if (r)
445703c6284dSMa Jun return r;
44584a0165f0SVictor Skvortsov }
44594a0165f0SVictor Skvortsov
44608e6d0b69Sshaoyunl /* enable PCIE atomic ops */
4461b4520bfdSGavin Wan if (amdgpu_sriov_vf(adev)) {
4462b4520bfdSGavin Wan if (adev->virt.fw_reserve.p_pf2vf)
44638e6d0b69Sshaoyunl adev->have_atomics_support = ((struct amd_sriov_msg_pf2vf_info *)
4464e15c9d06SBokun Zhang adev->virt.fw_reserve.p_pf2vf)->pcie_atomic_ops_support_flags ==
44658e6d0b69Sshaoyunl (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | PCI_EXP_DEVCAP2_ATOMIC_COMP64);
44660e768043SYifan Zhang /* APUs w/ gfx9 onwards doesn't reply on PCIe atomics, rather it is a
44670e768043SYifan Zhang * internal path natively support atomics, set have_atomics_support to true.
44680e768043SYifan Zhang */
4469b4520bfdSGavin Wan } else if ((adev->flags & AMD_IS_APU) &&
44704e8303cfSLijo Lazar (amdgpu_ip_version(adev, GC_HWIP, 0) >
44714e8303cfSLijo Lazar IP_VERSION(9, 0, 0))) {
44720e768043SYifan Zhang adev->have_atomics_support = true;
4473b4520bfdSGavin Wan } else {
44748e6d0b69Sshaoyunl adev->have_atomics_support =
44758e6d0b69Sshaoyunl !pci_enable_atomic_ops_to_root(adev->pdev,
44768e6d0b69Sshaoyunl PCI_EXP_DEVCAP2_ATOMIC_COMP32 |
44778e6d0b69Sshaoyunl PCI_EXP_DEVCAP2_ATOMIC_COMP64);
4478b4520bfdSGavin Wan }
4479b4520bfdSGavin Wan
44808e6d0b69Sshaoyunl if (!adev->have_atomics_support)
44818e6d0b69Sshaoyunl dev_info(adev->dev, "PCIE atomic ops is not supported\n");
44828e6d0b69Sshaoyunl
44836585661dSOak Zeng /* doorbell bar mapping and doorbell index init*/
448443c064dbSShashank Sharma amdgpu_doorbell_init(adev);
44856585661dSOak Zeng
44869475a943SShaoyun Liu if (amdgpu_emu_mode == 1) {
44879475a943SShaoyun Liu /* post the asic on emulation mode */
44889475a943SShaoyun Liu emu_soc_asic_init(adev);
4489bfca0289SShaoyun Liu goto fence_driver_init;
44909475a943SShaoyun Liu }
4491bfca0289SShaoyun Liu
449204442bf7SLijo Lazar amdgpu_reset_init(adev);
449304442bf7SLijo Lazar
44944e99a44eSMonk Liu /* detect if we are with an SRIOV vbios */
4495b4520bfdSGavin Wan if (adev->bios)
44964e99a44eSMonk Liu amdgpu_device_detect_sriov_bios(adev);
4497048765adSAndres Rodriguez
449895e8e59eSAlex Deucher /* check if we need to reset the asic
449995e8e59eSAlex Deucher * E.g., driver was not cleanly unloaded previously, etc.
450095e8e59eSAlex Deucher */
4501f14899fdSwentalou if (!amdgpu_sriov_vf(adev) && amdgpu_asic_need_reset_on_init(adev)) {
4502e3c1b071Sshaoyunl if (adev->gmc.xgmi.num_physical_nodes) {
4503e3c1b071Sshaoyunl dev_info(adev->dev, "Pending hive reset.\n");
45045839d27dSLijo Lazar amdgpu_set_init_level(adev,
45055839d27dSLijo Lazar AMDGPU_INIT_LEVEL_MINIMAL_XGMI);
45067c1d9e10SKenneth Feng } else if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) &&
45077c1d9e10SKenneth Feng !amdgpu_device_has_display_hardware(adev)) {
45087c1d9e10SKenneth Feng r = psp_gpu_reset(adev);
4509e3c1b071Sshaoyunl } else {
451059e9fff1Slyndonli tmp = amdgpu_reset_method;
451159e9fff1Slyndonli /* It should do a default reset when loading or reloading the driver,
451259e9fff1Slyndonli * regardless of the module parameter reset_method.
451359e9fff1Slyndonli */
451459e9fff1Slyndonli amdgpu_reset_method = AMD_RESET_METHOD_NONE;
451595e8e59eSAlex Deucher r = amdgpu_asic_reset(adev);
451659e9fff1Slyndonli amdgpu_reset_method = tmp;
45177c1d9e10SKenneth Feng }
45187c1d9e10SKenneth Feng
451995e8e59eSAlex Deucher if (r) {
452095e8e59eSAlex Deucher dev_err(adev->dev, "asic reset on init failed\n");
452195e8e59eSAlex Deucher goto failed;
452295e8e59eSAlex Deucher }
452395e8e59eSAlex Deucher }
452495e8e59eSAlex Deucher
4525d38ceaf9SAlex Deucher /* Post card if necessary */
452639c640c0SAlex Deucher if (amdgpu_device_need_post(adev)) {
4527d38ceaf9SAlex Deucher if (!adev->bios) {
4528bec86378SMonk Liu dev_err(adev->dev, "no vBIOS found\n");
452983ba126aSAlex Deucher r = -EINVAL;
453083ba126aSAlex Deucher goto failed;
4531d38ceaf9SAlex Deucher }
4532bec86378SMonk Liu DRM_INFO("GPU posting now...\n");
45334d2997abSAlex Deucher r = amdgpu_device_asic_init(adev);
45344e99a44eSMonk Liu if (r) {
45354e99a44eSMonk Liu dev_err(adev->dev, "gpu post error!\n");
45364e99a44eSMonk Liu goto failed;
45374e99a44eSMonk Liu }
4538d38ceaf9SAlex Deucher }
4539d38ceaf9SAlex Deucher
45409535a86aSShiwu Zhang if (adev->bios) {
454188b64e95SAlex Deucher if (adev->is_atom_fw) {
454288b64e95SAlex Deucher /* Initialize clocks */
454388b64e95SAlex Deucher r = amdgpu_atomfirmware_get_clock_info(adev);
454488b64e95SAlex Deucher if (r) {
454588b64e95SAlex Deucher dev_err(adev->dev, "amdgpu_atomfirmware_get_clock_info failed\n");
4546e23b74aaSAlex Deucher amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_ATOMBIOS_GET_CLOCK_FAIL, 0, 0);
454788b64e95SAlex Deucher goto failed;
454888b64e95SAlex Deucher }
454988b64e95SAlex Deucher } else {
4550d38ceaf9SAlex Deucher /* Initialize clocks */
4551d38ceaf9SAlex Deucher r = amdgpu_atombios_get_clock_info(adev);
45522c1a2784SAlex Deucher if (r) {
45532c1a2784SAlex Deucher dev_err(adev->dev, "amdgpu_atombios_get_clock_info failed\n");
4554e23b74aaSAlex Deucher amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_ATOMBIOS_GET_CLOCK_FAIL, 0, 0);
455589041940SGavin Wan goto failed;
45562c1a2784SAlex Deucher }
4557d38ceaf9SAlex Deucher /* init i2c buses */
45581c0b144bSAlex Deucher amdgpu_i2c_init(adev);
4559a5bde2f9SAlex Deucher }
45609535a86aSShiwu Zhang }
4561d38ceaf9SAlex Deucher
4562bfca0289SShaoyun Liu fence_driver_init:
4563d38ceaf9SAlex Deucher /* Fence driver */
4564067f44c8SGuchun Chen r = amdgpu_fence_driver_sw_init(adev);
45652c1a2784SAlex Deucher if (r) {
4566067f44c8SGuchun Chen dev_err(adev->dev, "amdgpu_fence_driver_sw_init failed\n");
4567e23b74aaSAlex Deucher amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_FENCE_INIT_FAIL, 0, 0);
456883ba126aSAlex Deucher goto failed;
45692c1a2784SAlex Deucher }
4570d38ceaf9SAlex Deucher
4571d38ceaf9SAlex Deucher /* init the mode config */
45724a580877SLuben Tuikov drm_mode_config_init(adev_to_drm(adev));
4573d38ceaf9SAlex Deucher
457406ec9070SAlex Deucher r = amdgpu_device_ip_init(adev);
4575d38ceaf9SAlex Deucher if (r) {
457606ec9070SAlex Deucher dev_err(adev->dev, "amdgpu_device_ip_init failed\n");
4577e23b74aaSAlex Deucher amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_INIT_FAIL, 0, 0);
4578970fd197SStanley.Yang goto release_ras_con;
4579d38ceaf9SAlex Deucher }
4580d38ceaf9SAlex Deucher
45818d35a259SLikun Gao amdgpu_fence_driver_hw_init(adev);
45828d35a259SLikun Gao
4583d69b8971SYong Zhao dev_info(adev->dev,
4584d69b8971SYong Zhao "SE %d, SH per SE %d, CU per SH %d, active_cu_number %d\n",
4585d7f72fe4SYong Zhao adev->gfx.config.max_shader_engines,
4586d7f72fe4SYong Zhao adev->gfx.config.max_sh_per_se,
4587d7f72fe4SYong Zhao adev->gfx.config.max_cu_per_sh,
4588d7f72fe4SYong Zhao adev->gfx.cu_info.number);
4589d7f72fe4SYong Zhao
4590d38ceaf9SAlex Deucher adev->accel_working = true;
4591d38ceaf9SAlex Deucher
4592e59c0205SAlex Xie amdgpu_vm_check_compute_bug(adev);
4593e59c0205SAlex Xie
459495844d20SMarek Olšák /* Initialize the buffer migration limit. */
459595844d20SMarek Olšák if (amdgpu_moverate >= 0)
459695844d20SMarek Olšák max_MBps = amdgpu_moverate;
459795844d20SMarek Olšák else
459895844d20SMarek Olšák max_MBps = 8; /* Allow 8 MB/s. */
459995844d20SMarek Olšák /* Get a log2 for easy divisions. */
460095844d20SMarek Olšák adev->mm_stats.log2_max_MBps = ilog2(max(1u, max_MBps));
460195844d20SMarek Olšák
4602b0adca4dSEvan Quan /*
4603b0adca4dSEvan Quan * Register gpu instance before amdgpu_device_enable_mgpu_fan_boost.
4604b0adca4dSEvan Quan * Otherwise the mgpu fan boost feature will be skipped due to the
4605b0adca4dSEvan Quan * gpu instance is counted less.
4606b0adca4dSEvan Quan */
4607b0adca4dSEvan Quan amdgpu_register_gpu_instance(adev);
4608b0adca4dSEvan Quan
4609d38ceaf9SAlex Deucher /* enable clockgating, etc. after ib tests, etc. since some blocks require
4610d38ceaf9SAlex Deucher * explicit gating rather than handling it automatically.
4611d38ceaf9SAlex Deucher */
46125839d27dSLijo Lazar if (adev->init_lvl->level != AMDGPU_INIT_LEVEL_MINIMAL_XGMI) {
461306ec9070SAlex Deucher r = amdgpu_device_ip_late_init(adev);
46142c1a2784SAlex Deucher if (r) {
461506ec9070SAlex Deucher dev_err(adev->dev, "amdgpu_device_ip_late_init failed\n");
4616e23b74aaSAlex Deucher amdgpu_vf_error_put(adev, AMDGIM_ERROR_VF_AMDGPU_LATE_INIT_FAIL, 0, r);
4617970fd197SStanley.Yang goto release_ras_con;
46182c1a2784SAlex Deucher }
4619108c6a63Sxinhui pan /* must succeed. */
4620511fdbc3Sxinhui pan amdgpu_ras_resume(adev);
4621beff74bcSAlex Deucher queue_delayed_work(system_wq, &adev->delayed_init_work,
4622beff74bcSAlex Deucher msecs_to_jiffies(AMDGPU_RESUME_MS));
4623e3c1b071Sshaoyunl }
4624beff74bcSAlex Deucher
462538eecbe0SChong Li if (amdgpu_sriov_vf(adev)) {
462638eecbe0SChong Li amdgpu_virt_release_full_gpu(adev, true);
46272c738637SMonk Liu flush_delayed_work(&adev->delayed_init_work);
462838eecbe0SChong Li }
46292c738637SMonk Liu
463090bcb9b5SEvan Quan /*
463190bcb9b5SEvan Quan * Place those sysfs registering after `late_init`. As some of those
463290bcb9b5SEvan Quan * operations performed in `late_init` might affect the sysfs
463390bcb9b5SEvan Quan * interfaces creating.
463490bcb9b5SEvan Quan */
463590bcb9b5SEvan Quan r = amdgpu_atombios_sysfs_init(adev);
463690bcb9b5SEvan Quan if (r)
463790bcb9b5SEvan Quan drm_err(&adev->ddev,
463890bcb9b5SEvan Quan "registering atombios sysfs failed (%d).\n", r);
463990bcb9b5SEvan Quan
464090bcb9b5SEvan Quan r = amdgpu_pm_sysfs_init(adev);
464190bcb9b5SEvan Quan if (r)
464290bcb9b5SEvan Quan DRM_ERROR("registering pm sysfs failed (%d).\n", r);
464390bcb9b5SEvan Quan
464490bcb9b5SEvan Quan r = amdgpu_ucode_sysfs_init(adev);
464590bcb9b5SEvan Quan if (r) {
464690bcb9b5SEvan Quan adev->ucode_sysfs_en = false;
464790bcb9b5SEvan Quan DRM_ERROR("Creating firmware sysfs failed (%d).\n", r);
464890bcb9b5SEvan Quan } else
464990bcb9b5SEvan Quan adev->ucode_sysfs_en = true;
465090bcb9b5SEvan Quan
46519c05636cSVictor Skvortsov r = amdgpu_device_attr_sysfs_init(adev);
46525aea5327SLuben Tuikov if (r)
465377f3a5cdSNirmoy Das dev_err(adev->dev, "Could not create amdgpu device attr\n");
4654bd607166SKent Russell
465576da73f0SLijo Lazar r = devm_device_add_group(adev->dev, &amdgpu_board_attrs_group);
465676da73f0SLijo Lazar if (r)
465776da73f0SLijo Lazar dev_err(adev->dev,
465876da73f0SLijo Lazar "Could not create amdgpu board attributes\n");
465976da73f0SLijo Lazar
46607957ec80SLijo Lazar amdgpu_fru_sysfs_init(adev);
4661af39e6f4SLijo Lazar amdgpu_reg_state_sysfs_init(adev);
46624ae86dc8SLijo Lazar amdgpu_xcp_cfg_sysfs_init(adev);
46637957ec80SLijo Lazar
4664d155bef0SArnd Bergmann if (IS_ENABLED(CONFIG_PERF_EVENTS))
46659c7c85f7SJonathan Kim r = amdgpu_pmu_init(adev);
46669c7c85f7SJonathan Kim if (r)
46679c7c85f7SJonathan Kim dev_err(adev->dev, "amdgpu_pmu_init failed\n");
46689c7c85f7SJonathan Kim
4669c1dd4aa6SAndrey Grodzovsky /* Have stored pci confspace at hand for restore in sudden PCI error */
4670c1dd4aa6SAndrey Grodzovsky if (amdgpu_device_cache_pci_state(adev->pdev))
4671c1dd4aa6SAndrey Grodzovsky pci_restore_state(pdev);
4672c1dd4aa6SAndrey Grodzovsky
46738c3dd61cSKai-Heng Feng /* if we have > 1 VGA cards, then disable the amdgpu VGA resources */
46748c3dd61cSKai-Heng Feng /* this will fail for cards that aren't VGA class devices, just
4675b8920e1eSSrinivasan Shanmugam * ignore it
4676b8920e1eSSrinivasan Shanmugam */
46778c3dd61cSKai-Heng Feng if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
4678bf44e8ceSChristoph Hellwig vga_client_register(adev->pdev, amdgpu_device_vga_set_decode);
46798c3dd61cSKai-Heng Feng
4680d37a3929SOrlando Chamberlain px = amdgpu_device_supports_px(ddev);
4681d37a3929SOrlando Chamberlain
46827b1c6263SAlex Deucher if (px || (!dev_is_removable(&adev->pdev->dev) &&
4683d37a3929SOrlando Chamberlain apple_gmux_detect(NULL, NULL)))
46848c3dd61cSKai-Heng Feng vga_switcheroo_register_client(adev->pdev,
46858c3dd61cSKai-Heng Feng &amdgpu_switcheroo_ops, px);
4686d37a3929SOrlando Chamberlain
4687d37a3929SOrlando Chamberlain if (px)
46888c3dd61cSKai-Heng Feng vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain);
46898c3dd61cSKai-Heng Feng
46905839d27dSLijo Lazar if (adev->init_lvl->level == AMDGPU_INIT_LEVEL_MINIMAL_XGMI)
4691631af731SLijo Lazar amdgpu_xgmi_reset_on_init(adev);
4692e3c1b071Sshaoyunl
46934a74c38cSPhilip Yang amdgpu_device_check_iommu_direct_map(adev);
46944a74c38cSPhilip Yang
46952965e635SMario Limonciello adev->pm_nb.notifier_call = amdgpu_device_pm_notifier;
46962965e635SMario Limonciello r = register_pm_notifier(&adev->pm_nb);
46972965e635SMario Limonciello if (r)
46982965e635SMario Limonciello goto failed;
46992965e635SMario Limonciello
4700d38ceaf9SAlex Deucher return 0;
470183ba126aSAlex Deucher
4702970fd197SStanley.Yang release_ras_con:
470338eecbe0SChong Li if (amdgpu_sriov_vf(adev))
470438eecbe0SChong Li amdgpu_virt_release_full_gpu(adev, true);
470538eecbe0SChong Li
470638eecbe0SChong Li /* failed in exclusive mode due to timeout */
470738eecbe0SChong Li if (amdgpu_sriov_vf(adev) &&
470838eecbe0SChong Li !amdgpu_sriov_runtime(adev) &&
470938eecbe0SChong Li amdgpu_virt_mmio_blocked(adev) &&
471038eecbe0SChong Li !amdgpu_virt_wait_reset(adev)) {
471138eecbe0SChong Li dev_err(adev->dev, "VF exclusive mode timeout\n");
471238eecbe0SChong Li /* Don't send request since VF is inactive. */
471338eecbe0SChong Li adev->virt.caps &= ~AMDGPU_SRIOV_CAPS_RUNTIME;
471438eecbe0SChong Li adev->virt.ops = NULL;
471538eecbe0SChong Li r = -EAGAIN;
471638eecbe0SChong Li }
4717970fd197SStanley.Yang amdgpu_release_ras_context(adev);
4718970fd197SStanley.Yang
471983ba126aSAlex Deucher failed:
472089041940SGavin Wan amdgpu_vf_error_trans_all(adev);
47218840a387Spding
472283ba126aSAlex Deucher return r;
4723d38ceaf9SAlex Deucher }
4724d38ceaf9SAlex Deucher
amdgpu_device_unmap_mmio(struct amdgpu_device * adev)472507775fc1SAndrey Grodzovsky static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev)
472607775fc1SAndrey Grodzovsky {
472762d5f9f7SLeslie Shi
472807775fc1SAndrey Grodzovsky /* Clear all CPU mappings pointing to this device */
472907775fc1SAndrey Grodzovsky unmap_mapping_range(adev->ddev.anon_inode->i_mapping, 0, 0, 1);
473007775fc1SAndrey Grodzovsky
473107775fc1SAndrey Grodzovsky /* Unmap all mapped bars - Doorbell, registers and VRAM */
473243c064dbSShashank Sharma amdgpu_doorbell_fini(adev);
473307775fc1SAndrey Grodzovsky
473407775fc1SAndrey Grodzovsky iounmap(adev->rmmio);
473507775fc1SAndrey Grodzovsky adev->rmmio = NULL;
473607775fc1SAndrey Grodzovsky if (adev->mman.aper_base_kaddr)
473707775fc1SAndrey Grodzovsky iounmap(adev->mman.aper_base_kaddr);
473807775fc1SAndrey Grodzovsky adev->mman.aper_base_kaddr = NULL;
473907775fc1SAndrey Grodzovsky
474007775fc1SAndrey Grodzovsky /* Memory manager related */
4741a0ba1279SLijo Lazar if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
474207775fc1SAndrey Grodzovsky arch_phys_wc_del(adev->gmc.vram_mtrr);
474307775fc1SAndrey Grodzovsky arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size);
474407775fc1SAndrey Grodzovsky }
474507775fc1SAndrey Grodzovsky }
474607775fc1SAndrey Grodzovsky
4747d38ceaf9SAlex Deucher /**
4748bbe04decSIsabella Basso * amdgpu_device_fini_hw - tear down the driver
4749d38ceaf9SAlex Deucher *
4750d38ceaf9SAlex Deucher * @adev: amdgpu_device pointer
4751d38ceaf9SAlex Deucher *
4752d38ceaf9SAlex Deucher * Tear down the driver info (all asics).
4753d38ceaf9SAlex Deucher * Called at driver shutdown.
4754d38ceaf9SAlex Deucher */
amdgpu_device_fini_hw(struct amdgpu_device * adev)475572c8c97bSAndrey Grodzovsky void amdgpu_device_fini_hw(struct amdgpu_device *adev)
4756d38ceaf9SAlex Deucher {
4757aac89168SDennis Li dev_info(adev->dev, "amdgpu: finishing device.\n");
47589f875167SJesse Zhang flush_delayed_work(&adev->delayed_init_work);
4759af76ca8eSVictor Zhao
4760af76ca8eSVictor Zhao if (adev->mman.initialized)
4761af76ca8eSVictor Zhao drain_workqueue(adev->mman.bdev.wq);
4762d0d13fe8SYintian Tao adev->shutdown = true;
47639f875167SJesse Zhang
47642965e635SMario Limonciello unregister_pm_notifier(&adev->pm_nb);
47652965e635SMario Limonciello
4766752c683dSMonk Liu /* make sure IB test finished before entering exclusive mode
4767752c683dSMonk Liu * to avoid preemption on IB test
4768b8920e1eSSrinivasan Shanmugam */
4769519b8b76SBokun Zhang if (amdgpu_sriov_vf(adev)) {
4770752c683dSMonk Liu amdgpu_virt_request_full_gpu(adev, false);
4771519b8b76SBokun Zhang amdgpu_virt_fini_data_exchange(adev);
4772519b8b76SBokun Zhang }
4773752c683dSMonk Liu
4774e5b03032SMikita Lipski /* disable all interrupts */
4775e5b03032SMikita Lipski amdgpu_irq_disable_all(adev);
4776ff97cba8SMikita Lipski if (adev->mode_info.mode_config_initialized) {
47771053b9c9SFlora Cui if (!drm_drv_uses_atomic_modeset(adev_to_drm(adev)))
47784a580877SLuben Tuikov drm_helper_force_disable_all(adev_to_drm(adev));
4779ff97cba8SMikita Lipski else
47804a580877SLuben Tuikov drm_atomic_helper_shutdown(adev_to_drm(adev));
4781ff97cba8SMikita Lipski }
47828d35a259SLikun Gao amdgpu_fence_driver_hw_fini(adev);
478372c8c97bSAndrey Grodzovsky
478453e9d836SGuchun Chen if (adev->pm.sysfs_initialized)
478558e955d9SEmily Deng amdgpu_pm_sysfs_fini(adev);
478672c8c97bSAndrey Grodzovsky if (adev->ucode_sysfs_en)
478772c8c97bSAndrey Grodzovsky amdgpu_ucode_sysfs_fini(adev);
47889c05636cSVictor Skvortsov amdgpu_device_attr_sysfs_fini(adev);
47897957ec80SLijo Lazar amdgpu_fru_sysfs_fini(adev);
479072c8c97bSAndrey Grodzovsky
4791af39e6f4SLijo Lazar amdgpu_reg_state_sysfs_fini(adev);
47924ae86dc8SLijo Lazar amdgpu_xcp_cfg_sysfs_fini(adev);
4793af39e6f4SLijo Lazar
4794232d1d43SStanley.Yang /* disable ras feature must before hw fini */
4795232d1d43SStanley.Yang amdgpu_ras_pre_fini(adev);
4796232d1d43SStanley.Yang
4797b7043800SAlex Deucher amdgpu_ttm_set_buffer_funcs_status(adev, false);
4798b7043800SAlex Deucher
4799e9669fb7SAndrey Grodzovsky amdgpu_device_ip_fini_early(adev);
4800d10d0daaSAndrey Grodzovsky
4801a3848df6SYuBiao Wang amdgpu_irq_fini_hw(adev);
4802a3848df6SYuBiao Wang
4803b6fd6e0fSSurbhi Kakarya if (adev->mman.initialized)
4804894c6890SAndrey Grodzovsky ttm_device_clear_dma_mappings(&adev->mman.bdev);
4805894c6890SAndrey Grodzovsky
4806d10d0daaSAndrey Grodzovsky amdgpu_gart_dummy_page_fini(adev);
480707775fc1SAndrey Grodzovsky
480839934d3eSVitaly Prosyak if (drm_dev_is_unplugged(adev_to_drm(adev)))
480907775fc1SAndrey Grodzovsky amdgpu_device_unmap_mmio(adev);
481087172e89SLeslie Shi
481172c8c97bSAndrey Grodzovsky }
481272c8c97bSAndrey Grodzovsky
amdgpu_device_fini_sw(struct amdgpu_device * adev)481372c8c97bSAndrey Grodzovsky void amdgpu_device_fini_sw(struct amdgpu_device *adev)
481472c8c97bSAndrey Grodzovsky {
4815bd22e44aSChristian König int i, idx;
4816d37a3929SOrlando Chamberlain bool px;
481762d5f9f7SLeslie Shi
4818a5c5d8d5SLang Yu amdgpu_device_ip_fini(adev);
4819b61badd2SVitaly Prosyak amdgpu_fence_driver_sw_fini(adev);
4820b31d3063SMario Limonciello amdgpu_ucode_release(&adev->firmware.gpu_info_fw);
4821d38ceaf9SAlex Deucher adev->accel_working = false;
482268ce8b24SChristian König dma_fence_put(rcu_dereference_protected(adev->gang_submit, true));
4823bd22e44aSChristian König for (i = 0; i < MAX_XCP; ++i) {
4824bd22e44aSChristian König dma_fence_put(adev->isolation[i].spearhead);
4825bd22e44aSChristian König amdgpu_sync_free(&adev->isolation[i].active);
4826bd22e44aSChristian König amdgpu_sync_free(&adev->isolation[i].prev);
4827bd22e44aSChristian König }
482804442bf7SLijo Lazar
482904442bf7SLijo Lazar amdgpu_reset_fini(adev);
483004442bf7SLijo Lazar
4831d38ceaf9SAlex Deucher /* free i2c buses */
4832d38ceaf9SAlex Deucher amdgpu_i2c_fini(adev);
4833bfca0289SShaoyun Liu
48346e8ca38eSLijo Lazar if (adev->bios) {
4835bfca0289SShaoyun Liu if (amdgpu_emu_mode != 1)
4836d38ceaf9SAlex Deucher amdgpu_atombios_fini(adev);
4837e986e896SLijo Lazar amdgpu_bios_release(adev);
48386e8ca38eSLijo Lazar }
4839d37a3929SOrlando Chamberlain
48408a2b5139SLijo Lazar kfree(adev->fru_info);
48418a2b5139SLijo Lazar adev->fru_info = NULL;
48428a2b5139SLijo Lazar
4843b5aaa82eSFlora Cui kfree(adev->xcp_mgr);
4844b5aaa82eSFlora Cui adev->xcp_mgr = NULL;
4845b5aaa82eSFlora Cui
4846d37a3929SOrlando Chamberlain px = amdgpu_device_supports_px(adev_to_drm(adev));
4847d37a3929SOrlando Chamberlain
48487b1c6263SAlex Deucher if (px || (!dev_is_removable(&adev->pdev->dev) &&
4849d37a3929SOrlando Chamberlain apple_gmux_detect(NULL, NULL)))
4850d38ceaf9SAlex Deucher vga_switcheroo_unregister_client(adev->pdev);
4851d37a3929SOrlando Chamberlain
4852d37a3929SOrlando Chamberlain if (px)
485383ba126aSAlex Deucher vga_switcheroo_fini_domain_pm_ops(adev->dev);
4854d37a3929SOrlando Chamberlain
485538d6be81SAlex Deucher if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
4856b8779475SChristoph Hellwig vga_client_unregister(adev->pdev);
4857e9bc1bf7SYintian Tao
485862d5f9f7SLeslie Shi if (drm_dev_enter(adev_to_drm(adev), &idx)) {
485962d5f9f7SLeslie Shi
486062d5f9f7SLeslie Shi iounmap(adev->rmmio);
486162d5f9f7SLeslie Shi adev->rmmio = NULL;
486262d5f9f7SLeslie Shi drm_dev_exit(idx);
486362d5f9f7SLeslie Shi }
486462d5f9f7SLeslie Shi
4865d155bef0SArnd Bergmann if (IS_ENABLED(CONFIG_PERF_EVENTS))
48669c7c85f7SJonathan Kim amdgpu_pmu_fini(adev);
486772de33f8SAlex Deucher if (adev->mman.discovery_bin)
4868a190d1c7SXiaojie Yuan amdgpu_discovery_fini(adev);
486972c8c97bSAndrey Grodzovsky
4870cfbb6b00SAndrey Grodzovsky amdgpu_reset_put_reset_domain(adev->reset_domain);
4871cfbb6b00SAndrey Grodzovsky adev->reset_domain = NULL;
4872cfbb6b00SAndrey Grodzovsky
487372c8c97bSAndrey Grodzovsky kfree(adev->pci_state);
487472c8c97bSAndrey Grodzovsky
4875d38ceaf9SAlex Deucher }
4876d38ceaf9SAlex Deucher
487758144d28SNirmoy Das /**
487858144d28SNirmoy Das * amdgpu_device_evict_resources - evict device resources
487958144d28SNirmoy Das * @adev: amdgpu device object
488058144d28SNirmoy Das *
488158144d28SNirmoy Das * Evicts all ttm device resources(vram BOs, gart table) from the lru list
488258144d28SNirmoy Das * of the vram memory type. Mainly used for evicting device resources
488358144d28SNirmoy Das * at suspend time.
488458144d28SNirmoy Das *
488558144d28SNirmoy Das */
amdgpu_device_evict_resources(struct amdgpu_device * adev)48867863c155SMario Limonciello static int amdgpu_device_evict_resources(struct amdgpu_device *adev)
488758144d28SNirmoy Das {
48887863c155SMario Limonciello int ret;
48897863c155SMario Limonciello
4890c2ee5c2fSMario Limonciello /* No need to evict vram on APUs unless going to S4 */
4891c2ee5c2fSMario Limonciello if (!adev->in_s4 && (adev->flags & AMD_IS_APU))
48927863c155SMario Limonciello return 0;
489358144d28SNirmoy Das
48947863c155SMario Limonciello ret = amdgpu_ttm_evict_resources(adev, TTM_PL_VRAM);
48957863c155SMario Limonciello if (ret)
489658144d28SNirmoy Das DRM_WARN("evicting device resources failed\n");
48977863c155SMario Limonciello return ret;
489858144d28SNirmoy Das }
4899d38ceaf9SAlex Deucher
4900d38ceaf9SAlex Deucher /*
4901d38ceaf9SAlex Deucher * Suspend & resume.
4902d38ceaf9SAlex Deucher */
4903d38ceaf9SAlex Deucher /**
49042965e635SMario Limonciello * amdgpu_device_pm_notifier - Notification block for Suspend/Hibernate events
49052965e635SMario Limonciello * @nb: notifier block
49062965e635SMario Limonciello * @mode: suspend mode
49072965e635SMario Limonciello * @data: data
49082965e635SMario Limonciello *
49092965e635SMario Limonciello * This function is called when the system is about to suspend or hibernate.
4910*4aaffc85SAlex Deucher * It is used to set the appropriate flags so that eviction can be optimized
4911*4aaffc85SAlex Deucher * in the pm prepare callback.
49122965e635SMario Limonciello */
amdgpu_device_pm_notifier(struct notifier_block * nb,unsigned long mode,void * data)49132965e635SMario Limonciello static int amdgpu_device_pm_notifier(struct notifier_block *nb, unsigned long mode,
49142965e635SMario Limonciello void *data)
49152965e635SMario Limonciello {
49162965e635SMario Limonciello struct amdgpu_device *adev = container_of(nb, struct amdgpu_device, pm_nb);
49172965e635SMario Limonciello
49182965e635SMario Limonciello switch (mode) {
49192965e635SMario Limonciello case PM_HIBERNATION_PREPARE:
49202965e635SMario Limonciello adev->in_s4 = true;
4921*4aaffc85SAlex Deucher break;
4922*4aaffc85SAlex Deucher case PM_POST_HIBERNATION:
4923*4aaffc85SAlex Deucher adev->in_s4 = false;
49242965e635SMario Limonciello break;
49252965e635SMario Limonciello }
49262965e635SMario Limonciello
49272965e635SMario Limonciello return NOTIFY_DONE;
49282965e635SMario Limonciello }
49292965e635SMario Limonciello
49302965e635SMario Limonciello /**
49315095d541SMario Limonciello * amdgpu_device_prepare - prepare for device suspend
49325095d541SMario Limonciello *
49335095d541SMario Limonciello * @dev: drm dev pointer
49345095d541SMario Limonciello *
49355095d541SMario Limonciello * Prepare to put the hw in the suspend state (all asics).
49365095d541SMario Limonciello * Returns 0 for success or an error on failure.
49375095d541SMario Limonciello * Called at driver suspend.
49385095d541SMario Limonciello */
amdgpu_device_prepare(struct drm_device * dev)49395095d541SMario Limonciello int amdgpu_device_prepare(struct drm_device *dev)
49405095d541SMario Limonciello {
49415095d541SMario Limonciello struct amdgpu_device *adev = drm_to_adev(dev);
4942cb11ca32SMario Limonciello int i, r;
49435095d541SMario Limonciello
49445095d541SMario Limonciello if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
49455095d541SMario Limonciello return 0;
49465095d541SMario Limonciello
49475095d541SMario Limonciello /* Evict the majority of BOs before starting suspend sequence */
49485095d541SMario Limonciello r = amdgpu_device_evict_resources(adev);
49495095d541SMario Limonciello if (r)
4950d0ce1aaaSAlex Deucher return r;
49515095d541SMario Limonciello
49520355b24bSMario Limonciello flush_delayed_work(&adev->gfx.gfx_off_delay_work);
49530355b24bSMario Limonciello
4954cb11ca32SMario Limonciello for (i = 0; i < adev->num_ip_blocks; i++) {
4955cb11ca32SMario Limonciello if (!adev->ip_blocks[i].status.valid)
4956cb11ca32SMario Limonciello continue;
4957cb11ca32SMario Limonciello if (!adev->ip_blocks[i].version->funcs->prepare_suspend)
4958cb11ca32SMario Limonciello continue;
495994b2e07aSSunil Khatri r = adev->ip_blocks[i].version->funcs->prepare_suspend(&adev->ip_blocks[i]);
4960cb11ca32SMario Limonciello if (r)
4961d0ce1aaaSAlex Deucher return r;
4962cb11ca32SMario Limonciello }
4963cb11ca32SMario Limonciello
49645095d541SMario Limonciello return 0;
49655095d541SMario Limonciello }
49665095d541SMario Limonciello
49675095d541SMario Limonciello /**
4968810ddc3aSAlex Deucher * amdgpu_device_suspend - initiate device suspend
4969d38ceaf9SAlex Deucher *
497087e3f136SDarren Powell * @dev: drm dev pointer
49714cf50baeSThomas Zimmermann * @notify_clients: notify in-kernel DRM clients
4972d38ceaf9SAlex Deucher *
4973d38ceaf9SAlex Deucher * Puts the hw in the suspend state (all asics).
4974d38ceaf9SAlex Deucher * Returns 0 for success or an error on failure.
4975d38ceaf9SAlex Deucher * Called at driver suspend.
4976d38ceaf9SAlex Deucher */
amdgpu_device_suspend(struct drm_device * dev,bool notify_clients)49774cf50baeSThomas Zimmermann int amdgpu_device_suspend(struct drm_device *dev, bool notify_clients)
4978d38ceaf9SAlex Deucher {
4979a2e15b0eSAlex Deucher struct amdgpu_device *adev = drm_to_adev(dev);
4980d7274ec7SBokun Zhang int r = 0;
4981d38ceaf9SAlex Deucher
4982d38ceaf9SAlex Deucher if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
4983d38ceaf9SAlex Deucher return 0;
4984d38ceaf9SAlex Deucher
498544779b43SRex Zhu adev->in_suspend = true;
49863fa8f89dSSathishkumar S
4987d7274ec7SBokun Zhang if (amdgpu_sriov_vf(adev)) {
4988d7274ec7SBokun Zhang amdgpu_virt_fini_data_exchange(adev);
4989d7274ec7SBokun Zhang r = amdgpu_virt_request_full_gpu(adev, false);
4990d7274ec7SBokun Zhang if (r)
4991d7274ec7SBokun Zhang return r;
4992d7274ec7SBokun Zhang }
4993d7274ec7SBokun Zhang
49943fa8f89dSSathishkumar S if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D3))
49953fa8f89dSSathishkumar S DRM_WARN("smart shift update failed\n");
49963fa8f89dSSathishkumar S
49974cf50baeSThomas Zimmermann if (notify_clients)
49984cf50baeSThomas Zimmermann drm_client_dev_suspend(adev_to_drm(adev), false);
49995f818173SShirish S
5000beff74bcSAlex Deucher cancel_delayed_work_sync(&adev->delayed_init_work);
5001a5459475SRex Zhu
50025e6932feSxinhui pan amdgpu_ras_suspend(adev);
50035e6932feSxinhui pan
50042196927bSLee Jones amdgpu_device_ip_suspend_phase1(adev);
5005fe1053b7SAlex Deucher
5006c004d44eSMukul Joshi if (!adev->in_s0ix)
5007ad887af9SAlex Deucher amdgpu_amdkfd_suspend(adev, adev->in_runpm);
500894fa5660SEvan Quan
50097863c155SMario Limonciello r = amdgpu_device_evict_resources(adev);
50107863c155SMario Limonciello if (r)
50117863c155SMario Limonciello return r;
5012d38ceaf9SAlex Deucher
5013dab96d8bSAlex Deucher amdgpu_ttm_set_buffer_funcs_status(adev, false);
5014dab96d8bSAlex Deucher
50158d35a259SLikun Gao amdgpu_fence_driver_hw_fini(adev);
5016d38ceaf9SAlex Deucher
50172196927bSLee Jones amdgpu_device_ip_suspend_phase2(adev);
5018d38ceaf9SAlex Deucher
5019d7274ec7SBokun Zhang if (amdgpu_sriov_vf(adev))
5020d7274ec7SBokun Zhang amdgpu_virt_release_full_gpu(adev, false);
5021d7274ec7SBokun Zhang
50222e9b1523SPerry Yuan r = amdgpu_dpm_notify_rlc_state(adev, false);
50232e9b1523SPerry Yuan if (r)
50242e9b1523SPerry Yuan return r;
50252e9b1523SPerry Yuan
5026d38ceaf9SAlex Deucher return 0;
5027d38ceaf9SAlex Deucher }
5028d38ceaf9SAlex Deucher
5029d38ceaf9SAlex Deucher /**
5030810ddc3aSAlex Deucher * amdgpu_device_resume - initiate device resume
5031d38ceaf9SAlex Deucher *
503287e3f136SDarren Powell * @dev: drm dev pointer
50334cf50baeSThomas Zimmermann * @notify_clients: notify in-kernel DRM clients
5034d38ceaf9SAlex Deucher *
5035d38ceaf9SAlex Deucher * Bring the hw back to operating state (all asics).
5036d38ceaf9SAlex Deucher * Returns 0 for success or an error on failure.
5037d38ceaf9SAlex Deucher * Called at driver resume.
5038d38ceaf9SAlex Deucher */
amdgpu_device_resume(struct drm_device * dev,bool notify_clients)50394cf50baeSThomas Zimmermann int amdgpu_device_resume(struct drm_device *dev, bool notify_clients)
5040d38ceaf9SAlex Deucher {
50411348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(dev);
504203161a6eSHuang Rui int r = 0;
5043d38ceaf9SAlex Deucher
5044d7274ec7SBokun Zhang if (amdgpu_sriov_vf(adev)) {
5045d7274ec7SBokun Zhang r = amdgpu_virt_request_full_gpu(adev, true);
5046d7274ec7SBokun Zhang if (r)
5047d7274ec7SBokun Zhang return r;
5048d7274ec7SBokun Zhang }
5049d7274ec7SBokun Zhang
5050d38ceaf9SAlex Deucher if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
5051d38ceaf9SAlex Deucher return 0;
5052d38ceaf9SAlex Deucher
505362498733SAlex Deucher if (adev->in_s0ix)
5054bc143d8bSEvan Quan amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D0Entry);
5055628c36d7SPrike Liang
5056d38ceaf9SAlex Deucher /* post card */
505739c640c0SAlex Deucher if (amdgpu_device_need_post(adev)) {
50584d2997abSAlex Deucher r = amdgpu_device_asic_init(adev);
505974b0b157Sjimqu if (r)
5060aac89168SDennis Li dev_err(adev->dev, "amdgpu asic init failed\n");
506174b0b157Sjimqu }
5062d38ceaf9SAlex Deucher
506306ec9070SAlex Deucher r = amdgpu_device_ip_resume(adev);
5064d7274ec7SBokun Zhang
5065e6707218SRex Zhu if (r) {
5066aac89168SDennis Li dev_err(adev->dev, "amdgpu_device_ip_resume failed (%d).\n", r);
50673c22c1eaSShikang Fan goto exit;
5068e6707218SRex Zhu }
50695ceb54c6SAlex Deucher
5070c004d44eSMukul Joshi if (!adev->in_s0ix) {
5071ad887af9SAlex Deucher r = amdgpu_amdkfd_resume(adev, adev->in_runpm);
5072ba997709SYong Zhao if (r)
50733c22c1eaSShikang Fan goto exit;
50745d3a2d95SAlex Deucher }
5075756e6880SAlex Deucher
50768ed79c40STim Huang r = amdgpu_device_ip_late_init(adev);
50778ed79c40STim Huang if (r)
50788ed79c40STim Huang goto exit;
50798ed79c40STim Huang
50808ed79c40STim Huang queue_delayed_work(system_wq, &adev->delayed_init_work,
50818ed79c40STim Huang msecs_to_jiffies(AMDGPU_RESUME_MS));
50823c22c1eaSShikang Fan exit:
50833c22c1eaSShikang Fan if (amdgpu_sriov_vf(adev)) {
50843c22c1eaSShikang Fan amdgpu_virt_init_data_exchange(adev);
50853c22c1eaSShikang Fan amdgpu_virt_release_full_gpu(adev, true);
50863c22c1eaSShikang Fan }
50873c22c1eaSShikang Fan
50883c22c1eaSShikang Fan if (r)
50893c22c1eaSShikang Fan return r;
50903c22c1eaSShikang Fan
509196a5d8d4SLeo Liu /* Make sure IB tests flushed */
5092beff74bcSAlex Deucher flush_delayed_work(&adev->delayed_init_work);
509396a5d8d4SLeo Liu
50944cf50baeSThomas Zimmermann if (notify_clients)
50954cf50baeSThomas Zimmermann drm_client_dev_resume(adev_to_drm(adev), false);
5096d38ceaf9SAlex Deucher
50975e6932feSxinhui pan amdgpu_ras_resume(adev);
50985e6932feSxinhui pan
5099d09ef243SAlex Deucher if (adev->mode_info.num_crtc) {
510023a1a9e5SLyude /*
510123a1a9e5SLyude * Most of the connector probing functions try to acquire runtime pm
510223a1a9e5SLyude * refs to ensure that the GPU is powered on when connector polling is
510323a1a9e5SLyude * performed. Since we're calling this from a runtime PM callback,
510423a1a9e5SLyude * trying to acquire rpm refs will cause us to deadlock.
510523a1a9e5SLyude *
510623a1a9e5SLyude * Since we're guaranteed to be holding the rpm lock, it's safe to
510723a1a9e5SLyude * temporarily disable the rpm helpers so this doesn't deadlock us.
510823a1a9e5SLyude */
510923a1a9e5SLyude #ifdef CONFIG_PM
511023a1a9e5SLyude dev->dev->power.disable_depth++;
511123a1a9e5SLyude #endif
5112d09ef243SAlex Deucher if (!adev->dc_enabled)
511354fb2a5cSAlex Deucher drm_helper_hpd_irq_event(dev);
51144562236bSHarry Wentland else
51154562236bSHarry Wentland drm_kms_helper_hotplug_event(dev);
511623a1a9e5SLyude #ifdef CONFIG_PM
511723a1a9e5SLyude dev->dev->power.disable_depth--;
511823a1a9e5SLyude #endif
5119d09ef243SAlex Deucher }
512044779b43SRex Zhu adev->in_suspend = false;
512144779b43SRex Zhu
5122dc907c9dSJack Xiao if (adev->enable_mes)
5123dc907c9dSJack Xiao amdgpu_mes_self_test(adev);
5124dc907c9dSJack Xiao
51253fa8f89dSSathishkumar S if (amdgpu_acpi_smart_shift_update(dev, AMDGPU_SS_DEV_D0))
51263fa8f89dSSathishkumar S DRM_WARN("smart shift update failed\n");
51273fa8f89dSSathishkumar S
51284d3b9ae5SShirish S return 0;
5129d38ceaf9SAlex Deucher }
5130d38ceaf9SAlex Deucher
5131e3ecdffaSAlex Deucher /**
5132e3ecdffaSAlex Deucher * amdgpu_device_ip_check_soft_reset - did soft reset succeed
5133e3ecdffaSAlex Deucher *
5134e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
5135e3ecdffaSAlex Deucher *
5136e3ecdffaSAlex Deucher * The list of all the hardware IPs that make up the asic is walked and
5137e3ecdffaSAlex Deucher * the check_soft_reset callbacks are run. check_soft_reset determines
5138e3ecdffaSAlex Deucher * if the asic is still hung or not.
5139e3ecdffaSAlex Deucher * Returns true if any of the IPs are still in a hung state, false if not.
5140e3ecdffaSAlex Deucher */
amdgpu_device_ip_check_soft_reset(struct amdgpu_device * adev)514106ec9070SAlex Deucher static bool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev)
514263fbf42fSChunming Zhou {
514363fbf42fSChunming Zhou int i;
514463fbf42fSChunming Zhou bool asic_hang = false;
514563fbf42fSChunming Zhou
5146f993d628SMonk Liu if (amdgpu_sriov_vf(adev))
5147f993d628SMonk Liu return true;
5148f993d628SMonk Liu
51498bc04c29SAlex Deucher if (amdgpu_asic_need_full_reset(adev))
51508bc04c29SAlex Deucher return true;
51518bc04c29SAlex Deucher
515263fbf42fSChunming Zhou for (i = 0; i < adev->num_ip_blocks; i++) {
5153a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
515463fbf42fSChunming Zhou continue;
5155a1255107SAlex Deucher if (adev->ip_blocks[i].version->funcs->check_soft_reset)
5156a1255107SAlex Deucher adev->ip_blocks[i].status.hang =
51576a9456e0SSunil Khatri adev->ip_blocks[i].version->funcs->check_soft_reset(
51586a9456e0SSunil Khatri &adev->ip_blocks[i]);
5159a1255107SAlex Deucher if (adev->ip_blocks[i].status.hang) {
5160aac89168SDennis Li dev_info(adev->dev, "IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name);
516163fbf42fSChunming Zhou asic_hang = true;
516263fbf42fSChunming Zhou }
516363fbf42fSChunming Zhou }
516463fbf42fSChunming Zhou return asic_hang;
516563fbf42fSChunming Zhou }
516663fbf42fSChunming Zhou
5167e3ecdffaSAlex Deucher /**
5168e3ecdffaSAlex Deucher * amdgpu_device_ip_pre_soft_reset - prepare for soft reset
5169e3ecdffaSAlex Deucher *
5170e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
5171e3ecdffaSAlex Deucher *
5172e3ecdffaSAlex Deucher * The list of all the hardware IPs that make up the asic is walked and the
5173e3ecdffaSAlex Deucher * pre_soft_reset callbacks are run if the block is hung. pre_soft_reset
5174e3ecdffaSAlex Deucher * handles any IP specific hardware or software state changes that are
5175e3ecdffaSAlex Deucher * necessary for a soft reset to succeed.
5176e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
5177e3ecdffaSAlex Deucher */
amdgpu_device_ip_pre_soft_reset(struct amdgpu_device * adev)517806ec9070SAlex Deucher static int amdgpu_device_ip_pre_soft_reset(struct amdgpu_device *adev)
5179d31a501eSChunming Zhou {
5180d31a501eSChunming Zhou int i, r = 0;
5181d31a501eSChunming Zhou
5182d31a501eSChunming Zhou for (i = 0; i < adev->num_ip_blocks; i++) {
5183a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
5184d31a501eSChunming Zhou continue;
5185a1255107SAlex Deucher if (adev->ip_blocks[i].status.hang &&
5186a1255107SAlex Deucher adev->ip_blocks[i].version->funcs->pre_soft_reset) {
51879d5ee7ceSSunil Khatri r = adev->ip_blocks[i].version->funcs->pre_soft_reset(&adev->ip_blocks[i]);
5188d31a501eSChunming Zhou if (r)
5189d31a501eSChunming Zhou return r;
5190d31a501eSChunming Zhou }
5191d31a501eSChunming Zhou }
5192d31a501eSChunming Zhou
5193d31a501eSChunming Zhou return 0;
5194d31a501eSChunming Zhou }
5195d31a501eSChunming Zhou
5196e3ecdffaSAlex Deucher /**
5197e3ecdffaSAlex Deucher * amdgpu_device_ip_need_full_reset - check if a full asic reset is needed
5198e3ecdffaSAlex Deucher *
5199e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
5200e3ecdffaSAlex Deucher *
5201e3ecdffaSAlex Deucher * Some hardware IPs cannot be soft reset. If they are hung, a full gpu
5202e3ecdffaSAlex Deucher * reset is necessary to recover.
5203e3ecdffaSAlex Deucher * Returns true if a full asic reset is required, false if not.
5204e3ecdffaSAlex Deucher */
amdgpu_device_ip_need_full_reset(struct amdgpu_device * adev)520506ec9070SAlex Deucher static bool amdgpu_device_ip_need_full_reset(struct amdgpu_device *adev)
520635d782feSChunming Zhou {
5207da146d3bSAlex Deucher int i;
5208da146d3bSAlex Deucher
52098bc04c29SAlex Deucher if (amdgpu_asic_need_full_reset(adev))
52108bc04c29SAlex Deucher return true;
52118bc04c29SAlex Deucher
5212da146d3bSAlex Deucher for (i = 0; i < adev->num_ip_blocks; i++) {
5213a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
5214da146d3bSAlex Deucher continue;
5215a1255107SAlex Deucher if ((adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) ||
5216a1255107SAlex Deucher (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) ||
5217a1255107SAlex Deucher (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_ACP) ||
521898512bb8SKen Wang (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) ||
521998512bb8SKen Wang adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) {
5220a1255107SAlex Deucher if (adev->ip_blocks[i].status.hang) {
5221aac89168SDennis Li dev_info(adev->dev, "Some block need full reset!\n");
522235d782feSChunming Zhou return true;
522335d782feSChunming Zhou }
5224da146d3bSAlex Deucher }
5225da146d3bSAlex Deucher }
522635d782feSChunming Zhou return false;
522735d782feSChunming Zhou }
522835d782feSChunming Zhou
5229e3ecdffaSAlex Deucher /**
5230e3ecdffaSAlex Deucher * amdgpu_device_ip_soft_reset - do a soft reset
5231e3ecdffaSAlex Deucher *
5232e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
5233e3ecdffaSAlex Deucher *
5234e3ecdffaSAlex Deucher * The list of all the hardware IPs that make up the asic is walked and the
5235e3ecdffaSAlex Deucher * soft_reset callbacks are run if the block is hung. soft_reset handles any
5236e3ecdffaSAlex Deucher * IP specific hardware or software state changes that are necessary to soft
5237e3ecdffaSAlex Deucher * reset the IP.
5238e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
5239e3ecdffaSAlex Deucher */
amdgpu_device_ip_soft_reset(struct amdgpu_device * adev)524006ec9070SAlex Deucher static int amdgpu_device_ip_soft_reset(struct amdgpu_device *adev)
524135d782feSChunming Zhou {
524235d782feSChunming Zhou int i, r = 0;
524335d782feSChunming Zhou
524435d782feSChunming Zhou for (i = 0; i < adev->num_ip_blocks; i++) {
5245a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
524635d782feSChunming Zhou continue;
5247a1255107SAlex Deucher if (adev->ip_blocks[i].status.hang &&
5248a1255107SAlex Deucher adev->ip_blocks[i].version->funcs->soft_reset) {
52490ef2a1e7SSunil Khatri r = adev->ip_blocks[i].version->funcs->soft_reset(&adev->ip_blocks[i]);
525035d782feSChunming Zhou if (r)
525135d782feSChunming Zhou return r;
525235d782feSChunming Zhou }
525335d782feSChunming Zhou }
525435d782feSChunming Zhou
525535d782feSChunming Zhou return 0;
525635d782feSChunming Zhou }
525735d782feSChunming Zhou
5258e3ecdffaSAlex Deucher /**
5259e3ecdffaSAlex Deucher * amdgpu_device_ip_post_soft_reset - clean up from soft reset
5260e3ecdffaSAlex Deucher *
5261e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
5262e3ecdffaSAlex Deucher *
5263e3ecdffaSAlex Deucher * The list of all the hardware IPs that make up the asic is walked and the
5264e3ecdffaSAlex Deucher * post_soft_reset callbacks are run if the asic was hung. post_soft_reset
5265e3ecdffaSAlex Deucher * handles any IP specific hardware or software state changes that are
5266e3ecdffaSAlex Deucher * necessary after the IP has been soft reset.
5267e3ecdffaSAlex Deucher * Returns 0 on success, negative error code on failure.
5268e3ecdffaSAlex Deucher */
amdgpu_device_ip_post_soft_reset(struct amdgpu_device * adev)526906ec9070SAlex Deucher static int amdgpu_device_ip_post_soft_reset(struct amdgpu_device *adev)
527035d782feSChunming Zhou {
527135d782feSChunming Zhou int i, r = 0;
527235d782feSChunming Zhou
527335d782feSChunming Zhou for (i = 0; i < adev->num_ip_blocks; i++) {
5274a1255107SAlex Deucher if (!adev->ip_blocks[i].status.valid)
527535d782feSChunming Zhou continue;
5276a1255107SAlex Deucher if (adev->ip_blocks[i].status.hang &&
5277a1255107SAlex Deucher adev->ip_blocks[i].version->funcs->post_soft_reset)
5278e15ec812SSunil Khatri r = adev->ip_blocks[i].version->funcs->post_soft_reset(&adev->ip_blocks[i]);
527935d782feSChunming Zhou if (r)
528035d782feSChunming Zhou return r;
528135d782feSChunming Zhou }
528235d782feSChunming Zhou
528335d782feSChunming Zhou return 0;
528435d782feSChunming Zhou }
528535d782feSChunming Zhou
5286e3ecdffaSAlex Deucher /**
528706ec9070SAlex Deucher * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf
52885740682eSMonk Liu *
5289982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
529025c01191SYunxiang Li * @reset_context: amdgpu reset context pointer
52915740682eSMonk Liu *
52925740682eSMonk Liu * do VF FLR and reinitialize Asic
52933f48c681SColin Ian King * return 0 means succeeded otherwise failed
529453cdccd5SChunming Zhou */
amdgpu_device_reset_sriov(struct amdgpu_device * adev,struct amdgpu_reset_context * reset_context)5295e3ecdffaSAlex Deucher static int amdgpu_device_reset_sriov(struct amdgpu_device *adev,
529625c01191SYunxiang Li struct amdgpu_reset_context *reset_context)
52975740682eSMonk Liu {
52985740682eSMonk Liu int r;
5299a5f67c93SZhigang Luo struct amdgpu_hive_info *hive = NULL;
53005740682eSMonk Liu
530125c01191SYunxiang Li if (test_bit(AMDGPU_HOST_FLR, &reset_context->flags)) {
5302cbda2758SVignesh Chander if (!amdgpu_ras_get_fed_status(adev))
53035c0a1cddSYunxiang Li amdgpu_virt_ready_to_reset(adev);
53045c0a1cddSYunxiang Li amdgpu_virt_wait_reset(adev);
530525c01191SYunxiang Li clear_bit(AMDGPU_HOST_FLR, &reset_context->flags);
53065740682eSMonk Liu r = amdgpu_virt_request_full_gpu(adev, true);
530725c01191SYunxiang Li } else {
53085740682eSMonk Liu r = amdgpu_virt_reset_gpu(adev);
530925c01191SYunxiang Li }
53105740682eSMonk Liu if (r)
53115740682eSMonk Liu return r;
531225c01191SYunxiang Li
5313e1ee2111SLijo Lazar amdgpu_ras_clear_err_state(adev);
5314f734b213SEmily Deng amdgpu_irq_gpu_reset_resume_helper(adev);
53155740682eSMonk Liu
531683f24a8fSHorace Chen /* some sw clean up VF needs to do before recover */
531783f24a8fSHorace Chen amdgpu_virt_post_reset(adev);
531883f24a8fSHorace Chen
53195740682eSMonk Liu /* Resume IP prior to SMC */
532006ec9070SAlex Deucher r = amdgpu_device_ip_reinit_early_sriov(adev);
53215740682eSMonk Liu if (r)
53226e4aa08fSYunxiang Li return r;
53235740682eSMonk Liu
5324c9ffa427SYintian Tao amdgpu_virt_init_data_exchange(adev);
53255740682eSMonk Liu
53267a3e0bb2SRex Zhu r = amdgpu_device_fw_loading(adev);
53277a3e0bb2SRex Zhu if (r)
53287a3e0bb2SRex Zhu return r;
53297a3e0bb2SRex Zhu
53305740682eSMonk Liu /* now we are okay to resume SMC/CP/SDMA */
533106ec9070SAlex Deucher r = amdgpu_device_ip_reinit_late_sriov(adev);
53325740682eSMonk Liu if (r)
53336e4aa08fSYunxiang Li return r;
53345740682eSMonk Liu
5335a5f67c93SZhigang Luo hive = amdgpu_get_xgmi_hive(adev);
5336a5f67c93SZhigang Luo /* Update PSP FW topology after reset */
5337a5f67c93SZhigang Luo if (hive && adev->gmc.xgmi.num_physical_nodes > 1)
5338a5f67c93SZhigang Luo r = amdgpu_xgmi_update_topology(hive, adev);
5339a5f67c93SZhigang Luo if (hive)
5340a5f67c93SZhigang Luo amdgpu_put_xgmi_hive(hive);
53416e4aa08fSYunxiang Li if (r)
53426e4aa08fSYunxiang Li return r;
5343a5f67c93SZhigang Luo
53445740682eSMonk Liu r = amdgpu_ib_ring_tests(adev);
53456e4aa08fSYunxiang Li if (r)
53466e4aa08fSYunxiang Li return r;
53479c12f5cdSJack Xiao
53487181faaaSChristian König if (adev->virt.gim_feature & AMDGIM_FEATURE_GIM_FLR_VRAMLOST)
5349e3526257SMonk Liu amdgpu_inc_vram_lost(adev);
53506e4aa08fSYunxiang Li
53516e4aa08fSYunxiang Li /* need to be called during full access so we can't do it later like
53526e4aa08fSYunxiang Li * bare-metal does.
53536e4aa08fSYunxiang Li */
53546e4aa08fSYunxiang Li amdgpu_amdkfd_post_reset(adev);
5355437f3e0bSHorace Chen amdgpu_virt_release_full_gpu(adev, true);
53565740682eSMonk Liu
53574752cac3SYunxiang Li /* Aldebaran and gfx_11_0_3 support ras in SRIOV, so need resume ras during reset */
53584752cac3SYunxiang Li if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 2) ||
53594752cac3SYunxiang Li amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
53605f571c61SHawking Zhang amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4) ||
5361d7f5c13eSEllen Pan amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0) ||
53624752cac3SYunxiang Li amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 0, 3))
53634752cac3SYunxiang Li amdgpu_ras_resume(adev);
536484a2947eSVictor Skvortsov
536584a2947eSVictor Skvortsov amdgpu_virt_ras_telemetry_post_reset(adev);
536684a2947eSVictor Skvortsov
53676e4aa08fSYunxiang Li return 0;
53685740682eSMonk Liu }
53695740682eSMonk Liu
53705740682eSMonk Liu /**
53710859eb54SShikang Fan * amdgpu_device_has_job_running - check if there is any unfinished job
53729a1cddd6Sjqdeng *
5373982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
53749a1cddd6Sjqdeng *
53750859eb54SShikang Fan * check if there is any job running on the device when guest driver receives
53760859eb54SShikang Fan * FLR notification from host driver. If there are still jobs running, then
53770859eb54SShikang Fan * the guest driver will not respond the FLR reset. Instead, let the job hit
53780859eb54SShikang Fan * the timeout and guest driver then issue the reset request.
53799a1cddd6Sjqdeng */
amdgpu_device_has_job_running(struct amdgpu_device * adev)53809a1cddd6Sjqdeng bool amdgpu_device_has_job_running(struct amdgpu_device *adev)
53819a1cddd6Sjqdeng {
53829a1cddd6Sjqdeng int i;
53839a1cddd6Sjqdeng
53849a1cddd6Sjqdeng for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
53859a1cddd6Sjqdeng struct amdgpu_ring *ring = adev->rings[i];
53869a1cddd6Sjqdeng
53879749c868SMa Jun if (!amdgpu_ring_sched_ready(ring))
53889a1cddd6Sjqdeng continue;
53899a1cddd6Sjqdeng
53900859eb54SShikang Fan if (amdgpu_fence_count_emitted(ring))
53919a1cddd6Sjqdeng return true;
53929a1cddd6Sjqdeng }
53939a1cddd6Sjqdeng return false;
53949a1cddd6Sjqdeng }
53959a1cddd6Sjqdeng
53969a1cddd6Sjqdeng /**
539712938fadSChristian König * amdgpu_device_should_recover_gpu - check if we should try GPU recovery
539812938fadSChristian König *
5399982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
540012938fadSChristian König *
540112938fadSChristian König * Check amdgpu_gpu_recovery and SRIOV status to see if we should try to recover
540212938fadSChristian König * a hung GPU.
540312938fadSChristian König */
amdgpu_device_should_recover_gpu(struct amdgpu_device * adev)540412938fadSChristian König bool amdgpu_device_should_recover_gpu(struct amdgpu_device *adev)
540512938fadSChristian König {
5406d3ef9d57SChengming Gui
5407d3ef9d57SChengming Gui if (amdgpu_gpu_recovery == 0)
5408d3ef9d57SChengming Gui goto disabled;
5409d3ef9d57SChengming Gui
54101a11a65dSYiPeng Chai /* Skip soft reset check in fatal error mode */
54111a11a65dSYiPeng Chai if (!amdgpu_ras_is_poison_mode_supported(adev))
54121a11a65dSYiPeng Chai return true;
54131a11a65dSYiPeng Chai
54143ba7b418SAndrey Grodzovsky if (amdgpu_sriov_vf(adev))
54153ba7b418SAndrey Grodzovsky return true;
54163ba7b418SAndrey Grodzovsky
54173ba7b418SAndrey Grodzovsky if (amdgpu_gpu_recovery == -1) {
54183ba7b418SAndrey Grodzovsky switch (adev->asic_type) {
5419b3523c45SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_SI
5420b3523c45SAlex Deucher case CHIP_VERDE:
5421b3523c45SAlex Deucher case CHIP_TAHITI:
5422b3523c45SAlex Deucher case CHIP_PITCAIRN:
5423b3523c45SAlex Deucher case CHIP_OLAND:
5424b3523c45SAlex Deucher case CHIP_HAINAN:
5425b3523c45SAlex Deucher #endif
5426b3523c45SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_CIK
5427b3523c45SAlex Deucher case CHIP_KAVERI:
5428b3523c45SAlex Deucher case CHIP_KABINI:
5429b3523c45SAlex Deucher case CHIP_MULLINS:
5430b3523c45SAlex Deucher #endif
5431b3523c45SAlex Deucher case CHIP_CARRIZO:
5432b3523c45SAlex Deucher case CHIP_STONEY:
5433b3523c45SAlex Deucher case CHIP_CYAN_SKILLFISH:
54343ba7b418SAndrey Grodzovsky goto disabled;
5435b3523c45SAlex Deucher default:
5436b3523c45SAlex Deucher break;
54373ba7b418SAndrey Grodzovsky }
543812938fadSChristian König }
543912938fadSChristian König
544012938fadSChristian König return true;
54413ba7b418SAndrey Grodzovsky
54423ba7b418SAndrey Grodzovsky disabled:
5443aac89168SDennis Li dev_info(adev->dev, "GPU recovery disabled.\n");
54443ba7b418SAndrey Grodzovsky return false;
544512938fadSChristian König }
544612938fadSChristian König
amdgpu_device_mode1_reset(struct amdgpu_device * adev)54475c03e584SFeifei Xu int amdgpu_device_mode1_reset(struct amdgpu_device *adev)
54485c03e584SFeifei Xu {
54495c03e584SFeifei Xu u32 i;
54505c03e584SFeifei Xu int ret = 0;
54515c03e584SFeifei Xu
54526e8ca38eSLijo Lazar if (adev->bios)
54535c03e584SFeifei Xu amdgpu_atombios_scratch_regs_engine_hung(adev, true);
54545c03e584SFeifei Xu
54555c03e584SFeifei Xu dev_info(adev->dev, "GPU mode1 reset\n");
54565c03e584SFeifei Xu
5457e779af8eSLijo Lazar /* Cache the state before bus master disable. The saved config space
5458e779af8eSLijo Lazar * values are used in other cases like restore after mode-2 reset.
5459e779af8eSLijo Lazar */
5460e779af8eSLijo Lazar amdgpu_device_cache_pci_state(adev->pdev);
5461e779af8eSLijo Lazar
54625c03e584SFeifei Xu /* disable BM */
54635c03e584SFeifei Xu pci_clear_master(adev->pdev);
54645c03e584SFeifei Xu
54655c03e584SFeifei Xu if (amdgpu_dpm_is_mode1_reset_supported(adev)) {
54665c03e584SFeifei Xu dev_info(adev->dev, "GPU smu mode1 reset\n");
54675c03e584SFeifei Xu ret = amdgpu_dpm_mode1_reset(adev);
54685c03e584SFeifei Xu } else {
54695c03e584SFeifei Xu dev_info(adev->dev, "GPU psp mode1 reset\n");
54705c03e584SFeifei Xu ret = psp_gpu_reset(adev);
54715c03e584SFeifei Xu }
54725c03e584SFeifei Xu
54735c03e584SFeifei Xu if (ret)
54747d442437SHawking Zhang goto mode1_reset_failed;
54755c03e584SFeifei Xu
54765c03e584SFeifei Xu amdgpu_device_load_pci_state(adev->pdev);
54777656168aSLijo Lazar ret = amdgpu_psp_wait_for_bootloader(adev);
54787656168aSLijo Lazar if (ret)
54797d442437SHawking Zhang goto mode1_reset_failed;
54805c03e584SFeifei Xu
54815c03e584SFeifei Xu /* wait for asic to come out of reset */
54825c03e584SFeifei Xu for (i = 0; i < adev->usec_timeout; i++) {
54835c03e584SFeifei Xu u32 memsize = adev->nbio.funcs->get_memsize(adev);
54845c03e584SFeifei Xu
54855c03e584SFeifei Xu if (memsize != 0xffffffff)
54865c03e584SFeifei Xu break;
54875c03e584SFeifei Xu udelay(1);
54885c03e584SFeifei Xu }
54895c03e584SFeifei Xu
54907d442437SHawking Zhang if (i >= adev->usec_timeout) {
54917d442437SHawking Zhang ret = -ETIMEDOUT;
54927d442437SHawking Zhang goto mode1_reset_failed;
54937d442437SHawking Zhang }
54947d442437SHawking Zhang
54956e8ca38eSLijo Lazar if (adev->bios)
54965c03e584SFeifei Xu amdgpu_atombios_scratch_regs_engine_hung(adev, false);
54977656168aSLijo Lazar
54987d442437SHawking Zhang return 0;
54997d442437SHawking Zhang
55007d442437SHawking Zhang mode1_reset_failed:
55017d442437SHawking Zhang dev_err(adev->dev, "GPU mode1 reset failed\n");
55025c03e584SFeifei Xu return ret;
55035c03e584SFeifei Xu }
550426bc5340SAndrey Grodzovsky
amdgpu_device_pre_asic_reset(struct amdgpu_device * adev,struct amdgpu_reset_context * reset_context)5505e3c1b071Sshaoyunl int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev,
550604442bf7SLijo Lazar struct amdgpu_reset_context *reset_context)
55075740682eSMonk Liu {
55085c1e6fa4SHuang Rui int i, r = 0;
550904442bf7SLijo Lazar struct amdgpu_job *job = NULL;
551013d8850aSSunil Khatri struct amdgpu_device *tmp_adev = reset_context->reset_req_dev;
551104442bf7SLijo Lazar bool need_full_reset =
551204442bf7SLijo Lazar test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
551304442bf7SLijo Lazar
551404442bf7SLijo Lazar if (reset_context->reset_req_dev == adev)
551504442bf7SLijo Lazar job = reset_context->job;
551671182665SMonk Liu
5517f83cec3bSVictor Skvortsov if (amdgpu_sriov_vf(adev))
5518f83cec3bSVictor Skvortsov amdgpu_virt_pre_reset(adev);
5519b602ca5fSTiecheng Zhou
55209e225fb9SAndrey Grodzovsky amdgpu_fence_driver_isr_toggle(adev, true);
55219e225fb9SAndrey Grodzovsky
552271182665SMonk Liu /* block all schedulers and reset given job's ring */
55235740682eSMonk Liu for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
55245740682eSMonk Liu struct amdgpu_ring *ring = adev->rings[i];
55255740682eSMonk Liu
55269749c868SMa Jun if (!amdgpu_ring_sched_ready(ring))
55275740682eSMonk Liu continue;
55285740682eSMonk Liu
5529b8920e1eSSrinivasan Shanmugam /* Clear job fence from fence drv to avoid force_completion
5530b8920e1eSSrinivasan Shanmugam * leave NULL and vm flush fence in fence drv
5531b8920e1eSSrinivasan Shanmugam */
55325c1e6fa4SHuang Rui amdgpu_fence_driver_clear_job_fences(ring);
5533c530b02fSJack Zhang
55345740682eSMonk Liu /* after all hw jobs are reset, hw fence is meaningless, so force_completion */
55355740682eSMonk Liu amdgpu_fence_driver_force_completion(ring);
55365740682eSMonk Liu }
55375740682eSMonk Liu
55389e225fb9SAndrey Grodzovsky amdgpu_fence_driver_isr_toggle(adev, false);
55399e225fb9SAndrey Grodzovsky
5540ff99849bSJingwen Chen if (job && job->vm)
5541222b5f04SAndrey Grodzovsky drm_sched_increase_karma(&job->base);
5542222b5f04SAndrey Grodzovsky
554304442bf7SLijo Lazar r = amdgpu_reset_prepare_hwcontext(adev, reset_context);
5544404b277bSLijo Lazar /* If reset handler not implemented, continue; otherwise return */
5545b8920e1eSSrinivasan Shanmugam if (r == -EOPNOTSUPP)
5546404b277bSLijo Lazar r = 0;
5547404b277bSLijo Lazar else
554804442bf7SLijo Lazar return r;
554904442bf7SLijo Lazar
55501d721ed6SAndrey Grodzovsky /* Don't suspend on bare metal if we are not going to HW reset the ASIC */
555126bc5340SAndrey Grodzovsky if (!amdgpu_sriov_vf(adev)) {
555226bc5340SAndrey Grodzovsky
555326bc5340SAndrey Grodzovsky if (!need_full_reset)
555426bc5340SAndrey Grodzovsky need_full_reset = amdgpu_device_ip_need_full_reset(adev);
555526bc5340SAndrey Grodzovsky
5556360cd081SLikun Gao if (!need_full_reset && amdgpu_gpu_recovery &&
5557360cd081SLikun Gao amdgpu_device_ip_check_soft_reset(adev)) {
555826bc5340SAndrey Grodzovsky amdgpu_device_ip_pre_soft_reset(adev);
555926bc5340SAndrey Grodzovsky r = amdgpu_device_ip_soft_reset(adev);
556026bc5340SAndrey Grodzovsky amdgpu_device_ip_post_soft_reset(adev);
556126bc5340SAndrey Grodzovsky if (r || amdgpu_device_ip_check_soft_reset(adev)) {
5562aac89168SDennis Li dev_info(adev->dev, "soft reset failed, will fallback to full reset!\n");
556326bc5340SAndrey Grodzovsky need_full_reset = true;
556426bc5340SAndrey Grodzovsky }
556526bc5340SAndrey Grodzovsky }
556626bc5340SAndrey Grodzovsky
556713d8850aSSunil Khatri if (!test_bit(AMDGPU_SKIP_COREDUMP, &reset_context->flags)) {
556813d8850aSSunil Khatri dev_info(tmp_adev->dev, "Dumping IP State\n");
556913d8850aSSunil Khatri /* Trigger ip dump before we reset the asic */
557013d8850aSSunil Khatri for (i = 0; i < tmp_adev->num_ip_blocks; i++)
557113d8850aSSunil Khatri if (tmp_adev->ip_blocks[i].version->funcs->dump_ip_state)
557213d8850aSSunil Khatri tmp_adev->ip_blocks[i].version->funcs
5573fa73462dSSunil Khatri ->dump_ip_state((void *)&tmp_adev->ip_blocks[i]);
557413d8850aSSunil Khatri dev_info(tmp_adev->dev, "Dumping IP State Completed\n");
557513d8850aSSunil Khatri }
557613d8850aSSunil Khatri
557726bc5340SAndrey Grodzovsky if (need_full_reset)
557826bc5340SAndrey Grodzovsky r = amdgpu_device_ip_suspend(adev);
557904442bf7SLijo Lazar if (need_full_reset)
558004442bf7SLijo Lazar set_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
558104442bf7SLijo Lazar else
558204442bf7SLijo Lazar clear_bit(AMDGPU_NEED_FULL_RESET,
558304442bf7SLijo Lazar &reset_context->flags);
558426bc5340SAndrey Grodzovsky }
558526bc5340SAndrey Grodzovsky
558626bc5340SAndrey Grodzovsky return r;
558726bc5340SAndrey Grodzovsky }
558826bc5340SAndrey Grodzovsky
amdgpu_device_reinit_after_reset(struct amdgpu_reset_context * reset_context)55896e37ae8bSLijo Lazar int amdgpu_device_reinit_after_reset(struct amdgpu_reset_context *reset_context)
559026bc5340SAndrey Grodzovsky {
55916e37ae8bSLijo Lazar struct list_head *device_list_handle;
55926e37ae8bSLijo Lazar bool full_reset, vram_lost = false;
55936e37ae8bSLijo Lazar struct amdgpu_device *tmp_adev;
5594a86e0c0eSLijo Lazar int r, init_level;
559526bc5340SAndrey Grodzovsky
55966e37ae8bSLijo Lazar device_list_handle = reset_context->reset_device_list;
5597ea137071SAhmad Rehman
55986e37ae8bSLijo Lazar if (!device_list_handle)
55996e37ae8bSLijo Lazar return -EINVAL;
56006e37ae8bSLijo Lazar
56016e37ae8bSLijo Lazar full_reset = test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
56026e37ae8bSLijo Lazar
5603a86e0c0eSLijo Lazar /**
5604a86e0c0eSLijo Lazar * If it's reset on init, it's default init level, otherwise keep level
5605a86e0c0eSLijo Lazar * as recovery level.
5606a86e0c0eSLijo Lazar */
5607a86e0c0eSLijo Lazar if (reset_context->method == AMD_RESET_METHOD_ON_INIT)
5608a86e0c0eSLijo Lazar init_level = AMDGPU_INIT_LEVEL_DEFAULT;
5609a86e0c0eSLijo Lazar else
5610a86e0c0eSLijo Lazar init_level = AMDGPU_INIT_LEVEL_RESET_RECOVERY;
5611a86e0c0eSLijo Lazar
5612404b277bSLijo Lazar r = 0;
5613655ce9cbSshaoyunl list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
5614a86e0c0eSLijo Lazar amdgpu_set_init_level(tmp_adev, init_level);
56156e37ae8bSLijo Lazar if (full_reset) {
561626bc5340SAndrey Grodzovsky /* post card */
5617e1ee2111SLijo Lazar amdgpu_ras_clear_err_state(tmp_adev);
5618e3c1b071Sshaoyunl r = amdgpu_device_asic_init(tmp_adev);
5619e3c1b071Sshaoyunl if (r) {
5620aac89168SDennis Li dev_warn(tmp_adev->dev, "asic atom init failed!");
5621e3c1b071Sshaoyunl } else {
562226bc5340SAndrey Grodzovsky dev_info(tmp_adev->dev, "GPU reset succeeded, trying to resume\n");
56239cec53c1SJames Zhu
562426bc5340SAndrey Grodzovsky r = amdgpu_device_ip_resume_phase1(tmp_adev);
562526bc5340SAndrey Grodzovsky if (r)
562626bc5340SAndrey Grodzovsky goto out;
562726bc5340SAndrey Grodzovsky
562826bc5340SAndrey Grodzovsky vram_lost = amdgpu_device_check_vram_lost(tmp_adev);
5629a7691785SAndré Almeida
5630ea137071SAhmad Rehman if (!test_bit(AMDGPU_SKIP_COREDUMP, &reset_context->flags))
56316122f5c7STrigger Huang amdgpu_coredump(tmp_adev, false, vram_lost, reset_context->job);
5632a7691785SAndré Almeida
563326bc5340SAndrey Grodzovsky if (vram_lost) {
563477e7f829SAndrey Grodzovsky DRM_INFO("VRAM is lost due to GPU reset!\n");
5635e3526257SMonk Liu amdgpu_inc_vram_lost(tmp_adev);
563626bc5340SAndrey Grodzovsky }
563726bc5340SAndrey Grodzovsky
563826bc5340SAndrey Grodzovsky r = amdgpu_device_fw_loading(tmp_adev);
563926bc5340SAndrey Grodzovsky if (r)
564026bc5340SAndrey Grodzovsky return r;
564126bc5340SAndrey Grodzovsky
5642c45e38f2SLijo Lazar r = amdgpu_xcp_restore_partition_mode(
5643c45e38f2SLijo Lazar tmp_adev->xcp_mgr);
5644c45e38f2SLijo Lazar if (r)
5645c45e38f2SLijo Lazar goto out;
5646c45e38f2SLijo Lazar
564726bc5340SAndrey Grodzovsky r = amdgpu_device_ip_resume_phase2(tmp_adev);
564826bc5340SAndrey Grodzovsky if (r)
564926bc5340SAndrey Grodzovsky goto out;
565026bc5340SAndrey Grodzovsky
5651b7043800SAlex Deucher if (tmp_adev->mman.buffer_funcs_ring->sched.ready)
5652b7043800SAlex Deucher amdgpu_ttm_set_buffer_funcs_status(tmp_adev, true);
5653b7043800SAlex Deucher
565473dae652SAlex Deucher r = amdgpu_device_ip_resume_phase3(tmp_adev);
565573dae652SAlex Deucher if (r)
565673dae652SAlex Deucher goto out;
565773dae652SAlex Deucher
565826bc5340SAndrey Grodzovsky if (vram_lost)
565926bc5340SAndrey Grodzovsky amdgpu_device_fill_reset_magic(tmp_adev);
566026bc5340SAndrey Grodzovsky
5661fdafb359SEvan Quan /*
5662fdafb359SEvan Quan * Add this ASIC as tracked as reset was already
5663fdafb359SEvan Quan * complete successfully.
5664fdafb359SEvan Quan */
5665fdafb359SEvan Quan amdgpu_register_gpu_instance(tmp_adev);
5666fdafb359SEvan Quan
566704442bf7SLijo Lazar if (!reset_context->hive &&
566804442bf7SLijo Lazar tmp_adev->gmc.xgmi.num_physical_nodes > 1)
5669e3c1b071Sshaoyunl amdgpu_xgmi_add_device(tmp_adev);
5670e3c1b071Sshaoyunl
56717c04ca50Sxinhui pan r = amdgpu_device_ip_late_init(tmp_adev);
56727c04ca50Sxinhui pan if (r)
56737c04ca50Sxinhui pan goto out;
56747c04ca50Sxinhui pan
56754cf50baeSThomas Zimmermann drm_client_dev_resume(adev_to_drm(tmp_adev), false);
5676565d1941SEvan Quan
5677e8fbaf03SGuchun Chen /*
5678e8fbaf03SGuchun Chen * The GPU enters bad state once faulty pages
5679e8fbaf03SGuchun Chen * by ECC has reached the threshold, and ras
5680e8fbaf03SGuchun Chen * recovery is scheduled next. So add one check
5681e8fbaf03SGuchun Chen * here to break recovery if it indeed exceeds
5682e8fbaf03SGuchun Chen * bad page threshold, and remind user to
5683e8fbaf03SGuchun Chen * retire this GPU or setting one bigger
5684e8fbaf03SGuchun Chen * bad_page_threshold value to fix this once
5685e8fbaf03SGuchun Chen * probing driver again.
5686e8fbaf03SGuchun Chen */
5687dd3e2962STao Zhou if (!amdgpu_ras_is_rma(tmp_adev)) {
5688e79a04d5Sxinhui pan /* must succeed. */
5689511fdbc3Sxinhui pan amdgpu_ras_resume(tmp_adev);
5690e8fbaf03SGuchun Chen } else {
5691e8fbaf03SGuchun Chen r = -EINVAL;
5692e8fbaf03SGuchun Chen goto out;
5693e8fbaf03SGuchun Chen }
5694e79a04d5Sxinhui pan
569526bc5340SAndrey Grodzovsky /* Update PSP FW topology after reset */
569604442bf7SLijo Lazar if (reset_context->hive &&
569704442bf7SLijo Lazar tmp_adev->gmc.xgmi.num_physical_nodes > 1)
569804442bf7SLijo Lazar r = amdgpu_xgmi_update_topology(
569904442bf7SLijo Lazar reset_context->hive, tmp_adev);
570026bc5340SAndrey Grodzovsky }
570126bc5340SAndrey Grodzovsky }
570226bc5340SAndrey Grodzovsky
570326bc5340SAndrey Grodzovsky out:
570426bc5340SAndrey Grodzovsky if (!r) {
5705a86e0c0eSLijo Lazar /* IP init is complete now, set level as default */
5706a86e0c0eSLijo Lazar amdgpu_set_init_level(tmp_adev,
5707a86e0c0eSLijo Lazar AMDGPU_INIT_LEVEL_DEFAULT);
570826bc5340SAndrey Grodzovsky amdgpu_irq_gpu_reset_resume_helper(tmp_adev);
570926bc5340SAndrey Grodzovsky r = amdgpu_ib_ring_tests(tmp_adev);
571026bc5340SAndrey Grodzovsky if (r) {
571126bc5340SAndrey Grodzovsky dev_err(tmp_adev->dev, "ib ring test failed (%d).\n", r);
571226bc5340SAndrey Grodzovsky r = -EAGAIN;
571326bc5340SAndrey Grodzovsky goto end;
571426bc5340SAndrey Grodzovsky }
571526bc5340SAndrey Grodzovsky }
571626bc5340SAndrey Grodzovsky
57177181faaaSChristian König if (r)
571826bc5340SAndrey Grodzovsky tmp_adev->asic_reset_res = r;
571926bc5340SAndrey Grodzovsky }
572026bc5340SAndrey Grodzovsky
572126bc5340SAndrey Grodzovsky end:
57226e37ae8bSLijo Lazar return r;
57236e37ae8bSLijo Lazar }
57246e37ae8bSLijo Lazar
amdgpu_do_asic_reset(struct list_head * device_list_handle,struct amdgpu_reset_context * reset_context)57256e37ae8bSLijo Lazar int amdgpu_do_asic_reset(struct list_head *device_list_handle,
57266e37ae8bSLijo Lazar struct amdgpu_reset_context *reset_context)
57276e37ae8bSLijo Lazar {
57286e37ae8bSLijo Lazar struct amdgpu_device *tmp_adev = NULL;
57296e37ae8bSLijo Lazar bool need_full_reset, skip_hw_reset;
57306e37ae8bSLijo Lazar int r = 0;
57316e37ae8bSLijo Lazar
57326e37ae8bSLijo Lazar /* Try reset handler method first */
57336e37ae8bSLijo Lazar tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device,
57346e37ae8bSLijo Lazar reset_list);
57356e37ae8bSLijo Lazar
57366e37ae8bSLijo Lazar reset_context->reset_device_list = device_list_handle;
57376e37ae8bSLijo Lazar r = amdgpu_reset_perform_reset(tmp_adev, reset_context);
57386e37ae8bSLijo Lazar /* If reset handler not implemented, continue; otherwise return */
57396e37ae8bSLijo Lazar if (r == -EOPNOTSUPP)
57406e37ae8bSLijo Lazar r = 0;
57416e37ae8bSLijo Lazar else
57426e37ae8bSLijo Lazar return r;
57436e37ae8bSLijo Lazar
57446e37ae8bSLijo Lazar /* Reset handler not implemented, use the default method */
57456e37ae8bSLijo Lazar need_full_reset =
57466e37ae8bSLijo Lazar test_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
57476e37ae8bSLijo Lazar skip_hw_reset = test_bit(AMDGPU_SKIP_HW_RESET, &reset_context->flags);
57486e37ae8bSLijo Lazar
57496e37ae8bSLijo Lazar /*
57506e37ae8bSLijo Lazar * ASIC reset has to be done on all XGMI hive nodes ASAP
57516e37ae8bSLijo Lazar * to allow proper links negotiation in FW (within 1 sec)
57526e37ae8bSLijo Lazar */
57536e37ae8bSLijo Lazar if (!skip_hw_reset && need_full_reset) {
57546e37ae8bSLijo Lazar list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
57556e37ae8bSLijo Lazar /* For XGMI run all resets in parallel to speed up the process */
57566e37ae8bSLijo Lazar if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
57576e37ae8bSLijo Lazar if (!queue_work(system_unbound_wq,
57586e37ae8bSLijo Lazar &tmp_adev->xgmi_reset_work))
57596e37ae8bSLijo Lazar r = -EALREADY;
57606e37ae8bSLijo Lazar } else
57616e37ae8bSLijo Lazar r = amdgpu_asic_reset(tmp_adev);
57626e37ae8bSLijo Lazar
57636e37ae8bSLijo Lazar if (r) {
57646e37ae8bSLijo Lazar dev_err(tmp_adev->dev,
57656e37ae8bSLijo Lazar "ASIC reset failed with error, %d for drm dev, %s",
57666e37ae8bSLijo Lazar r, adev_to_drm(tmp_adev)->unique);
57676e37ae8bSLijo Lazar goto out;
57686e37ae8bSLijo Lazar }
57696e37ae8bSLijo Lazar }
57706e37ae8bSLijo Lazar
57716e37ae8bSLijo Lazar /* For XGMI wait for all resets to complete before proceed */
57726e37ae8bSLijo Lazar if (!r) {
57736e37ae8bSLijo Lazar list_for_each_entry(tmp_adev, device_list_handle,
57746e37ae8bSLijo Lazar reset_list) {
57756e37ae8bSLijo Lazar if (tmp_adev->gmc.xgmi.num_physical_nodes > 1) {
57766e37ae8bSLijo Lazar flush_work(&tmp_adev->xgmi_reset_work);
57776e37ae8bSLijo Lazar r = tmp_adev->asic_reset_res;
57786e37ae8bSLijo Lazar if (r)
57796e37ae8bSLijo Lazar break;
57806e37ae8bSLijo Lazar }
57816e37ae8bSLijo Lazar }
57826e37ae8bSLijo Lazar }
57836e37ae8bSLijo Lazar }
57846e37ae8bSLijo Lazar
57856e37ae8bSLijo Lazar if (!r && amdgpu_ras_intr_triggered()) {
57866e37ae8bSLijo Lazar list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
57876e37ae8bSLijo Lazar amdgpu_ras_reset_error_count(tmp_adev,
57886e37ae8bSLijo Lazar AMDGPU_RAS_BLOCK__MMHUB);
57896e37ae8bSLijo Lazar }
57906e37ae8bSLijo Lazar
57916e37ae8bSLijo Lazar amdgpu_ras_intr_cleared();
57926e37ae8bSLijo Lazar }
57936e37ae8bSLijo Lazar
57946e37ae8bSLijo Lazar r = amdgpu_device_reinit_after_reset(reset_context);
57956e37ae8bSLijo Lazar if (r == -EAGAIN)
579604442bf7SLijo Lazar set_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
579704442bf7SLijo Lazar else
579804442bf7SLijo Lazar clear_bit(AMDGPU_NEED_FULL_RESET, &reset_context->flags);
57996e37ae8bSLijo Lazar
58006e37ae8bSLijo Lazar out:
580126bc5340SAndrey Grodzovsky return r;
580226bc5340SAndrey Grodzovsky }
580326bc5340SAndrey Grodzovsky
amdgpu_device_set_mp1_state(struct amdgpu_device * adev)5804e923be99SAndrey Grodzovsky static void amdgpu_device_set_mp1_state(struct amdgpu_device *adev)
580526bc5340SAndrey Grodzovsky {
58061d721ed6SAndrey Grodzovsky
5807a3a09142SAlex Deucher switch (amdgpu_asic_reset_method(adev)) {
5808a3a09142SAlex Deucher case AMD_RESET_METHOD_MODE1:
5809a3a09142SAlex Deucher adev->mp1_state = PP_MP1_STATE_SHUTDOWN;
5810a3a09142SAlex Deucher break;
5811a3a09142SAlex Deucher case AMD_RESET_METHOD_MODE2:
5812a3a09142SAlex Deucher adev->mp1_state = PP_MP1_STATE_RESET;
5813a3a09142SAlex Deucher break;
5814a3a09142SAlex Deucher default:
5815a3a09142SAlex Deucher adev->mp1_state = PP_MP1_STATE_NONE;
5816a3a09142SAlex Deucher break;
5817a3a09142SAlex Deucher }
581826bc5340SAndrey Grodzovsky }
581926bc5340SAndrey Grodzovsky
amdgpu_device_unset_mp1_state(struct amdgpu_device * adev)5820e923be99SAndrey Grodzovsky static void amdgpu_device_unset_mp1_state(struct amdgpu_device *adev)
582126bc5340SAndrey Grodzovsky {
582289041940SGavin Wan amdgpu_vf_error_trans_all(adev);
5823a3a09142SAlex Deucher adev->mp1_state = PP_MP1_STATE_NONE;
582491fb309dSHorace Chen }
582591fb309dSHorace Chen
amdgpu_device_resume_display_audio(struct amdgpu_device * adev)58263f12acc8SEvan Quan static void amdgpu_device_resume_display_audio(struct amdgpu_device *adev)
58273f12acc8SEvan Quan {
58283f12acc8SEvan Quan struct pci_dev *p = NULL;
58293f12acc8SEvan Quan
58303f12acc8SEvan Quan p = pci_get_domain_bus_and_slot(pci_domain_nr(adev->pdev->bus),
58313f12acc8SEvan Quan adev->pdev->bus->number, 1);
58323f12acc8SEvan Quan if (p) {
58333f12acc8SEvan Quan pm_runtime_enable(&(p->dev));
58343f12acc8SEvan Quan pm_runtime_resume(&(p->dev));
58353f12acc8SEvan Quan }
5836b85e285eSYang Yingliang
5837b85e285eSYang Yingliang pci_dev_put(p);
58383f12acc8SEvan Quan }
58393f12acc8SEvan Quan
amdgpu_device_suspend_display_audio(struct amdgpu_device * adev)58403f12acc8SEvan Quan static int amdgpu_device_suspend_display_audio(struct amdgpu_device *adev)
58413f12acc8SEvan Quan {
58423f12acc8SEvan Quan enum amd_reset_method reset_method;
58433f12acc8SEvan Quan struct pci_dev *p = NULL;
58443f12acc8SEvan Quan u64 expires;
58453f12acc8SEvan Quan
58463f12acc8SEvan Quan /*
58473f12acc8SEvan Quan * For now, only BACO and mode1 reset are confirmed
58483f12acc8SEvan Quan * to suffer the audio issue without proper suspended.
58493f12acc8SEvan Quan */
58503f12acc8SEvan Quan reset_method = amdgpu_asic_reset_method(adev);
58513f12acc8SEvan Quan if ((reset_method != AMD_RESET_METHOD_BACO) &&
58523f12acc8SEvan Quan (reset_method != AMD_RESET_METHOD_MODE1))
58533f12acc8SEvan Quan return -EINVAL;
58543f12acc8SEvan Quan
58553f12acc8SEvan Quan p = pci_get_domain_bus_and_slot(pci_domain_nr(adev->pdev->bus),
58563f12acc8SEvan Quan adev->pdev->bus->number, 1);
58573f12acc8SEvan Quan if (!p)
58583f12acc8SEvan Quan return -ENODEV;
58593f12acc8SEvan Quan
58603f12acc8SEvan Quan expires = pm_runtime_autosuspend_expiration(&(p->dev));
58613f12acc8SEvan Quan if (!expires)
58623f12acc8SEvan Quan /*
58633f12acc8SEvan Quan * If we cannot get the audio device autosuspend delay,
58643f12acc8SEvan Quan * a fixed 4S interval will be used. Considering 3S is
58653f12acc8SEvan Quan * the audio controller default autosuspend delay setting.
58663f12acc8SEvan Quan * 4S used here is guaranteed to cover that.
58673f12acc8SEvan Quan */
586854b7feb9SNathan Chancellor expires = ktime_get_mono_fast_ns() + NSEC_PER_SEC * 4ULL;
58693f12acc8SEvan Quan
58703f12acc8SEvan Quan while (!pm_runtime_status_suspended(&(p->dev))) {
58713f12acc8SEvan Quan if (!pm_runtime_suspend(&(p->dev)))
58723f12acc8SEvan Quan break;
58733f12acc8SEvan Quan
58743f12acc8SEvan Quan if (expires < ktime_get_mono_fast_ns()) {
58753f12acc8SEvan Quan dev_warn(adev->dev, "failed to suspend display audio\n");
5876b85e285eSYang Yingliang pci_dev_put(p);
58773f12acc8SEvan Quan /* TODO: abort the succeeding gpu reset? */
58783f12acc8SEvan Quan return -ETIMEDOUT;
58793f12acc8SEvan Quan }
58803f12acc8SEvan Quan }
58813f12acc8SEvan Quan
58823f12acc8SEvan Quan pm_runtime_disable(&(p->dev));
58833f12acc8SEvan Quan
5884b85e285eSYang Yingliang pci_dev_put(p);
58853f12acc8SEvan Quan return 0;
58863f12acc8SEvan Quan }
58873f12acc8SEvan Quan
amdgpu_device_stop_pending_resets(struct amdgpu_device * adev)5888d193b12bSKent Russell static inline void amdgpu_device_stop_pending_resets(struct amdgpu_device *adev)
5889247c7b0dSAndrey Grodzovsky {
5890247c7b0dSAndrey Grodzovsky struct amdgpu_ras *con = amdgpu_ras_get_context(adev);
5891247c7b0dSAndrey Grodzovsky
5892247c7b0dSAndrey Grodzovsky #if defined(CONFIG_DEBUG_FS)
5893247c7b0dSAndrey Grodzovsky if (!amdgpu_sriov_vf(adev))
5894247c7b0dSAndrey Grodzovsky cancel_work(&adev->reset_work);
5895247c7b0dSAndrey Grodzovsky #endif
5896247c7b0dSAndrey Grodzovsky
5897247c7b0dSAndrey Grodzovsky if (adev->kfd.dev)
5898247c7b0dSAndrey Grodzovsky cancel_work(&adev->kfd.reset_work);
5899247c7b0dSAndrey Grodzovsky
5900247c7b0dSAndrey Grodzovsky if (amdgpu_sriov_vf(adev))
5901247c7b0dSAndrey Grodzovsky cancel_work(&adev->virt.flr_work);
5902247c7b0dSAndrey Grodzovsky
5903247c7b0dSAndrey Grodzovsky if (con && adev->ras_enabled)
5904247c7b0dSAndrey Grodzovsky cancel_work(&con->recovery_work);
5905247c7b0dSAndrey Grodzovsky
5906247c7b0dSAndrey Grodzovsky }
5907247c7b0dSAndrey Grodzovsky
amdgpu_device_health_check(struct list_head * device_list_handle)5908dfe9c3cdSLijo Lazar static int amdgpu_device_health_check(struct list_head *device_list_handle)
5909dfe9c3cdSLijo Lazar {
5910dfe9c3cdSLijo Lazar struct amdgpu_device *tmp_adev;
5911dfe9c3cdSLijo Lazar int ret = 0;
5912dfe9c3cdSLijo Lazar u32 status;
5913dfe9c3cdSLijo Lazar
5914dfe9c3cdSLijo Lazar list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
5915dfe9c3cdSLijo Lazar pci_read_config_dword(tmp_adev->pdev, PCI_COMMAND, &status);
5916dfe9c3cdSLijo Lazar if (PCI_POSSIBLE_ERROR(status)) {
5917dfe9c3cdSLijo Lazar dev_err(tmp_adev->dev, "device lost from bus!");
5918dfe9c3cdSLijo Lazar ret = -ENODEV;
5919dfe9c3cdSLijo Lazar }
5920dfe9c3cdSLijo Lazar }
5921dfe9c3cdSLijo Lazar
5922dfe9c3cdSLijo Lazar return ret;
5923dfe9c3cdSLijo Lazar }
5924dfe9c3cdSLijo Lazar
592526bc5340SAndrey Grodzovsky /**
59266e9c65f7SAlex Deucher * amdgpu_device_gpu_recover - reset the asic and recover scheduler
592726bc5340SAndrey Grodzovsky *
5928982a820bSMauro Carvalho Chehab * @adev: amdgpu_device pointer
592926bc5340SAndrey Grodzovsky * @job: which job trigger hang
593080bd2de1SLee Jones * @reset_context: amdgpu reset context pointer
593126bc5340SAndrey Grodzovsky *
593226bc5340SAndrey Grodzovsky * Attempt to reset the GPU if it has hung (all asics).
593326bc5340SAndrey Grodzovsky * Attempt to do soft-reset or full-reset and reinitialize Asic
593426bc5340SAndrey Grodzovsky * Returns 0 for success or an error on failure.
593526bc5340SAndrey Grodzovsky */
593626bc5340SAndrey Grodzovsky
amdgpu_device_gpu_recover(struct amdgpu_device * adev,struct amdgpu_job * job,struct amdgpu_reset_context * reset_context)5937cf727044SAndrey Grodzovsky int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
5938f1549c09SLikun Gao struct amdgpu_job *job,
5939f1549c09SLikun Gao struct amdgpu_reset_context *reset_context)
594026bc5340SAndrey Grodzovsky {
594126bc5340SAndrey Grodzovsky struct list_head device_list, *device_list_handle = NULL;
59427dd8c205SEvan Quan bool job_signaled = false;
59431d721ed6SAndrey Grodzovsky struct amdgpu_hive_info *hive = NULL;
59441d721ed6SAndrey Grodzovsky struct amdgpu_device *tmp_adev = NULL;
59451d721ed6SAndrey Grodzovsky int i, r = 0;
5946bb5c7235SWenhui Sheng bool need_emergency_restart = false;
59473f12acc8SEvan Quan bool audio_suspended = false;
59486e4aa08fSYunxiang Li int retry_limit = AMDGPU_MAX_RETRY_LIMIT;
594926bc5340SAndrey Grodzovsky
59506e3cd2a9SMauro Carvalho Chehab /*
5951e1ee2111SLijo Lazar * If it reaches here because of hang/timeout and a RAS error is
5952e1ee2111SLijo Lazar * detected at the same time, let RAS recovery take care of it.
5953e1ee2111SLijo Lazar */
5954e1ee2111SLijo Lazar if (amdgpu_ras_is_err_state(adev, AMDGPU_RAS_BLOCK__ANY) &&
5955fccb446fSLijo Lazar !amdgpu_sriov_vf(adev) &&
5956e1ee2111SLijo Lazar reset_context->src != AMDGPU_RESET_SRC_RAS) {
5957e1ee2111SLijo Lazar dev_dbg(adev->dev,
5958e1ee2111SLijo Lazar "Gpu recovery from source: %d yielding to RAS error recovery handling",
5959e1ee2111SLijo Lazar reset_context->src);
5960e1ee2111SLijo Lazar return 0;
5961e1ee2111SLijo Lazar }
5962e1ee2111SLijo Lazar /*
5963bb5c7235SWenhui Sheng * Special case: RAS triggered and full reset isn't supported
5964bb5c7235SWenhui Sheng */
5965bb5c7235SWenhui Sheng need_emergency_restart = amdgpu_ras_need_emergency_restart(adev);
5966bb5c7235SWenhui Sheng
5967d5ea093eSAndrey Grodzovsky /*
5968d5ea093eSAndrey Grodzovsky * Flush RAM to disk so that after reboot
5969d5ea093eSAndrey Grodzovsky * the user can read log and see why the system rebooted.
5970d5ea093eSAndrey Grodzovsky */
597180285ae1SStanley.Yang if (need_emergency_restart && amdgpu_ras_get_context(adev) &&
597280285ae1SStanley.Yang amdgpu_ras_get_context(adev)->reboot) {
5973d5ea093eSAndrey Grodzovsky DRM_WARN("Emergency reboot.");
5974d5ea093eSAndrey Grodzovsky
5975d5ea093eSAndrey Grodzovsky ksys_sync_helper();
5976d5ea093eSAndrey Grodzovsky emergency_restart();
5977d5ea093eSAndrey Grodzovsky }
5978d5ea093eSAndrey Grodzovsky
5979b823821fSLe Ma dev_info(adev->dev, "GPU %s begin!\n",
5980bb5c7235SWenhui Sheng need_emergency_restart ? "jobs stop":"reset");
598126bc5340SAndrey Grodzovsky
5982175ac6ecSZhigang Luo if (!amdgpu_sriov_vf(adev))
5983d95e8e97SDennis Li hive = amdgpu_get_xgmi_hive(adev);
5984681260dfSAndrey Grodzovsky if (hive)
598553b3f8f4SDennis Li mutex_lock(&hive->hive_lock);
598626bc5340SAndrey Grodzovsky
5987f1549c09SLikun Gao reset_context->job = job;
5988f1549c09SLikun Gao reset_context->hive = hive;
598926bc5340SAndrey Grodzovsky /*
59909e94d22cSEvan Quan * Build list of devices to reset.
59919e94d22cSEvan Quan * In case we are in XGMI hive mode, resort the device list
59929e94d22cSEvan Quan * to put adev in the 1st position.
599326bc5340SAndrey Grodzovsky */
59949e94d22cSEvan Quan INIT_LIST_HEAD(&device_list);
5995b1f7810bSJesse Zhang if (!amdgpu_sriov_vf(adev) && (adev->gmc.xgmi.num_physical_nodes > 1) && hive) {
599683d29a5fSYiPeng Chai list_for_each_entry(tmp_adev, &hive->device_list, gmc.xgmi.head) {
5997655ce9cbSshaoyunl list_add_tail(&tmp_adev->reset_list, &device_list);
5998087a3e13SChristian König if (adev->shutdown)
599983d29a5fSYiPeng Chai tmp_adev->shutdown = true;
600083d29a5fSYiPeng Chai }
6001655ce9cbSshaoyunl if (!list_is_first(&adev->reset_list, &device_list))
6002655ce9cbSshaoyunl list_rotate_to_front(&adev->reset_list, &device_list);
6003655ce9cbSshaoyunl device_list_handle = &device_list;
600426bc5340SAndrey Grodzovsky } else {
6005655ce9cbSshaoyunl list_add_tail(&adev->reset_list, &device_list);
600626bc5340SAndrey Grodzovsky device_list_handle = &device_list;
600726bc5340SAndrey Grodzovsky }
600826bc5340SAndrey Grodzovsky
6009dfe9c3cdSLijo Lazar if (!amdgpu_sriov_vf(adev)) {
6010dfe9c3cdSLijo Lazar r = amdgpu_device_health_check(device_list_handle);
6011dfe9c3cdSLijo Lazar if (r)
6012dfe9c3cdSLijo Lazar goto end_reset;
6013dfe9c3cdSLijo Lazar }
6014dfe9c3cdSLijo Lazar
6015e923be99SAndrey Grodzovsky /* We need to lock reset domain only once both for XGMI and single device */
6016e923be99SAndrey Grodzovsky tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device,
6017e923be99SAndrey Grodzovsky reset_list);
60183675c2f2SAndrey Grodzovsky amdgpu_device_lock_reset_domain(tmp_adev->reset_domain);
6019e923be99SAndrey Grodzovsky
602012ffa55dSAndrey Grodzovsky /* block all schedulers and reset given job's ring */
6021655ce9cbSshaoyunl list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
6022f287a3c5SAndrey Grodzovsky
6023e923be99SAndrey Grodzovsky amdgpu_device_set_mp1_state(tmp_adev);
6024f287a3c5SAndrey Grodzovsky
60253f12acc8SEvan Quan /*
60263f12acc8SEvan Quan * Try to put the audio codec into suspend state
60273f12acc8SEvan Quan * before gpu reset started.
60283f12acc8SEvan Quan *
60293f12acc8SEvan Quan * Due to the power domain of the graphics device
60303f12acc8SEvan Quan * is shared with AZ power domain. Without this,
60313f12acc8SEvan Quan * we may change the audio hardware from behind
60323f12acc8SEvan Quan * the audio driver's back. That will trigger
60333f12acc8SEvan Quan * some audio codec errors.
60343f12acc8SEvan Quan */
60353f12acc8SEvan Quan if (!amdgpu_device_suspend_display_audio(tmp_adev))
60363f12acc8SEvan Quan audio_suspended = true;
60373f12acc8SEvan Quan
60389e94d22cSEvan Quan amdgpu_ras_set_error_query_ready(tmp_adev, false);
60399e94d22cSEvan Quan
604052fb44cfSEvan Quan cancel_delayed_work_sync(&tmp_adev->delayed_init_work);
604152fb44cfSEvan Quan
6042dbe2c4c8SEric Huang amdgpu_amdkfd_pre_reset(tmp_adev, reset_context);
60439e94d22cSEvan Quan
6044fdafb359SEvan Quan /*
6045a567db80SRandy Dunlap * Mark these ASICs to be reset as untracked first
6046fdafb359SEvan Quan * And add them back after reset completed
6047fdafb359SEvan Quan */
6048fdafb359SEvan Quan amdgpu_unregister_gpu_instance(tmp_adev);
6049fdafb359SEvan Quan
60504cf50baeSThomas Zimmermann drm_client_dev_suspend(adev_to_drm(tmp_adev), false);
6051565d1941SEvan Quan
6052f1c1314bSxinhui pan /* disable ras on ALL IPs */
6053bb5c7235SWenhui Sheng if (!need_emergency_restart &&
6054b823821fSLe Ma amdgpu_device_ip_need_full_reset(tmp_adev))
6055f1c1314bSxinhui pan amdgpu_ras_suspend(tmp_adev);
6056f1c1314bSxinhui pan
60571d721ed6SAndrey Grodzovsky for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
60581d721ed6SAndrey Grodzovsky struct amdgpu_ring *ring = tmp_adev->rings[i];
60591d721ed6SAndrey Grodzovsky
60609749c868SMa Jun if (!amdgpu_ring_sched_ready(ring))
60611d721ed6SAndrey Grodzovsky continue;
60621d721ed6SAndrey Grodzovsky
60630b2d2c2eSAndrey Grodzovsky drm_sched_stop(&ring->sched, job ? &job->base : NULL);
60647c6e68c7SAndrey Grodzovsky
6065bb5c7235SWenhui Sheng if (need_emergency_restart)
60667c6e68c7SAndrey Grodzovsky amdgpu_job_stop_all_jobs_on_sched(&ring->sched);
60671d721ed6SAndrey Grodzovsky }
60688f8c80f4SJingwen Chen atomic_inc(&tmp_adev->gpu_reset_counter);
60691d721ed6SAndrey Grodzovsky }
60701d721ed6SAndrey Grodzovsky
6071bb5c7235SWenhui Sheng if (need_emergency_restart)
60727c6e68c7SAndrey Grodzovsky goto skip_sched_resume;
60737c6e68c7SAndrey Grodzovsky
60741d721ed6SAndrey Grodzovsky /*
60751d721ed6SAndrey Grodzovsky * Must check guilty signal here since after this point all old
60761d721ed6SAndrey Grodzovsky * HW fences are force signaled.
60771d721ed6SAndrey Grodzovsky *
60781d721ed6SAndrey Grodzovsky * job->base holds a reference to parent fence
60791d721ed6SAndrey Grodzovsky */
6080f6a3f660SAndrey Grodzovsky if (job && dma_fence_is_signaled(&job->hw_fence)) {
60811d721ed6SAndrey Grodzovsky job_signaled = true;
60821d721ed6SAndrey Grodzovsky dev_info(adev->dev, "Guilty job already signaled, skipping HW reset");
60831d721ed6SAndrey Grodzovsky goto skip_hw_reset;
60841d721ed6SAndrey Grodzovsky }
60851d721ed6SAndrey Grodzovsky
608626bc5340SAndrey Grodzovsky retry: /* Rest of adevs pre asic reset from XGMI hive. */
6087655ce9cbSshaoyunl list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
6088f1549c09SLikun Gao r = amdgpu_device_pre_asic_reset(tmp_adev, reset_context);
608926bc5340SAndrey Grodzovsky /*TODO Should we stop ?*/
609026bc5340SAndrey Grodzovsky if (r) {
6091aac89168SDennis Li dev_err(tmp_adev->dev, "GPU pre asic reset failed with err, %d for drm dev, %s ",
60924a580877SLuben Tuikov r, adev_to_drm(tmp_adev)->unique);
609326bc5340SAndrey Grodzovsky tmp_adev->asic_reset_res = r;
609426bc5340SAndrey Grodzovsky }
609526bc5340SAndrey Grodzovsky }
609626bc5340SAndrey Grodzovsky
609726bc5340SAndrey Grodzovsky /* Actual ASIC resets if needed.*/
60984f30d920Sshaoyunl /* Host driver will handle XGMI hive reset for SRIOV */
609926bc5340SAndrey Grodzovsky if (amdgpu_sriov_vf(adev)) {
6100cbda2758SVignesh Chander if (amdgpu_ras_get_fed_status(adev) || amdgpu_virt_rcvd_ras_interrupt(adev)) {
6101cbda2758SVignesh Chander dev_dbg(adev->dev, "Detected RAS error, wait for FLR completion\n");
6102cbda2758SVignesh Chander amdgpu_ras_set_fed(adev, true);
6103cbda2758SVignesh Chander set_bit(AMDGPU_HOST_FLR, &reset_context->flags);
6104cbda2758SVignesh Chander }
6105cbda2758SVignesh Chander
610625c01191SYunxiang Li r = amdgpu_device_reset_sriov(adev, reset_context);
61076e4aa08fSYunxiang Li if (AMDGPU_RETRY_SRIOV_RESET(r) && (retry_limit--) > 0) {
61086e4aa08fSYunxiang Li amdgpu_virt_release_full_gpu(adev, true);
61096e4aa08fSYunxiang Li goto retry;
61106e4aa08fSYunxiang Li }
611126bc5340SAndrey Grodzovsky if (r)
611226bc5340SAndrey Grodzovsky adev->asic_reset_res = r;
611326bc5340SAndrey Grodzovsky } else {
6114f1549c09SLikun Gao r = amdgpu_do_asic_reset(device_list_handle, reset_context);
6115b98a1648SVictor Zhao if (r && r == -EAGAIN)
611626bc5340SAndrey Grodzovsky goto retry;
6117dac6b808SVictor Zhao }
611826bc5340SAndrey Grodzovsky
6119f4322b9fSYunxiang Li list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
6120f4322b9fSYunxiang Li /*
6121f4322b9fSYunxiang Li * Drop any pending non scheduler resets queued before reset is done.
6122f4322b9fSYunxiang Li * Any reset scheduled after this point would be valid. Scheduler resets
6123f4322b9fSYunxiang Li * were already dropped during drm_sched_stop and no new ones can come
6124f4322b9fSYunxiang Li * in before drm_sched_start.
6125f4322b9fSYunxiang Li */
6126f4322b9fSYunxiang Li amdgpu_device_stop_pending_resets(tmp_adev);
6127f4322b9fSYunxiang Li }
6128f4322b9fSYunxiang Li
61291d721ed6SAndrey Grodzovsky skip_hw_reset:
61301d721ed6SAndrey Grodzovsky
613126bc5340SAndrey Grodzovsky /* Post ASIC reset for all devs .*/
6132655ce9cbSshaoyunl list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
61337c6e68c7SAndrey Grodzovsky
61341d721ed6SAndrey Grodzovsky for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
61351d721ed6SAndrey Grodzovsky struct amdgpu_ring *ring = tmp_adev->rings[i];
61361d721ed6SAndrey Grodzovsky
61379749c868SMa Jun if (!amdgpu_ring_sched_ready(ring))
61381d721ed6SAndrey Grodzovsky continue;
61391d721ed6SAndrey Grodzovsky
6140b2ef8087SChristian König drm_sched_start(&ring->sched, 0);
61411d721ed6SAndrey Grodzovsky }
61421d721ed6SAndrey Grodzovsky
6143b8920e1eSSrinivasan Shanmugam if (!drm_drv_uses_atomic_modeset(adev_to_drm(tmp_adev)) && !job_signaled)
61444a580877SLuben Tuikov drm_helper_resume_force_mode(adev_to_drm(tmp_adev));
61451d721ed6SAndrey Grodzovsky
61467258fa31SSurbhi Kakarya if (tmp_adev->asic_reset_res)
61477258fa31SSurbhi Kakarya r = tmp_adev->asic_reset_res;
61487258fa31SSurbhi Kakarya
61491d721ed6SAndrey Grodzovsky tmp_adev->asic_reset_res = 0;
615026bc5340SAndrey Grodzovsky
615126bc5340SAndrey Grodzovsky if (r) {
6152b3a3c9a6STao Zhou /* bad news, how to tell it to userspace ?
6153b3a3c9a6STao Zhou * for ras error, we should report GPU bad status instead of
6154b3a3c9a6STao Zhou * reset failure
6155b3a3c9a6STao Zhou */
6156b3a3c9a6STao Zhou if (reset_context->src != AMDGPU_RESET_SRC_RAS ||
6157b3a3c9a6STao Zhou !amdgpu_ras_eeprom_check_err_threshold(tmp_adev))
6158b3a3c9a6STao Zhou dev_info(tmp_adev->dev, "GPU reset(%d) failed\n",
6159b3a3c9a6STao Zhou atomic_read(&tmp_adev->gpu_reset_counter));
616026bc5340SAndrey Grodzovsky amdgpu_vf_error_put(tmp_adev, AMDGIM_ERROR_VF_GPU_RESET_FAIL, 0, r);
616126bc5340SAndrey Grodzovsky } else {
616212ffa55dSAndrey Grodzovsky dev_info(tmp_adev->dev, "GPU reset(%d) succeeded!\n", atomic_read(&tmp_adev->gpu_reset_counter));
61633fa8f89dSSathishkumar S if (amdgpu_acpi_smart_shift_update(adev_to_drm(tmp_adev), AMDGPU_SS_DEV_D0))
61643fa8f89dSSathishkumar S DRM_WARN("smart shift update failed\n");
616526bc5340SAndrey Grodzovsky }
61667c6e68c7SAndrey Grodzovsky }
616726bc5340SAndrey Grodzovsky
61687c6e68c7SAndrey Grodzovsky skip_sched_resume:
6169655ce9cbSshaoyunl list_for_each_entry(tmp_adev, device_list_handle, reset_list) {
6170428890a3Sshaoyunl /* unlock kfd: SRIOV would do it separately */
6171c004d44eSMukul Joshi if (!need_emergency_restart && !amdgpu_sriov_vf(tmp_adev))
61727c6e68c7SAndrey Grodzovsky amdgpu_amdkfd_post_reset(tmp_adev);
61738e2712e7Sshaoyunl
61748e2712e7Sshaoyunl /* kfd_post_reset will do nothing if kfd device is not initialized,
61758e2712e7Sshaoyunl * need to bring up kfd here if it's not be initialized before
61768e2712e7Sshaoyunl */
61778e2712e7Sshaoyunl if (!adev->kfd.init_complete)
61788e2712e7Sshaoyunl amdgpu_amdkfd_device_init(adev);
61798e2712e7Sshaoyunl
61803f12acc8SEvan Quan if (audio_suspended)
61813f12acc8SEvan Quan amdgpu_device_resume_display_audio(tmp_adev);
6182e923be99SAndrey Grodzovsky
6183e923be99SAndrey Grodzovsky amdgpu_device_unset_mp1_state(tmp_adev);
6184d293470eSYiPeng Chai
6185d293470eSYiPeng Chai amdgpu_ras_set_error_query_ready(tmp_adev, true);
618626bc5340SAndrey Grodzovsky }
618726bc5340SAndrey Grodzovsky
6188e923be99SAndrey Grodzovsky tmp_adev = list_first_entry(device_list_handle, struct amdgpu_device,
6189e923be99SAndrey Grodzovsky reset_list);
6190e923be99SAndrey Grodzovsky amdgpu_device_unlock_reset_domain(tmp_adev->reset_domain);
6191e923be99SAndrey Grodzovsky
6192dfe9c3cdSLijo Lazar end_reset:
61939e94d22cSEvan Quan if (hive) {
61949e94d22cSEvan Quan mutex_unlock(&hive->hive_lock);
6195d95e8e97SDennis Li amdgpu_put_xgmi_hive(hive);
61969e94d22cSEvan Quan }
619726bc5340SAndrey Grodzovsky
6198f287a3c5SAndrey Grodzovsky if (r)
619926bc5340SAndrey Grodzovsky dev_info(adev->dev, "GPU reset end with ret = %d\n", r);
6200ab9a0b1fSAndrey Grodzovsky
6201ab9a0b1fSAndrey Grodzovsky atomic_set(&adev->reset_domain->reset_res, r);
62026fe52b63SAndré Almeida
62036fe52b63SAndré Almeida if (!r)
62046fe52b63SAndré Almeida drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE);
62056fe52b63SAndré Almeida
6206d38ceaf9SAlex Deucher return r;
6207d38ceaf9SAlex Deucher }
6208d38ceaf9SAlex Deucher
6209e3ecdffaSAlex Deucher /**
6210466a7d11SMario Limonciello * amdgpu_device_partner_bandwidth - find the bandwidth of appropriate partner
6211466a7d11SMario Limonciello *
6212466a7d11SMario Limonciello * @adev: amdgpu_device pointer
6213466a7d11SMario Limonciello * @speed: pointer to the speed of the link
6214466a7d11SMario Limonciello * @width: pointer to the width of the link
6215466a7d11SMario Limonciello *
6216466a7d11SMario Limonciello * Evaluate the hierarchy to find the speed and bandwidth capabilities of the
6217466a7d11SMario Limonciello * first physical partner to an AMD dGPU.
6218466a7d11SMario Limonciello * This will exclude any virtual switches and links.
6219466a7d11SMario Limonciello */
amdgpu_device_partner_bandwidth(struct amdgpu_device * adev,enum pci_bus_speed * speed,enum pcie_link_width * width)6220466a7d11SMario Limonciello static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev,
6221466a7d11SMario Limonciello enum pci_bus_speed *speed,
6222466a7d11SMario Limonciello enum pcie_link_width *width)
6223466a7d11SMario Limonciello {
6224466a7d11SMario Limonciello struct pci_dev *parent = adev->pdev;
6225466a7d11SMario Limonciello
6226466a7d11SMario Limonciello if (!speed || !width)
6227466a7d11SMario Limonciello return;
6228466a7d11SMario Limonciello
6229466a7d11SMario Limonciello *speed = PCI_SPEED_UNKNOWN;
6230466a7d11SMario Limonciello *width = PCIE_LNK_WIDTH_UNKNOWN;
6231466a7d11SMario Limonciello
623287dfeb47SAlex Deucher if (amdgpu_device_pcie_dynamic_switching_supported(adev)) {
6233466a7d11SMario Limonciello while ((parent = pci_upstream_bridge(parent))) {
6234466a7d11SMario Limonciello /* skip upstream/downstream switches internal to dGPU*/
6235466a7d11SMario Limonciello if (parent->vendor == PCI_VENDOR_ID_ATI)
6236466a7d11SMario Limonciello continue;
6237466a7d11SMario Limonciello *speed = pcie_get_speed_cap(parent);
6238466a7d11SMario Limonciello *width = pcie_get_width_cap(parent);
6239466a7d11SMario Limonciello break;
6240466a7d11SMario Limonciello }
624187dfeb47SAlex Deucher } else {
624287dfeb47SAlex Deucher /* use the current speeds rather than max if switching is not supported */
624387dfeb47SAlex Deucher pcie_bandwidth_available(adev->pdev, NULL, speed, width);
624487dfeb47SAlex Deucher }
6245466a7d11SMario Limonciello }
6246466a7d11SMario Limonciello
6247466a7d11SMario Limonciello /**
6248757e8b95SAlex Deucher * amdgpu_device_gpu_bandwidth - find the bandwidth of the GPU
6249757e8b95SAlex Deucher *
6250757e8b95SAlex Deucher * @adev: amdgpu_device pointer
6251757e8b95SAlex Deucher * @speed: pointer to the speed of the link
6252757e8b95SAlex Deucher * @width: pointer to the width of the link
6253757e8b95SAlex Deucher *
6254757e8b95SAlex Deucher * Evaluate the hierarchy to find the speed and bandwidth capabilities of the
6255757e8b95SAlex Deucher * AMD dGPU which may be a virtual upstream bridge.
6256757e8b95SAlex Deucher */
amdgpu_device_gpu_bandwidth(struct amdgpu_device * adev,enum pci_bus_speed * speed,enum pcie_link_width * width)6257757e8b95SAlex Deucher static void amdgpu_device_gpu_bandwidth(struct amdgpu_device *adev,
6258757e8b95SAlex Deucher enum pci_bus_speed *speed,
6259757e8b95SAlex Deucher enum pcie_link_width *width)
6260757e8b95SAlex Deucher {
6261757e8b95SAlex Deucher struct pci_dev *parent = adev->pdev;
6262757e8b95SAlex Deucher
6263757e8b95SAlex Deucher if (!speed || !width)
6264757e8b95SAlex Deucher return;
6265757e8b95SAlex Deucher
6266757e8b95SAlex Deucher parent = pci_upstream_bridge(parent);
6267757e8b95SAlex Deucher if (parent && parent->vendor == PCI_VENDOR_ID_ATI) {
6268757e8b95SAlex Deucher /* use the upstream/downstream switches internal to dGPU */
6269757e8b95SAlex Deucher *speed = pcie_get_speed_cap(parent);
6270757e8b95SAlex Deucher *width = pcie_get_width_cap(parent);
6271757e8b95SAlex Deucher while ((parent = pci_upstream_bridge(parent))) {
6272757e8b95SAlex Deucher if (parent->vendor == PCI_VENDOR_ID_ATI) {
6273757e8b95SAlex Deucher /* use the upstream/downstream switches internal to dGPU */
6274757e8b95SAlex Deucher *speed = pcie_get_speed_cap(parent);
6275757e8b95SAlex Deucher *width = pcie_get_width_cap(parent);
6276757e8b95SAlex Deucher }
6277757e8b95SAlex Deucher }
6278757e8b95SAlex Deucher } else {
6279757e8b95SAlex Deucher /* use the device itself */
6280dc915275SSrinivasan Shanmugam *speed = pcie_get_speed_cap(adev->pdev);
6281dc915275SSrinivasan Shanmugam *width = pcie_get_width_cap(adev->pdev);
6282757e8b95SAlex Deucher }
6283757e8b95SAlex Deucher }
6284757e8b95SAlex Deucher
6285757e8b95SAlex Deucher /**
6286e3ecdffaSAlex Deucher * amdgpu_device_get_pcie_info - fence pcie info about the PCIE slot
6287e3ecdffaSAlex Deucher *
6288e3ecdffaSAlex Deucher * @adev: amdgpu_device pointer
6289e3ecdffaSAlex Deucher *
6290a567db80SRandy Dunlap * Fetches and stores in the driver the PCIE capabilities (gen speed
6291e3ecdffaSAlex Deucher * and lanes) of the slot the device is in. Handles APUs and
6292e3ecdffaSAlex Deucher * virtualized environments where PCIE config space may not be available.
6293e3ecdffaSAlex Deucher */
amdgpu_device_get_pcie_info(struct amdgpu_device * adev)62945494d864SAlex Deucher static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev)
6295d0dd7f0cSAlex Deucher {
6296c5313457SHarish Kasiviswanathan enum pci_bus_speed speed_cap, platform_speed_cap;
6297757e8b95SAlex Deucher enum pcie_link_width platform_link_width, link_width;
6298d0dd7f0cSAlex Deucher
6299cd474ba0SAlex Deucher if (amdgpu_pcie_gen_cap)
6300cd474ba0SAlex Deucher adev->pm.pcie_gen_mask = amdgpu_pcie_gen_cap;
6301d0dd7f0cSAlex Deucher
6302cd474ba0SAlex Deucher if (amdgpu_pcie_lane_cap)
6303cd474ba0SAlex Deucher adev->pm.pcie_mlw_mask = amdgpu_pcie_lane_cap;
6304d0dd7f0cSAlex Deucher
6305cd474ba0SAlex Deucher /* covers APUs as well */
630604e85958STong Liu01 if (pci_is_root_bus(adev->pdev->bus) && !amdgpu_passthrough(adev)) {
6307cd474ba0SAlex Deucher if (adev->pm.pcie_gen_mask == 0)
6308cd474ba0SAlex Deucher adev->pm.pcie_gen_mask = AMDGPU_DEFAULT_PCIE_GEN_MASK;
6309cd474ba0SAlex Deucher if (adev->pm.pcie_mlw_mask == 0)
6310cd474ba0SAlex Deucher adev->pm.pcie_mlw_mask = AMDGPU_DEFAULT_PCIE_MLW_MASK;
6311d0dd7f0cSAlex Deucher return;
6312cd474ba0SAlex Deucher }
6313d0dd7f0cSAlex Deucher
6314c5313457SHarish Kasiviswanathan if (adev->pm.pcie_gen_mask && adev->pm.pcie_mlw_mask)
6315c5313457SHarish Kasiviswanathan return;
6316c5313457SHarish Kasiviswanathan
6317466a7d11SMario Limonciello amdgpu_device_partner_bandwidth(adev, &platform_speed_cap,
6318466a7d11SMario Limonciello &platform_link_width);
6319757e8b95SAlex Deucher amdgpu_device_gpu_bandwidth(adev, &speed_cap, &link_width);
6320c5313457SHarish Kasiviswanathan
6321cd474ba0SAlex Deucher if (adev->pm.pcie_gen_mask == 0) {
63225d9a6330SAlex Deucher /* asic caps */
63235d9a6330SAlex Deucher if (speed_cap == PCI_SPEED_UNKNOWN) {
63245d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
6325d0dd7f0cSAlex Deucher CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
6326d0dd7f0cSAlex Deucher CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3);
6327cd474ba0SAlex Deucher } else {
63282b3a1f51SFeifei Xu if (speed_cap == PCIE_SPEED_32_0GT)
63292b3a1f51SFeifei Xu adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63302b3a1f51SFeifei Xu CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
63312b3a1f51SFeifei Xu CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 |
63322b3a1f51SFeifei Xu CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN4 |
63332b3a1f51SFeifei Xu CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN5);
63342b3a1f51SFeifei Xu else if (speed_cap == PCIE_SPEED_16_0GT)
63355d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63365d9a6330SAlex Deucher CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
63375d9a6330SAlex Deucher CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3 |
63385d9a6330SAlex Deucher CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN4);
63395d9a6330SAlex Deucher else if (speed_cap == PCIE_SPEED_8_0GT)
63405d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63415d9a6330SAlex Deucher CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2 |
63425d9a6330SAlex Deucher CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN3);
63435d9a6330SAlex Deucher else if (speed_cap == PCIE_SPEED_5_0GT)
63445d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= (CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63455d9a6330SAlex Deucher CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN2);
63465d9a6330SAlex Deucher else
63475d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= CAIL_ASIC_PCIE_LINK_SPEED_SUPPORT_GEN1;
63485d9a6330SAlex Deucher }
63495d9a6330SAlex Deucher /* platform caps */
6350c5313457SHarish Kasiviswanathan if (platform_speed_cap == PCI_SPEED_UNKNOWN) {
63515d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63525d9a6330SAlex Deucher CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2);
63535d9a6330SAlex Deucher } else {
63542b3a1f51SFeifei Xu if (platform_speed_cap == PCIE_SPEED_32_0GT)
63552b3a1f51SFeifei Xu adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63562b3a1f51SFeifei Xu CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
63572b3a1f51SFeifei Xu CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 |
63582b3a1f51SFeifei Xu CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4 |
63592b3a1f51SFeifei Xu CAIL_PCIE_LINK_SPEED_SUPPORT_GEN5);
63602b3a1f51SFeifei Xu else if (platform_speed_cap == PCIE_SPEED_16_0GT)
63615d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63625d9a6330SAlex Deucher CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
63635d9a6330SAlex Deucher CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3 |
63645d9a6330SAlex Deucher CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4);
6365c5313457SHarish Kasiviswanathan else if (platform_speed_cap == PCIE_SPEED_8_0GT)
63665d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63675d9a6330SAlex Deucher CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
63685d9a6330SAlex Deucher CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3);
6369c5313457SHarish Kasiviswanathan else if (platform_speed_cap == PCIE_SPEED_5_0GT)
63705d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1 |
63715d9a6330SAlex Deucher CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2);
63725d9a6330SAlex Deucher else
63735d9a6330SAlex Deucher adev->pm.pcie_gen_mask |= CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1;
63745d9a6330SAlex Deucher
6375d0dd7f0cSAlex Deucher }
6376cd474ba0SAlex Deucher }
6377cd474ba0SAlex Deucher if (adev->pm.pcie_mlw_mask == 0) {
6378757e8b95SAlex Deucher /* asic caps */
6379757e8b95SAlex Deucher if (link_width == PCIE_LNK_WIDTH_UNKNOWN) {
6380757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= AMDGPU_DEFAULT_ASIC_PCIE_MLW_MASK;
6381757e8b95SAlex Deucher } else {
6382757e8b95SAlex Deucher switch (link_width) {
6383757e8b95SAlex Deucher case PCIE_LNK_X32:
6384757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X32 |
6385757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X16 |
6386757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X12 |
6387757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X8 |
6388757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X4 |
6389757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X2 |
6390757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X1);
6391757e8b95SAlex Deucher break;
6392757e8b95SAlex Deucher case PCIE_LNK_X16:
6393757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X16 |
6394757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X12 |
6395757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X8 |
6396757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X4 |
6397757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X2 |
6398757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X1);
6399757e8b95SAlex Deucher break;
6400757e8b95SAlex Deucher case PCIE_LNK_X12:
6401757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X12 |
6402757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X8 |
6403757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X4 |
6404757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X2 |
6405757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X1);
6406757e8b95SAlex Deucher break;
6407757e8b95SAlex Deucher case PCIE_LNK_X8:
6408757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X8 |
6409757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X4 |
6410757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X2 |
6411757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X1);
6412757e8b95SAlex Deucher break;
6413757e8b95SAlex Deucher case PCIE_LNK_X4:
6414757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X4 |
6415757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X2 |
6416757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X1);
6417757e8b95SAlex Deucher break;
6418757e8b95SAlex Deucher case PCIE_LNK_X2:
6419757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X2 |
6420757e8b95SAlex Deucher CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X1);
6421757e8b95SAlex Deucher break;
6422757e8b95SAlex Deucher case PCIE_LNK_X1:
6423757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= CAIL_ASIC_PCIE_LINK_WIDTH_SUPPORT_X1;
6424757e8b95SAlex Deucher break;
6425757e8b95SAlex Deucher default:
6426757e8b95SAlex Deucher break;
6427757e8b95SAlex Deucher }
6428757e8b95SAlex Deucher }
6429757e8b95SAlex Deucher /* platform caps */
6430c5313457SHarish Kasiviswanathan if (platform_link_width == PCIE_LNK_WIDTH_UNKNOWN) {
64315d9a6330SAlex Deucher adev->pm.pcie_mlw_mask |= AMDGPU_DEFAULT_PCIE_MLW_MASK;
64325d9a6330SAlex Deucher } else {
6433c5313457SHarish Kasiviswanathan switch (platform_link_width) {
64345d9a6330SAlex Deucher case PCIE_LNK_X32:
6435757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_PCIE_LINK_WIDTH_SUPPORT_X32 |
6436d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
6437d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
6438d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
6439d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
6440d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
6441d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
6442d0dd7f0cSAlex Deucher break;
64435d9a6330SAlex Deucher case PCIE_LNK_X16:
6444757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_PCIE_LINK_WIDTH_SUPPORT_X16 |
6445d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
6446d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
6447d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
6448d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
6449d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
6450d0dd7f0cSAlex Deucher break;
64515d9a6330SAlex Deucher case PCIE_LNK_X12:
6452757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_PCIE_LINK_WIDTH_SUPPORT_X12 |
6453d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
6454d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
6455d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
6456d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
6457d0dd7f0cSAlex Deucher break;
64585d9a6330SAlex Deucher case PCIE_LNK_X8:
6459757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_PCIE_LINK_WIDTH_SUPPORT_X8 |
6460d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
6461d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
6462d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
6463d0dd7f0cSAlex Deucher break;
64645d9a6330SAlex Deucher case PCIE_LNK_X4:
6465757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_PCIE_LINK_WIDTH_SUPPORT_X4 |
6466d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
6467d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
6468d0dd7f0cSAlex Deucher break;
64695d9a6330SAlex Deucher case PCIE_LNK_X2:
6470757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= (CAIL_PCIE_LINK_WIDTH_SUPPORT_X2 |
6471d0dd7f0cSAlex Deucher CAIL_PCIE_LINK_WIDTH_SUPPORT_X1);
6472d0dd7f0cSAlex Deucher break;
64735d9a6330SAlex Deucher case PCIE_LNK_X1:
6474757e8b95SAlex Deucher adev->pm.pcie_mlw_mask |= CAIL_PCIE_LINK_WIDTH_SUPPORT_X1;
6475d0dd7f0cSAlex Deucher break;
6476d0dd7f0cSAlex Deucher default:
6477d0dd7f0cSAlex Deucher break;
6478d0dd7f0cSAlex Deucher }
6479cd474ba0SAlex Deucher }
6480d0dd7f0cSAlex Deucher }
6481d0dd7f0cSAlex Deucher }
6482d38ceaf9SAlex Deucher
648308a2fd23SRamesh Errabolu /**
648408a2fd23SRamesh Errabolu * amdgpu_device_is_peer_accessible - Check peer access through PCIe BAR
648508a2fd23SRamesh Errabolu *
648608a2fd23SRamesh Errabolu * @adev: amdgpu_device pointer
648708a2fd23SRamesh Errabolu * @peer_adev: amdgpu_device pointer for peer device trying to access @adev
648808a2fd23SRamesh Errabolu *
648908a2fd23SRamesh Errabolu * Return true if @peer_adev can access (DMA) @adev through the PCIe
649008a2fd23SRamesh Errabolu * BAR, i.e. @adev is "large BAR" and the BAR matches the DMA mask of
649108a2fd23SRamesh Errabolu * @peer_adev.
649208a2fd23SRamesh Errabolu */
amdgpu_device_is_peer_accessible(struct amdgpu_device * adev,struct amdgpu_device * peer_adev)649308a2fd23SRamesh Errabolu bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev,
649408a2fd23SRamesh Errabolu struct amdgpu_device *peer_adev)
649508a2fd23SRamesh Errabolu {
649608a2fd23SRamesh Errabolu #ifdef CONFIG_HSA_AMD_P2P
6497bb66ecbfSLijo Lazar bool p2p_access =
6498bb66ecbfSLijo Lazar !adev->gmc.xgmi.connected_to_cpu &&
6499bb66ecbfSLijo Lazar !(pci_p2pdma_distance(adev->pdev, peer_adev->dev, false) < 0);
65008e29057eSRamesh Errabolu if (!p2p_access)
65018e29057eSRamesh Errabolu dev_info(adev->dev, "PCIe P2P access from peer device %s is not supported by the chipset\n",
65028e29057eSRamesh Errabolu pci_name(peer_adev->pdev));
650308a2fd23SRamesh Errabolu
650475f0efbcSRahul Jain bool is_large_bar = adev->gmc.visible_vram_size &&
650575f0efbcSRahul Jain adev->gmc.real_vram_size == adev->gmc.visible_vram_size;
650675f0efbcSRahul Jain bool p2p_addressable = amdgpu_device_check_iommu_remap(peer_adev);
650775f0efbcSRahul Jain
650875f0efbcSRahul Jain if (!p2p_addressable) {
650975f0efbcSRahul Jain uint64_t address_mask = peer_adev->dev->dma_mask ?
651075f0efbcSRahul Jain ~*peer_adev->dev->dma_mask : ~((1ULL << 32) - 1);
651175f0efbcSRahul Jain resource_size_t aper_limit =
651275f0efbcSRahul Jain adev->gmc.aper_base + adev->gmc.aper_size - 1;
651375f0efbcSRahul Jain
651475f0efbcSRahul Jain p2p_addressable = !(adev->gmc.aper_base & address_mask ||
651575f0efbcSRahul Jain aper_limit & address_mask);
651675f0efbcSRahul Jain }
651728b0ef92SBob Zhou return pcie_p2p && is_large_bar && p2p_access && p2p_addressable;
651808a2fd23SRamesh Errabolu #else
651908a2fd23SRamesh Errabolu return false;
652008a2fd23SRamesh Errabolu #endif
652108a2fd23SRamesh Errabolu }
652208a2fd23SRamesh Errabolu
amdgpu_device_baco_enter(struct drm_device * dev)6523361dbd01SAlex Deucher int amdgpu_device_baco_enter(struct drm_device *dev)
6524361dbd01SAlex Deucher {
65251348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(dev);
65267a22677bSLe Ma struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
6527361dbd01SAlex Deucher
65286ab68650SGuchun Chen if (!amdgpu_device_supports_baco(dev))
6529361dbd01SAlex Deucher return -ENOTSUPP;
6530361dbd01SAlex Deucher
65318ab0d6f0SLuben Tuikov if (ras && adev->ras_enabled &&
6532acdae216SLuben Tuikov adev->nbio.funcs->enable_doorbell_interrupt)
65337a22677bSLe Ma adev->nbio.funcs->enable_doorbell_interrupt(adev, false);
65347a22677bSLe Ma
65359530273eSEvan Quan return amdgpu_dpm_baco_enter(adev);
6536361dbd01SAlex Deucher }
6537361dbd01SAlex Deucher
amdgpu_device_baco_exit(struct drm_device * dev)6538361dbd01SAlex Deucher int amdgpu_device_baco_exit(struct drm_device *dev)
6539361dbd01SAlex Deucher {
65401348969aSLuben Tuikov struct amdgpu_device *adev = drm_to_adev(dev);
65417a22677bSLe Ma struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
65429530273eSEvan Quan int ret = 0;
6543361dbd01SAlex Deucher
65446ab68650SGuchun Chen if (!amdgpu_device_supports_baco(dev))
6545361dbd01SAlex Deucher return -ENOTSUPP;
6546361dbd01SAlex Deucher
65479530273eSEvan Quan ret = amdgpu_dpm_baco_exit(adev);
6548361dbd01SAlex Deucher if (ret)
6549361dbd01SAlex Deucher return ret;
6550361dbd01SAlex Deucher
65518ab0d6f0SLuben Tuikov if (ras && adev->ras_enabled &&
6552acdae216SLuben Tuikov adev->nbio.funcs->enable_doorbell_interrupt)
65537a22677bSLe Ma adev->nbio.funcs->enable_doorbell_interrupt(adev, true);
6554361dbd01SAlex Deucher
65550cdb3f97SFriedrich Vock if (amdgpu_passthrough(adev) && adev->nbio.funcs &&
65561bece222SChengzhe Liu adev->nbio.funcs->clear_doorbell_interrupt)
65571bece222SChengzhe Liu adev->nbio.funcs->clear_doorbell_interrupt(adev);
65581bece222SChengzhe Liu
6559361dbd01SAlex Deucher return 0;
6560361dbd01SAlex Deucher }
6561c9a6b82fSAndrey Grodzovsky
6562c9a6b82fSAndrey Grodzovsky /**
6563c9a6b82fSAndrey Grodzovsky * amdgpu_pci_error_detected - Called when a PCI error is detected.
6564c9a6b82fSAndrey Grodzovsky * @pdev: PCI device struct
6565c9a6b82fSAndrey Grodzovsky * @state: PCI channel state
6566c9a6b82fSAndrey Grodzovsky *
6567c9a6b82fSAndrey Grodzovsky * Description: Called when a PCI error is detected.
6568c9a6b82fSAndrey Grodzovsky *
6569c9a6b82fSAndrey Grodzovsky * Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT.
6570c9a6b82fSAndrey Grodzovsky */
amdgpu_pci_error_detected(struct pci_dev * pdev,pci_channel_state_t state)6571c9a6b82fSAndrey Grodzovsky pci_ers_result_t amdgpu_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
6572c9a6b82fSAndrey Grodzovsky {
6573c9a6b82fSAndrey Grodzovsky struct drm_device *dev = pci_get_drvdata(pdev);
6574c9a6b82fSAndrey Grodzovsky struct amdgpu_device *adev = drm_to_adev(dev);
6575acd89fcaSAndrey Grodzovsky int i;
6576c9a6b82fSAndrey Grodzovsky
6577c9a6b82fSAndrey Grodzovsky DRM_INFO("PCI error: detected callback, state(%d)!!\n", state);
6578c9a6b82fSAndrey Grodzovsky
65796894305cSAndrey Grodzovsky if (adev->gmc.xgmi.num_physical_nodes > 1) {
65806894305cSAndrey Grodzovsky DRM_WARN("No support for XGMI hive yet...");
65816894305cSAndrey Grodzovsky return PCI_ERS_RESULT_DISCONNECT;
65826894305cSAndrey Grodzovsky }
65836894305cSAndrey Grodzovsky
6584e17e27f9SGuchun Chen adev->pci_channel_state = state;
6585e17e27f9SGuchun Chen
6586c9a6b82fSAndrey Grodzovsky switch (state) {
6587c9a6b82fSAndrey Grodzovsky case pci_channel_io_normal:
6588c9a6b82fSAndrey Grodzovsky return PCI_ERS_RESULT_CAN_RECOVER;
6589c9a6b82fSAndrey Grodzovsky /* Fatal error, prepare for slot reset */
6590acd89fcaSAndrey Grodzovsky case pci_channel_io_frozen:
6591acd89fcaSAndrey Grodzovsky /*
6592d0fb18b5SAndrey Grodzovsky * Locking adev->reset_domain->sem will prevent any external access
6593acd89fcaSAndrey Grodzovsky * to GPU during PCI error recovery
6594acd89fcaSAndrey Grodzovsky */
65953675c2f2SAndrey Grodzovsky amdgpu_device_lock_reset_domain(adev->reset_domain);
6596e923be99SAndrey Grodzovsky amdgpu_device_set_mp1_state(adev);
6597acd89fcaSAndrey Grodzovsky
6598acd89fcaSAndrey Grodzovsky /*
6599acd89fcaSAndrey Grodzovsky * Block any work scheduling as we do for regular GPU reset
6600acd89fcaSAndrey Grodzovsky * for the duration of the recovery
6601acd89fcaSAndrey Grodzovsky */
6602acd89fcaSAndrey Grodzovsky for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
6603acd89fcaSAndrey Grodzovsky struct amdgpu_ring *ring = adev->rings[i];
6604acd89fcaSAndrey Grodzovsky
66059749c868SMa Jun if (!amdgpu_ring_sched_ready(ring))
6606acd89fcaSAndrey Grodzovsky continue;
6607acd89fcaSAndrey Grodzovsky
6608acd89fcaSAndrey Grodzovsky drm_sched_stop(&ring->sched, NULL);
6609acd89fcaSAndrey Grodzovsky }
66108f8c80f4SJingwen Chen atomic_inc(&adev->gpu_reset_counter);
6611c9a6b82fSAndrey Grodzovsky return PCI_ERS_RESULT_NEED_RESET;
6612c9a6b82fSAndrey Grodzovsky case pci_channel_io_perm_failure:
6613c9a6b82fSAndrey Grodzovsky /* Permanent error, prepare for device removal */
6614c9a6b82fSAndrey Grodzovsky return PCI_ERS_RESULT_DISCONNECT;
6615c9a6b82fSAndrey Grodzovsky }
6616c9a6b82fSAndrey Grodzovsky
6617c9a6b82fSAndrey Grodzovsky return PCI_ERS_RESULT_NEED_RESET;
6618c9a6b82fSAndrey Grodzovsky }
6619c9a6b82fSAndrey Grodzovsky
6620c9a6b82fSAndrey Grodzovsky /**
6621c9a6b82fSAndrey Grodzovsky * amdgpu_pci_mmio_enabled - Enable MMIO and dump debug registers
6622c9a6b82fSAndrey Grodzovsky * @pdev: pointer to PCI device
6623c9a6b82fSAndrey Grodzovsky */
amdgpu_pci_mmio_enabled(struct pci_dev * pdev)6624c9a6b82fSAndrey Grodzovsky pci_ers_result_t amdgpu_pci_mmio_enabled(struct pci_dev *pdev)
6625c9a6b82fSAndrey Grodzovsky {
6626c9a6b82fSAndrey Grodzovsky
6627c9a6b82fSAndrey Grodzovsky DRM_INFO("PCI error: mmio enabled callback!!\n");
6628c9a6b82fSAndrey Grodzovsky
6629c9a6b82fSAndrey Grodzovsky /* TODO - dump whatever for debugging purposes */
6630c9a6b82fSAndrey Grodzovsky
6631c9a6b82fSAndrey Grodzovsky /* This called only if amdgpu_pci_error_detected returns
6632c9a6b82fSAndrey Grodzovsky * PCI_ERS_RESULT_CAN_RECOVER. Read/write to the device still
6633c9a6b82fSAndrey Grodzovsky * works, no need to reset slot.
6634c9a6b82fSAndrey Grodzovsky */
6635c9a6b82fSAndrey Grodzovsky
6636c9a6b82fSAndrey Grodzovsky return PCI_ERS_RESULT_RECOVERED;
6637c9a6b82fSAndrey Grodzovsky }
6638c9a6b82fSAndrey Grodzovsky
6639c9a6b82fSAndrey Grodzovsky /**
6640c9a6b82fSAndrey Grodzovsky * amdgpu_pci_slot_reset - Called when PCI slot has been reset.
6641c9a6b82fSAndrey Grodzovsky * @pdev: PCI device struct
6642c9a6b82fSAndrey Grodzovsky *
6643c9a6b82fSAndrey Grodzovsky * Description: This routine is called by the pci error recovery
6644c9a6b82fSAndrey Grodzovsky * code after the PCI slot has been reset, just before we
6645c9a6b82fSAndrey Grodzovsky * should resume normal operations.
6646c9a6b82fSAndrey Grodzovsky */
amdgpu_pci_slot_reset(struct pci_dev * pdev)6647c9a6b82fSAndrey Grodzovsky pci_ers_result_t amdgpu_pci_slot_reset(struct pci_dev *pdev)
6648c9a6b82fSAndrey Grodzovsky {
6649c9a6b82fSAndrey Grodzovsky struct drm_device *dev = pci_get_drvdata(pdev);
6650c9a6b82fSAndrey Grodzovsky struct amdgpu_device *adev = drm_to_adev(dev);
6651362c7b91SAndrey Grodzovsky int r, i;
665204442bf7SLijo Lazar struct amdgpu_reset_context reset_context;
6653362c7b91SAndrey Grodzovsky u32 memsize;
66547ac71382SAndrey Grodzovsky struct list_head device_list;
6655601429ccSStanley.Yang
6656601429ccSStanley.Yang /* PCI error slot reset should be skipped During RAS recovery */
66575f571c61SHawking Zhang if ((amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) ||
66585f571c61SHawking Zhang amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4)) &&
66597e437167STao Zhou amdgpu_ras_in_recovery(adev))
6660601429ccSStanley.Yang return PCI_ERS_RESULT_RECOVERED;
6661c9a6b82fSAndrey Grodzovsky
6662c9a6b82fSAndrey Grodzovsky DRM_INFO("PCI error: slot reset callback!!\n");
6663c9a6b82fSAndrey Grodzovsky
666404442bf7SLijo Lazar memset(&reset_context, 0, sizeof(reset_context));
666504442bf7SLijo Lazar
66667ac71382SAndrey Grodzovsky INIT_LIST_HEAD(&device_list);
6667655ce9cbSshaoyunl list_add_tail(&adev->reset_list, &device_list);
66687ac71382SAndrey Grodzovsky
6669362c7b91SAndrey Grodzovsky /* wait for asic to come out of reset */
6670362c7b91SAndrey Grodzovsky msleep(500);
6671362c7b91SAndrey Grodzovsky
66727ac71382SAndrey Grodzovsky /* Restore PCI confspace */
6673c1dd4aa6SAndrey Grodzovsky amdgpu_device_load_pci_state(pdev);
6674c9a6b82fSAndrey Grodzovsky
6675362c7b91SAndrey Grodzovsky /* confirm ASIC came out of reset */
6676362c7b91SAndrey Grodzovsky for (i = 0; i < adev->usec_timeout; i++) {
6677362c7b91SAndrey Grodzovsky memsize = amdgpu_asic_get_config_memsize(adev);
6678362c7b91SAndrey Grodzovsky
6679362c7b91SAndrey Grodzovsky if (memsize != 0xffffffff)
6680362c7b91SAndrey Grodzovsky break;
6681362c7b91SAndrey Grodzovsky udelay(1);
6682362c7b91SAndrey Grodzovsky }
6683362c7b91SAndrey Grodzovsky if (memsize == 0xffffffff) {
6684362c7b91SAndrey Grodzovsky r = -ETIME;
6685362c7b91SAndrey Grodzovsky goto out;
6686362c7b91SAndrey Grodzovsky }
6687362c7b91SAndrey Grodzovsky
668804442bf7SLijo Lazar reset_context.method = AMD_RESET_METHOD_NONE;
668904442bf7SLijo Lazar reset_context.reset_req_dev = adev;
669004442bf7SLijo Lazar set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags);
669104442bf7SLijo Lazar set_bit(AMDGPU_SKIP_HW_RESET, &reset_context.flags);
669204442bf7SLijo Lazar
66937afefb81SAndrey Grodzovsky adev->no_hw_access = true;
669404442bf7SLijo Lazar r = amdgpu_device_pre_asic_reset(adev, &reset_context);
66957afefb81SAndrey Grodzovsky adev->no_hw_access = false;
6696c9a6b82fSAndrey Grodzovsky if (r)
6697c9a6b82fSAndrey Grodzovsky goto out;
6698c9a6b82fSAndrey Grodzovsky
669904442bf7SLijo Lazar r = amdgpu_do_asic_reset(&device_list, &reset_context);
6700c9a6b82fSAndrey Grodzovsky
6701c9a6b82fSAndrey Grodzovsky out:
6702c9a6b82fSAndrey Grodzovsky if (!r) {
6703c1dd4aa6SAndrey Grodzovsky if (amdgpu_device_cache_pci_state(adev->pdev))
6704c1dd4aa6SAndrey Grodzovsky pci_restore_state(adev->pdev);
6705c1dd4aa6SAndrey Grodzovsky
6706c9a6b82fSAndrey Grodzovsky DRM_INFO("PCIe error recovery succeeded\n");
6707c9a6b82fSAndrey Grodzovsky } else {
6708c9a6b82fSAndrey Grodzovsky DRM_ERROR("PCIe error recovery failed, err:%d", r);
6709e923be99SAndrey Grodzovsky amdgpu_device_unset_mp1_state(adev);
6710e923be99SAndrey Grodzovsky amdgpu_device_unlock_reset_domain(adev->reset_domain);
6711c9a6b82fSAndrey Grodzovsky }
6712c9a6b82fSAndrey Grodzovsky
6713c9a6b82fSAndrey Grodzovsky return r ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
6714c9a6b82fSAndrey Grodzovsky }
6715c9a6b82fSAndrey Grodzovsky
6716c9a6b82fSAndrey Grodzovsky /**
6717c9a6b82fSAndrey Grodzovsky * amdgpu_pci_resume() - resume normal ops after PCI reset
6718c9a6b82fSAndrey Grodzovsky * @pdev: pointer to PCI device
6719c9a6b82fSAndrey Grodzovsky *
6720c9a6b82fSAndrey Grodzovsky * Called when the error recovery driver tells us that its
6721505199a3SAlex Deucher * OK to resume normal operation.
6722c9a6b82fSAndrey Grodzovsky */
amdgpu_pci_resume(struct pci_dev * pdev)6723c9a6b82fSAndrey Grodzovsky void amdgpu_pci_resume(struct pci_dev *pdev)
6724c9a6b82fSAndrey Grodzovsky {
6725c9a6b82fSAndrey Grodzovsky struct drm_device *dev = pci_get_drvdata(pdev);
6726c9a6b82fSAndrey Grodzovsky struct amdgpu_device *adev = drm_to_adev(dev);
6727acd89fcaSAndrey Grodzovsky int i;
6728c9a6b82fSAndrey Grodzovsky
6729c9a6b82fSAndrey Grodzovsky
6730c9a6b82fSAndrey Grodzovsky DRM_INFO("PCI error: resume callback!!\n");
6731acd89fcaSAndrey Grodzovsky
6732e17e27f9SGuchun Chen /* Only continue execution for the case of pci_channel_io_frozen */
6733e17e27f9SGuchun Chen if (adev->pci_channel_state != pci_channel_io_frozen)
6734e17e27f9SGuchun Chen return;
6735e17e27f9SGuchun Chen
6736acd89fcaSAndrey Grodzovsky for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
6737acd89fcaSAndrey Grodzovsky struct amdgpu_ring *ring = adev->rings[i];
6738acd89fcaSAndrey Grodzovsky
67399749c868SMa Jun if (!amdgpu_ring_sched_ready(ring))
6740acd89fcaSAndrey Grodzovsky continue;
6741acd89fcaSAndrey Grodzovsky
6742b2ef8087SChristian König drm_sched_start(&ring->sched, 0);
6743acd89fcaSAndrey Grodzovsky }
6744acd89fcaSAndrey Grodzovsky
6745e923be99SAndrey Grodzovsky amdgpu_device_unset_mp1_state(adev);
6746e923be99SAndrey Grodzovsky amdgpu_device_unlock_reset_domain(adev->reset_domain);
6747c9a6b82fSAndrey Grodzovsky }
6748c1dd4aa6SAndrey Grodzovsky
amdgpu_device_cache_pci_state(struct pci_dev * pdev)6749c1dd4aa6SAndrey Grodzovsky bool amdgpu_device_cache_pci_state(struct pci_dev *pdev)
6750c1dd4aa6SAndrey Grodzovsky {
6751c1dd4aa6SAndrey Grodzovsky struct drm_device *dev = pci_get_drvdata(pdev);
6752c1dd4aa6SAndrey Grodzovsky struct amdgpu_device *adev = drm_to_adev(dev);
6753c1dd4aa6SAndrey Grodzovsky int r;
6754c1dd4aa6SAndrey Grodzovsky
6755afe260dfSVictor Zhao if (amdgpu_sriov_vf(adev))
6756afe260dfSVictor Zhao return false;
6757afe260dfSVictor Zhao
6758c1dd4aa6SAndrey Grodzovsky r = pci_save_state(pdev);
6759c1dd4aa6SAndrey Grodzovsky if (!r) {
6760c1dd4aa6SAndrey Grodzovsky kfree(adev->pci_state);
6761c1dd4aa6SAndrey Grodzovsky
6762c1dd4aa6SAndrey Grodzovsky adev->pci_state = pci_store_saved_state(pdev);
6763c1dd4aa6SAndrey Grodzovsky
6764c1dd4aa6SAndrey Grodzovsky if (!adev->pci_state) {
6765c1dd4aa6SAndrey Grodzovsky DRM_ERROR("Failed to store PCI saved state");
6766c1dd4aa6SAndrey Grodzovsky return false;
6767c1dd4aa6SAndrey Grodzovsky }
6768c1dd4aa6SAndrey Grodzovsky } else {
6769c1dd4aa6SAndrey Grodzovsky DRM_WARN("Failed to save PCI state, err:%d\n", r);
6770c1dd4aa6SAndrey Grodzovsky return false;
6771c1dd4aa6SAndrey Grodzovsky }
6772c1dd4aa6SAndrey Grodzovsky
6773c1dd4aa6SAndrey Grodzovsky return true;
6774c1dd4aa6SAndrey Grodzovsky }
6775c1dd4aa6SAndrey Grodzovsky
amdgpu_device_load_pci_state(struct pci_dev * pdev)6776c1dd4aa6SAndrey Grodzovsky bool amdgpu_device_load_pci_state(struct pci_dev *pdev)
6777c1dd4aa6SAndrey Grodzovsky {
6778c1dd4aa6SAndrey Grodzovsky struct drm_device *dev = pci_get_drvdata(pdev);
6779c1dd4aa6SAndrey Grodzovsky struct amdgpu_device *adev = drm_to_adev(dev);
6780c1dd4aa6SAndrey Grodzovsky int r;
6781c1dd4aa6SAndrey Grodzovsky
6782c1dd4aa6SAndrey Grodzovsky if (!adev->pci_state)
6783c1dd4aa6SAndrey Grodzovsky return false;
6784c1dd4aa6SAndrey Grodzovsky
6785c1dd4aa6SAndrey Grodzovsky r = pci_load_saved_state(pdev, adev->pci_state);
6786c1dd4aa6SAndrey Grodzovsky
6787c1dd4aa6SAndrey Grodzovsky if (!r) {
6788c1dd4aa6SAndrey Grodzovsky pci_restore_state(pdev);
6789c1dd4aa6SAndrey Grodzovsky } else {
6790c1dd4aa6SAndrey Grodzovsky DRM_WARN("Failed to load PCI state, err:%d\n", r);
6791c1dd4aa6SAndrey Grodzovsky return false;
6792c1dd4aa6SAndrey Grodzovsky }
6793c1dd4aa6SAndrey Grodzovsky
6794c1dd4aa6SAndrey Grodzovsky return true;
6795c1dd4aa6SAndrey Grodzovsky }
6796c1dd4aa6SAndrey Grodzovsky
amdgpu_device_flush_hdp(struct amdgpu_device * adev,struct amdgpu_ring * ring)6797810085ddSEric Huang void amdgpu_device_flush_hdp(struct amdgpu_device *adev,
6798810085ddSEric Huang struct amdgpu_ring *ring)
6799810085ddSEric Huang {
6800810085ddSEric Huang #ifdef CONFIG_X86_64
6801b818a5d3SAlex Deucher if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev))
6802810085ddSEric Huang return;
6803810085ddSEric Huang #endif
6804810085ddSEric Huang if (adev->gmc.xgmi.connected_to_cpu)
6805810085ddSEric Huang return;
6806c1dd4aa6SAndrey Grodzovsky
6807810085ddSEric Huang if (ring && ring->funcs->emit_hdp_flush)
6808810085ddSEric Huang amdgpu_ring_emit_hdp_flush(ring);
6809810085ddSEric Huang else
6810810085ddSEric Huang amdgpu_asic_flush_hdp(adev, ring);
6811810085ddSEric Huang }
6812810085ddSEric Huang
amdgpu_device_invalidate_hdp(struct amdgpu_device * adev,struct amdgpu_ring * ring)6813810085ddSEric Huang void amdgpu_device_invalidate_hdp(struct amdgpu_device *adev,
6814810085ddSEric Huang struct amdgpu_ring *ring)
6815810085ddSEric Huang {
6816810085ddSEric Huang #ifdef CONFIG_X86_64
6817b818a5d3SAlex Deucher if ((adev->flags & AMD_IS_APU) && !amdgpu_passthrough(adev))
6818810085ddSEric Huang return;
6819810085ddSEric Huang #endif
6820810085ddSEric Huang if (adev->gmc.xgmi.connected_to_cpu)
6821810085ddSEric Huang return;
6822810085ddSEric Huang
6823810085ddSEric Huang amdgpu_asic_invalidate_hdp(adev, ring);
6824810085ddSEric Huang }
682534f3a4a9SLang Yu
amdgpu_in_reset(struct amdgpu_device * adev)682689a7a870SAndrey Grodzovsky int amdgpu_in_reset(struct amdgpu_device *adev)
682789a7a870SAndrey Grodzovsky {
682889a7a870SAndrey Grodzovsky return atomic_read(&adev->reset_domain->in_gpu_reset);
682989a7a870SAndrey Grodzovsky }
683089a7a870SAndrey Grodzovsky
683134f3a4a9SLang Yu /**
683234f3a4a9SLang Yu * amdgpu_device_halt() - bring hardware to some kind of halt state
683334f3a4a9SLang Yu *
683434f3a4a9SLang Yu * @adev: amdgpu_device pointer
683534f3a4a9SLang Yu *
683634f3a4a9SLang Yu * Bring hardware to some kind of halt state so that no one can touch it
683734f3a4a9SLang Yu * any more. It will help to maintain error context when error occurred.
683834f3a4a9SLang Yu * Compare to a simple hang, the system will keep stable at least for SSH
683934f3a4a9SLang Yu * access. Then it should be trivial to inspect the hardware state and
684034f3a4a9SLang Yu * see what's going on. Implemented as following:
684134f3a4a9SLang Yu *
684234f3a4a9SLang Yu * 1. drm_dev_unplug() makes device inaccessible to user space(IOCTLs, etc),
684334f3a4a9SLang Yu * clears all CPU mappings to device, disallows remappings through page faults
684434f3a4a9SLang Yu * 2. amdgpu_irq_disable_all() disables all interrupts
684534f3a4a9SLang Yu * 3. amdgpu_fence_driver_hw_fini() signals all HW fences
684634f3a4a9SLang Yu * 4. set adev->no_hw_access to avoid potential crashes after setp 5
684734f3a4a9SLang Yu * 5. amdgpu_device_unmap_mmio() clears all MMIO mappings
684834f3a4a9SLang Yu * 6. pci_disable_device() and pci_wait_for_pending_transaction()
684934f3a4a9SLang Yu * flush any in flight DMA operations
685034f3a4a9SLang Yu */
amdgpu_device_halt(struct amdgpu_device * adev)685134f3a4a9SLang Yu void amdgpu_device_halt(struct amdgpu_device *adev)
685234f3a4a9SLang Yu {
685334f3a4a9SLang Yu struct pci_dev *pdev = adev->pdev;
6854e0f943b4SGuchun Chen struct drm_device *ddev = adev_to_drm(adev);
685534f3a4a9SLang Yu
68562c1c7ba4SJames Zhu amdgpu_xcp_dev_unplug(adev);
685734f3a4a9SLang Yu drm_dev_unplug(ddev);
685834f3a4a9SLang Yu
685934f3a4a9SLang Yu amdgpu_irq_disable_all(adev);
686034f3a4a9SLang Yu
686134f3a4a9SLang Yu amdgpu_fence_driver_hw_fini(adev);
686234f3a4a9SLang Yu
686334f3a4a9SLang Yu adev->no_hw_access = true;
686434f3a4a9SLang Yu
686534f3a4a9SLang Yu amdgpu_device_unmap_mmio(adev);
686634f3a4a9SLang Yu
686734f3a4a9SLang Yu pci_disable_device(pdev);
686834f3a4a9SLang Yu pci_wait_for_pending_transaction(pdev);
686934f3a4a9SLang Yu }
687086700a40SXiaojian Du
amdgpu_device_pcie_port_rreg(struct amdgpu_device * adev,u32 reg)687186700a40SXiaojian Du u32 amdgpu_device_pcie_port_rreg(struct amdgpu_device *adev,
687286700a40SXiaojian Du u32 reg)
687386700a40SXiaojian Du {
687486700a40SXiaojian Du unsigned long flags, address, data;
687586700a40SXiaojian Du u32 r;
687686700a40SXiaojian Du
687786700a40SXiaojian Du address = adev->nbio.funcs->get_pcie_port_index_offset(adev);
687886700a40SXiaojian Du data = adev->nbio.funcs->get_pcie_port_data_offset(adev);
687986700a40SXiaojian Du
688086700a40SXiaojian Du spin_lock_irqsave(&adev->pcie_idx_lock, flags);
688186700a40SXiaojian Du WREG32(address, reg * 4);
688286700a40SXiaojian Du (void)RREG32(address);
688386700a40SXiaojian Du r = RREG32(data);
688486700a40SXiaojian Du spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
688586700a40SXiaojian Du return r;
688686700a40SXiaojian Du }
688786700a40SXiaojian Du
amdgpu_device_pcie_port_wreg(struct amdgpu_device * adev,u32 reg,u32 v)688886700a40SXiaojian Du void amdgpu_device_pcie_port_wreg(struct amdgpu_device *adev,
688986700a40SXiaojian Du u32 reg, u32 v)
689086700a40SXiaojian Du {
689186700a40SXiaojian Du unsigned long flags, address, data;
689286700a40SXiaojian Du
689386700a40SXiaojian Du address = adev->nbio.funcs->get_pcie_port_index_offset(adev);
689486700a40SXiaojian Du data = adev->nbio.funcs->get_pcie_port_data_offset(adev);
689586700a40SXiaojian Du
689686700a40SXiaojian Du spin_lock_irqsave(&adev->pcie_idx_lock, flags);
689786700a40SXiaojian Du WREG32(address, reg * 4);
689886700a40SXiaojian Du (void)RREG32(address);
689986700a40SXiaojian Du WREG32(data, v);
690086700a40SXiaojian Du (void)RREG32(data);
690186700a40SXiaojian Du spin_unlock_irqrestore(&adev->pcie_idx_lock, flags);
690286700a40SXiaojian Du }
690368ce8b24SChristian König
690468ce8b24SChristian König /**
6905a6328c9cSChristian König * amdgpu_device_get_gang - return a reference to the current gang
6906a6328c9cSChristian König * @adev: amdgpu_device pointer
6907a6328c9cSChristian König *
6908a6328c9cSChristian König * Returns: A new reference to the current gang leader.
6909a6328c9cSChristian König */
amdgpu_device_get_gang(struct amdgpu_device * adev)6910a6328c9cSChristian König struct dma_fence *amdgpu_device_get_gang(struct amdgpu_device *adev)
6911a6328c9cSChristian König {
6912a6328c9cSChristian König struct dma_fence *fence;
6913a6328c9cSChristian König
6914a6328c9cSChristian König rcu_read_lock();
6915a6328c9cSChristian König fence = dma_fence_get_rcu_safe(&adev->gang_submit);
6916a6328c9cSChristian König rcu_read_unlock();
6917a6328c9cSChristian König return fence;
6918a6328c9cSChristian König }
6919a6328c9cSChristian König
6920a6328c9cSChristian König /**
692168ce8b24SChristian König * amdgpu_device_switch_gang - switch to a new gang
692268ce8b24SChristian König * @adev: amdgpu_device pointer
692368ce8b24SChristian König * @gang: the gang to switch to
692468ce8b24SChristian König *
692568ce8b24SChristian König * Try to switch to a new gang.
692668ce8b24SChristian König * Returns: NULL if we switched to the new gang or a reference to the current
692768ce8b24SChristian König * gang leader.
692868ce8b24SChristian König */
amdgpu_device_switch_gang(struct amdgpu_device * adev,struct dma_fence * gang)692968ce8b24SChristian König struct dma_fence *amdgpu_device_switch_gang(struct amdgpu_device *adev,
693068ce8b24SChristian König struct dma_fence *gang)
693168ce8b24SChristian König {
693268ce8b24SChristian König struct dma_fence *old = NULL;
693368ce8b24SChristian König
69340d9a9509SChristian König dma_fence_get(gang);
693568ce8b24SChristian König do {
693668ce8b24SChristian König dma_fence_put(old);
6937a6328c9cSChristian König old = amdgpu_device_get_gang(adev);
693868ce8b24SChristian König if (old == gang)
693968ce8b24SChristian König break;
694068ce8b24SChristian König
69410d9a9509SChristian König if (!dma_fence_is_signaled(old)) {
69420d9a9509SChristian König dma_fence_put(gang);
694368ce8b24SChristian König return old;
69440d9a9509SChristian König }
694568ce8b24SChristian König
694668ce8b24SChristian König } while (cmpxchg((struct dma_fence __force **)&adev->gang_submit,
694768ce8b24SChristian König old, gang) != old);
694868ce8b24SChristian König
69490d9a9509SChristian König /*
69500d9a9509SChristian König * Drop it once for the exchanged reference in adev and once for the
69510d9a9509SChristian König * thread local reference acquired in amdgpu_device_get_gang().
69520d9a9509SChristian König */
69530d9a9509SChristian König dma_fence_put(old);
695468ce8b24SChristian König dma_fence_put(old);
695568ce8b24SChristian König return NULL;
695668ce8b24SChristian König }
6957220c8cc8SAlex Deucher
6958bd22e44aSChristian König /**
6959bd22e44aSChristian König * amdgpu_device_enforce_isolation - enforce HW isolation
6960bd22e44aSChristian König * @adev: the amdgpu device pointer
6961bd22e44aSChristian König * @ring: the HW ring the job is supposed to run on
6962bd22e44aSChristian König * @job: the job which is about to be pushed to the HW ring
6963bd22e44aSChristian König *
6964bd22e44aSChristian König * Makes sure that only one client at a time can use the GFX block.
6965bd22e44aSChristian König * Returns: The dependency to wait on before the job can be pushed to the HW.
6966bd22e44aSChristian König * The function is called multiple times until NULL is returned.
6967bd22e44aSChristian König */
amdgpu_device_enforce_isolation(struct amdgpu_device * adev,struct amdgpu_ring * ring,struct amdgpu_job * job)6968bd22e44aSChristian König struct dma_fence *amdgpu_device_enforce_isolation(struct amdgpu_device *adev,
6969bd22e44aSChristian König struct amdgpu_ring *ring,
6970bd22e44aSChristian König struct amdgpu_job *job)
6971bd22e44aSChristian König {
6972bd22e44aSChristian König struct amdgpu_isolation *isolation = &adev->isolation[ring->xcp_id];
6973bd22e44aSChristian König struct drm_sched_fence *f = job->base.s_fence;
6974bd22e44aSChristian König struct dma_fence *dep;
6975bd22e44aSChristian König void *owner;
6976bd22e44aSChristian König int r;
6977bd22e44aSChristian König
6978bd22e44aSChristian König /*
6979bd22e44aSChristian König * For now enforce isolation only for the GFX block since we only need
6980bd22e44aSChristian König * the cleaner shader on those rings.
6981bd22e44aSChristian König */
6982bd22e44aSChristian König if (ring->funcs->type != AMDGPU_RING_TYPE_GFX &&
6983bd22e44aSChristian König ring->funcs->type != AMDGPU_RING_TYPE_COMPUTE)
6984bd22e44aSChristian König return NULL;
6985bd22e44aSChristian König
6986bd22e44aSChristian König /*
6987bd22e44aSChristian König * All submissions where enforce isolation is false are handled as if
6988bd22e44aSChristian König * they come from a single client. Use ~0l as the owner to distinct it
6989bd22e44aSChristian König * from kernel submissions where the owner is NULL.
6990bd22e44aSChristian König */
6991bd22e44aSChristian König owner = job->enforce_isolation ? f->owner : (void *)~0l;
6992bd22e44aSChristian König
6993bd22e44aSChristian König mutex_lock(&adev->enforce_isolation_mutex);
6994bd22e44aSChristian König
6995bd22e44aSChristian König /*
6996bd22e44aSChristian König * The "spearhead" submission is the first one which changes the
6997bd22e44aSChristian König * ownership to its client. We always need to wait for it to be
6998bd22e44aSChristian König * pushed to the HW before proceeding with anything.
6999bd22e44aSChristian König */
7000bd22e44aSChristian König if (&f->scheduled != isolation->spearhead &&
7001bd22e44aSChristian König !dma_fence_is_signaled(isolation->spearhead)) {
7002bd22e44aSChristian König dep = isolation->spearhead;
7003bd22e44aSChristian König goto out_grab_ref;
7004bd22e44aSChristian König }
7005bd22e44aSChristian König
7006bd22e44aSChristian König if (isolation->owner != owner) {
7007bd22e44aSChristian König
7008bd22e44aSChristian König /*
7009bd22e44aSChristian König * Wait for any gang to be assembled before switching to a
7010bd22e44aSChristian König * different owner or otherwise we could deadlock the
7011bd22e44aSChristian König * submissions.
7012bd22e44aSChristian König */
7013bd22e44aSChristian König if (!job->gang_submit) {
7014bd22e44aSChristian König dep = amdgpu_device_get_gang(adev);
7015bd22e44aSChristian König if (!dma_fence_is_signaled(dep))
7016bd22e44aSChristian König goto out_return_dep;
7017bd22e44aSChristian König dma_fence_put(dep);
7018bd22e44aSChristian König }
7019bd22e44aSChristian König
7020bd22e44aSChristian König dma_fence_put(isolation->spearhead);
7021bd22e44aSChristian König isolation->spearhead = dma_fence_get(&f->scheduled);
7022bd22e44aSChristian König amdgpu_sync_move(&isolation->active, &isolation->prev);
70231bb1314dSChristian König trace_amdgpu_isolation(isolation->owner, owner);
7024bd22e44aSChristian König isolation->owner = owner;
7025bd22e44aSChristian König }
7026bd22e44aSChristian König
7027bd22e44aSChristian König /*
7028bd22e44aSChristian König * Specifying the ring here helps to pipeline submissions even when
7029bd22e44aSChristian König * isolation is enabled. If that is not desired for testing NULL can be
7030bd22e44aSChristian König * used instead of the ring to enforce a CPU round trip while switching
7031bd22e44aSChristian König * between clients.
7032bd22e44aSChristian König */
7033bd22e44aSChristian König dep = amdgpu_sync_peek_fence(&isolation->prev, ring);
7034bd22e44aSChristian König r = amdgpu_sync_fence(&isolation->active, &f->finished, GFP_NOWAIT);
7035bd22e44aSChristian König if (r)
7036bd22e44aSChristian König DRM_WARN("OOM tracking isolation\n");
7037bd22e44aSChristian König
7038bd22e44aSChristian König out_grab_ref:
7039bd22e44aSChristian König dma_fence_get(dep);
7040bd22e44aSChristian König out_return_dep:
7041bd22e44aSChristian König mutex_unlock(&adev->enforce_isolation_mutex);
7042bd22e44aSChristian König return dep;
7043bd22e44aSChristian König }
7044bd22e44aSChristian König
amdgpu_device_has_display_hardware(struct amdgpu_device * adev)7045220c8cc8SAlex Deucher bool amdgpu_device_has_display_hardware(struct amdgpu_device *adev)
7046220c8cc8SAlex Deucher {
7047220c8cc8SAlex Deucher switch (adev->asic_type) {
7048220c8cc8SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_SI
7049220c8cc8SAlex Deucher case CHIP_HAINAN:
7050220c8cc8SAlex Deucher #endif
7051220c8cc8SAlex Deucher case CHIP_TOPAZ:
7052220c8cc8SAlex Deucher /* chips with no display hardware */
7053220c8cc8SAlex Deucher return false;
7054220c8cc8SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_SI
7055220c8cc8SAlex Deucher case CHIP_TAHITI:
7056220c8cc8SAlex Deucher case CHIP_PITCAIRN:
7057220c8cc8SAlex Deucher case CHIP_VERDE:
7058220c8cc8SAlex Deucher case CHIP_OLAND:
7059220c8cc8SAlex Deucher #endif
7060220c8cc8SAlex Deucher #ifdef CONFIG_DRM_AMDGPU_CIK
7061220c8cc8SAlex Deucher case CHIP_BONAIRE:
7062220c8cc8SAlex Deucher case CHIP_HAWAII:
7063220c8cc8SAlex Deucher case CHIP_KAVERI:
7064220c8cc8SAlex Deucher case CHIP_KABINI:
7065220c8cc8SAlex Deucher case CHIP_MULLINS:
7066220c8cc8SAlex Deucher #endif
7067220c8cc8SAlex Deucher case CHIP_TONGA:
7068220c8cc8SAlex Deucher case CHIP_FIJI:
7069220c8cc8SAlex Deucher case CHIP_POLARIS10:
7070220c8cc8SAlex Deucher case CHIP_POLARIS11:
7071220c8cc8SAlex Deucher case CHIP_POLARIS12:
7072220c8cc8SAlex Deucher case CHIP_VEGAM:
7073220c8cc8SAlex Deucher case CHIP_CARRIZO:
7074220c8cc8SAlex Deucher case CHIP_STONEY:
7075220c8cc8SAlex Deucher /* chips with display hardware */
7076220c8cc8SAlex Deucher return true;
7077220c8cc8SAlex Deucher default:
7078220c8cc8SAlex Deucher /* IP discovery */
70794e8303cfSLijo Lazar if (!amdgpu_ip_version(adev, DCE_HWIP, 0) ||
7080220c8cc8SAlex Deucher (adev->harvest_ip_mask & AMD_HARVEST_IP_DMU_MASK))
7081220c8cc8SAlex Deucher return false;
7082220c8cc8SAlex Deucher return true;
7083220c8cc8SAlex Deucher }
7084220c8cc8SAlex Deucher }
708581283feeSJames Zhu
amdgpu_device_wait_on_rreg(struct amdgpu_device * adev,uint32_t inst,uint32_t reg_addr,char reg_name[],uint32_t expected_value,uint32_t mask)708681283feeSJames Zhu uint32_t amdgpu_device_wait_on_rreg(struct amdgpu_device *adev,
708781283feeSJames Zhu uint32_t inst, uint32_t reg_addr, char reg_name[],
708881283feeSJames Zhu uint32_t expected_value, uint32_t mask)
708981283feeSJames Zhu {
709081283feeSJames Zhu uint32_t ret = 0;
709181283feeSJames Zhu uint32_t old_ = 0;
709281283feeSJames Zhu uint32_t tmp_ = RREG32(reg_addr);
709381283feeSJames Zhu uint32_t loop = adev->usec_timeout;
709481283feeSJames Zhu
709581283feeSJames Zhu while ((tmp_ & (mask)) != (expected_value)) {
709681283feeSJames Zhu if (old_ != tmp_) {
709781283feeSJames Zhu loop = adev->usec_timeout;
709881283feeSJames Zhu old_ = tmp_;
709981283feeSJames Zhu } else
710081283feeSJames Zhu udelay(1);
710181283feeSJames Zhu tmp_ = RREG32(reg_addr);
710281283feeSJames Zhu loop--;
710381283feeSJames Zhu if (!loop) {
710481283feeSJames Zhu DRM_WARN("Register(%d) [%s] failed to reach value 0x%08x != 0x%08xn",
710581283feeSJames Zhu inst, reg_name, (uint32_t)expected_value,
710681283feeSJames Zhu (uint32_t)(tmp_ & (mask)));
710781283feeSJames Zhu ret = -ETIMEDOUT;
710881283feeSJames Zhu break;
710981283feeSJames Zhu }
711081283feeSJames Zhu }
711181283feeSJames Zhu return ret;
711281283feeSJames Zhu }
71136c8d1f4bS[email protected]
amdgpu_get_soft_full_reset_mask(struct amdgpu_ring * ring)71146c8d1f4bS[email protected] ssize_t amdgpu_get_soft_full_reset_mask(struct amdgpu_ring *ring)
71156c8d1f4bS[email protected] {
71166c8d1f4bS[email protected] ssize_t size = 0;
71176c8d1f4bS[email protected]
71186c8d1f4bS[email protected] if (!ring || !ring->adev)
71196c8d1f4bS[email protected] return size;
71206c8d1f4bS[email protected]
71216c8d1f4bS[email protected] if (amdgpu_device_should_recover_gpu(ring->adev))
71226c8d1f4bS[email protected] size |= AMDGPU_RESET_TYPE_FULL;
71236c8d1f4bS[email protected]
71246c8d1f4bS[email protected] if (unlikely(!ring->adev->debug_disable_soft_recovery) &&
71256c8d1f4bS[email protected] !amdgpu_sriov_vf(ring->adev) && ring->funcs->soft_recovery)
71266c8d1f4bS[email protected] size |= AMDGPU_RESET_TYPE_SOFT_RESET;
71276c8d1f4bS[email protected]
71286c8d1f4bS[email protected] return size;
71296c8d1f4bS[email protected] }
71306c8d1f4bS[email protected]
amdgpu_show_reset_mask(char * buf,uint32_t supported_reset)71316c8d1f4bS[email protected] ssize_t amdgpu_show_reset_mask(char *buf, uint32_t supported_reset)
71326c8d1f4bS[email protected] {
71336c8d1f4bS[email protected] ssize_t size = 0;
71346c8d1f4bS[email protected]
71356c8d1f4bS[email protected] if (supported_reset == 0) {
71366c8d1f4bS[email protected] size += sysfs_emit_at(buf, size, "unsupported");
71376c8d1f4bS[email protected] size += sysfs_emit_at(buf, size, "\n");
71386c8d1f4bS[email protected] return size;
71396c8d1f4bS[email protected]
71406c8d1f4bS[email protected] }
71416c8d1f4bS[email protected]
71426c8d1f4bS[email protected] if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RESET)
71436c8d1f4bS[email protected] size += sysfs_emit_at(buf, size, "soft ");
71446c8d1f4bS[email protected]
71456c8d1f4bS[email protected] if (supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE)
71466c8d1f4bS[email protected] size += sysfs_emit_at(buf, size, "queue ");
71476c8d1f4bS[email protected]
71486c8d1f4bS[email protected] if (supported_reset & AMDGPU_RESET_TYPE_PER_PIPE)
71496c8d1f4bS[email protected] size += sysfs_emit_at(buf, size, "pipe ");
71506c8d1f4bS[email protected]
71516c8d1f4bS[email protected] if (supported_reset & AMDGPU_RESET_TYPE_FULL)
71526c8d1f4bS[email protected] size += sysfs_emit_at(buf, size, "full ");
71536c8d1f4bS[email protected]
71546c8d1f4bS[email protected] size += sysfs_emit_at(buf, size, "\n");
71556c8d1f4bS[email protected] return size;
71566c8d1f4bS[email protected] }
7157