Merge branch 'core-printk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / sfi / sfi_core.c
1 /* sfi_core.c Simple Firmware Interface - core internals */
2
3 /*
4
5   This file is provided under a dual BSD/GPLv2 license.  When using or
6   redistributing this file, you may do so under either license.
7
8   GPL LICENSE SUMMARY
9
10   Copyright(c) 2009 Intel Corporation. All rights reserved.
11
12   This program is free software; you can redistribute it and/or modify
13   it under the terms of version 2 of the GNU General Public License as
14   published by the Free Software Foundation.
15
16   This program is distributed in the hope that it will be useful, but
17   WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
24   The full GNU General Public License is included in this distribution
25   in the file called LICENSE.GPL.
26
27   BSD LICENSE
28
29   Copyright(c) 2009 Intel Corporation. All rights reserved.
30
31   Redistribution and use in source and binary forms, with or without
32   modification, are permitted provided that the following conditions
33   are met:
34
35     * Redistributions of source code must retain the above copyright
36       notice, this list of conditions and the following disclaimer.
37     * Redistributions in binary form must reproduce the above copyright
38       notice, this list of conditions and the following disclaimer in
39       the documentation and/or other materials provided with the
40       distribution.
41     * Neither the name of Intel Corporation nor the names of its
42       contributors may be used to endorse or promote products derived
43       from this software without specific prior written permission.
44
45   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
48   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
49   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
53   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
54   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
55   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56
57 */
58
59 #define KMSG_COMPONENT "SFI"
60 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
61
62 #include <linux/bootmem.h>
63 #include <linux/kernel.h>
64 #include <linux/module.h>
65 #include <linux/errno.h>
66 #include <linux/types.h>
67 #include <linux/acpi.h>
68 #include <linux/init.h>
69 #include <linux/sfi.h>
70
71 #include "sfi_core.h"
72
73 #define ON_SAME_PAGE(addr1, addr2) \
74         (((unsigned long)(addr1) & PAGE_MASK) == \
75         ((unsigned long)(addr2) & PAGE_MASK))
76 #define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
77                                 ON_SAME_PAGE(page, table + size))
78
79 int sfi_disabled __read_mostly;
80 EXPORT_SYMBOL(sfi_disabled);
81
82 static u64 syst_pa __read_mostly;
83 static struct sfi_table_simple *syst_va __read_mostly;
84
85 /*
86  * FW creates and saves the SFI tables in memory. When these tables get
87  * used, they may need to be mapped to virtual address space, and the mapping
88  * can happen before or after the ioremap() is ready, so a flag is needed
89  * to indicating this
90  */
91 static u32 sfi_use_ioremap __read_mostly;
92
93 /*
94  * sfi_un/map_memory calls early_ioremap/iounmap which is a __init function
95  * and introduces section mismatch. So use __ref to make it calm.
96  */
97 static void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
98 {
99         if (!phys || !size)
100                 return NULL;
101
102         if (sfi_use_ioremap)
103                 return ioremap(phys, size);
104         else
105                 return early_ioremap(phys, size);
106 }
107
108 static void __ref sfi_unmap_memory(void __iomem *virt, u32 size)
109 {
110         if (!virt || !size)
111                 return;
112
113         if (sfi_use_ioremap)
114                 iounmap(virt);
115         else
116                 early_iounmap(virt, size);
117 }
118
119 static void sfi_print_table_header(unsigned long long pa,
120                                 struct sfi_table_header *header)
121 {
122         pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n",
123                 header->sig, pa,
124                 header->len, header->rev, header->oem_id,
125                 header->oem_table_id);
126 }
127
128 /*
129  * sfi_verify_table()
130  * Sanity check table lengh, calculate checksum
131  */
132 static int sfi_verify_table(struct sfi_table_header *table)
133 {
134
135         u8 checksum = 0;
136         u8 *puchar = (u8 *)table;
137         u32 length = table->len;
138
139         /* Sanity check table length against arbitrary 1MB limit */
140         if (length > 0x100000) {
141                 pr_err("Invalid table length 0x%x\n", length);
142                 return -1;
143         }
144
145         while (length--)
146                 checksum += *puchar++;
147
148         if (checksum) {
149                 pr_err("Checksum %2.2X should be %2.2X\n",
150                         table->csum, table->csum - checksum);
151                 return -1;
152         }
153         return 0;
154 }
155
156 /*
157  * sfi_map_table()
158  *
159  * Return address of mapped table
160  * Check for common case that we can re-use mapping to SYST,
161  * which requires syst_pa, syst_va to be initialized.
162  */
163 struct sfi_table_header *sfi_map_table(u64 pa)
164 {
165         struct sfi_table_header *th;
166         u32 length;
167
168         if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
169                 th = sfi_map_memory(pa, sizeof(struct sfi_table_header));
170         else
171                 th = (void *)syst_va + (pa - syst_pa);
172
173          /* If table fits on same page as its header, we are done */
174         if (TABLE_ON_PAGE(th, th, th->len))
175                 return th;
176
177         /* Entire table does not fit on same page as SYST */
178         length = th->len;
179         if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
180                 sfi_unmap_memory(th, sizeof(struct sfi_table_header));
181
182         return sfi_map_memory(pa, length);
183 }
184
185 /*
186  * sfi_unmap_table()
187  *
188  * Undoes effect of sfi_map_table() by unmapping table
189  * if it did not completely fit on same page as SYST.
190  */
191 void sfi_unmap_table(struct sfi_table_header *th)
192 {
193         if (!TABLE_ON_PAGE(syst_va, th, th->len))
194                 sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
195                                         sizeof(*th) : th->len);
196 }
197
198 static int sfi_table_check_key(struct sfi_table_header *th,
199                                 struct sfi_table_key *key)
200 {
201
202         if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE)
203                 || (key->oem_id && strncmp(th->oem_id,
204                                 key->oem_id, SFI_OEM_ID_SIZE))
205                 || (key->oem_table_id && strncmp(th->oem_table_id,
206                                 key->oem_table_id, SFI_OEM_TABLE_ID_SIZE)))
207                 return -1;
208
209         return 0;
210 }
211
212 /*
213  * This function will be used in 2 cases:
214  * 1. used to enumerate and verify the tables addressed by SYST/XSDT,
215  *    thus no signature will be given (in kernel boot phase)
216  * 2. used to parse one specific table, signature must exist, and
217  *    the mapped virt address will be returned, and the virt space
218  *    will be released by call sfi_put_table() later
219  *
220  * This two cases are from two different functions with two different
221  * sections and causes section mismatch warning. So use __ref to tell
222  * modpost not to make any noise.
223  *
224  * Return value:
225  *      NULL:                   when can't find a table matching the key
226  *      ERR_PTR(error):         error value
227  *      virt table address:     when a matched table is found
228  */
229 struct sfi_table_header *
230  __ref sfi_check_table(u64 pa, struct sfi_table_key *key)
231 {
232         struct sfi_table_header *th;
233         void *ret = NULL;
234
235         th = sfi_map_table(pa);
236         if (!th)
237                 return ERR_PTR(-ENOMEM);
238
239         if (!key->sig) {
240                 sfi_print_table_header(pa, th);
241                 if (sfi_verify_table(th))
242                         ret = ERR_PTR(-EINVAL);
243         } else {
244                 if (!sfi_table_check_key(th, key))
245                         return th;      /* Success */
246         }
247
248         sfi_unmap_table(th);
249         return ret;
250 }
251
252 /*
253  * sfi_get_table()
254  *
255  * Search SYST for the specified table with the signature in
256  * the key, and return the mapped table
257  */
258 struct sfi_table_header *sfi_get_table(struct sfi_table_key *key)
259 {
260         struct sfi_table_header *th;
261         u32 tbl_cnt, i;
262
263         tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
264         for (i = 0; i < tbl_cnt; i++) {
265                 th = sfi_check_table(syst_va->pentry[i], key);
266                 if (!IS_ERR(th) && th)
267                         return th;
268         }
269
270         return NULL;
271 }
272
273 void sfi_put_table(struct sfi_table_header *th)
274 {
275         sfi_unmap_table(th);
276 }
277
278 /* Find table with signature, run handler on it */
279 int sfi_table_parse(char *signature, char *oem_id, char *oem_table_id,
280                         sfi_table_handler handler)
281 {
282         struct sfi_table_header *table = NULL;
283         struct sfi_table_key key;
284         int ret = -EINVAL;
285
286         if (sfi_disabled || !handler || !signature)
287                 goto exit;
288
289         key.sig = signature;
290         key.oem_id = oem_id;
291         key.oem_table_id = oem_table_id;
292
293         table = sfi_get_table(&key);
294         if (!table)
295                 goto exit;
296
297         ret = handler(table);
298         sfi_put_table(table);
299 exit:
300         return ret;
301 }
302 EXPORT_SYMBOL_GPL(sfi_table_parse);
303
304 /*
305  * sfi_parse_syst()
306  * Checksum all the tables in SYST and print their headers
307  *
308  * success: set syst_va, return 0
309  */
310 static int __init sfi_parse_syst(void)
311 {
312         struct sfi_table_key key = SFI_ANY_KEY;
313         int tbl_cnt, i;
314         void *ret;
315
316         syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple));
317         if (!syst_va)
318                 return -ENOMEM;
319
320         tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
321         for (i = 0; i < tbl_cnt; i++) {
322                 ret = sfi_check_table(syst_va->pentry[i], &key);
323                 if (IS_ERR(ret))
324                         return PTR_ERR(ret);
325         }
326
327         return 0;
328 }
329
330 /*
331  * The OS finds the System Table by searching 16-byte boundaries between
332  * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region
333  * starting at the low address and shall stop searching when the 1st valid SFI
334  * System Table is found.
335  *
336  * success: set syst_pa, return 0
337  * fail: return -1
338  */
339 static __init int sfi_find_syst(void)
340 {
341         unsigned long offset, len;
342         void *start;
343
344         len = SFI_SYST_SEARCH_END - SFI_SYST_SEARCH_BEGIN;
345         start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len);
346         if (!start)
347                 return -1;
348
349         for (offset = 0; offset < len; offset += 16) {
350                 struct sfi_table_header *syst_hdr;
351
352                 syst_hdr = start + offset;
353                 if (strncmp(syst_hdr->sig, SFI_SIG_SYST,
354                                 SFI_SIGNATURE_SIZE))
355                         continue;
356
357                 if (syst_hdr->len > PAGE_SIZE)
358                         continue;
359
360                 sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset,
361                                         syst_hdr);
362
363                 if (sfi_verify_table(syst_hdr))
364                         continue;
365
366                 /*
367                  * Enforce SFI spec mandate that SYST reside within a page.
368                  */
369                 if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) {
370                         pr_info("SYST 0x%llx + 0x%x crosses page\n",
371                                         syst_pa, syst_hdr->len);
372                         continue;
373                 }
374
375                 /* Success */
376                 syst_pa = SFI_SYST_SEARCH_BEGIN + offset;
377                 sfi_unmap_memory(start, len);
378                 return 0;
379         }
380
381         sfi_unmap_memory(start, len);
382         return -1;
383 }
384
385 void __init sfi_init(void)
386 {
387         if (!acpi_disabled)
388                 disable_sfi();
389
390         if (sfi_disabled)
391                 return;
392
393         pr_info("Simple Firmware Interface v0.7 http://simplefirmware.org\n");
394
395         if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
396                 disable_sfi();
397
398         return;
399 }
400
401 void __init sfi_init_late(void)
402 {
403         int length;
404
405         if (sfi_disabled)
406                 return;
407
408         length = syst_va->header.len;
409         sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple));
410
411         /* Use ioremap now after it is ready */
412         sfi_use_ioremap = 1;
413         syst_va = sfi_map_memory(syst_pa, length);
414
415         sfi_acpi_init();
416 }