diff options
Diffstat (limited to 'arch/x86/pci/fixup.c')
| -rw-r--r-- | arch/x86/pci/fixup.c | 240 |
1 files changed, 175 insertions, 65 deletions
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c index c82cbf4c722..b5e60268d93 100644 --- a/arch/x86/pci/fixup.c +++ b/arch/x86/pci/fixup.c @@ -5,11 +5,11 @@ #include <linux/delay.h> #include <linux/dmi.h> #include <linux/pci.h> -#include <linux/init.h> -#include "pci.h" +#include <linux/vgaarb.h> +#include <asm/hpet.h> +#include <asm/pci_x86.h> - -static void __devinit pci_fixup_i450nx(struct pci_dev *d) +static void pci_fixup_i450nx(struct pci_dev *d) { /* * i450NX -- Find and scan all secondary buses on all PXB's. @@ -17,23 +17,24 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d) int pxb, reg; u8 busno, suba, subb; - printk(KERN_WARNING "PCI: Searching for i450NX host bridges on %s\n", pci_name(d)); + dev_warn(&d->dev, "Searching for i450NX host bridges\n"); reg = 0xd0; - for(pxb=0; pxb<2; pxb++) { + for(pxb = 0; pxb < 2; pxb++) { pci_read_config_byte(d, reg++, &busno); pci_read_config_byte(d, reg++, &suba); pci_read_config_byte(d, reg++, &subb); - DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); + dev_dbg(&d->dev, "i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, + suba, subb); if (busno) - pci_scan_bus_with_sysdata(busno); /* Bus A */ + pcibios_scan_root(busno); /* Bus A */ if (suba < subb) - pci_scan_bus_with_sysdata(suba+1); /* Bus B */ + pcibios_scan_root(suba+1); /* Bus B */ } pcibios_last_bus = -1; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx); -static void __devinit pci_fixup_i450gx(struct pci_dev *d) +static void pci_fixup_i450gx(struct pci_dev *d) { /* * i450GX and i450KX -- Find and scan all secondary buses. @@ -41,13 +42,13 @@ static void __devinit pci_fixup_i450gx(struct pci_dev *d) */ u8 busno; pci_read_config_byte(d, 0x4a, &busno); - printk(KERN_INFO "PCI: i440KX/GX host bridge %s: secondary bus %02x\n", pci_name(d), busno); - pci_scan_bus_with_sysdata(busno); + dev_info(&d->dev, "i440KX/GX host bridge; secondary bus %02x\n", busno); + pcibios_scan_root(busno); pcibios_last_bus = -1; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, pci_fixup_i450gx); -static void __devinit pci_fixup_umc_ide(struct pci_dev *d) +static void pci_fixup_umc_ide(struct pci_dev *d) { /* * UM8886BF IDE controller sets region type bits incorrectly, @@ -55,38 +56,38 @@ static void __devinit pci_fixup_umc_ide(struct pci_dev *d) */ int i; - printk(KERN_WARNING "PCI: Fixing base address flags for device %s\n", pci_name(d)); - for(i=0; i<4; i++) + dev_warn(&d->dev, "Fixing base address flags\n"); + for(i = 0; i < 4; i++) d->resource[i].flags |= PCI_BASE_ADDRESS_SPACE_IO; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, pci_fixup_umc_ide); -static void __devinit pci_fixup_ncr53c810(struct pci_dev *d) +static void pci_fixup_ncr53c810(struct pci_dev *d) { /* * NCR 53C810 returns class code 0 (at least on some systems). * Fix class to be PCI_CLASS_STORAGE_SCSI */ if (!d->class) { - printk(KERN_WARNING "PCI: fixing NCR 53C810 class code for %s\n", pci_name(d)); + dev_warn(&d->dev, "Fixing NCR 53C810 class code\n"); d->class = PCI_CLASS_STORAGE_SCSI << 8; } } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, pci_fixup_ncr53c810); -static void __devinit pci_fixup_latency(struct pci_dev *d) +static void pci_fixup_latency(struct pci_dev *d) { /* * SiS 5597 and 5598 chipsets require latency timer set to * at most 32 to avoid lockups. */ - DBG("PCI: Setting max latency to 32\n"); + dev_dbg(&d->dev, "Setting max latency to 32\n"); pcibios_max_latency = 32; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, pci_fixup_latency); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5598, pci_fixup_latency); -static void __devinit pci_fixup_piix4_acpi(struct pci_dev *d) +static void pci_fixup_piix4_acpi(struct pci_dev *d) { /* * PIIX4 ACPI device: hardwired IRQ9 @@ -127,7 +128,7 @@ static void pci_fixup_via_northbridge_bug(struct pci_dev *d) NB latency to zero */ pci_write_config_byte(d, PCI_LATENCY_TIMER, 0); - where = 0x95; /* the memory write queue timer register is + where = 0x95; /* the memory write queue timer register is different for the KT266x's: 0x95 not 0x55 */ } else if (d->device == PCI_DEVICE_ID_VIA_8363_0 && (d->revision == VIA_8363_KL133_REVISION_ID || @@ -138,7 +139,7 @@ static void pci_fixup_via_northbridge_bug(struct pci_dev *d) pci_read_config_byte(d, where, &v); if (v & ~mask) { - printk(KERN_WARNING "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ + dev_warn(&d->dev, "Disabling VIA memory write queue (PCI ID %04x, rev %02x): [%02x] %02x & %02x -> %02x\n", \ d->device, d->revision, where, v, mask, v & mask); v &= mask; pci_write_config_byte(d, where, v); @@ -162,13 +163,13 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8367_0, pci_fixup_ * system to PCI bus no matter what are their window settings, so they are * "transparent" (or subtractive decoding) from programmers point of view. */ -static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev) +static void pci_fixup_transparent_bridge(struct pci_dev *dev) { - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && - (dev->device & 0xff00) == 0x2400) + if ((dev->device & 0xff00) == 0x2400) dev->transparent = 1; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixup_transparent_bridge); +DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + PCI_CLASS_BRIDGE_PCI, 8, pci_fixup_transparent_bridge); /* * Fixup for C1 Halt Disconnect problem on nForce2 systems. @@ -200,7 +201,7 @@ static void pci_fixup_nforce2(struct pci_dev *dev) * Apply fixup if needed, but don't touch disconnect state */ if ((val & 0x00FF0000) != 0x00010000) { - printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnect fixup\n"); + dev_warn(&dev->dev, "nForce2 C1 Halt Disconnect fixup\n"); pci_write_config_dword(dev, 0x6c, (val & 0xFF00FFFF) | 0x00010000); } } @@ -215,7 +216,8 @@ static int quirk_aspm_offset[MAX_PCIEROOT << 3]; static int quirk_pcie_aspm_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { - return raw_pci_ops->read(0, bus->number, devfn, where, size, value); + return raw_pci_read(pci_domain_nr(bus), bus->number, + devfn, where, size, value); } /* @@ -229,9 +231,10 @@ static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int wh offset = quirk_aspm_offset[GET_INDEX(bus->self->device, devfn)]; if ((offset) && (where == offset)) - value = value & 0xfffffffc; - - return raw_pci_ops->write(0, bus->number, devfn, where, size, value); + value = value & ~PCI_EXP_LNKCTL_ASPMC; + + return raw_pci_write(pci_domain_nr(bus), bus->number, + devfn, where, size, value); } static struct pci_ops quirk_pcie_aspm_ops = { @@ -249,7 +252,7 @@ static struct pci_ops quirk_pcie_aspm_ops = { */ static void pcie_rootport_aspm_quirk(struct pci_dev *pdev) { - int cap_base, i; + int i; struct pci_bus *pbus; struct pci_dev *dev; @@ -271,11 +274,11 @@ static void pcie_rootport_aspm_quirk(struct pci_dev *pdev) * after hot-remove, the pbus->devices is empty and this code * will set the offsets to zero and the bus ops to parent's bus * ops, which is unmodified. - */ - for (i= GET_INDEX(pdev->device, 0); i <= GET_INDEX(pdev->device, 7); ++i) + */ + for (i = GET_INDEX(pdev->device, 0); i <= GET_INDEX(pdev->device, 7); ++i) quirk_aspm_offset[i] = 0; - pbus->ops = pbus->parent->ops; + pci_bus_set_ops(pbus, pbus->parent->ops); } else { /* * If devices are attached to the root port at power-up or @@ -283,20 +286,22 @@ static void pcie_rootport_aspm_quirk(struct pci_dev *pdev) * each root port to save the register offsets and replace the * bus ops. */ - list_for_each_entry(dev, &pbus->devices, bus_list) { + list_for_each_entry(dev, &pbus->devices, bus_list) /* There are 0 to 8 devices attached to this bus */ - cap_base = pci_find_capability(dev, PCI_CAP_ID_EXP); - quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)]= cap_base + 0x10; - } - pbus->ops = &quirk_pcie_aspm_ops; + quirk_aspm_offset[GET_INDEX(pdev->device, dev->devfn)] = + dev->pcie_cap + PCI_EXP_LNKCTL; + + pci_bus_set_ops(pbus, &quirk_pcie_aspm_ops); + dev_info(&pbus->dev, "writes to ASPM control bits will be ignored\n"); } + } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA1, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk ); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA, pcie_rootport_aspm_quirk); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PA1, pcie_rootport_aspm_quirk); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB, pcie_rootport_aspm_quirk); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PB1, pcie_rootport_aspm_quirk); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_rootport_aspm_quirk); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk); /* * Fixup to mark boot BIOS video selected by BIOS before it changes @@ -309,20 +314,18 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_r * IORESOURCE_ROM_SHADOW is used to associate the boot video * card with this copy. On laptops this copy has to be used since * the main ROM may be compressed or combined with another image. - * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW - * is marked here since the boot video device will be the only enabled - * video device at this point. + * See pci_map_rom() for use of this flag. Before marking the device + * with IORESOURCE_ROM_SHADOW check if a vga_default_device is already set + * by either arch cde or vga-arbitration, if so only apply the fixup to this + * already determined primary video card. */ -static void __devinit pci_fixup_video(struct pci_dev *pdev) +static void pci_fixup_video(struct pci_dev *pdev) { struct pci_dev *bridge; struct pci_bus *bus; u16 config; - if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) - return; - /* Is VGA routed to us? */ bus = pdev->bus; while (bus) { @@ -335,9 +338,7 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev) * type BRIDGE, or CARDBUS. Host to PCI controllers use * PCI header type NORMAL. */ - if (bridge - &&((bridge->hdr_type == PCI_HEADER_TYPE_BRIDGE) - ||(bridge->hdr_type == PCI_HEADER_TYPE_CARDBUS))) { + if (bridge && (pci_is_bridge(bridge))) { pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &config); if (!(config & PCI_BRIDGE_CTL_VGA)) @@ -345,13 +346,64 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev) } bus = bus->parent; } - pci_read_config_word(pdev, PCI_COMMAND, &config); - if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { - pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; - printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev)); + if (!vga_default_device() || pdev == vga_default_device()) { + pci_read_config_word(pdev, PCI_COMMAND, &config); + if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) { + pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; + dev_printk(KERN_DEBUG, &pdev->dev, "Boot video device\n"); + vga_set_default_device(pdev); + } + } +} +DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_DISPLAY_VGA, 8, pci_fixup_video); + + +static const struct dmi_system_id msi_k8t_dmi_table[] = { + { + .ident = "MSI-K8T-Neo2Fir", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MSI"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-6702E"), + }, + }, + {} +}; + +/* + * The AMD-Athlon64 board MSI "K8T Neo2-FIR" disables the onboard sound + * card if a PCI-soundcard is added. + * + * The BIOS only gives options "DISABLED" and "AUTO". This code sets + * the corresponding register-value to enable the soundcard. + * + * The soundcard is only enabled, if the mainborad is identified + * via DMI-tables and the soundcard is detected to be off. + */ +static void pci_fixup_msi_k8t_onboard_sound(struct pci_dev *dev) +{ + unsigned char val; + if (!dmi_check_system(msi_k8t_dmi_table)) + return; /* only applies to MSI K8T Neo2-FIR */ + + pci_read_config_byte(dev, 0x50, &val); + if (val & 0x40) { + pci_write_config_byte(dev, 0x50, val & (~0x40)); + + /* verify the change for status output */ + pci_read_config_byte(dev, 0x50, &val); + if (val & 0x40) + dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; " + "can't enable onboard soundcard!\n"); + else + dev_info(&dev->dev, "Detected MSI K8T Neo2-FIR; " + "enabled onboard soundcard\n"); } } -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, + pci_fixup_msi_k8t_onboard_sound); +DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, + pci_fixup_msi_k8t_onboard_sound); /* * Some Toshiba laptops need extra code to enable their TI TSB43AB22/A. @@ -364,7 +416,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); */ static u16 toshiba_line_size; -static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = { +static const struct dmi_system_id toshiba_ohci1394_dmi_table[] = { { .ident = "Toshiba PS5 based laptop", .matches = { @@ -389,7 +441,7 @@ static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = { { } }; -static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev) +static void pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev) { if (!dmi_check_system(toshiba_ohci1394_dmi_table)) return; /* only applies to certain Toshibas (so far) */ @@ -400,7 +452,7 @@ static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev) DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0x8032, pci_pre_fixup_toshiba_ohci1394); -static void __devinit pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev) +static void pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev) { if (!dmi_check_system(toshiba_ohci1394_dmi_table)) return; /* only applies to certain Toshibas (so far) */ @@ -438,9 +490,67 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_LEGACY, * Siemens Nixdorf AG FSC Multiprocessor Interrupt Controller: * prevent update of the BAR0, which doesn't look like a normal BAR. */ -static void __devinit pci_siemens_interrupt_controller(struct pci_dev *dev) +static void pci_siemens_interrupt_controller(struct pci_dev *dev) { dev->resource[0].flags |= IORESOURCE_PCI_FIXED; } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015, pci_siemens_interrupt_controller); + +/* + * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from + * confusing the PCI engine: + */ +static void sb600_disable_hpet_bar(struct pci_dev *dev) +{ + u8 val; + + /* + * The SB600 and SB700 both share the same device + * ID, but the PM register 0x55 does something different + * for the SB700, so make sure we are dealing with the + * SB600 before touching the bit: + */ + + pci_read_config_byte(dev, 0x08, &val); + + if (val < 0x2F) { + outb(0x55, 0xCD6); + val = inb(0xCD7); + + /* Set bit 7 in PM register 0x55 */ + outb(0x55, 0xCD6); + outb(val | 0x80, 0xCD7); + } +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_ATI, 0x4385, sb600_disable_hpet_bar); + +#ifdef CONFIG_HPET_TIMER +static void sb600_hpet_quirk(struct pci_dev *dev) +{ + struct resource *r = &dev->resource[1]; + + if (r->flags & IORESOURCE_MEM && r->start == hpet_address) { + r->flags |= IORESOURCE_PCI_FIXED; + dev_info(&dev->dev, "reg 0x14 contains HPET; making it immovable\n"); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, 0x4385, sb600_hpet_quirk); +#endif + +/* + * Twinhead H12Y needs us to block out a region otherwise we map devices + * there and any access kills the box. + * + * See: https://bugzilla.kernel.org/show_bug.cgi?id=10231 + * + * Match off the LPC and svid/sdid (older kernels lose the bridge subvendor) + */ +static void twinhead_reserve_killing_zone(struct pci_dev *dev) +{ + if (dev->subsystem_vendor == 0x14FF && dev->subsystem_device == 0xA003) { + pr_info("Reserving memory on Twinhead H12Y\n"); + request_mem_region(0xFFB00000, 0x100000, "twinhead"); + } +} +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x27B9, twinhead_reserve_killing_zone); |
