1a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* 2a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * apei-base.c - ACPI Platform Error Interface (APEI) supporting 3a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * infrastructure 4a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * 5a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * APEI allows to report errors (for example from the chipset) to the 6a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * the operating system. This improves NMI handling especially. In 7a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * addition it supports error serialization and error injection. 8a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * 9a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * For more information about APEI, please refer to ACPI Specification 10a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * version 4.0, chapter 17. 11a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * 12a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * This file has Common functions used by more than one APEI table, 13a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * including framework of interpreter for ERST and EINJ; resource 14a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * management for APEI registers. 15a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * 16a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * Copyright (C) 2009, Intel Corp. 17a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * Author: Huang Ying <ying.huang@intel.com> 18a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * 19a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * This program is free software; you can redistribute it and/or 20a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * modify it under the terms of the GNU General Public License version 21a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * 2 as published by the Free Software Foundation. 22a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * 23a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * This program is distributed in the hope that it will be useful, 24a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * but WITHOUT ANY WARRANTY; without even the implied warranty of 25a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * GNU General Public License for more details. 27a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * 28a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * You should have received a copy of the GNU General Public License 29a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * along with this program; if not, write to the Free Software 30a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 31a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 32a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 33a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/kernel.h> 34a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/module.h> 35a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/init.h> 36a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/acpi.h> 37e0fb8c418520b41d57667befdb8861c46cdf69e0Tejun Heo#include <linux/slab.h> 38a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/io.h> 39a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/kref.h> 40a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/rculist.h> 41a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/interrupt.h> 42a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include <linux/debugfs.h> 43d3ab3edc029bf79b09f91d6a22881c24ecaeb000Chen, Gong#include <asm/unaligned.h> 44a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 45a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#include "apei-internal.h" 46a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 47a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#define APEI_PFX "APEI: " 48a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 49a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* 50a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * APEI ERST (Error Record Serialization Table) and EINJ (Error 51a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * INJection) interpreter framework. 52a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 53a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 54a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying#define APEI_EXEC_PRESERVE_REGISTER 0x1 55a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 56a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingvoid apei_exec_ctx_init(struct apei_exec_context *ctx, 57a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_exec_ins_type *ins_table, 58a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u32 instructions, 59a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *action_table, 60a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u32 entries) 61a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 62a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->ins_table = ins_table; 63a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->instructions = instructions; 64a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->action_table = action_table; 65a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->entries = entries; 66a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 67a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_ctx_init); 68a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 69a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val) 70a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 71a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc; 72a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 73700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe rc = apei_read(val, &entry->register_region); 74a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 75a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 76a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying *val >>= entry->register_region.bit_offset; 77a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying *val &= entry->mask; 78a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 79a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 80a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 81a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 82a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_exec_read_register(struct apei_exec_context *ctx, 83a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry) 84a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 85a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc; 86a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u64 val = 0; 87a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 88a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = __apei_exec_read_register(entry, &val); 89a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 90a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 91a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->value = val; 92a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 93a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 94a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 95a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_read_register); 96a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 97a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_exec_read_register_value(struct apei_exec_context *ctx, 98a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry) 99a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 100a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc; 101a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 102a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = apei_exec_read_register(ctx, entry); 103a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 104a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 105a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->value = (ctx->value == entry->value); 106a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 107a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 108a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 109a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_read_register_value); 110a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 111a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint __apei_exec_write_register(struct acpi_whea_header *entry, u64 val) 112a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 113a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc; 114a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 115a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying val &= entry->mask; 116a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying val <<= entry->register_region.bit_offset; 117a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) { 118a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u64 valr = 0; 119700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe rc = apei_read(&valr, &entry->register_region); 120a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 121a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 122a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying valr &= ~(entry->mask << entry->register_region.bit_offset); 123a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying val |= valr; 124a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 125700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe rc = apei_write(val, &entry->register_region); 126a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 127a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 128a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 129a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 130a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_exec_write_register(struct apei_exec_context *ctx, 131a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry) 132a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 133a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return __apei_exec_write_register(entry, ctx->value); 134a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 135a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_write_register); 136a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 137a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_exec_write_register_value(struct apei_exec_context *ctx, 138a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry) 139a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 140a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc; 141a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 142a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->value = entry->value; 143a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = apei_exec_write_register(ctx, entry); 144a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 145a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 146a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 147a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_write_register_value); 148a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 149a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_exec_noop(struct apei_exec_context *ctx, 150a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry) 151a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 152a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 153a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 154a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_noop); 155a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 156a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* 157a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * Interpret the specified action. Go through whole action table, 158a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * execute all instructions belong to the action. 159a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 160eecf2f7124834dd1cad21807526a8ea031ba8217Huang Yingint __apei_exec_run(struct apei_exec_context *ctx, u8 action, 161eecf2f7124834dd1cad21807526a8ea031ba8217Huang Ying bool optional) 162a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 163eecf2f7124834dd1cad21807526a8ea031ba8217Huang Ying int rc = -ENOENT; 164a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u32 i, ip; 165a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry; 166a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying apei_exec_ins_func_t run; 167a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 168a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->ip = 0; 169a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 170a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying /* 171a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * "ip" is the instruction pointer of current instruction, 172a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * "ctx->ip" specifies the next instruction to executed, 173a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * instruction "run" function may change the "ctx->ip" to 174a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * implement "goto" semantics. 175a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 176a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingrewind: 177a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ip = 0; 178a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying for (i = 0; i < ctx->entries; i++) { 179a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying entry = &ctx->action_table[i]; 180a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (entry->action != action) 181a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying continue; 182a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (ip == ctx->ip) { 183a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (entry->instruction >= ctx->instructions || 184a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying !ctx->ins_table[entry->instruction].run) { 185a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying pr_warning(FW_WARN APEI_PFX 186a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying "Invalid action table, unknown instruction type: %d\n", 187a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying entry->instruction); 188a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return -EINVAL; 189a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 190a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying run = ctx->ins_table[entry->instruction].run; 191a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = run(ctx, entry); 192a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc < 0) 193a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 194a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying else if (rc != APEI_EXEC_SET_IP) 195a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx->ip++; 196a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 197a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ip++; 198a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (ctx->ip < ip) 199a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying goto rewind; 200a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 201a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 202eecf2f7124834dd1cad21807526a8ea031ba8217Huang Ying return !optional && rc < 0 ? rc : 0; 203a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 204eecf2f7124834dd1cad21807526a8ea031ba8217Huang YingEXPORT_SYMBOL_GPL(__apei_exec_run); 205a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 206a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingtypedef int (*apei_exec_entry_func_t)(struct apei_exec_context *ctx, 207a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry, 208a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying void *data); 209a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 210a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstatic int apei_exec_for_each_entry(struct apei_exec_context *ctx, 211a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying apei_exec_entry_func_t func, 212a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying void *data, 213a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int *end) 214a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 215a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u8 ins; 216a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int i, rc; 217a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry; 218a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_exec_ins_type *ins_table = ctx->ins_table; 219a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 220a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying for (i = 0; i < ctx->entries; i++) { 221a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying entry = ctx->action_table + i; 222a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ins = entry->instruction; 223a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (end) 224a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying *end = i; 225a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (ins >= ctx->instructions || !ins_table[ins].run) { 226a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying pr_warning(FW_WARN APEI_PFX 227a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying "Invalid action table, unknown instruction type: %d\n", 228a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ins); 229a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return -EINVAL; 230a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 231a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = func(ctx, entry, data); 232a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 233a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 234a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 235a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 236a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 237a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 238a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 239a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstatic int pre_map_gar_callback(struct apei_exec_context *ctx, 240a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry, 241a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying void *data) 242a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 243a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u8 ins = entry->instruction; 244a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 245a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) 24634ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying return apei_map_generic_address(&entry->register_region); 247a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 248a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 249a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 250a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 251a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* 252a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * Pre-map all GARs in action table to make it possible to access them 253a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * in NMI handler. 254a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 255a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_exec_pre_map_gars(struct apei_exec_context *ctx) 256a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 257a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc, end; 258a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 259a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = apei_exec_for_each_entry(ctx, pre_map_gar_callback, 260a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying NULL, &end); 261a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) { 262a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_exec_context ctx_unmap; 263a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying memcpy(&ctx_unmap, ctx, sizeof(*ctx)); 264a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying ctx_unmap.entries = end; 265a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying apei_exec_post_unmap_gars(&ctx_unmap); 266a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 267a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 268a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 269a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 270a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_pre_map_gars); 271a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 272a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstatic int post_unmap_gar_callback(struct apei_exec_context *ctx, 273a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry, 274a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying void *data) 275a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 276a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u8 ins = entry->instruction; 277a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 278a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) 27934ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying apei_unmap_generic_address(&entry->register_region); 280a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 281a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 282a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 283a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 284a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* Post-unmap all GAR in action table. */ 285a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_exec_post_unmap_gars(struct apei_exec_context *ctx) 286a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 287a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return apei_exec_for_each_entry(ctx, post_unmap_gar_callback, 288a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying NULL, NULL); 289a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 290a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_post_unmap_gars); 291a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 292a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* 293a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * Resource management for GARs in APEI 294a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 295a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstruct apei_res { 296a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct list_head list; 297a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying unsigned long start; 298a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying unsigned long end; 299a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying}; 300a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 301a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* Collect all resources requested, to avoid conflict */ 302a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstruct apei_resources apei_resources_all = { 303a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying .iomem = LIST_HEAD_INIT(apei_resources_all.iomem), 304a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying .ioport = LIST_HEAD_INIT(apei_resources_all.ioport), 305a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying}; 306a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 307a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstatic int apei_res_add(struct list_head *res_list, 308a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying unsigned long start, unsigned long size) 309a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 310a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_res *res, *resn, *res_ins = NULL; 311a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying unsigned long end = start + size; 312a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 313a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (end <= start) 314a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 315a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingrepeat: 316a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry_safe(res, resn, res_list, list) { 317a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (res->start > end || res->end < start) 318a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying continue; 319a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying else if (end <= res->end && start >= res->start) { 320a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying kfree(res_ins); 321a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 322a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 323a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_del(&res->list); 324a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res->start = start = min(res->start, start); 325a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res->end = end = max(res->end, end); 326a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying kfree(res_ins); 327a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res_ins = res; 328a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying goto repeat; 329a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 330a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 331a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (res_ins) 332a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_add(&res_ins->list, res_list); 333a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying else { 334a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res_ins = kmalloc(sizeof(*res), GFP_KERNEL); 335a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (!res_ins) 336a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return -ENOMEM; 337a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res_ins->start = start; 338a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res_ins->end = end; 339a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_add(&res_ins->list, res_list); 340a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 341a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 342a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 343a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 344a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 345a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstatic int apei_res_sub(struct list_head *res_list1, 346a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct list_head *res_list2) 347a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 348a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_res *res1, *resn1, *res2, *res; 349a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res1 = list_entry(res_list1->next, struct apei_res, list); 350a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying resn1 = list_entry(res1->list.next, struct apei_res, list); 351a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying while (&res1->list != res_list1) { 352a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res2, res_list2, list) { 353a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (res1->start >= res2->end || 354a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res1->end <= res2->start) 355a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying continue; 356a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying else if (res1->end <= res2->end && 357a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res1->start >= res2->start) { 358a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_del(&res1->list); 359a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying kfree(res1); 360a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying break; 361a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } else if (res1->end > res2->end && 362a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res1->start < res2->start) { 363a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res = kmalloc(sizeof(*res), GFP_KERNEL); 364a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (!res) 365a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return -ENOMEM; 366a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res->start = res2->end; 367a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res->end = res1->end; 368a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res1->end = res2->start; 369a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_add(&res->list, &res1->list); 370a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying resn1 = res; 371a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } else { 372a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (res1->start < res2->start) 373a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res1->end = res2->start; 374a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying else 375a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res1->start = res2->end; 376a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 377a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 378a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res1 = resn1; 379a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying resn1 = list_entry(resn1->list.next, struct apei_res, list); 380a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 381a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 382a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 383a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 384a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 385a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstatic void apei_res_clean(struct list_head *res_list) 386a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 387a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_res *res, *resn; 388a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 389a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry_safe(res, resn, res_list, list) { 390a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_del(&res->list); 391a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying kfree(res); 392a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 393a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 394a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 395a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingvoid apei_resources_fini(struct apei_resources *resources) 396a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 397a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying apei_res_clean(&resources->iomem); 398a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying apei_res_clean(&resources->ioport); 399a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 400a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_resources_fini); 401a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 402a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstatic int apei_resources_merge(struct apei_resources *resources1, 403a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_resources *resources2) 404a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 405a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc; 406a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_res *res; 407a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 408a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res, &resources2->iomem, list) { 409a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = apei_res_add(&resources1->iomem, res->start, 410a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res->end - res->start); 411a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 412a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 413a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 414a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res, &resources2->ioport, list) { 415a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = apei_res_add(&resources1->ioport, res->start, 416a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res->end - res->start); 417a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 418a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 419a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 420a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 421a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 422a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 423a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 424fdea163d8c17ba08814142259a467ba3e899010dHuang Yingint apei_resources_add(struct apei_resources *resources, 425fdea163d8c17ba08814142259a467ba3e899010dHuang Ying unsigned long start, unsigned long size, 426fdea163d8c17ba08814142259a467ba3e899010dHuang Ying bool iomem) 427fdea163d8c17ba08814142259a467ba3e899010dHuang Ying{ 428fdea163d8c17ba08814142259a467ba3e899010dHuang Ying if (iomem) 429fdea163d8c17ba08814142259a467ba3e899010dHuang Ying return apei_res_add(&resources->iomem, start, size); 430fdea163d8c17ba08814142259a467ba3e899010dHuang Ying else 431fdea163d8c17ba08814142259a467ba3e899010dHuang Ying return apei_res_add(&resources->ioport, start, size); 432fdea163d8c17ba08814142259a467ba3e899010dHuang Ying} 433fdea163d8c17ba08814142259a467ba3e899010dHuang YingEXPORT_SYMBOL_GPL(apei_resources_add); 434fdea163d8c17ba08814142259a467ba3e899010dHuang Ying 435a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* 436a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * EINJ has two groups of GARs (EINJ table entry and trigger table 437a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * entry), so common resources are subtracted from the trigger table 438a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * resources before the second requesting. 439a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 440a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_resources_sub(struct apei_resources *resources1, 441a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_resources *resources2) 442a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 443a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc; 444a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 445a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying rc = apei_res_sub(&resources1->iomem, &resources2->iomem); 446a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 447a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 448a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return apei_res_sub(&resources1->ioport, &resources2->ioport); 449a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 450a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_resources_sub); 451a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 4524134b8c8811f23aa8a281db50dcee64dda414736Huang Yingstatic int apei_get_nvs_callback(__u64 start, __u64 size, void *data) 4534134b8c8811f23aa8a281db50dcee64dda414736Huang Ying{ 4544134b8c8811f23aa8a281db50dcee64dda414736Huang Ying struct apei_resources *resources = data; 4554134b8c8811f23aa8a281db50dcee64dda414736Huang Ying return apei_res_add(&resources->iomem, start, size); 4564134b8c8811f23aa8a281db50dcee64dda414736Huang Ying} 4574134b8c8811f23aa8a281db50dcee64dda414736Huang Ying 4584134b8c8811f23aa8a281db50dcee64dda414736Huang Yingstatic int apei_get_nvs_resources(struct apei_resources *resources) 4594134b8c8811f23aa8a281db50dcee64dda414736Huang Ying{ 4604134b8c8811f23aa8a281db50dcee64dda414736Huang Ying return acpi_nvs_for_each_region(apei_get_nvs_callback, resources); 4614134b8c8811f23aa8a281db50dcee64dda414736Huang Ying} 4624134b8c8811f23aa8a281db50dcee64dda414736Huang Ying 463a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* 4644134b8c8811f23aa8a281db50dcee64dda414736Huang Ying * IO memory/port resource management mechanism is used to check 465a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * whether memory/port area used by GARs conflicts with normal memory 466a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * or IO memory/port of devices. 467a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 468a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_resources_request(struct apei_resources *resources, 469a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying const char *desc) 470a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 47123f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying struct apei_res *res, *res_bak = NULL; 472a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct resource *r; 4734134b8c8811f23aa8a281db50dcee64dda414736Huang Ying struct apei_resources nvs_resources; 47423f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying int rc; 475a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 47623f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying rc = apei_resources_sub(resources, &apei_resources_all); 47723f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying if (rc) 47823f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying return rc; 479a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 4804134b8c8811f23aa8a281db50dcee64dda414736Huang Ying /* 4814134b8c8811f23aa8a281db50dcee64dda414736Huang Ying * Some firmware uses ACPI NVS region, that has been marked as 4824134b8c8811f23aa8a281db50dcee64dda414736Huang Ying * busy, so exclude it from APEI resources to avoid false 4834134b8c8811f23aa8a281db50dcee64dda414736Huang Ying * conflict. 4844134b8c8811f23aa8a281db50dcee64dda414736Huang Ying */ 4854134b8c8811f23aa8a281db50dcee64dda414736Huang Ying apei_resources_init(&nvs_resources); 4864134b8c8811f23aa8a281db50dcee64dda414736Huang Ying rc = apei_get_nvs_resources(&nvs_resources); 4874134b8c8811f23aa8a281db50dcee64dda414736Huang Ying if (rc) 4884134b8c8811f23aa8a281db50dcee64dda414736Huang Ying goto res_fini; 4894134b8c8811f23aa8a281db50dcee64dda414736Huang Ying rc = apei_resources_sub(resources, &nvs_resources); 4904134b8c8811f23aa8a281db50dcee64dda414736Huang Ying if (rc) 4914134b8c8811f23aa8a281db50dcee64dda414736Huang Ying goto res_fini; 4924134b8c8811f23aa8a281db50dcee64dda414736Huang Ying 49323f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying rc = -EINVAL; 494a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res, &resources->iomem, list) { 495a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying r = request_mem_region(res->start, res->end - res->start, 496a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying desc); 497a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (!r) { 498a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying pr_err(APEI_PFX 49946b91e379f7180b482b789fbe615946d91e3a07fBjorn Helgaas "Can not request [mem %#010llx-%#010llx] for %s registers\n", 500a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying (unsigned long long)res->start, 50146b91e379f7180b482b789fbe615946d91e3a07fBjorn Helgaas (unsigned long long)res->end - 1, desc); 502a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res_bak = res; 503a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying goto err_unmap_iomem; 504a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 505a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 506a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 507a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res, &resources->ioport, list) { 508a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying r = request_region(res->start, res->end - res->start, desc); 509a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (!r) { 510a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying pr_err(APEI_PFX 51146b91e379f7180b482b789fbe615946d91e3a07fBjorn Helgaas "Can not request [io %#06llx-%#06llx] for %s registers\n", 512a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying (unsigned long long)res->start, 51346b91e379f7180b482b789fbe615946d91e3a07fBjorn Helgaas (unsigned long long)res->end - 1, desc); 514a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res_bak = res; 515a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying goto err_unmap_ioport; 516a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 517a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 518a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 51923f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying rc = apei_resources_merge(&apei_resources_all, resources); 52023f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying if (rc) { 52123f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying pr_err(APEI_PFX "Fail to merge resources!\n"); 52223f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying goto err_unmap_ioport; 52323f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying } 524a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 525a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 526a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingerr_unmap_ioport: 527a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res, &resources->ioport, list) { 528a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (res == res_bak) 529a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying break; 5302663b3f23537618c0c286551b138353fe26b3df8Huang Ying release_region(res->start, res->end - res->start); 531a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 532a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying res_bak = NULL; 533a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingerr_unmap_iomem: 534a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res, &resources->iomem, list) { 535a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (res == res_bak) 536a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying break; 5372663b3f23537618c0c286551b138353fe26b3df8Huang Ying release_mem_region(res->start, res->end - res->start); 538a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 5394134b8c8811f23aa8a281db50dcee64dda414736Huang Yingres_fini: 5404134b8c8811f23aa8a281db50dcee64dda414736Huang Ying apei_resources_fini(&nvs_resources); 54123f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying return rc; 542a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 543a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_resources_request); 544a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 545a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingvoid apei_resources_release(struct apei_resources *resources) 546a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 54723f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying int rc; 548a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_res *res; 549a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 550a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res, &resources->iomem, list) 551a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying release_mem_region(res->start, res->end - res->start); 552a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying list_for_each_entry(res, &resources->ioport, list) 553a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying release_region(res->start, res->end - res->start); 554a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 55523f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying rc = apei_resources_sub(&apei_resources_all, resources); 55623f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying if (rc) 55723f124ca3dda98496b7ccf897cfd66264a212b6cHuang Ying pr_err(APEI_PFX "Fail to sub resources!\n"); 558a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 559a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_resources_release); 560a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 56115afae604651d4e17652d2ffb56f5e36f991cfefGary Hadestatic int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr, 56215afae604651d4e17652d2ffb56f5e36f991cfefGary Hade u32 *access_bit_width) 563a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 56415afae604651d4e17652d2ffb56f5e36f991cfefGary Hade u32 bit_width, bit_offset, access_size_code, space_id; 565a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 56615afae604651d4e17652d2ffb56f5e36f991cfefGary Hade bit_width = reg->bit_width; 56715afae604651d4e17652d2ffb56f5e36f991cfefGary Hade bit_offset = reg->bit_offset; 56815afae604651d4e17652d2ffb56f5e36f991cfefGary Hade access_size_code = reg->access_width; 569a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying space_id = reg->space_id; 570d3ab3edc029bf79b09f91d6a22881c24ecaeb000Chen, Gong *paddr = get_unaligned(®->address); 571a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (!*paddr) { 572a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying pr_warning(FW_BUG APEI_PFX 57315afae604651d4e17652d2ffb56f5e36f991cfefGary Hade "Invalid physical address in GAR [0x%llx/%u/%u/%u/%u]\n", 57415afae604651d4e17652d2ffb56f5e36f991cfefGary Hade *paddr, bit_width, bit_offset, access_size_code, 57515afae604651d4e17652d2ffb56f5e36f991cfefGary Hade space_id); 576a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return -EINVAL; 577a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 578a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 57915afae604651d4e17652d2ffb56f5e36f991cfefGary Hade if (access_size_code < 1 || access_size_code > 4) { 580a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying pr_warning(FW_BUG APEI_PFX 58115afae604651d4e17652d2ffb56f5e36f991cfefGary Hade "Invalid access size code in GAR [0x%llx/%u/%u/%u/%u]\n", 58215afae604651d4e17652d2ffb56f5e36f991cfefGary Hade *paddr, bit_width, bit_offset, access_size_code, 58315afae604651d4e17652d2ffb56f5e36f991cfefGary Hade space_id); 58415afae604651d4e17652d2ffb56f5e36f991cfefGary Hade return -EINVAL; 58515afae604651d4e17652d2ffb56f5e36f991cfefGary Hade } 58615afae604651d4e17652d2ffb56f5e36f991cfefGary Hade *access_bit_width = 1UL << (access_size_code + 2); 58715afae604651d4e17652d2ffb56f5e36f991cfefGary Hade 588f712c71f7b2b43b894d1e92e1b77385fcad8815fJean Delvare /* Fixup common BIOS bug */ 589f712c71f7b2b43b894d1e92e1b77385fcad8815fJean Delvare if (bit_width == 32 && bit_offset == 0 && (*paddr & 0x03) == 0 && 590f712c71f7b2b43b894d1e92e1b77385fcad8815fJean Delvare *access_bit_width < 32) 591f712c71f7b2b43b894d1e92e1b77385fcad8815fJean Delvare *access_bit_width = 32; 59225216865392a6e1f3032855aee7407de1fe0b70cLans Zhang else if (bit_width == 64 && bit_offset == 0 && (*paddr & 0x07) == 0 && 59325216865392a6e1f3032855aee7407de1fe0b70cLans Zhang *access_bit_width < 64) 59425216865392a6e1f3032855aee7407de1fe0b70cLans Zhang *access_bit_width = 64; 595f712c71f7b2b43b894d1e92e1b77385fcad8815fJean Delvare 59615afae604651d4e17652d2ffb56f5e36f991cfefGary Hade if ((bit_width + bit_offset) > *access_bit_width) { 59715afae604651d4e17652d2ffb56f5e36f991cfefGary Hade pr_warning(FW_BUG APEI_PFX 59815afae604651d4e17652d2ffb56f5e36f991cfefGary Hade "Invalid bit width + offset in GAR [0x%llx/%u/%u/%u/%u]\n", 59915afae604651d4e17652d2ffb56f5e36f991cfefGary Hade *paddr, bit_width, bit_offset, access_size_code, 60015afae604651d4e17652d2ffb56f5e36f991cfefGary Hade space_id); 601a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return -EINVAL; 602a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 603a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 604a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY && 605a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying space_id != ACPI_ADR_SPACE_SYSTEM_IO) { 606a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying pr_warning(FW_BUG APEI_PFX 60715afae604651d4e17652d2ffb56f5e36f991cfefGary Hade "Invalid address space type in GAR [0x%llx/%u/%u/%u/%u]\n", 60815afae604651d4e17652d2ffb56f5e36f991cfefGary Hade *paddr, bit_width, bit_offset, access_size_code, 60915afae604651d4e17652d2ffb56f5e36f991cfefGary Hade space_id); 610a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return -EINVAL; 611a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 612a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 613a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 614a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 615a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 61634ddeb035d704eafdcdb3cbc781894300136c3c4Huang Yingint apei_map_generic_address(struct acpi_generic_address *reg) 61734ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying{ 61834ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying int rc; 61934ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying u32 access_bit_width; 62034ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying u64 address; 62134ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying 62234ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying rc = apei_check_gar(reg, &address, &access_bit_width); 62334ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying if (rc) 62434ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying return rc; 62534ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying return acpi_os_map_generic_address(reg); 62634ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying} 62734ddeb035d704eafdcdb3cbc781894300136c3c4Huang YingEXPORT_SYMBOL_GPL(apei_map_generic_address); 62834ddeb035d704eafdcdb3cbc781894300136c3c4Huang Ying 629700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe/* read GAR in interrupt (including NMI) or process context */ 630700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stoweint apei_read(u64 *val, struct acpi_generic_address *reg) 631700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe{ 632700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe int rc; 63315afae604651d4e17652d2ffb56f5e36f991cfefGary Hade u32 access_bit_width; 634700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe u64 address; 635700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe acpi_status status; 636700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe 63715afae604651d4e17652d2ffb56f5e36f991cfefGary Hade rc = apei_check_gar(reg, &address, &access_bit_width); 638700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe if (rc) 639700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return rc; 640700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe 641700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe *val = 0; 642700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe switch(reg->space_id) { 643700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe case ACPI_ADR_SPACE_SYSTEM_MEMORY: 64473f05330497b98c45d157b7d0c60673798bb4c3bLen Brown status = acpi_os_read_memory((acpi_physical_address) address, 64515afae604651d4e17652d2ffb56f5e36f991cfefGary Hade val, access_bit_width); 646700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe if (ACPI_FAILURE(status)) 647700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return -EIO; 648700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe break; 649700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe case ACPI_ADR_SPACE_SYSTEM_IO: 65015afae604651d4e17652d2ffb56f5e36f991cfefGary Hade status = acpi_os_read_port(address, (u32 *)val, 65115afae604651d4e17652d2ffb56f5e36f991cfefGary Hade access_bit_width); 652700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe if (ACPI_FAILURE(status)) 653700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return -EIO; 654700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe break; 655700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe default: 656700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return -EINVAL; 657700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe } 658700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe 659700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return 0; 660700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe} 661700130b41f4ee54520ac2ef2f7f1d072789711a4Myron StoweEXPORT_SYMBOL_GPL(apei_read); 662700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe 663700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe/* write GAR in interrupt (including NMI) or process context */ 664700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stoweint apei_write(u64 val, struct acpi_generic_address *reg) 665700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe{ 666700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe int rc; 66715afae604651d4e17652d2ffb56f5e36f991cfefGary Hade u32 access_bit_width; 668700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe u64 address; 669700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe acpi_status status; 670700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe 67115afae604651d4e17652d2ffb56f5e36f991cfefGary Hade rc = apei_check_gar(reg, &address, &access_bit_width); 672700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe if (rc) 673700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return rc; 674700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe 675700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe switch (reg->space_id) { 676700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe case ACPI_ADR_SPACE_SYSTEM_MEMORY: 67773f05330497b98c45d157b7d0c60673798bb4c3bLen Brown status = acpi_os_write_memory((acpi_physical_address) address, 67815afae604651d4e17652d2ffb56f5e36f991cfefGary Hade val, access_bit_width); 679700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe if (ACPI_FAILURE(status)) 680700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return -EIO; 681700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe break; 682700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe case ACPI_ADR_SPACE_SYSTEM_IO: 68315afae604651d4e17652d2ffb56f5e36f991cfefGary Hade status = acpi_os_write_port(address, val, access_bit_width); 684700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe if (ACPI_FAILURE(status)) 685700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return -EIO; 686700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe break; 687700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe default: 688700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return -EINVAL; 689700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe } 690700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe 691700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe return 0; 692700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe} 693700130b41f4ee54520ac2ef2f7f1d072789711a4Myron StoweEXPORT_SYMBOL_GPL(apei_write); 694700130b41f4ee54520ac2ef2f7f1d072789711a4Myron Stowe 695a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstatic int collect_res_callback(struct apei_exec_context *ctx, 696a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_whea_header *entry, 697a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying void *data) 698a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 699a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_resources *resources = data; 700a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct acpi_generic_address *reg = &entry->register_region; 701a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u8 ins = entry->instruction; 70215afae604651d4e17652d2ffb56f5e36f991cfefGary Hade u32 access_bit_width; 703a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying u64 paddr; 704a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying int rc; 705a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 706a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (!(ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)) 707a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return 0; 708a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 70915afae604651d4e17652d2ffb56f5e36f991cfefGary Hade rc = apei_check_gar(reg, &paddr, &access_bit_width); 710a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (rc) 711a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return rc; 712a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 713a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying switch (reg->space_id) { 714a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying case ACPI_ADR_SPACE_SYSTEM_MEMORY: 715a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return apei_res_add(&resources->iomem, paddr, 71615afae604651d4e17652d2ffb56f5e36f991cfefGary Hade access_bit_width / 8); 717a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying case ACPI_ADR_SPACE_SYSTEM_IO: 718a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return apei_res_add(&resources->ioport, paddr, 71915afae604651d4e17652d2ffb56f5e36f991cfefGary Hade access_bit_width / 8); 720a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying default: 721a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return -EINVAL; 722a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying } 723a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 724a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 725a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying/* 726a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * Same register may be used by multiple instructions in GARs, so 727a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying * resources are collected before requesting. 728a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying */ 729a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingint apei_exec_collect_resources(struct apei_exec_context *ctx, 730a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying struct apei_resources *resources) 731a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 732a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return apei_exec_for_each_entry(ctx, collect_res_callback, 733a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying resources, NULL); 734a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 735a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_exec_collect_resources); 736a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 737a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Yingstruct dentry *apei_get_debugfs_dir(void) 738a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying{ 739a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying static struct dentry *dapei; 740a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 741a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying if (!dapei) 742a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying dapei = debugfs_create_dir("apei", NULL); 743a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying 744a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying return dapei; 745a643ce207f3e70030bdb431e2a363cc111a60c1aHuang Ying} 746a643ce207f3e70030bdb431e2a363cc111a60c1aHuang YingEXPORT_SYMBOL_GPL(apei_get_debugfs_dir); 7479fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying 7489dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowickiint __weak arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr, 7499dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki void *data) 7509dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki{ 7519dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki return 1; 7529dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki} 7539dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz NowickiEXPORT_SYMBOL_GPL(arch_apei_enable_cmcff); 7549dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki 7559dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowickivoid __weak arch_apei_report_mem_error(int sev, 7569dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki struct cper_sec_mem_err *mem_err) 7579dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki{ 7589dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki} 7599dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz NowickiEXPORT_SYMBOL_GPL(arch_apei_report_mem_error); 7609dae3d0d9e64c3cb8bb172f041d4e66d4b92088aTomasz Nowicki 7619fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Yingint apei_osc_setup(void) 7629fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying{ 7639fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying static u8 whea_uuid_str[] = "ed855e0c-6c90-47bf-a62a-26de0fc5ad5c"; 7649fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying acpi_handle handle; 7659fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying u32 capbuf[3]; 7669fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying struct acpi_osc_context context = { 7679fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying .uuid_str = whea_uuid_str, 7689fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying .rev = 1, 7699fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying .cap.length = sizeof(capbuf), 7709fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying .cap.pointer = capbuf, 7719fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying }; 7729fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying 773b938a229c85a567de7dba2d806d9f63a7c90483eBjorn Helgaas capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE; 774b938a229c85a567de7dba2d806d9f63a7c90483eBjorn Helgaas capbuf[OSC_SUPPORT_DWORD] = 1; 775b938a229c85a567de7dba2d806d9f63a7c90483eBjorn Helgaas capbuf[OSC_CONTROL_DWORD] = 0; 7769fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying 7779fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)) 7789fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying || ACPI_FAILURE(acpi_run_osc(handle, &context))) 7799fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying return -EIO; 7809fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying else { 7819fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying kfree(context.ret.pointer); 7829fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying return 0; 7839fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying } 7849fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang Ying} 7859fb0bfe1408d5506b7b83d13d1eed573fd71d67dHuang YingEXPORT_SYMBOL_GPL(apei_osc_setup); 786