aboutsummarylogtreecommitdiffstats
path: root/9001-v5.16-s0ix-patch-2022-01-17.patch
diff options
context:
space:
mode:
Diffstat (limited to '9001-v5.16-s0ix-patch-2022-01-17.patch')
-rw-r--r--9001-v5.16-s0ix-patch-2022-01-17.patch628
1 files changed, 628 insertions, 0 deletions
diff --git a/9001-v5.16-s0ix-patch-2022-01-17.patch b/9001-v5.16-s0ix-patch-2022-01-17.patch
new file mode 100644
index 000000000000..89fa4b80faee
--- /dev/null
+++ b/9001-v5.16-s0ix-patch-2022-01-17.patch
@@ -0,0 +1,628 @@
+From b4c5953e0377b39c43f0ddb62e1d130495bdf019 Mon Sep 17 00:00:00 2001
+From: Scott B <arglebargle@arglebargle.dev>
+Date: Mon, 17 Jan 2022 10:09:38 -0800
+Subject: [PATCH] v5.16 s0ix patch 2022-01-17
+
+Squashed commit of the following:
+
+commit b7fc459a41bbfbe7268279fb8d0769df37dfb957
+Author: Mario Limonciello <mario.limonciello@amd.com>
+Date: Fri Jan 7 10:49:59 2022 -0600
+
+ drm/amd/display: Revert W/A for hard hangs on DCN20/DCN21
+
+ The WA from commit 2a50edbf10c8 ("drm/amd/display: Apply w/a for hard hang
+ on HPD") and commit 1bd3bc745e7f ("drm/amd/display: Extend w/a for hard
+ hang on HPD to dcn20") causes a regression in s0ix where the system will
+ fail to resume properly on many laptops. Pull the workarounds out to
+ avoid that s0ix regression in the common case. This HPD hang happens with
+ an external device and a new W/A will need to be developed for this in the
+ future.
+
+ Cc: Kazlauskas Nicholas <Nicholas.Kazlauskas@amd.com>
+ Cc: Qingqing Zhuo <qingqing.zhuo@amd.com>
+ Reported-by: Scott Bruce <smbruce@gmail.com>
+ Reported-by: Chris Hixon <linux-kernel-bugs@hixontech.com>
+ Reported-by: spasswolf@web.de
+ Link: https://bugzilla.kernel.org/show_bug.cgi?id=215436
+ Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1821
+ Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1852
+ Fixes: 2a50edbf10c8 ("drm/amd/display: Apply w/a for hard hang on HPD")
+ Fixes: 1bd3bc745e7f ("drm/amd/display: Extend w/a for hard hang on HPD to dcn20")
+ Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+
+commit 73c260f09f0aa7ab79de33f191ae55248952e833
+Author: Sanket Goswami <Sanket.Goswami@amd.com>
+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 <Shyam-sundar.S-k@amd.com>
+ Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
+
+commit e6000d5a223f89882671e1aa61dd43e20051fe34
+Author: Sanket Goswami <Sanket.Goswami@amd.com>
+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 <hdegoede@redhat.com>
+ Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
+
+commit b6e9788d0f2d13aa2be66c88ca949ebf65ee32ea
+Author: Julian Sikorski <belegdol+github@gmail.com>
+Date: Fri Nov 19 17:52:36 2021 +0100
+
+ GFXOFF check patch by Lijo Lazar
+
+commit af2cbc6459a8108dcc0b8a513630b794c38d8c19
+Author: Mario Limonciello <mario.limonciello@amd.com>
+Date: Fri Sep 24 12:32:06 2021 -0500
+
+ ACPI: PM: s2idle: Don't report missing devices as failing constraints
+
+ ACPI tables may have entries for devices that are not physically
+ present but that can be connected. These devices shouldn't cause
+ constraints checking to fail.
+
+ Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+ Change-Id: I34f5ca978aab69ff0a0906191eec21649b19fe27
+---
+ drivers/acpi/x86/s2idle.c | 6 +
+ .../display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c | 11 +-
+ .../amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c | 11 +-
+ .../display/dc/irq/dcn20/irq_service_dcn20.c | 25 ---
+ .../display/dc/irq/dcn20/irq_service_dcn20.h | 2 -
+ .../display/dc/irq/dcn21/irq_service_dcn21.c | 25 ---
+ .../display/dc/irq/dcn21/irq_service_dcn21.h | 2 -
+ .../gpu/drm/amd/display/dc/irq/irq_service.c | 2 +-
+ .../gpu/drm/amd/display/dc/irq/irq_service.h | 4 -
+ drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 5 +-
+ drivers/platform/x86/amd-pmc.c | 172 ++++++++++++++++--
+ 11 files changed, 170 insertions(+), 95 deletions(-)
+
+diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
+index 1c48358b43ba..0b65d4623214 100644
+--- a/drivers/acpi/x86/s2idle.c
++++ b/drivers/acpi/x86/s2idle.c
+@@ -309,6 +309,12 @@ static void lpi_check_constraints(void)
+ continue;
+ }
+
++ if (!acpi_get_first_physical_node(adev)) {
++ acpi_handle_debug(handle, "LPI: Device is not physically present\n");
++ lpi_constraints_table[i].handle = NULL;
++ continue;
++ }
++
+ if (adev->power.state < lpi_constraints_table[i].min_dstate)
+ acpi_handle_info(handle,
+ "LPI: Constraint not met; min power state:%s current power state:%s\n",
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
+index 2108bff49d4e..146e6d670899 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn20/dcn20_clk_mgr.c
+@@ -38,7 +38,6 @@
+ #include "clk/clk_11_0_0_offset.h"
+ #include "clk/clk_11_0_0_sh_mask.h"
+
+-#include "irq/dcn20/irq_service_dcn20.h"
+
+ #undef FN
+ #define FN(reg_name, field_name) \
+@@ -223,8 +222,6 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base,
+ bool force_reset = false;
+ bool p_state_change_support;
+ int total_plane_count;
+- int irq_src;
+- uint32_t hpd_state;
+
+ if (dc->work_arounds.skip_clock_update)
+ return;
+@@ -242,13 +239,7 @@ void dcn2_update_clocks(struct clk_mgr *clk_mgr_base,
+ if (dc->res_pool->pp_smu)
+ pp_smu = &dc->res_pool->pp_smu->nv_funcs;
+
+- for (irq_src = DC_IRQ_SOURCE_HPD1; irq_src <= DC_IRQ_SOURCE_HPD6; irq_src++) {
+- hpd_state = dc_get_hpd_state_dcn20(dc->res_pool->irqs, irq_src);
+- if (hpd_state)
+- break;
+- }
+-
+- if (display_count == 0 && !hpd_state)
++ if (display_count == 0)
+ enter_display_off = true;
+
+ if (enter_display_off == safe_to_lower) {
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
+index ac2d4c4f04e4..d3c8db65ff45 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
+@@ -42,7 +42,6 @@
+ #include "clk/clk_10_0_2_sh_mask.h"
+ #include "renoir_ip_offset.h"
+
+-#include "irq/dcn21/irq_service_dcn21.h"
+
+ /* Constants */
+
+@@ -130,11 +129,9 @@ void rn_update_clocks(struct clk_mgr *clk_mgr_base,
+ struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
+ struct dc *dc = clk_mgr_base->ctx->dc;
+ int display_count;
+- int irq_src;
+ bool update_dppclk = false;
+ bool update_dispclk = false;
+ bool dpp_clock_lowered = false;
+- uint32_t hpd_state;
+
+ struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu;
+
+@@ -151,14 +148,8 @@ void rn_update_clocks(struct clk_mgr *clk_mgr_base,
+
+ display_count = rn_get_active_display_cnt_wa(dc, context);
+
+- for (irq_src = DC_IRQ_SOURCE_HPD1; irq_src <= DC_IRQ_SOURCE_HPD5; irq_src++) {
+- hpd_state = dc_get_hpd_state_dcn21(dc->res_pool->irqs, irq_src);
+- if (hpd_state)
+- break;
+- }
+-
+ /* if we can go lower, go lower */
+- if (display_count == 0 && !hpd_state) {
++ if (display_count == 0) {
+ rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
+ /* update power state */
+ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
+diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
+index 9ccafe007b23..c4b067d01895 100644
+--- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
++++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
+@@ -132,31 +132,6 @@ enum dc_irq_source to_dal_irq_source_dcn20(
+ }
+ }
+
+-uint32_t dc_get_hpd_state_dcn20(struct irq_service *irq_service, enum dc_irq_source source)
+-{
+- const struct irq_source_info *info;
+- uint32_t addr;
+- uint32_t value;
+- uint32_t current_status;
+-
+- info = find_irq_source_info(irq_service, source);
+- if (!info)
+- return 0;
+-
+- addr = info->status_reg;
+- if (!addr)
+- return 0;
+-
+- value = dm_read_reg(irq_service->ctx, addr);
+- current_status =
+- get_reg_field_value(
+- value,
+- HPD0_DC_HPD_INT_STATUS,
+- DC_HPD_SENSE);
+-
+- return current_status;
+-}
+-
+ static bool hpd_ack(
+ struct irq_service *irq_service,
+ const struct irq_source_info *info)
+diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h
+index 4d69ab24ca25..aee4b37999f1 100644
+--- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h
++++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.h
+@@ -31,6 +31,4 @@
+ struct irq_service *dal_irq_service_dcn20_create(
+ struct irq_service_init_data *init_data);
+
+-uint32_t dc_get_hpd_state_dcn20(struct irq_service *irq_service, enum dc_irq_source source);
+-
+ #endif
+diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
+index 78940cb20e10..ed54e1c819be 100644
+--- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
++++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
+@@ -135,31 +135,6 @@ enum dc_irq_source to_dal_irq_source_dcn21(
+ return DC_IRQ_SOURCE_INVALID;
+ }
+
+-uint32_t dc_get_hpd_state_dcn21(struct irq_service *irq_service, enum dc_irq_source source)
+-{
+- const struct irq_source_info *info;
+- uint32_t addr;
+- uint32_t value;
+- uint32_t current_status;
+-
+- info = find_irq_source_info(irq_service, source);
+- if (!info)
+- return 0;
+-
+- addr = info->status_reg;
+- if (!addr)
+- return 0;
+-
+- value = dm_read_reg(irq_service->ctx, addr);
+- current_status =
+- get_reg_field_value(
+- value,
+- HPD0_DC_HPD_INT_STATUS,
+- DC_HPD_SENSE);
+-
+- return current_status;
+-}
+-
+ static bool hpd_ack(
+ struct irq_service *irq_service,
+ const struct irq_source_info *info)
+diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.h b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.h
+index 616470e32380..da2bd0e93d7a 100644
+--- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.h
++++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.h
+@@ -31,6 +31,4 @@
+ struct irq_service *dal_irq_service_dcn21_create(
+ struct irq_service_init_data *init_data);
+
+-uint32_t dc_get_hpd_state_dcn21(struct irq_service *irq_service, enum dc_irq_source source);
+-
+ #endif
+diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
+index 4db1133e4466..a2a4fbeb83f8 100644
+--- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
++++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
+@@ -79,7 +79,7 @@ void dal_irq_service_destroy(struct irq_service **irq_service)
+ *irq_service = NULL;
+ }
+
+-const struct irq_source_info *find_irq_source_info(
++static const struct irq_source_info *find_irq_source_info(
+ struct irq_service *irq_service,
+ enum dc_irq_source source)
+ {
+diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
+index e60b82480093..dbfcb096eedd 100644
+--- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
++++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.h
+@@ -69,10 +69,6 @@ struct irq_service {
+ const struct irq_service_funcs *funcs;
+ };
+
+-const struct irq_source_info *find_irq_source_info(
+- struct irq_service *irq_service,
+- enum dc_irq_source source);
+-
+ void dal_irq_service_construct(
+ struct irq_service *irq_service,
+ struct irq_service_init_data *init_data);
+diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+index 9d7d64fdf410..37e83df92264 100644
+--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
++++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+@@ -277,8 +277,11 @@ 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) {
++ WARN(true, "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..15a5b23e7b8d 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,
+@@ -121,14 +128,21 @@ struct amd_pmc_dev {
+ u16 minor;
+ u16 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)
+ {
+@@ -175,6 +189,50 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
+ 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;
++}
++
++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 +346,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 +546,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 +573,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 +598,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 +667,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 +691,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 +718,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 +732,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 +743,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.34.1
+