// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2010 Google Inc. All Rights Reserved.
* Author: dlaurie@google.com (Duncan Laurie)
*
* Re-worked to expose sysfs APIs by mikew@google.com (Mike Waychison)
*
* EFI SMI interface for Google platforms
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/dmi.h>
#include <linux/kdebug.h>
#include <linux/reboot.h>
#include <linux/efi.h>
#include <linux/module.h>
#include <linux/ucs2_string.h>
#include <linux/suspend.h>
#define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */
/* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */
#define GSMI_SHUTDOWN_NMIWDT 1 /* NMI Watchdog */
#define GSMI_SHUTDOWN_PANIC 2 /* Panic */
#define GSMI_SHUTDOWN_OOPS 3 /* Oops */
#define GSMI_SHUTDOWN_DIE 4 /* Die -- No longer meaningful */
#define GSMI_SHUTDOWN_MCE 5 /* Machine Check */
#define GSMI_SHUTDOWN_SOFTWDT 6 /* Software Watchdog */
#define GSMI_SHUTDOWN_MBE 7 /* Uncorrected ECC */
#define GSMI_SHUTDOWN_TRIPLE 8 /* Triple Fault */
#define DRIVER_VERSION "1.0"
#define GSMI_GUID_SIZE 16
#define GSMI_BUF_SIZE 1024
#define GSMI_BUF_ALIGN sizeof(u64)
#define GSMI_CALLBACK 0xef
/* SMI return codes */
#define GSMI_SUCCESS 0x00
#define GSMI_UNSUPPORTED2 0x03
#define GSMI_LOG_FULL 0x0b
#define GSMI_VAR_NOT_FOUND 0x0e
#define GSMI_HANDSHAKE_SPIN 0x7d
#define GSMI_HANDSHAKE_CF 0x7e
#define GSMI_HANDSHAKE_NONE 0x7f
#define GSMI_INVALID_PARAMETER 0x82
#define GSMI_UNSUPPORTED 0x83
#define GSMI_BUFFER_TOO_SMALL 0x85
#define GSMI_NOT_READY 0x86
#define GSMI_DEVICE_ERROR 0x87
#define GSMI_NOT_FOUND 0x8e
#define QUIRKY_BOARD_HASH 0x78a30a50
/* Internally used commands passed to the firmware */
#define GSMI_CMD_GET_NVRAM_VAR 0x01
#define GSMI_CMD_GET_NEXT_VAR 0x02
#define GSMI_CMD_SET_NVRAM_VAR 0x03
#define GSMI_CMD_SET_EVENT_LOG 0x08
#define GSMI_CMD_CLEAR_EVENT_LOG 0x09
#define GSMI_CMD_LOG_S0IX_SUSPEND 0x0a
#define GSMI_CMD_LOG_S0IX_RESUME 0x0b
#define GSMI_CMD_CLEAR_CONFIG 0x20
#define GSMI_CMD_HANDSHAKE_TYPE 0xC1
#define GSMI_CMD_RESERVED 0xff
/* Magic entry type for kernel events */
#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD
/* SMI buffers must be in 32bit physical address space */
struct gsmi_buf {
u8 *start; /* start of buffer */
size_t length; /* length of buffer */
dma_addr_t handle; /* dma allocation handle */
u32 address; /* physical address of buffer */
};
static struct gsmi_device {
struct platform_device *pdev; /* platform device */
struct gsmi_buf *name_buf; /* variable name buffer */
struct gsmi_buf *data_buf; /* generic data buffer */
struct gsmi_buf *param_buf; /* parameter buffer */
spinlock_t lock; /* serialize access to SMIs */
u16 smi_cmd; /* SMI command port */
int handshake_type; /* firmware handler interlock type */
struct dma_pool *dma_pool; /* DMA buffer pool */
} gsmi_dev;
/* Packed structures for communicating with the firmware */
struct gsmi_nvram_var_param {
efi_guid_t guid;
u32 name_ptr;
u32 attributes;
u32 data_len;
u32 data_ptr;
} __packed;
struct gsmi_get_next_var_param {
u8 guid[GSMI_GUID_SIZE];
u32 name_ptr;
u32 name_len;
} __packed;
struct gsmi_set_eventlog_param {
u32 data_ptr;
u32 data_len;
u32 type;
} __packed;
/* Event log formats */
struct gsmi_log_entry_type_1 {
u16 type;
u32 instance;
} __packed;
/*
* Some platforms don't have explicit SMI handshake
* and need to wait for SMI to complete.
*/
#define GSMI_DEFAULT_SPINCOUNT 0x10000
static unsigned int spincount = GSMI_DEFAULT_SPINCOUNT;
module_param(spincount, uint, 0600);
MODULE_PARM_DESC(spincount,
"The number of loop iterations to use when using the spin handshake.");
/*
* Platforms might not support S0ix logging in their GSMI handlers. In order to
* avoid any side-effects of generating an SMI for S0ix logging, use the S0ix
* related GSMI commands only for those platforms that explicitly enable this
* option.
*/
static bool s0ix_logging_enable;
module_param(s0ix_logging_enable, bool, 0600);
static struct gsmi_buf *gsmi_buf_alloc(void)
{
struct gsmi_buf *smibuf;
smibuf = kzalloc(sizeof(*smibuf), GFP_KERNEL);
if (!smibuf) {
printk(KERN_ERR "gsmi: out of memory\n");
return NULL;
}
/* allocate buffer in 32bit address space */
smibuf->start = dma_pool_alloc(gsmi_dev.dma_pool, GFP_KERNEL,
&smibuf->handle);
if (!smibuf->start) {
printk(KERN_ERR "gsmi: failed to allocate name buffer\n");
kfree(smibuf);
return NULL;
}
/* fill in the buffer handle */
smibuf->length = GSMI_BUF_SIZE;
smibuf->address = (u32)virt_to_phys(smibuf->start);
return smibuf;
}
static void gsmi_buf_free(struct gsmi_buf *smibuf)
{
if (smibuf) {
if (smibuf->start)
dma_pool_free(gsmi_dev.dma_pool, smibuf->start,
smibuf->handle);
kfree(smibuf);
}
}
/*
* Make a call to gsmi func(sub). GSMI error codes are translated to
* in-kernel errnos (0 on success, -ERRNO on error).
*/
static int gsmi_exec(u8 func, u8 sub)