Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * APEI Boot Error Record Table (BERT) support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright 2011 Intel Corp.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *   Author: Huang Ying <ying.huang@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * Under normal circumstances, when a hardware error occurs, the error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * handler receives control and processes the error. This gives OSPM a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * chance to process the error condition, report it, and optionally attempt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * recovery. In some cases, the system is unable to process an error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * For example, system firmware or a management controller may choose to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * reset the system or the system might experience an uncontrolled crash
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  * or reset.The boot error source is used to report unhandled errors that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  * occurred in a previous boot. This mechanism is described in the BERT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  * table.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  * For more information about BERT, please refer to ACPI Specification
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  * version 4.0, section 17.3.1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include "apei-internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #undef pr_fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define pr_fmt(fmt) "BERT: " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #define ACPI_BERT_PRINT_MAX_LEN 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) static int bert_disable;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) static void __init bert_print_all(struct acpi_bert_region *region,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 				  unsigned int region_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	struct acpi_hest_generic_status *estatus =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 		(struct acpi_hest_generic_status *)region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	int remain = region_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	u32 estatus_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	while (remain >= sizeof(struct acpi_bert_region)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 		estatus_len = cper_estatus_len(estatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 		if (remain < estatus_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 			pr_err(FW_BUG "Truncated status block (length: %u).\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 			       estatus_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 		/* No more error records. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 		if (!estatus->block_status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 		if (cper_estatus_check(estatus)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 			pr_err(FW_BUG "Invalid error record.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 			return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 		pr_info_once("Error records from previous boot:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 		if (region_len < ACPI_BERT_PRINT_MAX_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 			cper_estatus_print(KERN_INFO HW_ERR, estatus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 			pr_info_once("Max print length exceeded, table data is available at:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 				     "/sys/firmware/acpi/tables/data/BERT");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		 * Because the boot error source is "one-time polled" type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		 * clear Block Status of current Generic Error Status Block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		 * once it's printed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 		estatus->block_status = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 		estatus = (void *)estatus + estatus_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		remain -= estatus_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) static int __init setup_bert_disable(char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	bert_disable = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) __setup("bert_disable", setup_bert_disable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) static int __init bert_check_table(struct acpi_table_bert *bert_tab)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	if (bert_tab->header.length < sizeof(struct acpi_table_bert) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	    bert_tab->region_length < sizeof(struct acpi_bert_region))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static int __init bert_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	struct apei_resources bert_resources;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	struct acpi_bert_region *boot_error_region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	struct acpi_table_bert *bert_tab;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	unsigned int region_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	if (acpi_disabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	if (bert_disable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		pr_info("Boot Error Record Table support is disabled.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	status = acpi_get_table(ACPI_SIG_BERT, 0, (struct acpi_table_header **)&bert_tab);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	if (status == AE_NOT_FOUND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 		pr_err("get table failed, %s.\n", acpi_format_exception(status));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	rc = bert_check_table(bert_tab);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		pr_err(FW_BUG "table invalid.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		goto out_put_bert_tab;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	region_len = bert_tab->region_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	apei_resources_init(&bert_resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	rc = apei_resources_add(&bert_resources, bert_tab->address,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 				region_len, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		goto out_put_bert_tab;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	rc = apei_resources_request(&bert_resources, "APEI BERT");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 		goto out_fini;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	boot_error_region = ioremap_cache(bert_tab->address, region_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	if (boot_error_region) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 		bert_print_all(boot_error_region, region_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 		iounmap(boot_error_region);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		rc = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	apei_resources_release(&bert_resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) out_fini:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	apei_resources_fini(&bert_resources);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) out_put_bert_tab:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	acpi_put_table((struct acpi_table_header *)bert_tab);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) late_initcall(bert_init);