diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index c5ca313..4b281f2 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -136,7 +136,7 @@ static inline unsigned int pci_calc_resource_flags(unsigned int flags) /* * Find the extent of a PCI decode.. */ -static u32 pci_size(u32 base, u32 maxbase, u32 mask) +u32 pci_size(u32 base, u32 maxbase, u32 mask) { u32 size = mask & maxbase; /* Find the significant bits */ if (!size) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index a807797..c11477c 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -893,6 +893,55 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SATA, quirk_amd_ide_mode); +static void __devinit quirk_ahci_sata(struct pci_dev *pdev) +{ + int ret; + + u32 sir, newval; + u16 mode; + + /* Make sure we're in AHCI mode */ + pci_read_config_word(pdev, 0x90, &mode); + pci_write_config_word(pdev, 0x90, 0x40); + + /* Need to set the SCRAE bit */ + pci_read_config_dword(pdev, 0x94, &sir); + newval = (sir | 0x200); + pci_write_config_dword(pdev, 0x94, newval); + pdev->resource[5].flags = IORESOURCE_MEM; + ret = pci_allocate_resource(pdev, 5); + if (ret) { + printk (KERN_INFO "Failed to allocate AHCI BAR - %d\n", ret); + pci_write_config_word(pdev, 0x90, mode); + pci_write_config_dword(pdev, 0x94, sir); + return; + } + + /* Set PCI_CLASS_STORAGE_SATA */ + if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { + pci_write_config_byte(pdev, PCI_CLASS_PROG, 0x01); + pci_write_config_byte(pdev, PCI_CLASS_DEVICE, 0x06); + } + pdev->class = PCI_CLASS_STORAGE_SATA_AHCI; + printk (KERN_INFO "Quirked PIIX device to AHCI mode\n"); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2651, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2652, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2653, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2680, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x27c0, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x27c4, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2820, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2825, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2828, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2920, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2921, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2926, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2928, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x292d, quirk_ahci_sata); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x292e, quirk_ahci_sata); + /* * Serverworks CSB5 IDE does not fully support native mode */ diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 3771323..3da97d1 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -25,6 +25,60 @@ #include #include "pci.h" +int +pci_allocate_resource(struct pci_dev *dev, int resno) +{ + int err; + u32 size, mask, reg; + resource_size_t start; + struct resource *res = &dev->resource[resno]; + struct resource *bres = pci_find_parent_resource(dev, res); + + if (!bres) { + BUG(); + } + + if (!bres) + return -ENOMEM; + + if (res->flags & IORESOURCE_IO) { + mask = (u32)PCI_BASE_ADDRESS_IO_MASK; + start = PCIBIOS_MIN_IO; + } else { + mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; + start = PCIBIOS_MIN_MEM; + } + + if (resno < 6) + reg = PCI_BASE_ADDRESS_0 + 4 * resno; + else + return -EINVAL; + + pci_write_config_dword(dev, reg, ~0); + pci_read_config_dword(dev, reg, &size); + + if (!size || size == 0xffffffff) + return -EBUSY; + + size = pci_size(0, size, mask); + + if (res->start != 0 && res->end != 0) + release_resource (res); + + err = allocate_resource (bres, res, size+1, start, ~0U, 1024, NULL, + NULL); + + if (err) { + printk ("Failed to allocate a resource\n"); + return err; + } + + pci_update_resource (dev, res, resno); + + return 0; +} + +EXPORT_SYMBOL(pci_allocate_resource); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno) diff --git a/include/linux/pci.h b/include/linux/pci.h index 0dd93bb..2a1952f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -573,6 +573,7 @@ int pcix_get_mmrbc(struct pci_dev *dev); int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc); int pcie_get_readrq(struct pci_dev *dev); int pcie_set_readrq(struct pci_dev *dev, int rq); +int pci_allocate_resource(struct pci_dev *dev, int resno); void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno); int __must_check pci_assign_resource(struct pci_dev *dev, int i); int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i); @@ -635,6 +636,7 @@ void pci_unregister_driver(struct pci_driver *); void pci_remove_behind_bridge(struct pci_dev *); struct pci_driver *pci_dev_driver(const struct pci_dev *); const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev); +u32 pci_size(u32 base, u32 maxbase, u32 mask); int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass); void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),