2008-01-30 15:30:05 +03:00
/*
* I / O delay strategies for inb_p / outb_p
2008-01-30 15:30:05 +03:00
*
* Allow for a DMI based override of port 0x80 , needed for certain HP laptops
* and possibly other systems . Also allow for the gradual elimination of
* outb_p / inb_p API uses .
2008-01-30 15:30:05 +03:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/delay.h>
2009-03-21 14:27:04 +03:00
# include <linux/init.h>
2008-01-30 15:30:05 +03:00
# include <linux/dmi.h>
2009-03-21 14:27:04 +03:00
# include <linux/io.h>
2008-01-30 15:30:05 +03:00
2008-01-30 15:30:05 +03:00
int io_delay_type __read_mostly = CONFIG_DEFAULT_IO_DELAY_TYPE ;
2008-01-30 15:30:05 +03:00
2008-01-30 15:30:05 +03:00
static int __initdata io_delay_override ;
2008-01-30 15:30:05 +03:00
/*
* Paravirt wants native_io_delay to be a constant .
*/
void native_io_delay ( void )
{
2008-01-30 15:30:05 +03:00
switch ( io_delay_type ) {
default :
case CONFIG_IO_DELAY_TYPE_0X80 :
asm volatile ( " outb %al, $0x80 " ) ;
break ;
case CONFIG_IO_DELAY_TYPE_0XED :
asm volatile ( " outb %al, $0xed " ) ;
break ;
case CONFIG_IO_DELAY_TYPE_UDELAY :
/*
* 2 usecs is an upper - bound for the outb delay but
* note that udelay doesn ' t have the bus - level
* side - effects that outb does , nor does udelay ( ) have
* precise timings during very early bootup ( the delays
* are shorter until calibrated ) :
*/
udelay ( 2 ) ;
case CONFIG_IO_DELAY_TYPE_NONE :
break ;
}
2008-01-30 15:30:05 +03:00
}
EXPORT_SYMBOL ( native_io_delay ) ;
2008-01-30 15:30:05 +03:00
static int __init dmi_io_delay_0xed_port ( const struct dmi_system_id * id )
2008-01-30 15:30:05 +03:00
{
2008-01-30 15:30:05 +03:00
if ( io_delay_type = = CONFIG_IO_DELAY_TYPE_0X80 ) {
2009-03-21 14:27:04 +03:00
pr_notice ( " %s: using 0xed I/O delay port \n " , id - > ident ) ;
2008-01-30 15:30:05 +03:00
io_delay_type = CONFIG_IO_DELAY_TYPE_0XED ;
}
2008-01-30 15:30:05 +03:00
return 0 ;
}
2008-01-30 15:30:05 +03:00
/*
* Quirk table for systems that misbehave ( lock up , etc . ) if port
* 0x80 is used :
*/
static struct dmi_system_id __initdata io_delay_0xed_port_dmi_table [ ] = {
2008-01-30 15:30:05 +03:00
{
. callback = dmi_io_delay_0xed_port ,
. ident = " Compaq Presario V6000 " ,
. matches = {
2009-03-21 14:27:04 +03:00
DMI_MATCH ( DMI_BOARD_VENDOR , " Quanta " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 30B7 " )
2008-01-30 15:30:05 +03:00
}
} ,
2008-01-30 15:30:05 +03:00
{
2008-01-30 15:30:05 +03:00
. callback = dmi_io_delay_0xed_port ,
2008-01-30 15:30:05 +03:00
. ident = " HP Pavilion dv9000z " ,
. matches = {
2009-03-21 14:27:04 +03:00
DMI_MATCH ( DMI_BOARD_VENDOR , " Quanta " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 30B9 " )
2008-01-30 15:30:05 +03:00
}
} ,
2008-03-21 12:06:32 +03:00
{
. callback = dmi_io_delay_0xed_port ,
. ident = " HP Pavilion dv6000 " ,
. matches = {
2009-03-21 14:27:04 +03:00
DMI_MATCH ( DMI_BOARD_VENDOR , " Quanta " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 30B8 " )
2008-03-21 12:06:32 +03:00
}
} ,
2008-01-30 15:30:05 +03:00
{
. callback = dmi_io_delay_0xed_port ,
. ident = " HP Pavilion tx1000 " ,
. matches = {
2009-03-21 14:27:04 +03:00
DMI_MATCH ( DMI_BOARD_VENDOR , " Quanta " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 30BF " )
2008-01-30 15:30:05 +03:00
}
} ,
2008-09-04 03:33:14 +04:00
{
. callback = dmi_io_delay_0xed_port ,
. ident = " Presario F700 " ,
. matches = {
2009-03-21 14:27:04 +03:00
DMI_MATCH ( DMI_BOARD_VENDOR , " Quanta " ) ,
DMI_MATCH ( DMI_BOARD_NAME , " 30D3 " )
2008-09-04 03:33:14 +04:00
}
} ,
2008-01-30 15:30:05 +03:00
{ }
2008-01-30 15:30:05 +03:00
} ;
void __init io_delay_init ( void )
{
if ( ! io_delay_override )
2008-01-30 15:30:05 +03:00
dmi_check_system ( io_delay_0xed_port_dmi_table ) ;
2008-01-30 15:30:05 +03:00
}
static int __init io_delay_param ( char * s )
{
2008-07-05 15:53:37 +04:00
if ( ! s )
return - EINVAL ;
2008-01-30 15:30:05 +03:00
if ( ! strcmp ( s , " 0x80 " ) )
io_delay_type = CONFIG_IO_DELAY_TYPE_0X80 ;
else if ( ! strcmp ( s , " 0xed " ) )
io_delay_type = CONFIG_IO_DELAY_TYPE_0XED ;
2008-01-30 15:30:05 +03:00
else if ( ! strcmp ( s , " udelay " ) )
2008-01-30 15:30:05 +03:00
io_delay_type = CONFIG_IO_DELAY_TYPE_UDELAY ;
else if ( ! strcmp ( s , " none " ) )
io_delay_type = CONFIG_IO_DELAY_TYPE_NONE ;
2008-01-30 15:30:05 +03:00
else
return - EINVAL ;
io_delay_override = 1 ;
return 0 ;
}
early_param ( " io_delay " , io_delay_param ) ;