16ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* sfi_core.c Simple Firmware Interface - core internals */
26ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
36ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
46ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
56ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  This file is provided under a dual BSD/GPLv2 license.  When using or
66ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  redistributing this file, you may do so under either license.
76ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
86ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  GPL LICENSE SUMMARY
96ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  Copyright(c) 2009 Intel Corporation. All rights reserved.
116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  This program is free software; you can redistribute it and/or modify
136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  it under the terms of version 2 of the GNU General Public License as
146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  published by the Free Software Foundation.
156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  This program is distributed in the hope that it will be useful, but
176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  WITHOUT ANY WARRANTY; without even the implied warranty of
186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  General Public License for more details.
206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
216ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  You should have received a copy of the GNU General Public License
226ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  along with this program; if not, write to the Free Software
236ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  The full GNU General Public License is included in this distribution
256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  in the file called LICENSE.GPL.
266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  BSD LICENSE
286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  Copyright(c) 2009 Intel Corporation. All rights reserved.
306ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  Redistribution and use in source and binary forms, with or without
326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  modification, are permitted provided that the following conditions
336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  are met:
346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang    * Redistributions of source code must retain the above copyright
366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang      notice, this list of conditions and the following disclaimer.
376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang    * Redistributions in binary form must reproduce the above copyright
386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang      notice, this list of conditions and the following disclaimer in
396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang      the documentation and/or other materials provided with the
406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang      distribution.
416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang    * Neither the name of Intel Corporation nor the names of its
426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang      contributors may be used to endorse or promote products derived
436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang      from this software without specific prior written permission.
446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang*/
586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define KMSG_COMPONENT "SFI"
606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/bootmem.h>
636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/kernel.h>
646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/module.h>
656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/errno.h>
666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/types.h>
676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/acpi.h>
686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/init.h>
696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include <linux/sfi.h>
70dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang#include <linux/slab.h>
716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include "sfi_core.h"
736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define ON_SAME_PAGE(addr1, addr2) \
756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	(((unsigned long)(addr1) & PAGE_MASK) == \
766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	((unsigned long)(addr2) & PAGE_MASK))
776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				ON_SAME_PAGE(page, table + size))
796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangint sfi_disabled __read_mostly;
816ae6996a466e14bcf41618cde641a74ae03dc285Feng TangEXPORT_SYMBOL(sfi_disabled);
826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic u64 syst_pa __read_mostly;
846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic struct sfi_table_simple *syst_va __read_mostly;
856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * FW creates and saves the SFI tables in memory. When these tables get
886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * used, they may need to be mapped to virtual address space, and the mapping
896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * can happen before or after the ioremap() is ready, so a flag is needed
906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * to indicating this
916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic u32 sfi_use_ioremap __read_mostly;
936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
9401674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick/*
9501674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * sfi_un/map_memory calls early_ioremap/iounmap which is a __init function
9601674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * and introduces section mismatch. So use __ref to make it calm.
9701674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick */
9801674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstatic void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!phys || !size)
1016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return NULL;
1026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_use_ioremap)
1045b026c4e3af52fda22c9313a3388344f82f3ba15Len Brown		return ioremap_cache(phys, size);
1056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	else
1066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return early_ioremap(phys, size);
1076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
10901674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstatic void __ref sfi_unmap_memory(void __iomem *virt, u32 size)
1106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!virt || !size)
1126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return;
1136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_use_ioremap)
1156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		iounmap(virt);
1166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	else
1176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		early_iounmap(virt, size);
1186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic void sfi_print_table_header(unsigned long long pa,
1216ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				struct sfi_table_header *header)
1226ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1236ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n",
1246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		header->sig, pa,
1256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		header->len, header->rev, header->oem_id,
1266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		header->oem_table_id);
1276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
1306ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_verify_table()
1316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Sanity check table lengh, calculate checksum
1326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
133011a606d0670196c17110b6770e39cc0865aa614Arjan van de Venstatic int sfi_verify_table(struct sfi_table_header *table)
1346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u8 checksum = 0;
1376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u8 *puchar = (u8 *)table;
1386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u32 length = table->len;
1396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	/* Sanity check table length against arbitrary 1MB limit */
1416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (length > 0x100000) {
1426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		pr_err("Invalid table length 0x%x\n", length);
1436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -1;
1446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
1456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	while (length--)
1476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		checksum += *puchar++;
1486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (checksum) {
1506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		pr_err("Checksum %2.2X should be %2.2X\n",
1516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			table->csum, table->csum - checksum);
1526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -1;
1536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
1546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return 0;
1556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
1586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_map_table()
1596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
1606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Return address of mapped table
1616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Check for common case that we can re-use mapping to SYST,
1626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * which requires syst_pa, syst_va to be initialized.
1636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
1646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstruct sfi_table_header *sfi_map_table(u64 pa)
1656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_header *th;
1676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u32 length;
1686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
1706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		th = sfi_map_memory(pa, sizeof(struct sfi_table_header));
1716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	else
1726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		th = (void *)syst_va + (pa - syst_pa);
1736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	 /* If table fits on same page as its header, we are done */
1756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (TABLE_ON_PAGE(th, th, th->len))
1766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return th;
1776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	/* Entire table does not fit on same page as SYST */
1796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	length = th->len;
1806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
1816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_unmap_memory(th, sizeof(struct sfi_table_header));
1826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return sfi_map_memory(pa, length);
1846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
1876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_unmap_table()
1886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
1896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Undoes effect of sfi_map_table() by unmapping table
1906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * if it did not completely fit on same page as SYST.
1916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
1926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid sfi_unmap_table(struct sfi_table_header *th)
1936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!TABLE_ON_PAGE(syst_va, th, th->len))
1956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
1966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang					sizeof(*th) : th->len);
1976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic int sfi_table_check_key(struct sfi_table_header *th,
2006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				struct sfi_table_key *key)
2016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE)
2046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		|| (key->oem_id && strncmp(th->oem_id,
2056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				key->oem_id, SFI_OEM_ID_SIZE))
2066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		|| (key->oem_table_id && strncmp(th->oem_table_id,
2076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				key->oem_table_id, SFI_OEM_TABLE_ID_SIZE)))
2086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -1;
2096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return 0;
2116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
2126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
2146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * This function will be used in 2 cases:
2156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 1. used to enumerate and verify the tables addressed by SYST/XSDT,
2166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *    thus no signature will be given (in kernel boot phase)
2176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 2. used to parse one specific table, signature must exist, and
2186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *    the mapped virt address will be returned, and the virt space
2196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *    will be released by call sfi_put_table() later
2206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
22101674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * This two cases are from two different functions with two different
22201674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * sections and causes section mismatch warning. So use __ref to tell
22301674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * modpost not to make any noise.
22401674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick *
2256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Return value:
2266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *	NULL:			when can't find a table matching the key
2276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *	ERR_PTR(error):		error value
2286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *	virt table address:	when a matched table is found
2296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
23001674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstruct sfi_table_header *
23101674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick __ref sfi_check_table(u64 pa, struct sfi_table_key *key)
2326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_header *th;
2346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	void *ret = NULL;
2356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	th = sfi_map_table(pa);
2376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!th)
2386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return ERR_PTR(-ENOMEM);
2396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!key->sig) {
2416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_print_table_header(pa, th);
2426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (sfi_verify_table(th))
2436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			ret = ERR_PTR(-EINVAL);
2446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	} else {
2456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (!sfi_table_check_key(th, key))
2466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			return th;	/* Success */
2476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
2486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_unmap_table(th);
2506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return ret;
2516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
2526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
2546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_get_table()
2556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
2566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Search SYST for the specified table with the signature in
2576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * the key, and return the mapped table
2586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
2596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstruct sfi_table_header *sfi_get_table(struct sfi_table_key *key)
2606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_header *th;
2626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u32 tbl_cnt, i;
2636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
2656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	for (i = 0; i < tbl_cnt; i++) {
2666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		th = sfi_check_table(syst_va->pentry[i], key);
2676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (!IS_ERR(th) && th)
2686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			return th;
2696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
2706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return NULL;
2726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
2736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid sfi_put_table(struct sfi_table_header *th)
2756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_unmap_table(th);
2776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
2786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* Find table with signature, run handler on it */
2806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangint sfi_table_parse(char *signature, char *oem_id, char *oem_table_id,
2816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			sfi_table_handler handler)
2826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_header *table = NULL;
2846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_key key;
2856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	int ret = -EINVAL;
2866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_disabled || !handler || !signature)
2886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		goto exit;
2896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	key.sig = signature;
2916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	key.oem_id = oem_id;
2926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	key.oem_table_id = oem_table_id;
2936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	table = sfi_get_table(&key);
2956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!table)
2966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		goto exit;
2976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	ret = handler(table);
2996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_put_table(table);
3006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangexit:
3016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return ret;
3026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
3036ae6996a466e14bcf41618cde641a74ae03dc285Feng TangEXPORT_SYMBOL_GPL(sfi_table_parse);
3046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
3066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_parse_syst()
3076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Checksum all the tables in SYST and print their headers
3086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
3096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * success: set syst_va, return 0
3106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
3116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic int __init sfi_parse_syst(void)
3126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
3136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_key key = SFI_ANY_KEY;
3146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	int tbl_cnt, i;
3156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	void *ret;
3166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple));
3186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!syst_va)
3196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -ENOMEM;
3206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3216ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
3226ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	for (i = 0; i < tbl_cnt; i++) {
3236ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		ret = sfi_check_table(syst_va->pentry[i], &key);
3246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (IS_ERR(ret))
3256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			return PTR_ERR(ret);
3266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
3276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return 0;
3296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
3306ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
3326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * The OS finds the System Table by searching 16-byte boundaries between
3336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region
3346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * starting at the low address and shall stop searching when the 1st valid SFI
3356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * System Table is found.
3366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
3376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * success: set syst_pa, return 0
3386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * fail: return -1
3396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
3406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic __init int sfi_find_syst(void)
3416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
3426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	unsigned long offset, len;
3436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	void *start;
3446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	len = SFI_SYST_SEARCH_END - SFI_SYST_SEARCH_BEGIN;
3466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len);
3476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!start)
3486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -1;
3496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	for (offset = 0; offset < len; offset += 16) {
3516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		struct sfi_table_header *syst_hdr;
3526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		syst_hdr = start + offset;
3546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (strncmp(syst_hdr->sig, SFI_SIG_SYST,
3556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				SFI_SIGNATURE_SIZE))
3566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			continue;
3576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (syst_hdr->len > PAGE_SIZE)
3596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			continue;
3606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset,
3626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang					syst_hdr);
3636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (sfi_verify_table(syst_hdr))
3656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			continue;
3666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		/*
3686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		 * Enforce SFI spec mandate that SYST reside within a page.
3696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		 */
3706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) {
3716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			pr_info("SYST 0x%llx + 0x%x crosses page\n",
3726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang					syst_pa, syst_hdr->len);
3736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			continue;
3746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		}
3756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		/* Success */
3776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		syst_pa = SFI_SYST_SEARCH_BEGIN + offset;
3786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_unmap_memory(start, len);
3796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return 0;
3806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
3816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_unmap_memory(start, len);
3836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return -1;
3846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
3856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
386dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tangstatic struct kobject *sfi_kobj;
387dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tangstatic struct kobject *tables_kobj;
388dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
389dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tangstatic ssize_t sfi_table_show(struct file *filp, struct kobject *kobj,
390dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang			       struct bin_attribute *bin_attr, char *buf,
391dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang			       loff_t offset, size_t count)
392dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang{
393dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	struct sfi_table_attr *tbl_attr =
394dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	    container_of(bin_attr, struct sfi_table_attr, attr);
395dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	struct sfi_table_header *th = NULL;
396dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	struct sfi_table_key key;
397dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	ssize_t cnt;
398dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
399dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	key.sig = tbl_attr->name;
400dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	key.oem_id = NULL;
401dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	key.oem_table_id = NULL;
402dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
403dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	if (strncmp(SFI_SIG_SYST, tbl_attr->name, SFI_SIGNATURE_SIZE)) {
404dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		th = sfi_get_table(&key);
405dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		if (!th)
406dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang			return 0;
407dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
408dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		cnt =  memory_read_from_buffer(buf, count, &offset,
409dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang						th, th->len);
410dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		sfi_put_table(th);
411dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	} else
412dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		cnt =  memory_read_from_buffer(buf, count, &offset,
413dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang					syst_va, syst_va->header.len);
414dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
415dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	return cnt;
416dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang}
417dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
418dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tangstruct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
419dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang{
420dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	struct sfi_table_attr *tbl_attr;
421dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	struct sfi_table_header *th;
422dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	int ret;
423dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
424dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	tbl_attr = kzalloc(sizeof(struct sfi_table_attr), GFP_KERNEL);
425dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	if (!tbl_attr)
426dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		return NULL;
427dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
428dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	th = sfi_map_table(pa);
429dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	if (!th || !th->sig[0]) {
430dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		kfree(tbl_attr);
431dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		return NULL;
432dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	}
433dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
434dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	sysfs_attr_init(&tbl_attr->attr.attr);
435dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	memcpy(tbl_attr->name, th->sig, SFI_SIGNATURE_SIZE);
436dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
437dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	tbl_attr->attr.size = 0;
438dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	tbl_attr->attr.read = sfi_table_show;
439dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	tbl_attr->attr.attr.name = tbl_attr->name;
440dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	tbl_attr->attr.attr.mode = 0400;
441dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
442dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	ret = sysfs_create_bin_file(tables_kobj,
443dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang				  &tbl_attr->attr);
444e29df91e67428c1a651d18df6ec047fcb30282d3Dan Carpenter	if (ret) {
445dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		kfree(tbl_attr);
446e29df91e67428c1a651d18df6ec047fcb30282d3Dan Carpenter		tbl_attr = NULL;
447e29df91e67428c1a651d18df6ec047fcb30282d3Dan Carpenter	}
448dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
449dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	sfi_unmap_table(th);
450dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	return tbl_attr;
451dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang}
452dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
453dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tangstatic int __init sfi_sysfs_init(void)
454dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang{
455dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	int tbl_cnt, i;
456dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
457dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	if (sfi_disabled)
458dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		return 0;
459dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
460dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	sfi_kobj = kobject_create_and_add("sfi", firmware_kobj);
461dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	if (!sfi_kobj)
462dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		return 0;
463dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
464dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	tables_kobj = kobject_create_and_add("tables", sfi_kobj);
465dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	if (!tables_kobj) {
466dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		kobject_put(sfi_kobj);
467dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		return 0;
468dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	}
469dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
470dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	sfi_sysfs_install_table(syst_pa);
471dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
472dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
473dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
474dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	for (i = 0; i < tbl_cnt; i++)
475dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang		sfi_sysfs_install_table(syst_va->pentry[i]);
476dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
477dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	sfi_acpi_sysfs_init();
478dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	kobject_uevent(sfi_kobj, KOBJ_ADD);
479dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	kobject_uevent(tables_kobj, KOBJ_ADD);
480dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	pr_info("SFI sysfs interfaces init success\n");
481dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang	return 0;
482dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang}
483dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
4846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid __init sfi_init(void)
4856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
4866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!acpi_disabled)
4876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		disable_sfi();
4886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_disabled)
4906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return;
4916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4925487ab4a5a71e955fef7094a0624df0542da91efFeng Tang	pr_info("Simple Firmware Interface v0.81 http://simplefirmware.org\n");
4936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
4956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		disable_sfi();
4966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return;
4986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
4996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
5006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid __init sfi_init_late(void)
5016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
5026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	int length;
5036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
5046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_disabled)
5056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return;
5066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
5076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	length = syst_va->header.len;
5086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple));
5096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
5106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	/* Use ioremap now after it is ready */
5116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_use_ioremap = 1;
5126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	syst_va = sfi_map_memory(syst_pa, length);
5136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
5146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_acpi_init();
5156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
516dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang
517dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang/*
51825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * The reason we put it here because we need wait till the /sys/firmware
519dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang * is setup, then our interface can be registered in /sys/firmware/sfi
520dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tang */
521dce80a56268fffd6b5ea57b3f6ba3d027a68f05eFeng Tangcore_initcall(sfi_sysfs_init);
522