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; 25fb9aa6f1SThomas Gleixner int pcibios_last_bus = -1; 26fb9aa6f1SThomas Gleixner unsigned long pirq_table_addr; 27fb9aa6f1SThomas Gleixner struct pci_bus *pci_root_bus; 28fb9aa6f1SThomas Gleixner struct pci_raw_ops *raw_pci_ops; 29b6ce068aSMatthew Wilcox struct pci_raw_ops *raw_pci_ext_ops; 30b6ce068aSMatthew Wilcox 31b6ce068aSMatthew Wilcox int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, 32b6ce068aSMatthew Wilcox int reg, int len, u32 *val) 33b6ce068aSMatthew Wilcox { 34b6ce068aSMatthew Wilcox if (reg < 256 && raw_pci_ops) 35b6ce068aSMatthew Wilcox return raw_pci_ops->read(domain, bus, devfn, reg, len, val); 36b6ce068aSMatthew Wilcox if (raw_pci_ext_ops) 37b6ce068aSMatthew Wilcox return raw_pci_ext_ops->read(domain, bus, devfn, reg, len, val); 38b6ce068aSMatthew Wilcox return -EINVAL; 39b6ce068aSMatthew Wilcox } 40b6ce068aSMatthew Wilcox 41b6ce068aSMatthew Wilcox int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, 42b6ce068aSMatthew Wilcox int reg, int len, u32 val) 43b6ce068aSMatthew Wilcox { 44b6ce068aSMatthew Wilcox if (reg < 256 && raw_pci_ops) 45b6ce068aSMatthew Wilcox return raw_pci_ops->write(domain, bus, devfn, reg, len, val); 46b6ce068aSMatthew Wilcox if (raw_pci_ext_ops) 47b6ce068aSMatthew Wilcox return raw_pci_ext_ops->write(domain, bus, devfn, reg, len, val); 48b6ce068aSMatthew Wilcox return -EINVAL; 49b6ce068aSMatthew Wilcox } 50fb9aa6f1SThomas Gleixner 51fb9aa6f1SThomas Gleixner static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) 52fb9aa6f1SThomas Gleixner { 53b6ce068aSMatthew Wilcox return raw_pci_read(pci_domain_nr(bus), bus->number, 54a79e4198SJeff Garzik devfn, where, size, value); 55fb9aa6f1SThomas Gleixner } 56fb9aa6f1SThomas Gleixner 57fb9aa6f1SThomas Gleixner static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) 58fb9aa6f1SThomas Gleixner { 59b6ce068aSMatthew Wilcox return raw_pci_write(pci_domain_nr(bus), bus->number, 60a79e4198SJeff Garzik devfn, where, size, value); 61fb9aa6f1SThomas Gleixner } 62fb9aa6f1SThomas Gleixner 63fb9aa6f1SThomas Gleixner struct pci_ops pci_root_ops = { 64fb9aa6f1SThomas Gleixner .read = pci_read, 65fb9aa6f1SThomas Gleixner .write = pci_write, 66fb9aa6f1SThomas Gleixner }; 67fb9aa6f1SThomas Gleixner 68fb9aa6f1SThomas Gleixner /* 69fb9aa6f1SThomas Gleixner * legacy, numa, and acpi all want to call pcibios_scan_root 70fb9aa6f1SThomas Gleixner * from their initcalls. This flag prevents that. 71fb9aa6f1SThomas Gleixner */ 72fb9aa6f1SThomas Gleixner int pcibios_scanned; 73fb9aa6f1SThomas Gleixner 74fb9aa6f1SThomas Gleixner /* 75fb9aa6f1SThomas Gleixner * This interrupt-safe spinlock protects all accesses to PCI 76fb9aa6f1SThomas Gleixner * configuration space. 77fb9aa6f1SThomas Gleixner */ 78fb9aa6f1SThomas Gleixner DEFINE_SPINLOCK(pci_config_lock); 79fb9aa6f1SThomas Gleixner 809f8daccaSGary Hade static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) 819f8daccaSGary Hade { 829f8daccaSGary Hade struct resource *rom_r = &dev->resource[PCI_ROM_RESOURCE]; 839f8daccaSGary Hade 849f8daccaSGary Hade if (rom_r->parent) 859f8daccaSGary Hade return; 869f8daccaSGary Hade if (rom_r->start) 879f8daccaSGary Hade /* we deal with BIOS assigned ROM later */ 889f8daccaSGary Hade return; 899f8daccaSGary Hade if (!(pci_probe & PCI_ASSIGN_ROMS)) 909f8daccaSGary Hade rom_r->start = rom_r->end = rom_r->flags = 0; 919f8daccaSGary Hade } 929f8daccaSGary Hade 93fb9aa6f1SThomas Gleixner /* 94fb9aa6f1SThomas Gleixner * Called after each bus is probed, but before its children 95fb9aa6f1SThomas Gleixner * are examined. 96fb9aa6f1SThomas Gleixner */ 97fb9aa6f1SThomas Gleixner 98fb9aa6f1SThomas Gleixner void __devinit pcibios_fixup_bus(struct pci_bus *b) 99fb9aa6f1SThomas Gleixner { 1009f8daccaSGary Hade struct pci_dev *dev; 1019f8daccaSGary Hade 102fb9aa6f1SThomas Gleixner pci_read_bridge_bases(b); 1039f8daccaSGary Hade list_for_each_entry(dev, &b->devices, bus_list) 1049f8daccaSGary Hade pcibios_fixup_device_resources(dev); 105fb9aa6f1SThomas Gleixner } 106fb9aa6f1SThomas Gleixner 107fb9aa6f1SThomas Gleixner /* 108fb9aa6f1SThomas Gleixner * Only use DMI information to set this if nothing was passed 109fb9aa6f1SThomas Gleixner * on the kernel command line (which was parsed earlier). 110fb9aa6f1SThomas Gleixner */ 111fb9aa6f1SThomas Gleixner 11219ad7ae4SLinus Torvalds static int __devinit set_bf_sort(const struct dmi_system_id *d) 113fb9aa6f1SThomas Gleixner { 114fb9aa6f1SThomas Gleixner if (pci_bf_sort == pci_bf_sort_default) { 115fb9aa6f1SThomas Gleixner pci_bf_sort = pci_dmi_bf; 116fb9aa6f1SThomas Gleixner printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident); 117fb9aa6f1SThomas Gleixner } 118fb9aa6f1SThomas Gleixner return 0; 119fb9aa6f1SThomas Gleixner } 120fb9aa6f1SThomas Gleixner 121fb9aa6f1SThomas Gleixner /* 122fb9aa6f1SThomas Gleixner * Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus) 123fb9aa6f1SThomas Gleixner */ 124fb9aa6f1SThomas Gleixner #ifdef __i386__ 12519ad7ae4SLinus Torvalds static int __devinit assign_all_busses(const struct dmi_system_id *d) 126fb9aa6f1SThomas Gleixner { 127fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ALL_BUSSES; 128fb9aa6f1SThomas Gleixner printk(KERN_INFO "%s detected: enabling PCI bus# renumbering" 129fb9aa6f1SThomas Gleixner " (pci=assign-busses)\n", d->ident); 130fb9aa6f1SThomas Gleixner return 0; 131fb9aa6f1SThomas Gleixner } 132fb9aa6f1SThomas Gleixner #endif 133fb9aa6f1SThomas Gleixner 134fb9aa6f1SThomas Gleixner static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { 135fb9aa6f1SThomas Gleixner #ifdef __i386__ 136fb9aa6f1SThomas Gleixner /* 137fb9aa6f1SThomas Gleixner * Laptops which need pci=assign-busses to see Cardbus cards 138fb9aa6f1SThomas Gleixner */ 139fb9aa6f1SThomas Gleixner { 140fb9aa6f1SThomas Gleixner .callback = assign_all_busses, 141fb9aa6f1SThomas Gleixner .ident = "Samsung X20 Laptop", 142fb9aa6f1SThomas Gleixner .matches = { 143fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Samsung Electronics"), 144fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "SX20S"), 145fb9aa6f1SThomas Gleixner }, 146fb9aa6f1SThomas Gleixner }, 147fb9aa6f1SThomas Gleixner #endif /* __i386__ */ 148fb9aa6f1SThomas Gleixner { 149fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 150fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 1950", 151fb9aa6f1SThomas Gleixner .matches = { 152fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 153fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), 154fb9aa6f1SThomas Gleixner }, 155fb9aa6f1SThomas Gleixner }, 156fb9aa6f1SThomas Gleixner { 157fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 158fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 1955", 159fb9aa6f1SThomas Gleixner .matches = { 160fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 161fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"), 162fb9aa6f1SThomas Gleixner }, 163fb9aa6f1SThomas Gleixner }, 164fb9aa6f1SThomas Gleixner { 165fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 166fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 2900", 167fb9aa6f1SThomas Gleixner .matches = { 168fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 169fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"), 170fb9aa6f1SThomas Gleixner }, 171fb9aa6f1SThomas Gleixner }, 172fb9aa6f1SThomas Gleixner { 173fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 174fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge 2950", 175fb9aa6f1SThomas Gleixner .matches = { 176fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 177fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"), 178fb9aa6f1SThomas Gleixner }, 179fb9aa6f1SThomas Gleixner }, 180fb9aa6f1SThomas Gleixner { 181fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 182fb9aa6f1SThomas Gleixner .ident = "Dell PowerEdge R900", 183fb9aa6f1SThomas Gleixner .matches = { 184fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "Dell"), 185fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R900"), 186fb9aa6f1SThomas Gleixner }, 187fb9aa6f1SThomas Gleixner }, 188fb9aa6f1SThomas Gleixner { 189fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 190fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL20p G3", 191fb9aa6f1SThomas Gleixner .matches = { 192fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 193fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G3"), 194fb9aa6f1SThomas Gleixner }, 195fb9aa6f1SThomas Gleixner }, 196fb9aa6f1SThomas Gleixner { 197fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 198fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL20p G4", 199fb9aa6f1SThomas Gleixner .matches = { 200fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 201fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL20p G4"), 202fb9aa6f1SThomas Gleixner }, 203fb9aa6f1SThomas Gleixner }, 204fb9aa6f1SThomas Gleixner { 205fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 206fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL30p G1", 207fb9aa6f1SThomas Gleixner .matches = { 208fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 209fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL30p G1"), 210fb9aa6f1SThomas Gleixner }, 211fb9aa6f1SThomas Gleixner }, 212fb9aa6f1SThomas Gleixner { 213fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 214fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL25p G1", 215fb9aa6f1SThomas Gleixner .matches = { 216fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 217fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL25p G1"), 218fb9aa6f1SThomas Gleixner }, 219fb9aa6f1SThomas Gleixner }, 220fb9aa6f1SThomas Gleixner { 221fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 222fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL35p G1", 223fb9aa6f1SThomas Gleixner .matches = { 224fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 225fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL35p G1"), 226fb9aa6f1SThomas Gleixner }, 227fb9aa6f1SThomas Gleixner }, 228fb9aa6f1SThomas Gleixner { 229fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 230fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL45p G1", 231fb9aa6f1SThomas Gleixner .matches = { 232fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 233fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G1"), 234fb9aa6f1SThomas Gleixner }, 235fb9aa6f1SThomas Gleixner }, 236fb9aa6f1SThomas Gleixner { 237fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 238fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL45p G2", 239fb9aa6f1SThomas Gleixner .matches = { 240fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 241fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL45p G2"), 242fb9aa6f1SThomas Gleixner }, 243fb9aa6f1SThomas Gleixner }, 244fb9aa6f1SThomas Gleixner { 245fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 246fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL460c G1", 247fb9aa6f1SThomas Gleixner .matches = { 248fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 249fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL460c G1"), 250fb9aa6f1SThomas Gleixner }, 251fb9aa6f1SThomas Gleixner }, 252fb9aa6f1SThomas Gleixner { 253fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 254fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL465c G1", 255fb9aa6f1SThomas Gleixner .matches = { 256fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 257fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL465c G1"), 258fb9aa6f1SThomas Gleixner }, 259fb9aa6f1SThomas Gleixner }, 260fb9aa6f1SThomas Gleixner { 261fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 262fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL480c G1", 263fb9aa6f1SThomas Gleixner .matches = { 264fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 265fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL480c G1"), 266fb9aa6f1SThomas Gleixner }, 267fb9aa6f1SThomas Gleixner }, 268fb9aa6f1SThomas Gleixner { 269fb9aa6f1SThomas Gleixner .callback = set_bf_sort, 270fb9aa6f1SThomas Gleixner .ident = "HP ProLiant BL685c G1", 271fb9aa6f1SThomas Gleixner .matches = { 272fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_SYS_VENDOR, "HP"), 273fb9aa6f1SThomas Gleixner DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant BL685c G1"), 274fb9aa6f1SThomas Gleixner }, 275fb9aa6f1SThomas Gleixner }, 2768f8ae1a7SMichal Schmidt { 2778f8ae1a7SMichal Schmidt .callback = set_bf_sort, 2788f8ae1a7SMichal Schmidt .ident = "HP ProLiant DL385 G2", 2798f8ae1a7SMichal Schmidt .matches = { 2808f8ae1a7SMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 2818f8ae1a7SMichal Schmidt DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL385 G2"), 2828f8ae1a7SMichal Schmidt }, 2838f8ae1a7SMichal Schmidt }, 2848f8ae1a7SMichal Schmidt { 2858f8ae1a7SMichal Schmidt .callback = set_bf_sort, 2868f8ae1a7SMichal Schmidt .ident = "HP ProLiant DL585 G2", 2878f8ae1a7SMichal Schmidt .matches = { 2888f8ae1a7SMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 2898f8ae1a7SMichal Schmidt DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"), 2908f8ae1a7SMichal Schmidt }, 2918f8ae1a7SMichal Schmidt }, 2925b1ea82fSJuha Laiho #ifdef __i386__ 2935b1ea82fSJuha Laiho { 2945b1ea82fSJuha Laiho .callback = assign_all_busses, 2955b1ea82fSJuha Laiho .ident = "Compaq EVO N800c", 2965b1ea82fSJuha Laiho .matches = { 2975b1ea82fSJuha Laiho DMI_MATCH(DMI_SYS_VENDOR, "Compaq"), 2985b1ea82fSJuha Laiho DMI_MATCH(DMI_PRODUCT_NAME, "EVO N800c"), 2995b1ea82fSJuha Laiho }, 3005b1ea82fSJuha Laiho }, 3015b1ea82fSJuha Laiho #endif 302c82bc5adSMichal Schmidt { 303c82bc5adSMichal Schmidt .callback = set_bf_sort, 304c82bc5adSMichal Schmidt .ident = "HP ProLiant DL385 G2", 305c82bc5adSMichal Schmidt .matches = { 306c82bc5adSMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 307c82bc5adSMichal Schmidt DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL385 G2"), 308c82bc5adSMichal Schmidt }, 309c82bc5adSMichal Schmidt }, 310c82bc5adSMichal Schmidt { 311c82bc5adSMichal Schmidt .callback = set_bf_sort, 312c82bc5adSMichal Schmidt .ident = "HP ProLiant DL585 G2", 313c82bc5adSMichal Schmidt .matches = { 314c82bc5adSMichal Schmidt DMI_MATCH(DMI_SYS_VENDOR, "HP"), 315c82bc5adSMichal Schmidt DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"), 316c82bc5adSMichal Schmidt }, 317c82bc5adSMichal Schmidt }, 318fb9aa6f1SThomas Gleixner {} 319fb9aa6f1SThomas Gleixner }; 320fb9aa6f1SThomas Gleixner 321fb9aa6f1SThomas Gleixner struct pci_bus * __devinit pcibios_scan_root(int busnum) 322fb9aa6f1SThomas Gleixner { 323fb9aa6f1SThomas Gleixner struct pci_bus *bus = NULL; 324fb9aa6f1SThomas Gleixner struct pci_sysdata *sd; 325fb9aa6f1SThomas Gleixner 326fb9aa6f1SThomas Gleixner dmi_check_system(pciprobe_dmi_table); 327fb9aa6f1SThomas Gleixner 328fb9aa6f1SThomas Gleixner while ((bus = pci_find_next_bus(bus)) != NULL) { 329fb9aa6f1SThomas Gleixner if (bus->number == busnum) { 330fb9aa6f1SThomas Gleixner /* Already scanned */ 331fb9aa6f1SThomas Gleixner return bus; 332fb9aa6f1SThomas Gleixner } 333fb9aa6f1SThomas Gleixner } 334fb9aa6f1SThomas Gleixner 335fb9aa6f1SThomas Gleixner /* Allocate per-root-bus (not per bus) arch-specific data. 336fb9aa6f1SThomas Gleixner * TODO: leak; this memory is never freed. 337fb9aa6f1SThomas Gleixner * It's arguable whether it's worth the trouble to care. 338fb9aa6f1SThomas Gleixner */ 339fb9aa6f1SThomas Gleixner sd = kzalloc(sizeof(*sd), GFP_KERNEL); 340fb9aa6f1SThomas Gleixner if (!sd) { 341fb9aa6f1SThomas Gleixner printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); 342fb9aa6f1SThomas Gleixner return NULL; 343fb9aa6f1SThomas Gleixner } 344fb9aa6f1SThomas Gleixner 345fb9aa6f1SThomas Gleixner printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum); 346fb9aa6f1SThomas Gleixner 347fb9aa6f1SThomas Gleixner return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd); 348fb9aa6f1SThomas Gleixner } 349fb9aa6f1SThomas Gleixner 350fb9aa6f1SThomas Gleixner extern u8 pci_cache_line_size; 351fb9aa6f1SThomas Gleixner 352fb9aa6f1SThomas Gleixner static int __init pcibios_init(void) 353fb9aa6f1SThomas Gleixner { 354fb9aa6f1SThomas Gleixner struct cpuinfo_x86 *c = &boot_cpu_data; 355fb9aa6f1SThomas Gleixner 356fb9aa6f1SThomas Gleixner if (!raw_pci_ops) { 357fb9aa6f1SThomas Gleixner printk(KERN_WARNING "PCI: System does not support PCI\n"); 358fb9aa6f1SThomas Gleixner return 0; 359fb9aa6f1SThomas Gleixner } 360fb9aa6f1SThomas Gleixner 361fb9aa6f1SThomas Gleixner /* 362fb9aa6f1SThomas Gleixner * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8 363fb9aa6f1SThomas Gleixner * and P4. It's also good for 386/486s (which actually have 16) 364fb9aa6f1SThomas Gleixner * as quite a few PCI devices do not support smaller values. 365fb9aa6f1SThomas Gleixner */ 366fb9aa6f1SThomas Gleixner pci_cache_line_size = 32 >> 2; 367fb9aa6f1SThomas Gleixner if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) 368fb9aa6f1SThomas Gleixner pci_cache_line_size = 64 >> 2; /* K7 & K8 */ 369fb9aa6f1SThomas Gleixner else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) 370fb9aa6f1SThomas Gleixner pci_cache_line_size = 128 >> 2; /* P4 */ 371fb9aa6f1SThomas Gleixner 372fb9aa6f1SThomas Gleixner pcibios_resource_survey(); 373fb9aa6f1SThomas Gleixner 374fb9aa6f1SThomas Gleixner if (pci_bf_sort >= pci_force_bf) 375fb9aa6f1SThomas Gleixner pci_sort_breadthfirst(); 376fb9aa6f1SThomas Gleixner return 0; 377fb9aa6f1SThomas Gleixner } 378fb9aa6f1SThomas Gleixner 379fb9aa6f1SThomas Gleixner subsys_initcall(pcibios_init); 380fb9aa6f1SThomas Gleixner 381fb9aa6f1SThomas Gleixner char * __devinit pcibios_setup(char *str) 382fb9aa6f1SThomas Gleixner { 383fb9aa6f1SThomas Gleixner if (!strcmp(str, "off")) { 384fb9aa6f1SThomas Gleixner pci_probe = 0; 385fb9aa6f1SThomas Gleixner return NULL; 386fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "bfsort")) { 387fb9aa6f1SThomas Gleixner pci_bf_sort = pci_force_bf; 388fb9aa6f1SThomas Gleixner return NULL; 389fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "nobfsort")) { 390fb9aa6f1SThomas Gleixner pci_bf_sort = pci_force_nobf; 391fb9aa6f1SThomas Gleixner return NULL; 392fb9aa6f1SThomas Gleixner } 393fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_BIOS 394fb9aa6f1SThomas Gleixner else if (!strcmp(str, "bios")) { 395fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_BIOS; 396fb9aa6f1SThomas Gleixner return NULL; 397fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "nobios")) { 398fb9aa6f1SThomas Gleixner pci_probe &= ~PCI_PROBE_BIOS; 399fb9aa6f1SThomas Gleixner return NULL; 400fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "biosirq")) { 401fb9aa6f1SThomas Gleixner pci_probe |= PCI_BIOS_IRQ_SCAN; 402fb9aa6f1SThomas Gleixner return NULL; 403fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "pirqaddr=", 9)) { 404fb9aa6f1SThomas Gleixner pirq_table_addr = simple_strtoul(str+9, NULL, 0); 405fb9aa6f1SThomas Gleixner return NULL; 406fb9aa6f1SThomas Gleixner } 407fb9aa6f1SThomas Gleixner #endif 408fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_DIRECT 409fb9aa6f1SThomas Gleixner else if (!strcmp(str, "conf1")) { 410fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_CONF1 | PCI_NO_CHECKS; 411fb9aa6f1SThomas Gleixner return NULL; 412fb9aa6f1SThomas Gleixner } 413fb9aa6f1SThomas Gleixner else if (!strcmp(str, "conf2")) { 414fb9aa6f1SThomas Gleixner pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS; 415fb9aa6f1SThomas Gleixner return NULL; 416fb9aa6f1SThomas Gleixner } 417fb9aa6f1SThomas Gleixner #endif 418fb9aa6f1SThomas Gleixner #ifdef CONFIG_PCI_MMCONFIG 419fb9aa6f1SThomas Gleixner else if (!strcmp(str, "nommconf")) { 420fb9aa6f1SThomas Gleixner pci_probe &= ~PCI_PROBE_MMCONF; 421fb9aa6f1SThomas Gleixner return NULL; 422fb9aa6f1SThomas Gleixner } 423fb9aa6f1SThomas Gleixner #endif 424fb9aa6f1SThomas Gleixner else if (!strcmp(str, "noacpi")) { 425fb9aa6f1SThomas Gleixner acpi_noirq_set(); 426fb9aa6f1SThomas Gleixner return NULL; 427fb9aa6f1SThomas Gleixner } 428fb9aa6f1SThomas Gleixner else if (!strcmp(str, "noearly")) { 429fb9aa6f1SThomas Gleixner pci_probe |= PCI_PROBE_NOEARLY; 430fb9aa6f1SThomas Gleixner return NULL; 431fb9aa6f1SThomas Gleixner } 432fb9aa6f1SThomas Gleixner #ifndef CONFIG_X86_VISWS 433fb9aa6f1SThomas Gleixner else if (!strcmp(str, "usepirqmask")) { 434fb9aa6f1SThomas Gleixner pci_probe |= PCI_USE_PIRQ_MASK; 435fb9aa6f1SThomas Gleixner return NULL; 436fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "irqmask=", 8)) { 437fb9aa6f1SThomas Gleixner pcibios_irq_mask = simple_strtol(str+8, NULL, 0); 438fb9aa6f1SThomas Gleixner return NULL; 439fb9aa6f1SThomas Gleixner } else if (!strncmp(str, "lastbus=", 8)) { 440fb9aa6f1SThomas Gleixner pcibios_last_bus = simple_strtol(str+8, NULL, 0); 441fb9aa6f1SThomas Gleixner return NULL; 442fb9aa6f1SThomas Gleixner } 443fb9aa6f1SThomas Gleixner #endif 444fb9aa6f1SThomas Gleixner else if (!strcmp(str, "rom")) { 445fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ROMS; 446fb9aa6f1SThomas Gleixner return NULL; 447fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "assign-busses")) { 448fb9aa6f1SThomas Gleixner pci_probe |= PCI_ASSIGN_ALL_BUSSES; 449fb9aa6f1SThomas Gleixner return NULL; 45062f420f8SGary Hade } else if (!strcmp(str, "use_crs")) { 45162f420f8SGary Hade pci_probe |= PCI_USE__CRS; 45262f420f8SGary Hade return NULL; 453fb9aa6f1SThomas Gleixner } else if (!strcmp(str, "routeirq")) { 454fb9aa6f1SThomas Gleixner pci_routeirq = 1; 455fb9aa6f1SThomas Gleixner return NULL; 456fb9aa6f1SThomas Gleixner } 457fb9aa6f1SThomas Gleixner return str; 458fb9aa6f1SThomas Gleixner } 459fb9aa6f1SThomas Gleixner 460fb9aa6f1SThomas Gleixner unsigned int pcibios_assign_all_busses(void) 461fb9aa6f1SThomas Gleixner { 462fb9aa6f1SThomas Gleixner return (pci_probe & PCI_ASSIGN_ALL_BUSSES) ? 1 : 0; 463fb9aa6f1SThomas Gleixner } 464fb9aa6f1SThomas Gleixner 465fb9aa6f1SThomas Gleixner int pcibios_enable_device(struct pci_dev *dev, int mask) 466fb9aa6f1SThomas Gleixner { 467fb9aa6f1SThomas Gleixner int err; 468fb9aa6f1SThomas Gleixner 469b81d988cSBjorn Helgaas if ((err = pci_enable_resources(dev, mask)) < 0) 470fb9aa6f1SThomas Gleixner return err; 471fb9aa6f1SThomas Gleixner 472fb9aa6f1SThomas Gleixner if (!dev->msi_enabled) 473fb9aa6f1SThomas Gleixner return pcibios_enable_irq(dev); 474fb9aa6f1SThomas Gleixner return 0; 475fb9aa6f1SThomas Gleixner } 476fb9aa6f1SThomas Gleixner 477fb9aa6f1SThomas Gleixner void pcibios_disable_device (struct pci_dev *dev) 478fb9aa6f1SThomas Gleixner { 479fb9aa6f1SThomas Gleixner if (!dev->msi_enabled && pcibios_disable_irq) 480fb9aa6f1SThomas Gleixner pcibios_disable_irq(dev); 481fb9aa6f1SThomas Gleixner } 482fb9aa6f1SThomas Gleixner 4836871b76fSSam Ravnborg struct pci_bus *__devinit pci_scan_bus_with_sysdata(int busno) 484fb9aa6f1SThomas Gleixner { 485fb9aa6f1SThomas Gleixner struct pci_bus *bus = NULL; 486fb9aa6f1SThomas Gleixner struct pci_sysdata *sd; 487fb9aa6f1SThomas Gleixner 488fb9aa6f1SThomas Gleixner /* 489fb9aa6f1SThomas Gleixner * Allocate per-root-bus (not per bus) arch-specific data. 490fb9aa6f1SThomas Gleixner * TODO: leak; this memory is never freed. 491fb9aa6f1SThomas Gleixner * It's arguable whether it's worth the trouble to care. 492fb9aa6f1SThomas Gleixner */ 493fb9aa6f1SThomas Gleixner sd = kzalloc(sizeof(*sd), GFP_KERNEL); 494fb9aa6f1SThomas Gleixner if (!sd) { 495fb9aa6f1SThomas Gleixner printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno); 496fb9aa6f1SThomas Gleixner return NULL; 497fb9aa6f1SThomas Gleixner } 498fb9aa6f1SThomas Gleixner sd->node = -1; 499fb9aa6f1SThomas Gleixner bus = pci_scan_bus(busno, &pci_root_ops, sd); 500fb9aa6f1SThomas Gleixner if (!bus) 501fb9aa6f1SThomas Gleixner kfree(sd); 502fb9aa6f1SThomas Gleixner 503fb9aa6f1SThomas Gleixner return bus; 504fb9aa6f1SThomas Gleixner } 505