1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59#define KMSG_COMPONENT "SFI"
60#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
61
62#include <linux/kernel.h>
63#include <acpi/acpi.h>
64
65#include <linux/sfi.h>
66#include "sfi_core.h"
67
68
69
70
71
72
73
74
75
76static struct acpi_table_xsdt *xsdt_va __read_mostly;
77
78#define XSDT_GET_NUM_ENTRIES(ptable, entry_type) \
79 ((ptable->header.length - sizeof(struct acpi_table_header)) / \
80 (sizeof(entry_type)))
81
82static inline struct sfi_table_header *acpi_to_sfi_th(
83 struct acpi_table_header *th)
84{
85 return (struct sfi_table_header *)th;
86}
87
88static inline struct acpi_table_header *sfi_to_acpi_th(
89 struct sfi_table_header *th)
90{
91 return (struct acpi_table_header *)th;
92}
93
94
95
96
97
98
99static int __init sfi_acpi_parse_xsdt(struct sfi_table_header *th)
100{
101 struct sfi_table_key key = SFI_ANY_KEY;
102 int tbl_cnt, i;
103 void *ret;
104
105 xsdt_va = (struct acpi_table_xsdt *)th;
106 tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
107 for (i = 0; i < tbl_cnt; i++) {
108 ret = sfi_check_table(xsdt_va->table_offset_entry[i], &key);
109 if (IS_ERR(ret)) {
110 disable_sfi();
111 return -1;
112 }
113 }
114
115 return 0;
116}
117
118int __init sfi_acpi_init(void)
119{
120 struct sfi_table_key xsdt_key = { .sig = SFI_SIG_XSDT };
121
122 sfi_table_parse(SFI_SIG_XSDT, NULL, NULL, sfi_acpi_parse_xsdt);
123
124
125 xsdt_va = (struct acpi_table_xsdt *)sfi_get_table(&xsdt_key);
126 return 0;
127}
128
129static struct acpi_table_header *sfi_acpi_get_table(struct sfi_table_key *key)
130{
131 u32 tbl_cnt, i;
132 void *ret;
133
134 tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
135 for (i = 0; i < tbl_cnt; i++) {
136 ret = sfi_check_table(xsdt_va->table_offset_entry[i], key);
137 if (!IS_ERR(ret) && ret)
138 return sfi_to_acpi_th(ret);
139 }
140
141 return NULL;
142}
143
144static void sfi_acpi_put_table(struct acpi_table_header *table)
145{
146 sfi_put_table(acpi_to_sfi_th(table));
147}
148
149
150
151
152
153
154int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id,
155 int(*handler)(struct acpi_table_header *))
156{
157 struct acpi_table_header *table = NULL;
158 struct sfi_table_key key;
159 int ret = 0;
160
161 if (sfi_disabled)
162 return -1;
163
164 key.sig = signature;
165 key.oem_id = oem_id;
166 key.oem_table_id = oem_table_id;
167
168 table = sfi_acpi_get_table(&key);
169 if (!table)
170 return -EINVAL;
171
172 ret = handler(table);
173 sfi_acpi_put_table(table);
174 return ret;
175}
176
177static ssize_t sfi_acpi_table_show(struct file *filp, struct kobject *kobj,
178 struct bin_attribute *bin_attr, char *buf,
179 loff_t offset, size_t count)
180{
181 struct sfi_table_attr *tbl_attr =
182 container_of(bin_attr, struct sfi_table_attr, attr);
183 struct acpi_table_header *th = NULL;
184 struct sfi_table_key key;
185 ssize_t cnt;
186
187 key.sig = tbl_attr->name;
188 key.oem_id = NULL;
189 key.oem_table_id = NULL;
190
191 th = sfi_acpi_get_table(&key);
192 if (!th)
193 return 0;
194
195 cnt = memory_read_from_buffer(buf, count, &offset,
196 th, th->length);
197 sfi_acpi_put_table(th);
198
199 return cnt;
200}
201
202
203void __init sfi_acpi_sysfs_init(void)
204{
205 u32 tbl_cnt, i;
206 struct sfi_table_attr *tbl_attr;
207
208 tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
209 for (i = 0; i < tbl_cnt; i++) {
210 tbl_attr =
211 sfi_sysfs_install_table(xsdt_va->table_offset_entry[i]);
212 tbl_attr->attr.read = sfi_acpi_table_show;
213 }
214
215 return;
216}
217