// SPDX-License-Identifier: GPL-2.0+ /** @file avm_reboot_status.c * * mbahr: * 1.) hold and get reboot-status after Soft/NMI-Reboot * 2.) handle die-notifier * 3.) handle panic-notifier */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) #include #endif #include #include #include #include #if defined(CONFIG_AVM_FASTIRQ) #if defined(CONFIG_AVM_FASTIRQ_ARCH_ARM_COMMON) #include #else #include #endif #endif /*--- #if defined(CONFIG_AVM_FASTIRQ) ---*/ #include "avm_sammel.h" #define MAILBOX_SIZE 512U #if defined(CONFIG_SOC_GRX500) #include "arch_grx.h" #endif /*--- #if defined(CONFIG_SOC_GRX500) ---*/ #if defined(CONFIG_VR9) || defined(CONFIG_AR10) #include "arch_ifx.h" #endif /*--- #if defined(CONFIG_VR9) || defined(CONFIG_AR10) ---*/ #if defined(CONFIG_MACH_PUMA6) #include "arch_puma6a.h" #elif defined(CONFIG_X86) && !defined(CONFIG_X86_PUMA7) #include "arch_puma6x.h" #elif defined(CONFIG_MACH_PUMA7) #if defined(CONFIG_X86_PUMA7) #include "arch_puma7x.h" #else #include "arch_puma7.h" #endif #endif #if defined(CONFIG_MACH_BCM963138) || defined(CONFIG_BCM963178) #include "arch_brcma.h" #endif /*--- #if defined(CONFIG_MACH_BCM963138) || defined(CONFIG_BCM963178) ---*/ #if defined(CONFIG_ARCH_IPQ40XX) #include "arch_ipq40xx.h" #endif /*--- #if defined(CONFIG_ARCH_IPQ40XX) ---*/ #if defined(CONFIG_ARCH_IPQ5018) #include "arch_ipq5018.h" #endif #if defined(CONFIG_SOC_AR724X) || defined(CONFIG_SOC_AR934X) || \ defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA953X) || \ defined(CONFIG_SOC_QCA956X) #include "arch_scrpn.h" #endif /*--- #if defined(CONFIG_SOC_AR724X) || defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA953X) || defined(CONFIG_SOC_QCA956X) ---*/ #include #define DEBUG_MAILBOX 0 #define AVM_REBOOT_INFO_CURRENT 0 #define AVM_REBOOT_INFO_NEXT 1 static struct avm_reboot_info avm_reboot_info[2]; static struct avm_firmware_build_info reboot_buildinfo; /* parsed from mailbox */ /** * \brief Deliver last reboot-status */ enum _avm_reset_status avm_reset_status(void) { return avm_reboot_info[AVM_REBOOT_INFO_CURRENT].reboot_status; } EXPORT_SYMBOL(avm_reset_status); enum _avm_reset_status avm_next_reset_status(void) { return avm_reboot_info[AVM_REBOOT_INFO_NEXT].reboot_status; } EXPORT_SYMBOL(avm_next_reset_status); struct _reboot_info { const enum _avm_reset_status status; const char *matchtext; int matchlen; const char *printouttext; const char *shortprintouttext; unsigned int reboot_count; }; #define REBOOT_INFO_ENTRY(_status, user_txt, mbox_txt, mbox_counter) { \ .status = (_status), \ .matchtext = (mbox_txt), \ .matchlen = (mbox_txt) ? sizeof(mbox_txt) : 0, \ .printouttext = (user_txt), \ .shortprintouttext = (mbox_counter), \ } // clang-format off static struct _reboot_info reboot_info[] = { REBOOT_INFO_ENTRY(RS_SOFTWATCHDOG, "Softwatchdog-Reboot", SOFTWATCHDOG_REBOOT_STATUS_TEXT, "WD"), REBOOT_INFO_ENTRY(RS_NMIWATCHDOG, "NMI-Watchdog-Reset", NMI_REBOOT_STATUS_TEXT, "NMI"), REBOOT_INFO_ENTRY(RS_FIRMWAREUPDATE, "Fw-Update", UPDATE_REBOOT_STATUS_TEXT, NULL), REBOOT_INFO_ENTRY(RS_SHORTREBOOT, "Short-PowerOff-Reboot", POWERON_REBOOT_STATUS_TEXT, "SHORTPOWERCUT"), REBOOT_INFO_ENTRY(RS_TEMP_REBOOT, "Temperature-Reboot", TEMP_REBOOT_STATUS_TEXT, "TEMPERATURE"), REBOOT_INFO_ENTRY(RS_REBOOT_FOR_UPDATE, "Update-Reboot", SOFT_REBOOT_STATUS_TEXT_UPDATE, "UPDATE"), REBOOT_INFO_ENTRY(RS_PANIC, "Soft-Reboot", SOFT_REBOOT_STATUS_TEXT_PANIC, "PANIC"), REBOOT_INFO_ENTRY(RS_OOM, "Soft-Reboot", SOFT_REBOOT_STATUS_TEXT_OOM, "OOM"), REBOOT_INFO_ENTRY(RS_OOPS, "Soft-Reboot", SOFT_REBOOT_STATUS_TEXT_OOPS, "KCRASH"), REBOOT_INFO_ENTRY(RS_DOCSIS_LOCAL, "Soft-Reboot", SOFT_REBOOT_STATUS_TEXT_DOCSIS_LOCAL, "DOCSIS_LOCAL"), REBOOT_INFO_ENTRY(RS_DOCSIS_OPERATOR, "Soft-Reboot", SOFT_REBOOT_STATUS_TEXT_DOCSIS_OPERATOR, "DOCSIS_OPERATOR"), REBOOT_INFO_ENTRY(RS_BOXCHANGE, "Soft-Reboot", SOFT_REBOOT_STATUS_TEXT_BOXCHANGE, "BOXCHANGE"), REBOOT_INFO_ENTRY(RS_OPERATOR, "Soft-Reboot", SOFT_REBOOT_STATUS_TEXT_OPERATOR, "OPERATOR"), /*--- als vorletzter Eintrag, da dieser Untermenge von RS_PANIC/RS_OOM/RS_OOPS ---*/ REBOOT_INFO_ENTRY(RS_REBOOT, "Soft-Reboot", SOFT_REBOOT_STATUS_TEXT, NULL), /*--- definition: have to be last entry: ---*/ REBOOT_INFO_ENTRY(RS_POWERON, "Power-On", NULL, NULL), }; // clang-format on static int mailbox_get_value(const char *mbox, const char *mbkey, char *buf, size_t bufsiz) { const char *s, *e; size_t len; if (!bufsiz) return 0; s = mbox; while ((s = strstr(s, mbkey))) { s += strlen(mbkey); if (*s++ == '(') break; } if (!s) return -ENOENT; e = strnchr(s, bufsiz, ')'); len = e ? e-s : bufsiz-1; strlcpy(buf, s, len+1); return 0; } /** */ static void read_reboot_counters(const char *mbox) { unsigned int i, control, sum = 0; unsigned int counter[ARRAY_SIZE(reboot_info)]; char val[32]; int err; for (i = 0; i < ARRAY_SIZE(reboot_info); i++) { const char *mbkey; counter[i] = 0; mbkey = reboot_info[i].shortprintouttext; if (!mbkey) continue; err = mailbox_get_value(mbox, mbkey, val, sizeof(val)); if (err) continue; sscanf(val, "%u", &counter[i]); sum += counter[i]; } err = mailbox_get_value(mbox, "SUM", val, sizeof(val)); if (!err) { sscanf(val, "%u", &control); if (control == sum) { for (i = 0; i < ARRAY_SIZE(reboot_info); i++) reboot_info[i].reboot_count = counter[i]; } } } /** * read uptime and fw-info from mailbox * format UP()UTC(