Skip to content

Commit 8942b2d

Browse files
Furquan Shaikhgregkh
authored andcommitted
gsmi: Add GSMI commands to log S0ix info
Add new GSMI commands (GSMI_CMD_LOG_S0IX_SUSPEND = 0xa, GSMI_CMD_LOG_S0IX_RESUME = 0xb) that allow firmware to log any information during S0ix suspend/resume paths. Traditional ACPI suspend S3 involves BIOS both during the suspend and the resume paths. However, modern suspend type like S0ix does not involve firmware on either of the paths. This command gives the firmware an opportunity to log any required information about the suspend and resume operations e.g. wake sources. Additionally, this change adds a module parameter to allow platforms to specifically enable S0ix logging if required. This prevents any other platforms from unnecessarily making a GSMI call which could have any side-effects. Tested by verifying that wake sources are correctly logged in eventlog. Signed-off-by: Furquan Shaikh <furquan@chromium.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org> Reviewed-by: Rajat Jain <rajatja@chromium.org> Signed-off-by: Furquan Shaikh <furquan@google.com> Tested-by: Furquan Shaikh <furquan@chromium.org> Reviewed-by: Aaron Durbin <adurbin@chromium.org> [zwisler: update changelog for upstream] Signed-off-by: Ross Zwisler <zwisler@google.com> Reviewed-by: Guenter Roeck <groeck@chromium.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d31655b commit 8942b2d

File tree

1 file changed

+92
-1
lines changed

1 file changed

+92
-1
lines changed

drivers/firmware/google/gsmi.c

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <linux/efi.h>
3030
#include <linux/module.h>
3131
#include <linux/ucs2_string.h>
32+
#include <linux/suspend.h>
3233

3334
#define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */
3435
/* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */
@@ -70,6 +71,8 @@
7071
#define GSMI_CMD_SET_NVRAM_VAR 0x03
7172
#define GSMI_CMD_SET_EVENT_LOG 0x08
7273
#define GSMI_CMD_CLEAR_EVENT_LOG 0x09
74+
#define GSMI_CMD_LOG_S0IX_SUSPEND 0x0a
75+
#define GSMI_CMD_LOG_S0IX_RESUME 0x0b
7376
#define GSMI_CMD_CLEAR_CONFIG 0x20
7477
#define GSMI_CMD_HANDSHAKE_TYPE 0xC1
7578

@@ -122,7 +125,6 @@ struct gsmi_log_entry_type_1 {
122125
u32 instance;
123126
} __packed;
124127

125-
126128
/*
127129
* Some platforms don't have explicit SMI handshake
128130
* and need to wait for SMI to complete.
@@ -133,6 +135,15 @@ module_param(spincount, uint, 0600);
133135
MODULE_PARM_DESC(spincount,
134136
"The number of loop iterations to use when using the spin handshake.");
135137

138+
/*
139+
* Platforms might not support S0ix logging in their GSMI handlers. In order to
140+
* avoid any side-effects of generating an SMI for S0ix logging, use the S0ix
141+
* related GSMI commands only for those platforms that explicitly enable this
142+
* option.
143+
*/
144+
static bool s0ix_logging_enable;
145+
module_param(s0ix_logging_enable, bool, 0600);
146+
136147
static struct gsmi_buf *gsmi_buf_alloc(void)
137148
{
138149
struct gsmi_buf *smibuf;
@@ -781,6 +792,78 @@ static const struct platform_device_info gsmi_dev_info = {
781792
.dma_mask = DMA_BIT_MASK(32),
782793
};
783794

795+
#ifdef CONFIG_PM
796+
static void gsmi_log_s0ix_info(u8 cmd)
797+
{
798+
unsigned long flags;
799+
800+
/*
801+
* If platform has not enabled S0ix logging, then no action is
802+
* necessary.
803+
*/
804+
if (!s0ix_logging_enable)
805+
return;
806+
807+
spin_lock_irqsave(&gsmi_dev.lock, flags);
808+
809+
memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
810+
811+
gsmi_exec(GSMI_CALLBACK, cmd);
812+
813+
spin_unlock_irqrestore(&gsmi_dev.lock, flags);
814+
}
815+
816+
static int gsmi_log_s0ix_suspend(struct device *dev)
817+
{
818+
/*
819+
* If system is not suspending via firmware using the standard ACPI Sx
820+
* types, then make a GSMI call to log the suspend info.
821+
*/
822+
if (!pm_suspend_via_firmware())
823+
gsmi_log_s0ix_info(GSMI_CMD_LOG_S0IX_SUSPEND);
824+
825+
/*
826+
* Always return success, since we do not want suspend
827+
* to fail just because of logging failure.
828+
*/
829+
return 0;
830+
}
831+
832+
static int gsmi_log_s0ix_resume(struct device *dev)
833+
{
834+
/*
835+
* If system did not resume via firmware, then make a GSMI call to log
836+
* the resume info and wake source.
837+
*/
838+
if (!pm_resume_via_firmware())
839+
gsmi_log_s0ix_info(GSMI_CMD_LOG_S0IX_RESUME);
840+
841+
/*
842+
* Always return success, since we do not want resume
843+
* to fail just because of logging failure.
844+
*/
845+
return 0;
846+
}
847+
848+
static const struct dev_pm_ops gsmi_pm_ops = {
849+
.suspend_noirq = gsmi_log_s0ix_suspend,
850+
.resume_noirq = gsmi_log_s0ix_resume,
851+
};
852+
853+
static int gsmi_platform_driver_probe(struct platform_device *dev)
854+
{
855+
return 0;
856+
}
857+
858+
static struct platform_driver gsmi_driver_info = {
859+
.driver = {
860+
.name = "gsmi",
861+
.pm = &gsmi_pm_ops,
862+
},
863+
.probe = gsmi_platform_driver_probe,
864+
};
865+
#endif
866+
784867
static __init int gsmi_init(void)
785868
{
786869
unsigned long flags;
@@ -792,6 +875,14 @@ static __init int gsmi_init(void)
792875

793876
gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command;
794877

878+
#ifdef CONFIG_PM
879+
ret = platform_driver_register(&gsmi_driver_info);
880+
if (unlikely(ret)) {
881+
printk(KERN_ERR "gsmi: unable to register platform driver\n");
882+
return ret;
883+
}
884+
#endif
885+
795886
/* register device */
796887
gsmi_dev.pdev = platform_device_register_full(&gsmi_dev_info);
797888
if (IS_ERR(gsmi_dev.pdev)) {

0 commit comments

Comments
 (0)