From: zhaoxp3 Date: Mon, 6 Aug 2018 04:31:54 +0000 (+0800) Subject: soc:qcom: add bootinfo support X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=6e7af17f2b35e1f834da40c99d68cc258d1c9e87;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git soc:qcom: add bootinfo support The interface would 1. export /proc/bootinfo to user space, bugreport can use it 2. annotate boot info to last_kmsg port the following gerrits http://gerrit.mot.com/862769 http://gerrit.mot.com/848543 http://gerrit.mot.com/845197 http://gerrit.mot.com/792195 http://gerrit.mot.com/782682 Change-Id: Icc0e48f833b119dad73a07cd564e24f169d1ac4d Signed-off-by: zhaoxp3 Reviewed-on: https://gerrit.mot.com/1221136 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Submit-Approved: Jira Key --- diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig index 515abffb8dc6..56c8a9047206 100644 --- a/drivers/soc/samsung/Kconfig +++ b/drivers/soc/samsung/Kconfig @@ -194,4 +194,12 @@ config DEBUG_SNAPSHOT_LOGGING_SMC depends on DEBUG_SNAPSHOT default y +config BOOTINFO + bool "Boot Information Feature" + default n + help + This feature provides access to certain boot information + from both kernel context (via function call) and user + context (via /proc/bootinfo). + endif diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index 9ad490c15668..7a7644e388aa 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -72,3 +72,6 @@ obj-$(CONFIG_EXYNOS_HIU) += exynos-hiu.o # HAFM & HAFM-TB obj-$(CONFIG_EXYNOS_PSTATE_HAFM) += exynos-hafm.o obj-$(CONFIG_EXYNOS_PSTATE_HAFM_TB) += exynos-hafm-tb.o + +# bootinfo +obj-$(CONFIG_BOOTINFO) += bootinfo.o diff --git a/drivers/soc/samsung/bootinfo.c b/drivers/soc/samsung/bootinfo.c new file mode 100644 index 000000000000..264b4fde8627 --- /dev/null +++ b/drivers/soc/samsung/bootinfo.c @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2009 Motorola, Inc. + * Copyright (C) 2012 Motorola Mobility. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ARM64 +/* these are defined in kernel/setup.c for "arm" targets */ +unsigned int system_rev; +EXPORT_SYMBOL(system_rev); + +unsigned int system_serial_low; +EXPORT_SYMBOL(system_serial_low); + +unsigned int system_serial_high; +EXPORT_SYMBOL(system_serial_high); +#endif + +/* + * EMIT_BOOTINFO and EMIT_BOOTINFO_STR are used to emit the bootinfo + * information for data provided via DEVICE TREE. + * + * The format for all bootinfo lines is "name : val" and these macros + * enforce that format. + * + * strname is the name printed in the name/val pair. + * name is the name of the function to call + * + * EMIT_BOOTINFO and EMIT_BOOTINFO_STR depend on buf and len to already + * be defined. + */ +#define EMIT_BOOTINFO(strname, fmt, name) \ + do { \ + seq_printf(m, strname ": " fmt "\n", \ + bi_##name()); \ + } while (0) + +#define EMIT_BOOTINFO_STR(strname, strval) \ + do { \ + if (strlen(strval) == 0) { \ + seq_printf(m, "%s: UNKNOWN\n", \ + strname); \ + } else { \ + seq_printf(m, "%s: %s\n", \ + strname, strval); \ + } \ + } while (0) + +#define EMIT_BOOTINFO_LASTKMSG(buf, strname, fmt, name) \ + do { \ + snprintf(buf, sizeof(buf), strname ": " fmt "\n", \ + bi_##name()); \ + pstore_annotate(buf); \ + } while (0) + +/*-------------------------------------------------------------------------*/ + +/* + * powerup_reason contains the powerup reason provided by the ATAGs when + * the machine boots. + * + * Exported symbols: + * bi_powerup_reason() -- returns the powerup reason + */ + +#ifdef CONFIG_OF +static void of_powerup(u32 *pwr) +{ + struct device_node *n = of_find_node_by_path("/chosen"); + + of_property_read_u32(n, "mmi,powerup_reason", pwr); + of_node_put(n); +} +#else +static inline void of_powerup(u32 *pwr) { } +#endif + +u32 bi_powerup_reason(void) +{ + u32 reason = PU_REASON_INVALID; + + of_powerup(&reason); + return reason; +} +EXPORT_SYMBOL(bi_powerup_reason); + +#define EMIT_POWERUPREASON() \ + EMIT_BOOTINFO("POWERUPREASON", "0x%08x", powerup_reason) + + +/* + * mbm_version contains the MBM version. + * mbm_loader_version contains the MBM loader version. + * mbm_version and mbm_loader_version default to 0 if they are + * not set. + * + * Exported symbols: + * bi_mbm_version() -- returns the MBM version + */ +#ifdef CONFIG_OF +static void of_mbmver(u32 *ver) +{ + struct device_node *n = of_find_node_by_path("/chosen"); + + of_property_read_u32(n, "mmi,mbmversion", ver); + of_node_put(n); +} +#else +static inline void of_mbmver(u32 *ver) { } +#endif + +u32 bi_mbm_version(void) +{ + u32 version = 0xFFFFFFFF; + + of_mbmver(&version); + return version; +} +EXPORT_SYMBOL(bi_mbm_version); + +#define EMIT_MBM_VERSION() \ + EMIT_BOOTINFO("MBM_VERSION", "0x%08x", mbm_version) + +/* + * boot_seq contains the boot sequence number. + * boot_seq default to 0 if it is not set. + * + * Exported symbols: + * bi_boot_seq() -- returns the boot seq + */ +#ifdef CONFIG_OF +static void of_bootseq(u32 *seq) +{ + struct device_node *n = of_find_node_by_path("/chosen"); + + of_property_read_u32(n, "mmi,boot_seq", seq); + of_node_put(n); +} +#else +static inline void of_boot_seq(u32 *seq) { } +#endif + +u32 bi_boot_seq(void) +{ + u32 seq = 0x0; + + of_bootseq(&seq); + return seq; +} +EXPORT_SYMBOL(bi_boot_seq); + +#define EMIT_BOOT_SEQ() \ + EMIT_BOOTINFO("BOOT_SEQ", "0x%08x", boot_seq) + +/* + * BL build signature a succession of lines of text each denoting + * build/versioning information for each bootloader component, + * as passed along from bootloader via ATAG_BL_BUILD_SIG(s) + */ + +#define MAX_BL_BUILD_SIG 16 +#define MAX_BLD_SIG_ITEM 20 +#define MAX_BLD_SIG_VALUE 80 + +struct bl_build_sig { + char item[MAX_BLD_SIG_ITEM]; + char value[MAX_BLD_SIG_VALUE]; +}; + +static unsigned bl_build_sig_count; +static struct bl_build_sig bl_build_sigs[MAX_BL_BUILD_SIG]; + +static void convert_to_upper(char *str) +{ + while (*str) { + *str = toupper(*str); + str++; + } +} + +void bi_add_bl_build_sig(char *bld_sig) +{ + int pos; + char *value; + char *ptr; + + if (!bld_sig || (bl_build_sig_count >= MAX_BL_BUILD_SIG)) { + return; + } + + value = (char *)memchr((void *)bld_sig, '=', MAX_BLD_SIG_ITEM); + if (!value) { + return; + } + pos = value - bld_sig; + + ptr = bl_build_sigs[bl_build_sig_count].item; + strlcpy(ptr, bld_sig, pos+1); + convert_to_upper(ptr); + + ptr = bl_build_sigs[bl_build_sig_count].value; + strlcpy(ptr, value+1, MAX_BLD_SIG_VALUE); + + bl_build_sig_count++; + + return; +} +EXPORT_SYMBOL(bi_add_bl_build_sig); + +#ifdef CONFIG_OF +static void __init of_blsig(void) +{ + struct property *p; + struct device_node *n; + + /* Only do this one time once we find the sigs */ + if (bl_build_sig_count) + return; + + n = of_find_node_by_path("/chosen/mmi,bl_sigs"); + if (n == NULL) + return; + + for_each_property_of_node(n, p) + if (strcmp(p->name, "name")) + bi_add_bl_build_sig(p->value); + + of_node_put(n); +} +static void __init of_systemrev(void) +{ + struct device_node *n = of_find_node_by_path("/chosen"); + if (n == NULL) + return; + + of_property_read_u32(n, "linux,hwrev", &system_rev); + of_property_read_u32(n, "linux,seriallow", &system_serial_low); + of_property_read_u32(n, "linux,serialhigh", &system_serial_high); + of_node_put(n); +} +#else +static inline void of_blsig(void) { } +static inline void of_systemrev(void) { } +#endif + +#define EMIT_BL_BUILD_SIG() \ + do { \ + int i; \ + for (i = 0; i < bl_build_sig_count; i++) { \ + EMIT_BOOTINFO_STR(bl_build_sigs[i].item, \ + bl_build_sigs[i].value); \ + } \ + } while (0) + +/* System revision s global symbol exported by setup.c + * use wrapper to maintain coherent format with the other + * boot info elements + */ + +static u32 bi_hwrev(void) +{ + return system_rev; +} + +#define EMIT_HWREV() \ + EMIT_BOOTINFO("HW_REV", "0x%04x", hwrev) + +/* Serial high and low are symbols exported by setup.c + * use wrapper to maintain coherent format with the other + * boot info elements + */ + +static u64 bi_serial(void) +{ + return ((u64)system_serial_high << 32) + | (u64)system_serial_low; +} + +#define EMIT_SERIAL() \ + EMIT_BOOTINFO("SERIAL", "0x%llx", serial) + +#define BOOTREASON_MAX_LEN 64 +static char bootreason[BOOTREASON_MAX_LEN]; +int __init bootinfo_bootreason_init(char *s) +{ + strlcpy(bootreason, s, BOOTREASON_MAX_LEN); + return 1; +} +__setup("androidboot.bootreason=", bootinfo_bootreason_init); + +const char *bi_bootreason(void) +{ + return bootreason; +} +EXPORT_SYMBOL(bi_bootreason); + +static char bootmode[BOOTMODE_MAX_LEN]; +int __init bootinfo_bootmode_init(char *s) +{ + strlcpy(bootmode, s, BOOTMODE_MAX_LEN); + return 1; +} +__setup("androidboot.mode=", bootinfo_bootmode_init); + +const char *bi_bootmode(void) +{ + return bootmode; +} +EXPORT_SYMBOL(bi_bootmode); + +static void bootinfo_lastkmsg_annotate_bl(struct bl_build_sig *bl) +{ + int i; + char buf[BOOTREASON_MAX_LEN]; + for (i = 0; i < bl_build_sig_count; i++) { + bl[i].item[MAX_BLD_SIG_ITEM - 1] = 0; + bl[i].value[MAX_BLD_SIG_VALUE - 1] = 0; + pstore_annotate(bl[i].item); + pstore_annotate("="); + pstore_annotate(bl[i].value); + pstore_annotate("\n"); + } + + EMIT_BOOTINFO_LASTKMSG(buf, "MBM_VERSION", "0x%08x", mbm_version); + pstore_annotate(linux_banner); + EMIT_BOOTINFO_LASTKMSG(buf, "SERIAL", "0x%llx", serial); + EMIT_BOOTINFO_LASTKMSG(buf, "HW_REV", "0x%04x", hwrev); + EMIT_BOOTINFO_LASTKMSG(buf, "BOOT_SEQ", "0x%08x", boot_seq); + persistent_ram_annotation_append("POWERUPREASON: 0x%08x\n", + bi_powerup_reason()); + persistent_ram_annotation_append("\nBoot info:\n"); + persistent_ram_annotation_append("Last boot reason: %s\n", bootreason); +} + +/* get_bootinfo fills in the /proc/bootinfo information. + * We currently only have the powerup reason, mbm_version, serial + * and hwrevision. + */ + +static int get_bootinfo(struct seq_file *m, void *v) +{ + int len = 0; + + EMIT_SERIAL(); + EMIT_HWREV(); + EMIT_POWERUPREASON(); + EMIT_MBM_VERSION(); + EMIT_BL_BUILD_SIG(); + EMIT_BOOT_SEQ(); + EMIT_BOOTINFO("Last boot reason", "%s", bootreason); + + return len; +} + +static struct proc_dir_entry *proc_bootinfo; + +static int bootinfo_proc_open(struct inode *inode, struct file *file) { + return single_open(file, get_bootinfo, PDE_DATA(inode)); +} + +static const struct file_operations bootinfo_proc_fops = { + .open = bootinfo_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +int __init bootinfo_init_module(void) +{ + of_blsig(); + of_systemrev(); + proc_bootinfo = &proc_root; + if (!proc_create_data("bootinfo", 0, NULL, &bootinfo_proc_fops, NULL)) + printk(KERN_ERR "Failed to create bootinfo entry"); + bootinfo_lastkmsg_annotate_bl(bl_build_sigs); + return 0; +} + +void __exit bootinfo_cleanup_module(void) +{ + if (proc_bootinfo) { + remove_proc_entry("bootinfo", proc_bootinfo); + proc_bootinfo = NULL; + } +} + +module_init(bootinfo_init_module); +module_exit(bootinfo_cleanup_module); + +MODULE_AUTHOR("MOTOROLA"); diff --git a/include/soc/samsung/bootinfo.h b/include/soc/samsung/bootinfo.h new file mode 100644 index 000000000000..1b1ae340cb6f --- /dev/null +++ b/include/soc/samsung/bootinfo.h @@ -0,0 +1,109 @@ +/* + * linux/include/asm/bootinfo.h: Include file for boot information + * provided on Motorola phones + * + * Copyright (C) 2009 Motorola, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Date Author Comment + * 01/07/2009 Motorola Initial version + */ + +#ifndef __ASMARM_BOOTINFO_H +#define __ASMARM_BOOTINFO_H + + +/* + * These #defines are used for the bits in powerup_reason. + */ +#define PU_REASON_USB_CABLE 0x00000010 /* Bit 4 */ +#define PU_REASON_FACTORY_CABLE 0x00000020 /* Bit 5 */ +#define PU_REASON_PWR_KEY_PRESS 0x00000080 /* Bit 7 */ +#define PU_REASON_CHARGER 0x00000100 /* Bit 8 */ +#define PU_REASON_POWER_CUT 0x00000200 /* bit 9 */ +#define PU_REASON_SW_AP_RESET 0x00004000 /* Bit 14 */ +#define PU_REASON_WDOG_AP_RESET 0x00008000 /* Bit 15 */ +#define PU_REASON_AP_KERNEL_PANIC 0x00020000 /* Bit 17 */ +#define PU_REASON_MODEM_RESET 0x80000000 /* Bit 31 */ +#define PU_REASON_INVALID 0xFFFFFFFF + + +#if !defined(__KERNEL__) || defined(CONFIG_BOOTINFO) + +/* + * These #defines are used for the battery status at boot. + * When no battery is present, the status is BATTERY_LO_VOLTAGE. + */ +#define BATTERY_GOOD_VOLTAGE 1 +#define BATTERY_LO_VOLTAGE 2 +#define BATTERY_UNKNOWN (-1) + +/* + * /proc/bootinfo has a strict format. Each line contains a name/value + * pair which are separated with a colon and a single space on both + * sides of the colon. The following defines help you size the + * buffers used to read the data from /proc/bootinfo. + * + * BOOTINFO_MAX_NAME_LEN: maximum size in bytes of a name in the + * bootinfo line. Don't forget to add space + * for the NUL if you need it. + * BOOTINFO_MAX_VAL_LEN: maximum size in bytes of a value in the + * bootinfo line. Don't forget to add space + * for the NUL if you need it. + * BOOTINFO_BUF_SIZE: size in bytes of buffer that is large enough + * to read a /proc/bootinfo line. The extra + * 3 is for the " : ". Don't forget to add + * space for the NUL and newline if you + * need them. + */ +#define BOOTINFO_MAX_NAME_LEN 32 +#define BOOTINFO_MAX_VAL_LEN 128 +#define BOOTINFO_BUF_SIZE (BOOTINFO_MAX_NAME_LEN + \ + 3 + BOOTINFO_MAX_VAL_LEN) + +#endif + + +#if defined(__KERNEL__) +#if defined(CONFIG_BOOTINFO) + +extern struct proc_dir_entry proc_root; + +u32 bi_powerup_reason(void); +const char *bi_bootreason(void); +u32 bi_mbm_version(void); +#define BOOTMODE_MAX_LEN 64 +const char *bi_bootmode(void); + +void bi_add_bl_build_sig(char *bld_sig); + +#ifdef CONFIG_ARM64 +extern unsigned int system_rev; +extern unsigned int system_serial_low; +extern unsigned int system_serial_high; +#else +#include +#endif + +#else /* defined(CONFIG_BOOTINFO) */ +static inline u32 bi_powerup_reason(void) { return PU_REASON_INVALID; } +static inline const char *bi_bootreason(void) { return "NOTSUPPORTED"; } +static inline const char *bi_bootmode(void) { return "NOTSUPPORTED"; } +static inline u32 bi_mbm_version(void) { return 0xFFFFFFFF; } +#endif /* !defined(CONFIG_BOOTINFO) */ +#endif /* defined(__KERNEL__) */ + +#endif