Linux Audio

Check our new training course

Loading...
v5.9
  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/memblock.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#include <linux/slab.h>
 71#include <linux/io.h>
 72
 73#include "sfi_core.h"
 74
 75#define ON_SAME_PAGE(addr1, addr2) \
 76	(((unsigned long)(addr1) & PAGE_MASK) == \
 77	((unsigned long)(addr2) & PAGE_MASK))
 78#define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
 79				ON_SAME_PAGE(page, table + size))
 80
 81int sfi_disabled __read_mostly;
 82EXPORT_SYMBOL(sfi_disabled);
 83
 84static u64 syst_pa __read_mostly;
 85static struct sfi_table_simple *syst_va __read_mostly;
 86
 87/*
 88 * FW creates and saves the SFI tables in memory. When these tables get
 89 * used, they may need to be mapped to virtual address space, and the mapping
 90 * can happen before or after the memremap() is ready, so a flag is needed
 91 * to indicating this
 92 */
 93static u32 sfi_use_memremap __read_mostly;
 94
 95/*
 96 * sfi_un/map_memory calls early_memremap/memunmap which is a __init function
 97 * and introduces section mismatch. So use __ref to make it calm.
 98 */
 99static void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
100{
101	if (!phys || !size)
102		return NULL;
103
104	if (sfi_use_memremap)
105		return memremap(phys, size, MEMREMAP_WB);
106	else
107		return early_memremap(phys, size);
108}
109
110static void __ref sfi_unmap_memory(void __iomem *virt, u32 size)
111{
112	if (!virt || !size)
113		return;
114
115	if (sfi_use_memremap)
116		memunmap(virt);
117	else
118		early_memunmap(virt, size);
119}
120
121static void sfi_print_table_header(unsigned long long pa,
122				struct sfi_table_header *header)
123{
124	pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n",
125		header->sig, pa,
126		header->len, header->rev, header->oem_id,
127		header->oem_table_id);
128}
129
130/*
131 * sfi_verify_table()
132 * Sanity check table lengh, calculate checksum
133 */
134static int sfi_verify_table(struct sfi_table_header *table)
135{
136
137	u8 checksum = 0;
138	u8 *puchar = (u8 *)table;
139	u32 length = table->len;
140
141	/* Sanity check table length against arbitrary 1MB limit */
142	if (length > 0x100000) {
143		pr_err("Invalid table length 0x%x\n", length);
144		return -1;
145	}
146
147	while (length--)
148		checksum += *puchar++;
149
150	if (checksum) {
151		pr_err("Checksum %2.2X should be %2.2X\n",
152			table->csum, table->csum - checksum);
153		return -1;
154	}
155	return 0;
156}
157
158/*
159 * sfi_map_table()
160 *
161 * Return address of mapped table
162 * Check for common case that we can re-use mapping to SYST,
163 * which requires syst_pa, syst_va to be initialized.
164 */
165static struct sfi_table_header *sfi_map_table(u64 pa)
166{
167	struct sfi_table_header *th;
168	u32 length;
169
170	if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
171		th = sfi_map_memory(pa, sizeof(struct sfi_table_header));
172	else
173		th = (void *)syst_va + (pa - syst_pa);
174
175	 /* If table fits on same page as its header, we are done */
176	if (TABLE_ON_PAGE(th, th, th->len))
177		return th;
178
179	/* Entire table does not fit on same page as SYST */
180	length = th->len;
181	if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
182		sfi_unmap_memory(th, sizeof(struct sfi_table_header));
183
184	return sfi_map_memory(pa, length);
185}
186
187/*
188 * sfi_unmap_table()
189 *
190 * Undoes effect of sfi_map_table() by unmapping table
191 * if it did not completely fit on same page as SYST.
192 */
193static void sfi_unmap_table(struct sfi_table_header *th)
194{
195	if (!TABLE_ON_PAGE(syst_va, th, th->len))
196		sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
197					sizeof(*th) : th->len);
198}
199
200static int sfi_table_check_key(struct sfi_table_header *th,
201				struct sfi_table_key *key)
202{
203
204	if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE)
205		|| (key->oem_id && strncmp(th->oem_id,
206				key->oem_id, SFI_OEM_ID_SIZE))
207		|| (key->oem_table_id && strncmp(th->oem_table_id,
208				key->oem_table_id, SFI_OEM_TABLE_ID_SIZE)))
209		return -1;
210
211	return 0;
212}
213
214/*
215 * This function will be used in 2 cases:
216 * 1. used to enumerate and verify the tables addressed by SYST/XSDT,
217 *    thus no signature will be given (in kernel boot phase)
218 * 2. used to parse one specific table, signature must exist, and
219 *    the mapped virt address will be returned, and the virt space
220 *    will be released by call sfi_put_table() later
221 *
222 * This two cases are from two different functions with two different
223 * sections and causes section mismatch warning. So use __ref to tell
224 * modpost not to make any noise.
225 *
226 * Return value:
227 *	NULL:			when can't find a table matching the key
228 *	ERR_PTR(error):		error value
229 *	virt table address:	when a matched table is found
230 */
231struct sfi_table_header *
232 __ref sfi_check_table(u64 pa, struct sfi_table_key *key)
233{
234	struct sfi_table_header *th;
235	void *ret = NULL;
236
237	th = sfi_map_table(pa);
238	if (!th)
239		return ERR_PTR(-ENOMEM);
240
241	if (!key->sig) {
242		sfi_print_table_header(pa, th);
243		if (sfi_verify_table(th))
244			ret = ERR_PTR(-EINVAL);
245	} else {
246		if (!sfi_table_check_key(th, key))
247			return th;	/* Success */
248	}
249
250	sfi_unmap_table(th);
251	return ret;
252}
253
254/*
255 * sfi_get_table()
256 *
257 * Search SYST for the specified table with the signature in
258 * the key, and return the mapped table
259 */
260struct sfi_table_header *sfi_get_table(struct sfi_table_key *key)
261{
262	struct sfi_table_header *th;
263	u32 tbl_cnt, i;
264
265	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
266	for (i = 0; i < tbl_cnt; i++) {
267		th = sfi_check_table(syst_va->pentry[i], key);
268		if (!IS_ERR(th) && th)
269			return th;
270	}
271
272	return NULL;
273}
274
275void sfi_put_table(struct sfi_table_header *th)
276{
277	sfi_unmap_table(th);
278}
279
280/* Find table with signature, run handler on it */
281int sfi_table_parse(char *signature, char *oem_id, char *oem_table_id,
282			sfi_table_handler handler)
283{
284	struct sfi_table_header *table = NULL;
285	struct sfi_table_key key;
286	int ret = -EINVAL;
287
288	if (sfi_disabled || !handler || !signature)
289		goto exit;
290
291	key.sig = signature;
292	key.oem_id = oem_id;
293	key.oem_table_id = oem_table_id;
294
295	table = sfi_get_table(&key);
296	if (!table)
297		goto exit;
298
299	ret = handler(table);
300	sfi_put_table(table);
301exit:
302	return ret;
303}
304EXPORT_SYMBOL_GPL(sfi_table_parse);
305
306/*
307 * sfi_parse_syst()
308 * Checksum all the tables in SYST and print their headers
309 *
310 * success: set syst_va, return 0
311 */
312static int __init sfi_parse_syst(void)
313{
314	struct sfi_table_key key = SFI_ANY_KEY;
315	int tbl_cnt, i;
316	void *ret;
317
318	syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple));
319	if (!syst_va)
320		return -ENOMEM;
321
322	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
323	for (i = 0; i < tbl_cnt; i++) {
324		ret = sfi_check_table(syst_va->pentry[i], &key);
325		if (IS_ERR(ret))
326			return PTR_ERR(ret);
327	}
328
329	return 0;
330}
331
332/*
333 * The OS finds the System Table by searching 16-byte boundaries between
334 * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region
335 * starting at the low address and shall stop searching when the 1st valid SFI
336 * System Table is found.
337 *
338 * success: set syst_pa, return 0
339 * fail: return -1
340 */
341static __init int sfi_find_syst(void)
342{
343	unsigned long offset, len;
344	void *start;
345
346	len = SFI_SYST_SEARCH_END - SFI_SYST_SEARCH_BEGIN;
347	start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len);
348	if (!start)
349		return -1;
350
351	for (offset = 0; offset < len; offset += 16) {
352		struct sfi_table_header *syst_hdr;
353
354		syst_hdr = start + offset;
355		if (strncmp(syst_hdr->sig, SFI_SIG_SYST,
356				SFI_SIGNATURE_SIZE))
357			continue;
358
359		if (syst_hdr->len > PAGE_SIZE)
360			continue;
361
362		sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset,
363					syst_hdr);
364
365		if (sfi_verify_table(syst_hdr))
366			continue;
367
368		/*
369		 * Enforce SFI spec mandate that SYST reside within a page.
370		 */
371		if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) {
372			pr_info("SYST 0x%llx + 0x%x crosses page\n",
373					syst_pa, syst_hdr->len);
374			continue;
375		}
376
377		/* Success */
378		syst_pa = SFI_SYST_SEARCH_BEGIN + offset;
379		sfi_unmap_memory(start, len);
380		return 0;
381	}
382
383	sfi_unmap_memory(start, len);
384	return -1;
385}
386
387static struct kobject *sfi_kobj;
388static struct kobject *tables_kobj;
389
390static ssize_t sfi_table_show(struct file *filp, struct kobject *kobj,
391			       struct bin_attribute *bin_attr, char *buf,
392			       loff_t offset, size_t count)
393{
394	struct sfi_table_attr *tbl_attr =
395	    container_of(bin_attr, struct sfi_table_attr, attr);
396	struct sfi_table_header *th = NULL;
397	struct sfi_table_key key;
398	ssize_t cnt;
399
400	key.sig = tbl_attr->name;
401	key.oem_id = NULL;
402	key.oem_table_id = NULL;
403
404	if (strncmp(SFI_SIG_SYST, tbl_attr->name, SFI_SIGNATURE_SIZE)) {
405		th = sfi_get_table(&key);
406		if (!th)
407			return 0;
408
409		cnt =  memory_read_from_buffer(buf, count, &offset,
410						th, th->len);
411		sfi_put_table(th);
412	} else
413		cnt =  memory_read_from_buffer(buf, count, &offset,
414					syst_va, syst_va->header.len);
415
416	return cnt;
417}
418
419struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
420{
421	struct sfi_table_attr *tbl_attr;
422	struct sfi_table_header *th;
423	int ret;
424
425	tbl_attr = kzalloc(sizeof(struct sfi_table_attr), GFP_KERNEL);
426	if (!tbl_attr)
427		return NULL;
428
429	th = sfi_map_table(pa);
430	if (!th || !th->sig[0]) {
431		kfree(tbl_attr);
432		return NULL;
433	}
434
435	sysfs_attr_init(&tbl_attr->attr.attr);
436	memcpy(tbl_attr->name, th->sig, SFI_SIGNATURE_SIZE);
437
438	tbl_attr->attr.size = 0;
439	tbl_attr->attr.read = sfi_table_show;
440	tbl_attr->attr.attr.name = tbl_attr->name;
441	tbl_attr->attr.attr.mode = 0400;
442
443	ret = sysfs_create_bin_file(tables_kobj,
444				  &tbl_attr->attr);
445	if (ret) {
446		kfree(tbl_attr);
447		tbl_attr = NULL;
448	}
449
450	sfi_unmap_table(th);
451	return tbl_attr;
452}
453
454static int __init sfi_sysfs_init(void)
455{
456	int tbl_cnt, i;
457
458	if (sfi_disabled)
459		return 0;
460
461	sfi_kobj = kobject_create_and_add("sfi", firmware_kobj);
462	if (!sfi_kobj)
463		return 0;
464
465	tables_kobj = kobject_create_and_add("tables", sfi_kobj);
466	if (!tables_kobj) {
467		kobject_put(sfi_kobj);
468		return 0;
469	}
470
471	sfi_sysfs_install_table(syst_pa);
472
473	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
474
475	for (i = 0; i < tbl_cnt; i++)
476		sfi_sysfs_install_table(syst_va->pentry[i]);
477
478	sfi_acpi_sysfs_init();
479	kobject_uevent(sfi_kobj, KOBJ_ADD);
480	kobject_uevent(tables_kobj, KOBJ_ADD);
481	pr_info("SFI sysfs interfaces init success\n");
482	return 0;
483}
484
485void __init sfi_init(void)
486{
487	if (!acpi_disabled)
488		disable_sfi();
489
490	if (sfi_disabled)
491		return;
492
493	pr_info("Simple Firmware Interface v0.81 http://simplefirmware.org\n");
494
495	if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
496		disable_sfi();
497
498	return;
499}
500
501void __init sfi_init_late(void)
502{
503	int length;
504
505	if (sfi_disabled)
506		return;
507
508	length = syst_va->header.len;
509	sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple));
510
511	/* Use memremap now after it is ready */
512	sfi_use_memremap = 1;
513	syst_va = sfi_map_memory(syst_pa, length);
514
515	sfi_acpi_init();
516}
517
518/*
519 * The reason we put it here because we need wait till the /sys/firmware
520 * is setup, then our interface can be registered in /sys/firmware/sfi
521 */
522core_initcall(sfi_sysfs_init);
v4.6
  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#include <linux/slab.h>
 
 71
 72#include "sfi_core.h"
 73
 74#define ON_SAME_PAGE(addr1, addr2) \
 75	(((unsigned long)(addr1) & PAGE_MASK) == \
 76	((unsigned long)(addr2) & PAGE_MASK))
 77#define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
 78				ON_SAME_PAGE(page, table + size))
 79
 80int sfi_disabled __read_mostly;
 81EXPORT_SYMBOL(sfi_disabled);
 82
 83static u64 syst_pa __read_mostly;
 84static struct sfi_table_simple *syst_va __read_mostly;
 85
 86/*
 87 * FW creates and saves the SFI tables in memory. When these tables get
 88 * used, they may need to be mapped to virtual address space, and the mapping
 89 * can happen before or after the ioremap() is ready, so a flag is needed
 90 * to indicating this
 91 */
 92static u32 sfi_use_ioremap __read_mostly;
 93
 94/*
 95 * sfi_un/map_memory calls early_ioremap/iounmap which is a __init function
 96 * and introduces section mismatch. So use __ref to make it calm.
 97 */
 98static void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
 99{
100	if (!phys || !size)
101		return NULL;
102
103	if (sfi_use_ioremap)
104		return ioremap_cache(phys, size);
105	else
106		return early_ioremap(phys, size);
107}
108
109static void __ref sfi_unmap_memory(void __iomem *virt, u32 size)
110{
111	if (!virt || !size)
112		return;
113
114	if (sfi_use_ioremap)
115		iounmap(virt);
116	else
117		early_iounmap(virt, size);
118}
119
120static void sfi_print_table_header(unsigned long long pa,
121				struct sfi_table_header *header)
122{
123	pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n",
124		header->sig, pa,
125		header->len, header->rev, header->oem_id,
126		header->oem_table_id);
127}
128
129/*
130 * sfi_verify_table()
131 * Sanity check table lengh, calculate checksum
132 */
133static int sfi_verify_table(struct sfi_table_header *table)
134{
135
136	u8 checksum = 0;
137	u8 *puchar = (u8 *)table;
138	u32 length = table->len;
139
140	/* Sanity check table length against arbitrary 1MB limit */
141	if (length > 0x100000) {
142		pr_err("Invalid table length 0x%x\n", length);
143		return -1;
144	}
145
146	while (length--)
147		checksum += *puchar++;
148
149	if (checksum) {
150		pr_err("Checksum %2.2X should be %2.2X\n",
151			table->csum, table->csum - checksum);
152		return -1;
153	}
154	return 0;
155}
156
157/*
158 * sfi_map_table()
159 *
160 * Return address of mapped table
161 * Check for common case that we can re-use mapping to SYST,
162 * which requires syst_pa, syst_va to be initialized.
163 */
164static struct sfi_table_header *sfi_map_table(u64 pa)
165{
166	struct sfi_table_header *th;
167	u32 length;
168
169	if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
170		th = sfi_map_memory(pa, sizeof(struct sfi_table_header));
171	else
172		th = (void *)syst_va + (pa - syst_pa);
173
174	 /* If table fits on same page as its header, we are done */
175	if (TABLE_ON_PAGE(th, th, th->len))
176		return th;
177
178	/* Entire table does not fit on same page as SYST */
179	length = th->len;
180	if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
181		sfi_unmap_memory(th, sizeof(struct sfi_table_header));
182
183	return sfi_map_memory(pa, length);
184}
185
186/*
187 * sfi_unmap_table()
188 *
189 * Undoes effect of sfi_map_table() by unmapping table
190 * if it did not completely fit on same page as SYST.
191 */
192static void sfi_unmap_table(struct sfi_table_header *th)
193{
194	if (!TABLE_ON_PAGE(syst_va, th, th->len))
195		sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
196					sizeof(*th) : th->len);
197}
198
199static int sfi_table_check_key(struct sfi_table_header *th,
200				struct sfi_table_key *key)
201{
202
203	if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE)
204		|| (key->oem_id && strncmp(th->oem_id,
205				key->oem_id, SFI_OEM_ID_SIZE))
206		|| (key->oem_table_id && strncmp(th->oem_table_id,
207				key->oem_table_id, SFI_OEM_TABLE_ID_SIZE)))
208		return -1;
209
210	return 0;
211}
212
213/*
214 * This function will be used in 2 cases:
215 * 1. used to enumerate and verify the tables addressed by SYST/XSDT,
216 *    thus no signature will be given (in kernel boot phase)
217 * 2. used to parse one specific table, signature must exist, and
218 *    the mapped virt address will be returned, and the virt space
219 *    will be released by call sfi_put_table() later
220 *
221 * This two cases are from two different functions with two different
222 * sections and causes section mismatch warning. So use __ref to tell
223 * modpost not to make any noise.
224 *
225 * Return value:
226 *	NULL:			when can't find a table matching the key
227 *	ERR_PTR(error):		error value
228 *	virt table address:	when a matched table is found
229 */
230struct sfi_table_header *
231 __ref sfi_check_table(u64 pa, struct sfi_table_key *key)
232{
233	struct sfi_table_header *th;
234	void *ret = NULL;
235
236	th = sfi_map_table(pa);
237	if (!th)
238		return ERR_PTR(-ENOMEM);
239
240	if (!key->sig) {
241		sfi_print_table_header(pa, th);
242		if (sfi_verify_table(th))
243			ret = ERR_PTR(-EINVAL);
244	} else {
245		if (!sfi_table_check_key(th, key))
246			return th;	/* Success */
247	}
248
249	sfi_unmap_table(th);
250	return ret;
251}
252
253/*
254 * sfi_get_table()
255 *
256 * Search SYST for the specified table with the signature in
257 * the key, and return the mapped table
258 */
259struct sfi_table_header *sfi_get_table(struct sfi_table_key *key)
260{
261	struct sfi_table_header *th;
262	u32 tbl_cnt, i;
263
264	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
265	for (i = 0; i < tbl_cnt; i++) {
266		th = sfi_check_table(syst_va->pentry[i], key);
267		if (!IS_ERR(th) && th)
268			return th;
269	}
270
271	return NULL;
272}
273
274void sfi_put_table(struct sfi_table_header *th)
275{
276	sfi_unmap_table(th);
277}
278
279/* Find table with signature, run handler on it */
280int sfi_table_parse(char *signature, char *oem_id, char *oem_table_id,
281			sfi_table_handler handler)
282{
283	struct sfi_table_header *table = NULL;
284	struct sfi_table_key key;
285	int ret = -EINVAL;
286
287	if (sfi_disabled || !handler || !signature)
288		goto exit;
289
290	key.sig = signature;
291	key.oem_id = oem_id;
292	key.oem_table_id = oem_table_id;
293
294	table = sfi_get_table(&key);
295	if (!table)
296		goto exit;
297
298	ret = handler(table);
299	sfi_put_table(table);
300exit:
301	return ret;
302}
303EXPORT_SYMBOL_GPL(sfi_table_parse);
304
305/*
306 * sfi_parse_syst()
307 * Checksum all the tables in SYST and print their headers
308 *
309 * success: set syst_va, return 0
310 */
311static int __init sfi_parse_syst(void)
312{
313	struct sfi_table_key key = SFI_ANY_KEY;
314	int tbl_cnt, i;
315	void *ret;
316
317	syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple));
318	if (!syst_va)
319		return -ENOMEM;
320
321	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
322	for (i = 0; i < tbl_cnt; i++) {
323		ret = sfi_check_table(syst_va->pentry[i], &key);
324		if (IS_ERR(ret))
325			return PTR_ERR(ret);
326	}
327
328	return 0;
329}
330
331/*
332 * The OS finds the System Table by searching 16-byte boundaries between
333 * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region
334 * starting at the low address and shall stop searching when the 1st valid SFI
335 * System Table is found.
336 *
337 * success: set syst_pa, return 0
338 * fail: return -1
339 */
340static __init int sfi_find_syst(void)
341{
342	unsigned long offset, len;
343	void *start;
344
345	len = SFI_SYST_SEARCH_END - SFI_SYST_SEARCH_BEGIN;
346	start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len);
347	if (!start)
348		return -1;
349
350	for (offset = 0; offset < len; offset += 16) {
351		struct sfi_table_header *syst_hdr;
352
353		syst_hdr = start + offset;
354		if (strncmp(syst_hdr->sig, SFI_SIG_SYST,
355				SFI_SIGNATURE_SIZE))
356			continue;
357
358		if (syst_hdr->len > PAGE_SIZE)
359			continue;
360
361		sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset,
362					syst_hdr);
363
364		if (sfi_verify_table(syst_hdr))
365			continue;
366
367		/*
368		 * Enforce SFI spec mandate that SYST reside within a page.
369		 */
370		if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) {
371			pr_info("SYST 0x%llx + 0x%x crosses page\n",
372					syst_pa, syst_hdr->len);
373			continue;
374		}
375
376		/* Success */
377		syst_pa = SFI_SYST_SEARCH_BEGIN + offset;
378		sfi_unmap_memory(start, len);
379		return 0;
380	}
381
382	sfi_unmap_memory(start, len);
383	return -1;
384}
385
386static struct kobject *sfi_kobj;
387static struct kobject *tables_kobj;
388
389static ssize_t sfi_table_show(struct file *filp, struct kobject *kobj,
390			       struct bin_attribute *bin_attr, char *buf,
391			       loff_t offset, size_t count)
392{
393	struct sfi_table_attr *tbl_attr =
394	    container_of(bin_attr, struct sfi_table_attr, attr);
395	struct sfi_table_header *th = NULL;
396	struct sfi_table_key key;
397	ssize_t cnt;
398
399	key.sig = tbl_attr->name;
400	key.oem_id = NULL;
401	key.oem_table_id = NULL;
402
403	if (strncmp(SFI_SIG_SYST, tbl_attr->name, SFI_SIGNATURE_SIZE)) {
404		th = sfi_get_table(&key);
405		if (!th)
406			return 0;
407
408		cnt =  memory_read_from_buffer(buf, count, &offset,
409						th, th->len);
410		sfi_put_table(th);
411	} else
412		cnt =  memory_read_from_buffer(buf, count, &offset,
413					syst_va, syst_va->header.len);
414
415	return cnt;
416}
417
418struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
419{
420	struct sfi_table_attr *tbl_attr;
421	struct sfi_table_header *th;
422	int ret;
423
424	tbl_attr = kzalloc(sizeof(struct sfi_table_attr), GFP_KERNEL);
425	if (!tbl_attr)
426		return NULL;
427
428	th = sfi_map_table(pa);
429	if (!th || !th->sig[0]) {
430		kfree(tbl_attr);
431		return NULL;
432	}
433
434	sysfs_attr_init(&tbl_attr->attr.attr);
435	memcpy(tbl_attr->name, th->sig, SFI_SIGNATURE_SIZE);
436
437	tbl_attr->attr.size = 0;
438	tbl_attr->attr.read = sfi_table_show;
439	tbl_attr->attr.attr.name = tbl_attr->name;
440	tbl_attr->attr.attr.mode = 0400;
441
442	ret = sysfs_create_bin_file(tables_kobj,
443				  &tbl_attr->attr);
444	if (ret) {
445		kfree(tbl_attr);
446		tbl_attr = NULL;
447	}
448
449	sfi_unmap_table(th);
450	return tbl_attr;
451}
452
453static int __init sfi_sysfs_init(void)
454{
455	int tbl_cnt, i;
456
457	if (sfi_disabled)
458		return 0;
459
460	sfi_kobj = kobject_create_and_add("sfi", firmware_kobj);
461	if (!sfi_kobj)
462		return 0;
463
464	tables_kobj = kobject_create_and_add("tables", sfi_kobj);
465	if (!tables_kobj) {
466		kobject_put(sfi_kobj);
467		return 0;
468	}
469
470	sfi_sysfs_install_table(syst_pa);
471
472	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
473
474	for (i = 0; i < tbl_cnt; i++)
475		sfi_sysfs_install_table(syst_va->pentry[i]);
476
477	sfi_acpi_sysfs_init();
478	kobject_uevent(sfi_kobj, KOBJ_ADD);
479	kobject_uevent(tables_kobj, KOBJ_ADD);
480	pr_info("SFI sysfs interfaces init success\n");
481	return 0;
482}
483
484void __init sfi_init(void)
485{
486	if (!acpi_disabled)
487		disable_sfi();
488
489	if (sfi_disabled)
490		return;
491
492	pr_info("Simple Firmware Interface v0.81 http://simplefirmware.org\n");
493
494	if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
495		disable_sfi();
496
497	return;
498}
499
500void __init sfi_init_late(void)
501{
502	int length;
503
504	if (sfi_disabled)
505		return;
506
507	length = syst_va->header.len;
508	sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple));
509
510	/* Use ioremap now after it is ready */
511	sfi_use_ioremap = 1;
512	syst_va = sfi_map_memory(syst_pa, length);
513
514	sfi_acpi_init();
515}
516
517/*
518 * The reason we put it here because we need wait till the /sys/firmware
519 * is setup, then our interface can be registered in /sys/firmware/sfi
520 */
521core_initcall(sfi_sysfs_init);