sfi_core.c revision 011a606d0670196c17110b6770e39cc0865aa614
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>
706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#include "sfi_core.h"
726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define ON_SAME_PAGE(addr1, addr2) \
746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	(((unsigned long)(addr1) & PAGE_MASK) == \
756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	((unsigned long)(addr2) & PAGE_MASK))
766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang#define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				ON_SAME_PAGE(page, table + size))
786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangint sfi_disabled __read_mostly;
806ae6996a466e14bcf41618cde641a74ae03dc285Feng TangEXPORT_SYMBOL(sfi_disabled);
816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic u64 syst_pa __read_mostly;
836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic struct sfi_table_simple *syst_va __read_mostly;
846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * FW creates and saves the SFI tables in memory. When these tables get
876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * used, they may need to be mapped to virtual address space, and the mapping
886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * can happen before or after the ioremap() is ready, so a flag is needed
896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * to indicating this
906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic u32 sfi_use_ioremap __read_mostly;
926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
9301674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick/*
9401674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * sfi_un/map_memory calls early_ioremap/iounmap which is a __init function
9501674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * and introduces section mismatch. So use __ref to make it calm.
9601674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick */
9701674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstatic void __iomem * __ref sfi_map_memory(u64 phys, u32 size)
986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!phys || !size)
1006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return NULL;
1016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_use_ioremap)
1036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return ioremap(phys, size);
1046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	else
1056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return early_ioremap(phys, size);
1066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
10801674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstatic void __ref sfi_unmap_memory(void __iomem *virt, u32 size)
1096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!virt || !size)
1116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return;
1126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_use_ioremap)
1146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		iounmap(virt);
1156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	else
1166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		early_iounmap(virt, size);
1176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic void sfi_print_table_header(unsigned long long pa,
1206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				struct sfi_table_header *header)
1216ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1226ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	pr_info("%4.4s %llX, %04X (v%d %6.6s %8.8s)\n",
1236ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		header->sig, pa,
1246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		header->len, header->rev, header->oem_id,
1256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		header->oem_table_id);
1266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
1296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_verify_table()
1306ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Sanity check table lengh, calculate checksum
1316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
132011a606d0670196c17110b6770e39cc0865aa614Arjan van de Venstatic int sfi_verify_table(struct sfi_table_header *table)
1336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u8 checksum = 0;
1366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u8 *puchar = (u8 *)table;
1376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u32 length = table->len;
1386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	/* Sanity check table length against arbitrary 1MB limit */
1406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (length > 0x100000) {
1416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		pr_err("Invalid table length 0x%x\n", length);
1426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -1;
1436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
1446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	while (length--)
1466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		checksum += *puchar++;
1476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (checksum) {
1496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		pr_err("Checksum %2.2X should be %2.2X\n",
1506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			table->csum, table->csum - checksum);
1516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -1;
1526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
1536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return 0;
1546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
1576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_map_table()
1586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
1596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Return address of mapped table
1606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Check for common case that we can re-use mapping to SYST,
1616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * which requires syst_pa, syst_va to be initialized.
1626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
1636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstruct sfi_table_header *sfi_map_table(u64 pa)
1646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_header *th;
1666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u32 length;
1676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
1696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		th = sfi_map_memory(pa, sizeof(struct sfi_table_header));
1706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	else
1716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		th = (void *)syst_va + (pa - syst_pa);
1726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	 /* If table fits on same page as its header, we are done */
1746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (TABLE_ON_PAGE(th, th, th->len))
1756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return th;
1766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	/* Entire table does not fit on same page as SYST */
1786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	length = th->len;
1796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!TABLE_ON_PAGE(syst_pa, pa, sizeof(struct sfi_table_header)))
1806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_unmap_memory(th, sizeof(struct sfi_table_header));
1816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return sfi_map_memory(pa, length);
1836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
1866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_unmap_table()
1876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
1886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Undoes effect of sfi_map_table() by unmapping table
1896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * if it did not completely fit on same page as SYST.
1906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
1916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid sfi_unmap_table(struct sfi_table_header *th)
1926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
1936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!TABLE_ON_PAGE(syst_va, th, th->len))
1946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
1956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang					sizeof(*th) : th->len);
1966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
1976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
1986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic int sfi_table_check_key(struct sfi_table_header *th,
1996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				struct sfi_table_key *key)
2006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (strncmp(th->sig, key->sig, SFI_SIGNATURE_SIZE)
2036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		|| (key->oem_id && strncmp(th->oem_id,
2046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				key->oem_id, SFI_OEM_ID_SIZE))
2056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		|| (key->oem_table_id && strncmp(th->oem_table_id,
2066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				key->oem_table_id, SFI_OEM_TABLE_ID_SIZE)))
2076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -1;
2086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return 0;
2106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
2116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
2136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * This function will be used in 2 cases:
2146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 1. used to enumerate and verify the tables addressed by SYST/XSDT,
2156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *    thus no signature will be given (in kernel boot phase)
2166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * 2. used to parse one specific table, signature must exist, and
2176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *    the mapped virt address will be returned, and the virt space
2186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *    will be released by call sfi_put_table() later
2196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
22001674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * This two cases are from two different functions with two different
22101674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * sections and causes section mismatch warning. So use __ref to tell
22201674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick * modpost not to make any noise.
22301674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick *
2246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Return value:
2256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *	NULL:			when can't find a table matching the key
2266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *	ERR_PTR(error):		error value
2276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *	virt table address:	when a matched table is found
2286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
22901674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullickstruct sfi_table_header *
23001674da6f587a3f3940eedf2c1e97d51c35b994eRakib Mullick __ref sfi_check_table(u64 pa, struct sfi_table_key *key)
2316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_header *th;
2336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	void *ret = NULL;
2346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	th = sfi_map_table(pa);
2366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!th)
2376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return ERR_PTR(-ENOMEM);
2386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!key->sig) {
2406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_print_table_header(pa, th);
2416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (sfi_verify_table(th))
2426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			ret = ERR_PTR(-EINVAL);
2436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	} else {
2446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (!sfi_table_check_key(th, key))
2456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			return th;	/* Success */
2466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
2476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_unmap_table(th);
2496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return ret;
2506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
2516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
2536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_get_table()
2546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
2556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Search SYST for the specified table with the signature in
2566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * the key, and return the mapped table
2576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
2586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstruct sfi_table_header *sfi_get_table(struct sfi_table_key *key)
2596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_header *th;
2616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	u32 tbl_cnt, i;
2626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
2646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	for (i = 0; i < tbl_cnt; i++) {
2656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		th = sfi_check_table(syst_va->pentry[i], key);
2666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (!IS_ERR(th) && th)
2676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			return th;
2686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
2696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return NULL;
2716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
2726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid sfi_put_table(struct sfi_table_header *th)
2746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_unmap_table(th);
2766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
2776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/* Find table with signature, run handler on it */
2796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangint sfi_table_parse(char *signature, char *oem_id, char *oem_table_id,
2806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			sfi_table_handler handler)
2816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
2826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_header *table = NULL;
2836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_key key;
2846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	int ret = -EINVAL;
2856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_disabled || !handler || !signature)
2876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		goto exit;
2886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	key.sig = signature;
2906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	key.oem_id = oem_id;
2916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	key.oem_table_id = oem_table_id;
2926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	table = sfi_get_table(&key);
2946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!table)
2956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		goto exit;
2966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
2976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	ret = handler(table);
2986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_put_table(table);
2996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangexit:
3006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return ret;
3016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
3026ae6996a466e14bcf41618cde641a74ae03dc285Feng TangEXPORT_SYMBOL_GPL(sfi_table_parse);
3036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
3056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * sfi_parse_syst()
3066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * Checksum all the tables in SYST and print their headers
3076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
3086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * success: set syst_va, return 0
3096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
3106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic int __init sfi_parse_syst(void)
3116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
3126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	struct sfi_table_key key = SFI_ANY_KEY;
3136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	int tbl_cnt, i;
3146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	void *ret;
3156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	syst_va = sfi_map_memory(syst_pa, sizeof(struct sfi_table_simple));
3176ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!syst_va)
3186ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -ENOMEM;
3196ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3206ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	tbl_cnt = SFI_GET_NUM_ENTRIES(syst_va, u64);
3216ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	for (i = 0; i < tbl_cnt; i++) {
3226ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		ret = sfi_check_table(syst_va->pentry[i], &key);
3236ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (IS_ERR(ret))
3246ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			return PTR_ERR(ret);
3256ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
3266ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3276ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return 0;
3286ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
3296ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3306ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang/*
3316ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * The OS finds the System Table by searching 16-byte boundaries between
3326ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * physical address 0x000E0000 and 0x000FFFFF. The OS shall search this region
3336ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * starting at the low address and shall stop searching when the 1st valid SFI
3346ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * System Table is found.
3356ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang *
3366ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * success: set syst_pa, return 0
3376ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang * fail: return -1
3386ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang */
3396ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangstatic __init int sfi_find_syst(void)
3406ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
3416ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	unsigned long offset, len;
3426ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	void *start;
3436ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3446ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	len = SFI_SYST_SEARCH_END - SFI_SYST_SEARCH_BEGIN;
3456ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	start = sfi_map_memory(SFI_SYST_SEARCH_BEGIN, len);
3466ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!start)
3476ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return -1;
3486ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3496ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	for (offset = 0; offset < len; offset += 16) {
3506ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		struct sfi_table_header *syst_hdr;
3516ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3526ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		syst_hdr = start + offset;
3536ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (strncmp(syst_hdr->sig, SFI_SIG_SYST,
3546ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang				SFI_SIGNATURE_SIZE))
3556ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			continue;
3566ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3576ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (syst_hdr->len > PAGE_SIZE)
3586ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			continue;
3596ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3606ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_print_table_header(SFI_SYST_SEARCH_BEGIN + offset,
3616ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang					syst_hdr);
3626ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3636ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (sfi_verify_table(syst_hdr))
3646ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			continue;
3656ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3666ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		/*
3676ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		 * Enforce SFI spec mandate that SYST reside within a page.
3686ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		 */
3696ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		if (!ON_SAME_PAGE(syst_pa, syst_pa + syst_hdr->len)) {
3706ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			pr_info("SYST 0x%llx + 0x%x crosses page\n",
3716ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang					syst_pa, syst_hdr->len);
3726ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang			continue;
3736ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		}
3746ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3756ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		/* Success */
3766ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		syst_pa = SFI_SYST_SEARCH_BEGIN + offset;
3776ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		sfi_unmap_memory(start, len);
3786ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return 0;
3796ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	}
3806ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3816ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_unmap_memory(start, len);
3826ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return -1;
3836ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
3846ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3856ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid __init sfi_init(void)
3866ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
3876ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (!acpi_disabled)
3886ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		disable_sfi();
3896ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3906ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_disabled)
3916ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return;
3926ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3936ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	pr_info("Simple Firmware Interface v0.7 http://simplefirmware.org\n");
3946ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3956ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_find_syst() || sfi_parse_syst() || sfi_platform_init())
3966ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		disable_sfi();
3976ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
3986ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	return;
3996ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
4006ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4016ae6996a466e14bcf41618cde641a74ae03dc285Feng Tangvoid __init sfi_init_late(void)
4026ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang{
4036ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	int length;
4046ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4056ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	if (sfi_disabled)
4066ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang		return;
4076ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4086ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	length = syst_va->header.len;
4096ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_unmap_memory(syst_va, sizeof(struct sfi_table_simple));
4106ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4116ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	/* Use ioremap now after it is ready */
4126ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_use_ioremap = 1;
4136ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	syst_va = sfi_map_memory(syst_pa, length);
4146ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang
4156ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang	sfi_acpi_init();
4166ae6996a466e14bcf41618cde641a74ae03dc285Feng Tang}
417