Signed-off-by: Andrew Morton --- /dev/null | 62 ---- 25-akpm/Documentation/kernel-parameters.txt | 4 25-akpm/arch/i386/kernel/quirks.c | 4 25-akpm/arch/i386/pci/acpi.c | 30 +- 25-akpm/arch/i386/pci/common.c | 4 25-akpm/arch/i386/pci/fixup.c | 129 +++++++++ 25-akpm/arch/i386/pci/irq.c | 16 - 25-akpm/arch/ia64/pci/pci.c | 33 +- 25-akpm/drivers/atm/idt77252.c | 4 25-akpm/drivers/char/cyclades.c | 2 25-akpm/drivers/isdn/tpam/tpam_main.c | 4 25-akpm/drivers/misc/ibmasm/module.c | 6 25-akpm/drivers/net/tulip/de4x5.c | 4 25-akpm/drivers/pci/Makefile | 8 25-akpm/drivers/pci/hotplug/acpiphp_glue.c | 4 25-akpm/drivers/pci/hotplug/pciehp.h | 21 + 25-akpm/drivers/pci/hotplug/pciehp_core.c | 18 - 25-akpm/drivers/pci/hotplug/pciehp_ctrl.c | 387 +++++++++++++++++----------- 25-akpm/drivers/pci/hotplug/pciehp_hpc.c | 36 +- 25-akpm/drivers/pci/hotplug/pciehp_pci.c | 8 25-akpm/drivers/pci/hotplug/pciehprm_acpi.c | 43 ++- 25-akpm/drivers/pci/hotplug/shpchp_ctrl.c | 34 ++ 25-akpm/drivers/pci/hotplug/shpchp_hpc.c | 1 25-akpm/drivers/pci/pci-acpi.c | 209 +++++++++++++++ 25-akpm/drivers/pci/pci-driver.c | 15 - 25-akpm/drivers/pci/pci-sysfs.c | 120 ++++++++ 25-akpm/drivers/pci/pci.c | 12 25-akpm/drivers/pci/pci.h | 6 25-akpm/drivers/pci/probe.c | 5 25-akpm/drivers/pci/quirks.c | 18 - 25-akpm/drivers/pci/remove.c | 2 25-akpm/drivers/pci/rom.c | 225 ++++++++++++++++ 25-akpm/drivers/pci/setup-res.c | 2 25-akpm/include/asm-generic/vmlinux.lds.h | 3 25-akpm/include/linux/ioport.h | 5 25-akpm/include/linux/pci-acpi.h | 61 ++++ 25-akpm/include/linux/pci.h | 42 +-- 25-akpm/include/linux/pci_ids.h | 8 arch/i386/kernel/acpi/boot.c | 0 39 files changed, 1286 insertions(+), 309 deletions(-) diff -puN arch/i386/kernel/acpi/boot.c~bk-pci arch/i386/kernel/acpi/boot.c diff -puN arch/i386/kernel/quirks.c~bk-pci arch/i386/kernel/quirks.c --- 25/arch/i386/kernel/quirks.c~bk-pci 2004-11-09 01:18:58.767259992 -0800 +++ 25-akpm/arch/i386/kernel/quirks.c 2004-11-09 01:18:59.829098568 -0800 @@ -6,7 +6,7 @@ #if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP) -void __init quirk_intel_irqbalance(struct pci_dev *dev) +void __devinit quirk_intel_irqbalance(struct pci_dev *dev) { u8 config, rev; u32 word; @@ -45,5 +45,5 @@ void __init quirk_intel_irqbalance(struc } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_intel_irqbalance); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_intel_irqbalance); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_intel_irqbalance); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_intel_irqbalance); #endif diff -puN arch/i386/pci/acpi.c~bk-pci arch/i386/pci/acpi.c --- 25/arch/i386/pci/acpi.c~bk-pci 2004-11-09 01:18:58.769259688 -0800 +++ 25-akpm/arch/i386/pci/acpi.c 2004-11-09 01:18:59.829098568 -0800 @@ -15,6 +15,7 @@ struct pci_bus * __devinit pci_acpi_scan return pcibios_scan_root(busnum); } +extern int pci_routeirq; static int __init pci_acpi_init(void) { struct pci_dev *dev = NULL; @@ -30,14 +31,27 @@ static int __init pci_acpi_init(void) pcibios_scanned++; pcibios_enable_irq = acpi_pci_irq_enable; - /* - * PCI IRQ routing is set up by pci_enable_device(), but we - * also do it here in case there are still broken drivers that - * don't use pci_enable_device(). - */ - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) - acpi_pci_irq_enable(dev); - + if (pci_routeirq) { + /* + * PCI IRQ routing is set up by pci_enable_device(), but we + * also do it here in case there are still broken drivers that + * don't use pci_enable_device(). + */ + printk(KERN_INFO "** Routing PCI interrupts for all devices because \"pci=routeirq\"\n"); + printk(KERN_INFO "** was specified. If this was required to make a driver work,\n"); + printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n"); + printk(KERN_INFO "** so I can fix the driver.\n"); + while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) + acpi_pci_irq_enable(dev); + } else { + printk(KERN_INFO "** PCI interrupts are no longer routed automatically. If this\n"); + printk(KERN_INFO "** causes a device to stop working, it is probably because the\n"); + printk(KERN_INFO "** driver failed to call pci_enable_device(). As a temporary\n"); + printk(KERN_INFO "** workaround, the \"pci=routeirq\" argument restores the old\n"); + printk(KERN_INFO "** behavior. If this argument makes the device work again,\n"); + printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n"); + printk(KERN_INFO "** so I can fix the driver.\n"); + } #ifdef CONFIG_X86_IO_APIC if (acpi_ioapic) print_IO_APIC(); diff -L arch/i386/pci/changelog -puN arch/i386/pci/changelog~bk-pci /dev/null --- 25/arch/i386/pci/changelog +++ /dev/null 2003-09-15 06:40:47.000000000 -0700 @@ -1,62 +0,0 @@ -/* - * CHANGELOG : - * Jun 17, 1994 : Modified to accommodate the broken pre-PCI BIOS SPECIFICATION - * Revision 2.0 present on 's ASUS mainboard. - * - * Jan 5, 1995 : Modified to probe PCI hardware at boot time by Frederic - * Potter, potter@cao-vlsi.ibp.fr - * - * Jan 10, 1995 : Modified to store the information about configured pci - * devices into a list, which can be accessed via /proc/pci by - * Curtis Varner, cvarner@cs.ucr.edu - * - * Jan 12, 1995 : CPU-PCI bridge optimization support by Frederic Potter. - * Alpha version. Intel & UMC chipset support only. - * - * Apr 16, 1995 : Source merge with the DEC Alpha PCI support. Most of the code - * moved to drivers/pci/pci.c. - * - * Dec 7, 1996 : Added support for direct configuration access of boards - * with Intel compatible access schemes (tsbogend@alpha.franken.de) - * - * Feb 3, 1997 : Set internal functions to static, save/restore flags - * avoid dead locks reading broken PCI BIOS, werner@suse.de - * - * Apr 26, 1997 : Fixed case when there is BIOS32, but not PCI BIOS - * (mj@atrey.karlin.mff.cuni.cz) - * - * May 7, 1997 : Added some missing cli()'s. [mj] - * - * Jun 20, 1997 : Corrected problems in "conf1" type accesses. - * (paubert@iram.es) - * - * Aug 2, 1997 : Split to PCI BIOS handling and direct PCI access parts - * and cleaned it up... Martin Mares - * - * Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj] - * - * May 1, 1998 : Support for peer host bridges. [mj] - * - * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space - * can be accessed from interrupts even on SMP systems. [mj] - * - * August 1998 : Better support for peer host bridges and more paranoid - * checks for direct hardware access. Ugh, this file starts to look as - * a large gallery of common hardware bug workarounds (watch the comments) - * -- the PCI specs themselves are sane, but most implementors should be - * hit hard with \hammer scaled \magstep5. [mj] - * - * Jan 23, 1999 : More improvements to peer host bridge logic. i450NX fixup. [mj] - * - * Feb 8, 1999 : Added UM8886BF I/O address fixup. [mj] - * - * August 1999 : New resource management and configuration access stuff. [mj] - * - * Sep 19, 1999 : Use PCI IRQ routing tables for detection of peer host bridges. - * Based on ideas by Chris Frantz and David Hinds. [mj] - * - * Sep 28, 1999 : Handle unreported/unassigned IRQs. Thanks to Shuu Yamaguchi - * for a lot of patience during testing. [mj] - * - * Oct 8, 1999 : Split to pci-i386.c, pci-pc.c and pci-visws.c. [mj] - */ \ No newline at end of file diff -puN arch/i386/pci/common.c~bk-pci arch/i386/pci/common.c --- 25/arch/i386/pci/common.c~bk-pci 2004-11-09 01:18:58.772259232 -0800 +++ 25-akpm/arch/i386/pci/common.c 2004-11-09 01:18:59.831098264 -0800 @@ -23,6 +23,7 @@ extern void pcibios_sort(void); unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | PCI_PROBE_MMCONF; +int pci_routeirq; int pcibios_last_bus = -1; struct pci_bus *pci_root_bus = NULL; struct pci_raw_ops *raw_pci_ops; @@ -227,6 +228,9 @@ char * __devinit pcibios_setup(char *st } else if (!strcmp(str, "assign-busses")) { pci_probe |= PCI_ASSIGN_ALL_BUSSES; return NULL; + } else if (!strcmp(str, "routeirq")) { + pci_routeirq = 1; + return NULL; } return str; } diff -puN arch/i386/pci/fixup.c~bk-pci arch/i386/pci/fixup.c --- 25/arch/i386/pci/fixup.c~bk-pci 2004-11-09 01:18:58.773259080 -0800 +++ 25-akpm/arch/i386/pci/fixup.c 2004-11-09 01:18:59.832098112 -0800 @@ -255,3 +255,132 @@ static void __init pci_fixup_nforce2(str } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2, pci_fixup_nforce2); +/* Max PCI Express root ports */ +#define MAX_PCIEROOT 6 +static int quirk_aspm_offset[MAX_PCIEROOT << 3]; + +#define GET_INDEX(a, b) (((a - PCI_DEVICE_ID_INTEL_MCH_PA) << 3) + b) + +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); +} + +/* + * Replace the original pci bus ops for write with a new one that will filter + * the request to insure ASPM cannot be enabled. + */ +static int quirk_pcie_aspm_write(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value) +{ + u8 offset; + + 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); +} + +struct pci_ops quirk_pcie_aspm_ops = { + .read = quirk_pcie_aspm_read, + .write = quirk_pcie_aspm_write, +}; + +/* + * Prevents PCI Express ASPM (Active State Power Management) being enabled. + * + * Save the register offset, where the ASPM control bits are located, + * for each PCI Express device that is in the device list of + * the root port in an array for fast indexing. Replace the bus ops + * with the modified one. + */ +void pcie_rootport_aspm_quirk(struct pci_dev *pdev) +{ + int cap_base, i; + struct pci_bus *pbus; + struct pci_dev *dev; + + if ((pbus = pdev->subordinate) == NULL) + return; + + /* + * Check if the DID of pdev matches one of the six root ports. This + * check is needed in the case this function is called directly by the + * hot-plug driver. + */ + if ((pdev->device < PCI_DEVICE_ID_INTEL_MCH_PA) || + (pdev->device > PCI_DEVICE_ID_INTEL_MCH_PC1)) + return; + + if (list_empty(&pbus->devices)) { + /* + * If no device is attached to the root port at power-up or + * 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) + quirk_aspm_offset[i] = 0; + + pbus->ops = pbus->parent->ops; + } else { + /* + * If devices are attached to the root port at power-up or + * after hot-add, the code loops through the device list of + * each root port to save the register offsets and replace the + * bus ops. + */ + 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; + } +} +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 + * + * From information provided by "Jon Smirl" + * + * The standard boot ROM sequence for an x86 machine uses the BIOS + * to select an initial video card for boot display. This boot video + * card will have it's BIOS copied to C0000 in system RAM. + * 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. + * + */static void __devinit pci_fixup_video(struct pci_dev *pdev) +{ + struct pci_dev *bridge; + struct pci_bus *bus; + u16 l; + + if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA) + return; + + /* Is VGA routed to us? */ + bus = pdev->bus; + while (bus) { + bridge = bus->self; + if (bridge) { + pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &l); + if (!(l & PCI_BRIDGE_CTL_VGA)) + return; + } + bus = bus->parent; + } + pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW; +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); diff -puN arch/i386/pci/irq.c~bk-pci arch/i386/pci/irq.c --- 25/arch/i386/pci/irq.c~bk-pci 2004-11-09 01:18:58.775258776 -0800 +++ 25-akpm/arch/i386/pci/irq.c 2004-11-09 01:19:00.611979552 -0800 @@ -460,21 +460,17 @@ static int pirq_bios_set(struct pci_dev #endif - static __init int intel_router_probe(struct irq_router *r, struct pci_dev *router, u16 device) { - struct pci_dev *dev1, *dev2; + static struct pci_device_id pirq_440gx[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) }, + { }, + }; /* 440GX has a proprietary PIRQ router -- don't use it */ - dev1 = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82443GX_0, NULL); - dev2 = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82443GX_2, NULL); - if ((dev1 != NULL) || (dev2 != NULL)) { - pci_dev_put(dev1); - pci_dev_put(dev2); + if (pci_dev_present(pirq_440gx)) return 0; - } switch(device) { diff -puN arch/ia64/pci/pci.c~bk-pci arch/ia64/pci/pci.c --- 25/arch/ia64/pci/pci.c~bk-pci 2004-11-09 01:18:58.776258624 -0800 +++ 25-akpm/arch/ia64/pci/pci.c 2004-11-09 01:19:00.613979248 -0800 @@ -46,6 +46,8 @@ #define DBG(x...) #endif +static int pci_routeirq; + /* * Low-level SAL-based PCI configuration access functions. Note that SAL * calls are already serialized (via sal_lock), so we don't need another @@ -141,13 +143,28 @@ extern acpi_status acpi_map_iosapic (acp acpi_get_devices(NULL, acpi_map_iosapic, NULL, NULL); #endif - /* - * PCI IRQ routing is set up by pci_enable_device(), but we - * also do it here in case there are still broken drivers that - * don't use pci_enable_device(). - */ - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) - acpi_pci_irq_enable(dev); + + if (pci_routeirq) { + /* + * PCI IRQ routing is set up by pci_enable_device(), but we + * also do it here in case there are still broken drivers that + * don't use pci_enable_device(). + */ + printk(KERN_INFO "** Routing PCI interrupts for all devices because \"pci=routeirq\"\n"); + printk(KERN_INFO "** was specified. If this was required to make a driver work,\n"); + printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n"); + printk(KERN_INFO "** so I can fix the driver.\n"); + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) + acpi_pci_irq_enable(dev); + } else { + printk(KERN_INFO "** PCI interrupts are no longer routed automatically. If this\n"); + printk(KERN_INFO "** causes a device to stop working, it is probably because the\n"); + printk(KERN_INFO "** driver failed to call pci_enable_device(). As a temporary\n"); + printk(KERN_INFO "** workaround, the \"pci=routeirq\" argument restores the old\n"); + printk(KERN_INFO "** behavior. If this argument makes the device work again,\n"); + printk(KERN_INFO "** please email the output of \"lspci\" to bjorn.helgaas@hp.com\n"); + printk(KERN_INFO "** so I can fix the driver.\n"); + } return 0; } @@ -475,6 +492,8 @@ pcibios_align_resource (void *data, stru char * __init pcibios_setup (char *str) { + if (!strcmp(str, "routeirq")) + pci_routeirq = 1; return NULL; } diff -puN Documentation/kernel-parameters.txt~bk-pci Documentation/kernel-parameters.txt --- 25/Documentation/kernel-parameters.txt~bk-pci 2004-11-09 01:18:58.778258320 -0800 +++ 25-akpm/Documentation/kernel-parameters.txt 2004-11-09 01:18:58.831250264 -0800 @@ -940,6 +940,10 @@ running once the system is up. enabled. noacpi [IA-32] Do not use ACPI for IRQ routing or for PCI scanning. + routeirq Do IRQ routing for all PCI devices. + This is normally done in pci_enable_device(), + so this option is a temporary workaround + for broken drivers that don't call it. firmware [ARM] Do not re-enumerate the bus but instead just use the configuration diff -puN drivers/atm/idt77252.c~bk-pci drivers/atm/idt77252.c --- 25/drivers/atm/idt77252.c~bk-pci 2004-11-09 01:18:58.780258016 -0800 +++ 25-akpm/drivers/atm/idt77252.c 2004-11-09 01:19:00.615978944 -0800 @@ -3685,9 +3685,9 @@ idt77252_init_one(struct pci_dev *pcidev int i, err; - if (pci_enable_device(pcidev)) { + if ((err = pci_enable_device(pcidev))) { printk("idt77252: can't enable PCI device at %s\n", pci_name(pcidev)); - return -ENODEV; + return err; } if (pci_read_config_word(pcidev, PCI_REVISION_ID, &revision)) { diff -puN drivers/char/cyclades.c~bk-pci drivers/char/cyclades.c --- 25/drivers/char/cyclades.c~bk-pci 2004-11-09 01:18:58.782257712 -0800 +++ 25-akpm/drivers/char/cyclades.c 2004-11-09 01:19:00.620978184 -0800 @@ -4725,7 +4725,7 @@ cy_detect_pci(void) for (i = 0; i < NR_CARDS; i++) { /* look for a Cyclades card by vendor and device id */ while((device_id = cy_pci_dev_id[dev_index]) != 0) { - if((pdev = pci_find_device(PCI_VENDOR_ID_CYCLADES, + if((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES, device_id, pdev)) == NULL) { dev_index++; /* try next device id */ } else { diff -puN drivers/isdn/tpam/tpam_main.c~bk-pci drivers/isdn/tpam/tpam_main.c --- 25/drivers/isdn/tpam/tpam_main.c~bk-pci 2004-11-09 01:18:58.783257560 -0800 +++ 25-akpm/drivers/isdn/tpam/tpam_main.c 2004-11-09 01:19:00.620978184 -0800 @@ -88,10 +88,10 @@ static int __devinit tpam_probe(struct p tpam_card *card, *c; int i, err; - if (pci_enable_device(dev)) { + if ((err = pci_enable_device(dev))) { printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n", pci_name(dev)); - return -ENODEV; + return err; } /* allocate memory for the board structure */ diff -puN drivers/misc/ibmasm/module.c~bk-pci drivers/misc/ibmasm/module.c --- 25/drivers/misc/ibmasm/module.c~bk-pci 2004-11-09 01:18:58.785257256 -0800 +++ 25-akpm/drivers/misc/ibmasm/module.c 2004-11-09 01:19:00.621978032 -0800 @@ -59,13 +59,13 @@ static int __init ibmasm_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { - int result = -ENOMEM; + int err, result = -ENOMEM; struct service_processor *sp; - if (pci_enable_device(pdev)) { + if ((err = pci_enable_device(pdev))) { printk(KERN_ERR "%s: can't enable PCI device at %s\n", DRIVER_NAME, pci_name(pdev)); - return -ENODEV; + return err; } sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL); diff -puN drivers/net/tulip/de4x5.c~bk-pci drivers/net/tulip/de4x5.c --- 25/drivers/net/tulip/de4x5.c~bk-pci 2004-11-09 01:18:58.787256952 -0800 +++ 25-akpm/drivers/net/tulip/de4x5.c 2004-11-09 01:19:00.625977424 -0800 @@ -2242,8 +2242,8 @@ static int __devinit de4x5_pci_probe (st return -ENODEV; /* Ok, the device seems to be for us. */ - if (pci_enable_device (pdev)) - return -ENODEV; + if ((error = pci_enable_device (pdev))) + return error; if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) { error = -ENOMEM; diff -puN drivers/pci/hotplug/acpiphp_glue.c~bk-pci drivers/pci/hotplug/acpiphp_glue.c --- 25/drivers/pci/hotplug/acpiphp_glue.c~bk-pci 2004-11-09 01:18:58.788256800 -0800 +++ 25-akpm/drivers/pci/hotplug/acpiphp_glue.c 2004-11-09 01:19:00.627977120 -0800 @@ -389,7 +389,7 @@ static void add_host_bridge(acpi_handle bridge->pci_bus = pci_find_bus(seg, bus); - bridge->res_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&bridge->res_lock); /* to be overridden when we decode _CRS */ bridge->sub = bridge->bus; @@ -457,7 +457,7 @@ static void add_p2p_bridge(acpi_handle * return; } - bridge->res_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&bridge->res_lock); bridge->bus = bridge->pci_bus->number; bridge->sub = bridge->pci_bus->subordinate; diff -puN drivers/pci/hotplug/pciehp_core.c~bk-pci drivers/pci/hotplug/pciehp_core.c --- 25/drivers/pci/hotplug/pciehp_core.c~bk-pci 2004-11-09 01:18:58.790256496 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp_core.c 2004-11-09 01:19:00.629976816 -0800 @@ -204,11 +204,10 @@ static int get_ctlr_slot_config(struct c int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/ int first_device_num; /* Not needed */ int physical_slot_num; - int updown; /* Not needed */ + u8 ctrlcap; int rc; - int flags; /* Not needed */ - rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &updown, &flags); + rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap); if (rc) { err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device); return (-1); @@ -217,10 +216,10 @@ static int get_ctlr_slot_config(struct c ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */ ctrl->slot_device_offset = first_device_num; ctrl->first_slot = physical_slot_num; - ctrl->slot_num_inc = updown; /* Not needed */ /* either -1 or 1 */ + ctrl->ctrlcap = ctrlcap; - dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d (%x:%x)\n", - __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, updown, + dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n", + __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap, ctrl->bus, ctrl->device); return (0); @@ -237,7 +236,9 @@ static int set_attention_status(struct h dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); hotplug_slot->info->attention_status = status; - slot->hpc_ops->set_attention_status(slot, status); + + if (ATTN_LED(slot->ctrl->ctrlcap)) + slot->hpc_ops->set_attention_status(slot, status); return 0; } @@ -451,7 +452,8 @@ static int pcie_probe(struct pci_dev *pd t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ dbg("%s: adpater value %x\n", __FUNCTION__, value); - if (!value) { + + if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ if (rc) { /* Done with exclusive hardware access */ diff -puN drivers/pci/hotplug/pciehp_ctrl.c~bk-pci drivers/pci/hotplug/pciehp_ctrl.c --- 25/drivers/pci/hotplug/pciehp_ctrl.c~bk-pci 2004-11-09 01:18:58.792256192 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp_ctrl.c 2004-11-09 01:19:00.633976208 -0800 @@ -38,6 +38,7 @@ #include #include #include +#include "../pci.h" #include "pciehp.h" #include "pciehprm.h" @@ -51,6 +52,7 @@ static struct semaphore event_semaphore; static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ static int event_finished; static unsigned long pushbutton_pending; /* = 0 */ +static unsigned long surprise_rm_pending; /* = 0 */ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id) { @@ -1063,25 +1065,29 @@ static void set_slot_off(struct controll /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); - /* turn off slot, turn on Amber LED, turn off Green LED */ - if (pslot->hpc_ops->power_off_slot(pslot)) { - err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); - return; + /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ + if (POWER_CTRL(ctrl->ctrlcap)) { + if (pslot->hpc_ops->power_off_slot(pslot)) { + err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); + return; + } + wait_for_ctrl_irq (ctrl); } - wait_for_ctrl_irq (ctrl); - pslot->hpc_ops->green_led_off(pslot); - - wait_for_ctrl_irq (ctrl); + if (PWR_LED(ctrl->ctrlcap)) { + pslot->hpc_ops->green_led_off(pslot); + wait_for_ctrl_irq (ctrl); + } - /* turn on Amber LED */ - if (pslot->hpc_ops->set_attention_status(pslot, 1)) { - err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); - return; + if (ATTN_LED(ctrl->ctrlcap)) { + if (pslot->hpc_ops->set_attention_status(pslot, 1)) { + err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); + return; + } + wait_for_ctrl_irq (ctrl); } - wait_for_ctrl_irq (ctrl); /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -1112,20 +1118,24 @@ static u32 board_added(struct pci_func * /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); - /* Power on slot */ - rc = p_slot->hpc_ops->power_on_slot(p_slot); - if (rc) { - up(&ctrl->crit_sect); - return -1; - } + if (POWER_CTRL(ctrl->ctrlcap)) { + /* Power on slot */ + rc = p_slot->hpc_ops->power_on_slot(p_slot); + if (rc) { + up(&ctrl->crit_sect); + return -1; + } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } - p_slot->hpc_ops->green_led_blink(p_slot); + if (PWR_LED(ctrl->ctrlcap)) { + p_slot->hpc_ops->green_led_blink(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -1212,18 +1222,24 @@ static u32 board_added(struct pci_func * } } while (new_func); - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - p_slot->hpc_ops->green_led_on(p_slot); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); - + /* + * Some PCI Express root ports require fixup after hot-plug operation. + */ + if (pcie_mch_quirk) + pci_fixup_device(pci_fixup_final, ctrl->pci_dev); + + if (PWR_LED(ctrl->ctrlcap)) { + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); + + p_slot->hpc_ops->green_led_on(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } } else { set_slot_off(ctrl, p_slot); return -1; @@ -1289,21 +1305,25 @@ static u32 remove_board(struct pci_func /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); - /* power off slot */ - rc = p_slot->hpc_ops->power_off_slot(p_slot); - if (rc) { - err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); - up(&ctrl->crit_sect); - return rc; + if (POWER_CTRL(ctrl->ctrlcap)) { + /* power off slot */ + rc = p_slot->hpc_ops->power_off_slot(p_slot); + if (rc) { + err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); + return rc; + } + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - /* turn off Green LED */ - p_slot->hpc_ops->green_led_off(p_slot); + if (PWR_LED(ctrl->ctrlcap)) { + /* turn off Green LED */ + p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -1368,7 +1388,6 @@ static void pushbutton_helper_thread(uns up(&event_semaphore); } - /** * pciehp_pushbutton_thread * @@ -1399,7 +1418,55 @@ static void pciehp_pushbutton_thread(uns p_slot->state = POWERON_STATE; dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); - if (pciehp_enable_slot(p_slot)) { + if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { + /* Wait for exclusive access to hardware */ + down(&p_slot->ctrl->crit_sect); + + p_slot->hpc_ops->green_led_off(p_slot); + + /* Wait for the command to complete */ + wait_for_ctrl_irq (p_slot->ctrl); + + /* Done with exclusive hardware access */ + up(&p_slot->ctrl->crit_sect); + } + p_slot->state = STATIC_STATE; + } + + return; +} + +/** + * pciehp_surprise_rm_thread + * + * Scheduled procedure to handle blocking stuff for the surprise removal + * Handles all pending events and exits. + * + */ +static void pciehp_surprise_rm_thread(unsigned long slot) +{ + struct slot *p_slot = (struct slot *) slot; + u8 getstatus; + + surprise_rm_pending = 0; + + if (!p_slot) { + dbg("%s: Error! slot NULL\n", __FUNCTION__); + return; + } + + p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (!getstatus) { + p_slot->state = POWEROFF_STATE; + dbg("In removing board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); + + pciehp_disable_slot(p_slot); + p_slot->state = STATIC_STATE; + } else { + p_slot->state = POWERON_STATE; + dbg("In add_board, b:d(%x:%x)\n", p_slot->bus, p_slot->device); + + if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { /* Wait for exclusive access to hardware */ down(&p_slot->ctrl->crit_sect); @@ -1418,6 +1485,7 @@ static void pciehp_pushbutton_thread(uns } + /* this is the main worker thread */ static int event_thread(void* data) { @@ -1436,6 +1504,8 @@ static int event_thread(void* data) /* Do stuff here */ if (pushbutton_pending) pciehp_pushbutton_thread(pushbutton_pending); + else if (surprise_rm_pending) + pciehp_surprise_rm_thread(surprise_rm_pending); else for (ctrl = pciehp_ctrl_list; ctrl; ctrl=ctrl->next) interrupt_event_handler(ctrl); @@ -1528,16 +1598,18 @@ static void interrupt_event_handler(stru case BLINKINGOFF_STATE: /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); - - p_slot->hpc_ops->green_led_on(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - p_slot->hpc_ops->set_attention_status(p_slot, 0); - - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - + + if (PWR_LED(ctrl->ctrlcap)) { + p_slot->hpc_ops->green_led_on(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } + if (ATTN_LED(ctrl->ctrlcap)) { + p_slot->hpc_ops->set_attention_status(p_slot, 0); + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } /* Done with exclusive hardware access */ up(&ctrl->crit_sect); break; @@ -1545,14 +1617,16 @@ static void interrupt_event_handler(stru /* Wait for exclusive access to hardware */ down(&ctrl->crit_sect); - p_slot->hpc_ops->green_led_off(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - - p_slot->hpc_ops->set_attention_status(p_slot, 0); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - + if (PWR_LED(ctrl->ctrlcap)) { + p_slot->hpc_ops->green_led_off(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } + if (ATTN_LED(ctrl->ctrlcap)){ + p_slot->hpc_ops->set_attention_status(p_slot, 0); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } /* Done with exclusive hardware access */ up(&ctrl->crit_sect); @@ -1566,59 +1640,83 @@ static void interrupt_event_handler(stru } /* ***********Button Pressed (No action on 1st press...) */ else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { - dbg("Button pressed\n"); - - p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (getstatus) { - /* slot is on */ - dbg("slot is on\n"); - p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->number); - } else { - /* slot is off */ - dbg("slot is off\n"); - p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->number); - } - - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); - - /* blink green LED and turn off amber */ - p_slot->hpc_ops->green_led_blink(p_slot); - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); - p_slot->hpc_ops->set_attention_status(p_slot, 0); + if (ATTN_BUTTN(ctrl->ctrlcap)) { + dbg("Button pressed\n"); + p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (getstatus) { + /* slot is on */ + dbg("slot is on\n"); + p_slot->state = BLINKINGOFF_STATE; + info(msg_button_off, p_slot->number); + } else { + /* slot is off */ + dbg("slot is off\n"); + p_slot->state = BLINKINGON_STATE; + info(msg_button_on, p_slot->number); + } - /* Wait for the command to complete */ - wait_for_ctrl_irq (ctrl); + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + /* blink green LED and turn off amber */ + if (PWR_LED(ctrl->ctrlcap)) { + p_slot->hpc_ops->green_led_blink(p_slot); + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } + + if (ATTN_LED(ctrl->ctrlcap)) { + p_slot->hpc_ops->set_attention_status(p_slot, 0); + + /* Wait for the command to complete */ + wait_for_ctrl_irq (ctrl); + } + + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); - init_timer(&p_slot->task_event); - p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ - p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; - p_slot->task_event.data = (unsigned long) p_slot; + init_timer(&p_slot->task_event); + p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ + p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread; + p_slot->task_event.data = (unsigned long) p_slot; - dbg("add_timer p_slot = %p\n", (void *) p_slot); - add_timer(&p_slot->task_event); + dbg("add_timer p_slot = %p\n", (void *) p_slot); + add_timer(&p_slot->task_event); + } } /***********POWER FAULT********************/ else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { - dbg("power fault\n"); - /* Wait for exclusive access to hardware */ - down(&ctrl->crit_sect); + if (POWER_CTRL(ctrl->ctrlcap)) { + dbg("power fault\n"); + /* Wait for exclusive access to hardware */ + down(&ctrl->crit_sect); - p_slot->hpc_ops->set_attention_status(p_slot, 1); - wait_for_ctrl_irq (ctrl); - - p_slot->hpc_ops->green_led_off(p_slot); - wait_for_ctrl_irq (ctrl); + if (ATTN_LED(ctrl->ctrlcap)) { + p_slot->hpc_ops->set_attention_status(p_slot, 1); + wait_for_ctrl_irq (ctrl); + } + + if (PWR_LED(ctrl->ctrlcap)) { + p_slot->hpc_ops->green_led_off(p_slot); + wait_for_ctrl_irq (ctrl); + } - /* Done with exclusive hardware access */ - up(&ctrl->crit_sect); + /* Done with exclusive hardware access */ + up(&ctrl->crit_sect); + } + } + /***********SURPRISE REMOVAL********************/ + else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || + (ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) { + if (HP_SUPR_RM(ctrl->ctrlcap)) { + dbg("Surprise Removal\n"); + if (p_slot) { + surprise_rm_pending = (unsigned long) p_slot; + up(&event_semaphore); + update_slot_info(p_slot); + } + } } else { /* refresh notification */ if (p_slot) @@ -1648,25 +1746,29 @@ int pciehp_enable_slot(struct slot *p_sl /* Check to see if (latch closed, card present, power off) */ down(&p_slot->ctrl->crit_sect); + rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); up(&p_slot->ctrl->crit_sect); return 1; } - - rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - if (rc || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return 1; + if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + if (rc || getstatus) { + info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return 1; + } } - rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (rc || getstatus) { - info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return 1; + if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (rc || getstatus) { + info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return 1; + } } up(&p_slot->ctrl->crit_sect); @@ -1735,26 +1837,33 @@ int pciehp_disable_slot(struct slot *p_s /* Check to see if (latch closed, card present, power on) */ down(&p_slot->ctrl->crit_sect); - ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); - if (ret || !getstatus) { - info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return 1; + if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { + ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (ret || !getstatus) { + info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return 1; + } } - ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - if (ret || getstatus) { - info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return 1; + if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + if (ret || getstatus) { + info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return 1; + } } - ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (ret || !getstatus) { - info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); - up(&p_slot->ctrl->crit_sect); - return 1; + if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (ret || !getstatus) { + info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); + up(&p_slot->ctrl->crit_sect); + return 1; + } } + up(&p_slot->ctrl->crit_sect); func = pciehp_slot_find(p_slot->bus, p_slot->device, index++); diff -puN drivers/pci/hotplug/pciehp.h~bk-pci drivers/pci/hotplug/pciehp.h --- 25/drivers/pci/hotplug/pciehp.h~bk-pci 2004-11-09 01:18:58.793256040 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp.h 2004-11-09 01:19:00.628976968 -0800 @@ -127,8 +127,7 @@ struct controller { enum pci_bus_speed speed; u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ - u8 push_flag; - u16 ctlrcap; + u8 ctrlcap; u16 vendor_id; }; @@ -180,6 +179,21 @@ struct resource_lists { #define DISABLE_CARD 1 +/* Field definitions in Slot Capabilities Register */ +#define ATTN_BUTTN_PRSN 0x00000001 +#define PWR_CTRL_PRSN 0x00000002 +#define MRL_SENS_PRSN 0x00000004 +#define ATTN_LED_PRSN 0x00000008 +#define PWR_LED_PRSN 0x00000010 +#define HP_SUPR_RM_SUP 0x00000020 + +#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN) +#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN) +#define MRL_SENS(cap) (cap & MRL_SENS_PRSN) +#define ATTN_LED(cap) (cap & ATTN_LED_PRSN) +#define PWR_LED(cap) (cap & PWR_LED_PRSN) +#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) + /* * error Messages */ @@ -312,8 +326,7 @@ int pcie_get_ctlr_slot_config(struct con int *num_ctlr_slots, int *first_device_num, int *physical_slot_num, - int *updown, - int *flags); + u8 *ctrlcap); struct hpc_ops { int (*power_on_slot) (struct slot *slot); diff -puN drivers/pci/hotplug/pciehp_hpc.c~bk-pci drivers/pci/hotplug/pciehp_hpc.c --- 25/drivers/pci/hotplug/pciehp_hpc.c~bk-pci 2004-11-09 01:18:58.795255736 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp_hpc.c 2004-11-09 01:19:00.635975904 -0800 @@ -182,7 +182,7 @@ static int pcie_cap_base = 0; /* Base o #define MRL_SENS_PRSN 0x00000004 #define ATTN_LED_PRSN 0x00000008 #define PWR_LED_PRSN 0x00000010 -#define HP_SUPR_RM 0x00000020 +#define HP_SUPR_RM_SUP 0x00000020 #define HP_CAP 0x00000040 #define SLOT_PWR_VALUE 0x000003F8 #define SLOT_PWR_LIMIT 0x00000C00 @@ -237,8 +237,8 @@ struct php_ctlr_state_s { static spinlock_t hpc_event_lock; DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ -static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */ -static int ctlr_seq_num; /* Controller sequence # */ +static struct php_ctlr_state_s *php_ctlr_list_head = 0; /* HPC state linked list */ +static int ctlr_seq_num = 0; /* Controller sequence # */ static spinlock_t list_lock; static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs); @@ -691,8 +691,7 @@ int pcie_get_ctlr_slot_config(struct con int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */ int *first_device_num, /* PCI dev num of the first slot in this PCIE */ int *physical_slot_num, /* phy slot num of the first slot in this PCIE */ - int *updown, /* physical_slot_num increament: 1 or -1 */ - int *flags) + u8 *ctrlcap) { struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; u32 slot_cap; @@ -716,8 +715,9 @@ int pcie_get_ctlr_slot_config(struct con } *physical_slot_num = slot_cap >> 19; - - *updown = -1; + dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num); + + *ctrlcap = slot_cap & 0x0000007f; DBG_LEAVE_ROUTINE return 0; @@ -741,6 +741,8 @@ static void hpc_release_ctlr(struct cont if (php_ctlr->irq) { free_irq(php_ctlr->irq, ctrl); php_ctlr->irq = 0; + if (!pcie_mch_quirk) + pci_disable_msi(php_ctlr->pci_dev); } } if (php_ctlr->pci_dev) @@ -1259,7 +1261,7 @@ int pcie_init(struct controller * ctrl, static int first = 1; u16 temp_word; u16 cap_reg; - u16 intr_enable; + u16 intr_enable = 0; u32 slot_cap; int cap_base, saved_cap_base; u16 slot_status, slot_ctrl; @@ -1402,8 +1404,8 @@ int pcie_init(struct controller * ctrl, start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */ } else { /* Installs the interrupt handler */ - dbg("%s: pciehp_msi_quirk = %x\n", __FUNCTION__, pciehp_msi_quirk); - if (!pciehp_msi_quirk) { + dbg("%s: pcie_mch_quirk = %x\n", __FUNCTION__, pcie_mch_quirk); + if (!pcie_mch_quirk) { rc = pci_enable_msi(pdev); if (rc) { info("Can't get msi for the hotplug controller\n"); @@ -1412,6 +1414,7 @@ int pcie_init(struct controller * ctrl, } else php_ctlr->irq = pdev->irq; } + rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl); dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc); if (rc) { @@ -1426,9 +1429,18 @@ int pcie_init(struct controller * ctrl, goto abort_free_ctlr; } dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word); + dbg("%s: slot_cap %x\n", __FUNCTION__, slot_cap); - intr_enable = ATTN_BUTTN_ENABLE | PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE; + intr_enable = intr_enable | PRSN_DETECT_ENABLE; + + if (ATTN_BUTTN(slot_cap)) + intr_enable = intr_enable | ATTN_BUTTN_ENABLE; + + if (POWER_CTRL(slot_cap)) + intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; + + if (MRL_SENS(slot_cap)) + intr_enable = intr_enable | MRL_DETECT_ENABLE; temp_word = (temp_word & ~intr_enable) | intr_enable; diff -puN drivers/pci/hotplug/pciehp_pci.c~bk-pci drivers/pci/hotplug/pciehp_pci.c --- 25/drivers/pci/hotplug/pciehp_pci.c~bk-pci 2004-11-09 01:18:58.796255584 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp_pci.c 2004-11-09 01:19:00.636975752 -0800 @@ -82,9 +82,11 @@ int pciehp_unconfigure_device(struct pci { int rc = 0; int j; + struct pci_bus *pbus; dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function); + pbus = func->pci_dev->bus; for (j=0; j<8 ; j++) { struct pci_dev* temp = pci_find_slot(func->bus, @@ -93,6 +95,12 @@ int pciehp_unconfigure_device(struct pci pci_remove_bus_device(temp); } } + /* + * Some PCI Express root ports require fixup after hot-plug operation. + */ + if (pcie_mch_quirk) + pci_fixup_device(pci_fixup_final, pbus->self); + return rc; } diff -puN drivers/pci/hotplug/pciehprm_acpi.c~bk-pci drivers/pci/hotplug/pciehprm_acpi.c --- 25/drivers/pci/hotplug/pciehprm_acpi.c~bk-pci 2004-11-09 01:18:58.798255280 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehprm_acpi.c 2004-11-09 01:19:00.638975448 -0800 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_IA64 @@ -50,6 +51,14 @@ #define METHOD_NAME__HPP "_HPP" #define METHOD_NAME_OSHP "OSHP" +/* Status code for running acpi method to gain native control */ +#define NC_NOT_RUN 0 +#define OSC_NOT_EXIST 1 +#define OSC_RUN_FAILED 2 +#define OSHP_NOT_EXIST 3 +#define OSHP_RUN_FAILED 4 +#define NC_RUN_SUCCESS 5 + #define PHP_RES_BUS 0xA0 #define PHP_RES_IO 0xA1 #define PHP_RES_MEM 0xA2 @@ -125,7 +134,9 @@ static u8 * acpi_path_name( acpi_handle } static void acpi_get__hpp ( struct acpi_bridge *ab); -static void acpi_run_oshp ( struct acpi_bridge *ab); +static int acpi_run_oshp ( struct acpi_bridge *ab); +static int osc_run_status = NC_NOT_RUN; +static int oshp_run_status = NC_NOT_RUN; static int acpi_add_slot_to_php_slots( struct acpi_bridge *ab, @@ -158,8 +169,9 @@ static int acpi_add_slot_to_php_slots( ab->scanned += 1; if (!ab->_hpp) acpi_get__hpp(ab); - - acpi_run_oshp(ab); + + if (osc_run_status == OSC_NOT_EXIST) + oshp_run_status = acpi_run_oshp(ab); if (sun != samesun) { info("acpi_pciehprm: Slot sun(%x) at s:b:d:f=0x%02x:%02x:%02x:%02x\n", @@ -238,7 +250,7 @@ free_and_return: kfree(ret_buf.pointer); } -static void acpi_run_oshp ( struct acpi_bridge *ab) +static int acpi_run_oshp ( struct acpi_bridge *ab) { acpi_status status; u8 *path_name = acpi_path_name(ab->handle); @@ -248,9 +260,13 @@ static void acpi_run_oshp ( struct acpi_ status = acpi_evaluate_object(ab->handle, METHOD_NAME_OSHP, NULL, &ret_buf); if (ACPI_FAILURE(status)) { err("acpi_pciehprm:%s OSHP fails=0x%x\n", path_name, status); - } else + oshp_run_status = (status == AE_NOT_FOUND) ? OSHP_NOT_EXIST : OSHP_RUN_FAILED; + } else { + oshp_run_status = NC_RUN_SUCCESS; dbg("acpi_pciehprm:%s OSHP passes =0x%x\n", path_name, status); - return; + dbg("acpi_pciehprm:%s oshp_run_status =0x%x\n", path_name, oshp_run_status); + } + return oshp_run_status; } static acpi_status acpi_evaluate_crs( @@ -1056,6 +1072,16 @@ static struct acpi_bridge * add_host_bri kfree(ab); return NULL; } + + status = pci_osc_control_set (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL); + if (ACPI_FAILURE(status)) { + err("%s: status %x\n", __FUNCTION__, status); + osc_run_status = (status == AE_NOT_FOUND) ? OSC_NOT_EXIST : OSC_RUN_FAILED; + } else { + osc_run_status = NC_RUN_SUCCESS; + } + dbg("%s: osc_run_status %x\n", __FUNCTION__, osc_run_status); + build_a_bridge(ab, ab); return ab; @@ -1141,6 +1167,11 @@ int pciehprm_init(enum php_ctlr_type ctl if (rc) return rc; + if ((oshp_run_status != NC_RUN_SUCCESS) && (osc_run_status != NC_RUN_SUCCESS)) { + err("Fails to gain control of native hot-plug\n"); + rc = -ENODEV; + } + dbg("pciehprm ACPI init %s\n", (rc)?"fail":"success"); return rc; } diff -puN drivers/pci/hotplug/shpchp_ctrl.c~bk-pci drivers/pci/hotplug/shpchp_ctrl.c --- 25/drivers/pci/hotplug/shpchp_ctrl.c~bk-pci 2004-11-09 01:18:58.799255128 -0800 +++ 25-akpm/drivers/pci/hotplug/shpchp_ctrl.c 2004-11-09 01:19:00.640975144 -0800 @@ -1157,6 +1157,40 @@ static u32 board_added(struct pci_func * return -1; } + + if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) { + if (slots_not_empty) + return WRONG_BUS_FREQUENCY; + + if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { + err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + wait_for_ctrl_irq (ctrl); + + if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { + err("%s: Can't set bus speed/mode in the case of adapter & bus mismatch\n", + __FUNCTION__); + err("%s: Error code (%d)\n", __FUNCTION__, rc); + up(&ctrl->crit_sect); + return WRONG_BUS_FREQUENCY; + } + /* turn on board, blink green LED, turn off Amber LED */ + if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { + err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); + up(&ctrl->crit_sect); + return rc; + } + wait_for_ctrl_irq (ctrl); + + if ((rc = p_slot->hpc_ops->check_cmd_status(ctrl))) { + err("%s: Failed to enable slot, error code(%d)\n", __FUNCTION__, rc); + up(&ctrl->crit_sect); + return rc; + } + } + rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &adapter_speed); /* 0 = PCI 33Mhz, 1 = PCI 66 Mhz, 2 = PCI-X 66 PA, 4 = PCI-X 66 ECC, */ /* 5 = PCI-X 133 PA, 7 = PCI-X 133 ECC, 0xa = PCI-X 133 Mhz 266, */ diff -puN drivers/pci/hotplug/shpchp_hpc.c~bk-pci drivers/pci/hotplug/shpchp_hpc.c --- 25/drivers/pci/hotplug/shpchp_hpc.c~bk-pci 2004-11-09 01:18:58.801254824 -0800 +++ 25-akpm/drivers/pci/hotplug/shpchp_hpc.c 2004-11-09 01:19:00.642974840 -0800 @@ -792,6 +792,7 @@ static void hpc_release_ctlr(struct cont if (php_ctlr->irq) { free_irq(php_ctlr->irq, ctrl); php_ctlr->irq = 0; + pci_disable_msi(php_ctlr->pci_dev); } } if (php_ctlr->pci_dev) { diff -puN drivers/pci/Makefile~bk-pci drivers/pci/Makefile --- 25/drivers/pci/Makefile~bk-pci 2004-11-09 01:18:58.802254672 -0800 +++ 25-akpm/drivers/pci/Makefile 2004-11-09 01:19:00.626977272 -0800 @@ -3,7 +3,8 @@ # obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ - names.o pci-driver.o search.o pci-sysfs.o + names.o pci-driver.o search.o pci-sysfs.o \ + rom.o obj-$(CONFIG_PROC_FS) += proc.o ifndef CONFIG_SPARC64 @@ -28,6 +29,11 @@ obj-$(CONFIG_MIPS) += setup-bus.o setup- obj-$(CONFIG_X86_VISWS) += setup-irq.o obj-$(CONFIG_PCI_MSI) += msi.o +# +# ACPI Related PCI FW Functions +# +obj-$(CONFIG_ACPI) += pci-acpi.o + # Cardbus & CompactPCI use setup-bus obj-$(CONFIG_HOTPLUG) += setup-bus.o diff -puN /dev/null drivers/pci/pci-acpi.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/pci/pci-acpi.c 2004-11-09 01:19:00.643974688 -0800 @@ -0,0 +1,209 @@ +/* + * File: pci-acpi.c + * Purpose: Provide PCI supports in ACPI + * + * Copyright (C) 2004 Intel + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static u32 ctrlset_buf[3] = {0, 0, 0}; +static u32 global_ctrlsets = 0; +u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; + +static acpi_status +acpi_query_osc ( + acpi_handle handle, + u32 level, + void *context, + void **retval ) +{ + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[4]; + struct acpi_buffer output; + union acpi_object out_obj; + u32 osc_dw0; + + /* Setting up output buffer */ + output.length = sizeof(out_obj) + 3*sizeof(u32); + output.pointer = &out_obj; + + /* Setting up input parameters */ + input.count = 4; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = 16; + in_params[0].buffer.pointer = OSC_UUID; + in_params[1].type = ACPI_TYPE_INTEGER; + in_params[1].integer.value = 1; + in_params[2].type = ACPI_TYPE_INTEGER; + in_params[2].integer.value = 3; + in_params[3].type = ACPI_TYPE_BUFFER; + in_params[3].buffer.length = 12; + in_params[3].buffer.pointer = (u8 *)context; + + status = acpi_evaluate_object(handle, "_OSC", &input, &output); + if (ACPI_FAILURE (status)) { + printk(KERN_DEBUG + "Evaluate _OSC Set fails. Status = 0x%04x\n", status); + return status; + } + if (out_obj.type != ACPI_TYPE_BUFFER) { + printk(KERN_DEBUG + "Evaluate _OSC returns wrong type\n"); + return AE_TYPE; + } + osc_dw0 = *((u32 *) out_obj.buffer.pointer); + if (osc_dw0) { + if (osc_dw0 & OSC_REQUEST_ERROR) + printk(KERN_DEBUG "_OSC request fails\n"); + if (osc_dw0 & OSC_INVALID_UUID_ERROR) + printk(KERN_DEBUG "_OSC invalid UUID\n"); + if (osc_dw0 & OSC_INVALID_REVISION_ERROR) + printk(KERN_DEBUG "_OSC invalid revision\n"); + if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { + /* Update Global Control Set */ + global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8)); + return AE_OK; + } + return AE_ERROR; + } + + /* Update Global Control Set */ + global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8)); + return AE_OK; +} + + +static acpi_status +acpi_run_osc ( + acpi_handle handle, + u32 level, + void *context, + void **retval ) +{ + acpi_status status; + struct acpi_object_list input; + union acpi_object in_params[4]; + struct acpi_buffer output; + union acpi_object out_obj; + u32 osc_dw0; + + /* Setting up output buffer */ + output.length = sizeof(out_obj) + 3*sizeof(u32); + output.pointer = &out_obj; + + /* Setting up input parameters */ + input.count = 4; + input.pointer = in_params; + in_params[0].type = ACPI_TYPE_BUFFER; + in_params[0].buffer.length = 16; + in_params[0].buffer.pointer = OSC_UUID; + in_params[1].type = ACPI_TYPE_INTEGER; + in_params[1].integer.value = 1; + in_params[2].type = ACPI_TYPE_INTEGER; + in_params[2].integer.value = 3; + in_params[3].type = ACPI_TYPE_BUFFER; + in_params[3].buffer.length = 12; + in_params[3].buffer.pointer = (u8 *)context; + + status = acpi_evaluate_object(handle, "_OSC", &input, &output); + if (ACPI_FAILURE (status)) { + printk(KERN_DEBUG + "Evaluate _OSC Set fails. Status = 0x%04x\n", status); + return status; + } + if (out_obj.type != ACPI_TYPE_BUFFER) { + printk(KERN_DEBUG + "Evaluate _OSC returns wrong type\n"); + return AE_TYPE; + } + osc_dw0 = *((u32 *) out_obj.buffer.pointer); + if (osc_dw0) { + if (osc_dw0 & OSC_REQUEST_ERROR) + printk(KERN_DEBUG "_OSC request fails\n"); + if (osc_dw0 & OSC_INVALID_UUID_ERROR) + printk(KERN_DEBUG "_OSC invalid UUID\n"); + if (osc_dw0 & OSC_INVALID_REVISION_ERROR) + printk(KERN_DEBUG "_OSC invalid revision\n"); + if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { + printk(KERN_DEBUG "_OSC FW not grant req. control\n"); + return AE_SUPPORT; + } + return AE_ERROR; + } + return AE_OK; +} + +/** + * pci_osc_support_set - register OS support to Firmware + * @flags: OS support bits + * + * Update OS support fields and doing a _OSC Query to obtain an update + * from Firmware on supported control bits. + **/ +acpi_status pci_osc_support_set(u32 flags) +{ + u32 temp; + + if (!(flags & OSC_SUPPORT_MASKS)) { + return AE_TYPE; + } + ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS); + + /* do _OSC query for all possible controls */ + temp = ctrlset_buf[OSC_CONTROL_TYPE]; + ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; + ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; + acpi_get_devices ( PCI_ROOT_HID_STRING, + acpi_query_osc, + ctrlset_buf, + NULL ); + ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE; + ctrlset_buf[OSC_CONTROL_TYPE] = temp; + return AE_OK; +} +EXPORT_SYMBOL(pci_osc_support_set); + +/** + * pci_osc_control_set - commit requested control to Firmware + * @flags: driver's requested control bits + * + * Attempt to take control from Firmware on requested control bits. + **/ +acpi_status pci_osc_control_set(u32 flags) +{ + acpi_status status; + u32 ctrlset; + + ctrlset = (flags & OSC_CONTROL_MASKS); + if (!ctrlset) { + return AE_TYPE; + } + if (ctrlset_buf[OSC_SUPPORT_TYPE] && + ((global_ctrlsets & ctrlset) != ctrlset)) { + return AE_SUPPORT; + } + ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset; + status = acpi_get_devices ( PCI_ROOT_HID_STRING, + acpi_run_osc, + ctrlset_buf, + NULL ); + if (ACPI_FAILURE (status)) { + ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset; + } + + return status; +} +EXPORT_SYMBOL(pci_osc_control_set); diff -puN drivers/pci/pci.c~bk-pci drivers/pci/pci.c --- 25/drivers/pci/pci.c~bk-pci 2004-11-09 01:18:58.804254368 -0800 +++ 25-akpm/drivers/pci/pci.c 2004-11-09 01:19:00.646974232 -0800 @@ -375,6 +375,16 @@ pci_enable_device(struct pci_dev *dev) } /** + * pcibios_disable_device - disable arch specific PCI resources for device dev + * @dev: the PCI device to disable + * + * Disables architecture specific PCI resources for the device. This + * is the default implementation. Architecture implementations can + * override this. + */ +void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {} + +/** * pci_disable_device - Disable PCI device after use * @dev: PCI device to be disabled * @@ -394,6 +404,8 @@ pci_disable_device(struct pci_dev *dev) pci_command &= ~PCI_COMMAND_MASTER; pci_write_config_word(dev, PCI_COMMAND, pci_command); } + + pcibios_disable_device(dev); } /** diff -puN drivers/pci/pci-driver.c~bk-pci drivers/pci/pci-driver.c --- 25/drivers/pci/pci-driver.c~bk-pci 2004-11-09 01:18:58.805254216 -0800 +++ 25-akpm/drivers/pci/pci-driver.c 2004-11-09 01:19:00.644974536 -0800 @@ -271,17 +271,14 @@ static int pci_device_remove(struct devi pci_dev->driver = NULL; } -#ifdef CONFIG_DEBUG_KERNEL /* - * If the driver decides to stop using the device, it should - * call pci_disable_device(). + * We would love to complain here if pci_dev->is_enabled is set, that + * the driver should have called pci_disable_device(), but the + * unfortunate fact is there are too many odd BIOS and bridge setups + * that don't like drivers doing that all of the time. + * Oh well, we can dream of sane hardware when we sleep, no matter how + * horrible the crap we have to deal with is when we are awake... */ - if (pci_dev->is_enabled) { - dev_warn(&pci_dev->dev, "Device was removed without properly " - "calling pci_disable_device(). This may need fixing.\n"); - /* WARN_ON(1); */ - } -#endif /* CONFIG_DEBUG_KERNEL */ pci_dev_put(pci_dev); return 0; diff -puN drivers/pci/pci.h~bk-pci drivers/pci/pci.h --- 25/drivers/pci/pci.h~bk-pci 2004-11-09 01:18:58.807253912 -0800 +++ 25-akpm/drivers/pci/pci.h 2004-11-09 01:19:00.646974232 -0800 @@ -2,7 +2,9 @@ extern int pci_hotplug (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); -extern void pci_create_sysfs_dev_files(struct pci_dev *pdev); +extern int pci_create_sysfs_dev_files(struct pci_dev *pdev); +extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev); +extern void pci_cleanup_rom(struct pci_dev *dev); extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, unsigned long size, unsigned long align, unsigned long min, unsigned int type_mask, @@ -61,7 +63,7 @@ extern int pci_visit_dev(struct pci_visi /* Lock for read/write access to pci device and bus lists */ extern spinlock_t pci_bus_lock; -extern int pciehp_msi_quirk; +extern int pcie_mch_quirk; extern struct device_attribute pci_dev_attrs[]; /** diff -puN drivers/pci/pci-sysfs.c~bk-pci drivers/pci/pci-sysfs.c --- 25/drivers/pci/pci-sysfs.c~bk-pci 2004-11-09 01:18:58.808253760 -0800 +++ 25-akpm/drivers/pci/pci-sysfs.c 2004-11-09 01:19:00.645974384 -0800 @@ -5,6 +5,8 @@ * (C) Copyright 2002-2004 IBM Corp. * (C) Copyright 2003 Matthew Wilcox * (C) Copyright 2003 Hewlett-Packard + * (C) Copyright 2004 Jon Smirl + * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes * * File attributes for PCI devices * @@ -20,6 +22,8 @@ #include "pci.h" +static int sysfs_initialized; /* = 0 */ + /* show configuration fields */ #define pci_config_attr(field, format_string) \ static ssize_t \ @@ -164,6 +168,65 @@ pci_write_config(struct kobject *kobj, c return count; } +/** + * pci_write_rom - used to enable access to the PCI ROM display + * @kobj: kernel object handle + * @buf: user input + * @off: file offset + * @count: number of byte in input + * + * writing anything except 0 enables it + */ +static ssize_t +pci_write_rom(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); + + if ((off == 0) && (*buf == '0') && (count == 2)) + pdev->rom_attr_enabled = 0; + else + pdev->rom_attr_enabled = 1; + + return count; +} + +/** + * pci_read_rom - read a PCI ROM + * @kobj: kernel object handle + * @buf: where to put the data we read from the ROM + * @off: file offset + * @count: number of bytes to read + * + * Put @count bytes starting at @off into @buf from the ROM in the PCI + * device corresponding to @kobj. + */ +static ssize_t +pci_read_rom(struct kobject *kobj, char *buf, loff_t off, size_t count) +{ + struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); + void __iomem *rom; + size_t size; + + if (!pdev->rom_attr_enabled) + return -EINVAL; + + rom = pci_map_rom(pdev, &size); /* size starts out as PCI window size */ + if (!rom) + return 0; + + if (off >= size) + count = 0; + else { + if (off + count > size) + count = size - off; + + memcpy_fromio(buf, rom + off, count); + } + pci_unmap_rom(pdev, rom); + + return count; +} + static struct bin_attribute pci_config_attr = { .attr = { .name = "config", @@ -186,13 +249,68 @@ static struct bin_attribute pcie_config_ .write = pci_write_config, }; -void pci_create_sysfs_dev_files (struct pci_dev *pdev) +int pci_create_sysfs_dev_files (struct pci_dev *pdev) { + if (!sysfs_initialized) + return -EACCES; + if (pdev->cfg_size < 4096) sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); else sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); + /* If the device has a ROM, try to expose it in sysfs. */ + if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { + struct bin_attribute *rom_attr; + + rom_attr = kmalloc(sizeof(*rom_attr), GFP_ATOMIC); + if (rom_attr) { + pdev->rom_attr = rom_attr; + rom_attr->size = pci_resource_len(pdev, PCI_ROM_RESOURCE); + rom_attr->attr.name = "rom"; + rom_attr->attr.mode = S_IRUSR; + rom_attr->attr.owner = THIS_MODULE; + rom_attr->read = pci_read_rom; + rom_attr->write = pci_write_rom; + sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); + } + } /* add platform-specific attributes */ pcibios_add_platform_entries(pdev); + + return 0; +} + +/** + * pci_remove_sysfs_dev_files - cleanup PCI specific sysfs files + * @pdev: device whose entries we should free + * + * Cleanup when @pdev is removed from sysfs. + */ +void pci_remove_sysfs_dev_files(struct pci_dev *pdev) +{ + if (pdev->cfg_size < 4096) + sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); + else + sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); + + if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { + if (pdev->rom_attr) { + sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); + kfree(pdev->rom_attr); + } + } } + +static int __init pci_sysfs_init(void) +{ + struct pci_dev *pdev = NULL; + + sysfs_initialized = 1; + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) + pci_create_sysfs_dev_files(pdev); + + return 0; +} + +__initcall(pci_sysfs_init); diff -puN drivers/pci/probe.c~bk-pci drivers/pci/probe.c --- 25/drivers/pci/probe.c~bk-pci 2004-11-09 01:18:58.810253456 -0800 +++ 25-akpm/drivers/pci/probe.c 2004-11-09 01:19:00.647974080 -0800 @@ -170,7 +170,7 @@ static void pci_read_bases(struct pci_de if (sz && sz != 0xffffffff) { sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK); if (sz) { - res->flags = (l & PCI_ROM_ADDRESS_ENABLE) | + res->flags = (l & IORESOURCE_ROM_ENABLE) | IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE; res->start = l & PCI_ROM_ADDRESS_MASK; @@ -478,6 +478,9 @@ static int pci_setup_device(struct pci_d /* "Unknown power state" */ dev->current_state = 4; + /* Early fixups, before probing the BARs */ + pci_fixup_device(pci_fixup_early, dev); + switch (dev->hdr_type) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ if (class == PCI_CLASS_BRIDGE_PCI) diff -puN drivers/pci/quirks.c~bk-pci drivers/pci/quirks.c --- 25/drivers/pci/quirks.c~bk-pci 2004-11-09 01:18:58.812253152 -0800 +++ 25-akpm/drivers/pci/quirks.c 2004-11-09 01:19:00.648973928 -0800 @@ -1136,7 +1136,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I #endif #ifdef CONFIG_SCSI_SATA -static void __init quirk_intel_ide_combined(struct pci_dev *pdev) +static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev) { u8 prog, comb, tmp; int ich = 0; @@ -1210,14 +1210,15 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN #endif /* CONFIG_SCSI_SATA */ -int pciehp_msi_quirk; +int pcie_mch_quirk; -static void __devinit quirk_pciehp_msi(struct pci_dev *pdev) +static void __devinit quirk_pcie_mch(struct pci_dev *pdev) { - pciehp_msi_quirk = 1; + pcie_mch_quirk = 1; } -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SMCH, quirk_pciehp_msi ); - +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, quirk_pcie_mch ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7320_MCH, quirk_pcie_mch ); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7525_MCH, quirk_pcie_mch ); static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { @@ -1266,4 +1267,7 @@ void pci_fixup_device(enum pci_fixup_pas pci_do_fixups(dev, start, end); } -EXPORT_SYMBOL(pciehp_msi_quirk); +EXPORT_SYMBOL(pcie_mch_quirk); +#ifdef CONFIG_HOTPLUG +EXPORT_SYMBOL(pci_fixup_device); +#endif diff -puN drivers/pci/remove.c~bk-pci drivers/pci/remove.c --- 25/drivers/pci/remove.c~bk-pci 2004-11-09 01:18:58.813253000 -0800 +++ 25-akpm/drivers/pci/remove.c 2004-11-09 01:19:00.649973776 -0800 @@ -16,6 +16,7 @@ static void pci_free_resources(struct pc msi_remove_pci_irq_vectors(dev); + pci_cleanup_rom(dev); for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *res = dev->resource + i; if (res->parent) @@ -26,6 +27,7 @@ static void pci_free_resources(struct pc static void pci_destroy_dev(struct pci_dev *dev) { pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); device_unregister(&dev->dev); /* Remove the device from the device lists, and prevent any further diff -puN /dev/null drivers/pci/rom.c --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/drivers/pci/rom.c 2004-11-09 01:19:00.650973624 -0800 @@ -0,0 +1,225 @@ +/* + * drivers/pci/rom.c + * + * (C) Copyright 2004 Jon Smirl + * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes + * + * PCI ROM access routines + * + */ + + +#include +#include +#include + +#include "pci.h" + +/** + * pci_enable_rom - enable ROM decoding for a PCI device + * @dev: PCI device to enable + * + * Enable ROM decoding on @dev. This involves simply turning on the last + * bit of the PCI ROM BAR. Note that some cards may share address decoders + * between the ROM and other resources, so enabling it may disable access + * to MMIO registers or other card memory. + */ +static void +pci_enable_rom(struct pci_dev *pdev) +{ + u32 rom_addr; + + pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); + rom_addr |= PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); +} + +/** + * pci_disable_rom - disable ROM decoding for a PCI device + * @dev: PCI device to disable + * + * Disable ROM decoding on a PCI device by turning off the last bit in the + * ROM BAR. + */ +static void +pci_disable_rom(struct pci_dev *pdev) +{ + u32 rom_addr; + pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); + rom_addr &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); +} + +/** + * pci_map_rom - map a PCI ROM to kernel space + * @dev: pointer to pci device struct + * @size: pointer to receive size of pci window over ROM + * @return: kernel virtual pointer to image of ROM + * + * Map a PCI ROM into kernel space. If ROM is boot video ROM, + * the shadow BIOS copy will be returned instead of the + * actual ROM. + */ +void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) +{ + struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; + loff_t start; + void __iomem *rom; + void __iomem *image; + int last_image; + + if (res->flags & IORESOURCE_ROM_SHADOW) { /* IORESOURCE_ROM_SHADOW only set on x86 */ + start = (loff_t)0xC0000; /* primary video rom always starts here */ + *size = 0x20000; /* cover C000:0 through E000:0 */ + } else { + if (res->flags & IORESOURCE_ROM_COPY) { + *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); + return (void __iomem *)pci_resource_start(pdev, PCI_ROM_RESOURCE); + } else { + /* assign the ROM an address if it doesn't have one */ + if (res->parent == NULL) + pci_assign_resource(pdev, PCI_ROM_RESOURCE); + + start = pci_resource_start(pdev, PCI_ROM_RESOURCE); + *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); + if (*size == 0) + return NULL; + + /* Enable ROM space decodes */ + pci_enable_rom(pdev); + } + } + + rom = ioremap(start, *size); + if (!rom) { + /* restore enable if ioremap fails */ + if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY))) + pci_disable_rom(pdev); + return NULL; + } + + /* Try to find the true size of the ROM since sometimes the PCI window */ + /* size is much larger than the actual size of the ROM. */ + /* True size is important if the ROM is going to be copied. */ + image = rom; + do { + void __iomem *pds; + /* Standard PCI ROMs start out with these bytes 55 AA */ + if (readb(image) != 0x55) + break; + if (readb(image + 1) != 0xAA) + break; + /* get the PCI data structure and check its signature */ + pds = image + readw(image + 24); + if (readb(pds) != 'P') + break; + if (readb(pds + 1) != 'C') + break; + if (readb(pds + 2) != 'I') + break; + if (readb(pds + 3) != 'R') + break; + last_image = readb(pds + 21) & 0x80; + /* this length is reliable */ + image += readw(pds + 16) * 512; + } while (!last_image); + + *size = image - rom; + + return rom; +} + +/** + * pci_map_rom_copy - map a PCI ROM to kernel space, create a copy + * @dev: pointer to pci device struct + * @size: pointer to receive size of pci window over ROM + * @return: kernel virtual pointer to image of ROM + * + * Map a PCI ROM into kernel space. If ROM is boot video ROM, + * the shadow BIOS copy will be returned instead of the + * actual ROM. + */ +void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size) +{ + struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; + void __iomem *rom; + + rom = pci_map_rom(pdev, size); + if (!rom) + return NULL; + + if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_SHADOW)) + return rom; + + res->start = (unsigned long)kmalloc(*size, GFP_KERNEL); + if (!res->start) + return rom; + + res->end = res->start + *size; + memcpy_fromio((void*)res->start, rom, *size); + pci_unmap_rom(pdev, rom); + res->flags |= IORESOURCE_ROM_COPY; + + return (void __iomem *)res->start; +} + +/** + * pci_unmap_rom - unmap the ROM from kernel space + * @dev: pointer to pci device struct + * @rom: virtual address of the previous mapping + * + * Remove a mapping of a previously mapped ROM + */ +void +pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) +{ + struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; + + if (res->flags & IORESOURCE_ROM_COPY) + return; + + iounmap(rom); + + /* Disable again before continuing, leave enabled if pci=rom */ + if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) + pci_disable_rom(pdev); +} + +/** + * pci_remove_rom - disable the ROM and remove its sysfs attribute + * @dev: pointer to pci device struct + * + */ +void +pci_remove_rom(struct pci_dev *pdev) +{ + struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; + + if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) + sysfs_remove_bin_file(&pdev->dev.kobj, pdev->rom_attr); + if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW | IORESOURCE_ROM_COPY))) + pci_disable_rom(pdev); +} + +/** + * pci_cleanup_rom - internal routine for freeing the ROM copy created + * by pci_map_rom_copy called from remove.c + * @dev: pointer to pci device struct + * + */ +void +pci_cleanup_rom(struct pci_dev *pdev) +{ + struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; + if (res->flags & IORESOURCE_ROM_COPY) { + kfree((void*)res->start); + res->flags &= ~IORESOURCE_ROM_COPY; + res->start = 0; + res->end = 0; + } +} + +EXPORT_SYMBOL(pci_map_rom); +EXPORT_SYMBOL(pci_map_rom_copy); +EXPORT_SYMBOL(pci_unmap_rom); +EXPORT_SYMBOL(pci_remove_rom); diff -puN drivers/pci/setup-res.c~bk-pci drivers/pci/setup-res.c --- 25/drivers/pci/setup-res.c~bk-pci 2004-11-09 01:18:58.815252696 -0800 +++ 25-akpm/drivers/pci/setup-res.c 2004-11-09 01:19:00.651973472 -0800 @@ -56,7 +56,7 @@ pci_update_resource(struct pci_dev *dev, if (resno < 6) { reg = PCI_BASE_ADDRESS_0 + 4 * resno; } else if (resno == PCI_ROM_RESOURCE) { - new |= res->flags & PCI_ROM_ADDRESS_ENABLE; + new |= res->flags & IORESOURCE_ROM_ENABLE; reg = dev->rom_base_reg; } else { /* Hmm, non-standard resource. */ diff -puN include/asm-generic/vmlinux.lds.h~bk-pci include/asm-generic/vmlinux.lds.h --- 25/include/asm-generic/vmlinux.lds.h~bk-pci 2004-11-09 01:18:58.816252544 -0800 +++ 25-akpm/include/asm-generic/vmlinux.lds.h 2004-11-09 01:19:00.651973472 -0800 @@ -18,6 +18,9 @@ \ /* PCI quirks */ \ .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ + *(.pci_fixup_early) \ + VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ *(.pci_fixup_header) \ VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ diff -puN include/linux/ioport.h~bk-pci include/linux/ioport.h --- 25/include/linux/ioport.h~bk-pci 2004-11-09 01:18:58.817252392 -0800 +++ 25-akpm/include/linux/ioport.h 2004-11-09 01:19:00.652973320 -0800 @@ -82,6 +82,11 @@ struct resource_list { #define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ #define IORESOURCE_MEM_EXPANSIONROM (1<<6) +/* PCI ROM control bits (IORESOURCE_BITS) */ +#define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */ +#define IORESOURCE_ROM_SHADOW (1<<1) /* ROM is copy at C000:0 */ +#define IORESOURCE_ROM_COPY (1<<2) /* ROM is alloc'd copy, resource field overlaid */ + /* PC/ISA/whatever - the normal PC address spaces: IO and memory */ extern struct resource ioport_resource; extern struct resource iomem_resource; diff -puN /dev/null include/linux/pci-acpi.h --- /dev/null 2003-09-15 06:40:47.000000000 -0700 +++ 25-akpm/include/linux/pci-acpi.h 2004-11-09 01:19:00.652973320 -0800 @@ -0,0 +1,61 @@ +/* + * File pci-acpi.h + * + * Copyright (C) 2004 Intel + * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) + */ + +#ifndef _PCI_ACPI_H_ +#define _PCI_ACPI_H_ + +#define OSC_QUERY_TYPE 0 +#define OSC_SUPPORT_TYPE 1 +#define OSC_CONTROL_TYPE 2 +#define OSC_SUPPORT_MASKS 0x1f + +/* + * _OSC DW0 Definition + */ +#define OSC_QUERY_ENABLE 1 +#define OSC_REQUEST_ERROR 2 +#define OSC_INVALID_UUID_ERROR 4 +#define OSC_INVALID_REVISION_ERROR 8 +#define OSC_CAPABILITIES_MASK_ERROR 16 + +/* + * _OSC DW1 Definition (OS Support Fields) + */ +#define OSC_EXT_PCI_CONFIG_SUPPORT 1 +#define OSC_ACTIVE_STATE_PWR_SUPPORT 2 +#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT 4 +#define OSC_PCI_SEGMENT_GROUPS_SUPPORT 8 +#define OSC_MSI_SUPPORT 16 + +/* + * _OSC DW1 Definition (OS Control Fields) + */ +#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 1 +#define OSC_SHPC_NATIVE_HP_CONTROL 2 +#define OSC_PCI_EXPRESS_PME_CONTROL 4 +#define OSC_PCI_EXPRESS_AER_CONTROL 8 +#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL 16 + +#define OSC_CONTROL_MASKS (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \ + OSC_SHPC_NATIVE_HP_CONTROL | \ + OSC_PCI_EXPRESS_PME_CONTROL | \ + OSC_PCI_EXPRESS_AER_CONTROL | \ + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL) + +#ifdef CONFIG_ACPI +extern acpi_status pci_osc_control_set(u32 flags); +extern acpi_status pci_osc_support_set(u32 flags); +#else +#if !defined(acpi_status) +typedef u32 acpi_status; +#define AE_ERROR (acpi_status) (0x0001) +#endif +static inline acpi_status pci_osc_control_set(u32 flags) {return AE_ERROR;} +static inline acpi_status pci_osc_support_set(u32 flags) {return AE_ERROR;} +#endif + +#endif /* _PCI_ACPI_H_ */ diff -puN include/linux/pci.h~bk-pci include/linux/pci.h --- 25/include/linux/pci.h~bk-pci 2004-11-09 01:18:58.819252088 -0800 +++ 25-akpm/include/linux/pci.h 2004-11-09 01:19:00.654973016 -0800 @@ -537,6 +537,8 @@ struct pci_dev { unsigned int is_busmaster:1; /* device is busmaster */ u32 saved_config_space[16]; /* config space saved at suspend time */ + struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ + int rom_attr_enabled; /* has display of the rom attribute been enabled? */ #ifdef CONFIG_PCI_NAMES #define PCI_NAME_SIZE 96 #define PCI_NAME_HALF __stringify(43) /* less than half to handle slop */ @@ -785,6 +787,12 @@ int pci_dac_set_dma_mask(struct pci_dev int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); int pci_assign_resource(struct pci_dev *dev, int i); +/* ROM control related routines */ +void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size); +void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size); +void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); +void pci_remove_rom(struct pci_dev *pdev); + /* Power management related routines */ int pci_save_state(struct pci_dev *dev); int pci_restore_state(struct pci_dev *dev); @@ -989,31 +997,33 @@ static inline char *pci_name(struct pci_ */ struct pci_fixup { - u16 vendor, device; /* You can use PCI_ANY_ID here of course */ + u16 vendor, device; /* You can use PCI_ANY_ID here of course */ void (*hook)(struct pci_dev *dev); }; enum pci_fixup_pass { - pci_fixup_header, /* Called immediately after reading configuration header */ + pci_fixup_early, /* Before probing BARs */ + pci_fixup_header, /* After reading configuration header */ pci_fixup_final, /* Final phase of device fixups */ pci_fixup_enable, /* pci_enable_device() time */ }; /* Anonymous variables would be nice... */ -#define DECLARE_PCI_FIXUP_HEADER(vendor, device, hook) \ - static struct pci_fixup __pci_fixup_##vendor##device##hook __attribute_used__ \ - __attribute__((__section__(".pci_fixup_header"))) = { \ - vendor, device, hook }; - -#define DECLARE_PCI_FIXUP_FINAL(vendor, device, hook) \ - static struct pci_fixup __pci_fixup_##vendor##device##hook __attribute_used__ \ - __attribute__((__section__(".pci_fixup_final"))) = { \ - vendor, device, hook }; - -#define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook) \ - static struct pci_fixup __pci_fixup_##vendor##device##hook __attribute_used__ \ - __attribute__((__section__(".pci_fixup_enable"))) = { \ - vendor, device, hook }; +#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, hook) \ + static struct pci_fixup __pci_fixup_##name __attribute_used__ \ + __attribute__((__section__(#section))) = { vendor, device, hook }; +#define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \ + DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \ + vendor##device##hook, vendor, device, hook) +#define DECLARE_PCI_FIXUP_HEADER(vendor, device, hook) \ + DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header, \ + vendor##device##hook, vendor, device, hook) +#define DECLARE_PCI_FIXUP_FINAL(vendor, device, hook) \ + DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final, \ + vendor##device##hook, vendor, device, hook) +#define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook) \ + DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \ + vendor##device##hook, vendor, device, hook) void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); diff -puN include/linux/pci_ids.h~bk-pci include/linux/pci_ids.h --- 25/include/linux/pci_ids.h~bk-pci 2004-11-09 01:18:58.821251784 -0800 +++ 25-akpm/include/linux/pci_ids.h 2004-11-09 01:19:00.667971040 -0800 @@ -2209,8 +2209,14 @@ #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 #define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 #define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582 -#define PCI_DEVICE_ID_INTEL_SMCH 0x3590 +#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590 #define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592 +#define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595 +#define PCI_DEVICE_ID_INTEL_MCH_PA1 0x3596 +#define PCI_DEVICE_ID_INTEL_MCH_PB 0x3597 +#define PCI_DEVICE_ID_INTEL_MCH_PB1 0x3598 +#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599 +#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a #define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e #define PCI_DEVICE_ID_INTEL_80310 0x530d #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 _