2006-09-26 12:52:30 +04:00
/* Various workarounds for chipset bugs.
This code runs very early and can ' t use the regular PCI subsystem
The entries are keyed to PCI bridges which usually identify chipsets
uniquely .
This is only for whole classes of chipsets with specific problems which
need early invasive action ( e . g . before the timers are initialized ) .
Most PCI device specific workarounds can be done later and should be
in standard PCI quirks
Mainboard specific bugs should be handled by DMI entries .
CPU specific bugs in setup . c */
# include <linux/pci.h>
# include <linux/acpi.h>
# include <linux/pci_ids.h>
# include <asm/pci-direct.h>
# include <asm/dma.h>
2007-10-19 22:35:03 +04:00
# include <asm/io_apic.h>
# include <asm/apic.h>
2007-10-24 14:49:48 +04:00
# ifdef CONFIG_GART_IOMMU
2007-10-24 14:49:47 +04:00
# include <asm/gart.h>
2007-10-19 22:35:03 +04:00
# endif
2006-09-26 12:52:30 +04:00
2007-03-16 23:07:36 +03:00
static void __init via_bugs ( void )
2006-09-26 12:52:30 +04:00
{
2007-10-24 14:49:48 +04:00
# ifdef CONFIG_GART_IOMMU
2006-09-26 12:52:30 +04:00
if ( ( end_pfn > MAX_DMA32_PFN | | force_iommu ) & &
! iommu_aperture_allowed ) {
printk ( KERN_INFO
2007-10-19 22:35:03 +04:00
" Looks like a VIA chipset. Disabling IOMMU. "
" Override with iommu=allowed \n " ) ;
2006-09-26 12:52:30 +04:00
iommu_aperture_disabled = 1 ;
}
# endif
}
# ifdef CONFIG_ACPI
2007-10-27 22:57:43 +04:00
# ifdef CONFIG_X86_IO_APIC
2006-09-26 12:52:30 +04:00
2007-02-02 19:48:22 +03:00
static int __init nvidia_hpet_check ( struct acpi_table_header * header )
2006-09-26 12:52:30 +04:00
{
return 0 ;
}
2007-10-27 22:57:43 +04:00
# endif /* CONFIG_X86_IO_APIC */
# endif /* CONFIG_ACPI */
2006-09-26 12:52:30 +04:00
2007-03-16 23:07:36 +03:00
static void __init nvidia_bugs ( void )
2006-09-26 12:52:30 +04:00
{
# ifdef CONFIG_ACPI
2007-10-19 22:35:03 +04:00
# ifdef CONFIG_X86_IO_APIC
2006-09-26 12:52:30 +04:00
/*
* All timer overrides on Nvidia are
* wrong unless HPET is enabled .
2006-11-14 18:57:46 +03:00
* Unfortunately that ' s not true on many Asus boards .
* We don ' t know yet how to detect this automatically , but
* at least allow a command line override .
2006-09-26 12:52:30 +04:00
*/
2006-11-14 18:57:46 +03:00
if ( acpi_use_timer_override )
return ;
2007-03-09 02:28:32 +03:00
if ( acpi_table_parse ( ACPI_SIG_HPET , nvidia_hpet_check ) ) {
2006-09-26 12:52:30 +04:00
acpi_skip_timer_override = 1 ;
printk ( KERN_INFO " Nvidia board "
" detected. Ignoring ACPI "
" timer override. \n " ) ;
2006-11-14 18:57:46 +03:00
printk ( KERN_INFO " If you got timer trouble "
" try acpi_use_timer_override \n " ) ;
2006-09-26 12:52:30 +04:00
}
2007-10-19 22:35:03 +04:00
# endif
2006-09-26 12:52:30 +04:00
# endif
/* RED-PEN skip them on mptables too? */
}
2007-03-16 23:07:36 +03:00
static void __init ati_bugs ( void )
2006-09-26 12:52:30 +04:00
{
2007-10-19 22:35:03 +04:00
# ifdef CONFIG_X86_IO_APIC
2007-01-09 02:04:46 +03:00
if ( timer_over_8254 = = 1 ) {
timer_over_8254 = 0 ;
printk ( KERN_INFO
2007-10-19 22:35:03 +04:00
" ATI board detected. Disabling timer routing over 8254. \n " ) ;
2007-01-09 02:04:46 +03:00
}
2007-10-19 22:35:03 +04:00
# endif
2006-09-26 12:52:30 +04:00
}
struct chipset {
u16 vendor ;
void ( * f ) ( void ) ;
} ;
2007-04-09 03:04:03 +04:00
static struct chipset early_qrk [ ] __initdata = {
2006-09-26 12:52:30 +04:00
{ PCI_VENDOR_ID_NVIDIA , nvidia_bugs } ,
{ PCI_VENDOR_ID_VIA , via_bugs } ,
{ PCI_VENDOR_ID_ATI , ati_bugs } ,
{ }
} ;
void __init early_quirks ( void )
{
int num , slot , func ;
2006-09-26 12:52:41 +04:00
if ( ! early_pci_allowed ( ) )
return ;
2006-09-26 12:52:30 +04:00
/* Poor man's PCI discovery */
for ( num = 0 ; num < 32 ; num + + ) {
for ( slot = 0 ; slot < 32 ; slot + + ) {
for ( func = 0 ; func < 8 ; func + + ) {
u32 class ;
u32 vendor ;
u8 type ;
int i ;
class = read_pci_config ( num , slot , func ,
PCI_CLASS_REVISION ) ;
if ( class = = 0xffffffff )
break ;
2007-10-19 22:35:03 +04:00
if ( ( class > > 16 ) ! = PCI_CLASS_BRIDGE_PCI )
2006-09-26 12:52:30 +04:00
continue ;
vendor = read_pci_config ( num , slot , func ,
PCI_VENDOR_ID ) ;
vendor & = 0xffff ;
for ( i = 0 ; early_qrk [ i ] . f ; i + + )
if ( early_qrk [ i ] . vendor = = vendor ) {
early_qrk [ i ] . f ( ) ;
return ;
}
type = read_pci_config_byte ( num , slot , func ,
PCI_HEADER_TYPE ) ;
if ( ! ( type & 0x80 ) )
break ;
}
}
}
}