lkml.org 
[lkml]   [2012]   [Jan]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 41/50] ACPI APEI: Convert atomicio routines
    Date
    From: Myron Stowe <mstowe@redhat.com>

    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>
    ---
    drivers/acpi/apei/apei-base.c | 102 ++++++++++++++++++++++++++++++++++--
    drivers/acpi/apei/apei-internal.h | 3 +
    drivers/acpi/apei/ghes.c | 10 ++--
    3 files changed, 104 insertions(+), 11 deletions(-)

    diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
    index 4abb6c7..e45350c 100644
    --- a/drivers/acpi/apei/apei-base.c
    +++ b/drivers/acpi/apei/apei-base.c
    @@ -34,13 +34,13 @@
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/acpi.h>
    +#include <linux/acpi_io.h>
    #include <linux/slab.h>
    #include <linux/io.h>
    #include <linux/kref.h>
    #include <linux/rculist.h>
    #include <linux/interrupt.h>
    #include <linux/debugfs.h>
    -#include <acpi/atomicio.h>

    #include "apei-internal.h"

    @@ -70,7 +70,7 @@ int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val)
    {
    int rc;

    - rc = acpi_atomic_read(val, &entry->register_region);
    + rc = apei_read(val, &entry->register_region);
    if (rc)
    return rc;
    *val >>= entry->register_region.bit_offset;
    @@ -116,13 +116,13 @@ int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val)
    val <<= entry->register_region.bit_offset;
    if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) {
    u64 valr = 0;
    - rc = acpi_atomic_read(&valr, &entry->register_region);
    + rc = apei_read(&valr, &entry->register_region);
    if (rc)
    return rc;
    valr &= ~(entry->mask << entry->register_region.bit_offset);
    val |= valr;
    }
    - rc = acpi_atomic_write(val, &entry->register_region);
    + rc = apei_write(val, &entry->register_region);

    return rc;
    }
    @@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx,
    u8 ins = entry->instruction;

    if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
    - return acpi_pre_map_gar(&entry->register_region);
    + return acpi_os_map_generic_address(&entry->register_region);

    return 0;
    }
    @@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx,
    u8 ins = entry->instruction;

    if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
    - acpi_post_unmap_gar(&entry->register_region);
    + acpi_os_unmap_generic_address(&entry->register_region);

    return 0;
    }
    @@ -591,6 +591,96 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr)
    return 0;
    }

    +/* read GAR in interrupt (including NMI) or process context */
    +int apei_read(u64 *val, struct acpi_generic_address *reg)
    +{
    + int rc;
    + u64 address;
    + u32 tmp, width = reg->bit_width;
    + acpi_status status;
    +
    + rc = apei_check_gar(reg, &address);
    + if (rc)
    + return rc;
    +
    + if (width == 64)
    + width = 32; /* Break into two 32-bit transfers */
    +
    + *val = 0;
    + switch(reg->space_id) {
    + case ACPI_ADR_SPACE_SYSTEM_MEMORY:
    + status = acpi_os_read_memory((acpi_physical_address)
    + address, &tmp, width);
    + if (ACPI_FAILURE(status))
    + return -EIO;
    + *val = tmp;
    +
    + if (reg->bit_width == 64) {
    + /* Read the top 32 bits */
    + status = acpi_os_read_memory((acpi_physical_address)
    + (address + 4), &tmp, 32);
    + if (ACPI_FAILURE(status))
    + return -EIO;
    + *val |= ((u64)tmp << 32);
    + }
    + break;
    + case ACPI_ADR_SPACE_SYSTEM_IO:
    + status = acpi_os_read_port(address, (u32 *)val, reg->bit_width);
    + if (ACPI_FAILURE(status))
    + return -EIO;
    + break;
    + default:
    + return -EINVAL;
    + }
    +
    + return 0;
    +}
    +EXPORT_SYMBOL_GPL(apei_read);
    +
    +/* write GAR in interrupt (including NMI) or process context */
    +int apei_write(u64 val, struct acpi_generic_address *reg)
    +{
    + int rc;
    + u64 address;
    + u32 width = reg->bit_width;
    + acpi_status status;
    +
    + rc = apei_check_gar(reg, &address);
    + if (rc)
    + return rc;
    +
    + if (width == 64)
    + width = 32; /* Break into two 32-bit transfers */
    +
    + switch (reg->space_id) {
    + case ACPI_ADR_SPACE_SYSTEM_MEMORY:
    + status = acpi_os_write_memory((acpi_physical_address)
    + address, ACPI_LODWORD(val),
    + width);
    + if (ACPI_FAILURE(status))
    + return -EIO;
    +
    + if (reg->bit_width == 64) {
    + status = acpi_os_write_memory((acpi_physical_address)
    + (address + 4),
    + ACPI_HIDWORD(val), 32);
    + if (ACPI_FAILURE(status))
    + return -EIO;
    + }
    + break;
    + case ACPI_ADR_SPACE_SYSTEM_IO:
    + status = acpi_os_write_port(address, val, reg->bit_width);
    + if (ACPI_FAILURE(status))
    + return -EIO;
    + break;
    + default:
    + return -EINVAL;
    + }
    +
    + return 0;
    +}
    +EXPORT_SYMBOL_GPL(apei_write);
    +
    static int collect_res_callback(struct apei_exec_context *ctx,
    struct acpi_whea_header *entry,
    void *data)
    diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
    index d778edd..cca240a 100644
    --- a/drivers/acpi/apei/apei-internal.h
    +++ b/drivers/acpi/apei/apei-internal.h
    @@ -68,6 +68,9 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio
    /* 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,
    diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
    index aaf3609..b3207e1 100644
    --- a/drivers/acpi/apei/ghes.c
    +++ b/drivers/acpi/apei/ghes.c
    @@ -33,6 +33,7 @@
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/acpi.h>
    +#include <linux/acpi_io.h>
    #include <linux/io.h>
    #include <linux/interrupt.h>
    #include <linux/timer.h>
    @@ -48,7 +49,6 @@
    #include <linux/pci.h>
    #include <linux/aer.h>
    #include <acpi/apei.h>
    -#include <acpi/atomicio.h>
    #include <acpi/hed.h>
    #include <asm/mce.h>
    #include <asm/tlbflush.h>
    @@ -301,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
    if (!ghes)
    return ERR_PTR(-ENOMEM);
    ghes->generic = generic;
    - rc = acpi_pre_map_gar(&generic->error_status_address);
    + rc = acpi_os_map_generic_address(&generic->error_status_address);
    if (rc)
    goto err_free;
    error_block_length = generic->error_block_length;
    @@ -321,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
    return ghes;

    err_unmap:
    - acpi_post_unmap_gar(&generic->error_status_address);
    + acpi_os_unmap_generic_address(&generic->error_status_address);
    err_free:
    kfree(ghes);
    return ERR_PTR(rc);
    @@ -330,7 +330,7 @@ err_free:
    static void ghes_fini(struct ghes *ghes)
    {
    kfree(ghes->estatus);
    - acpi_post_unmap_gar(&ghes->generic->error_status_address);
    + acpi_os_unmap_generic_address(&ghes->generic->error_status_address);
    }

    enum {
    @@ -401,7 +401,7 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
    u32 len;
    int rc;

    - rc = acpi_atomic_read(&buf_paddr, &g->error_status_address);
    + rc = apei_read(&buf_paddr, &g->error_status_address);
    if (rc) {
    if (!silent && printk_ratelimit())
    pr_warning(FW_WARN GHES_PFX
    --
    1.7.9.rc1


    \
     
     \ /
      Last update: 2012-01-17 13:25    [W:2.672 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site