[alsa-devel] [PATCH 00/20] Enable BACO for power savings (v3)
This patch set enables BACO (Bus Active Chip Off) for power savings on VI+ asics. Similar to PowerXpress and Hybrid Graphics (PX/HG) laptops, we can disable GPUs at runtime when they are not in use if they support BACO. The runtime pm code in amdgpu was originally developed for PX/HG laptops, so it was pretty entangled with the vga_switcheroo and ACPI code. Since the GPU contains an audio codec for HDMI/DP, there is some interaction with the hda driver. I am by no means an expert on alsa, so any advice on those patches is much appreciated. I had to enable runtime pm on the hda device to allow the GPU to enter runtime pm because they are linked.
The full tree can be found here: https://cgit.freedesktop.org/~agd5f/linux/log/?h=baco
TODO: - Turn off runtime pm when KFD user queues are active
I've tested these pretty extensively on the asics I have access to. All seems to work properly. HDMI audio works fine with runtime pm both with and without the GPU BACO stuff.
I'd like to land the the audio patches and the first 15 GPU patches. I don't plan to enable this by default (last patch in the GPU set) until the KFD changes are in place to properly handle runtime pm, however it can be enabled via module parameter (runpm=1).
v2: - Split whitespace changes from baco callback addition - Fix pci ref counting in px/hg handling in hda driver - Handle CONFIG_ACPI properly - Split adding new hda pci ids from adding runpm flag
v3: - Don't enable BACO on Navi chips yet
Alex Deucher (20): drm/amdgpu: add asic callback for BACO support drm/amdgpu: add supports_baco callback for soc15 asics. (v2) drm/amdgpu: add supports_baco callback for SI asics. drm/amdgpu: add supports_baco callback for CIK asics. drm/amdgpu: add supports_baco callback for VI asics. drm/amdgpu: add supports_baco callback for NV asics. drm/amdgpu: add a amdgpu_device_supports_baco helper drm/amdgpu: rename amdgpu_device_is_px to amdgpu_device_supports_boco (v2) drm/amdgpu: add additional boco checks to runtime suspend/resume (v2) drm/amdgpu: split swSMU baco_reset into enter and exit drm/amdgpu: add helpers for baco entry and exit drm/amdgpu: add baco support to runtime suspend/resume drm/amdgpu: start to disentangle boco from runtime pm drm/amdgpu: disentangle runtime pm and vga_switcheroo drm/amdgpu: enable runtime pm on BACO capable boards if runpm=1 drm/amdgpu/runpm: enable runpm on baco capable VI+ asics (v2) ALSA: hda/hdmi - fix vgaswitcheroo detection for AMD ALSA: hda/hdmi - Add new pci ids for AMD GPU display audio ALSA: hda/hdmi - enable runtime pm for newer AMD display audio ALSA: hda/hdmi - enable automatic runtime pm for AMD HDMI codecs by default
drivers/gpu/drm/amd/amdgpu/amdgpu.h | 11 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 106 ++++++++++++++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 63 ++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 21 +++- drivers/gpu/drm/amd/amdgpu/cik.c | 18 +++ drivers/gpu/drm/amd/amdgpu/nv.c | 18 ++- drivers/gpu/drm/amd/amdgpu/si.c | 6 + drivers/gpu/drm/amd/amdgpu/soc15.c | 34 +++++- drivers/gpu/drm/amd/amdgpu/vi.c | 22 ++++ drivers/gpu/drm/amd/powerplay/amdgpu_smu.c | 20 +++- drivers/gpu/drm/amd/powerplay/arcturus_ppt.c | 3 +- .../gpu/drm/amd/powerplay/inc/amdgpu_smu.h | 6 +- drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h | 3 +- drivers/gpu/drm/amd/powerplay/navi10_ppt.c | 3 +- drivers/gpu/drm/amd/powerplay/smu_v11_0.c | 9 +- drivers/gpu/drm/amd/powerplay/vega20_ppt.c | 3 +- sound/pci/hda/hda_intel.c | 80 ++++++++++++- sound/pci/hda/patch_hdmi.c | 1 + 18 files changed, 366 insertions(+), 61 deletions(-)
BACO - Bus Active, Chip Off
Used to check whether the device supports BACO. This will be used to enable runtime pm on devices which support BACO.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 4eac1549d4de..d951907980b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -591,6 +591,8 @@ struct amdgpu_asic_funcs { bool (*need_reset_on_init)(struct amdgpu_device *adev); /* PCIe replay counter */ uint64_t (*get_pcie_replay_count)(struct amdgpu_device *adev); + /* device supports BACO */ + bool (*supports_baco)(struct amdgpu_device *adev); };
/* @@ -1121,6 +1123,8 @@ int emu_soc_asic_init(struct amdgpu_device *adev); #define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1))) #define amdgpu_asic_need_reset_on_init(adev) (adev)->asic_funcs->need_reset_on_init((adev)) #define amdgpu_asic_get_pcie_replay_count(adev) ((adev)->asic_funcs->get_pcie_replay_count((adev))) +#define amdgpu_asic_supports_baco(adev) (adev)->asic_funcs->supports_baco((adev)) + #define amdgpu_inc_vram_lost(adev) atomic_inc(&((adev)->vram_lost_counter));
/* Common functions */
BACO - Bus Active, Chip Off
Check the BACO capabilities from the powerplay table.
v2: drop unrelated struct cleanup
Reviewed-by: Evan Quan evan.quan@amd.com (v1) Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/soc15.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 305ad3eec987..1acbb38f6384 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -599,6 +599,28 @@ static int soc15_asic_reset(struct amdgpu_device *adev) } }
+static bool soc15_supports_baco(struct amdgpu_device *adev) +{ + bool baco_support; + + switch (adev->asic_type) { + case CHIP_VEGA10: + case CHIP_VEGA12: + soc15_asic_get_baco_capability(adev, &baco_support); + break; + case CHIP_VEGA20: + if (adev->psp.sos_fw_version >= 0x80067) + soc15_asic_get_baco_capability(adev, &baco_support); + else + baco_support = false; + break; + default: + return false; + } + + return baco_support; +} + /*static int soc15_set_uvd_clock(struct amdgpu_device *adev, u32 clock, u32 cntl_reg, u32 status_reg) { @@ -999,6 +1021,7 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs = .get_pcie_usage = &soc15_get_pcie_usage, .need_reset_on_init = &soc15_need_reset_on_init, .get_pcie_replay_count = &soc15_get_pcie_replay_count, + .supports_baco = &soc15_supports_baco, };
static const struct amdgpu_asic_funcs vega20_asic_funcs = @@ -1020,6 +1043,7 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs = .get_pcie_usage = &vega20_get_pcie_usage, .need_reset_on_init = &soc15_need_reset_on_init, .get_pcie_replay_count = &soc15_get_pcie_replay_count, + .supports_baco = &soc15_supports_baco, };
static int soc15_common_early_init(void *handle)
BACO - Bus Active, Chip Off
Not supported.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/si.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 29024e64c886..cb682d44737a 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1197,6 +1197,11 @@ static int si_asic_reset(struct amdgpu_device *adev) return 0; }
+static bool si_asic_supports_baco(struct amdgpu_device *adev) +{ + return false; +} + static enum amd_reset_method si_asic_reset_method(struct amdgpu_device *adev) { @@ -1425,6 +1430,7 @@ static const struct amdgpu_asic_funcs si_asic_funcs = .get_pcie_usage = &si_get_pcie_usage, .need_reset_on_init = &si_need_reset_on_init, .get_pcie_replay_count = &si_get_pcie_replay_count, + .supports_baco = &si_asic_supports_baco, };
static uint32_t si_get_rev_id(struct amdgpu_device *adev)
BACO - Bus Active, Chip Off
Check the BACO capabilities from the powerplay table.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/cik.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 2d64d270725d..968bc706b94d 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1310,6 +1310,23 @@ static int cik_asic_pci_config_reset(struct amdgpu_device *adev) return r; }
+static bool cik_asic_supports_baco(struct amdgpu_device *adev) +{ + bool baco_support; + + switch (adev->asic_type) { + case CHIP_BONAIRE: + case CHIP_HAWAII: + smu7_asic_get_baco_capability(adev, &baco_support); + break; + default: + baco_support = false; + break; + } + + return baco_support; +} + static enum amd_reset_method cik_asic_reset_method(struct amdgpu_device *adev) { @@ -1899,6 +1916,7 @@ static const struct amdgpu_asic_funcs cik_asic_funcs = .get_pcie_usage = &cik_get_pcie_usage, .need_reset_on_init = &cik_need_reset_on_init, .get_pcie_replay_count = &cik_get_pcie_replay_count, + .supports_baco = &cik_asic_supports_baco, };
static int cik_common_early_init(void *handle)
BACO - Bus Active, Chip Off
Check the BACO capabilities from the powerplay table.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/vi.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 78e5cdc0c058..871c0b8c6b0b 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -745,6 +745,27 @@ static int vi_asic_pci_config_reset(struct amdgpu_device *adev) return r; }
+static bool vi_asic_supports_baco(struct amdgpu_device *adev) +{ + bool baco_support; + + switch (adev->asic_type) { + case CHIP_FIJI: + case CHIP_TONGA: + case CHIP_POLARIS10: + case CHIP_POLARIS11: + case CHIP_POLARIS12: + case CHIP_TOPAZ: + smu7_asic_get_baco_capability(adev, &baco_support); + break; + default: + baco_support = false; + break; + } + + return baco_support; +} + static enum amd_reset_method vi_asic_reset_method(struct amdgpu_device *adev) { @@ -1116,6 +1137,7 @@ static const struct amdgpu_asic_funcs vi_asic_funcs = .get_pcie_usage = &vi_get_pcie_usage, .need_reset_on_init = &vi_need_reset_on_init, .get_pcie_replay_count = &vi_get_pcie_replay_count, + .supports_baco = &vi_asic_supports_baco, };
#define CZ_REV_BRISTOL(rev) \
BACO - Bus Active, Chip Off
Check the BACO capabilities from the powerplay table.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/nv.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 0ba66bef5746..b25b72a73048 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -314,6 +314,16 @@ static int nv_asic_mode1_reset(struct amdgpu_device *adev) return ret; }
+static bool nv_asic_supports_baco(struct amdgpu_device *adev) +{ + struct smu_context *smu = &adev->smu; + + if (smu_baco_is_support(smu)) + return true; + else + return false; +} + static enum amd_reset_method nv_asic_reset_method(struct amdgpu_device *adev) { @@ -617,6 +627,7 @@ static const struct amdgpu_asic_funcs nv_asic_funcs = .get_pcie_usage = &nv_get_pcie_usage, .need_reset_on_init = &nv_need_reset_on_init, .get_pcie_replay_count = &nv_get_pcie_replay_count, + .supports_baco = &nv_asic_supports_baco, };
static int nv_common_early_init(void *handle)
BACO - Bus Active, Chip Off
To check if a device supports BACO or not. This will be used in determining when to enable runtime pm.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index d951907980b1..6bc73fbd49fa 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1142,6 +1142,7 @@ void amdgpu_device_program_register_sequence(struct amdgpu_device *adev, const u32 array_size);
bool amdgpu_device_is_px(struct drm_device *dev); +bool amdgpu_device_supports_baco(struct drm_device *dev); bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, struct amdgpu_device *peer_adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 85c024b74d6d..e6dfc246e621 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -154,6 +154,21 @@ bool amdgpu_device_is_px(struct drm_device *dev) return false; }
+/** + * amdgpu_device_supports_baco - Does the device support BACO + * + * @dev: drm_device pointer + * + * Returns true if the device supporte BACO, + * otherwise return false. + */ +bool amdgpu_device_supports_baco(struct drm_device *dev) +{ + struct amdgpu_device *adev = dev->dev_private; + + return amdgpu_asic_supports_baco(adev); +} + /** * VRAM access helper functions. *
BACO - Bus Active, Chip Off BOCO - Bus Off, Chip Off
To better match what we are checking for and to align with amdgpu_device_supports_baco.
BOCO is used on PowerXpress/Hybrid Graphics systems and BACO is used on desktop dGPU boards.
v2: fix typo in documentation
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 8 ++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 8 ++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 6bc73fbd49fa..186135ea6033 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1141,7 +1141,7 @@ void amdgpu_device_program_register_sequence(struct amdgpu_device *adev, const u32 *registers, const u32 array_size);
-bool amdgpu_device_is_px(struct drm_device *dev); +bool amdgpu_device_supports_boco(struct drm_device *dev); bool amdgpu_device_supports_baco(struct drm_device *dev); bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, struct amdgpu_device *peer_adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index e6dfc246e621..45c196845497 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -138,14 +138,14 @@ static DEVICE_ATTR(pcie_replay_count, S_IRUGO, static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev);
/** - * amdgpu_device_is_px - Is the device is a dGPU with HG/PX power control + * amdgpu_device_supports_boco - Is the device a dGPU with HG/PX power control * * @dev: drm_device pointer * * Returns true if the device is a dGPU with HG/PX power control, * otherwise return false. */ -bool amdgpu_device_is_px(struct drm_device *dev) +bool amdgpu_device_supports_boco(struct drm_device *dev) { struct amdgpu_device *adev = dev->dev_private;
@@ -1091,7 +1091,7 @@ static void amdgpu_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero { struct drm_device *dev = pci_get_drvdata(pdev);
- if (amdgpu_device_is_px(dev) && state == VGA_SWITCHEROO_OFF) + if (amdgpu_device_supports_boco(dev) && state == VGA_SWITCHEROO_OFF) return;
if (state == VGA_SWITCHEROO_ON) { @@ -2914,7 +2914,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, * ignore it */ vga_client_register(adev->pdev, adev, NULL, amdgpu_device_vga_set_decode);
- if (amdgpu_device_is_px(ddev)) + if (amdgpu_device_supports_boco(ddev)) runtime = true; if (!pci_is_thunderbolt_attached(adev->pdev)) vga_switcheroo_register_client(adev->pdev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 5c2190558f69..bfd91cf9150b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1166,7 +1166,7 @@ static int amdgpu_pmops_resume(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev);
/* GPU comes up enabled by the bios on resume */ - if (amdgpu_device_is_px(drm_dev)) { + if (amdgpu_device_supports_boco(drm_dev)) { pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -1214,7 +1214,7 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) struct drm_device *drm_dev = pci_get_drvdata(pdev); int ret;
- if (!amdgpu_device_is_px(drm_dev)) { + if (!amdgpu_device_supports_boco(drm_dev)) { pm_runtime_forbid(dev); return -EBUSY; } @@ -1241,7 +1241,7 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) struct drm_device *drm_dev = pci_get_drvdata(pdev); int ret;
- if (!amdgpu_device_is_px(drm_dev)) + if (!amdgpu_device_supports_boco(drm_dev)) return -EINVAL;
drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; @@ -1266,7 +1266,7 @@ static int amdgpu_pmops_runtime_idle(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev); struct drm_crtc *crtc;
- if (!amdgpu_device_is_px(drm_dev)) { + if (!amdgpu_device_supports_boco(drm_dev)) { pm_runtime_forbid(dev); return -EBUSY; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 2d428ca45184..4093af6e575a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -91,7 +91,7 @@ void amdgpu_driver_unload_kms(struct drm_device *dev) if (amdgpu_sriov_vf(adev)) amdgpu_virt_request_full_gpu(adev, false);
- if (amdgpu_device_is_px(dev)) { + if (amdgpu_device_supports_boco(dev)) { pm_runtime_get_sync(dev->dev); pm_runtime_forbid(dev->dev); } @@ -180,7 +180,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) "Error during ACPI methods call\n"); }
- if (amdgpu_device_is_px(dev)) { + if (amdgpu_device_supports_boco(dev)) { dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NEVER_SKIP); pm_runtime_use_autosuspend(dev->dev); pm_runtime_set_autosuspend_delay(dev->dev, 5000); @@ -193,7 +193,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) out: if (r) { /* balance pm_runtime_get_sync in amdgpu_driver_unload_kms */ - if (adev->rmmio && amdgpu_device_is_px(dev)) + if (adev->rmmio && amdgpu_device_supports_boco(dev)) pm_runtime_put_noidle(dev->dev); amdgpu_driver_unload_kms(dev); }
BACO - Bus Active, Chip Off BOCO - Bus Off, Chip Off
We will take slightly different paths for boco and baco.
v2: fold together two consecutive if clauses
Reviewed-by: Evan Quan evan.quan@amd.com (v1) Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 47 ++++++++++++++----------- 1 file changed, 26 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index bfd91cf9150b..d05f8c03e559 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1219,18 +1219,21 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) return -EBUSY; }
- drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + if (amdgpu_device_supports_boco(drm_dev)) + drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(drm_dev);
ret = amdgpu_device_suspend(drm_dev, false, false); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_ignore_hotplug(pdev); - if (amdgpu_is_atpx_hybrid()) - pci_set_power_state(pdev, PCI_D3cold); - else if (!amdgpu_has_atpx_dgpu_power_cntl()) - pci_set_power_state(pdev, PCI_D3hot); - drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; + if (amdgpu_device_supports_boco(drm_dev)) { + pci_save_state(pdev); + pci_disable_device(pdev); + pci_ignore_hotplug(pdev); + if (amdgpu_is_atpx_hybrid()) + pci_set_power_state(pdev, PCI_D3cold); + else if (!amdgpu_has_atpx_dgpu_power_cntl()) + pci_set_power_state(pdev, PCI_D3hot); + drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; + }
return 0; } @@ -1244,20 +1247,22 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) if (!amdgpu_device_supports_boco(drm_dev)) return -EINVAL;
- drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; - - if (amdgpu_is_atpx_hybrid() || - !amdgpu_has_atpx_dgpu_power_cntl()) - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) - return ret; - pci_set_master(pdev); - + if (amdgpu_device_supports_boco(drm_dev)) { + drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; + + if (amdgpu_is_atpx_hybrid() || + !amdgpu_has_atpx_dgpu_power_cntl()) + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) + return ret; + pci_set_master(pdev); + } ret = amdgpu_device_resume(drm_dev, false, false); drm_kms_helper_poll_enable(drm_dev); - drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; + if (amdgpu_device_supports_boco(drm_dev)) + drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; return 0; }
BACO - Bus Active, Chip Off
So we can use it for power savings rather than just reset.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/nv.c | 7 ++++++- drivers/gpu/drm/amd/amdgpu/soc15.c | 10 ++++++++-- drivers/gpu/drm/amd/powerplay/amdgpu_smu.c | 20 ++++++++++++++++--- drivers/gpu/drm/amd/powerplay/arcturus_ppt.c | 3 ++- .../gpu/drm/amd/powerplay/inc/amdgpu_smu.h | 6 ++++-- drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h | 3 ++- drivers/gpu/drm/amd/powerplay/navi10_ppt.c | 3 ++- drivers/gpu/drm/amd/powerplay/smu_v11_0.c | 9 ++++++++- drivers/gpu/drm/amd/powerplay/vega20_ppt.c | 3 ++- 9 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index b25b72a73048..7b19a8381675 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -352,7 +352,12 @@ static int nv_asic_reset(struct amdgpu_device *adev) if (nv_asic_reset_method(adev) == AMD_RESET_METHOD_BACO) { if (!adev->in_suspend) amdgpu_inc_vram_lost(adev); - ret = smu_baco_reset(smu); + ret = smu_baco_enter(smu); + if (ret) + return ret; + ret = smu_baco_exit(smu); + if (ret) + return ret; } else { if (!adev->in_suspend) amdgpu_inc_vram_lost(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 1acbb38f6384..3e37a3af59eb 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -509,9 +509,15 @@ static int soc15_asic_baco_reset(struct amdgpu_device *adev)
if (is_support_sw_smu(adev)) { struct smu_context *smu = &adev->smu; + int ret;
- if (smu_baco_reset(smu)) - return -EIO; + ret = smu_baco_enter(smu); + if (ret) + return ret; + + ret = smu_baco_exit(smu); + if (ret) + return ret; } else { void *pp_handle = adev->powerplay.pp_handle; const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c index 753c1afcfaa3..356be22910db 100644 --- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c @@ -2428,14 +2428,28 @@ int smu_baco_get_state(struct smu_context *smu, enum smu_baco_state *state) return 0; }
-int smu_baco_reset(struct smu_context *smu) +int smu_baco_enter(struct smu_context *smu) { int ret = 0;
mutex_lock(&smu->mutex);
- if (smu->ppt_funcs->baco_reset) - ret = smu->ppt_funcs->baco_reset(smu); + if (smu->ppt_funcs->baco_enter) + ret = smu->ppt_funcs->baco_enter(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_baco_exit(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->baco_exit) + ret = smu->ppt_funcs->baco_exit(smu);
mutex_unlock(&smu->mutex);
diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c index 58c7c4a3053e..f251e402147c 100644 --- a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c @@ -2156,7 +2156,8 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .baco_is_support= smu_v11_0_baco_is_support, .baco_get_state = smu_v11_0_baco_get_state, .baco_set_state = smu_v11_0_baco_set_state, - .baco_reset = smu_v11_0_baco_reset, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, .override_pcie_parameters = smu_v11_0_override_pcie_parameters, diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h index 999445c5c010..725acd6d5e00 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h @@ -542,7 +542,8 @@ struct pptable_funcs { bool (*baco_is_support)(struct smu_context *smu); enum smu_baco_state (*baco_get_state)(struct smu_context *smu); int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state); - int (*baco_reset)(struct smu_context *smu); + int (*baco_enter)(struct smu_context *smu); + int (*baco_exit)(struct smu_context *smu); int (*mode2_reset)(struct smu_context *smu); int (*get_dpm_ultimate_freq)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max); int (*set_soft_freq_limited_range)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max); @@ -624,7 +625,8 @@ bool smu_baco_is_support(struct smu_context *smu);
int smu_baco_get_state(struct smu_context *smu, enum smu_baco_state *state);
-int smu_baco_reset(struct smu_context *smu); +int smu_baco_enter(struct smu_context *smu); +int smu_baco_exit(struct smu_context *smu);
int smu_mode2_reset(struct smu_context *smu);
diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h index 606149085683..5a277136f2aa 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h @@ -248,7 +248,8 @@ enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu);
int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state);
-int smu_v11_0_baco_reset(struct smu_context *smu); +int smu_v11_0_baco_enter(struct smu_context *smu); +int smu_v11_0_baco_exit(struct smu_context *smu);
int smu_v11_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max); diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c index 14be350a6127..f843ecb09db6 100644 --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c @@ -2064,7 +2064,8 @@ static const struct pptable_funcs navi10_ppt_funcs = { .baco_is_support= smu_v11_0_baco_is_support, .baco_get_state = smu_v11_0_baco_get_state, .baco_set_state = smu_v11_0_baco_set_state, - .baco_reset = smu_v11_0_baco_reset, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, .override_pcie_parameters = smu_v11_0_override_pcie_parameters, diff --git a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c index fc9679ea2368..6071510ed206 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c +++ b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c @@ -1688,7 +1688,7 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) return ret; }
-int smu_v11_0_baco_reset(struct smu_context *smu) +int smu_v11_0_baco_enter(struct smu_context *smu) { int ret = 0;
@@ -1702,6 +1702,13 @@ int smu_v11_0_baco_reset(struct smu_context *smu)
msleep(10);
+ return ret; +} + +int smu_v11_0_baco_exit(struct smu_context *smu) +{ + int ret = 0; + ret = smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_EXIT); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c index 0b4892833808..02ede5c8b73a 100644 --- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c @@ -3257,7 +3257,8 @@ static const struct pptable_funcs vega20_ppt_funcs = { .baco_is_support= smu_v11_0_baco_is_support, .baco_get_state = smu_v11_0_baco_get_state, .baco_set_state = smu_v11_0_baco_set_state, - .baco_reset = smu_v11_0_baco_reset, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, .override_pcie_parameters = smu_v11_0_override_pcie_parameters,
BACO - Bus Active, Chip Off
Will be used for runtime pm. Entry will enter the BACO state (chip off). Exit will exit the BACO state (chip on).
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 61 ++++++++++++++++++++++ 2 files changed, 63 insertions(+)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 186135ea6033..64bc5771b34f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1145,6 +1145,8 @@ bool amdgpu_device_supports_boco(struct drm_device *dev); bool amdgpu_device_supports_baco(struct drm_device *dev); bool amdgpu_device_is_peer_accessible(struct amdgpu_device *adev, struct amdgpu_device *peer_adev); +int amdgpu_device_baco_enter(struct drm_device *dev); +int amdgpu_device_baco_exit(struct drm_device *dev);
/* atpx handler */ #if defined(CONFIG_VGA_SWITCHEROO) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 45c196845497..7195ef83ddba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4299,3 +4299,64 @@ static void amdgpu_device_get_pcie_info(struct amdgpu_device *adev) } }
+int amdgpu_device_baco_enter(struct drm_device *dev) +{ + struct amdgpu_device *adev = dev->dev_private; + + if (!amdgpu_device_supports_baco(adev->ddev)) + return -ENOTSUPP; + + if (is_support_sw_smu(adev)) { + struct smu_context *smu = &adev->smu; + int ret; + + ret = smu_baco_enter(smu); + if (ret) + return ret; + + return 0; + } else { + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs ||!pp_funcs->get_asic_baco_state ||!pp_funcs->set_asic_baco_state) + return -ENOENT; + + /* enter BACO state */ + if (pp_funcs->set_asic_baco_state(pp_handle, 1)) + return -EIO; + + return 0; + } +} + +int amdgpu_device_baco_exit(struct drm_device *dev) +{ + struct amdgpu_device *adev = dev->dev_private; + + if (!amdgpu_device_supports_baco(adev->ddev)) + return -ENOTSUPP; + + if (is_support_sw_smu(adev)) { + struct smu_context *smu = &adev->smu; + int ret; + + ret = smu_baco_exit(smu); + if (ret) + return ret; + + return 0; + } else { + void *pp_handle = adev->powerplay.pp_handle; + const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; + + if (!pp_funcs ||!pp_funcs->get_asic_baco_state ||!pp_funcs->set_asic_baco_state) + return -ENOENT; + + /* exit BACO state */ + if (pp_funcs->set_asic_baco_state(pp_handle, 0)) + return -EIO; + + return 0; + } +}
BACO - Bus Active, Chip Off
This adds the necessary support to the runtime suspend and resume functions to handle boards that support baco.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index d05f8c03e559..7b5437a87b01 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1166,7 +1166,8 @@ static int amdgpu_pmops_resume(struct device *dev) struct drm_device *drm_dev = dev_get_drvdata(dev);
/* GPU comes up enabled by the bios on resume */ - if (amdgpu_device_supports_boco(drm_dev)) { + if (amdgpu_device_supports_boco(drm_dev) || + amdgpu_device_supports_baco(drm_dev)) { pm_runtime_disable(dev); pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -1233,6 +1234,8 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) else if (!amdgpu_has_atpx_dgpu_power_cntl()) pci_set_power_state(pdev, PCI_D3hot); drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; + } else if (amdgpu_device_supports_baco(drm_dev)) { + amdgpu_device_baco_enter(drm_dev); }
return 0; @@ -1258,6 +1261,8 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) if (ret) return ret; pci_set_master(pdev); + } else if (amdgpu_device_supports_baco(drm_dev)) { + amdgpu_device_baco_exit(drm_dev); } ret = amdgpu_device_resume(drm_dev, false, false); drm_kms_helper_poll_enable(drm_dev);
BACO - Bus Active, Chip Off BOCO - Bus Off, Chip Off
We originally only supported runtime pm on PX/HG laptops so most of the runtime pm code looks for this. Add a new flag to check for runtime pm enablement and use this rather than checking for PX/HG.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 ++ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 9 ++++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 13 ++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 64bc5771b34f..8f6c995fd2ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -988,6 +988,8 @@ struct amdgpu_device {
/* device pstate */ int pstate; + /* enable runtime pm on the device */ + bool runpm; };
static inline struct amdgpu_device *amdgpu_ttm_adev(struct ttm_bo_device *bdev) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 7b5437a87b01..ea763bc5b233 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -1213,9 +1213,10 @@ static int amdgpu_pmops_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct amdgpu_device *adev = drm_dev->dev_private; int ret;
- if (!amdgpu_device_supports_boco(drm_dev)) { + if (!adev->runpm) { pm_runtime_forbid(dev); return -EBUSY; } @@ -1245,9 +1246,10 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); + struct amdgpu_device *adev = drm_dev->dev_private; int ret;
- if (!amdgpu_device_supports_boco(drm_dev)) + if (!adev->runpm) return -EINVAL;
if (amdgpu_device_supports_boco(drm_dev)) { @@ -1274,9 +1276,10 @@ static int amdgpu_pmops_runtime_resume(struct device *dev) static int amdgpu_pmops_runtime_idle(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_dev->dev_private; struct drm_crtc *crtc;
- if (!amdgpu_device_supports_boco(drm_dev)) { + if (!adev->runpm) { pm_runtime_forbid(dev); return -EBUSY; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 4093af6e575a..89b021c54b93 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -91,7 +91,7 @@ void amdgpu_driver_unload_kms(struct drm_device *dev) if (amdgpu_sriov_vf(adev)) amdgpu_virt_request_full_gpu(adev, false);
- if (amdgpu_device_supports_boco(dev)) { + if (adev->runpm) { pm_runtime_get_sync(dev->dev); pm_runtime_forbid(dev->dev); } @@ -150,14 +150,17 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) } dev->dev_private = (void *)adev;
- if ((amdgpu_runtime_pm != 0) && - amdgpu_has_atpx() && + if (amdgpu_has_atpx() && (amdgpu_is_atpx_hybrid() || amdgpu_has_atpx_dgpu_power_cntl()) && ((flags & AMD_IS_APU) == 0) && !pci_is_thunderbolt_attached(dev->pdev)) flags |= AMD_IS_PX;
+ if ((amdgpu_runtime_pm != 0) && + (flags & AMD_IS_PX)) + adev->runpm = true; + /* amdgpu_device_init should report only fatal error * like memory allocation failure or iomapping failure, * or memory manager initialization failure, it must @@ -180,7 +183,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) "Error during ACPI methods call\n"); }
- if (amdgpu_device_supports_boco(dev)) { + if (adev->runpm) { dev_pm_set_driver_flags(dev->dev, DPM_FLAG_NEVER_SKIP); pm_runtime_use_autosuspend(dev->dev); pm_runtime_set_autosuspend_delay(dev->dev, 5000); @@ -193,7 +196,7 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) out: if (r) { /* balance pm_runtime_get_sync in amdgpu_driver_unload_kms */ - if (adev->rmmio && amdgpu_device_supports_boco(dev)) + if (adev->rmmio && adev->runpm) pm_runtime_put_noidle(dev->dev); amdgpu_driver_unload_kms(dev); }
Originally we only supported runtime pm on PX/HG laptops so vga_switcheroo and runtime pm are sort of entangled.
Attempt to logically separate them.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 7195ef83ddba..f48c4898e31a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2744,7 +2744,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, uint32_t flags) { int r, i; - bool runtime = false; + bool boco = false; u32 max_MBps;
adev->shutdown = false; @@ -2915,11 +2915,14 @@ int amdgpu_device_init(struct amdgpu_device *adev, vga_client_register(adev->pdev, adev, NULL, amdgpu_device_vga_set_decode);
if (amdgpu_device_supports_boco(ddev)) - runtime = true; - if (!pci_is_thunderbolt_attached(adev->pdev)) + boco = true; + if (amdgpu_has_atpx() && + (amdgpu_is_atpx_hybrid() || + amdgpu_has_atpx_dgpu_power_cntl()) && + !pci_is_thunderbolt_attached(adev->pdev)) vga_switcheroo_register_client(adev->pdev, - &amdgpu_switcheroo_ops, runtime); - if (runtime) + &amdgpu_switcheroo_ops, boco); + if (boco) vga_switcheroo_init_domain_pm_ops(adev->dev, &adev->vga_pm_domain);
if (amdgpu_emu_mode == 1) { @@ -3103,7 +3106,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
failed: amdgpu_vf_error_trans_all(adev); - if (runtime) + if (boco) vga_switcheroo_fini_domain_pm_ops(adev->dev);
return r; @@ -3153,9 +3156,12 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
kfree(adev->bios); adev->bios = NULL; - if (!pci_is_thunderbolt_attached(adev->pdev)) + if (amdgpu_has_atpx() && + (amdgpu_is_atpx_hybrid() || + amdgpu_has_atpx_dgpu_power_cntl()) && + !pci_is_thunderbolt_attached(adev->pdev)) vga_switcheroo_unregister_client(adev->pdev); - if (adev->flags & AMD_IS_PX) + if (amdgpu_device_supports_boco(adev->ddev)) vga_switcheroo_fini_domain_pm_ops(adev->dev); vga_client_register(adev->pdev, NULL, NULL, NULL); if (adev->rio_mem)
BACO - Bus Active, Chip Off
Everything is in place now. Not enabled by default yet. You still have to specify runpm=1.
Reviewed-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 89b021c54b93..169db941f933 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -157,10 +157,6 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) !pci_is_thunderbolt_attached(dev->pdev)) flags |= AMD_IS_PX;
- if ((amdgpu_runtime_pm != 0) && - (flags & AMD_IS_PX)) - adev->runpm = true; - /* amdgpu_device_init should report only fatal error * like memory allocation failure or iomapping failure, * or memory manager initialization failure, it must @@ -173,6 +169,13 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) goto out; }
+ if (amdgpu_device_supports_boco(dev) && + (amdgpu_runtime_pm != 0)) /* enable runpm by default */ + adev->runpm = true; + else if (amdgpu_device_supports_baco(dev) && + (amdgpu_runtime_pm > 0)) /* enable runpm if runpm=1 */ + adev->runpm = true; + /* Call ACPI methods: require modeset init * but failure is not fatal */
BACO - Bus Active, Chip Off
Works reliably on VI, vega.
v2: don't enable on navi yet.
Reviewed-by: Evan Quan evan.quan@amd.com (v1) Signed-off-by: Alex Deucher alexander.deucher@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 169db941f933..0c122ff2a7d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -170,10 +170,15 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) }
if (amdgpu_device_supports_boco(dev) && - (amdgpu_runtime_pm != 0)) /* enable runpm by default */ + (amdgpu_runtime_pm != 0)) /* enable runpm by default for boco */ adev->runpm = true; else if (amdgpu_device_supports_baco(dev) && - (amdgpu_runtime_pm > 0)) /* enable runpm if runpm=1 */ + (amdgpu_runtime_pm != 0) && + (adev->asic_type >= CHIP_TOPAZ) && + (adev->asic_type <= CHIP_VEGA20)) /* enable runpm by default on VI, vega */ + adev->runpm = true; + else if (amdgpu_device_supports_baco(dev) && + (amdgpu_runtime_pm > 0)) /* enable runpm if runpm=1 on CI, NV */ adev->runpm = true;
/* Call ACPI methods: require modeset init
Only enable the vga_switcheroo logic on systems with the ATPX ACPI method. This logic is not needed for asics that are not part of a PX (PowerXpress)/HG (Hybrid Graphics) platform.
Reviewed-by: Takashi Iwai tiwai@suse.de Acked-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/pci/hda/hda_intel.c | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 240f4ca76391..3ebc7b2a897f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -35,6 +35,7 @@ #include <linux/clocksource.h> #include <linux/time.h> #include <linux/completion.h> +#include <linux/acpi.h>
#ifdef CONFIG_X86 /* for snoop control */ @@ -1393,6 +1394,34 @@ static int azx_dev_free(struct snd_device *device) }
#ifdef SUPPORT_VGA_SWITCHEROO +#ifdef CONFIG_ACPI +/* ATPX is in the integrated GPU's namespace */ +static bool atpx_present(void) +{ + struct pci_dev *pdev = NULL; + acpi_handle dhandle, atpx_handle; + acpi_status status; + + while ((pdev = pci_get_class(PCI_BASE_CLASS_DISPLAY << 16, pdev)) != NULL) { + dhandle = ACPI_HANDLE(&pdev->dev); + if (dhandle) { + status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); + if (!ACPI_FAILURE(status)) { + pci_dev_put(pdev); + return true; + } + } + pci_dev_put(pdev); + } + return false; +} +#else +static bool atpx_present(void) +{ + return false; +} +#endif + /* * Check of disabled HDMI controller by vga_switcheroo */ @@ -1404,6 +1433,22 @@ static struct pci_dev *get_bound_vga(struct pci_dev *pci) switch (pci->vendor) { case PCI_VENDOR_ID_ATI: case PCI_VENDOR_ID_AMD: + if (pci->devfn == 1) { + p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus), + pci->bus->number, 0); + if (p) { + /* ATPX is in the integrated GPU's ACPI namespace + * rather than the dGPU's namespace. However, + * the dGPU is the one who is involved in + * vgaswitcheroo. + */ + if (((p->class >> 16) == PCI_BASE_CLASS_DISPLAY) && + atpx_present()) + return p; + pci_dev_put(p); + } + } + break; case PCI_VENDOR_ID_NVIDIA: if (pci->devfn == 1) { p = pci_get_domain_bus_and_slot(pci_domain_nr(pci->bus),
These are needed so we can enable runtime pm in a subsequent patch.
Reviewed-by: Takashi Iwai tiwai@suse.de Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/pci/hda/hda_intel.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3ebc7b2a897f..79ca97d6c811 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2606,6 +2606,20 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, { PCI_DEVICE(0x1002, 0xaaf0), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + { PCI_DEVICE(0x1002, 0xaaf8), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + { PCI_DEVICE(0x1002, 0xab00), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + { PCI_DEVICE(0x1002, 0xab08), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + { PCI_DEVICE(0x1002, 0xab10), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + { PCI_DEVICE(0x1002, 0xab18), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + { PCI_DEVICE(0x1002, 0xab20), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + { PCI_DEVICE(0x1002, 0xab38), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, /* VIA VT8251/VT8237A */ { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, /* VIA GFX VT7122/VX900 */
We are able to power down the GPU and audio via the GPU driver so flag these asics as supporting runtime pm.
Reviewed-by: Takashi Iwai tiwai@suse.de Acked-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/pci/hda/hda_intel.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-)
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 79ca97d6c811..111b9a869162 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2599,27 +2599,38 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x1002, 0xaac8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, { PCI_DEVICE(0x1002, 0xaad8), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, - { PCI_DEVICE(0x1002, 0xaae8), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xaae0), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, + { PCI_DEVICE(0x1002, 0xaae8), + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xaaf0), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xaaf8), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xab00), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xab08), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xab10), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xab18), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xab20), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, { PCI_DEVICE(0x1002, 0xab38), - .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, + .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS | + AZX_DCAPS_PM_RUNTIME }, /* VIA VT8251/VT8237A */ { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, /* VIA GFX VT7122/VX900 */
So that we can power down the GPU and audio to save power.
Reviewed-by: Takashi Iwai tiwai@suse.de Acked-by: Evan Quan evan.quan@amd.com Signed-off-by: Alex Deucher alexander.deucher@amd.com --- sound/pci/hda/patch_hdmi.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 795cbda32cbb..8785fcc850b9 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -3961,6 +3961,7 @@ static int atihdmi_init(struct hda_codec *codec) ATI_VERB_SET_MULTICHANNEL_MODE, ATI_MULTICHANNEL_MODE_SINGLE); } + codec->auto_runtime_pm = 1;
return 0; }
participants (1)
-
Alex Deucher