linux/drivers/acpi/apei/apei-internal.h
Myron Stowe 700130b41f 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>
2012-01-17 04:36:40 -05:00

136 lines
3.9 KiB
C

/*
* apei-internal.h - ACPI Platform Error Interface internal
* definations.
*/
#ifndef APEI_INTERNAL_H
#define APEI_INTERNAL_H
#include <linux/cper.h>
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;
}
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);
}
/* Common instruction implementation */
/* IP has been set in instruction function */
#define APEI_EXEC_SET_IP 1
int apei_read(u64 *val, struct acpi_generic_address *reg);
int apei_write(u64 val, struct acpi_generic_address *reg);
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);
int apei_resources_add(struct apei_resources *resources,
unsigned long start, unsigned long size,
bool iomem);
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);
#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;
}
void apei_estatus_print(const char *pfx,
const struct acpi_hest_generic_status *estatus);
int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus);
int apei_estatus_check(const struct acpi_hest_generic_status *estatus);
int apei_osc_setup(void);
#endif