Merge branches 'apei', 'battery-mwh-fix', 'bugzilla-10807', 'bugzilla-14736', 'bugzil...
authorLen Brown <len.brown@intel.com>
Wed, 29 Sep 2010 19:18:28 +0000 (15:18 -0400)
committerLen Brown <len.brown@intel.com>
Wed, 29 Sep 2010 19:18:28 +0000 (15:18 -0400)
1  2  3  4  5  6  7  8 
drivers/acpi/apei/erst-dbg.c
drivers/acpi/apei/erst.c
drivers/acpi/bus.c

index 8561cfe,0000000,5281ddd,5281ddd,5281ddd,5281ddd,5281ddd,98ffa29..da1228a
mode 100644,000000,100644,100644,100644,100644,100644,100644..100644
--- /dev/null
@@@@@@@@@ -1,211 -1,0 -1,207 -1,207 -1,207 -1,207 -1,207 -1,207 +1,211 @@@@@@@@@
- -----  * infomation to and from a persistent store. This file provide the
 +      /*
 +       * APEI Error Record Serialization Table debug support
 +       *
 +       * ERST is a way provided by APEI to save and retrieve hardware error
  ------                kfree(erst_dbg_buf);
+++++++  * information to and from a persistent store. This file provide the
 +       * debugging/testing support for ERST kernel support and firmware
 +       * implementation.
 +       *
 +       * Copyright 2010 Intel Corp.
 +       *   Author: Huang Ying <ying.huang@intel.com>
 +       *
 +       * This program is free software; you can redistribute it and/or
 +       * modify it under the terms of the GNU General Public License version
 +       * 2 as published by the Free Software Foundation.
 +       *
 +       * This program is distributed in the hope that it will be useful,
 +       * but WITHOUT ANY WARRANTY; without even the implied warranty of
 +       * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +       * GNU General Public License for more details.
 +       *
 +       * You should have received a copy of the GNU General Public License
 +       * along with this program; if not, write to the Free Software
 +       * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 +       */
 +      
 +      #include <linux/kernel.h>
 +      #include <linux/module.h>
 +      #include <linux/uaccess.h>
 +      #include <acpi/apei.h>
 +      #include <linux/miscdevice.h>
 +      
 +      #include "apei-internal.h"
 +      
 +      #define ERST_DBG_PFX                    "ERST DBG: "
 +      
 +      #define ERST_DBG_RECORD_LEN_MAX         4096
 +      
 +      static void *erst_dbg_buf;
 +      static unsigned int erst_dbg_buf_len;
 +      
 +      /* Prevent erst_dbg_read/write from being invoked concurrently */
 +      static DEFINE_MUTEX(erst_dbg_mutex);
 +      
 +      static int erst_dbg_open(struct inode *inode, struct file *file)
 +      {
 +              if (erst_disable)
 +                      return -ENODEV;
 +      
 +              return nonseekable_open(inode, file);
 +      }
 +      
 +      static long erst_dbg_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
 +      {
 +              int rc;
 +              u64 record_id;
 +              u32 record_count;
 +      
 +              switch (cmd) {
 +              case APEI_ERST_CLEAR_RECORD:
 +                      rc = copy_from_user(&record_id, (void __user *)arg,
 +                                          sizeof(record_id));
 +                      if (rc)
 +                              return -EFAULT;
 +                      return erst_clear(record_id);
 +              case APEI_ERST_GET_RECORD_COUNT:
 +                      rc = erst_get_record_count();
 +                      if (rc < 0)
 +                              return rc;
 +                      record_count = rc;
 +                      rc = put_user(record_count, (u32 __user *)arg);
 +                      if (rc)
 +                              return rc;
 +                      return 0;
 +              default:
 +                      return -ENOTTY;
 +              }
 +      }
 +      
 +      static ssize_t erst_dbg_read(struct file *filp, char __user *ubuf,
 +                                   size_t usize, loff_t *off)
 +      {
 +              int rc;
 +              ssize_t len = 0;
 +              u64 id;
 +      
 +              if (*off != 0)
 +                      return -EINVAL;
 +      
 +              if (mutex_lock_interruptible(&erst_dbg_mutex) != 0)
 +                      return -EINTR;
 +      
 +      retry_next:
 +              rc = erst_get_next_record_id(&id);
 +              if (rc)
 +                      goto out;
 +              /* no more record */
 +              if (id == APEI_ERST_INVALID_RECORD_ID)
 +                      goto out;
 +      retry:
 +              rc = len = erst_read(id, erst_dbg_buf, erst_dbg_buf_len);
 +              /* The record may be cleared by others, try read next record */
 +              if (rc == -ENOENT)
 +                      goto retry_next;
 +              if (rc < 0)
 +                      goto out;
 +              if (len > ERST_DBG_RECORD_LEN_MAX) {
 +                      pr_warning(ERST_DBG_PFX
 +                                 "Record (ID: 0x%llx) length is too long: %zd\n",
 +                                 id, len);
 +                      rc = -EIO;
 +                      goto out;
 +              }
 +              if (len > erst_dbg_buf_len) {
  ------                erst_dbg_buf = kmalloc(len, GFP_KERNEL);
  ------                if (!erst_dbg_buf)
 +++++++                void *p;
 +                      rc = -ENOMEM;
  ------                kfree(erst_dbg_buf);
 +++++++                p = kmalloc(len, GFP_KERNEL);
 +++++++                if (!p)
 +                              goto out;
 +++++++                kfree(erst_dbg_buf);
 +++++++                erst_dbg_buf = p;
 +                      erst_dbg_buf_len = len;
 +                      goto retry;
 +              }
 +      
 +              rc = -EINVAL;
 +              if (len > usize)
 +                      goto out;
 +      
 +              rc = -EFAULT;
 +              if (copy_to_user(ubuf, erst_dbg_buf, len))
 +                      goto out;
 +              rc = 0;
 +      out:
 +              mutex_unlock(&erst_dbg_mutex);
 +              return rc ? rc : len;
 +      }
 +      
 +      static ssize_t erst_dbg_write(struct file *filp, const char __user *ubuf,
 +                                    size_t usize, loff_t *off)
 +      {
 +              int rc;
 +              struct cper_record_header *rcd;
 +      
 +              if (!capable(CAP_SYS_ADMIN))
 +                      return -EPERM;
 +      
 +              if (usize > ERST_DBG_RECORD_LEN_MAX) {
 +                      pr_err(ERST_DBG_PFX "Too long record to be written\n");
 +                      return -EINVAL;
 +              }
 +      
 +              if (mutex_lock_interruptible(&erst_dbg_mutex))
 +                      return -EINTR;
 +              if (usize > erst_dbg_buf_len) {
  ------                erst_dbg_buf = kmalloc(usize, GFP_KERNEL);
  ------                if (!erst_dbg_buf)
 +++++++                void *p;
 +                      rc = -ENOMEM;
 +++++++                p = kmalloc(usize, GFP_KERNEL);
 +++++++                if (!p)
 +                              goto out;
 +++++++                kfree(erst_dbg_buf);
 +++++++                erst_dbg_buf = p;
 +                      erst_dbg_buf_len = usize;
 +              }
 +              rc = copy_from_user(erst_dbg_buf, ubuf, usize);
 +              if (rc) {
 +                      rc = -EFAULT;
 +                      goto out;
 +              }
 +              rcd = erst_dbg_buf;
 +              rc = -EINVAL;
 +              if (rcd->record_length != usize)
 +                      goto out;
 +      
 +              rc = erst_write(erst_dbg_buf);
 +      
 +      out:
 +              mutex_unlock(&erst_dbg_mutex);
 +              return rc < 0 ? rc : usize;
 +      }
 +      
 +      static const struct file_operations erst_dbg_ops = {
 +              .owner          = THIS_MODULE,
 +              .open           = erst_dbg_open,
 +              .read           = erst_dbg_read,
 +              .write          = erst_dbg_write,
 +              .unlocked_ioctl = erst_dbg_ioctl,
 +      };
 +      
 +      static struct miscdevice erst_dbg_dev = {
 +              .minor  = MISC_DYNAMIC_MINOR,
 +              .name   = "erst_dbg",
 +              .fops   = &erst_dbg_ops,
 +      };
 +      
 +      static __init int erst_dbg_init(void)
 +      {
 +              return misc_register(&erst_dbg_dev);
 +      }
 +      
 +      static __exit void erst_dbg_exit(void)
 +      {
 +              misc_deregister(&erst_dbg_dev);
 +              kfree(erst_dbg_buf);
 +      }
 +      
 +      module_init(erst_dbg_init);
 +      module_exit(erst_dbg_exit);
 +      
 +      MODULE_AUTHOR("Huang Ying");
 +      MODULE_DESCRIPTION("APEI Error Record Serialization Table debug support");
 +      MODULE_LICENSE("GPL");
Simple merge
Simple merge