"Luck, Tony" <tony.l...@intel.com> writes:

> On Tue, Aug 15, 2017 at 11:22:06AM +0100, Punit Agrawal wrote:
>> There is already a bert driver which prints the error record. Would it
>> make sense to integrate the character device there instead of creating a
>> new driver?
>
> Like this?  The source code is smaller. But it doesn't offer the option to 
> unload
> the driver and unmap the BERT data region after you have retrieved the error 
> record.

Is there any benefit in being able to unload the driver in real world
usage?

It should be possible to convert the existing driver into a loadable
module - thought that means re-printing the error records to the kernel
log if the module is re-loaded. Not sure if that breaks any existing
usecases.

One thing I missed commenting on in the previous version -

Have you thought of exposing the error records via /sys/firmware/acpi?
The tables are already exposed there and as BERT is part of ACPI
logically that's a better fit compared to a misc device.

>
> Either looks plausible to me (but I'm hardly a disinterested party).
>
> Votes?
>
> -Tony
>
> From cbeabf2d83fe91eebd960cd5cc1b61faaeed1441 Mon Sep 17 00:00:00 2001
> From: Tony Luck <tony.l...@intel.com>
> Date: Tue, 15 Aug 2017 13:48:28 -0700
> Subject: [PATCH] ACPI: APEI: Extend BERT driver to provide a character device
>  to access data
>
> The BERT table simply provides the size and address of the error
> record in BIOS reserved memory. Currently this driver decodes the
> record to the console log. But other users of BERT may want to access
> the full binary record.
>
> In an earlier age we might have used /dev/mem to retrieve this error
> record, but many systems disable /dev/mem for security reasons.
>
> Extend this driver to provide read-only access to the data via a character
> special device "/dev/bert-data".
>
> Cc: Len Brown <l...@kernel.org>
> Cc: Boris Petkov <b...@suse.de>
> Cc: Tyler Baicar <tbai...@codeaurora.org>
> Cc: Punit Agrawal <punit.agra...@arm.com>
> Cc: linux-a...@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Tony Luck <tony.l...@intel.com>
>
> v2: (suggested by Punit Agrawal) don't make a whole new driver, merge
>     this functionality into the existing BERT driver.
> ---
>  drivers/acpi/apei/bert.c | 45 ++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 42 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/acpi/apei/bert.c b/drivers/acpi/apei/bert.c
> index 12771fcf0417..9bc39b1bffde 100644
> --- a/drivers/acpi/apei/bert.c
> +++ b/drivers/acpi/apei/bert.c
> @@ -26,12 +26,16 @@
>  #include <linux/init.h>
>  #include <linux/acpi.h>
>  #include <linux/io.h>
> +#include <linux/miscdevice.h>
> +#include <linux/uaccess.h>
>  
>  #include "apei-internal.h"
>  
>  #undef pr_fmt
>  #define pr_fmt(fmt) "BERT: " fmt
>  
> +static __iomem void *bert_data;
> +static unsigned int region_len;
>  static int bert_disable;
>  
>  static void __init bert_print_all(struct acpi_bert_region *region,
> @@ -95,12 +99,45 @@ static int __init bert_check_table(struct acpi_table_bert 
> *bert_tab)
>       return 0;
>  }
>  
> +static int bert_chrdev_open(struct inode *inode, struct file *file)
> +{
> +     if (file->f_flags & (O_WRONLY | O_RDWR))
> +             return -EPERM;
> +     inode->i_size = region_len;
> +     return 0;
> +}
> +
> +static ssize_t bert_chrdev_read(struct file *filp, char __user *ubuf,
> +                             size_t usize, loff_t *off)
> +{
> +     if (*off > region_len)
> +             return -EINVAL;
> +     if (*off + usize > region_len)
> +             usize = region_len - *off;
> +     if (copy_to_user(ubuf, bert_data + *off, usize))
> +             return -EFAULT;
> +     *off += usize;
> +     return usize;
> +}
> +
> +static const struct file_operations bert_chrdev_ops = {
> +     .open           = bert_chrdev_open,
> +     .read           = bert_chrdev_read,
> +     .llseek         = default_llseek,
> +};
> +
> +static struct miscdevice bert_chrdev_device = {
> +     .minor          = MISC_DYNAMIC_MINOR,
> +     .name           = "bert-data",
> +     .fops           = &bert_chrdev_ops,
> +     .mode           = 0444,
> +};
> +
>  static int __init bert_init(void)
>  {
> -     struct apei_resources bert_resources;
>       struct acpi_bert_region *boot_error_region;
> +     struct apei_resources bert_resources;
>       struct acpi_table_bert *bert_tab;
> -     unsigned int region_len;
>       acpi_status status;
>       int rc = 0;
>  
> @@ -139,7 +176,9 @@ static int __init bert_init(void)
>       boot_error_region = ioremap_cache(bert_tab->address, region_len);
>       if (boot_error_region) {
>               bert_print_all(boot_error_region, region_len);
> -             iounmap(boot_error_region);
> +             bert_data = boot_error_region;
> +             if (misc_register(&bert_chrdev_device))
> +                     iounmap(boot_error_region);
>       } else {
>               rc = -ENOMEM;
>       }

Reply via email to