2005-04-17 02:20:36 +04:00
/*
* blacklist . c
*
* Check to see if the given machine has a known bad ACPI BIOS
* or if the BIOS is too old .
*
* Copyright ( C ) 2004 Len Brown < len . brown @ intel . com >
* Copyright ( C ) 2002 Andy Grover < andrew . grover @ intel . com >
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or ( at
* your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/acpi.h>
# include <acpi/acpi_bus.h>
# include <linux/dmi.h>
2005-08-05 08:44:28 +04:00
enum acpi_blacklist_predicates {
all_versions ,
less_than_or_equal ,
equal ,
greater_than_or_equal ,
2005-04-17 02:20:36 +04:00
} ;
2005-08-05 08:44:28 +04:00
struct acpi_blacklist_item {
char oem_id [ 7 ] ;
char oem_table_id [ 9 ] ;
u32 oem_revision ;
acpi_table_type table ;
enum acpi_blacklist_predicates oem_revision_predicate ;
char * reason ;
u32 is_critical_error ;
2005-04-17 02:20:36 +04:00
} ;
/*
* POLICY : If * anything * doesn ' t work , put it on the blacklist .
* If they are critical errors , mark it critical , and abort driver load .
*/
2005-08-05 08:44:28 +04:00
static struct acpi_blacklist_item acpi_blacklist [ ] __initdata = {
2005-04-17 02:20:36 +04:00
/* Compaq Presario 1700 */
2005-08-05 08:44:28 +04:00
{ " PTLTD " , " DSDT " , 0x06040000 , ACPI_DSDT , less_than_or_equal ,
" Multiple problems " , 1 } ,
2005-04-17 02:20:36 +04:00
/* Sony FX120, FX140, FX150? */
2005-08-05 08:44:28 +04:00
{ " SONY " , " U0 " , 0x20010313 , ACPI_DSDT , less_than_or_equal ,
" ACPI driver problem " , 1 } ,
2005-04-17 02:20:36 +04:00
/* Compaq Presario 800, Insyde BIOS */
2005-08-05 08:44:28 +04:00
{ " INT440 " , " SYSFexxx " , 0x00001001 , ACPI_DSDT , less_than_or_equal ,
" Does not use _REG to protect EC OpRegions " , 1 } ,
2005-04-17 02:20:36 +04:00
/* IBM 600E - _ADR should return 7, but it returns 1 */
2005-08-05 08:44:28 +04:00
{ " IBM " , " TP600E " , 0x00000105 , ACPI_DSDT , less_than_or_equal ,
" Incorrect _ADR " , 1 } ,
{ " ASUS \0 \0 " , " P2B-S " , 0 , ACPI_DSDT , all_versions ,
" Bogus PCI routing " , 1 } ,
2005-04-17 02:20:36 +04:00
{ " " }
} ;
# if CONFIG_ACPI_BLACKLIST_YEAR
2005-08-05 08:44:28 +04:00
static int __init blacklist_by_year ( void )
2005-04-17 02:20:36 +04:00
{
2006-03-25 18:30:19 +03:00
int year = dmi_get_year ( DMI_BIOS_DATE ) ;
/* Doesn't exist? Likely an old system */
if ( year = = - 1 )
return 1 ;
/* 0? Likely a buggy new BIOS */
if ( year = = 0 )
2005-04-17 02:20:36 +04:00
return 0 ;
if ( year < CONFIG_ACPI_BLACKLIST_YEAR ) {
2005-08-05 08:44:28 +04:00
printk ( KERN_ERR PREFIX " BIOS age (%d) fails cutoff (%d), "
" acpi=force is required to enable ACPI \n " ,
year , CONFIG_ACPI_BLACKLIST_YEAR ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
return 0 ;
}
# else
2005-08-05 08:44:28 +04:00
static inline int blacklist_by_year ( void )
{
return 0 ;
}
2005-04-17 02:20:36 +04:00
# endif
2005-08-05 08:44:28 +04:00
int __init acpi_blacklisted ( void )
2005-04-17 02:20:36 +04:00
{
int i = 0 ;
int blacklisted = 0 ;
struct acpi_table_header * table_header ;
2005-08-05 08:44:28 +04:00
while ( acpi_blacklist [ i ] . oem_id [ 0 ] ! = ' \0 ' ) {
if ( acpi_get_table_header_early
( acpi_blacklist [ i ] . table , & table_header ) ) {
2005-04-17 02:20:36 +04:00
i + + ;
continue ;
}
if ( strncmp ( acpi_blacklist [ i ] . oem_id , table_header - > oem_id , 6 ) ) {
i + + ;
continue ;
}
2005-08-05 08:44:28 +04:00
if ( strncmp
( acpi_blacklist [ i ] . oem_table_id , table_header - > oem_table_id ,
8 ) ) {
2005-04-17 02:20:36 +04:00
i + + ;
continue ;
}
if ( ( acpi_blacklist [ i ] . oem_revision_predicate = = all_versions )
2005-08-05 08:44:28 +04:00
| | ( acpi_blacklist [ i ] . oem_revision_predicate = =
less_than_or_equal
& & table_header - > oem_revision < =
acpi_blacklist [ i ] . oem_revision )
| | ( acpi_blacklist [ i ] . oem_revision_predicate = =
greater_than_or_equal
& & table_header - > oem_revision > =
acpi_blacklist [ i ] . oem_revision )
2005-04-17 02:20:36 +04:00
| | ( acpi_blacklist [ i ] . oem_revision_predicate = = equal
2005-08-05 08:44:28 +04:00
& & table_header - > oem_revision = =
acpi_blacklist [ i ] . oem_revision ) ) {
printk ( KERN_ERR PREFIX
" Vendor \" %6.6s \" System \" %8.8s \" "
" Revision 0x%x has a known ACPI BIOS problem. \n " ,
acpi_blacklist [ i ] . oem_id ,
acpi_blacklist [ i ] . oem_table_id ,
acpi_blacklist [ i ] . oem_revision ) ;
printk ( KERN_ERR PREFIX
" Reason: %s. This is a %s error \n " ,
acpi_blacklist [ i ] . reason ,
( acpi_blacklist [ i ] .
is_critical_error ? " non-recoverable " :
" recoverable " ) ) ;
2005-04-17 02:20:36 +04:00
blacklisted = acpi_blacklist [ i ] . is_critical_error ;
break ;
2005-08-05 08:44:28 +04:00
} else {
2005-04-17 02:20:36 +04:00
i + + ;
}
}
blacklisted + = blacklist_by_year ( ) ;
return blacklisted ;
}