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 <linux/sfi_acpi.h>
64#include "sfi_core.h"
65
66
67
68
69
70
71
72
73
74static struct acpi_table_xsdt *xsdt_va __read_mostly;
75
76#define XSDT_GET_NUM_ENTRIES(ptable, entry_type) \
77 ((ptable->header.length - sizeof(struct acpi_table_header)) / \
78 (sizeof(entry_type)))
79
80static inline struct sfi_table_header *acpi_to_sfi_th(
81 struct acpi_table_header *th)
82{
83 return (struct sfi_table_header *)th;
84}
85
86static inline struct acpi_table_header *sfi_to_acpi_th(
87 struct sfi_table_header *th)
88{
89 return (struct acpi_table_header *)th;
90}
91
92
93
94
95
96
97static int __init sfi_acpi_parse_xsdt(struct sfi_table_header *th)
98{
99 struct sfi_table_key key = SFI_ANY_KEY;
100 int tbl_cnt, i;
101 void *ret;
102
103 xsdt_va = (struct acpi_table_xsdt *)th;
104 tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
105 for (i = 0; i < tbl_cnt; i++) {
106 ret = sfi_check_table(xsdt_va->table_offset_entry[i], &key);
107 if (IS_ERR(ret)) {
108 disable_sfi();
109 return -1;
110 }
111 }
112
113 return 0;
114}
115
116int __init sfi_acpi_init(void)
117{
118 struct sfi_table_key xsdt_key = { .sig = SFI_SIG_XSDT };
119
120 sfi_table_parse(SFI_SIG_XSDT, NULL, NULL, sfi_acpi_parse_xsdt);
121
122
123 xsdt_va = (struct acpi_table_xsdt *)sfi_get_table(&xsdt_key);
124 return 0;
125}
126
127static struct acpi_table_header *sfi_acpi_get_table(struct sfi_table_key *key)
128{
129 u32 tbl_cnt, i;
130 void *ret;
131
132 tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
133 for (i = 0; i < tbl_cnt; i++) {
134 ret = sfi_check_table(xsdt_va->table_offset_entry[i], key);
135 if (!IS_ERR(ret) && ret)
136 return sfi_to_acpi_th(ret);
137 }
138
139 return NULL;
140}
141
142static void sfi_acpi_put_table(struct acpi_table_header *table)
143{
144 sfi_put_table(acpi_to_sfi_th(table));
145}
146
147
148
149
150
151
152int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id,
153 int(*handler)(struct acpi_table_header *))
154{
155 struct acpi_table_header *table = NULL;
156 struct sfi_table_key key;
157 int ret = 0;
158
159 if (sfi_disabled)
160 return -1;
161
162 key.sig = signature;
163 key.oem_id = oem_id;
164 key.oem_table_id = oem_table_id;
165
166 table = sfi_acpi_get_table(&key);
167 if (!table)
168 return -EINVAL;
169
170 ret = handler(table);
171 sfi_acpi_put_table(table);
172 return ret;
173}
174
175static ssize_t sfi_acpi_table_show(struct file *filp, struct kobject *kobj,
176 struct bin_attribute *bin_attr, char *buf,
177 loff_t offset, size_t count)
178{
179 struct sfi_table_attr *tbl_attr =
180 container_of(bin_attr, struct sfi_table_attr, attr);
181 struct acpi_table_header *th = NULL;
182 struct sfi_table_key key;
183 ssize_t cnt;
184
185 key.sig = tbl_attr->name;
186 key.oem_id = NULL;
187 key.oem_table_id = NULL;
188
189 th = sfi_acpi_get_table(&key);
190 if (!th)
191 return 0;
192
193 cnt = memory_read_from_buffer(buf, count, &offset,
194 th, th->length);
195 sfi_acpi_put_table(th);
196
197 return cnt;
198}
199
200
201void __init sfi_acpi_sysfs_init(void)
202{
203 u32 tbl_cnt, i;
204 struct sfi_table_attr *tbl_attr;
205
206 tbl_cnt = XSDT_GET_NUM_ENTRIES(xsdt_va, u64);
207 for (i = 0; i < tbl_cnt; i++) {
208 tbl_attr =
209 sfi_sysfs_install_table(xsdt_va->table_offset_entry[i]);
210 tbl_attr->attr.read = sfi_acpi_table_show;
211 }
212
213 return;
214}
215