2010-05-18 14:35:12 +08:00
|
|
|
/*
|
|
|
|
* apei-internal.h - ACPI Platform Error Interface internal
|
|
|
|
* definations.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef APEI_INTERNAL_H
|
|
|
|
#define APEI_INTERNAL_H
|
|
|
|
|
2010-05-18 14:35:19 +08:00
|
|
|
#include <linux/cper.h>
|
2012-06-12 11:20:19 +08:00
|
|
|
#include <linux/acpi.h>
|
|
|
|
#include <linux/acpi_io.h>
|
2010-05-18 14:35:19 +08:00
|
|
|
|
2010-05-18 14:35:12 +08:00
|
|
|
struct apei_exec_context;
|
|
|
|
|
|
|
|
typedef int (*apei_exec_ins_func_t)(struct apei_exec_context *ctx,
|
|
|
|
struct acpi_whea_header *entry);
|
|
|
|
|
|
|
|
#define APEI_EXEC_INS_ACCESS_REGISTER 0x0001
|
|
|
|
|
|
|
|
struct apei_exec_ins_type {
|
|
|
|
u32 flags;
|
|
|
|
apei_exec_ins_func_t run;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct apei_exec_context {
|
|
|
|
u32 ip;
|
|
|
|
u64 value;
|
|
|
|
u64 var1;
|
|
|
|
u64 var2;
|
|
|
|
u64 src_base;
|
|
|
|
u64 dst_base;
|
|
|
|
struct apei_exec_ins_type *ins_table;
|
|
|
|
u32 instructions;
|
|
|
|
struct acpi_whea_header *action_table;
|
|
|
|
u32 entries;
|
|
|
|
};
|
|
|
|
|
|
|
|
void apei_exec_ctx_init(struct apei_exec_context *ctx,
|
|
|
|
struct apei_exec_ins_type *ins_table,
|
|
|
|
u32 instructions,
|
|
|
|
struct acpi_whea_header *action_table,
|
|
|
|
u32 entries);
|
|
|
|
|
|
|
|
static inline void apei_exec_ctx_set_input(struct apei_exec_context *ctx,
|
|
|
|
u64 input)
|
|
|
|
{
|
|
|
|
ctx->value = input;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 apei_exec_ctx_get_output(struct apei_exec_context *ctx)
|
|
|
|
{
|
|
|
|
return ctx->value;
|
|
|
|
}
|
|
|
|
|
ACPI, APEI, Add apei_exec_run_optional
Some actions in APEI ERST and EINJ tables are optional, for example,
ACPI_EINJ_BEGIN_OPERATION action is used to do some preparation for
error injection, and firmware may choose to do nothing here. While
some other actions are mandatory, for example, firmware must provide
ACPI_EINJ_GET_ERROR_TYPE implementation.
Original implementation treats all actions as optional (that is, can
have no instructions), that may cause issue if firmware does not
provide some mandatory actions. To fix this, this patch adds
apei_exec_run_optional, which should be used for optional actions.
The original apei_exec_run should be used for mandatory actions.
Cc: Thomas Renninger <trenn@novell.com>
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2011-07-13 13:14:16 +08:00
|
|
|
int __apei_exec_run(struct apei_exec_context *ctx, u8 action, bool optional);
|
|
|
|
|
|
|
|
static inline int apei_exec_run(struct apei_exec_context *ctx, u8 action)
|
|
|
|
{
|
|
|
|
return __apei_exec_run(ctx, action, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It is optional whether the firmware provides the action */
|
|
|
|
static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 action)
|
|
|
|
{
|
|
|
|
return __apei_exec_run(ctx, action, 1);
|
|
|
|
}
|
2010-05-18 14:35:12 +08:00
|
|
|
|
|
|
|
/* Common instruction implementation */
|
|
|
|
|
|
|
|
/* IP has been set in instruction function */
|
|
|
|
#define APEI_EXEC_SET_IP 1
|
|
|
|
|
2012-06-12 11:20:19 +08:00
|
|
|
int apei_map_generic_address(struct acpi_generic_address *reg);
|
|
|
|
|
|
|
|
static inline void apei_unmap_generic_address(struct acpi_generic_address *reg)
|
|
|
|
{
|
|
|
|
acpi_os_unmap_generic_address(reg);
|
|
|
|
}
|
|
|
|
|
ACPI APEI: Convert atomicio routines
APEI needs memory access in interrupt context. The obvious choice is
acpi_read(), but originally it couldn't be used in interrupt context
because it makes temporary mappings with ioremap(). Therefore, we added
drivers/acpi/atomicio.c, which provides:
acpi_pre_map_gar() -- ioremap in process context
acpi_atomic_read() -- memory access in interrupt context
acpi_post_unmap_gar() -- iounmap
Later we added acpi_os_map_generic_address() (2971852) and enhanced
acpi_read() so it works in interrupt context as long as the address has
been previously mapped (620242a). Now this sequence:
acpi_os_map_generic_address() -- ioremap in process context
acpi_read()/apei_read() -- now OK in interrupt context
acpi_os_unmap_generic_address()
is equivalent to what atomicio.c provides.
This patch introduces apei_read() and apei_write(), which currently are
functional equivalents of acpi_read() and acpi_write(). This is mainly
proactive, to prevent APEI breakages if acpi_read() and acpi_write()
are ever augmented to support the 'bit_offset' field of GAS, as APEI's
__apei_exec_write_register() precludes splitting up functionality
related to 'bit_offset' and APEI's 'mask' (see its
APEI_EXEC_PRESERVE_REGISTER block).
With apei_read() and apei_write() in place, usages of atomicio routines
are converted to apei_read()/apei_write() and existing calls within
osl.c and the CA, based on the re-factoring that was done in an earlier
patch series - http://marc.info/?l=linux-acpi&m=128769263327206&w=2:
acpi_pre_map_gar() --> acpi_os_map_generic_address()
acpi_post_unmap_gar() --> acpi_os_unmap_generic_address()
acpi_atomic_read() --> apei_read()
acpi_atomic_write() --> apei_write()
Note that acpi_read() and acpi_write() currently use 'bit_width'
for accessing GARs which seems incorrect. 'bit_width' is the size of
the register, while 'access_width' is the size of the access the
processor must generate on the bus. The 'access_width' may be larger,
for example, if the hardware only supports 32-bit or 64-bit reads. I
wanted to minimize any possible impacts with this patch series so I
did *not* change this behavior.
Signed-off-by: Myron Stowe <myron.stowe@redhat.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2011-11-08 07:23:41 +08:00
|
|
|
int apei_read(u64 *val, struct acpi_generic_address *reg);
|
|
|
|
int apei_write(u64 val, struct acpi_generic_address *reg);
|
|
|
|
|
2010-05-18 14:35:12 +08:00
|
|
|
int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val);
|
|
|
|
int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val);
|
|
|
|
int apei_exec_read_register(struct apei_exec_context *ctx,
|
|
|
|
struct acpi_whea_header *entry);
|
|
|
|
int apei_exec_read_register_value(struct apei_exec_context *ctx,
|
|
|
|
struct acpi_whea_header *entry);
|
|
|
|
int apei_exec_write_register(struct apei_exec_context *ctx,
|
|
|
|
struct acpi_whea_header *entry);
|
|
|
|
int apei_exec_write_register_value(struct apei_exec_context *ctx,
|
|
|
|
struct acpi_whea_header *entry);
|
|
|
|
int apei_exec_noop(struct apei_exec_context *ctx,
|
|
|
|
struct acpi_whea_header *entry);
|
|
|
|
int apei_exec_pre_map_gars(struct apei_exec_context *ctx);
|
|
|
|
int apei_exec_post_unmap_gars(struct apei_exec_context *ctx);
|
|
|
|
|
|
|
|
struct apei_resources {
|
|
|
|
struct list_head iomem;
|
|
|
|
struct list_head ioport;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline void apei_resources_init(struct apei_resources *resources)
|
|
|
|
{
|
|
|
|
INIT_LIST_HEAD(&resources->iomem);
|
|
|
|
INIT_LIST_HEAD(&resources->ioport);
|
|
|
|
}
|
|
|
|
|
|
|
|
void apei_resources_fini(struct apei_resources *resources);
|
2011-12-08 11:25:47 +08:00
|
|
|
int apei_resources_add(struct apei_resources *resources,
|
|
|
|
unsigned long start, unsigned long size,
|
|
|
|
bool iomem);
|
2010-05-18 14:35:12 +08:00
|
|
|
int apei_resources_sub(struct apei_resources *resources1,
|
|
|
|
struct apei_resources *resources2);
|
|
|
|
int apei_resources_request(struct apei_resources *resources,
|
|
|
|
const char *desc);
|
|
|
|
void apei_resources_release(struct apei_resources *resources);
|
|
|
|
int apei_exec_collect_resources(struct apei_exec_context *ctx,
|
|
|
|
struct apei_resources *resources);
|
|
|
|
|
|
|
|
struct dentry;
|
|
|
|
struct dentry *apei_get_debugfs_dir(void);
|
2010-05-18 14:35:19 +08:00
|
|
|
|
|
|
|
#define apei_estatus_for_each_section(estatus, section) \
|
|
|
|
for (section = (struct acpi_hest_generic_data *)(estatus + 1); \
|
|
|
|
(void *)section - (void *)estatus < estatus->data_length; \
|
|
|
|
section = (void *)(section+1) + section->error_data_length)
|
|
|
|
|
|
|
|
static inline u32 apei_estatus_len(struct acpi_hest_generic_status *estatus)
|
|
|
|
{
|
|
|
|
if (estatus->raw_data_length)
|
|
|
|
return estatus->raw_data_offset + \
|
|
|
|
estatus->raw_data_length;
|
|
|
|
else
|
|
|
|
return sizeof(*estatus) + estatus->data_length;
|
|
|
|
}
|
|
|
|
|
ACPI, APEI, Add APEI generic error status printing support
In APEI, Hardware error information reported by firmware to Linux
kernel is in the data structure of APEI generic error status (struct
acpi_hes_generic_status). While now printk is used by Linux kernel to
report hardware error information to user space.
So, this patch adds printing support for the data structure, so that
the corresponding hardware error information can be reported to user
space via printk.
PCIe AER information printing is not implemented yet. Will refactor the
original PCIe AER information printing code to avoid code duplicating.
The output format is as follow:
<error record> :=
APEI generic hardware error status
severity: <integer>, <severity string>
section: <integer>, severity: <integer>, <severity string>
flags: <integer>
<section flags strings>
fru_id: <uuid string>
fru_text: <string>
section_type: <section type string>
<section data>
<severity string>* := recoverable | fatal | corrected | info
<section flags strings># :=
[primary][, containment warning][, reset][, threshold exceeded]\
[, resource not accessible][, latent error]
<section type string> := generic processor error | memory error | \
PCIe error | unknown, <uuid string>
<section data> :=
<generic processor section data> | <memory section data> | \
<pcie section data> | <null>
<generic processor section data> :=
[processor_type: <integer>, <proc type string>]
[processor_isa: <integer>, <proc isa string>]
[error_type: <integer>
<proc error type strings>]
[operation: <integer>, <proc operation string>]
[flags: <integer>
<proc flags strings>]
[level: <integer>]
[version_info: <integer>]
[processor_id: <integer>]
[target_address: <integer>]
[requestor_id: <integer>]
[responder_id: <integer>]
[IP: <integer>]
<proc type string>* := IA32/X64 | IA64
<proc isa string>* := IA32 | IA64 | X64
<processor error type strings># :=
[cache error][, TLB error][, bus error][, micro-architectural error]
<proc operation string>* := unknown or generic | data read | data write | \
instruction execution
<proc flags strings># :=
[restartable][, precise IP][, overflow][, corrected]
<memory section data> :=
[error_status: <integer>]
[physical_address: <integer>]
[physical_address_mask: <integer>]
[node: <integer>]
[card: <integer>]
[module: <integer>]
[bank: <integer>]
[device: <integer>]
[row: <integer>]
[column: <integer>]
[bit_position: <integer>]
[requestor_id: <integer>]
[responder_id: <integer>]
[target_id: <integer>]
[error_type: <integer>, <mem error type string>]
<mem error type string>* :=
unknown | no error | single-bit ECC | multi-bit ECC | \
single-symbol chipkill ECC | multi-symbol chipkill ECC | master abort | \
target abort | parity error | watchdog timeout | invalid address | \
mirror Broken | memory sparing | scrub corrected error | \
scrub uncorrected error
<pcie section data> :=
[port_type: <integer>, <pcie port type string>]
[version: <integer>.<integer>]
[command: <integer>, status: <integer>]
[device_id: <integer>:<integer>:<integer>.<integer>
slot: <integer>
secondary_bus: <integer>
vendor_id: <integer>, device_id: <integer>
class_code: <integer>]
[serial number: <integer>, <integer>]
[bridge: secondary_status: <integer>, control: <integer>]
<pcie port type string>* := PCIe end point | legacy PCI end point | \
unknown | unknown | root port | upstream switch port | \
downstream switch port | PCIe to PCI/PCI-X bridge | \
PCI/PCI-X to PCIe bridge | root complex integrated endpoint device | \
root complex event collector
Where, [] designate corresponding content is optional
All <field string> description with * has the following format:
field: <integer>, <field string>
Where value of <integer> should be the position of "string" in <field
string> description. Otherwise, <field string> will be "unknown".
All <field strings> description with # has the following format:
field: <integer>
<field strings>
Where each string in <fields strings> corresponding to one set bit of
<integer>. The bit position is the position of "string" in <field
strings> description.
For more detailed explanation of every field, please refer to UEFI
specification version 2.3 or later, section Appendix N: Common
Platform Error Record.
Signed-off-by: Huang Ying <ying.huang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
2010-12-07 10:22:30 +08:00
|
|
|
void apei_estatus_print(const char *pfx,
|
|
|
|
const struct acpi_hest_generic_status *estatus);
|
2010-05-18 14:35:19 +08:00
|
|
|
int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
|
|
|
|
int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
|
2011-07-13 13:14:21 +08:00
|
|
|
|
|
|
|
int apei_osc_setup(void);
|
2010-05-18 14:35:12 +08:00
|
|
|
#endif
|