diff options
Diffstat (limited to '9001-v5.14.13-s0ix-patch-2021-10-17.patch')
-rw-r--r-- | 9001-v5.14.13-s0ix-patch-2021-10-17.patch | 803 |
1 files changed, 803 insertions, 0 deletions
diff --git a/9001-v5.14.13-s0ix-patch-2021-10-17.patch b/9001-v5.14.13-s0ix-patch-2021-10-17.patch new file mode 100644 index 000000000000..b768c9891b7f --- /dev/null +++ b/9001-v5.14.13-s0ix-patch-2021-10-17.patch @@ -0,0 +1,803 @@ +From 96d064ca676e6f62cc4e8850bebc3ce56498c2a5 Mon Sep 17 00:00:00 2001 +From: Scott B <arglebargle@arglebargle.dev> +Date: Sun, 17 Oct 2021 07:39:02 -0700 +Subject: [PATCH] v5.14.13 s0ix patch 2021-10-17 + +Squashed commit of the following: + +commit 88230ab44d6f9fa6f76b6f24dc4e2ce6636715c5 +Author: Scott B <arglebargle@arglebargle.dev> +Date: Sun Oct 17 07:03:00 2021 -0700 + + pinctrl: amd: Fix wakeups when IRQ is shared with SCI (FIXUP) + +commit 71ec0b27fda84c20b2051f33d2830be749a21257 +Author: Mario Limonciello <mario.limonciello@amd.com> +Date: Fri Oct 15 09:43:32 2021 -0500 + + pinctrl: amd: Fix wakeups when IRQ is shared with SCI + + On some Lenovo AMD Gen2 platforms the IRQ for the SCI and pinctrl drivers + are shared. Due to how the s2idle loop handling works, this case needs + an extra explicit check whether the interrupt was caused by SCI or by + the GPIO controller. + + To fix this rework the existing IRQ handler function to function as a + checker and an IRQ handler depending on the calling arguments. + + BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1738 + Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> + +commit 5de6a0019bc8c145249a581c7f9a9d39a37e769c +Author: Sachi King <nakato@nakato.io> +Date: Sat Oct 9 14:32:40 2021 +1100 + + pinctrl: amd: disable and mask interrupts on probe + + Some systems such as the Microsoft Surface Laptop 4 leave interrupts + enabled and configured for use in sleep states on boot, which cause + unexpected behaviour such as spurious wakes and failed resumes in + s2idle states. + + As interrupts should not be enabled until they are claimed and + explicitly enabled, disabling any interrupts mistakenly left enabled by + firmware should be safe. + + Signed-off-by: Sachi King <nakato@nakato.io> + +commit f7ebc28774dacd2005465491b477f1f4c22eb0e2 +Author: Sanket Goswami <Sanket.Goswami@amd.com> +Date: Tue Oct 5 21:26:41 2021 +0530 + + platform/x86: amd-pmc: Add support for AMD Smart Trace Buffer + + STB (Smart Trace Buffer), is a debug trace buffer which is used to help + isolate failures by analyzing the last feature that a system was running + before hitting a failure. This nonintrusive way is always running in the + background and trace is stored into the SoC. + + This patch 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> + Reviewed-by: Mario Limonciello <mario.limonciello@amd.com> + +commit eac3a5ace2bf72169c1b603f925cb31b064ec1fd +Author: Sachi King <nakato@nakato.io> +Date: Sat Oct 2 14:18:40 2021 +1000 + + ACPI: PM: Include alternate AMDI0005 id in special behaviour + + The Surface Laptop 4 AMD has used the AMD0005 to identify this + controller instead of using the appropriate ACPI ID AMDI0005. The + AMD0005 needs the same special casing as AMDI0005. + + Cc: <stable@vger.kernel.org> # 5.14+ + Signed-off-by: Sachi King <nakato@nakato.io> + +commit cee45b2ead71565f22f31594d55addbeb1ac9f5e +Author: Sachi King <nakato@nakato.io> +Date: Sat Oct 2 14:18:39 2021 +1000 + + platform/x86: amd-pmc: Add alternative acpi id for PMC controller + + The Surface Laptop 4 AMD has used the AMD0005 to identify this + controller instead of using the appropriate ACPI ID AMDI0005. Include + AMD0005 in the acpi id list. + + Cc: <stable@vger.kernel.org> # 5.14+ + Signed-off-by: Sachi King <nakato@nakato.io> + +commit b8ca017aaf1ccaf765d665b70033f31faae702cc +Author: Hans de Goede <hdegoede@redhat.com> +Date: Tue Sep 28 16:21:22 2021 +0200 + + platform/x86: amd-pmc: Fix compilation when CONFIG_DEBUGFS is disabled + + The amd_pmc_get_smu_version() and amd_pmc_idlemask_read() functions are + used in the probe / suspend/resume code, so they are also used when + CONFIG_DEBUGFS is disabled, move them outside of the #ifdef CONFIG_DEBUGFS + block. + + Note this purely moves the code to above the #ifdef CONFIG_DEBUGFS, + the code is completely unchanged. + + Cc: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + Cc: Sanket Goswami <Sanket.Goswami@amd.com> + Reported-by: Nathan Chancellor <nathan@kernel.org> + Signed-off-by: Hans de Goede <hdegoede@redhat.com> + +commit 1b5d54074071b787f5f000e690bbbffe300039fe +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 + +commit 43ad349462f59bec501a1204b7701d3dc2dd7b73 +Author: Sanket Goswami <Sanket.Goswami@amd.com> +Date: Tue Sep 21 17:30:20 2021 +0530 + + platform/x86: amd-pmc: Add a message to print resume time info + + Add a message to print the resume time information obtained from the + smu_metrics structure. + + Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com> + +commit 4711b9421ba64c864fdfd9b52c1425216559cc37 +Author: Sanket Goswami <Sanket.Goswami@amd.com> +Date: Tue Sep 21 17:29:10 2021 +0530 + + platform/x86: amd-pmc: Send command to dump data after clearing OS_HINT + + It was reported that the resume stats received from the firmware are + always zero. This happens because the SMU expects the driver to send the + command to dump the log data after clearing the OS_HINT. + + Adjust the order of the commands sent to SMU. + + Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com> + +commit 0bf64dbc15381fd63cef11035e54970c19052058 +Author: Sanket Goswami <Sanket.Goswami@amd.com> +Date: Thu Sep 16 18:11:30 2021 +0530 + + platform/x86: amd-pmc: Check s0i3 cycle status + + As the PM firmware returns the status of the last s0i3 in the smu_metrics + structure, the existing name "s0i3_cyclecount" seems to be a misnomer. + Change it accordingly to "s0i3_last_entry_status". + + Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com> + Acked-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + +commit 6738be9a1e6a13dfc050482e6289e8b62df59e5d +Author: Sanket Goswami <Sanket.Goswami@amd.com> +Date: Thu Sep 16 18:10:02 2021 +0530 + + platform/x86: amd-pmc: Export Idlemask values based on the APU + + IdleMask is the metric used by the PM firmware to know the status of each + of the Hardware IP blocks monitored by the PM firmware. + + Knowing this value is key to get the information of s2idle suspend/resume + status. This value is mapped to PMC scratch registers, retrieve them + accordingly based on the CPU family and the underlying firmware support. + + 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> + Acked-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + Reviewed-by: Mario Limonciello <mario.limonciello@amd.com> + +commit 9e06b4819516c194ed762b59ff345fde96835c5a +Author: Mario Limonciello <mario.limonciello@amd.com> +Date: Wed Sep 15 16:52:16 2021 -0500 + + ACPI: processor idle: Allow playing dead in C3 + + commit 1a022e3f1be1 ("idle, x86: Allow off-lined CPU to enter + deeper C states") originally allowed offlined CPUs to play dead + up to ACPI C2. Although this improves power consumption of offlined + CPUs, it does not allow the CPUs to get into the deepest state + on AMD platforms blocking s0i3 entry. + + BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1708 + Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> + +commit c2690a5827ca0da39ebc5d52386e71d6e427f3a9 +Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> +Date: Tue Aug 31 17:36:12 2021 +0530 + + pinctrl: amd: Add irq field data + + pinctrl_amd use gpiochip_get_data() to get their local state containers + back from the gpiochip passed as amd_gpio chip data. + + Hence added irq field data to get directly using amd_gpio chip data. + + Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> + +commit ce18e7758d09249f615318a663c061c7cd56c036 +Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> +Date: Tue Aug 31 17:36:13 2021 +0530 + + pinctrl: amd: Handle wake-up interrupt + + Enable/disable power management wakeup mode, which is disabled by + default. enable_irq_wake enables wakes the system from sleep. + + Hence added enable/disable irq_wake to handle wake-up interrupt. + + Signed-off-by: Basavaraj Natikar <Basavaraj.Natikar@amd.com> +--- + drivers/acpi/processor_idle.c | 3 +- + drivers/acpi/x86/s2idle.c | 9 +- + drivers/pinctrl/Kconfig | 2 +- + drivers/pinctrl/pinctrl-amd.c | 77 +++++++++++-- + drivers/pinctrl/pinctrl-amd.h | 1 + + drivers/platform/x86/amd-pmc.c | 200 ++++++++++++++++++++++++++++++++- + 6 files changed, 276 insertions(+), 16 deletions(-) + +diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c +index 095c8aca141e..1b6529396371 100644 +--- a/drivers/acpi/processor_idle.c ++++ b/drivers/acpi/processor_idle.c +@@ -789,7 +789,8 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr) + state->enter = acpi_idle_enter; + + state->flags = 0; +- if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2) { ++ if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2 ++ || cx->type == ACPI_STATE_C3) { + state->enter_dead = acpi_idle_play_dead; + drv->safe_state_index = count; + } +diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c +index bd92b549fd5a..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", +@@ -371,7 +377,7 @@ static int lps0_device_attach(struct acpi_device *adev, + return 0; + + if (acpi_s2idle_vendor_amd()) { +- /* AMD0004, AMDI0005: ++ /* AMD0004, AMD0005, AMDI0005: + * - Should use rev_id 0x0 + * - function mask > 0x3: Should use AMD method, but has off by one bug + * - function mask = 0x3: Should use Microsoft method +@@ -390,6 +396,7 @@ static int lps0_device_attach(struct acpi_device *adev, + ACPI_LPS0_DSM_UUID_MICROSOFT, 0, + &lps0_dsm_guid_microsoft); + if (lps0_dsm_func_mask > 0x3 && (!strcmp(hid, "AMD0004") || ++ !strcmp(hid, "AMD0005") || + !strcmp(hid, "AMDI0005"))) { + lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1; + acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n", +diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig +index f38f12801f18..b225e28e433c 100644 +--- a/drivers/pinctrl/Kconfig ++++ b/drivers/pinctrl/Kconfig +@@ -96,7 +96,7 @@ config PINCTRL_AT91PIO4 + config PINCTRL_AMD + tristate "AMD GPIO pin control" + depends on HAS_IOMEM +- depends on ACPI || COMPILE_TEST ++ depends on ACPI + select GPIOLIB + select GPIOLIB_IRQCHIP + select PINMUX +diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c +index 5b764740b829..0a9360ee6be1 100644 +--- a/drivers/pinctrl/pinctrl-amd.c ++++ b/drivers/pinctrl/pinctrl-amd.c +@@ -445,6 +445,7 @@ static int amd_gpio_irq_set_wake(struct irq_data *d, unsigned int on) + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct amd_gpio *gpio_dev = gpiochip_get_data(gc); + u32 wake_mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3); ++ int err; + + raw_spin_lock_irqsave(&gpio_dev->lock, flags); + pin_reg = readl(gpio_dev->base + (d->hwirq)*4); +@@ -457,6 +458,15 @@ static int amd_gpio_irq_set_wake(struct irq_data *d, unsigned int on) + writel(pin_reg, gpio_dev->base + (d->hwirq)*4); + raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); + ++ if (on) ++ err = enable_irq_wake(gpio_dev->irq); ++ else ++ err = disable_irq_wake(gpio_dev->irq); ++ ++ if (err) ++ dev_err(&gpio_dev->pdev->dev, "failed to %s wake-up interrupt\n", ++ on ? "enable" : "disable"); ++ + return 0; + } + +@@ -588,16 +598,16 @@ static struct irq_chip amd_gpio_irqchip = { + + #define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF)) + +-static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) ++static bool _amd_gpio_irq_handler(int irq, void *dev_id) + { + struct amd_gpio *gpio_dev = dev_id; + struct gpio_chip *gc = &gpio_dev->gc; +- irqreturn_t ret = IRQ_NONE; + unsigned int i, irqnr; + unsigned long flags; + u32 __iomem *regs; + u32 regval; + u64 status, mask; ++ bool ret = false; + + /* Read the wake status */ + raw_spin_lock_irqsave(&gpio_dev->lock, flags); +@@ -617,6 +627,12 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) + /* Each status bit covers four pins */ + for (i = 0; i < 4; i++) { + regval = readl(regs + i); ++ /* called from resume context on a shared IRQ, just ++ * checking wake source. ++ */ ++ if (irq < 0 && (regval & BIT(WAKE_STS_OFF))) ++ return true; ++ + if (!(regval & PIN_IRQ_PENDING) || + !(regval & BIT(INTERRUPT_MASK_OFF))) + continue; +@@ -642,9 +658,12 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) + } + writel(regval, regs + i); + raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); +- ret = IRQ_HANDLED; ++ ret = true; + } + } ++ /* called from resume context on shared IRQ but didn't cause wake */ ++ if (irq < 0) ++ return ret; + + /* Signal EOI to the GPIO unit */ + raw_spin_lock_irqsave(&gpio_dev->lock, flags); +@@ -656,6 +675,16 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) + return ret; + } + ++static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id) ++{ ++ return _amd_gpio_irq_handler(irq, dev_id) ? IRQ_HANDLED : IRQ_NONE; ++} ++ ++static bool amd_gpio_check_wake(void *dev_id) ++{ ++ return _amd_gpio_irq_handler(-1, dev_id); ++} ++ + static int amd_get_groups_count(struct pinctrl_dev *pctldev) + { + struct amd_gpio *gpio_dev = pinctrl_dev_get_drvdata(pctldev); +@@ -832,6 +861,34 @@ static const struct pinconf_ops amd_pinconf_ops = { + .pin_config_group_set = amd_pinconf_group_set, + }; + ++static void amd_gpio_irq_init(struct amd_gpio *gpio_dev) ++{ ++ struct pinctrl_desc *desc = gpio_dev->pctrl->desc; ++ unsigned long flags; ++ u32 pin_reg, mask; ++ int i; ++ ++ mask = BIT(WAKE_CNTRL_OFF_S0I3) | BIT(WAKE_CNTRL_OFF_S3) | ++ BIT(INTERRUPT_MASK_OFF) | BIT(INTERRUPT_ENABLE_OFF) | ++ BIT(WAKE_CNTRL_OFF_S4); ++ ++ for (i = 0; i < desc->npins; i++) { ++ int pin = desc->pins[i].number; ++ const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin); ++ ++ if (!pd) ++ continue; ++ ++ raw_spin_lock_irqsave(&gpio_dev->lock, flags); ++ ++ pin_reg = readl(gpio_dev->base + i * 4); ++ pin_reg &= ~mask; ++ writel(pin_reg, gpio_dev->base + i * 4); ++ ++ raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); ++ } ++} ++ + #ifdef CONFIG_PM_SLEEP + static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin) + { +@@ -904,7 +961,6 @@ static struct pinctrl_desc amd_pinctrl_desc = { + static int amd_gpio_probe(struct platform_device *pdev) + { + int ret = 0; +- int irq_base; + struct resource *res; + struct amd_gpio *gpio_dev; + struct gpio_irq_chip *girq; +@@ -927,9 +983,9 @@ static int amd_gpio_probe(struct platform_device *pdev) + if (!gpio_dev->base) + return -ENOMEM; + +- irq_base = platform_get_irq(pdev, 0); +- if (irq_base < 0) +- return irq_base; ++ gpio_dev->irq = platform_get_irq(pdev, 0); ++ if (gpio_dev->irq < 0) ++ return gpio_dev->irq; + + #ifdef CONFIG_PM_SLEEP + gpio_dev->saved_regs = devm_kcalloc(&pdev->dev, amd_pinctrl_desc.npins, +@@ -969,6 +1025,9 @@ static int amd_gpio_probe(struct platform_device *pdev) + return PTR_ERR(gpio_dev->pctrl); + } + ++ /* Disable and mask interrupts */ ++ amd_gpio_irq_init(gpio_dev); ++ + girq = &gpio_dev->gc.irq; + girq->chip = &amd_gpio_irqchip; + /* This will let us handle the parent IRQ in the driver */ +@@ -989,12 +1048,13 @@ static int amd_gpio_probe(struct platform_device *pdev) + goto out2; + } + +- ret = devm_request_irq(&pdev->dev, irq_base, amd_gpio_irq_handler, ++ ret = devm_request_irq(&pdev->dev, gpio_dev->irq, amd_gpio_irq_handler, + IRQF_SHARED, KBUILD_MODNAME, gpio_dev); + if (ret) + goto out2; + + platform_set_drvdata(pdev, gpio_dev); ++ acpi_register_wakeup_handler(gpio_dev->irq, amd_gpio_check_wake, gpio_dev); + + dev_dbg(&pdev->dev, "amd gpio driver loaded\n"); + return ret; +@@ -1012,6 +1072,7 @@ static int amd_gpio_remove(struct platform_device *pdev) + gpio_dev = platform_get_drvdata(pdev); + + gpiochip_remove(&gpio_dev->gc); ++ acpi_unregister_wakeup_handler(amd_gpio_check_wake, gpio_dev); + + return 0; + } +diff --git a/drivers/pinctrl/pinctrl-amd.h b/drivers/pinctrl/pinctrl-amd.h +index 95e763424042..1d4317073654 100644 +--- a/drivers/pinctrl/pinctrl-amd.h ++++ b/drivers/pinctrl/pinctrl-amd.h +@@ -98,6 +98,7 @@ struct amd_gpio { + struct resource *res; + struct platform_device *pdev; + u32 *saved_regs; ++ int irq; + }; + + /* KERNCZ configuration*/ +diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd-pmc.c +index d6a7c896ac86..dc851c2c4d1c 100644 +--- a/drivers/platform/x86/amd-pmc.c ++++ b/drivers/platform/x86/amd-pmc.c +@@ -29,6 +29,16 @@ + #define AMD_PMC_REGISTER_RESPONSE 0x980 + #define AMD_PMC_REGISTER_ARGUMENT 0x9BC + ++/* PMC Scratch Registers */ ++#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 +@@ -76,6 +86,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, +@@ -110,14 +121,26 @@ struct amd_pmc_dev { + u32 base_addr; + u32 cpu_id; + u32 active_ips; ++/* SMU version information */ ++ u16 major; ++ 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 u32 stb_data[FIFO_SIZE]; ++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_write_stb(struct amd_pmc_dev *dev, u32 data); ++static int amd_pmc_read_stb(struct amd_pmc_dev *dev); + static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret); + + static inline u32 amd_pmc_reg_read(struct amd_pmc_dev *dev, int reg_offset) +@@ -133,7 +156,7 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3 + struct smu_metrics { + u32 table_version; + u32 hint_count; +- u32 s0i3_cyclecount; ++ u32 s0i3_last_entry_status; + u32 timein_s0i2; + u64 timeentering_s0i3_lastcapture; + u64 timeentering_s0i3_totaltime; +@@ -147,6 +170,49 @@ struct smu_metrics { + u64 timecondition_notmet_totaltime[SOC_SUBSYSTEM_IP_MAX]; + } __packed; + ++static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev) ++{ ++ int rc; ++ u32 val; ++ ++ rc = amd_pmc_send_cmd(dev, 0, &val, SMU_MSG_GETSMUVERSION, 1); ++ if (rc) ++ return rc; ++ ++ dev->major = (val >> 16) & GENMASK(15, 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); ++ ++ return 0; ++} ++ ++static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, ++ struct seq_file *s) ++{ ++ u32 val; ++ ++ switch (pdev->cpu_id) { ++ case AMD_CPU_ID_CZN: ++ val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN); ++ break; ++ case AMD_CPU_ID_YC: ++ val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ if (dev) ++ dev_dbg(pdev->dev, "SMU idlemask s0i3: 0x%x\n", val); ++ ++ if (s) ++ seq_printf(s, "SMU idlemask : 0x%x\n", val); ++ ++ return 0; ++} ++ + #ifdef CONFIG_DEBUG_FS + static int smu_fw_info_show(struct seq_file *s, void *unused) + { +@@ -162,9 +228,12 @@ static int smu_fw_info_show(struct seq_file *s, void *unused) + seq_puts(s, "\n=== SMU Statistics ===\n"); + seq_printf(s, "Table Version: %d\n", table.table_version); + seq_printf(s, "Hint Count: %d\n", table.hint_count); +- seq_printf(s, "S0i3 Cycle Count: %d\n", table.s0i3_cyclecount); ++ seq_printf(s, "Last S0i3 Status: %s\n", table.s0i3_last_entry_status ? "Success" : ++ "Unknown/Fail"); + seq_printf(s, "Time (in us) to S0i3: %lld\n", table.timeentering_s0i3_lastcapture); + seq_printf(s, "Time (in us) in S0i3: %lld\n", table.timein_s0i3_lastcapture); ++ seq_printf(s, "Time (in us) to resume from S0i3: %lld\n", ++ table.timeto_resume_to_os_lastcapture); + + seq_puts(s, "\n=== Active time (in us) ===\n"); + for (idx = 0 ; idx < SOC_SUBSYSTEM_IP_MAX ; idx++) { +@@ -201,6 +270,37 @@ static int s0ix_stats_show(struct seq_file *s, void *unused) + } + DEFINE_SHOW_ATTRIBUTE(s0ix_stats); + ++static int amd_pmc_idlemask_show(struct seq_file *s, void *unused) ++{ ++ struct amd_pmc_dev *dev = s->private; ++ int rc; ++ ++ if (dev->major > 56 || (dev->major >= 55 && dev->minor >= 37)) { ++ rc = amd_pmc_idlemask_read(dev, NULL, s); ++ if (rc) ++ return rc; ++ } else { ++ seq_puts(s, "Unsupported SMU version for Idlemask\n"); ++ } ++ ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(amd_pmc_idlemask); ++ ++static int stb_read_show(struct seq_file *seq, void *unused) ++{ ++ struct amd_pmc_dev *pdev = seq->private; ++ int i; ++ ++ amd_pmc_read_stb(pdev); ++ ++ for (i = 0; i < FIFO_SIZE; i += 4) ++ seq_hex_dump(seq, "", DUMP_PREFIX_NONE, 16, 1, &stb_data[i], 16, true); ++ ++ return 0; ++} ++DEFINE_SHOW_ATTRIBUTE(stb_read); ++ + static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) + { + debugfs_remove_recursive(dev->dbgfs_dir); +@@ -213,6 +313,12 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) + &smu_fw_info_fops); + debugfs_create_file("s0ix_stats", 0644, dev->dbgfs_dir, 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, ++ &stb_read_fops); + } + #else + static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) +@@ -349,11 +455,16 @@ static int __maybe_unused amd_pmc_suspend(struct device *dev) + amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_RESET, 0); + amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_START, 0); + ++ /* Dump the IdleMask before we send hint to SMU */ ++ amd_pmc_idlemask_read(pdev, dev, NULL); + msg = amd_pmc_get_os_hint(pdev); + rc = amd_pmc_send_cmd(pdev, 1, NULL, msg, 0); + if (rc) + dev_err(pdev->dev, "suspend failed\n"); + ++ if (enable_stb) ++ amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF); ++ + return rc; + } + +@@ -363,14 +474,21 @@ static int __maybe_unused amd_pmc_resume(struct device *dev) + int rc; + u8 msg; + +- /* Let SMU know that we are looking for stats */ +- amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0); +- + msg = amd_pmc_get_os_hint(pdev); + rc = amd_pmc_send_cmd(pdev, 0, NULL, msg, 0); + if (rc) + dev_err(pdev->dev, "resume failed\n"); + ++ /* Let SMU know that we are looking for stats */ ++ amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_DUMP_DATA, 0); ++ ++ /* 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) ++ amd_pmc_write_stb(pdev, AMD_PMC_STB_PREDEF + 1); ++ + return 0; + } + +@@ -387,6 +505,76 @@ static const struct pci_device_id pmc_pci_ids[] = { + { } + }; + ++static int amd_pmc_get_root_port(struct amd_pmc_dev *dev) ++{ ++ dev->rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); ++ if (!dev->rdev || !pci_match_id(pmc_pci_ids, dev->rdev)) { ++ pci_dev_put(dev->rdev); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static int amd_pmc_write_stb(struct amd_pmc_dev *dev, u32 data) ++{ ++ int rc; ++ ++ rc = amd_pmc_get_root_port(dev); ++ if (rc) ++ return rc; ++ ++ rc = pci_write_config_dword(dev->rdev, AMD_PMC_STB_INDEX_ADDRESS, AMD_PMC_STB_PMI_0); ++ if (rc) { ++ dev_err(dev->dev, "failed to write addr in stb: 0x%X\n", ++ AMD_PMC_STB_INDEX_ADDRESS); ++ pci_dev_put(dev->rdev); ++ return pcibios_err_to_errno(rc); ++ } ++ ++ rc = pci_write_config_dword(dev->rdev, AMD_PMC_STB_INDEX_DATA, data); ++ if (rc) { ++ dev_err(dev->dev, "failed to write data in stb: 0x%X\n", ++ AMD_PMC_STB_INDEX_DATA); ++ pci_dev_put(dev->rdev); ++ return pcibios_err_to_errno(rc); ++ } ++ ++ return 0; ++} ++ ++static int amd_pmc_read_stb(struct amd_pmc_dev *dev) ++{ ++ u32 cnt = 0, value; ++ int i, err; ++ ++ err = amd_pmc_get_root_port(dev); ++ if (err) ++ return 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); ++ pci_dev_put(dev->rdev); ++ return pcibios_err_to_errno(err); ++ } ++ ++ for (i = 0; i < FIFO_SIZE; i++) { ++ err = pci_read_config_dword(dev->rdev, AMD_PMC_STB_INDEX_DATA, &value); ++ if (err) { ++ dev_err(dev->dev, "error reading data from stb: 0x%X\n", ++ AMD_PMC_STB_INDEX_DATA); ++ pci_dev_put(dev->rdev); ++ return pcibios_err_to_errno(err); ++ } ++ ++ stb_data[cnt++] = value; ++ } ++ ++ return 0; ++} ++ + static int amd_pmc_probe(struct platform_device *pdev) + { + struct amd_pmc_dev *dev = &pmc; +@@ -457,6 +645,7 @@ static int amd_pmc_probe(struct platform_device *pdev) + if (err) + dev_err(dev->dev, "SMU debugging info not supported on this platform\n"); + ++ amd_pmc_get_smu_version(dev); + platform_set_drvdata(pdev, dev); + amd_pmc_dbgfs_register(dev); + return 0; +@@ -476,6 +665,7 @@ static const struct acpi_device_id amd_pmc_acpi_ids[] = { + {"AMDI0006", 0}, + {"AMDI0007", 0}, + {"AMD0004", 0}, ++ {"AMD0005", 0}, + { } + }; + MODULE_DEVICE_TABLE(acpi, amd_pmc_acpi_ids); +-- +2.33.1 + |