Signed-off-by: Andrew Morton --- 25-akpm/Documentation/kernel-parameters.txt | 4 25-akpm/arch/i386/pci/acpi.c | 30 +- 25-akpm/arch/i386/pci/common.c | 4 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/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 | 5 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 | 382 +++++++++++++++++----------- 25-akpm/drivers/pci/hotplug/pciehp_hpc.c | 30 +- 25-akpm/drivers/pci/hotplug/pciehprm_acpi.c | 43 ++- 25-akpm/drivers/pci/hotplug/shpchp_ctrl.c | 34 ++ 25-akpm/drivers/pci/pci-acpi.c | 209 +++++++++++++++ 25-akpm/drivers/pci/pci.c | 12 25-akpm/include/linux/pci-acpi.h | 61 ++++ arch/i386/kernel/acpi/boot.c | 0 20 files changed, 718 insertions(+), 202 deletions(-) diff -puN arch/i386/kernel/acpi/boot.c~bk-pci arch/i386/kernel/acpi/boot.c diff -puN arch/i386/pci/acpi.c~bk-pci arch/i386/pci/acpi.c --- 25/arch/i386/pci/acpi.c~bk-pci 2004-11-04 20:29:41.563149488 -0800 +++ 25-akpm/arch/i386/pci/acpi.c 2004-11-04 20:29:42.799961464 -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 -puN arch/i386/pci/common.c~bk-pci arch/i386/pci/common.c --- 25/arch/i386/pci/common.c~bk-pci 2004-11-04 20:29:41.564149336 -0800 +++ 25-akpm/arch/i386/pci/common.c 2004-11-04 20:29:42.799961464 -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/irq.c~bk-pci arch/i386/pci/irq.c --- 25/arch/i386/pci/irq.c~bk-pci 2004-11-04 20:29:41.566149032 -0800 +++ 25-akpm/arch/i386/pci/irq.c 2004-11-04 20:29:43.646832720 -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-04 20:29:41.568148728 -0800 +++ 25-akpm/arch/ia64/pci/pci.c 2004-11-04 20:29:43.648832416 -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-04 20:29:41.570148424 -0800 +++ 25-akpm/Documentation/kernel-parameters.txt 2004-11-04 20:29:41.597144320 -0800 @@ -930,6 +930,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-04 20:29:41.572148120 -0800 +++ 25-akpm/drivers/atm/idt77252.c 2004-11-04 20:29:43.650832112 -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/isdn/tpam/tpam_main.c~bk-pci drivers/isdn/tpam/tpam_main.c --- 25/drivers/isdn/tpam/tpam_main.c~bk-pci 2004-11-04 20:29:41.573147968 -0800 +++ 25-akpm/drivers/isdn/tpam/tpam_main.c 2004-11-04 20:29:43.651831960 -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-04 20:29:41.575147664 -0800 +++ 25-akpm/drivers/misc/ibmasm/module.c 2004-11-04 20:29:43.651831960 -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-04 20:29:41.577147360 -0800 +++ 25-akpm/drivers/net/tulip/de4x5.c 2004-11-04 20:29:43.656831200 -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/pciehp_core.c~bk-pci drivers/pci/hotplug/pciehp_core.c --- 25/drivers/pci/hotplug/pciehp_core.c~bk-pci 2004-11-04 20:29:41.578147208 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp_core.c 2004-11-04 20:29:43.658830896 -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-04 20:29:41.580146904 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp_ctrl.c 2004-11-04 20:29:43.662830288 -0800 @@ -51,6 +51,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 +1064,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 +1117,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); @@ -1211,19 +1220,19 @@ static u32 board_added(struct pci_func * pciehp_configure_device(ctrl, new_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); - + + 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 +1298,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 +1381,6 @@ static void pushbutton_helper_thread(uns up(&event_semaphore); } - /** * pciehp_pushbutton_thread * @@ -1399,7 +1411,7 @@ 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); @@ -1417,6 +1429,55 @@ static void pciehp_pushbutton_thread(uns 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); + + 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; +} + + /* this is the main worker thread */ static int event_thread(void* data) @@ -1436,6 +1497,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 +1591,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 +1610,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 +1633,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 +1739,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 +1830,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-04 20:29:41.581146752 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp.h 2004-11-04 20:29:43.657831048 -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-04 20:29:41.583146448 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehp_hpc.c 2004-11-04 20:29:43.664829984 -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; @@ -1259,7 +1259,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; @@ -1412,6 +1412,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 +1427,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/pciehprm_acpi.c~bk-pci drivers/pci/hotplug/pciehprm_acpi.c --- 25/drivers/pci/hotplug/pciehprm_acpi.c~bk-pci 2004-11-04 20:29:41.584146296 -0800 +++ 25-akpm/drivers/pci/hotplug/pciehprm_acpi.c 2004-11-04 20:29:43.666829680 -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-04 20:29:41.586145992 -0800 +++ 25-akpm/drivers/pci/hotplug/shpchp_ctrl.c 2004-11-04 20:29:43.668829376 -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/Makefile~bk-pci drivers/pci/Makefile --- 25/drivers/pci/Makefile~bk-pci 2004-11-04 20:29:41.587145840 -0800 +++ 25-akpm/drivers/pci/Makefile 2004-11-04 20:29:43.656831200 -0800 @@ -28,6 +28,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-04 20:29:43.670829072 -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-04 20:29:41.589145536 -0800 +++ 25-akpm/drivers/pci/pci.c 2004-11-04 20:29:43.671828920 -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 /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-04 20:29:43.671828920 -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_ */ _