| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Do early PCI probing for bug detection when the main PCI subsystem is | 
|  | 3 | * not up yet. | 
|  | 4 | */ | 
|  | 5 | #include <linux/init.h> | 
|  | 6 | #include <linux/kernel.h> | 
|  | 7 | #include <linux/pci.h> | 
| Andy Currid | d44647b | 2006-06-08 00:43:38 -0700 | [diff] [blame] | 8 | #include <linux/acpi.h> | 
|  | 9 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 10 | #include <asm/pci-direct.h> | 
|  | 11 | #include <asm/acpi.h> | 
| Andi Kleen | f9262c1 | 2006-03-08 17:57:25 -0800 | [diff] [blame] | 12 | #include <asm/apic.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 13 |  | 
| Andy Currid | d44647b | 2006-06-08 00:43:38 -0700 | [diff] [blame] | 14 | #ifdef CONFIG_ACPI | 
|  | 15 |  | 
| Alexey Starikovskiy | ceb6c46 | 2007-02-02 19:48:22 +0300 | [diff] [blame] | 16 | static int __init nvidia_hpet_check(struct acpi_table_header *header) | 
| Andy Currid | d44647b | 2006-06-08 00:43:38 -0700 | [diff] [blame] | 17 | { | 
| Andy Currid | d44647b | 2006-06-08 00:43:38 -0700 | [diff] [blame] | 18 | return 0; | 
|  | 19 | } | 
|  | 20 | #endif | 
|  | 21 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 22 | static int __init check_bridge(int vendor, int device) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 | { | 
| Andi Kleen | f9262c1 | 2006-03-08 17:57:25 -0800 | [diff] [blame] | 24 | #ifdef CONFIG_ACPI | 
| Zachary Amsden | afd3810 | 2007-04-25 15:32:23 -0400 | [diff] [blame] | 25 | static int warned; | 
| Andy Currid | d44647b | 2006-06-08 00:43:38 -0700 | [diff] [blame] | 26 | /* According to Nvidia all timer overrides are bogus unless HPET | 
|  | 27 | is enabled. */ | 
| Andi Kleen | fa18f47 | 2006-11-14 16:57:46 +0100 | [diff] [blame] | 28 | if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) { | 
| Thierry Vignaud | b2983f1 | 2007-04-25 15:31:30 -0400 | [diff] [blame] | 29 | if (!warned && acpi_table_parse(ACPI_SIG_HPET, | 
|  | 30 | nvidia_hpet_check)) { | 
|  | 31 | warned = 1; | 
| Andy Currid | d44647b | 2006-06-08 00:43:38 -0700 | [diff] [blame] | 32 | acpi_skip_timer_override = 1; | 
| Andi Kleen | fa18f47 | 2006-11-14 16:57:46 +0100 | [diff] [blame] | 33 | printk(KERN_INFO "Nvidia board " | 
|  | 34 | "detected. Ignoring ACPI " | 
|  | 35 | "timer override.\n"); | 
|  | 36 | printk(KERN_INFO "If you got timer trouble " | 
|  | 37 | "try acpi_use_timer_override\n"); | 
|  | 38 |  | 
| Andy Currid | d44647b | 2006-06-08 00:43:38 -0700 | [diff] [blame] | 39 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 40 | } | 
| Andi Kleen | f9262c1 | 2006-03-08 17:57:25 -0800 | [diff] [blame] | 41 | #endif | 
|  | 42 | if (vendor == PCI_VENDOR_ID_ATI && timer_over_8254 == 1) { | 
|  | 43 | timer_over_8254 = 0; | 
|  | 44 | printk(KERN_INFO "ATI board detected. Disabling timer routing " | 
|  | 45 | "over 8254.\n"); | 
|  | 46 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 47 | return 0; | 
|  | 48 | } | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 49 |  | 
|  | 50 | void __init check_acpi_pci(void) | 
|  | 51 | { | 
|  | 52 | int num, slot, func; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 53 |  | 
|  | 54 | /* Assume the machine supports type 1. If not it will | 
| Andi Kleen | 0637a70 | 2006-09-26 10:52:41 +0200 | [diff] [blame] | 55 | always read ffffffff and should not have any side effect. | 
|  | 56 | Actually a few buggy systems can machine check. Allow the user | 
|  | 57 | to disable it by command line option at least -AK */ | 
|  | 58 | if (!early_pci_allowed()) | 
|  | 59 | return; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 60 |  | 
|  | 61 | /* Poor man's PCI discovery */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 62 | for (num = 0; num < 32; num++) { | 
|  | 63 | for (slot = 0; slot < 32; slot++) { | 
|  | 64 | for (func = 0; func < 8; func++) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | u32 class; | 
|  | 66 | u32 vendor; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 67 | class = read_pci_config(num, slot, func, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 68 | PCI_CLASS_REVISION); | 
|  | 69 | if (class == 0xffffffff) | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 70 | break; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 71 |  | 
|  | 72 | if ((class >> 16) != PCI_CLASS_BRIDGE_PCI) | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 73 | continue; | 
|  | 74 |  | 
|  | 75 | vendor = read_pci_config(num, slot, func, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 76 | PCI_VENDOR_ID); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 77 |  | 
|  | 78 | if (check_bridge(vendor & 0xffff, vendor >> 16)) | 
|  | 79 | return; | 
|  | 80 | } | 
|  | 81 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 | } | 
|  | 83 | } | 
|  | 84 | } |