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> 1782487711SJaswinder Singh Rajput #include <asm/pci_x86.h> 18fb9aa6f1SThomas Gleixner 19fb9aa6f1SThomas Gleixner unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | 20fb9aa6f1SThomas Gleixner PCI_PROBE_MMCONF; 21fb9aa6f1SThomas Gleixner 22e3f2baebSYinghai Lu unsigned int pci_early_dump_regs; 23fb9aa6f1SThomas Gleixner static int pci_bf_sort; 24fb9aa6f1SThomas Gleixner int pci_routeirq; 25a9322f64SStefan Assmann int noioapicquirk; 2641b9eb26SStefan Assmann #ifdef CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS 2741b9eb26SStefan Assmann int noioapicreroute = 0; 2841b9eb26SStefan Assmann #else 299197979bSStefan Assmann int noioapicreroute = 1; 3041b9eb26SStefan Assmann #endif 31fb9aa6f1SThomas Gleixner int pcibios_last_bus = -1; 32fb9aa6f1SThomas Gleixner unsigned long pirq_table_addr; 33fb9aa6f1SThomas Gleixner struct pci_bus *pci_root_bus; 34fb9aa6f1SThomas Gleixner struct pci_raw_ops *raw_pci_ops; 35b6ce068aSMatthew Wilcox struct pci_raw_ops *raw_pci_ext_ops; 36b6ce068aSMatthew Wilcox 37b6ce068aSMatthew Wilcox int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, 38b6ce068aSMatthew Wilcox int reg, int len, u32 *val) 39b6ce068aSMatthew Wilcox { 40beef3129SMatthew Wilcox if (domain == 0 && reg < 256 && raw_pci_ops) 41b6ce068aSMatthew Wilcox return raw_pci_ops->read(domain, bus, devfn, reg, len, val); 42b6ce068aSMatthew Wilcox if (raw_pci_ext_ops) 43b6ce068aSMatthew Wilcox return raw_pci_ext_ops->read(domain, bus, devfn, reg, len, val); 44b6ce068aSMatthew Wilcox return -EINVAL; 45b6ce068aSMatthew Wilcox } 46b6ce068aSMatthew Wilcox 47b6ce068aSMatthew Wilcox int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, 48b6ce068aSMatthew Wilcox int reg, int len, u32 val) 49b6ce068aSMatthew Wilcox { 50beef3129SMatthew Wilcox if (domain == 0 && reg < 256 && raw_pci_ops) 51b6ce068aSMatthew Wilcox return raw_pci_ops->write(domain, bus, devfn, reg, len, val); 52b6ce068aSMatthew Wilcox if (raw_pci_ext_ops) 53b6ce068aSMatthew Wilcox return raw_pci_ext_ops->write(domain, bus, devfn, reg, len, val); 54b6ce068aSMatthew Wilcox return -EINVAL; 55b6ce068aSMatthew Wilcox } 56fb9aa6f1SThomas Gleixner 57fb9aa6f1SThomas Gleixner static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) 58fb9aa6f1SThomas Gleixner { 59b6ce068aSMatthew Wilcox return raw_pci_read(pci_domain_nr(bus), bus->number, 60a79e4198SJeff Garzik devfn, where, size, value); 61fb9aa6f1SThomas Gleixner } 62fb9aa6f1SThomas Gleixner 63fb9aa6f1SThomas Gleixner static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) 64fb9aa6f1SThomas Gleixner { 65b6ce068aSMatthew Wilcox return raw_pci_write(pci_domain_nr(bus), bus->number, 66a79e4198SJeff Garzik devfn, where, size, value); 67fb9aa6f1SThomas Gleixner } 68fb9aa6f1SThomas Gleixner 69fb9aa6f1SThomas Gleixner struct pci_ops pci_root_ops = { 70fb9aa6f1SThomas Gleixner .read = pci_read, 71fb9aa6f1SThomas Gleixner .write = pci_write, 72fb9aa6f1SThomas Gleixner }; 73fb9aa6f1SThomas Gleixner 74fb9aa6f1SThomas Gleixner /* 75fb9aa6f1SThomas Gleixner * legacy, numa, and acpi all want to call pcibios_scan_root 76fb9aa6f1SThomas Gleixner * from their initcalls. This flag prevents that. 77fb9aa6f1SThomas Gleixner */ 78fb9aa6f1SThomas Gleixner int pcibios_scanned; 79fb9aa6f1SThomas Gleixner 80fb9aa6f1SThomas Gleixner /* 81fb9aa6f1SThomas Gleixner * This interrupt-safe spinlock protects all accesses to PCI 82fb9aa6f1SThomas Gleixner * configuration space. 83fb9aa6f1SThomas Gleixner */ 84fb9aa6f1SThomas Gleixner DEFINE_SPINLOCK(pci_config_lock); 85fb9aa6f1SThomas Gleixner 8613a6ddb0SYinghai Lu static int __devinit can_skip_ioresource_align(const struct dmi_system_id *d) 8713a6ddb0SYinghai Lu { 8813a6ddb0SYinghai Lu pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; 8913a6ddb0SYinghai Lu printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident); 9013a6ddb0SYinghai Lu return 0; 9113a6ddb0SYinghai Lu } 9213a6ddb0SYinghai Lu 93821508d4SJan Beulich static const struct dmi_system_id can_skip_pciprobe_dmi_table[] __devinitconst = { 9413a6ddb0SYinghai Lu /* 9513a6ddb0SYinghai Lu * Systems where PCI IO resource ISA alignment can be skipped 9613a6ddb0SYinghai Lu * when the ISA enable bit in the bridge control is not set 9713a6ddb0SYinghai Lu */ 9813a6ddb0SYinghai Lu { 9913a6ddb0SYinghai Lu .callback = can_skip_ioresource_align, 10013a6ddb0SYinghai Lu .ident = "IBM System x3800", 10113a6ddb0SYinghai Lu .matches = { 10213a6ddb0SYinghai Lu DMI_MATCH(DMI_SYS_VENDOR, "IBM"), 10313a6ddb0SYinghai Lu DMI_MATCH(DMI_PRODUCT_NAME, "x3800"), 10413a6ddb0SYinghai Lu }, 10513a6ddb0SYinghai Lu }, 10613a6ddb0SYinghai Lu { 10713a6ddb0SYinghai Lu .callback = can_skip_ioresource_align, 10813a6ddb0SYinghai Lu .ident = "IBM System x3850", 10913a6ddb0SYinghai Lu .matches = { 11013a6ddb0SYinghai Lu DMI_MATCH(DMI_SYS_VENDOR, "IBM"), 11113a6ddb0SYinghai Lu DMI_MATCH(DMI_PRODUCT_NAME, "x3850"), 11213a6ddb0SYinghai Lu }, 11313a6ddb0SYinghai Lu }, 11413a6ddb0SYinghai Lu { 11513a6ddb0SYinghai Lu .callback = can_skip_ioresource_align, 11613a6ddb0SYinghai Lu .ident = "IBM System x3950", 11713a6ddb0SYinghai Lu .matches = { 11813a6ddb0SYinghai Lu DMI_MATCH(DMI_SYS_VENDOR, "IBM"), 11913a6ddb0SYinghai Lu DMI_MATCH(DMI_PRODUCT_NAME, "x3950"), 12013a6ddb0SYinghai Lu }, 12113a6ddb0SYinghai Lu }, 12213a6ddb0SYinghai Lu {} 12313a6ddb0SYinghai Lu }; 12413a6ddb0SYinghai Lu 12513a6ddb0SYinghai Lu void __init dmi_check_skip_isa_align(void) 12613a6ddb0SYinghai Lu { 12713a6ddb0SYinghai Lu dmi_check_system(can_skip_pciprobe_dmi_table); 12813a6ddb0SYinghai Lu } 12913a6ddb0SYinghai Lu 130bb71ad88SGary Hade static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) 131bb71ad88SGary Hade { 132bb71ad88SGary Hade struct resource *rom_r = &dev->resource[PCI_ROM_RESOURCE]; 133bb71ad88SGary Hade 134bb71ad88SGary Hade if (pci_probe & PCI_NOASSIGN_ROMS) { 135bb71ad88SGary Hade if (rom_r->parent) 136bb71ad88SGary Hade return; 137bb71ad88SGary Hade if (rom_r->start) { 138bb71ad88SGary Hade /* we deal with BIOS assigned ROM later */ 139bb71ad88SGary Hade return; 140bb71ad88SGary Hade } 141bb71ad88SGary Hade rom_r->start = rom_r->end = rom_r->flags = 0; 142bb71ad88SGary Hade } 143bb71ad88SGary Hade } 144bb71ad88SGary Hade 145fb9aa6f1SThomas Gleixner /* 146fb9aa6f1SThomas Gleixner * Called after each bus is probed, but before its children 147fb9aa6f1SThomas Gleixner * are examined. 148fb9aa6f1SThomas Gleixner */ 149fb9aa6f1SThomas Gleixner 150fb9aa6f1SThomas Gleixner void __devinit pcibios_fixup_bus(struct pci_bus *b) 151fb9aa6f1SThomas Gleixner { 152bb71ad88SGary Hade struct pci_dev *dev; 153bb71ad88SGary Hade 1540e94ecd0SYinghai Lu /* root bus? */ 1550e94ecd0SYinghai Lu if (!b->parent) 1560e94ecd0SYinghai Lu x86_pci_root_bus_res_quirks(b); 157fb9aa6f1SThomas Gleixner pci_read_bridge_bases(b); 158bb71ad88SGary Hade list_for_each_entry(dev, &b->devices, bus_list) 159bb71ad88SGary Hade pcibios_fixup_device_resources(dev); 160fb9aa6f1SThomas Gleixner } 161fb9aa6f1SThomas Gleixner 162fb9aa6f1SThomas Gleixner /* 163fb9aa6f1SThomas Gleixner * Only use DMI information to set this if nothing was passed 164fb9aa6f1SThomas Gleixner * on the kernel command line (which was parsed earlier). 165fb9aa6f1SThomas Gleixner */ 166fb9aa6f1SThomas Gleixner 16719ad7ae4SLinus Torvalds static int __devinit set_bf_sort(const struct dmi_system_id *d) 168fb9aa6f1SThomas Gleixner { 169fb9aa6f1SThomas Gleixner if (pci_bf_sort == pci_bf_sort_default) { 170fb9aa6f1SThomas Gleixner pci_bf_sort = pci_dmi_bf; 171fb9aa6f1SThomas Gleixner printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); 172fb9aa6f1SThomas Gleixner } 173fb9aa6f1SThomas Gleixner return 0; 174fb9aa6f1SThomas Gleixner } 175fb9aa6f1SThomas Gleixner 176fb9aa6f1SThomas Gleixner /* 177fb9aa6f1SThomas Gleixner * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) 178fb9aa6f1SThomas Gleixner */ 179fb9aa6f1SThomas Gleixner #ifdef __i386__ 18019ad7ae4SLinus Torvalds static int __devinit assign_all_busses(const struct dmi_system_id *d) 181fb9aa6f1SThomas Gleixner { 182fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ALL_BUSSES; 183fb9aa6f1SThomas Gleixner printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" 184fb9aa6f1SThomas Gleixner " (pci=assign-busses)\n", d->ident); 185fb9aa6f1SThomas Gleixner return 0; 186fb9aa6f1SThomas Gleixner } 187fb9aa6f1SThomas Gleixner #endif 188fb9aa6f1SThomas Gleixner 189821508d4SJan Beulich static const struct dmi_system_id __devinitconst pciprobe_dmi_table[] = { 190fb9aa6f1SThomas Gleixner #ifdef __i386__ 191fb9aa6f1SThomas Gleixner /* 192fb9aa6f1SThomas Gleixner * Laptops which need pci=assign-busses to see Cardbus cards 193fb9aa6f1SThomas Gleixner */ 194fb9aa6f1SThomas Gleixner { 195fb9aa6f1SThomas Gleixner .callback = assign_all_busses, 196fb9aa6f1SThomas Gleixner .ident = "Samsung X20 Laptop", 197fb9aa6f1SThomas Gleixner .matches = { 198fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), 199fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), 200fb9aa6f1SThomas Gleixner }, 201fb9aa6f1SThomas Gleixner }, 202fb9aa6f1SThomas Gleixner #endif /* __i386__ */ 203fb9aa6f1SThomas Gleixner { 204fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 205fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 1950", 206fb9aa6f1SThomas Gleixner .matches = { 207fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 208fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), 209fb9aa6f1SThomas Gleixner }, 210fb9aa6f1SThomas Gleixner }, 211fb9aa6f1SThomas Gleixner { 212fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 213fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 1955", 214fb9aa6f1SThomas Gleixner .matches = { 215fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 216fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), 217fb9aa6f1SThomas Gleixner }, 218fb9aa6f1SThomas Gleixner }, 219fb9aa6f1SThomas Gleixner { 220fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 221fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 2900", 222fb9aa6f1SThomas Gleixner .matches = { 223fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 224fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), 225fb9aa6f1SThomas Gleixner }, 226fb9aa6f1SThomas Gleixner }, 227fb9aa6f1SThomas Gleixner { 228fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 229fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 2950", 230fb9aa6f1SThomas Gleixner .matches = { 231fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 232fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), 233fb9aa6f1SThomas Gleixner }, 234fb9aa6f1SThomas Gleixner }, 235fb9aa6f1SThomas Gleixner { 236fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 237fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge R900", 238fb9aa6f1SThomas Gleixner .matches = { 239fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 240fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"), 241fb9aa6f1SThomas Gleixner }, 242fb9aa6f1SThomas Gleixner }, 243fb9aa6f1SThomas Gleixner { 244fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 245fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL20p G3", 246fb9aa6f1SThomas Gleixner .matches = { 247fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 248fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"), 249fb9aa6f1SThomas Gleixner }, 250fb9aa6f1SThomas Gleixner }, 251fb9aa6f1SThomas Gleixner { 252fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 253fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL20p G4", 254fb9aa6f1SThomas Gleixner .matches = { 255fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 256fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"), 257fb9aa6f1SThomas Gleixner }, 258fb9aa6f1SThomas Gleixner }, 259fb9aa6f1SThomas Gleixner { 260fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 261fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL30p G1", 262fb9aa6f1SThomas Gleixner .matches = { 263fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 264fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"), 265fb9aa6f1SThomas Gleixner }, 266fb9aa6f1SThomas Gleixner }, 267fb9aa6f1SThomas Gleixner { 268fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 269fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL25p G1", 270fb9aa6f1SThomas Gleixner .matches = { 271fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 272fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"), 273fb9aa6f1SThomas Gleixner }, 274fb9aa6f1SThomas Gleixner }, 275fb9aa6f1SThomas Gleixner { 276fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 277fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL35p G1", 278fb9aa6f1SThomas Gleixner .matches = { 279fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 280fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"), 281fb9aa6f1SThomas Gleixner }, 282fb9aa6f1SThomas Gleixner }, 283fb9aa6f1SThomas Gleixner { 284fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 285fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL45p G1", 286fb9aa6f1SThomas Gleixner .matches = { 287fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 288fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"), 289fb9aa6f1SThomas Gleixner }, 290fb9aa6f1SThomas Gleixner }, 291fb9aa6f1SThomas Gleixner { 292fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 293fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL45p G2", 294fb9aa6f1SThomas Gleixner .matches = { 295fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 296fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"), 297fb9aa6f1SThomas Gleixner }, 298fb9aa6f1SThomas Gleixner }, 299fb9aa6f1SThomas Gleixner { 300fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 301fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL460c G1", 302fb9aa6f1SThomas Gleixner .matches = { 303fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 304fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"), 305fb9aa6f1SThomas Gleixner }, 306fb9aa6f1SThomas Gleixner }, 307fb9aa6f1SThomas Gleixner { 308fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 309fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL465c G1", 310fb9aa6f1SThomas Gleixner .matches = { 311fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 312fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"), 313fb9aa6f1SThomas Gleixner }, 314fb9aa6f1SThomas Gleixner }, 315fb9aa6f1SThomas Gleixner { 316fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 317fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL480c G1", 318fb9aa6f1SThomas Gleixner .matches = { 319fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 320fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"), 321fb9aa6f1SThomas Gleixner }, 322fb9aa6f1SThomas Gleixner }, 323fb9aa6f1SThomas Gleixner { 324fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 325fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL685c G1", 326fb9aa6f1SThomas Gleixner .matches = { 327fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 328fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), 329fb9aa6f1SThomas Gleixner }, 330fb9aa6f1SThomas Gleixner }, 3318f8ae1a7SMichal Schmidt { 3328f8ae1a7SMichal Schmidt .callback = set_bf_sort, 3338d64c781STony Camuso .ident = "HP ProLiant DL360", 3348f8ae1a7SMichal Schmidt .matches = { 3358f8ae1a7SMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 3368d64c781STony Camuso DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL360"), 3378f8ae1a7SMichal Schmidt }, 3388f8ae1a7SMichal Schmidt }, 3398f8ae1a7SMichal Schmidt { 3408f8ae1a7SMichal Schmidt .callback = set_bf_sort, 3418d64c781STony Camuso .ident = "HP ProLiant DL380", 3428f8ae1a7SMichal Schmidt .matches = { 3438f8ae1a7SMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 3448d64c781STony Camuso DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL380"), 3458f8ae1a7SMichal Schmidt }, 3468f8ae1a7SMichal Schmidt }, 3475b1ea82fSJuha Laiho #ifdef __i386__ 3485b1ea82fSJuha Laiho { 3495b1ea82fSJuha Laiho .callback = assign_all_busses, 3505b1ea82fSJuha Laiho .ident = "Compaq EVO N800c", 3515b1ea82fSJuha Laiho .matches = { 3525b1ea82fSJuha Laiho DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), 3535b1ea82fSJuha Laiho DMI_MATCH(DMI_PRODUCT_NAME, "EVO N800c"), 3545b1ea82fSJuha Laiho }, 3555b1ea82fSJuha Laiho }, 3565b1ea82fSJuha Laiho #endif 357c82bc5adSMichal Schmidt { 358c82bc5adSMichal Schmidt .callback = set_bf_sort, 359739db07fSJesse Barnes .ident = "HP ProLiant DL385 G2", 360c82bc5adSMichal Schmidt .matches = { 361c82bc5adSMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 362739db07fSJesse Barnes DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL385 G2"), 363c82bc5adSMichal Schmidt }, 364c82bc5adSMichal Schmidt }, 365c82bc5adSMichal Schmidt { 366c82bc5adSMichal Schmidt .callback = set_bf_sort, 367739db07fSJesse Barnes .ident = "HP ProLiant DL585 G2", 368c82bc5adSMichal Schmidt .matches = { 369c82bc5adSMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 370739db07fSJesse Barnes DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"), 371c82bc5adSMichal Schmidt }, 372c82bc5adSMichal Schmidt }, 373fb9aa6f1SThomas Gleixner {} 374fb9aa6f1SThomas Gleixner }; 375fb9aa6f1SThomas Gleixner 3760df18ff3SYinghai Lu void __init dmi_check_pciprobe(void) 3770df18ff3SYinghai Lu { 3780df18ff3SYinghai Lu dmi_check_system(pciprobe_dmi_table); 3790df18ff3SYinghai Lu } 3800df18ff3SYinghai Lu 381fb9aa6f1SThomas Gleixner struct pci_bus * __devinit pcibios_scan_root(int busnum) 382fb9aa6f1SThomas Gleixner { 383fb9aa6f1SThomas Gleixner struct pci_bus *bus = NULL; 384fb9aa6f1SThomas Gleixner struct pci_sysdata *sd; 385fb9aa6f1SThomas Gleixner 386fb9aa6f1SThomas Gleixner while ((bus = pci_find_next_bus(bus)) != NULL) { 387fb9aa6f1SThomas Gleixner if (bus->number == busnum) { 388fb9aa6f1SThomas Gleixner /* Already scanned */ 389fb9aa6f1SThomas Gleixner return bus; 390fb9aa6f1SThomas Gleixner } 391fb9aa6f1SThomas Gleixner } 392fb9aa6f1SThomas Gleixner 393fb9aa6f1SThomas Gleixner /* Allocate per-root-bus (not per bus) arch-specific data. 394fb9aa6f1SThomas Gleixner * TODO: leak; this memory is never freed. 395fb9aa6f1SThomas Gleixner * It's arguable whether it's worth the trouble to care. 396fb9aa6f1SThomas Gleixner */ 397fb9aa6f1SThomas Gleixner sd = kzalloc(sizeof(*sd), GFP_KERNEL); 398fb9aa6f1SThomas Gleixner if (!sd) { 399fb9aa6f1SThomas Gleixner printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); 400fb9aa6f1SThomas Gleixner return NULL; 401fb9aa6f1SThomas Gleixner } 402fb9aa6f1SThomas Gleixner 403871d5f8dSYinghai Lu sd->node = get_mp_bus_to_node(busnum); 404fb9aa6f1SThomas Gleixner 405871d5f8dSYinghai Lu printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); 406871d5f8dSYinghai Lu bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); 407871d5f8dSYinghai Lu if (!bus) 408871d5f8dSYinghai Lu kfree(sd); 409871d5f8dSYinghai Lu 410871d5f8dSYinghai Lu return bus; 411fb9aa6f1SThomas Gleixner } 412fb9aa6f1SThomas Gleixner 4138dd779b1SRobert Richter int __init pcibios_init(void) 414fb9aa6f1SThomas Gleixner { 415fb9aa6f1SThomas Gleixner struct cpuinfo_x86 *c = &boot_cpu_data; 416fb9aa6f1SThomas Gleixner 417fb9aa6f1SThomas Gleixner if (!raw_pci_ops) { 418fb9aa6f1SThomas Gleixner printk(KERN_WARNING "PCI: System does not support PCI\n"); 419fb9aa6f1SThomas Gleixner return 0; 420fb9aa6f1SThomas Gleixner } 421fb9aa6f1SThomas Gleixner 422fb9aa6f1SThomas Gleixner /* 42376b1a87bSDave Jones * Set PCI cacheline size to that of the CPU if the CPU has reported it. 42476b1a87bSDave Jones * (For older CPUs that don't support cpuid, we se it to 32 bytes 42576b1a87bSDave Jones * It's also good for 386/486s (which actually have 16) 426fb9aa6f1SThomas Gleixner * as quite a few PCI devices do not support smaller values. 427fb9aa6f1SThomas Gleixner */ 42876b1a87bSDave Jones if (c->x86_clflush_size > 0) { 42976b1a87bSDave Jones pci_dfl_cache_line_size = c->x86_clflush_size >> 2; 43076b1a87bSDave Jones printk(KERN_DEBUG "PCI: pci_cache_line_size set to %d bytes\n", 43176b1a87bSDave Jones pci_dfl_cache_line_size << 2); 43276b1a87bSDave Jones } else { 433ac1aa47bSJesse Barnes pci_dfl_cache_line_size = 32 >> 2; 43476b1a87bSDave Jones printk(KERN_DEBUG "PCI: Unknown cacheline size. Setting to 32 bytes\n"); 43576b1a87bSDave Jones } 436fb9aa6f1SThomas Gleixner 437fb9aa6f1SThomas Gleixner pcibios_resource_survey(); 438fb9aa6f1SThomas Gleixner 439fb9aa6f1SThomas Gleixner if (pci_bf_sort >= pci_force_bf) 440fb9aa6f1SThomas Gleixner pci_sort_breadthfirst(); 441fb9aa6f1SThomas Gleixner return 0; 442fb9aa6f1SThomas Gleixner } 443fb9aa6f1SThomas Gleixner 444fb9aa6f1SThomas Gleixner char * __devinit pcibios_setup(char *str) 445fb9aa6f1SThomas Gleixner { 446fb9aa6f1SThomas Gleixner if (!strcmp(str, "off")) { 447fb9aa6f1SThomas Gleixner pci_probe = 0; 448fb9aa6f1SThomas Gleixner return NULL; 449fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "bfsort")) { 450fb9aa6f1SThomas Gleixner pci_bf_sort = pci_force_bf; 451fb9aa6f1SThomas Gleixner return NULL; 452fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "nobfsort")) { 453fb9aa6f1SThomas Gleixner pci_bf_sort = pci_force_nobf; 454fb9aa6f1SThomas Gleixner return NULL; 455fb9aa6f1SThomas Gleixner } 456fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_BIOS 457fb9aa6f1SThomas Gleixner else if (!strcmp(str, "bios")) { 458fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_BIOS; 459fb9aa6f1SThomas Gleixner return NULL; 460fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "nobios")) { 461fb9aa6f1SThomas Gleixner pci_probe &= ~PCI_PROBE_BIOS; 462fb9aa6f1SThomas Gleixner return NULL; 463fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "biosirq")) { 464fb9aa6f1SThomas Gleixner pci_probe |= PCI_BIOS_IRQ_SCAN; 465fb9aa6f1SThomas Gleixner return NULL; 466fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "pirqaddr=", 9)) { 467fb9aa6f1SThomas Gleixner pirq_table_addr = simple_strtoul(str+9, NULL, 0); 468fb9aa6f1SThomas Gleixner return NULL; 469fb9aa6f1SThomas Gleixner } 470fb9aa6f1SThomas Gleixner #endif 471fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_DIRECT 472fb9aa6f1SThomas Gleixner else if (!strcmp(str, "conf1")) { 473fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS; 474fb9aa6f1SThomas Gleixner return NULL; 475fb9aa6f1SThomas Gleixner } 476fb9aa6f1SThomas Gleixner else if (!strcmp(str, "conf2")) { 477fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS; 478fb9aa6f1SThomas Gleixner return NULL; 479fb9aa6f1SThomas Gleixner } 480fb9aa6f1SThomas Gleixner #endif 481fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_MMCONFIG 482fb9aa6f1SThomas Gleixner else if (!strcmp(str, "nommconf")) { 483fb9aa6f1SThomas Gleixner pci_probe &= ~PCI_PROBE_MMCONF; 484fb9aa6f1SThomas Gleixner return NULL; 485fb9aa6f1SThomas Gleixner } 4865f0b2976SYinghai Lu else if (!strcmp(str, "check_enable_amd_mmconf")) { 4875f0b2976SYinghai Lu pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF; 4885f0b2976SYinghai Lu return NULL; 4895f0b2976SYinghai Lu } 490fb9aa6f1SThomas Gleixner #endif 491fb9aa6f1SThomas Gleixner else if (!strcmp(str, "noacpi")) { 492fb9aa6f1SThomas Gleixner acpi_noirq_set(); 493fb9aa6f1SThomas Gleixner return NULL; 494fb9aa6f1SThomas Gleixner } 495fb9aa6f1SThomas Gleixner else if (!strcmp(str, "noearly")) { 496fb9aa6f1SThomas Gleixner pci_probe |= PCI_PROBE_NOEARLY; 497fb9aa6f1SThomas Gleixner return NULL; 498fb9aa6f1SThomas Gleixner } 499fb9aa6f1SThomas Gleixner #ifndef CONFIG_X86_VISWS 500fb9aa6f1SThomas Gleixner else if (!strcmp(str, "usepirqmask")) { 501fb9aa6f1SThomas Gleixner pci_probe |= PCI_USE_PIRQ_MASK; 502fb9aa6f1SThomas Gleixner return NULL; 503fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "irqmask=", 8)) { 504fb9aa6f1SThomas Gleixner pcibios_irq_mask = simple_strtol(str+8, NULL, 0); 505fb9aa6f1SThomas Gleixner return NULL; 506fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "lastbus=", 8)) { 507fb9aa6f1SThomas Gleixner pcibios_last_bus = simple_strtol(str+8, NULL, 0); 508fb9aa6f1SThomas Gleixner return NULL; 509fb9aa6f1SThomas Gleixner } 510fb9aa6f1SThomas Gleixner #endif 511fb9aa6f1SThomas Gleixner else if (!strcmp(str, "rom")) { 512fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ROMS; 513fb9aa6f1SThomas Gleixner return NULL; 514bb71ad88SGary Hade } else if (!strcmp(str, "norom")) { 515bb71ad88SGary Hade pci_probe |= PCI_NOASSIGN_ROMS; 516bb71ad88SGary Hade return NULL; 517fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "assign-busses")) { 518fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ALL_BUSSES; 519fb9aa6f1SThomas Gleixner return NULL; 520236e946bSLinus Torvalds } else if (!strcmp(str, "use_crs")) { 521236e946bSLinus Torvalds pci_probe |= PCI_USE__CRS; 52262f420f8SGary Hade return NULL; 5237bc5e3f2SBjorn Helgaas } else if (!strcmp(str, "nocrs")) { 5247bc5e3f2SBjorn Helgaas pci_probe |= PCI_ROOT_NO_CRS; 5257bc5e3f2SBjorn Helgaas return NULL; 526e3f2baebSYinghai Lu } else if (!strcmp(str, "earlydump")) { 527e3f2baebSYinghai Lu pci_early_dump_regs = 1; 528e3f2baebSYinghai Lu return NULL; 529fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "routeirq")) { 530fb9aa6f1SThomas Gleixner pci_routeirq = 1; 531fb9aa6f1SThomas Gleixner return NULL; 53213a6ddb0SYinghai Lu } else if (!strcmp(str, "skip_isa_align")) { 53313a6ddb0SYinghai Lu pci_probe |= PCI_CAN_SKIP_ISA_ALIGN; 53413a6ddb0SYinghai Lu return NULL; 535a9322f64SStefan Assmann } else if (!strcmp(str, "noioapicquirk")) { 536a9322f64SStefan Assmann noioapicquirk = 1; 537a9322f64SStefan Assmann return NULL; 5389197979bSStefan Assmann } else if (!strcmp(str, "ioapicreroute")) { 5399197979bSStefan Assmann if (noioapicreroute != -1) 5409197979bSStefan Assmann noioapicreroute = 0; 5419197979bSStefan Assmann return NULL; 54241b9eb26SStefan Assmann } else if (!strcmp(str, "noioapicreroute")) { 54341b9eb26SStefan Assmann if (noioapicreroute != -1) 54441b9eb26SStefan Assmann noioapicreroute = 1; 54541b9eb26SStefan Assmann return NULL; 546fb9aa6f1SThomas Gleixner } 547fb9aa6f1SThomas Gleixner return str; 548fb9aa6f1SThomas Gleixner } 549fb9aa6f1SThomas Gleixner 550fb9aa6f1SThomas Gleixner unsigned int pcibios_assign_all_busses(void) 551fb9aa6f1SThomas Gleixner { 552fb9aa6f1SThomas Gleixner return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; 553fb9aa6f1SThomas Gleixner } 554fb9aa6f1SThomas Gleixner 555fb9aa6f1SThomas Gleixner int pcibios_enable_device(struct pci_dev *dev, int mask) 556fb9aa6f1SThomas Gleixner { 557fb9aa6f1SThomas Gleixner int err; 558fb9aa6f1SThomas Gleixner 559b81d988cSBjorn Helgaas if ((err = pci_enable_resources(dev, mask)) < 0) 560fb9aa6f1SThomas Gleixner return err; 561fb9aa6f1SThomas Gleixner 56216cf0ebcSRafael J. Wysocki if (!pci_dev_msi_enabled(dev)) 563fb9aa6f1SThomas Gleixner return pcibios_enable_irq(dev); 564fb9aa6f1SThomas Gleixner return 0; 565fb9aa6f1SThomas Gleixner } 566fb9aa6f1SThomas Gleixner 567fb9aa6f1SThomas Gleixner void pcibios_disable_device (struct pci_dev *dev) 568fb9aa6f1SThomas Gleixner { 56916cf0ebcSRafael J. Wysocki if (!pci_dev_msi_enabled(dev) && pcibios_disable_irq) 570fb9aa6f1SThomas Gleixner pcibios_disable_irq(dev); 571fb9aa6f1SThomas Gleixner } 572fb9aa6f1SThomas Gleixner 5730ef5f8f6SAndrew Patterson int pci_ext_cfg_avail(struct pci_dev *dev) 5740ef5f8f6SAndrew Patterson { 5750ef5f8f6SAndrew Patterson if (raw_pci_ext_ops) 5760ef5f8f6SAndrew Patterson return 1; 5770ef5f8f6SAndrew Patterson else 5780ef5f8f6SAndrew Patterson return 0; 5790ef5f8f6SAndrew Patterson } 5800ef5f8f6SAndrew Patterson 58198db6f19SSam Ravnborg struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node) 582fb9aa6f1SThomas Gleixner { 583fb9aa6f1SThomas Gleixner struct pci_bus *bus = NULL; 584fb9aa6f1SThomas Gleixner struct pci_sysdata *sd; 585fb9aa6f1SThomas Gleixner 586fb9aa6f1SThomas Gleixner /* 587fb9aa6f1SThomas Gleixner * Allocate per-root-bus (not per bus) arch-specific data. 588fb9aa6f1SThomas Gleixner * TODO: leak; this memory is never freed. 589fb9aa6f1SThomas Gleixner * It's arguable whether it's worth the trouble to care. 590fb9aa6f1SThomas Gleixner */ 591fb9aa6f1SThomas Gleixner sd = kzalloc(sizeof(*sd), GFP_KERNEL); 592fb9aa6f1SThomas Gleixner if (!sd) { 593fb9aa6f1SThomas Gleixner printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); 594fb9aa6f1SThomas Gleixner return NULL; 595fb9aa6f1SThomas Gleixner } 596871d5f8dSYinghai Lu sd->node = node; 597871d5f8dSYinghai Lu bus = pci_scan_bus(busno, ops, sd); 598fb9aa6f1SThomas Gleixner if (!bus) 599fb9aa6f1SThomas Gleixner kfree(sd); 600fb9aa6f1SThomas Gleixner 601fb9aa6f1SThomas Gleixner return bus; 602fb9aa6f1SThomas Gleixner } 603871d5f8dSYinghai Lu 60498db6f19SSam Ravnborg struct pci_bus * __devinit pci_scan_bus_with_sysdata(int busno) 605871d5f8dSYinghai Lu { 606871d5f8dSYinghai Lu return pci_scan_bus_on_node(busno, &pci_root_ops, -1); 607871d5f8dSYinghai Lu } 6082547089cSJesse Barnes 6092547089cSJesse Barnes /* 6102547089cSJesse Barnes * NUMA info for PCI busses 6112547089cSJesse Barnes * 6122547089cSJesse Barnes * Early arch code is responsible for filling in reasonable values here. 6132547089cSJesse Barnes * A node id of "-1" means "use current node". In other words, if a bus 6142547089cSJesse Barnes * has a -1 node id, it's not tightly coupled to any particular chunk 6152547089cSJesse Barnes * of memory (as is the case on some Nehalem systems). 6162547089cSJesse Barnes */ 6172547089cSJesse Barnes #ifdef CONFIG_NUMA 6182547089cSJesse Barnes 6192547089cSJesse Barnes #define BUS_NR 256 6202547089cSJesse Barnes 6212547089cSJesse Barnes #ifdef CONFIG_X86_64 6222547089cSJesse Barnes 6232547089cSJesse Barnes static int mp_bus_to_node[BUS_NR] = { 6242547089cSJesse Barnes [0 ... BUS_NR - 1] = -1 6252547089cSJesse Barnes }; 6262547089cSJesse Barnes 6272547089cSJesse Barnes void set_mp_bus_to_node(int busnum, int node) 6282547089cSJesse Barnes { 6292547089cSJesse Barnes if (busnum >= 0 && busnum < BUS_NR) 6302547089cSJesse Barnes mp_bus_to_node[busnum] = node; 6312547089cSJesse Barnes } 6322547089cSJesse Barnes 6332547089cSJesse Barnes int get_mp_bus_to_node(int busnum) 6342547089cSJesse Barnes { 6352547089cSJesse Barnes int node = -1; 6362547089cSJesse Barnes 6372547089cSJesse Barnes if (busnum < 0 || busnum > (BUS_NR - 1)) 6382547089cSJesse Barnes return node; 6392547089cSJesse Barnes 6402547089cSJesse Barnes node = mp_bus_to_node[busnum]; 6412547089cSJesse Barnes 6422547089cSJesse Barnes /* 6432547089cSJesse Barnes * let numa_node_id to decide it later in dma_alloc_pages 6442547089cSJesse Barnes * if there is no ram on that node 6452547089cSJesse Barnes */ 6462547089cSJesse Barnes if (node != -1 && !node_online(node)) 6472547089cSJesse Barnes node = -1; 6482547089cSJesse Barnes 6492547089cSJesse Barnes return node; 6502547089cSJesse Barnes } 6512547089cSJesse Barnes 6522547089cSJesse Barnes #else /* CONFIG_X86_32 */ 6532547089cSJesse Barnes 65476baeebfSJesse Barnes static int mp_bus_to_node[BUS_NR] = { 6552547089cSJesse Barnes [0 ... BUS_NR - 1] = -1 6562547089cSJesse Barnes }; 6572547089cSJesse Barnes 6582547089cSJesse Barnes void set_mp_bus_to_node(int busnum, int node) 6592547089cSJesse Barnes { 6602547089cSJesse Barnes if (busnum >= 0 && busnum < BUS_NR) 6612547089cSJesse Barnes mp_bus_to_node[busnum] = (unsigned char) node; 6622547089cSJesse Barnes } 6632547089cSJesse Barnes 6642547089cSJesse Barnes int get_mp_bus_to_node(int busnum) 6652547089cSJesse Barnes { 6662547089cSJesse Barnes int node; 6672547089cSJesse Barnes 6682547089cSJesse Barnes if (busnum < 0 || busnum > (BUS_NR - 1)) 6692547089cSJesse Barnes return 0; 6702547089cSJesse Barnes node = mp_bus_to_node[busnum]; 6712547089cSJesse Barnes return node; 6722547089cSJesse Barnes } 6732547089cSJesse Barnes 6742547089cSJesse Barnes #endif /* CONFIG_X86_32 */ 6752547089cSJesse Barnes 6762547089cSJesse Barnes #endif /* CONFIG_NUMA */ 677