2007-02-02 19:48:20 +03:00
/******************************************************************************
*
* Module Name : tbfadt - FADT table utilities
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
2012-01-12 09:27:23 +04:00
* Copyright ( C ) 2000 - 2012 , Intel Corp .
2007-02-02 19:48:20 +03:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions , and the following disclaimer ,
* without modification .
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* substantially similar to the " NO WARRANTY " disclaimer below
* ( " Disclaimer " ) and any redistribution must be conditioned upon
* including a substantially similar Disclaimer requirement for further
* binary redistribution .
* 3. Neither the names of the above - listed copyright holders nor the names
* of any contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* Alternatively , this software may be distributed under the terms of the
* GNU General Public License ( " GPL " ) version 2 as published by the Free
* Software Foundation .
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION )
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT ,
* STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES .
*/
# include <acpi/acpi.h>
2009-01-09 08:30:03 +03:00
# include "accommon.h"
# include "actables.h"
2007-02-02 19:48:20 +03:00
# define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME ( " tbfadt " )
/* Local prototypes */
2010-09-15 09:36:55 +04:00
static ACPI_INLINE void
2007-02-02 19:48:20 +03:00
acpi_tb_init_generic_address ( struct acpi_generic_address * generic_address ,
2008-12-30 22:06:06 +03:00
u8 space_id , u8 byte_width , u64 address ) ;
2007-02-02 19:48:20 +03:00
2007-02-02 19:48:20 +03:00
static void acpi_tb_convert_fadt ( void ) ;
static void acpi_tb_validate_fadt ( void ) ;
2009-02-18 09:06:12 +03:00
static void acpi_tb_setup_fadt_registers ( void ) ;
2007-02-02 19:48:20 +03:00
/* Table for conversion of FADT to common internal format and FADT validation */
2007-02-02 19:48:20 +03:00
2007-02-02 19:48:20 +03:00
typedef struct acpi_fadt_info {
char * name ;
2012-01-12 07:09:58 +04:00
u16 address64 ;
u16 address32 ;
u16 length ;
2008-12-31 08:07:26 +03:00
u8 default_length ;
2007-02-02 19:48:20 +03:00
u8 type ;
2007-02-02 19:48:20 +03:00
2007-02-02 19:48:20 +03:00
} acpi_fadt_info ;
2007-02-02 19:48:20 +03:00
2012-01-12 07:09:58 +04:00
# define ACPI_FADT_OPTIONAL 0
2007-02-02 19:48:20 +03:00
# define ACPI_FADT_REQUIRED 1
# define ACPI_FADT_SEPARATE_LENGTH 2
static struct acpi_fadt_info fadt_info_table [ ] = {
2008-12-31 08:07:26 +03:00
{ " Pm1aEventBlock " ,
ACPI_FADT_OFFSET ( xpm1a_event_block ) ,
2007-02-02 19:48:20 +03:00
ACPI_FADT_OFFSET ( pm1a_event_block ) ,
2008-12-31 08:07:26 +03:00
ACPI_FADT_OFFSET ( pm1_event_length ) ,
ACPI_PM1_REGISTER_WIDTH * 2 , /* Enable + Status register */
ACPI_FADT_REQUIRED } ,
2007-02-02 19:48:20 +03:00
2008-12-31 08:07:26 +03:00
{ " Pm1bEventBlock " ,
ACPI_FADT_OFFSET ( xpm1b_event_block ) ,
2007-02-02 19:48:20 +03:00
ACPI_FADT_OFFSET ( pm1b_event_block ) ,
2008-12-31 08:07:26 +03:00
ACPI_FADT_OFFSET ( pm1_event_length ) ,
ACPI_PM1_REGISTER_WIDTH * 2 , /* Enable + Status register */
2012-01-12 07:09:58 +04:00
ACPI_FADT_OPTIONAL } ,
2007-02-02 19:48:20 +03:00
2008-12-31 08:07:26 +03:00
{ " Pm1aControlBlock " ,
ACPI_FADT_OFFSET ( xpm1a_control_block ) ,
2007-02-02 19:48:20 +03:00
ACPI_FADT_OFFSET ( pm1a_control_block ) ,
2008-12-31 08:07:26 +03:00
ACPI_FADT_OFFSET ( pm1_control_length ) ,
ACPI_PM1_REGISTER_WIDTH ,
ACPI_FADT_REQUIRED } ,
2007-02-02 19:48:20 +03:00
2008-12-31 08:07:26 +03:00
{ " Pm1bControlBlock " ,
ACPI_FADT_OFFSET ( xpm1b_control_block ) ,
2007-02-02 19:48:20 +03:00
ACPI_FADT_OFFSET ( pm1b_control_block ) ,
2008-12-31 08:07:26 +03:00
ACPI_FADT_OFFSET ( pm1_control_length ) ,
ACPI_PM1_REGISTER_WIDTH ,
2012-01-12 07:09:58 +04:00
ACPI_FADT_OPTIONAL } ,
2007-02-02 19:48:20 +03:00
2008-12-31 08:07:26 +03:00
{ " Pm2ControlBlock " ,
ACPI_FADT_OFFSET ( xpm2_control_block ) ,
2007-02-02 19:48:20 +03:00
ACPI_FADT_OFFSET ( pm2_control_block ) ,
2008-12-31 08:07:26 +03:00
ACPI_FADT_OFFSET ( pm2_control_length ) ,
ACPI_PM2_REGISTER_WIDTH ,
ACPI_FADT_SEPARATE_LENGTH } ,
2007-02-02 19:48:20 +03:00
2008-12-31 08:07:26 +03:00
{ " PmTimerBlock " ,
ACPI_FADT_OFFSET ( xpm_timer_block ) ,
2007-02-02 19:48:20 +03:00
ACPI_FADT_OFFSET ( pm_timer_block ) ,
2008-12-31 08:07:26 +03:00
ACPI_FADT_OFFSET ( pm_timer_length ) ,
ACPI_PM_TIMER_WIDTH ,
ACPI_FADT_REQUIRED } ,
2007-02-02 19:48:20 +03:00
2008-12-31 08:07:26 +03:00
{ " Gpe0Block " ,
ACPI_FADT_OFFSET ( xgpe0_block ) ,
2007-02-02 19:48:20 +03:00
ACPI_FADT_OFFSET ( gpe0_block ) ,
2008-12-31 08:07:26 +03:00
ACPI_FADT_OFFSET ( gpe0_block_length ) ,
0 ,
ACPI_FADT_SEPARATE_LENGTH } ,
2007-02-02 19:48:20 +03:00
2008-12-31 08:07:26 +03:00
{ " Gpe1Block " ,
ACPI_FADT_OFFSET ( xgpe1_block ) ,
2007-02-02 19:48:20 +03:00
ACPI_FADT_OFFSET ( gpe1_block ) ,
2008-12-31 08:07:26 +03:00
ACPI_FADT_OFFSET ( gpe1_block_length ) ,
0 ,
ACPI_FADT_SEPARATE_LENGTH }
2007-02-02 19:48:20 +03:00
} ;
2009-02-18 10:03:30 +03:00
# define ACPI_FADT_INFO_ENTRIES \
( sizeof ( fadt_info_table ) / sizeof ( struct acpi_fadt_info ) )
2007-02-02 19:48:20 +03:00
2009-02-18 09:06:12 +03:00
/* Table used to split Event Blocks into separate status/enable registers */
typedef struct acpi_fadt_pm_info {
struct acpi_generic_address * target ;
2012-01-12 07:09:58 +04:00
u16 source ;
2009-02-18 09:06:12 +03:00
u8 register_num ;
} acpi_fadt_pm_info ;
static struct acpi_fadt_pm_info fadt_pm_info_table [ ] = {
{ & acpi_gbl_xpm1a_status ,
ACPI_FADT_OFFSET ( xpm1a_event_block ) ,
0 } ,
{ & acpi_gbl_xpm1a_enable ,
ACPI_FADT_OFFSET ( xpm1a_event_block ) ,
1 } ,
{ & acpi_gbl_xpm1b_status ,
ACPI_FADT_OFFSET ( xpm1b_event_block ) ,
0 } ,
{ & acpi_gbl_xpm1b_enable ,
ACPI_FADT_OFFSET ( xpm1b_event_block ) ,
1 }
} ;
2009-02-18 10:03:30 +03:00
# define ACPI_FADT_PM_INFO_ENTRIES \
( sizeof ( fadt_pm_info_table ) / sizeof ( struct acpi_fadt_pm_info ) )
2009-02-18 09:06:12 +03:00
2007-02-02 19:48:20 +03:00
/*******************************************************************************
*
* FUNCTION : acpi_tb_init_generic_address
*
2007-02-02 19:48:20 +03:00
* PARAMETERS : generic_address - GAS struct to be initialized
ACPI: fix FADT parsing
The (1.0 inherited) separate length fields in the FADT are byte granular.
Further, PM1a/b may have distinct lengths (if using the v2 fields was
okay) and may live in distinct address spaces. acpi_tb_convert_fadt()
should account for all of these conditions.
Apart from these changes I'm puzzled by the fact that, not just for
acpi_gbl_xpm1{a,b}_enable, acpi_hw_low_level_{read,write}() get an
explicit size passed rather than using the size found in the passed GAS.
What happens on a platform that defines PM1{a,b} wider than 16 bits? Of
course, acpi_hw_low_level_{read,write}() at present are entirely
un-prepared to deal with sizes other than 8, 16, or 32, not to speak of a
non-zero bit_offset or access_width...
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Len Brown <len.brown@intel.com>
2008-09-20 02:50:32 +04:00
* byte_width - Width of this register
2007-02-02 19:48:20 +03:00
* Address - Address of the register
*
* RETURN : None
*
2007-02-02 19:48:20 +03:00
* DESCRIPTION : Initialize a Generic Address Structure ( GAS )
* See the ACPI specification for a full description and
* definition of this structure .
2007-02-02 19:48:20 +03:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-09-15 09:36:55 +04:00
static ACPI_INLINE void
2007-02-02 19:48:20 +03:00
acpi_tb_init_generic_address ( struct acpi_generic_address * generic_address ,
2008-12-30 22:06:06 +03:00
u8 space_id , u8 byte_width , u64 address )
2007-02-02 19:48:20 +03:00
{
2007-02-02 19:48:20 +03:00
/*
* The 64 - bit Address field is non - aligned in the byte packed
* GAS struct .
*/
ACPI_MOVE_64_TO_64 ( & generic_address - > address , & address ) ;
/* All other fields are byte-wide */
2008-12-30 22:06:06 +03:00
generic_address - > space_id = space_id ;
generic_address - > bit_width = ( u8 ) ACPI_MUL_8 ( byte_width ) ;
2007-02-02 19:48:20 +03:00
generic_address - > bit_offset = 0 ;
2008-12-30 22:06:06 +03:00
generic_address - > access_width = 0 ; /* Access width ANY */
2007-02-02 19:48:20 +03:00
}
/*******************************************************************************
*
* FUNCTION : acpi_tb_parse_fadt
*
* PARAMETERS : table_index - Index for the FADT
*
* RETURN : None
*
* DESCRIPTION : Initialize the FADT , DSDT and FACS tables
* ( FADT contains the addresses of the DSDT and FACS )
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-03 09:41:03 +03:00
void acpi_tb_parse_fadt ( u32 table_index )
2007-02-02 19:48:20 +03:00
{
u32 length ;
struct acpi_table_header * table ;
/*
2007-02-02 19:48:20 +03:00
* The FADT has multiple versions with different lengths ,
* and it contains pointers to both the DSDT and FACS tables .
2007-02-02 19:48:20 +03:00
*
* Get a local copy of the FADT and convert it to a common format
* Map entire FADT , assumed to be smaller than one page .
*/
length = acpi_gbl_root_table_list . tables [ table_index ] . length ;
table =
acpi_os_map_memory ( acpi_gbl_root_table_list . tables [ table_index ] .
address , length ) ;
if ( ! table ) {
return ;
}
/*
* Validate the FADT checksum before we copy the table . Ignore
* checksum error as we want to try to get the DSDT and FACS .
*/
( void ) acpi_tb_verify_checksum ( table , length ) ;
2009-02-18 09:06:12 +03:00
/* Create a local copy of the FADT in common ACPI 2.0+ format */
2007-02-02 19:48:20 +03:00
acpi_tb_create_local_fadt ( table , length ) ;
/* All done with the real FADT, unmap it */
acpi_os_unmap_memory ( table , length ) ;
/* Obtain the DSDT and FACS tables via their addresses within the FADT */
acpi_tb_install_table ( ( acpi_physical_address ) acpi_gbl_FADT . Xdsdt ,
2009-02-03 09:41:03 +03:00
ACPI_SIG_DSDT , ACPI_TABLE_INDEX_DSDT ) ;
2007-02-02 19:48:20 +03:00
2011-11-16 06:57:28 +04:00
/* If Hardware Reduced flag is set, there is no FACS */
if ( ! acpi_gbl_reduced_hardware ) {
acpi_tb_install_table ( ( acpi_physical_address ) acpi_gbl_FADT .
Xfacs , ACPI_SIG_FACS ,
ACPI_TABLE_INDEX_FACS ) ;
}
2007-02-02 19:48:20 +03:00
}
/*******************************************************************************
*
* FUNCTION : acpi_tb_create_local_fadt
*
* PARAMETERS : Table - Pointer to BIOS FADT
* Length - Length of the table
*
* RETURN : None
*
* DESCRIPTION : Get a local copy of the FADT and convert it to a common format .
* Performs validation on some important FADT fields .
*
2007-05-02 23:51:37 +04:00
* NOTE : We create a local copy of the FADT regardless of the version .
*
2007-02-02 19:48:20 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void acpi_tb_create_local_fadt ( struct acpi_table_header * table , u32 length )
{
2007-02-02 19:48:20 +03:00
/*
2007-05-02 23:51:37 +04:00
* Check if the FADT is larger than the largest table that we expect
2011-11-16 06:42:09 +04:00
* ( the ACPI 5.0 version ) . If so , truncate the table , and issue
2007-05-02 23:51:37 +04:00
* a warning .
2007-02-02 19:48:20 +03:00
*/
if ( length > sizeof ( struct acpi_table_fadt ) ) {
ACPI_WARNING ( ( AE_INFO ,
2011-11-16 06:42:09 +04:00
" FADT (revision %u) is longer than ACPI 5.0 version, "
2010-03-05 12:56:40 +03:00
" truncating length %u to %u " ,
2009-04-22 08:52:51 +04:00
table - > revision , length ,
( u32 ) sizeof ( struct acpi_table_fadt ) ) ) ;
2007-02-02 19:48:20 +03:00
}
2007-02-02 19:48:20 +03:00
2007-05-02 23:51:37 +04:00
/* Clear the entire local FADT */
2007-02-02 19:48:20 +03:00
2007-02-02 19:48:20 +03:00
ACPI_MEMSET ( & acpi_gbl_FADT , 0 , sizeof ( struct acpi_table_fadt ) ) ;
2007-02-02 19:48:20 +03:00
2007-05-02 23:51:37 +04:00
/* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */
2007-02-02 19:48:20 +03:00
ACPI_MEMCPY ( & acpi_gbl_FADT , table ,
ACPI_MIN ( length , sizeof ( struct acpi_table_fadt ) ) ) ;
2011-11-16 06:57:28 +04:00
/* Take a copy of the Hardware Reduced flag */
acpi_gbl_reduced_hardware = FALSE ;
if ( acpi_gbl_FADT . flags & ACPI_FADT_HW_REDUCED ) {
acpi_gbl_reduced_hardware = TRUE ;
}
2009-02-18 09:06:12 +03:00
/* Convert the local copy of the FADT to the common internal format */
2007-02-02 19:48:20 +03:00
acpi_tb_convert_fadt ( ) ;
2009-02-18 09:06:12 +03:00
/* Validate FADT values now, before we make any changes */
acpi_tb_validate_fadt ( ) ;
/* Initialize the global ACPI register structures */
acpi_tb_setup_fadt_registers ( ) ;
2007-02-02 19:48:20 +03:00
}
/*******************************************************************************
*
* FUNCTION : acpi_tb_convert_fadt
*
* PARAMETERS : None , uses acpi_gbl_FADT
*
* RETURN : None
*
* DESCRIPTION : Converts all versions of the FADT to a common internal format .
2009-03-19 05:12:13 +03:00
* Expand 32 - bit addresses to 64 - bit as necessary .
2007-02-02 19:48:20 +03:00
*
2007-02-02 19:48:20 +03:00
* NOTE : acpi_gbl_FADT must be of size ( struct acpi_table_fadt ) ,
* and must contain a copy of the actual FADT .
2007-02-02 19:48:20 +03:00
*
2009-03-19 05:12:13 +03:00
* Notes on 64 - bit register addresses :
2007-02-02 19:48:20 +03:00
*
2009-03-19 05:12:13 +03:00
* After this FADT conversion , later ACPICA code will only use the 64 - bit " X "
* fields of the FADT for all ACPI register addresses .
2007-02-02 19:48:20 +03:00
*
2009-03-19 05:12:13 +03:00
* The 64 - bit " X " fields are optional extensions to the original 32 - bit FADT
* V1 .0 fields . Even if they are present in the FADT , they are optional and
* are unused if the BIOS sets them to zero . Therefore , we must copy / expand
* 32 - bit V1 .0 fields if the corresponding X field is zero .
2007-02-02 19:48:20 +03:00
*
2009-03-19 05:12:13 +03:00
* For ACPI 1.0 FADTs , all 32 - bit address fields are expanded to the
* corresponding " X " fields in the internal FADT .
*
* For ACPI 2.0 + FADTs , all valid ( non - zero ) 32 - bit address fields are expanded
* to the corresponding 64 - bit X fields . For compatibility with other ACPI
* implementations , we ignore the 64 - bit field if the 32 - bit field is valid ,
* regardless of whether the host OS is 32 - bit or 64 - bit .
2007-02-02 19:48:20 +03:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-02-02 19:48:20 +03:00
static void acpi_tb_convert_fadt ( void )
2007-02-02 19:48:20 +03:00
{
2009-03-19 05:12:13 +03:00
struct acpi_generic_address * address64 ;
u32 address32 ;
2008-06-10 09:42:13 +04:00
u32 i ;
2007-02-02 19:48:20 +03:00
2008-11-12 10:23:20 +03:00
/*
* Expand the 32 - bit FACS and DSDT addresses to 64 - bit as necessary .
* Later code will always use the X 64 - bit field . Also , check for an
* address mismatch between the 32 - bit and 64 - bit address fields
* ( FIRMWARE_CTRL / X_FIRMWARE_CTRL , DSDT / X_DSDT ) which would indicate
* the presence of two FACS or two DSDT tables .
*/
2007-02-02 19:48:20 +03:00
if ( ! acpi_gbl_FADT . Xfacs ) {
acpi_gbl_FADT . Xfacs = ( u64 ) acpi_gbl_FADT . facs ;
2008-11-12 10:23:20 +03:00
} else if ( acpi_gbl_FADT . facs & &
( acpi_gbl_FADT . Xfacs ! = ( u64 ) acpi_gbl_FADT . facs ) ) {
ACPI_WARNING ( ( AE_INFO ,
" 32/64 FACS address mismatch in FADT - two FACS tables! " ) ) ;
2007-02-02 19:48:20 +03:00
}
if ( ! acpi_gbl_FADT . Xdsdt ) {
acpi_gbl_FADT . Xdsdt = ( u64 ) acpi_gbl_FADT . dsdt ;
2008-11-12 10:23:20 +03:00
} else if ( acpi_gbl_FADT . dsdt & &
( acpi_gbl_FADT . Xdsdt ! = ( u64 ) acpi_gbl_FADT . dsdt ) ) {
ACPI_WARNING ( ( AE_INFO ,
" 32/64 DSDT address mismatch in FADT - two DSDT tables! " ) ) ;
2007-02-02 19:48:20 +03:00
}
/*
2007-05-02 23:51:37 +04:00
* For ACPI 1.0 FADTs ( revision 1 or 2 ) , ensure that reserved fields which
* should be zero are indeed zero . This will workaround BIOSs that
* inadvertently place values in these fields .
*
* The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
* offset 45 , 55 , 95 , and the word located at offset 109 , 110.
2011-02-14 10:50:42 +03:00
*
* Note : The FADT revision value is unreliable . Only the length can be
* trusted .
2007-05-02 23:51:37 +04:00
*/
2011-02-14 10:50:42 +03:00
if ( acpi_gbl_FADT . header . length < = ACPI_FADT_V2_SIZE ) {
2007-05-02 23:51:37 +04:00
acpi_gbl_FADT . preferred_profile = 0 ;
acpi_gbl_FADT . pstate_control = 0 ;
acpi_gbl_FADT . cst_control = 0 ;
acpi_gbl_FADT . boot_flags = 0 ;
}
2012-02-24 00:40:43 +04:00
/* Update the local FADT table header length */
acpi_gbl_FADT . header . length = sizeof ( struct acpi_table_fadt ) ;
2007-05-02 23:51:37 +04:00
/*
2008-12-31 08:07:26 +03:00
* Expand the ACPI 1.0 32 - bit addresses to the ACPI 2.0 64 - bit " X "
* generic address structures as necessary . Later code will always use
* the 64 - bit address structures .
2009-03-19 05:12:13 +03:00
*
* March 2009 :
* We now always use the 32 - bit address if it is valid ( non - null ) . This
* is not in accordance with the ACPI specification which states that
* the 64 - bit address supersedes the 32 - bit version , but we do this for
* compatibility with other ACPI implementations . Most notably , in the
* case where both the 32 and 64 versions are non - null , we use the 32 - bit
* version . This is the only address that is guaranteed to have been
* tested by the BIOS manufacturer .
2007-02-02 19:48:20 +03:00
*/
2007-02-02 19:48:20 +03:00
for ( i = 0 ; i < ACPI_FADT_INFO_ENTRIES ; i + + ) {
2009-03-19 05:12:13 +03:00
address32 = * ACPI_ADD_PTR ( u32 ,
& acpi_gbl_FADT ,
fadt_info_table [ i ] . address32 ) ;
2007-02-02 19:48:20 +03:00
2009-03-19 05:12:13 +03:00
address64 = ACPI_ADD_PTR ( struct acpi_generic_address ,
& acpi_gbl_FADT ,
fadt_info_table [ i ] . address64 ) ;
2007-02-02 19:48:20 +03:00
2009-03-19 05:12:13 +03:00
/*
* If both 32 - and 64 - bit addresses are valid ( non - zero ) ,
* they must match .
*/
if ( address64 - > address & & address32 & &
( address64 - > address ! = ( u64 ) address32 ) ) {
ACPI_ERROR ( ( AE_INFO ,
2010-03-05 12:56:40 +03:00
" 32/64X address mismatch in %s: 0x%8.8X/0x%8.8X%8.8X, using 32 " ,
2009-03-19 05:12:13 +03:00
fadt_info_table [ i ] . name , address32 ,
ACPI_FORMAT_UINT64 ( address64 - > address ) ) ) ;
}
2008-12-30 22:06:06 +03:00
2009-03-19 05:12:13 +03:00
/* Always use 32-bit address if it is valid (non-null) */
2008-12-30 22:06:06 +03:00
2009-03-19 05:12:13 +03:00
if ( address32 ) {
/*
* Copy the 32 - bit address to the 64 - bit GAS structure . The
* Space ID is always I / O for 32 - bit legacy address fields
*/
acpi_tb_init_generic_address ( address64 ,
2008-12-30 22:06:06 +03:00
ACPI_ADR_SPACE_SYSTEM_IO ,
2007-02-02 19:48:20 +03:00
* ACPI_ADD_PTR ( u8 ,
& acpi_gbl_FADT ,
2007-02-02 19:48:20 +03:00
fadt_info_table
2007-02-02 19:48:20 +03:00
[ i ] . length ) ,
2009-04-22 09:02:06 +04:00
( u64 ) address32 ) ;
2007-02-02 19:48:20 +03:00
}
}
}
2009-02-18 10:03:30 +03:00
/*******************************************************************************
2007-02-02 19:48:20 +03:00
*
* FUNCTION : acpi_tb_validate_fadt
*
2007-02-02 19:48:20 +03:00
* PARAMETERS : Table - Pointer to the FADT to be validated
2007-02-02 19:48:20 +03:00
*
2007-02-02 19:48:20 +03:00
* RETURN : None
2007-02-02 19:48:20 +03:00
*
2007-02-02 19:48:20 +03:00
* DESCRIPTION : Validate various important fields within the FADT . If a problem
* is found , issue a message , but no status is returned .
* Used by both the table manager and the disassembler .
*
* Possible additional checks :
* ( acpi_gbl_FADT . pm1_event_length > = 4 )
* ( acpi_gbl_FADT . pm1_control_length > = 2 )
* ( acpi_gbl_FADT . pm_timer_length > = 4 )
* Gpe block lengths must be multiple of 2
2007-02-02 19:48:20 +03:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-02-02 19:48:20 +03:00
static void acpi_tb_validate_fadt ( void )
2007-02-02 19:48:20 +03:00
{
2008-12-30 22:06:06 +03:00
char * name ;
2007-02-02 19:48:20 +03:00
struct acpi_generic_address * address64 ;
u8 length ;
2008-06-10 09:42:13 +04:00
u32 i ;
2007-02-02 19:48:20 +03:00
2008-12-30 22:06:06 +03:00
/*
* Check for FACS and DSDT address mismatches . An address mismatch between
* the 32 - bit and 64 - bit address fields ( FIRMWARE_CTRL / X_FIRMWARE_CTRL and
* DSDT / X_DSDT ) would indicate the presence of two FACS or two DSDT tables .
*/
if ( acpi_gbl_FADT . facs & &
( acpi_gbl_FADT . Xfacs ! = ( u64 ) acpi_gbl_FADT . facs ) ) {
ACPI_WARNING ( ( AE_INFO ,
2008-12-16 13:22:01 +03:00
" 32/64X FACS address mismatch in FADT - "
2010-03-05 12:56:40 +03:00
" 0x%8.8X/0x%8.8X%8.8X, using 32 " ,
2008-12-30 22:06:06 +03:00
acpi_gbl_FADT . facs ,
ACPI_FORMAT_UINT64 ( acpi_gbl_FADT . Xfacs ) ) ) ;
2009-03-19 05:13:40 +03:00
acpi_gbl_FADT . Xfacs = ( u64 ) acpi_gbl_FADT . facs ;
2008-12-30 22:06:06 +03:00
}
2007-02-02 19:48:20 +03:00
2008-12-30 22:06:06 +03:00
if ( acpi_gbl_FADT . dsdt & &
( acpi_gbl_FADT . Xdsdt ! = ( u64 ) acpi_gbl_FADT . dsdt ) ) {
ACPI_WARNING ( ( AE_INFO ,
2008-12-16 13:22:01 +03:00
" 32/64X DSDT address mismatch in FADT - "
2010-03-05 12:56:40 +03:00
" 0x%8.8X/0x%8.8X%8.8X, using 32 " ,
2008-12-30 22:06:06 +03:00
acpi_gbl_FADT . dsdt ,
ACPI_FORMAT_UINT64 ( acpi_gbl_FADT . Xdsdt ) ) ) ;
2009-03-19 05:13:40 +03:00
acpi_gbl_FADT . Xdsdt = ( u64 ) acpi_gbl_FADT . dsdt ;
2008-12-30 22:06:06 +03:00
}
2007-02-02 19:48:20 +03:00
2011-11-16 06:57:28 +04:00
/* If Hardware Reduced flag is set, we are all done */
if ( acpi_gbl_reduced_hardware ) {
return ;
}
2008-12-30 22:06:06 +03:00
/* Examine all of the 64-bit extended address fields (X fields) */
2007-02-02 19:48:20 +03:00
2008-12-30 22:06:06 +03:00
for ( i = 0 ; i < ACPI_FADT_INFO_ENTRIES ; i + + ) {
/*
2009-04-22 09:02:06 +04:00
* Generate pointer to the 64 - bit address , get the register
* length ( width ) and the register name
2008-12-30 22:06:06 +03:00
*/
address64 = ACPI_ADD_PTR ( struct acpi_generic_address ,
& acpi_gbl_FADT ,
2008-12-31 08:07:26 +03:00
fadt_info_table [ i ] . address64 ) ;
2007-02-02 19:48:20 +03:00
length =
* ACPI_ADD_PTR ( u8 , & acpi_gbl_FADT ,
fadt_info_table [ i ] . length ) ;
2008-12-30 22:06:06 +03:00
name = fadt_info_table [ i ] . name ;
/*
* For each extended field , check for length mismatch between the
2008-12-31 08:07:26 +03:00
* legacy length field and the corresponding 64 - bit X length field .
2008-12-30 22:06:06 +03:00
*/
2009-03-06 05:09:00 +03:00
if ( address64 - > address & &
( address64 - > bit_width ! = ACPI_MUL_8 ( length ) ) ) {
2008-12-30 22:06:06 +03:00
ACPI_WARNING ( ( AE_INFO ,
2010-03-05 12:56:40 +03:00
" 32/64X length mismatch in %s: %u/%u " ,
2008-12-30 22:06:06 +03:00
name , ACPI_MUL_8 ( length ) ,
address64 - > bit_width ) ) ;
}
2007-02-02 19:48:20 +03:00
if ( fadt_info_table [ i ] . type & ACPI_FADT_REQUIRED ) {
/*
* Field is required ( Pm1a_event , Pm1a_control , pm_timer ) .
* Both the address and length must be non - zero .
*/
if ( ! address64 - > address | | ! length ) {
ACPI_ERROR ( ( AE_INFO ,
2009-02-18 10:03:30 +03:00
" Required field %s has zero address and/or length: "
2010-03-05 12:56:40 +03:00
" 0x%8.8X%8.8X/0x%X " ,
2008-12-30 22:06:06 +03:00
name ,
2007-02-02 19:48:20 +03:00
ACPI_FORMAT_UINT64 ( address64 - >
address ) ,
length ) ) ;
}
} else if ( fadt_info_table [ i ] . type & ACPI_FADT_SEPARATE_LENGTH ) {
/*
* Field is optional ( PM2Control , GPE0 , GPE1 ) AND has its own
2009-02-18 10:03:30 +03:00
* length field . If present , both the address and length must
* be valid .
2007-02-02 19:48:20 +03:00
*/
2009-02-18 10:03:30 +03:00
if ( ( address64 - > address & & ! length ) | |
( ! address64 - > address & & length ) ) {
2007-02-02 19:48:20 +03:00
ACPI_WARNING ( ( AE_INFO ,
2009-02-18 10:03:30 +03:00
" Optional field %s has zero address or length: "
2010-03-05 12:56:40 +03:00
" 0x%8.8X%8.8X/0x%X " ,
2008-12-30 22:06:06 +03:00
name ,
2007-02-02 19:48:20 +03:00
ACPI_FORMAT_UINT64 ( address64 - >
address ) ,
length ) ) ;
}
}
2007-02-02 19:48:20 +03:00
}
}
2009-02-18 09:06:12 +03:00
2009-02-18 10:03:30 +03:00
/*******************************************************************************
2009-02-18 09:06:12 +03:00
*
* FUNCTION : acpi_tb_setup_fadt_registers
*
* PARAMETERS : None , uses acpi_gbl_FADT .
*
* RETURN : None
*
* DESCRIPTION : Initialize global ACPI PM1 register definitions . Optionally ,
* force FADT register definitions to their default lengths .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void acpi_tb_setup_fadt_registers ( void )
{
struct acpi_generic_address * target64 ;
struct acpi_generic_address * source64 ;
u8 pm1_register_byte_width ;
u32 i ;
/*
* Optionally check all register lengths against the default values and
* update them if they are incorrect .
*/
if ( acpi_gbl_use_default_register_widths ) {
for ( i = 0 ; i < ACPI_FADT_INFO_ENTRIES ; i + + ) {
target64 =
ACPI_ADD_PTR ( struct acpi_generic_address ,
& acpi_gbl_FADT ,
fadt_info_table [ i ] . address64 ) ;
/*
* If a valid register ( Address ! = 0 ) and the ( default_length > 0 )
* ( Not a GPE register ) , then check the width against the default .
*/
if ( ( target64 - > address ) & &
( fadt_info_table [ i ] . default_length > 0 ) & &
( fadt_info_table [ i ] . default_length ! =
target64 - > bit_width ) ) {
ACPI_WARNING ( ( AE_INFO ,
2010-03-05 12:56:40 +03:00
" Invalid length for %s: %u, using default %u " ,
2009-02-18 09:06:12 +03:00
fadt_info_table [ i ] . name ,
target64 - > bit_width ,
fadt_info_table [ i ] .
default_length ) ) ;
/* Incorrect size, set width to the default */
target64 - > bit_width =
fadt_info_table [ i ] . default_length ;
}
}
}
/*
* Get the length of the individual PM1 registers ( enable and status ) .
* Each register is defined to be ( event block length / 2 ) . Extra divide
* by 8 converts bits to bytes .
*/
2009-02-18 10:03:30 +03:00
pm1_register_byte_width = ( u8 )
ACPI_DIV_16 ( acpi_gbl_FADT . xpm1a_event_block . bit_width ) ;
2009-02-18 09:06:12 +03:00
/*
* Calculate separate GAS structs for the PM1x ( A / B ) Status and Enable
* registers . These addresses do not appear ( directly ) in the FADT , so it
* is useful to pre - calculate them from the PM1 Event Block definitions .
*
* The PM event blocks are split into two register blocks , first is the
* PM Status Register block , followed immediately by the PM Enable
* Register block . Each is of length ( pm1_event_length / 2 )
*
* Note : The PM1A event block is required by the ACPI specification .
* However , the PM1B event block is optional and is rarely , if ever ,
* used .
*/
for ( i = 0 ; i < ACPI_FADT_PM_INFO_ENTRIES ; i + + ) {
source64 =
ACPI_ADD_PTR ( struct acpi_generic_address , & acpi_gbl_FADT ,
fadt_pm_info_table [ i ] . source ) ;
2009-03-04 09:31:25 +03:00
if ( source64 - > address ) {
acpi_tb_init_generic_address ( fadt_pm_info_table [ i ] .
target , source64 - > space_id ,
pm1_register_byte_width ,
source64 - > address +
( fadt_pm_info_table [ i ] .
register_num *
pm1_register_byte_width ) ) ;
}
2009-02-18 09:06:12 +03:00
}
}