1fb9aa6f1SThomas Gleixner /* 2fb9aa6f1SThomas Gleixner * Low-Level PCI Support for PC 3fb9aa6f1SThomas Gleixner * 4fb9aa6f1SThomas Gleixner * (c) 1999--2000 Martin Mares <mj@ucw.cz> 5fb9aa6f1SThomas Gleixner */ 6fb9aa6f1SThomas Gleixner 7fb9aa6f1SThomas Gleixner #include <linux/sched.h> 8fb9aa6f1SThomas Gleixner #include <linux/pci.h> 9fb9aa6f1SThomas Gleixner #include <linux/ioport.h> 10fb9aa6f1SThomas Gleixner #include <linux/init.h> 11fb9aa6f1SThomas Gleixner #include <linux/dmi.h> 12fb9aa6f1SThomas Gleixner 13fb9aa6f1SThomas Gleixner #include <asm/acpi.h> 14fb9aa6f1SThomas Gleixner #include <asm/segment.h> 15fb9aa6f1SThomas Gleixner #include <asm/io.h> 16fb9aa6f1SThomas Gleixner #include <asm/smp.h> 17fb9aa6f1SThomas Gleixner 18fb9aa6f1SThomas Gleixner #include "pci.h" 19fb9aa6f1SThomas Gleixner 20fb9aa6f1SThomas Gleixner unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | 21fb9aa6f1SThomas Gleixner PCI_PROBE_MMCONF; 22fb9aa6f1SThomas Gleixner 23fb9aa6f1SThomas Gleixner static int pci_bf_sort; 24fb9aa6f1SThomas Gleixner int pci_routeirq; 25a9322f64SStefan Assmann int noioapicquirk; 26fb9aa6f1SThomas Gleixner int pcibios_last_bus = -1; 27fb9aa6f1SThomas Gleixner unsigned long pirq_table_addr; 28fb9aa6f1SThomas Gleixner struct pci_bus *pci_root_bus; 29fb9aa6f1SThomas Gleixner struct pci_raw_ops *raw_pci_ops; 30b6ce068aSMatthew Wilcox struct pci_raw_ops *raw_pci_ext_ops; 31b6ce068aSMatthew Wilcox 32b6ce068aSMatthew Wilcox int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, 33b6ce068aSMatthew Wilcox int reg, int len, u32 *val) 34b6ce068aSMatthew Wilcox { 35b6ce068aSMatthew Wilcox if (reg < 256 && raw_pci_ops) 36b6ce068aSMatthew Wilcox return raw_pci_ops->read(domain, bus, devfn, reg, len, val); 37b6ce068aSMatthew Wilcox if (raw_pci_ext_ops) 38b6ce068aSMatthew Wilcox return raw_pci_ext_ops->read(domain, bus, devfn, reg, len, val); 39b6ce068aSMatthew Wilcox return -EINVAL; 40b6ce068aSMatthew Wilcox } 41b6ce068aSMatthew Wilcox 42b6ce068aSMatthew Wilcox int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, 43b6ce068aSMatthew Wilcox int reg, int len, u32 val) 44b6ce068aSMatthew Wilcox { 45b6ce068aSMatthew Wilcox if (reg < 256 && raw_pci_ops) 46b6ce068aSMatthew Wilcox return raw_pci_ops->write(domain, bus, devfn, reg, len, val); 47b6ce068aSMatthew Wilcox if (raw_pci_ext_ops) 48b6ce068aSMatthew Wilcox return raw_pci_ext_ops->write(domain, bus, devfn, reg, len, val); 49b6ce068aSMatthew Wilcox return -EINVAL; 50b6ce068aSMatthew Wilcox } 51fb9aa6f1SThomas Gleixner 52fb9aa6f1SThomas Gleixner static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) 53fb9aa6f1SThomas Gleixner { 54b6ce068aSMatthew Wilcox return raw_pci_read(pci_domain_nr(bus), bus->number, 55a79e4198SJeff Garzik devfn, where, size, value); 56fb9aa6f1SThomas Gleixner } 57fb9aa6f1SThomas Gleixner 58fb9aa6f1SThomas Gleixner static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) 59fb9aa6f1SThomas Gleixner { 60b6ce068aSMatthew Wilcox return raw_pci_write(pci_domain_nr(bus), bus->number, 61a79e4198SJeff Garzik devfn, where, size, value); 62fb9aa6f1SThomas Gleixner } 63fb9aa6f1SThomas Gleixner 64fb9aa6f1SThomas Gleixner struct pci_ops pci_root_ops = { 65fb9aa6f1SThomas Gleixner .read = pci_read, 66fb9aa6f1SThomas Gleixner .write = pci_write, 67fb9aa6f1SThomas Gleixner }; 68fb9aa6f1SThomas Gleixner 69fb9aa6f1SThomas Gleixner /* 70fb9aa6f1SThomas Gleixner * legacy, numa, and acpi all want to call pcibios_scan_root 71fb9aa6f1SThomas Gleixner * from their initcalls. This flag prevents that. 72fb9aa6f1SThomas Gleixner */ 73fb9aa6f1SThomas Gleixner int pcibios_scanned; 74fb9aa6f1SThomas Gleixner 75fb9aa6f1SThomas Gleixner /* 76fb9aa6f1SThomas Gleixner * This interrupt-safe spinlock protects all accesses to PCI 77fb9aa6f1SThomas Gleixner * configuration space. 78fb9aa6f1SThomas Gleixner */ 79fb9aa6f1SThomas Gleixner DEFINE_SPINLOCK(pci_config_lock); 80fb9aa6f1SThomas Gleixner 8113a6ddb0SYinghai Lu static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d) 8213a6ddb0SYinghai Lu { 8313a6ddb0SYinghai Lu pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; 8413a6ddb0SYinghai Lu printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident); 8513a6ddb0SYinghai Lu return 0; 8613a6ddb0SYinghai Lu } 8713a6ddb0SYinghai Lu 8813a6ddb0SYinghai Lu static struct dmi_system_id can_skip_pciprobe_dmi_table[] __devinitdata = { 8913a6ddb0SYinghai Lu /* 9013a6ddb0SYinghai Lu * Systems where PCI IO resource ISA alignment can be skipped 9113a6ddb0SYinghai Lu * when the ISA enable bit in the bridge control is not set 9213a6ddb0SYinghai Lu */ 9313a6ddb0SYinghai Lu { 9413a6ddb0SYinghai Lu .callback = can_skip_ioresource_align, 9513a6ddb0SYinghai Lu .ident = "IBM System x3800", 9613a6ddb0SYinghai Lu .matches = { 9713a6ddb0SYinghai Lu DMI_MATCH(DMI_SYS_VENDOR, "IBM"), 9813a6ddb0SYinghai Lu DMI_MATCH(DMI_PRODUCT_NAME, "x3800"), 9913a6ddb0SYinghai Lu }, 10013a6ddb0SYinghai Lu }, 10113a6ddb0SYinghai Lu { 10213a6ddb0SYinghai Lu .callback = can_skip_ioresource_align, 10313a6ddb0SYinghai Lu .ident = "IBM System x3850", 10413a6ddb0SYinghai Lu .matches = { 10513a6ddb0SYinghai Lu DMI_MATCH(DMI_SYS_VENDOR, "IBM"), 10613a6ddb0SYinghai Lu DMI_MATCH(DMI_PRODUCT_NAME, "x3850"), 10713a6ddb0SYinghai Lu }, 10813a6ddb0SYinghai Lu }, 10913a6ddb0SYinghai Lu { 11013a6ddb0SYinghai Lu .callback = can_skip_ioresource_align, 11113a6ddb0SYinghai Lu .ident = "IBM System x3950", 11213a6ddb0SYinghai Lu .matches = { 11313a6ddb0SYinghai Lu DMI_MATCH(DMI_SYS_VENDOR, "IBM"), 11413a6ddb0SYinghai Lu DMI_MATCH(DMI_PRODUCT_NAME, "x3950"), 11513a6ddb0SYinghai Lu }, 11613a6ddb0SYinghai Lu }, 11713a6ddb0SYinghai Lu {} 11813a6ddb0SYinghai Lu }; 11913a6ddb0SYinghai Lu 12013a6ddb0SYinghai Lu void __init dmi_check_skip_isa_align(void) 12113a6ddb0SYinghai Lu { 12213a6ddb0SYinghai Lu dmi_check_system(can_skip_pciprobe_dmi_table); 12313a6ddb0SYinghai Lu } 12413a6ddb0SYinghai Lu 125fb9aa6f1SThomas Gleixner /* 126fb9aa6f1SThomas Gleixner * Called after each bus is probed, but before its children 127fb9aa6f1SThomas Gleixner * are examined. 128fb9aa6f1SThomas Gleixner */ 129fb9aa6f1SThomas Gleixner 130fb9aa6f1SThomas Gleixner void __devinit pcibios_fixup_bus(struct pci_bus *b) 131fb9aa6f1SThomas Gleixner { 132fb9aa6f1SThomas Gleixner pci_read_bridge_bases(b); 133fb9aa6f1SThomas Gleixner } 134fb9aa6f1SThomas Gleixner 135fb9aa6f1SThomas Gleixner /* 136fb9aa6f1SThomas Gleixner * Only use DMI information to set this if nothing was passed 137fb9aa6f1SThomas Gleixner * on the kernel command line (which was parsed earlier). 138fb9aa6f1SThomas Gleixner */ 139fb9aa6f1SThomas Gleixner 14019ad7ae4SLinus Torvalds static int __devinit set_bf_sort(const struct dmi_system_id *d) 141fb9aa6f1SThomas Gleixner { 142fb9aa6f1SThomas Gleixner if (pci_bf_sort == pci_bf_sort_default) { 143fb9aa6f1SThomas Gleixner pci_bf_sort = pci_dmi_bf; 144fb9aa6f1SThomas Gleixner printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); 145fb9aa6f1SThomas Gleixner } 146fb9aa6f1SThomas Gleixner return 0; 147fb9aa6f1SThomas Gleixner } 148fb9aa6f1SThomas Gleixner 149fb9aa6f1SThomas Gleixner /* 150fb9aa6f1SThomas Gleixner * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) 151fb9aa6f1SThomas Gleixner */ 152fb9aa6f1SThomas Gleixner #ifdef __i386__ 15319ad7ae4SLinus Torvalds static int __devinit assign_all_busses(const struct dmi_system_id *d) 154fb9aa6f1SThomas Gleixner { 155fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ALL_BUSSES; 156fb9aa6f1SThomas Gleixner printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" 157fb9aa6f1SThomas Gleixner " (pci=assign-busses)\n", d->ident); 158fb9aa6f1SThomas Gleixner return 0; 159fb9aa6f1SThomas Gleixner } 160fb9aa6f1SThomas Gleixner #endif 161fb9aa6f1SThomas Gleixner 162fb9aa6f1SThomas Gleixner static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { 163fb9aa6f1SThomas Gleixner #ifdef __i386__ 164fb9aa6f1SThomas Gleixner /* 165fb9aa6f1SThomas Gleixner * Laptops which need pci=assign-busses to see Cardbus cards 166fb9aa6f1SThomas Gleixner */ 167fb9aa6f1SThomas Gleixner { 168fb9aa6f1SThomas Gleixner .callback = assign_all_busses, 169fb9aa6f1SThomas Gleixner .ident = "Samsung X20 Laptop", 170fb9aa6f1SThomas Gleixner .matches = { 171fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), 172fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), 173fb9aa6f1SThomas Gleixner }, 174fb9aa6f1SThomas Gleixner }, 175fb9aa6f1SThomas Gleixner #endif /* __i386__ */ 176fb9aa6f1SThomas Gleixner { 177fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 178fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 1950", 179fb9aa6f1SThomas Gleixner .matches = { 180fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 181fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), 182fb9aa6f1SThomas Gleixner }, 183fb9aa6f1SThomas Gleixner }, 184fb9aa6f1SThomas Gleixner { 185fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 186fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 1955", 187fb9aa6f1SThomas Gleixner .matches = { 188fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 189fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), 190fb9aa6f1SThomas Gleixner }, 191fb9aa6f1SThomas Gleixner }, 192fb9aa6f1SThomas Gleixner { 193fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 194fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 2900", 195fb9aa6f1SThomas Gleixner .matches = { 196fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 197fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), 198fb9aa6f1SThomas Gleixner }, 199fb9aa6f1SThomas Gleixner }, 200fb9aa6f1SThomas Gleixner { 201fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 202fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 2950", 203fb9aa6f1SThomas Gleixner .matches = { 204fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 205fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), 206fb9aa6f1SThomas Gleixner }, 207fb9aa6f1SThomas Gleixner }, 208fb9aa6f1SThomas Gleixner { 209fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 210fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge R900", 211fb9aa6f1SThomas Gleixner .matches = { 212fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 213fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"), 214fb9aa6f1SThomas Gleixner }, 215fb9aa6f1SThomas Gleixner }, 216fb9aa6f1SThomas Gleixner { 217fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 218fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL20p G3", 219fb9aa6f1SThomas Gleixner .matches = { 220fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 221fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"), 222fb9aa6f1SThomas Gleixner }, 223fb9aa6f1SThomas Gleixner }, 224fb9aa6f1SThomas Gleixner { 225fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 226fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL20p G4", 227fb9aa6f1SThomas Gleixner .matches = { 228fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 229fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"), 230fb9aa6f1SThomas Gleixner }, 231fb9aa6f1SThomas Gleixner }, 232fb9aa6f1SThomas Gleixner { 233fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 234fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL30p G1", 235fb9aa6f1SThomas Gleixner .matches = { 236fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 237fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"), 238fb9aa6f1SThomas Gleixner }, 239fb9aa6f1SThomas Gleixner }, 240fb9aa6f1SThomas Gleixner { 241fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 242fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL25p G1", 243fb9aa6f1SThomas Gleixner .matches = { 244fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 245fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"), 246fb9aa6f1SThomas Gleixner }, 247fb9aa6f1SThomas Gleixner }, 248fb9aa6f1SThomas Gleixner { 249fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 250fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL35p G1", 251fb9aa6f1SThomas Gleixner .matches = { 252fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 253fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"), 254fb9aa6f1SThomas Gleixner }, 255fb9aa6f1SThomas Gleixner }, 256fb9aa6f1SThomas Gleixner { 257fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 258fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL45p G1", 259fb9aa6f1SThomas Gleixner .matches = { 260fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 261fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"), 262fb9aa6f1SThomas Gleixner }, 263fb9aa6f1SThomas Gleixner }, 264fb9aa6f1SThomas Gleixner { 265fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 266fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL45p G2", 267fb9aa6f1SThomas Gleixner .matches = { 268fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 269fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"), 270fb9aa6f1SThomas Gleixner }, 271fb9aa6f1SThomas Gleixner }, 272fb9aa6f1SThomas Gleixner { 273fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 274fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL460c G1", 275fb9aa6f1SThomas Gleixner .matches = { 276fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 277fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"), 278fb9aa6f1SThomas Gleixner }, 279fb9aa6f1SThomas Gleixner }, 280fb9aa6f1SThomas Gleixner { 281fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 282fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL465c G1", 283fb9aa6f1SThomas Gleixner .matches = { 284fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 285fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"), 286fb9aa6f1SThomas Gleixner }, 287fb9aa6f1SThomas Gleixner }, 288fb9aa6f1SThomas Gleixner { 289fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 290fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL480c G1", 291fb9aa6f1SThomas Gleixner .matches = { 292fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 293fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"), 294fb9aa6f1SThomas Gleixner }, 295fb9aa6f1SThomas Gleixner }, 296fb9aa6f1SThomas Gleixner { 297fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 298fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL685c G1", 299fb9aa6f1SThomas Gleixner .matches = { 300fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 301fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), 302fb9aa6f1SThomas Gleixner }, 303fb9aa6f1SThomas Gleixner }, 3048f8ae1a7SMichal Schmidt { 3058f8ae1a7SMichal Schmidt .callback = set_bf_sort, 3068d64c781STony Camuso .ident = "HP ProLiant DL360", 3078f8ae1a7SMichal Schmidt .matches = { 3088f8ae1a7SMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 3098d64c781STony Camuso DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL360"), 3108f8ae1a7SMichal Schmidt }, 3118f8ae1a7SMichal Schmidt }, 3128f8ae1a7SMichal Schmidt { 3138f8ae1a7SMichal Schmidt .callback = set_bf_sort, 3148d64c781STony Camuso .ident = "HP ProLiant DL380", 3158f8ae1a7SMichal Schmidt .matches = { 3168f8ae1a7SMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 3178d64c781STony Camuso DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL380"), 3188f8ae1a7SMichal Schmidt }, 3198f8ae1a7SMichal Schmidt }, 3205b1ea82fSJuha Laiho #ifdef __i386__ 3215b1ea82fSJuha Laiho { 3225b1ea82fSJuha Laiho .callback = assign_all_busses, 3235b1ea82fSJuha Laiho .ident = "Compaq EVO N800c", 3245b1ea82fSJuha Laiho .matches = { 3255b1ea82fSJuha Laiho DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), 3265b1ea82fSJuha Laiho DMI_MATCH(DMI_PRODUCT_NAME, "EVO N800c"), 3275b1ea82fSJuha Laiho }, 3285b1ea82fSJuha Laiho }, 3295b1ea82fSJuha Laiho #endif 330c82bc5adSMichal Schmidt { 331c82bc5adSMichal Schmidt .callback = set_bf_sort, 332a1676072STony Camuso .ident = "HP ProLiant DL360", 333c82bc5adSMichal Schmidt .matches = { 334c82bc5adSMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 335a1676072STony Camuso DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL360"), 336c82bc5adSMichal Schmidt }, 337c82bc5adSMichal Schmidt }, 338c82bc5adSMichal Schmidt { 339c82bc5adSMichal Schmidt .callback = set_bf_sort, 340a1676072STony Camuso .ident = "HP ProLiant DL380", 341c82bc5adSMichal Schmidt .matches = { 342c82bc5adSMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 343a1676072STony Camuso DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL380"), 344c82bc5adSMichal Schmidt }, 345c82bc5adSMichal Schmidt }, 346fb9aa6f1SThomas Gleixner {} 347fb9aa6f1SThomas Gleixner }; 348fb9aa6f1SThomas Gleixner 3490df18ff3SYinghai Lu void __init dmi_check_pciprobe(void) 3500df18ff3SYinghai Lu { 3510df18ff3SYinghai Lu dmi_check_system(pciprobe_dmi_table); 3520df18ff3SYinghai Lu } 3530df18ff3SYinghai Lu 354fb9aa6f1SThomas Gleixner struct pci_bus * __devinit pcibios_scan_root(int busnum) 355fb9aa6f1SThomas Gleixner { 356fb9aa6f1SThomas Gleixner struct pci_bus *bus = NULL; 357fb9aa6f1SThomas Gleixner struct pci_sysdata *sd; 358fb9aa6f1SThomas Gleixner 359fb9aa6f1SThomas Gleixner while ((bus = pci_find_next_bus(bus)) != NULL) { 360fb9aa6f1SThomas Gleixner if (bus->number == busnum) { 361fb9aa6f1SThomas Gleixner /* Already scanned */ 362fb9aa6f1SThomas Gleixner return bus; 363fb9aa6f1SThomas Gleixner } 364fb9aa6f1SThomas Gleixner } 365fb9aa6f1SThomas Gleixner 366fb9aa6f1SThomas Gleixner /* Allocate per-root-bus (not per bus) arch-specific data. 367fb9aa6f1SThomas Gleixner * TODO: leak; this memory is never freed. 368fb9aa6f1SThomas Gleixner * It's arguable whether it's worth the trouble to care. 369fb9aa6f1SThomas Gleixner */ 370fb9aa6f1SThomas Gleixner sd = kzalloc(sizeof(*sd), GFP_KERNEL); 371fb9aa6f1SThomas Gleixner if (!sd) { 372fb9aa6f1SThomas Gleixner printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); 373fb9aa6f1SThomas Gleixner return NULL; 374fb9aa6f1SThomas Gleixner } 375fb9aa6f1SThomas Gleixner 376871d5f8dSYinghai Lu sd->node = get_mp_bus_to_node(busnum); 377fb9aa6f1SThomas Gleixner 378871d5f8dSYinghai Lu printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); 379871d5f8dSYinghai Lu bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); 380871d5f8dSYinghai Lu if (!bus) 381871d5f8dSYinghai Lu kfree(sd); 382871d5f8dSYinghai Lu 383871d5f8dSYinghai Lu return bus; 384fb9aa6f1SThomas Gleixner } 385fb9aa6f1SThomas Gleixner 386fb9aa6f1SThomas Gleixner extern u8 pci_cache_line_size; 387fb9aa6f1SThomas Gleixner 388fb9aa6f1SThomas Gleixner static int __init pcibios_init(void) 389fb9aa6f1SThomas Gleixner { 390fb9aa6f1SThomas Gleixner struct cpuinfo_x86 *c = &boot_cpu_data; 391fb9aa6f1SThomas Gleixner 392fb9aa6f1SThomas Gleixner if (!raw_pci_ops) { 393fb9aa6f1SThomas Gleixner printk(KERN_WARNING "PCI: System does not support PCI\n"); 394fb9aa6f1SThomas Gleixner return 0; 395fb9aa6f1SThomas Gleixner } 396fb9aa6f1SThomas Gleixner 397fb9aa6f1SThomas Gleixner /* 398fb9aa6f1SThomas Gleixner * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8 399fb9aa6f1SThomas Gleixner * and P4. It's also good for 386/486s (which actually have 16) 400fb9aa6f1SThomas Gleixner * as quite a few PCI devices do not support smaller values. 401fb9aa6f1SThomas Gleixner */ 402fb9aa6f1SThomas Gleixner pci_cache_line_size = 32 >> 2; 403fb9aa6f1SThomas Gleixner if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) 404fb9aa6f1SThomas Gleixner pci_cache_line_size = 64 >> 2; /* K7 & K8 */ 405fb9aa6f1SThomas Gleixner else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) 406fb9aa6f1SThomas Gleixner pci_cache_line_size = 128 >> 2; /* P4 */ 407fb9aa6f1SThomas Gleixner 408fb9aa6f1SThomas Gleixner pcibios_resource_survey(); 409fb9aa6f1SThomas Gleixner 410fb9aa6f1SThomas Gleixner if (pci_bf_sort >= pci_force_bf) 411fb9aa6f1SThomas Gleixner pci_sort_breadthfirst(); 412fb9aa6f1SThomas Gleixner return 0; 413fb9aa6f1SThomas Gleixner } 414fb9aa6f1SThomas Gleixner 415fb9aa6f1SThomas Gleixner subsys_initcall(pcibios_init); 416fb9aa6f1SThomas Gleixner 417fb9aa6f1SThomas Gleixner char * __devinit pcibios_setup(char *str) 418fb9aa6f1SThomas Gleixner { 419fb9aa6f1SThomas Gleixner if (!strcmp(str, "off")) { 420fb9aa6f1SThomas Gleixner pci_probe = 0; 421fb9aa6f1SThomas Gleixner return NULL; 422fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "bfsort")) { 423fb9aa6f1SThomas Gleixner pci_bf_sort = pci_force_bf; 424fb9aa6f1SThomas Gleixner return NULL; 425fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "nobfsort")) { 426fb9aa6f1SThomas Gleixner pci_bf_sort = pci_force_nobf; 427fb9aa6f1SThomas Gleixner return NULL; 428fb9aa6f1SThomas Gleixner } 429fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_BIOS 430fb9aa6f1SThomas Gleixner else if (!strcmp(str, "bios")) { 431fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_BIOS; 432fb9aa6f1SThomas Gleixner return NULL; 433fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "nobios")) { 434fb9aa6f1SThomas Gleixner pci_probe &= ~PCI_PROBE_BIOS; 435fb9aa6f1SThomas Gleixner return NULL; 436fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "biosirq")) { 437fb9aa6f1SThomas Gleixner pci_probe |= PCI_BIOS_IRQ_SCAN; 438fb9aa6f1SThomas Gleixner return NULL; 439fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "pirqaddr=", 9)) { 440fb9aa6f1SThomas Gleixner pirq_table_addr = simple_strtoul(str+9, NULL, 0); 441fb9aa6f1SThomas Gleixner return NULL; 442fb9aa6f1SThomas Gleixner } 443fb9aa6f1SThomas Gleixner #endif 444fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_DIRECT 445fb9aa6f1SThomas Gleixner else if (!strcmp(str, "conf1")) { 446fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS; 447fb9aa6f1SThomas Gleixner return NULL; 448fb9aa6f1SThomas Gleixner } 449fb9aa6f1SThomas Gleixner else if (!strcmp(str, "conf2")) { 450fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS; 451fb9aa6f1SThomas Gleixner return NULL; 452fb9aa6f1SThomas Gleixner } 453fb9aa6f1SThomas Gleixner #endif 454fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_MMCONFIG 455fb9aa6f1SThomas Gleixner else if (!strcmp(str, "nommconf")) { 456fb9aa6f1SThomas Gleixner pci_probe &= ~PCI_PROBE_MMCONF; 457fb9aa6f1SThomas Gleixner return NULL; 458fb9aa6f1SThomas Gleixner } 4595f0b2976SYinghai Lu else if (!strcmp(str, "check_enable_amd_mmconf")) { 4605f0b2976SYinghai Lu pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF; 4615f0b2976SYinghai Lu return NULL; 4625f0b2976SYinghai Lu } 463fb9aa6f1SThomas Gleixner #endif 464fb9aa6f1SThomas Gleixner else if (!strcmp(str, "noacpi")) { 465fb9aa6f1SThomas Gleixner acpi_noirq_set(); 466fb9aa6f1SThomas Gleixner return NULL; 467fb9aa6f1SThomas Gleixner } 468fb9aa6f1SThomas Gleixner else if (!strcmp(str, "noearly")) { 469fb9aa6f1SThomas Gleixner pci_probe |= PCI_PROBE_NOEARLY; 470fb9aa6f1SThomas Gleixner return NULL; 471fb9aa6f1SThomas Gleixner } 472fb9aa6f1SThomas Gleixner #ifndef CONFIG_X86_VISWS 473fb9aa6f1SThomas Gleixner else if (!strcmp(str, "usepirqmask")) { 474fb9aa6f1SThomas Gleixner pci_probe |= PCI_USE_PIRQ_MASK; 475fb9aa6f1SThomas Gleixner return NULL; 476fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "irqmask=", 8)) { 477fb9aa6f1SThomas Gleixner pcibios_irq_mask = simple_strtol(str+8, NULL, 0); 478fb9aa6f1SThomas Gleixner return NULL; 479fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "lastbus=", 8)) { 480fb9aa6f1SThomas Gleixner pcibios_last_bus = simple_strtol(str+8, NULL, 0); 481fb9aa6f1SThomas Gleixner return NULL; 482fb9aa6f1SThomas Gleixner } 483fb9aa6f1SThomas Gleixner #endif 484fb9aa6f1SThomas Gleixner else if (!strcmp(str, "rom")) { 485fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ROMS; 486fb9aa6f1SThomas Gleixner return NULL; 487fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "assign-busses")) { 488fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ALL_BUSSES; 489fb9aa6f1SThomas Gleixner return NULL; 49062f420f8SGary Hade } else if (!strcmp(str, "use_crs")) { 49162f420f8SGary Hade pci_probe |= PCI_USE__CRS; 49262f420f8SGary Hade return NULL; 493fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "routeirq")) { 494fb9aa6f1SThomas Gleixner pci_routeirq = 1; 495fb9aa6f1SThomas Gleixner return NULL; 49613a6ddb0SYinghai Lu } else if (!strcmp(str, "skip_isa_align")) { 49713a6ddb0SYinghai Lu pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; 49813a6ddb0SYinghai Lu return NULL; 499a9322f64SStefan Assmann } else if (!strcmp(str, "noioapicquirk")) { 500a9322f64SStefan Assmann noioapicquirk = 1; 501a9322f64SStefan Assmann return NULL; 502fb9aa6f1SThomas Gleixner } 503fb9aa6f1SThomas Gleixner return str; 504fb9aa6f1SThomas Gleixner } 505fb9aa6f1SThomas Gleixner 506fb9aa6f1SThomas Gleixner unsigned int pcibios_assign_all_busses(void) 507fb9aa6f1SThomas Gleixner { 508fb9aa6f1SThomas Gleixner return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; 509fb9aa6f1SThomas Gleixner } 510fb9aa6f1SThomas Gleixner 511fb9aa6f1SThomas Gleixner int pcibios_enable_device(struct pci_dev *dev, int mask) 512fb9aa6f1SThomas Gleixner { 513fb9aa6f1SThomas Gleixner int err; 514fb9aa6f1SThomas Gleixner 515b81d988cSBjorn Helgaas if ((err = pci_enable_resources(dev, mask)) < 0) 516fb9aa6f1SThomas Gleixner return err; 517fb9aa6f1SThomas Gleixner 518fb9aa6f1SThomas Gleixner if (!dev->msi_enabled) 519fb9aa6f1SThomas Gleixner return pcibios_enable_irq(dev); 520fb9aa6f1SThomas Gleixner return 0; 521fb9aa6f1SThomas Gleixner } 522fb9aa6f1SThomas Gleixner 523fb9aa6f1SThomas Gleixner void pcibios_disable_device (struct pci_dev *dev) 524fb9aa6f1SThomas Gleixner { 525fb9aa6f1SThomas Gleixner if (!dev->msi_enabled && pcibios_disable_irq) 526fb9aa6f1SThomas Gleixner pcibios_disable_irq(dev); 527fb9aa6f1SThomas Gleixner } 528fb9aa6f1SThomas Gleixner 52998db6f19SSam Ravnborg struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) 530fb9aa6f1SThomas Gleixner { 531fb9aa6f1SThomas Gleixner struct pci_bus *bus = NULL; 532fb9aa6f1SThomas Gleixner struct pci_sysdata *sd; 533fb9aa6f1SThomas Gleixner 534fb9aa6f1SThomas Gleixner /* 535fb9aa6f1SThomas Gleixner * Allocate per-root-bus (not per bus) arch-specific data. 536fb9aa6f1SThomas Gleixner * TODO: leak; this memory is never freed. 537fb9aa6f1SThomas Gleixner * It's arguable whether it's worth the trouble to care. 538fb9aa6f1SThomas Gleixner */ 539fb9aa6f1SThomas Gleixner sd = kzalloc(sizeof(*sd), GFP_KERNEL); 540fb9aa6f1SThomas Gleixner if (!sd) { 541fb9aa6f1SThomas Gleixner printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); 542fb9aa6f1SThomas Gleixner return NULL; 543fb9aa6f1SThomas Gleixner } 544871d5f8dSYinghai Lu sd->node = node; 545871d5f8dSYinghai Lu bus = pci_scan_bus(busno, ops, sd); 546fb9aa6f1SThomas Gleixner if (!bus) 547fb9aa6f1SThomas Gleixner kfree(sd); 548fb9aa6f1SThomas Gleixner 549fb9aa6f1SThomas Gleixner return bus; 550fb9aa6f1SThomas Gleixner } 551871d5f8dSYinghai Lu 55298db6f19SSam Ravnborg struct pci_bus * __devinit pci_scan_bus_with_sysdata(int busno) 553871d5f8dSYinghai Lu { 554871d5f8dSYinghai Lu return pci_scan_bus_on_node(busno, &pci_root_ops, -1); 555871d5f8dSYinghai Lu } 556