Merge branch 'drm-intel-next' of git://git.kernel.org/pub/scm/linux/kernel/git/anholt...
[pandora-kernel.git] / drivers / acpi / apei / cper.c
1 /*
2  * UEFI Common Platform Error Record (CPER) support
3  *
4  * Copyright (C) 2010, Intel Corp.
5  *      Author: Huang Ying <ying.huang@intel.com>
6  *
7  * CPER is the format used to describe platform hardware error by
8  * various APEI tables, such as ERST, BERT and HEST etc.
9  *
10  * For more information about CPER, please refer to Appendix N of UEFI
11  * Specification version 2.3.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License version
15  * 2 as published by the Free Software Foundation.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/time.h>
30 #include <linux/cper.h>
31 #include <linux/acpi.h>
32
33 /*
34  * CPER record ID need to be unique even after reboot, because record
35  * ID is used as index for ERST storage, while CPER records from
36  * multiple boot may co-exist in ERST.
37  */
38 u64 cper_next_record_id(void)
39 {
40         static atomic64_t seq;
41
42         if (!atomic64_read(&seq))
43                 atomic64_set(&seq, ((u64)get_seconds()) << 32);
44
45         return atomic64_inc_return(&seq);
46 }
47 EXPORT_SYMBOL_GPL(cper_next_record_id);
48
49 int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
50 {
51         if (estatus->data_length &&
52             estatus->data_length < sizeof(struct acpi_hest_generic_data))
53                 return -EINVAL;
54         if (estatus->raw_data_length &&
55             estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
56                 return -EINVAL;
57
58         return 0;
59 }
60 EXPORT_SYMBOL_GPL(apei_estatus_check_header);
61
62 int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
63 {
64         struct acpi_hest_generic_data *gdata;
65         unsigned int data_len, gedata_len;
66         int rc;
67
68         rc = apei_estatus_check_header(estatus);
69         if (rc)
70                 return rc;
71         data_len = estatus->data_length;
72         gdata = (struct acpi_hest_generic_data *)(estatus + 1);
73         while (data_len > sizeof(*gdata)) {
74                 gedata_len = gdata->error_data_length;
75                 if (gedata_len > data_len - sizeof(*gdata))
76                         return -EINVAL;
77                 data_len -= gedata_len + sizeof(*gdata);
78         }
79         if (data_len)
80                 return -EINVAL;
81
82         return 0;
83 }
84 EXPORT_SYMBOL_GPL(apei_estatus_check);