From 05d3b9eb053b8deb2575b5fa72ab55cb5a506371 Mon Sep 17 00:00:00 2001 From: Scott B Date: Thu, 17 Feb 2022 06:34:33 -0800 Subject: [PATCH] v5.16.10 s0ix patch 2022-02-17 Squashed commit of the following: commit 3998be5da29cb360b589c1293e43a9dc37d6c383 Author: Rajib Mahapatra Date: Thu Feb 10 19:05:07 2022 +0530 drm/amdgpu: skipping SDMA hw_init and hw_fini for S0ix. [Why] SDMA ring buffer test failed if suspend is aborted during S0i3 resume. [How] If suspend is aborted for some reason during S0i3 resume cycle, it follows SDMA ring test failing and errors in amdgpu resume. For RN/CZN/Picasso, SMU saves and restores SDMA registers during S0ix cycle. So, skipping SDMA suspend and resume from driver solves the issue. This time, the system is able to resume gracefully even the suspend is aborted. v2: add changes on sdma_v4, skipping SDMA hw_init and hw_fini. Signed-off-by: Rajib Mahapatra Reviewed-by: Mario Limonciello Reviewed-by: Alex Deucher commit 2952523c1a30d751d8de445a610310a52381152f Author: Mario Limonciello Date: Tue Jan 11 14:00:26 2022 -0600 drm/amd: Warn users about potential s0ix problems On some OEM setups users can configure the BIOS for S3 or S2idle. When configured to S3 users can still choose 's2idle' in the kernel by using `/sys/power/mem_sleep`. Before commit 6dc8265f9803 ("drm/amdgpu: always reset the asic in suspend (v2)"), the GPU would crash. Now when configured this way, the system should resume but will use more power. As such, adjust the `amdpu_acpi_is_s0ix function` to warn users about potential power consumption issues during their first attempt at suspending. Reported-by: Bjoren Dasse Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1824 Reviewed-by: Alex Deucher Signed-off-by: Mario Limonciello Signed-off-by: Alex Deucher commit e5bb891a29ae0037169b0248d1f72b75947a1e49 Author: Mario Limonciello Date: Thu Jan 20 11:44:39 2022 -0600 platform/x86: amd-pmc: Correct usage of SMU version Yellow carp has been outputting versions like `1093.24.0`, but this is supposed to be 69.24.0. That is the MSB is being interpreted incorrectly. The MSB is not part of the major version, but has generally been treated that way thus far. It's actually the program, and used to distinguish between two programs from a similar family but different codebase. Link: https://patchwork.freedesktop.org/patch/469993/ Signed-off-by: Mario Limonciello commit 5408afca1aebd7a772de1d55015bfa81fcf0ef2f Author: Hans de Goede Date: Mon Jan 17 12:26:43 2022 +0100 platform/x86: amd-pmc: Make amd_pmc_stb_debugfs_fops static amd_pmc_stb_debugfs_fops is not used outside of amd-pmc.c, make it static. Cc: Sanket Goswami Reported-by: kernel test robot Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220117112644.260168-1-hdegoede@redhat.com commit 1137ab8b2c29e8c2e21e6cebe8266f7e453d7892 Author: Sanket Goswami Date: Tue Nov 30 16:53:18 2021 +0530 platform/x86: amd-pmc: Add support for AMD Smart Trace Buffer (v6) STB (Smart Trace Buffer), is a debug trace buffer that isolates the failures by analyzing the last running feature of a system. This non-intrusive way always runs in the background and stores the trace into the SoC. This patch enables the STB feature by passing module param "enable_stb=1" while loading the driver and provides mechanism to access the STB buffer using the read and write routines. Co-developed-by: Shyam Sundar S K Signed-off-by: Shyam Sundar S K Signed-off-by: Sanket Goswami commit 014563cdf9fe0eebf7586e944ac94a9bb13c2043 Author: Sanket Goswami Date: Tue Nov 30 16:53:17 2021 +0530 platform/x86: amd-pmc: Simplify error handling and store the pci_dev in amd_pmc_dev structure Handle error-exits in the amd_pmc_probe() to avoid duplication and store the root port information in amd_pmc_probe() so that the information can be used across multiple routines. Suggested-by: Hans de Goede Signed-off-by: Sanket Goswami commit a4182b0fa24e12de590530feb36beddcdc93c20f Author: Lijo Lazar Date: Thu Nov 25 19:45:42 2021 +0800 drm/amd/pm: Add warning for unexpected PG requests v1: Ideally power gate/ungate requests shouldn't come when smu block is uninitialized. Add a WARN message to check the origins if such a thing ever happens. v2: Use dev_WARN to log device info (Felix/Guchun). Signed-off-by: Lijo Lazar Reviewed-by: Guchun Chen Reviewed-by: Kevin Yang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 8 +- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 24 ++- drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c | 8 + drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 6 +- drivers/platform/x86/amd-pmc.c | 185 +++++++++++++++++++--- 5 files changed, 203 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 7d67aec6f4a2..0a5a5370a200 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1406,12 +1406,10 @@ int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_sta int amdgpu_acpi_pcie_notify_device_ready(struct amdgpu_device *adev); void amdgpu_acpi_get_backlight_caps(struct amdgpu_dm_backlight_caps *caps); -bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev); void amdgpu_acpi_detect(void); #else static inline int amdgpu_acpi_init(struct amdgpu_device *adev) { return 0; } static inline void amdgpu_acpi_fini(struct amdgpu_device *adev) { } -static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; } static inline void amdgpu_acpi_detect(void) { } static inline bool amdgpu_acpi_is_power_shift_control_supported(void) { return false; } static inline int amdgpu_acpi_power_shift_control(struct amdgpu_device *adev, @@ -1420,6 +1418,12 @@ static inline int amdgpu_acpi_smart_shift_update(struct drm_device *dev, enum amdgpu_ss ss_state) { return 0; } #endif +#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND) +bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev); +#else +static inline bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { return false; } +#endif + int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser, uint64_t addr, struct amdgpu_bo **bo, struct amdgpu_bo_va_mapping **mapping); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 4811b0faafd9..b19d40751802 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -1031,6 +1031,7 @@ void amdgpu_acpi_detect(void) } } +#if IS_ENABLED(CONFIG_SUSPEND) /** * amdgpu_acpi_is_s0ix_active * @@ -1040,11 +1041,24 @@ void amdgpu_acpi_detect(void) */ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev) { -#if IS_ENABLED(CONFIG_AMD_PMC) && IS_ENABLED(CONFIG_SUSPEND) - if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) { - if (adev->flags & AMD_IS_APU) - return pm_suspend_target_state == PM_SUSPEND_TO_IDLE; + if (!(adev->flags & AMD_IS_APU) || + (pm_suspend_target_state != PM_SUSPEND_TO_IDLE)) + return false; + + if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) { + dev_warn_once(adev->dev, + "Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n" + "To use suspend-to-idle change the sleep mode in BIOS setup.\n"); + return false; } -#endif + +#if !IS_ENABLED(CONFIG_AMD_PMC) + dev_warn_once(adev->dev, + "Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n"); return false; +#else + return true; +#endif /* CONFIG_AMD_PMC */ } + +#endif /* CONFIG_SUSPEND */ diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c index e8e4749e9c79..f0638db57111 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c @@ -2057,6 +2057,10 @@ static int sdma_v4_0_suspend(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + /* SMU saves SDMA state for us */ + if (adev->in_s0ix) + return 0; + return sdma_v4_0_hw_fini(adev); } @@ -2064,6 +2068,10 @@ static int sdma_v4_0_resume(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + /* SMU restores SDMA state for us */ + if (adev->in_s0ix) + return 0; + return sdma_v4_0_hw_init(adev); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 9d7d64fdf410..8a05b28f7365 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -277,8 +277,12 @@ static int smu_dpm_set_power_gate(void *handle, struct smu_context *smu = handle; int ret = 0; - if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) { + dev_WARN(smu->adev->dev, + "SMU uninitialized but power %s requested for %u!\n", + gate ? "gate" : "ungate", block_type); return -EOPNOTSUPP; + } switch (block_type) { /* diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c index 230593ae5d6d..61cb1d05158e 100644 --- a/drivers/platform/x86/amd-pmc.c +++ b/drivers/platform/x86/amd-pmc.c @@ -35,6 +35,12 @@ #define AMD_PMC_SCRATCH_REG_CZN 0x94 #define AMD_PMC_SCRATCH_REG_YC 0xD14 +/* STB Registers */ +#define AMD_PMC_STB_INDEX_ADDRESS 0xF8 +#define AMD_PMC_STB_INDEX_DATA 0xFC +#define AMD_PMC_STB_PMI_0 0x03E30600 +#define AMD_PMC_STB_PREDEF 0xC6000001 + /* Base address of SMU for mapping physical address to virtual address */ #define AMD_PMC_SMU_INDEX_ADDRESS 0xB8 #define AMD_PMC_SMU_INDEX_DATA 0xBC @@ -82,6 +88,7 @@ #define SOC_SUBSYSTEM_IP_MAX 12 #define DELAY_MIN_US 2000 #define DELAY_MAX_US 3000 +#define FIFO_SIZE 4096 enum amd_pmc_def { MSG_TEST = 0x01, MSG_OS_HINT_PCO, @@ -117,18 +124,26 @@ struct amd_pmc_dev { u32 cpu_id; u32 active_ips; /* SMU version information */ - u16 major; - u16 minor; - u16 rev; + u8 smu_program; + u8 major; + u8 minor; + u8 rev; struct device *dev; + struct pci_dev *rdev; struct mutex lock; /* generic mutex lock */ #if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *dbgfs_dir; #endif /* CONFIG_DEBUG_FS */ }; +static bool enable_stb; +module_param(enable_stb, bool, 0644); +MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism"); + static struct amd_pmc_dev pmc; static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret); +static int amd_pmc_write_stb(struct amd_pmc_dev *dev, u32 data); +static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf); static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset) { @@ -166,15 +181,61 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev) if (rc) return rc; - dev->major = (val >> 16) & GENMASK(15, 0); + dev->smu_program = (val >> 24) & GENMASK(7, 0); + dev->major = (val >> 16) & GENMASK(7, 0); dev->minor = (val >> 8) & GENMASK(7, 0); dev->rev = (val >> 0) & GENMASK(7, 0); - dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev); + dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n", + dev->smu_program, dev->major, dev->minor, dev->rev); return 0; } +static int amd_pmc_stb_debugfs_open(struct inode *inode, struct file *filp) +{ + struct amd_pmc_dev *dev = filp->f_inode->i_private; + u32 size = FIFO_SIZE * sizeof(u32); + u32 *buf; + int rc; + + buf = kzalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + rc = amd_pmc_read_stb(dev, buf); + if (rc) { + kfree(buf); + return rc; + } + + filp->private_data = buf; + return rc; +} + +static ssize_t amd_pmc_stb_debugfs_read(struct file *filp, char __user *buf, size_t size, + loff_t *pos) +{ + if (!filp->private_data) + return -EINVAL; + + return simple_read_from_buffer(buf, size, pos, filp->private_data, + FIFO_SIZE * sizeof(u32)); +} + +static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp) +{ + kfree(filp->private_data); + return 0; +} + +static const struct file_operations amd_pmc_stb_debugfs_fops = { + .owner = THIS_MODULE, + .open = amd_pmc_stb_debugfs_open, + .read = amd_pmc_stb_debugfs_read, + .release = amd_pmc_stb_debugfs_release, +}; + static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, struct seq_file *s) { @@ -288,6 +349,10 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) &s0ix_stats_fops); debugfs_create_file("amd_pmc_idlemask", 0644, dev->dbgfs_dir, dev, &amd_pmc_idlemask_fops); + /* Enable STB only when the module_param is set */ + if (enable_stb) + debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, + &amd_pmc_stb_debugfs_fops); } #else static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) @@ -484,6 +549,13 @@ static int __maybe_unused amd_pmc_suspend(struct device *dev) if (rc) dev_err(pdev->dev, "suspend failed\n"); + if (enable_stb) + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF); + if (rc) { + dev_err(pdev->dev, "error writing to STB\n"); + return rc; + } + return rc; } @@ -504,6 +576,14 @@ static int __maybe_unused amd_pmc_resume(struct device *dev) /* Dump the IdleMask to see the blockers */ amd_pmc_idlemask_read(pdev, dev, NULL); + /* Write data incremented by 1 to distinguish in stb_read */ + if (enable_stb) + rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF + 1); + if (rc) { + dev_err(pdev->dev, "error writing to STB\n"); + return rc; + } + return 0; } @@ -521,6 +601,62 @@ static const struct pci_device_id pmc_pci_ids[] = { { } }; +static int amd_pmc_write_stb(struct amd_pmc_dev *dev, u32 data) +{ + int err; + + err = pci_write_config_dword(dev->rdev, AMD_PMC_STB_INDEX_ADDRESS, AMD_PMC_STB_PMI_0); + if (err) { + dev_err(dev->dev, "failed to write addr in stb: 0x%X\n", + AMD_PMC_STB_INDEX_ADDRESS); + err = pcibios_err_to_errno(err); + goto err_pci_dev_put; + } + + err = pci_write_config_dword(dev->rdev, AMD_PMC_STB_INDEX_DATA, data); + if (err) { + dev_err(dev->dev, "failed to write data in stb: 0x%X\n", + AMD_PMC_STB_INDEX_DATA); + err = pcibios_err_to_errno(err); + goto err_pci_dev_put; + } + + return 0; + +err_pci_dev_put: + pci_dev_put(dev->rdev); + return err; +} + +static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf) +{ + int i, err; + + err = pci_write_config_dword(dev->rdev, AMD_PMC_STB_INDEX_ADDRESS, AMD_PMC_STB_PMI_0); + if (err) { + dev_err(dev->dev, "error writing addr to stb: 0x%X\n", + AMD_PMC_STB_INDEX_ADDRESS); + err = pcibios_err_to_errno(err); + goto err_pci_dev_put; + } + + for (i = 0; i < FIFO_SIZE; i++) { + err = pci_read_config_dword(dev->rdev, AMD_PMC_STB_INDEX_DATA, buf++); + if (err) { + dev_err(dev->dev, "error reading data from stb: 0x%X\n", + AMD_PMC_STB_INDEX_DATA); + err = pcibios_err_to_errno(err); + goto err_pci_dev_put; + } + } + + return 0; + +err_pci_dev_put: + pci_dev_put(dev->rdev); + return err; +} + static int amd_pmc_probe(struct platform_device *pdev) { struct amd_pmc_dev *dev = &pmc; @@ -534,22 +670,23 @@ static int amd_pmc_probe(struct platform_device *pdev) rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); if (!rdev || !pci_match_id(pmc_pci_ids, rdev)) { - pci_dev_put(rdev); - return -ENODEV; + err = -ENODEV; + goto err_pci_dev_put; } dev->cpu_id = rdev->device; + dev->rdev = rdev; err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_LO); if (err) { dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS); - pci_dev_put(rdev); - return pcibios_err_to_errno(err); + err = pcibios_err_to_errno(err); + goto err_pci_dev_put; } err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val); if (err) { - pci_dev_put(rdev); - return pcibios_err_to_errno(err); + err = pcibios_err_to_errno(err); + goto err_pci_dev_put; } base_addr_lo = val & AMD_PMC_BASE_ADDR_HI_MASK; @@ -557,24 +694,25 @@ static int amd_pmc_probe(struct platform_device *pdev) err = pci_write_config_dword(rdev, AMD_PMC_SMU_INDEX_ADDRESS, AMD_PMC_BASE_ADDR_HI); if (err) { dev_err(dev->dev, "error writing to 0x%x\n", AMD_PMC_SMU_INDEX_ADDRESS); - pci_dev_put(rdev); - return pcibios_err_to_errno(err); + err = pcibios_err_to_errno(err); + goto err_pci_dev_put; } err = pci_read_config_dword(rdev, AMD_PMC_SMU_INDEX_DATA, &val); if (err) { - pci_dev_put(rdev); - return pcibios_err_to_errno(err); + err = pcibios_err_to_errno(err); + goto err_pci_dev_put; } base_addr_hi = val & AMD_PMC_BASE_ADDR_LO_MASK; - pci_dev_put(rdev); base_addr = ((u64)base_addr_hi << 32 | base_addr_lo); dev->regbase = devm_ioremap(dev->dev, base_addr + AMD_PMC_BASE_ADDR_OFFSET, AMD_PMC_MAPPING_SIZE); - if (!dev->regbase) - return -ENOMEM; + if (!dev->regbase) { + err = -ENOMEM; + goto err_pci_dev_put; + } mutex_init(&dev->lock); @@ -583,8 +721,10 @@ static int amd_pmc_probe(struct platform_device *pdev) base_addr_hi = FCH_BASE_PHY_ADDR_HIGH; fch_phys_addr = ((u64)base_addr_hi << 32 | base_addr_lo); dev->fch_virt_addr = devm_ioremap(dev->dev, fch_phys_addr, FCH_SSC_MAPPING_SIZE); - if (!dev->fch_virt_addr) - return -ENOMEM; + if (!dev->fch_virt_addr) { + err = -ENOMEM; + goto err_pci_dev_put; + } /* Use SMU to get the s0i3 debug stats */ err = amd_pmc_setup_smu_logging(dev); @@ -595,6 +735,10 @@ static int amd_pmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); amd_pmc_dbgfs_register(dev); return 0; + +err_pci_dev_put: + pci_dev_put(rdev); + return err; } static int amd_pmc_remove(struct platform_device *pdev) @@ -602,6 +746,7 @@ static int amd_pmc_remove(struct platform_device *pdev) struct amd_pmc_dev *dev = platform_get_drvdata(pdev); amd_pmc_dbgfs_unregister(dev); + pci_dev_put(dev->rdev); mutex_destroy(&dev->lock); return 0; } -- 2.35.1