diff options
Diffstat (limited to 'sys-kernel_arch-sources-g14_files-9001-v5.13.14-s0ix-patch-2021-09-03.patch')
-rw-r--r-- | sys-kernel_arch-sources-g14_files-9001-v5.13.14-s0ix-patch-2021-09-03.patch | 1293 |
1 files changed, 0 insertions, 1293 deletions
diff --git a/sys-kernel_arch-sources-g14_files-9001-v5.13.14-s0ix-patch-2021-09-03.patch b/sys-kernel_arch-sources-g14_files-9001-v5.13.14-s0ix-patch-2021-09-03.patch deleted file mode 100644 index f4a636338294..000000000000 --- a/sys-kernel_arch-sources-g14_files-9001-v5.13.14-s0ix-patch-2021-09-03.patch +++ /dev/null @@ -1,1293 +0,0 @@ -From 36f737e3129d1058f2717dafa8e21c30a825f79f Mon Sep 17 00:00:00 2001 -From: Scott B <arglebargle@arglebargle.dev> -Date: Fri, 3 Sep 2021 03:07:06 -0700 -Subject: [PATCH] v5.13.14 s0ix patch 2021-09-03 - -Squashed commit of the following: - -commit d41335d4b59b3af5b5b0004da80a16067acd8303 -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 5ae23ad72e5302c875a1218886350368de215b42 -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> - -commit df56b40e5e30d43eef647a54e6f2b57988a99e36 -Author: Mario Limonciello <mario.limonciello@amd.com> -Date: Mon Aug 9 15:15:13 2021 -0500 - - pinctrl: amd: Fix an issue with shutdown when system set to s0ix - - IRQs are getting armed on shutdown causing the system to immediately - wake back up. - - Link: https://lkml.org/lkml/2021/8/2/1114 - Reported-by: nix.or.die@googlemail.com - Acked-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> - Tested-by: Gabriel Craciunescu <nix.or.die@gmail.com> - CC: Raul E Rangel <rrangel@chromium.org> - Fixes: d62bd5ce12d7 ("pinctrl: amd: Implement irq_set_wake") - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - Link: https://lore.kernel.org/r/20210809201513.12367-1-mario.limonciello@amd.com - Signed-off-by: Linus Walleij <linus.walleij@linaro.org> - -commit 38c5d80d5a7e15529e7c9f4136273f46938bec9f -Author: Raul E Rangel <rrangel@chromium.org> -Date: Thu Apr 29 16:34:24 2021 -0600 - - pinctrl: amd: Implement irq_set_wake - - This allows the OS to control which devices produce wake events. - - $ grep enabled /sys/kernel/irq/*/wakeup - /sys/kernel/irq/24/wakeup:enabled - - Signed-off-by: Raul E Rangel <rrangel@chromium.org> - Link: https://lore.kernel.org/r/20210429163341.1.I7631534622233689dd81410525e0dd617b9b2012@changeid - Signed-off-by: Linus Walleij <linus.walleij@linaro.org> - -commit e3629e35a34298d38875fcc8a8d9d2b5352a4f32 -Author: Mario Limonciello <mario.limonciello@amd.com> -Date: Tue Aug 31 11:36:19 2021 -0500 - - ACPI: PM: s2idle: Run both AMD and Microsoft methods if both are supported - - It was reported that on "HP ENVY x360" that power LED does not come back - on, certain keys like brightness controls do not work, and the fan never - spins up, even under load. - - In analysis of the SSDT it's clear that the Microsoft UUID doesn't provide - functional support, but rather the AMD UUID should be supporting this - system. - - Because this is a gap in the expected logic, confirmation with internal - team is that AMD uPEP *does* run even when Microsoft UUID present, but - most OEM systems have adopted value of "0x3" for supported functions and - hence nothing runs. - - Henceforth add support for running both Microsoft and AMD methods. This - approach will also allow the same logic on Intel systems if desired at a - future time as well by pulling the evaluation of - `lps0_dsm_func_mask_microsoft` out of the if block for - `acpi_s2idle_vendor_amd`. - - BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1691 - Reported-by: Maxwell Beck <max@ryt.one> - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - -commit 80ced3f9f485dd07ac5a5180bf2cc88f2179e2e3 -Author: Mario Limonciello <mario.limonciello@amd.com> -Date: Mon Aug 9 20:40:04 2021 -0500 - - ACPI: PM: s2idle: Invert Microsoft UUID entry and exit - - It was reported by a user with a Dell m15 R5 (5800H) that - the keyboard backlight was turning on when entering suspend - and turning off when exiting (the opposite of how it should be). - - The user bisected it back to commit 5dbf50997578 ("ACPI: PM: - s2idle: Add support for new Microsoft UUID"). Previous to that - commit the LEDs didn't turn off at all. Confirming in the spec, - these were reversed when introduced. - - Fix them to match the spec. - - BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1230#note_1021836 - Fixes: 5dbf50997578 ("ACPI: PM: s2idle: Add support for new Microsoft UUID") - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - -commit 6d363060e6590441f4755cdd96ced1f5e5ffb1e0 -Author: Mario Limonciello <mario.limonciello@amd.com> -Date: Wed Jul 7 09:16:47 2021 -0500 - - platform/x86: amd-pmc: Use return code on suspend - - Right now the driver will still return success even if the OS_HINT - command failed to send to the SMU. In the rare event of a failure, - the suspend should really be aborted here so that relevant logs - can may be captured. - - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - Acked-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> - -commit 311131001c64e1fb04d73c45a8e4ba7a6835a079 -Author: Mario Limonciello <mario.limonciello@amd.com> -Date: Wed Jun 30 14:46:06 2021 -0500 - - ACPI: PM: Only mark EC GPE for wakeup on Intel systems - - When using s2idle on a variety of AMD notebook systems, they are - experiencing spurious events that the EC or SMU are in the wrong - state leading to a hard time waking up or higher than expected - power consumption. - - These events only occur when the EC GPE is inadvertently set as a wakeup - source. Originally the EC GPE was only set as a wakeup source when using - the intel-vbtn or intel-hid drivers in commit 10a08fd65ec1 ("ACPI: PM: - Set up EC GPE for system wakeup from drivers that need it") but during - testing a reporter discovered that this was not enough for their ASUS - Zenbook UX430UNR/i7-8550U to wakeup by lid event or keypress. - Marking the EC GPE for wakeup universally resolved this for that - reporter in commit b90ff3554aa3 ("ACPI: PM: s2idle: Always set up EC GPE - for system wakeup"). - - However this behavior has lead to a number of problems: - - * On both Lenovo T14 and P14s the keyboard wakeup doesn't work, and - sometimes the power button event doesn't work. - * On HP 635 G7 detaching or attaching AC during suspend will cause - the system not to wakeup - * On Asus vivobook to prevent detaching AC causing resume problems - * On Lenovo 14ARE05 to prevent detaching AC causing resume problems - * On HP ENVY x360 to prevent detaching AC causing resume problems - - As there may be other Intel systems besides ASUS Zenbook UX430UNR/i7-8550U - that don't use intel-vbtn or intel-hid avoid these problems by only - universally marking the EC GPE wakesource on non-AMD systems. - - Link: https://patchwork.kernel.org/project/linux-pm/cover/5997740.FPbUVk04hV@kreacher/#22825489 - Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1230 - Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1629 - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - Acked-by: Alex Deucher <alexander.deucher@amd.com> - -commit 0a7afaec19f871bc83950919530fe84e93e90dd5 -Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> -Date: Tue Jun 29 14:18:03 2021 +0530 - - platform/x86: amd-pmc: Add new acpi id for future PMC controllers - - The upcoming PMC controller would have a newer acpi id, add that to - the supported acpid device list. - - Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> - Reviewed-by: Hans de Goede <hdegoede@redhat.com> - -commit ab0fbff1630447b320a00a56d2d03abcb956e8d3 -Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> -Date: Tue Jun 29 14:18:02 2021 +0530 - - platform/x86: amd-pmc: Add support for ACPI ID AMDI0006 - - Some newer BIOSes have added another ACPI ID for the uPEP device. - SMU statistics behave identically on this device. - - Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> - Reviewed-by: Hans de Goede <hdegoede@redhat.com> - -commit 27a6b6eb5de59f8be31d5276044eda4fda974450 -Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> -Date: Tue Jun 29 14:18:01 2021 +0530 - - amd-pmc: Add support for logging s0ix counters - - Even the FCH SSC registers provides certain level of information - about the s0ix entry and exit times which comes handy when the SMU - fails to report the statistics via the mailbox communication. - - This information is captured via a new debugfs file "s0ix_stats". - A non-zero entry in this counters would mean that the system entered - the s0ix state. - - If s0ix entry time and exit time don't change during suspend to idle, - the silicon has not entered the deepest state. - - Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> - Reviewed-by: Hans de Goede <hdegoede@redhat.com> - -commit 44c1c5f0d6d12a7c368b28e549315dd0f9475649 -Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> -Date: Tue Jun 29 14:18:00 2021 +0530 - - platform/x86: amd-pmc: Add support for logging SMU metrics - - SMU provides a way to dump the s0ix debug statistics in the form of a - metrics table via a of set special mailbox commands. - - Add support to the driver which can send these commands to SMU and expose - the information received via debugfs. The information contains the s0ix - entry/exit, active time of each IP block etc. - - As a side note, SMU subsystem logging is not supported on Picasso based - SoC's. - - Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> - Reviewed-by: Hans de Goede <hdegoede@redhat.com> - -commit 2fc643aca016fa2290274cc0211865c9faced3c8 -Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> -Date: Tue Jun 29 14:17:59 2021 +0530 - - platform/x86: amd-pmc: call dump registers only once - - Currently amd_pmc_dump_registers() routine is being called at - multiple places. The best to call it is after command submission - to SMU. - - Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> - -commit cf41f866c72024d26d540503f29f4fd40ff99e47 -Author: Mario Limonciello <mario.limonciello@amd.com> -Date: Thu Jun 17 11:42:12 2021 -0500 - - ACPI: PM: Adjust behavior for field problems on AMD systems - - Some AMD Systems with uPEP _HID AMD004/AMDI005 have an off by one bug - in their function mask return. This means that they will call entrance - but not exit for matching functions. - - Other AMD systems with this HID should use the Microsoft generic UUID. - - AMD systems with uPEP HID AMDI006 should be using the Microsoft method. - - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - -commit eee65e7c8960f636fc10c94b00c183a7a844b971 -Author: Pratik Vishwakarma <Pratik.Vishwakarma@amd.com> -Date: Thu Jun 17 11:42:11 2021 -0500 - - ACPI: PM: s2idle: Add support for new Microsoft UUID - - This adds supports for _DSM notifications to the Microsoft UUID - described by Microsoft documentation for s2idle. - - Link: https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/modern-standby-firmware-notifications - Co-developed-by: Mario Limonciello <mario.limonciello@amd.com> - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - Signed-off-by: Pratik Vishwakarma <Pratik.Vishwakarma@amd.com> - -commit aebc1c48faed67b707ca79a7c66029684cb8eeab -Author: Pratik Vishwakarma <Pratik.Vishwakarma@amd.com> -Date: Thu Jun 17 11:42:10 2021 -0500 - - ACPI: PM: s2idle: Add support for multiple func mask - - Required for follow-up patch adding new UUID - needing new function mask. - - Signed-off-by: Pratik Vishwakarma <Pratik.Vishwakarma@amd.com> - -commit 4d027ca3853f82e0f678b1ca2c2247140762fb3e -Author: Pratik Vishwakarma <Pratik.Vishwakarma@amd.com> -Date: Thu Jun 17 11:42:09 2021 -0500 - - ACPI: PM: s2idle: Refactor common code - - Refactor common code to prepare for upcoming changes. - * Remove unused struct. - * Print error before returning. - * Frees ACPI obj if _DSM type is not as expected. - * Treat lps0_dsm_func_mask as an integer rather than character - * Remove extra out_obj - * Move rev_id - - Co-developed-by: Mario Limonciello <mario.limonciello@amd.com> - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - Signed-off-by: Pratik Vishwakarma <Pratik.Vishwakarma@amd.com> - -commit c2a6a33c8255b8c38ad935c623848ecbc6964811 -Author: Pratik Vishwakarma <Pratik.Vishwakarma@amd.com> -Date: Thu Jun 17 11:42:08 2021 -0500 - - ACPI: PM: s2idle: Use correct revision id - - AMD spec mentions only revision 0. With this change, - device constraint list is populated properly. - - Signed-off-by: Pratik Vishwakarma <Pratik.Vishwakarma@amd.com> - -commit a799a0e4fd4dfab53e85e0cc687f64a9c22a41a2 -Author: Mario Limonciello <mario.limonciello@amd.com> -Date: Wed Jun 9 13:40:18 2021 -0500 - - ACPI: Add quirks for AMD Renoir/Lucienne CPUs to force the D3 hint - - AMD systems from Renoir and Lucienne require that the NVME controller - is put into D3 over a Modern Standby / suspend-to-idle - cycle. This is "typically" accomplished using the `StorageD3Enable` - property in the _DSD, but this property was introduced after many - of these systems launched and most OEM systems don't have it in - their BIOS. - - On AMD Renoir without these drives going into D3 over suspend-to-idle - the resume will fail with the NVME controller being reset and a trace - like this in the kernel logs: - ``` - [ 83.556118] nvme nvme0: I/O 161 QID 2 timeout, aborting - [ 83.556178] nvme nvme0: I/O 162 QID 2 timeout, aborting - [ 83.556187] nvme nvme0: I/O 163 QID 2 timeout, aborting - [ 83.556196] nvme nvme0: I/O 164 QID 2 timeout, aborting - [ 95.332114] nvme nvme0: I/O 25 QID 0 timeout, reset controller - [ 95.332843] nvme nvme0: Abort status: 0x371 - [ 95.332852] nvme nvme0: Abort status: 0x371 - [ 95.332856] nvme nvme0: Abort status: 0x371 - [ 95.332859] nvme nvme0: Abort status: 0x371 - [ 95.332909] PM: dpm_run_callback(): pci_pm_resume+0x0/0xe0 returns -16 - [ 95.332936] nvme 0000:03:00.0: PM: failed to resume async: error -16 - ``` - - The Microsoft documentation for StorageD3Enable mentioned that Windows has - a hardcoded allowlist for D3 support, which was used for these platforms. - Introduce quirks to hardcode them for Linux as well. - - As this property is now "standardized", OEM systems using AMD Cezanne and - newer APU's have adopted this property, and quirks like this should not be - necessary. - - CC: Shyam-sundar S-k <Shyam-sundar.S-k@amd.com> - CC: Alexander Deucher <Alexander.Deucher@amd.com> - CC: Prike Liang <prike.liang@amd.com> - Link: https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-intro - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> - Tested-by: Julian Sikorski <belegdol@gmail.com> - Signed-off-by: Christoph Hellwig <hch@lst.de> - -commit b626c7c5162646c04f1b208951421d70996cda0e -Author: Mario Limonciello <mario.limonciello@amd.com> -Date: Wed Jun 9 13:40:17 2021 -0500 - - ACPI: Check StorageD3Enable _DSD property in ACPI code - - Although first implemented for NVME, this check may be usable by - other drivers as well. Microsoft's specification explicitly mentions - that is may be usable by SATA and AHCI devices. Google also indicates - that they have used this with SDHCI in a downstream kernel tree that - a user can plug a storage device into. - - Link: https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/power-management-for-storage-hardware-devices-intro - Suggested-by: Keith Busch <kbusch@kernel.org> - CC: Shyam-sundar S-k <Shyam-sundar.S-k@amd.com> - CC: Alexander Deucher <Alexander.Deucher@amd.com> - CC: Rafael J. Wysocki <rjw@rjwysocki.net> - CC: Prike Liang <prike.liang@amd.com> - Signed-off-by: Mario Limonciello <mario.limonciello@amd.com> - Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> - Signed-off-by: Christoph Hellwig <hch@lst.de> ---- - drivers/acpi/device_pm.c | 32 ++++++ - drivers/acpi/internal.h | 9 ++ - drivers/acpi/x86/s2idle.c | 176 +++++++++++++++++++--------- - drivers/acpi/x86/utils.c | 25 ++++ - drivers/nvme/host/pci.c | 28 +---- - drivers/pinctrl/pinctrl-amd.c | 50 +++++++- - drivers/pinctrl/pinctrl-amd.h | 1 + - drivers/platform/x86/amd-pmc.c | 204 ++++++++++++++++++++++++++++++--- - include/linux/acpi.h | 5 + - 9 files changed, 429 insertions(+), 101 deletions(-) - -diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c -index 9d2d3b9bb8b5..0cfdef2fc3ad 100644 ---- a/drivers/acpi/device_pm.c -+++ b/drivers/acpi/device_pm.c -@@ -1338,4 +1338,36 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) - return 1; - } - EXPORT_SYMBOL_GPL(acpi_dev_pm_attach); -+ -+/** -+ * acpi_storage_d3 - Check if D3 should be used in the suspend path -+ * @dev: Device to check -+ * -+ * Return %true if the platform firmware wants @dev to be programmed -+ * into D3hot or D3cold (if supported) in the suspend path, or %false -+ * when there is no specific preference. On some platforms, if this -+ * hint is ignored, @dev may remain unresponsive after suspending the -+ * platform as a whole. -+ * -+ * Although the property has storage in the name it actually is -+ * applied to the PCIe slot and plugging in a non-storage device the -+ * same platform restrictions will likely apply. -+ */ -+bool acpi_storage_d3(struct device *dev) -+{ -+ struct acpi_device *adev = ACPI_COMPANION(dev); -+ u8 val; -+ -+ if (force_storage_d3()) -+ return true; -+ -+ if (!adev) -+ return false; -+ if (fwnode_property_read_u8(acpi_fwnode_handle(adev), "StorageD3Enable", -+ &val)) -+ return false; -+ return val == 1; -+} -+EXPORT_SYMBOL_GPL(acpi_storage_d3); -+ - #endif /* CONFIG_PM */ -diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h -index e21611c9a170..7ac01b03ba67 100644 ---- a/drivers/acpi/internal.h -+++ b/drivers/acpi/internal.h -@@ -236,6 +236,15 @@ static inline int suspend_nvs_save(void) { return 0; } - static inline void suspend_nvs_restore(void) {} - #endif - -+#ifdef CONFIG_X86 -+bool force_storage_d3(void); -+#else -+static inline bool force_storage_d3(void) -+{ -+ return false; -+} -+#endif -+ - /*-------------------------------------------------------------------------- - Device properties - -------------------------------------------------------------------------- */ -diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c -index 2d7ddb8a8cb6..bd35009bb005 100644 ---- a/drivers/acpi/x86/s2idle.c -+++ b/drivers/acpi/x86/s2idle.c -@@ -32,6 +32,9 @@ static const struct acpi_device_id lps0_device_ids[] = { - {"", }, - }; - -+/* Microsoft platform agnostic UUID */ -+#define ACPI_LPS0_DSM_UUID_MICROSOFT "11e00d56-ce64-47ce-837b-1f898f9aa461" -+ - #define ACPI_LPS0_DSM_UUID "c4eb40a0-6cd2-11e2-bcfd-0800200c9a66" - - #define ACPI_LPS0_GET_DEVICE_CONSTRAINTS 1 -@@ -39,6 +42,8 @@ static const struct acpi_device_id lps0_device_ids[] = { - #define ACPI_LPS0_SCREEN_ON 4 - #define ACPI_LPS0_ENTRY 5 - #define ACPI_LPS0_EXIT 6 -+#define ACPI_LPS0_MS_ENTRY 7 -+#define ACPI_LPS0_MS_EXIT 8 - - /* AMD */ - #define ACPI_LPS0_DSM_UUID_AMD "e3f32452-febc-43ce-9039-932122d37721" -@@ -49,7 +54,10 @@ static const struct acpi_device_id lps0_device_ids[] = { - - static acpi_handle lps0_device_handle; - static guid_t lps0_dsm_guid; --static char lps0_dsm_func_mask; -+static int lps0_dsm_func_mask; -+ -+static guid_t lps0_dsm_guid_microsoft; -+static int lps0_dsm_func_mask_microsoft; - - /* Device constraint entry structure */ - struct lpi_device_info { -@@ -70,15 +78,7 @@ struct lpi_constraints { - int min_dstate; - }; - --/* AMD */ --/* Device constraint entry structure */ --struct lpi_device_info_amd { -- int revision; -- int count; -- union acpi_object *package; --}; -- --/* Constraint package structure */ -+/* AMD Constraint package structure */ - struct lpi_device_constraint_amd { - char *name; - int enabled; -@@ -96,15 +96,15 @@ static void lpi_device_get_constraints_amd(void) - int i, j, k; - - out_obj = acpi_evaluate_dsm_typed(lps0_device_handle, &lps0_dsm_guid, -- 1, ACPI_LPS0_GET_DEVICE_CONSTRAINTS, -+ rev_id, ACPI_LPS0_GET_DEVICE_CONSTRAINTS, - NULL, ACPI_TYPE_PACKAGE); - -- if (!out_obj) -- return; -- - acpi_handle_debug(lps0_device_handle, "_DSM function 1 eval %s\n", - out_obj ? "successful" : "failed"); - -+ if (!out_obj) -+ return; -+ - for (i = 0; i < out_obj->package.count; i++) { - union acpi_object *package = &out_obj->package.elements[i]; - -@@ -317,14 +317,15 @@ static void lpi_check_constraints(void) - } - } - --static void acpi_sleep_run_lps0_dsm(unsigned int func) -+static void acpi_sleep_run_lps0_dsm(unsigned int func, unsigned int func_mask, guid_t dsm_guid) - { - union acpi_object *out_obj; - -- if (!(lps0_dsm_func_mask & (1 << func))) -+ if (!(func_mask & (1 << func))) - return; - -- out_obj = acpi_evaluate_dsm(lps0_device_handle, &lps0_dsm_guid, rev_id, func, NULL); -+ out_obj = acpi_evaluate_dsm(lps0_device_handle, &dsm_guid, -+ rev_id, func, NULL); - ACPI_FREE(out_obj); - - acpi_handle_debug(lps0_device_handle, "_DSM function %u evaluation %s\n", -@@ -336,11 +337,33 @@ static bool acpi_s2idle_vendor_amd(void) - return boot_cpu_data.x86_vendor == X86_VENDOR_AMD; - } - -+static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *dsm_guid) -+{ -+ union acpi_object *obj; -+ int ret = -EINVAL; -+ -+ guid_parse(uuid, dsm_guid); -+ obj = acpi_evaluate_dsm(handle, dsm_guid, rev, 0, NULL); -+ -+ /* Check if the _DSM is present and as expected. */ -+ if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length == 0 || -+ obj->buffer.length > sizeof(u32)) { -+ acpi_handle_debug(handle, -+ "_DSM UUID %s rev %d function 0 evaluation failed\n", uuid, rev); -+ goto out; -+ } -+ -+ ret = *(int *)obj->buffer.pointer; -+ acpi_handle_debug(handle, "_DSM UUID %s rev %d function mask: 0x%x\n", uuid, rev, ret); -+ -+out: -+ ACPI_FREE(obj); -+ return ret; -+} -+ - static int lps0_device_attach(struct acpi_device *adev, - const struct acpi_device_id *not_used) - { -- union acpi_object *out_obj; -- - if (lps0_device_handle) - return 0; - -@@ -348,28 +371,36 @@ static int lps0_device_attach(struct acpi_device *adev, - return 0; - - if (acpi_s2idle_vendor_amd()) { -- guid_parse(ACPI_LPS0_DSM_UUID_AMD, &lps0_dsm_guid); -- out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 0, 0, NULL); -+ /* AMD0004, 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 -+ * AMDI0006: -+ * - should use rev_id 0x0 -+ * - function mask = 0x3: Should use Microsoft method -+ */ -+ const char *hid = acpi_device_hid(adev); - rev_id = 0; -+ lps0_dsm_func_mask = validate_dsm(adev->handle, -+ ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid); -+ lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle, -+ ACPI_LPS0_DSM_UUID_MICROSOFT, rev_id, -+ &lps0_dsm_guid_microsoft); -+ if (lps0_dsm_func_mask > 0x3 && (!strcmp(hid, "AMD0004") || -+ !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", -+ ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask); -+ } - } else { -- guid_parse(ACPI_LPS0_DSM_UUID, &lps0_dsm_guid); -- out_obj = acpi_evaluate_dsm(adev->handle, &lps0_dsm_guid, 1, 0, NULL); - rev_id = 1; -+ lps0_dsm_func_mask = validate_dsm(adev->handle, -+ ACPI_LPS0_DSM_UUID, rev_id, &lps0_dsm_guid); -+ lps0_dsm_func_mask_microsoft = -EINVAL; - } - -- /* Check if the _DSM is present and as expected. */ -- if (!out_obj || out_obj->type != ACPI_TYPE_BUFFER) { -- acpi_handle_debug(adev->handle, -- "_DSM function 0 evaluation failed\n"); -- return 0; -- } -- -- lps0_dsm_func_mask = *(char *)out_obj->buffer.pointer; -- -- ACPI_FREE(out_obj); -- -- acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n", -- lps0_dsm_func_mask); -+ if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0) -+ return 0; //function evaluation failed - - lps0_device_handle = adev->handle; - -@@ -386,11 +417,15 @@ static int lps0_device_attach(struct acpi_device *adev, - mem_sleep_current = PM_SUSPEND_TO_IDLE; - - /* -- * Some LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U, require the -- * EC GPE to be enabled while suspended for certain wakeup devices to -- * work, so mark it as wakeup-capable. -+ * Some Intel based LPS0 systems, like ASUS Zenbook UX430UNR/i7-8550U don't -+ * use intel-hid or intel-vbtn but require the EC GPE to be enabled while -+ * suspended for certain wakeup devices to work, so mark it as wakeup-capable. -+ * -+ * Only enable on !AMD as enabling this universally causes problems for a number -+ * of AMD based systems. - */ -- acpi_ec_mark_gpe_for_wake(); -+ if (!acpi_s2idle_vendor_amd()) -+ acpi_ec_mark_gpe_for_wake(); - - return 0; - } -@@ -408,14 +443,30 @@ int acpi_s2idle_prepare_late(void) - if (pm_debug_messages_on) - lpi_check_constraints(); - -- if (acpi_s2idle_vendor_amd()) { -- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF_AMD); -- acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY_AMD); -- } else { -- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF); -- acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY); -- } -+ /* screen off */ -+ if (lps0_dsm_func_mask > 0) -+ acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ? -+ ACPI_LPS0_SCREEN_OFF_AMD : -+ ACPI_LPS0_SCREEN_OFF, -+ lps0_dsm_func_mask, lps0_dsm_guid); - -+ if (lps0_dsm_func_mask_microsoft > 0) -+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF, -+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); -+ -+ /* lps0 entry */ -+ if (lps0_dsm_func_mask > 0) -+ acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ? -+ ACPI_LPS0_ENTRY_AMD : -+ ACPI_LPS0_ENTRY, -+ lps0_dsm_func_mask, lps0_dsm_guid); -+ if (lps0_dsm_func_mask_microsoft > 0) { -+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY, -+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); -+ /* modern standby entry */ -+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY, -+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); -+ } - return 0; - } - -@@ -424,13 +475,30 @@ void acpi_s2idle_restore_early(void) - if (!lps0_device_handle || sleep_no_lps0) - return; - -- if (acpi_s2idle_vendor_amd()) { -- acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT_AMD); -- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON_AMD); -- } else { -- acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT); -- acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON); -- } -+ /* mdoern standby exit */ -+ if (lps0_dsm_func_mask_microsoft > 0) -+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT, -+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); -+ -+ /* lps0 exit */ -+ if (lps0_dsm_func_mask > 0) -+ acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ? -+ ACPI_LPS0_EXIT_AMD : -+ ACPI_LPS0_EXIT, -+ lps0_dsm_func_mask, lps0_dsm_guid); -+ if (lps0_dsm_func_mask_microsoft > 0) -+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT, -+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); -+ -+ /* screen on */ -+ if (lps0_dsm_func_mask_microsoft > 0) -+ acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON, -+ lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); -+ if (lps0_dsm_func_mask > 0) -+ acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ? -+ ACPI_LPS0_SCREEN_ON_AMD : -+ ACPI_LPS0_SCREEN_ON, -+ lps0_dsm_func_mask, lps0_dsm_guid); - } - - static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = { -diff --git a/drivers/acpi/x86/utils.c b/drivers/acpi/x86/utils.c -index bdc1ba00aee9..f22f23933063 100644 ---- a/drivers/acpi/x86/utils.c -+++ b/drivers/acpi/x86/utils.c -@@ -135,3 +135,28 @@ bool acpi_device_always_present(struct acpi_device *adev) - - return ret; - } -+ -+/* -+ * AMD systems from Renoir and Lucienne *require* that the NVME controller -+ * is put into D3 over a Modern Standby / suspend-to-idle cycle. -+ * -+ * This is "typically" accomplished using the `StorageD3Enable` -+ * property in the _DSD that is checked via the `acpi_storage_d3` function -+ * but this property was introduced after many of these systems launched -+ * and most OEM systems don't have it in their BIOS. -+ * -+ * The Microsoft documentation for StorageD3Enable mentioned that Windows has -+ * a hardcoded allowlist for D3 support, which was used for these platforms. -+ * -+ * This allows quirking on Linux in a similar fashion. -+ */ -+static const struct x86_cpu_id storage_d3_cpu_ids[] = { -+ X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 96, NULL), /* Renoir */ -+ X86_MATCH_VENDOR_FAM_MODEL(AMD, 23, 104, NULL), /* Lucienne */ -+ {} -+}; -+ -+bool force_storage_d3(void) -+{ -+ return x86_match_cpu(storage_d3_cpu_ids); -+} -diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c -index d963f25fc7ae..66455e2261d0 100644 ---- a/drivers/nvme/host/pci.c -+++ b/drivers/nvme/host/pci.c -@@ -2880,32 +2880,6 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev) - return 0; - } - --#ifdef CONFIG_ACPI --static bool nvme_acpi_storage_d3(struct pci_dev *dev) --{ -- struct acpi_device *adev = ACPI_COMPANION(&dev->dev); -- u8 val; -- -- /* -- * Look for _DSD property specifying that the storage device on the port -- * must use D3 to support deep platform power savings during -- * suspend-to-idle. -- */ -- -- if (!adev) -- return false; -- if (fwnode_property_read_u8(acpi_fwnode_handle(adev), "StorageD3Enable", -- &val)) -- return false; -- return val == 1; --} --#else --static inline bool nvme_acpi_storage_d3(struct pci_dev *dev) --{ -- return false; --} --#endif /* CONFIG_ACPI */ -- - static void nvme_async_probe(void *data, async_cookie_t cookie) - { - struct nvme_dev *dev = data; -@@ -2955,7 +2929,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) - - quirks |= check_vendor_combination_bug(pdev); - -- if (!noacpi && nvme_acpi_storage_d3(pdev)) { -+ if (!noacpi && acpi_storage_d3(&pdev->dev)) { - /* - * Some systems use a bios work around to ask for D3 on - * platforms that support kernel managed suspend. -diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c -index c5950a3b4e4c..d19974aceb2e 100644 ---- a/drivers/pinctrl/pinctrl-amd.c -+++ b/drivers/pinctrl/pinctrl-amd.c -@@ -438,6 +438,38 @@ static void amd_gpio_irq_unmask(struct irq_data *d) - raw_spin_unlock_irqrestore(&gpio_dev->lock, flags); - } - -+static int amd_gpio_irq_set_wake(struct irq_data *d, unsigned int on) -+{ -+ u32 pin_reg; -+ unsigned long flags; -+ 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); -+ -+ if (on) -+ pin_reg |= wake_mask; -+ else -+ pin_reg &= ~wake_mask; -+ -+ 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; -+} -+ - static void amd_gpio_irq_eoi(struct irq_data *d) - { - u32 reg; -@@ -552,9 +584,16 @@ static struct irq_chip amd_gpio_irqchip = { - .irq_disable = amd_gpio_irq_disable, - .irq_mask = amd_gpio_irq_mask, - .irq_unmask = amd_gpio_irq_unmask, -+ .irq_set_wake = amd_gpio_irq_set_wake, - .irq_eoi = amd_gpio_irq_eoi, - .irq_set_type = amd_gpio_irq_set_type, -- .flags = IRQCHIP_SKIP_SET_WAKE, -+ /* -+ * We need to set IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND so that a wake event -+ * also generates an IRQ. We need the IRQ so the irq_handler can clear -+ * the wake event. Otherwise the wake event will never clear and -+ * prevent the system from suspending. -+ */ -+ .flags = IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND, - }; - - #define PIN_IRQ_PENDING (BIT(INTERRUPT_STS_OFF) | BIT(WAKE_STS_OFF)) -@@ -875,7 +914,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; -@@ -898,9 +936,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, -@@ -960,7 +998,7 @@ 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; -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 ca95c2a52e26..663a4ca0580d 100644 ---- a/drivers/platform/x86/amd-pmc.c -+++ b/drivers/platform/x86/amd-pmc.c -@@ -46,26 +46,70 @@ - #define AMD_PMC_RESULT_CMD_UNKNOWN 0xFE - #define AMD_PMC_RESULT_FAILED 0xFF - -+/* FCH SSC Registers */ -+#define FCH_S0I3_ENTRY_TIME_L_OFFSET 0x30 -+#define FCH_S0I3_ENTRY_TIME_H_OFFSET 0x34 -+#define FCH_S0I3_EXIT_TIME_L_OFFSET 0x38 -+#define FCH_S0I3_EXIT_TIME_H_OFFSET 0x3C -+#define FCH_SSC_MAPPING_SIZE 0x800 -+#define FCH_BASE_PHY_ADDR_LOW 0xFED81100 -+#define FCH_BASE_PHY_ADDR_HIGH 0x00000000 -+ -+/* SMU Message Definations */ -+#define SMU_MSG_GETSMUVERSION 0x02 -+#define SMU_MSG_LOG_GETDRAM_ADDR_HI 0x04 -+#define SMU_MSG_LOG_GETDRAM_ADDR_LO 0x05 -+#define SMU_MSG_LOG_START 0x06 -+#define SMU_MSG_LOG_RESET 0x07 -+#define SMU_MSG_LOG_DUMP_DATA 0x08 -+#define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 - /* List of supported CPU ids */ - #define AMD_CPU_ID_RV 0x15D0 - #define AMD_CPU_ID_RN 0x1630 - #define AMD_CPU_ID_PCO AMD_CPU_ID_RV - #define AMD_CPU_ID_CZN AMD_CPU_ID_RN -+#define AMD_CPU_ID_YC 0x14B5 - - #define PMC_MSG_DELAY_MIN_US 100 - #define RESPONSE_REGISTER_LOOP_MAX 200 - -+#define SOC_SUBSYSTEM_IP_MAX 12 -+#define DELAY_MIN_US 2000 -+#define DELAY_MAX_US 3000 - enum amd_pmc_def { - MSG_TEST = 0x01, - MSG_OS_HINT_PCO, - MSG_OS_HINT_RN, - }; - -+struct amd_pmc_bit_map { -+ const char *name; -+ u32 bit_mask; -+}; -+ -+static const struct amd_pmc_bit_map soc15_ip_blk[] = { -+ {"DISPLAY", BIT(0)}, -+ {"CPU", BIT(1)}, -+ {"GFX", BIT(2)}, -+ {"VDD", BIT(3)}, -+ {"ACP", BIT(4)}, -+ {"VCN", BIT(5)}, -+ {"ISP", BIT(6)}, -+ {"NBIO", BIT(7)}, -+ {"DF", BIT(8)}, -+ {"USB0", BIT(9)}, -+ {"USB1", BIT(10)}, -+ {"LAPIC", BIT(11)}, -+ {} -+}; -+ - struct amd_pmc_dev { - void __iomem *regbase; -- void __iomem *smu_base; -+ void __iomem *smu_virt_addr; -+ void __iomem *fch_virt_addr; - u32 base_addr; - u32 cpu_id; -+ u32 active_ips; - struct device *dev; - struct mutex lock; /* generic mutex lock */ - #if IS_ENABLED(CONFIG_DEBUG_FS) -@@ -74,6 +118,7 @@ struct amd_pmc_dev { - }; - - static struct amd_pmc_dev pmc; -+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) - { -@@ -85,13 +130,76 @@ static inline void amd_pmc_reg_write(struct amd_pmc_dev *dev, int reg_offset, u3 - iowrite32(val, dev->regbase + reg_offset); - } - -+struct smu_metrics { -+ u32 table_version; -+ u32 hint_count; -+ u32 s0i3_cyclecount; -+ u32 timein_s0i2; -+ u64 timeentering_s0i3_lastcapture; -+ u64 timeentering_s0i3_totaltime; -+ u64 timeto_resume_to_os_lastcapture; -+ u64 timeto_resume_to_os_totaltime; -+ u64 timein_s0i3_lastcapture; -+ u64 timein_s0i3_totaltime; -+ u64 timein_swdrips_lastcapture; -+ u64 timein_swdrips_totaltime; -+ u64 timecondition_notmet_lastcapture[SOC_SUBSYSTEM_IP_MAX]; -+ u64 timecondition_notmet_totaltime[SOC_SUBSYSTEM_IP_MAX]; -+} __packed; -+ - #ifdef CONFIG_DEBUG_FS - static int smu_fw_info_show(struct seq_file *s, void *unused) - { -+ struct amd_pmc_dev *dev = s->private; -+ struct smu_metrics table; -+ int idx; -+ -+ if (dev->cpu_id == AMD_CPU_ID_PCO) -+ return -EINVAL; -+ -+ memcpy_fromio(&table, dev->smu_virt_addr, sizeof(struct smu_metrics)); -+ -+ 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, "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_puts(s, "\n=== Active time (in us) ===\n"); -+ for (idx = 0 ; idx < SOC_SUBSYSTEM_IP_MAX ; idx++) { -+ if (soc15_ip_blk[idx].bit_mask & dev->active_ips) -+ seq_printf(s, "%-8s : %lld\n", soc15_ip_blk[idx].name, -+ table.timecondition_notmet_lastcapture[idx]); -+ } -+ - return 0; - } - DEFINE_SHOW_ATTRIBUTE(smu_fw_info); - -+static int s0ix_stats_show(struct seq_file *s, void *unused) -+{ -+ struct amd_pmc_dev *dev = s->private; -+ u64 entry_time, exit_time, residency; -+ -+ entry_time = ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_H_OFFSET); -+ entry_time = entry_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_ENTRY_TIME_L_OFFSET); -+ -+ exit_time = ioread32(dev->fch_virt_addr + FCH_S0I3_EXIT_TIME_H_OFFSET); -+ exit_time = exit_time << 32 | ioread32(dev->fch_virt_addr + FCH_S0I3_EXIT_TIME_L_OFFSET); -+ -+ /* It's in 48MHz. We need to convert it */ -+ residency = (exit_time - entry_time) / 48; -+ -+ seq_puts(s, "=== S0ix statistics ===\n"); -+ seq_printf(s, "S0ix Entry Time: %lld\n", entry_time); -+ seq_printf(s, "S0ix Exit Time: %lld\n", exit_time); -+ seq_printf(s, "Residency Time: %lld\n", residency); -+ -+ return 0; -+} -+DEFINE_SHOW_ATTRIBUTE(s0ix_stats); -+ - static void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) - { - debugfs_remove_recursive(dev->dbgfs_dir); -@@ -102,6 +210,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) - dev->dbgfs_dir = debugfs_create_dir("amd_pmc", NULL); - debugfs_create_file("smu_fw_info", 0644, dev->dbgfs_dir, dev, - &smu_fw_info_fops); -+ debugfs_create_file("s0ix_stats", 0644, dev->dbgfs_dir, dev, -+ &s0ix_stats_fops); - } - #else - static inline void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) -@@ -113,6 +223,32 @@ static inline void amd_pmc_dbgfs_unregister(struct amd_pmc_dev *dev) - } - #endif /* CONFIG_DEBUG_FS */ - -+static int amd_pmc_setup_smu_logging(struct amd_pmc_dev *dev) -+{ -+ u32 phys_addr_low, phys_addr_hi; -+ u64 smu_phys_addr; -+ -+ if (dev->cpu_id == AMD_CPU_ID_PCO) -+ return -EINVAL; -+ -+ /* Get Active devices list from SMU */ -+ amd_pmc_send_cmd(dev, 0, &dev->active_ips, SMU_MSG_GET_SUP_CONSTRAINTS, 1); -+ -+ /* Get dram address */ -+ amd_pmc_send_cmd(dev, 0, &phys_addr_low, SMU_MSG_LOG_GETDRAM_ADDR_LO, 1); -+ amd_pmc_send_cmd(dev, 0, &phys_addr_hi, SMU_MSG_LOG_GETDRAM_ADDR_HI, 1); -+ smu_phys_addr = ((u64)phys_addr_hi << 32 | phys_addr_low); -+ -+ dev->smu_virt_addr = devm_ioremap(dev->dev, smu_phys_addr, sizeof(struct smu_metrics)); -+ if (!dev->smu_virt_addr) -+ return -ENOMEM; -+ -+ /* Start the logging */ -+ amd_pmc_send_cmd(dev, 0, NULL, SMU_MSG_LOG_START, 0); -+ -+ return 0; -+} -+ - static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) - { - u32 value; -@@ -127,10 +263,9 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev) - dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value); - } - --static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set) -+static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set, u32 *data, u8 msg, bool ret) - { - int rc; -- u8 msg; - u32 val; - - mutex_lock(&dev->lock); -@@ -150,8 +285,8 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set) - amd_pmc_reg_write(dev, AMD_PMC_REGISTER_ARGUMENT, set); - - /* Write message ID to message ID register */ -- msg = (dev->cpu_id == AMD_CPU_ID_RN) ? MSG_OS_HINT_RN : MSG_OS_HINT_PCO; - amd_pmc_reg_write(dev, AMD_PMC_REGISTER_MESSAGE, msg); -+ - /* Wait until we get a valid response */ - rc = readx_poll_timeout(ioread32, dev->regbase + AMD_PMC_REGISTER_RESPONSE, - val, val != 0, PMC_MSG_DELAY_MIN_US, -@@ -163,6 +298,11 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set) - - switch (val) { - case AMD_PMC_RESULT_OK: -+ if (ret) { -+ /* PMFW may take longer time to return back the data */ -+ usleep_range(DELAY_MIN_US, 10 * DELAY_MAX_US); -+ *data = amd_pmc_reg_read(dev, AMD_PMC_REGISTER_ARGUMENT); -+ } - break; - case AMD_PMC_RESULT_CMD_REJECT_BUSY: - dev_err(dev->dev, "SMU not ready. err: 0x%x\n", val); -@@ -182,32 +322,54 @@ static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, bool set) - - out_unlock: - mutex_unlock(&dev->lock); -+ amd_pmc_dump_registers(dev); - return rc; - } - -+static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev) -+{ -+ switch (dev->cpu_id) { -+ case AMD_CPU_ID_PCO: -+ return MSG_OS_HINT_PCO; -+ case AMD_CPU_ID_RN: -+ case AMD_CPU_ID_YC: -+ return MSG_OS_HINT_RN; -+ } -+ return -EINVAL; -+} -+ - static int __maybe_unused amd_pmc_suspend(struct device *dev) - { - struct amd_pmc_dev *pdev = dev_get_drvdata(dev); - int rc; -+ u8 msg; - -- rc = amd_pmc_send_cmd(pdev, 1); -+ /* Reset and Start SMU logging - to monitor the s0i3 stats */ -+ amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_RESET, 0); -+ amd_pmc_send_cmd(pdev, 0, NULL, SMU_MSG_LOG_START, 0); -+ -+ 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"); - -- amd_pmc_dump_registers(pdev); -- return 0; -+ return rc; - } - - static int __maybe_unused amd_pmc_resume(struct device *dev) - { - struct amd_pmc_dev *pdev = dev_get_drvdata(dev); - int rc; -+ u8 msg; - -- rc = amd_pmc_send_cmd(pdev, 0); -+ /* 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"); - -- amd_pmc_dump_registers(pdev); - return 0; - } - -@@ -216,6 +378,7 @@ static const struct dev_pm_ops amd_pmc_pm_ops = { - }; - - static const struct pci_device_id pmc_pci_ids[] = { -+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) }, -@@ -227,9 +390,8 @@ static int amd_pmc_probe(struct platform_device *pdev) - { - struct amd_pmc_dev *dev = &pmc; - struct pci_dev *rdev; -- u32 base_addr_lo; -- u32 base_addr_hi; -- u64 base_addr; -+ u32 base_addr_lo, base_addr_hi; -+ u64 base_addr, fch_phys_addr; - int err; - u32 val; - -@@ -279,9 +441,21 @@ static int amd_pmc_probe(struct platform_device *pdev) - if (!dev->regbase) - return -ENOMEM; - -- amd_pmc_dump_registers(dev); -- - mutex_init(&dev->lock); -+ -+ /* Use FCH registers to get the S0ix stats */ -+ base_addr_lo = FCH_BASE_PHY_ADDR_LOW; -+ 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; -+ -+ /* Use SMU to get the s0i3 debug stats */ -+ err = amd_pmc_setup_smu_logging(dev); -+ if (err) -+ dev_err(dev->dev, "SMU debugging info not supported on this platform\n"); -+ - platform_set_drvdata(pdev, dev); - amd_pmc_dbgfs_register(dev); - return 0; -@@ -298,6 +472,8 @@ static int amd_pmc_remove(struct platform_device *pdev) - - static const struct acpi_device_id amd_pmc_acpi_ids[] = { - {"AMDI0005", 0}, -+ {"AMDI0006", 0}, -+ {"AMDI0007", 0}, - {"AMD0004", 0}, - { } - }; -diff --git a/include/linux/acpi.h b/include/linux/acpi.h -index c60745f657e9..dd0dafd21e33 100644 ---- a/include/linux/acpi.h -+++ b/include/linux/acpi.h -@@ -1004,6 +1004,7 @@ int acpi_dev_resume(struct device *dev); - int acpi_subsys_runtime_suspend(struct device *dev); - int acpi_subsys_runtime_resume(struct device *dev); - int acpi_dev_pm_attach(struct device *dev, bool power_on); -+bool acpi_storage_d3(struct device *dev); - #else - static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; } - static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; } -@@ -1011,6 +1012,10 @@ static inline int acpi_dev_pm_attach(struct device *dev, bool power_on) - { - return 0; - } -+static inline bool acpi_storage_d3(struct device *dev) -+{ -+ return false; -+} - #endif - - #if defined(CONFIG_ACPI) && defined(CONFIG_PM_SLEEP) --- -2.33.0 - |