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