fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / pci / hotplug / pciehp_hpc.c
index 1cda30b..25d3aad 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * Send feedback to <greg@kroah.com>,<dely.l.sy@intel.com>
+ * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
+#include <linux/signal.h>
+#include <linux/jiffies.h>
+#include <linux/timer.h>
 #include <linux/pci.h>
-#include <asm/system.h>
+#include <linux/interrupt.h>
+
 #include "../pci.h"
 #include "pciehp.h"
-
 #ifdef DEBUG
 #define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)      /* On function entry */
 #define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)      /* On function exit */
@@ -217,23 +215,6 @@ static int pcie_cap_base = 0;              /* Base of the PCI Express capability item struct
 #define MRL_STATE              0x0020
 #define PRSN_STATE             0x0040
 
-struct php_ctlr_state_s {
-       struct php_ctlr_state_s *pnext;
-       struct pci_dev *pci_dev;
-       unsigned int irq;
-       unsigned long flags;                            /* spinlock's */
-       u32 slot_device_offset;
-       u32 num_slots;
-       struct timer_list       int_poll_timer;         /* Added for poll event */
-       php_intr_callback_t     attention_button_callback;
-       php_intr_callback_t     switch_change_callback;
-       php_intr_callback_t     presence_change_callback;
-       php_intr_callback_t     power_fault_callback;
-       void                    *callback_instance_id;
-       struct ctrl_reg         *creg;                          /* Ptr to controller register space */
-};
-
-
 static spinlock_t hpc_event_lock;
 
 DEFINE_DBG_BUFFER              /* Debug string buffer for entire HPC defined here */
@@ -241,7 +222,7 @@ static struct php_ctlr_state_s *php_ctlr_list_head; /* 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);
+static irqreturn_t pcie_isr(int IRQ, void *dev_id);
 
 static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
 
@@ -258,7 +239,7 @@ static void int_poll_timeout(unsigned long lphp_ctlr)
        }
 
        /* Poll for interrupt events.  regs == NULL => polling */
-       pcie_isr( 0, (void *)php_ctlr, NULL );
+       pcie_isr( 0, (void *)php_ctlr );
 
        init_timer(&php_ctlr->int_poll_timer);
 
@@ -297,7 +278,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd)
 
        DBG_ENTER_ROUTINE 
        
-       dbg("%s : Enter\n", __FUNCTION__);
        if (!php_ctlr) {
                err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
                return -1;
@@ -308,7 +288,6 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd)
                        err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
                        return retval;
                }
-       dbg("%s : hp_register_read_word SLOT_STATUS %x\n", __FUNCTION__, slot_status);
        
        if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { 
                /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue 
@@ -316,14 +295,11 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd)
                dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
        }
 
-       dbg("%s: Before hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd);
        retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
        if (retval) {
                err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
                return retval;
        }
-       dbg("%s : hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, cmd | CMD_CMPL_INTR_ENABLE);
-       dbg("%s : Exit\n", __FUNCTION__);
 
        DBG_LEAVE_ROUTINE 
        return retval;
@@ -509,7 +485,6 @@ static int hpc_query_power_fault(struct slot * slot)
        u16 slot_status;
        u8 pwr_fault;
        int retval = 0;
-       u8 status;
 
        DBG_ENTER_ROUTINE 
 
@@ -521,15 +496,13 @@ static int hpc_query_power_fault(struct slot * slot)
        retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
 
        if (retval) {
-               err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s : Cannot check for power fault\n", __FUNCTION__);
                return retval;
        }
        pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
-       status = (pwr_fault != 1) ? 1 : 0;
        
        DBG_LEAVE_ROUTINE
-       /* Note: Logic 0 => fault */
-       return status;
+       return pwr_fault;
 }
 
 static int hpc_set_attention_status(struct slot *slot, u8 value)
@@ -539,7 +512,8 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
        u16 slot_ctrl;
        int rc = 0;
 
-       dbg("%s: \n", __FUNCTION__);
+       DBG_ENTER_ROUTINE
+
        if (!php_ctlr) {
                err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
                return -1;
@@ -555,7 +529,6 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
                err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                return rc;
        }
-       dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
 
        switch (value) {
                case 0 :        /* turn off */
@@ -576,6 +549,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
        pcie_write_cmd(slot, slot_cmd);
        dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
        
+       DBG_LEAVE_ROUTINE
        return rc;
 }
 
@@ -587,7 +561,8 @@ static void hpc_set_green_led_on(struct slot *slot)
        u16 slot_ctrl;
        int rc = 0;
                
-       dbg("%s: \n", __FUNCTION__);    
+       DBG_ENTER_ROUTINE
+
        if (!php_ctlr) {
                err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
                return ;
@@ -604,7 +579,6 @@ static void hpc_set_green_led_on(struct slot *slot)
                err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                return;
        }
-       dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
        slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
        if (!pciehp_poll_mode)
                slot_cmd = slot_cmd | HP_INTR_ENABLE; 
@@ -612,6 +586,7 @@ static void hpc_set_green_led_on(struct slot *slot)
        pcie_write_cmd(slot, slot_cmd);
 
        dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       DBG_LEAVE_ROUTINE
        return;
 }
 
@@ -622,7 +597,8 @@ static void hpc_set_green_led_off(struct slot *slot)
        u16 slot_ctrl;
        int rc = 0;
 
-       dbg("%s: \n", __FUNCTION__);    
+       DBG_ENTER_ROUTINE
+
        if (!php_ctlr) {
                err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
                return ;
@@ -639,7 +615,6 @@ static void hpc_set_green_led_off(struct slot *slot)
                err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                return;
        }
-       dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
 
        slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0300;
 
@@ -648,6 +623,7 @@ static void hpc_set_green_led_off(struct slot *slot)
        pcie_write_cmd(slot, slot_cmd);
        dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 
+       DBG_LEAVE_ROUTINE
        return;
 }
 
@@ -658,7 +634,8 @@ static void hpc_set_green_led_blink(struct slot *slot)
        u16 slot_ctrl;
        int rc = 0; 
        
-       dbg("%s: \n", __FUNCTION__);    
+       DBG_ENTER_ROUTINE
+
        if (!php_ctlr) {
                err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
                return ;
@@ -675,7 +652,6 @@ static void hpc_set_green_led_blink(struct slot *slot)
                err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                return;
        }
-       dbg("%s : hp_register_read_word SLOT_CTRL %x\n", __FUNCTION__, slot_ctrl);
 
        slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0200;
 
@@ -684,6 +660,7 @@ static void hpc_set_green_led_blink(struct slot *slot)
        pcie_write_cmd(slot, slot_cmd);
 
        dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       DBG_LEAVE_ROUTINE
        return;
 }
 
@@ -741,8 +718,6 @@ static void hpc_release_ctlr(struct controller *ctrl)
                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) 
@@ -775,12 +750,11 @@ static int hpc_power_on_slot(struct slot * slot)
 {
        struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
        u16 slot_cmd;
-       u16 slot_ctrl;
+       u16 slot_ctrl, slot_status;
 
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
-       dbg("%s: \n", __FUNCTION__);    
 
        if (!php_ctlr) {
                err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
@@ -793,19 +767,30 @@ static int hpc_power_on_slot(struct slot * slot)
                return -1;
        }
 
+       /* Clear sticky power-fault bit from previous power failures */
+       hp_register_read_word(php_ctlr->pci_dev,
+                       SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+       slot_status &= PWR_FAULT_DETECTED;
+       if (slot_status)
+               hp_register_write_word(php_ctlr->pci_dev,
+                       SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+
        retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
        if (retval) {
                err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                return retval;
        }
-       dbg("%s: SLOT_CTRL %x, value read %xn", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base),
-               slot_ctrl);
 
        slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_ON;
 
+       /* Enable detection that we turned off at slot power-off time */
        if (!pciehp_poll_mode)
-               slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+               slot_cmd = slot_cmd |
+                          PWR_FAULT_DETECT_ENABLE |
+                          MRL_DETECT_ENABLE |
+                          PRSN_DETECT_ENABLE |
+                          HP_INTR_ENABLE;
 
        retval = pcie_write_cmd(slot, slot_cmd);
 
@@ -829,7 +814,6 @@ static int hpc_power_off_slot(struct slot * slot)
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
-       dbg("%s: \n", __FUNCTION__);    
 
        if (!php_ctlr) {
                err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
@@ -848,13 +832,21 @@ static int hpc_power_off_slot(struct slot * slot)
                err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                return retval;
        }
-       dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base),
-               slot_ctrl);
 
        slot_cmd = (slot_ctrl & ~PWR_CTRL) | POWER_OFF;
 
+       /*
+        * If we get MRL or presence detect interrupts now, the isr
+        * will notice the sticky power-fault bit too and issue power
+        * indicator change commands. This will lead to an endless loop
+        * of command completions, since the power-fault bit remains on
+        * till the slot is powered on again.
+        */
        if (!pciehp_poll_mode)
-               slot_cmd = slot_cmd | HP_INTR_ENABLE; 
+               slot_cmd = (slot_cmd &
+                           ~PWR_FAULT_DETECT_ENABLE &
+                           ~MRL_DETECT_ENABLE &
+                           ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE;
 
        retval = pcie_write_cmd(slot, slot_cmd);
 
@@ -869,7 +861,7 @@ static int hpc_power_off_slot(struct slot * slot)
        return retval;
 }
 
-static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pcie_isr(int IRQ, void *dev_id)
 {
        struct controller *ctrl = NULL;
        struct php_ctlr_state_s *php_ctlr;
@@ -924,7 +916,6 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
                        return IRQ_NONE;
                }
 
-               dbg("%s: Set Mask Hot-plug Interrupt Enable\n", __FUNCTION__);
                dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
                temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
 
@@ -933,7 +924,6 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
                        err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
                        return IRQ_NONE;
                }
-               dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
                
                rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
                if (rc) {
@@ -949,14 +939,12 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
                        err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
                        return IRQ_NONE;
                }
-               dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word);
        }
        
        if (intr_loc & CMD_COMPLETED) {
                /* 
                 * Command Complete Interrupt Pending 
                 */
-               dbg("%s: In Command Complete Interrupt Pending\n", __FUNCTION__);
                wake_up_interruptible(&ctrl->queue);
        }
 
@@ -989,7 +977,6 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
                }
 
                dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
-               dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
                temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
 
                rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
@@ -997,14 +984,12 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
                        err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
                        return IRQ_NONE;
                }
-               dbg("%s: hp_register_write_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);   
        
                rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
                if (rc) {
                        err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
                        return IRQ_NONE;
                }
-               dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); 
                
                /* Clear command complete interrupt caused by this write */
                temp_word = 0x1F;
@@ -1248,12 +1233,77 @@ static struct hpc_ops pciehp_hpc_ops = {
        .check_lnk_status               = hpc_check_lnk_status,
 };
 
-int pcie_init(struct controller * ctrl,
-       struct pcie_device *dev,
-       php_intr_callback_t attention_button_callback,
-       php_intr_callback_t switch_change_callback,
-       php_intr_callback_t presence_change_callback,
-       php_intr_callback_t power_fault_callback)
+#ifdef CONFIG_ACPI
+int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
+{
+       acpi_status status;
+       acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
+       struct pci_dev *pdev = dev;
+       struct pci_bus *parent;
+       struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
+
+       /*
+        * Per PCI firmware specification, we should run the ACPI _OSC
+        * method to get control of hotplug hardware before using it.
+        * If an _OSC is missing, we look for an OSHP to do the same thing.
+        * To handle different BIOS behavior, we look for _OSC and OSHP
+        * within the scope of the hotplug controller and its parents, upto
+        * the host bridge under which this controller exists.
+        */
+       while (!handle) {
+               /*
+                * This hotplug controller was not listed in the ACPI name
+                * space at all. Try to get acpi handle of parent pci bus.
+                */
+               if (!pdev || !pdev->bus->parent)
+                       break;
+               parent = pdev->bus->parent;
+               dbg("Could not find %s in acpi namespace, trying parent\n",
+                               pci_name(pdev));
+               if (!parent->self)
+                       /* Parent must be a host bridge */
+                       handle = acpi_get_pci_rootbridge_handle(
+                                       pci_domain_nr(parent),
+                                       parent->number);
+               else
+                       handle = DEVICE_ACPI_HANDLE(
+                                       &(parent->self->dev));
+               pdev = parent->self;
+       }
+
+       while (handle) {
+               acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
+               dbg("Trying to get hotplug control for %s \n",
+                       (char *)string.pointer);
+               status = pci_osc_control_set(handle,
+                               OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
+               if (status == AE_NOT_FOUND)
+                       status = acpi_run_oshp(handle);
+               if (ACPI_SUCCESS(status)) {
+                       dbg("Gained control for hotplug HW for pci %s (%s)\n",
+                               pci_name(dev), (char *)string.pointer);
+                       kfree(string.pointer);
+                       return 0;
+               }
+               if (acpi_root_bridge(handle))
+                       break;
+               chandle = handle;
+               status = acpi_get_parent(chandle, &handle);
+               if (ACPI_FAILURE(status))
+                       break;
+       }
+
+       err("Cannot get control of hotplug hardware for pci %s\n",
+                       pci_name(dev));
+
+       kfree(string.pointer);
+       return -1;
+}
+#endif
+
+
+
+int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 {
        struct php_ctlr_state_s *php_ctlr, *p;
        void *instance_id = ctrl;
@@ -1270,7 +1320,7 @@ int pcie_init(struct controller * ctrl,
        DBG_ENTER_ROUTINE
        
        spin_lock_init(&list_lock);     
-       php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
+       php_ctlr = kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
 
        if (!php_ctlr) {        /* allocate controller state data */
                err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
@@ -1282,8 +1332,8 @@ int pcie_init(struct controller * ctrl,
        pdev = dev->port;
        php_ctlr->pci_dev = pdev;       /* save pci_dev in context */
 
-       dbg("%s: pdev->vendor %x pdev->device %x\n", __FUNCTION__,
-               pdev->vendor, pdev->device);
+       dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
+                       __FUNCTION__, pdev->vendor, pdev->device);
 
        saved_cap_base = pcie_cap_base;
 
@@ -1340,32 +1390,29 @@ int pcie_init(struct controller * ctrl,
                first = 0;
        }
 
-       dbg("pdev = %p: b:d:f:irq=0x%x:%x:%x:%x\n", pdev, pdev->bus->number, 
-               PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
        for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
                if (pci_resource_len(pdev, rc) > 0)
-                       dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
-                               pci_resource_start(pdev, rc), pci_resource_len(pdev, rc));
+                       dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
+                           (unsigned long long)pci_resource_start(pdev, rc),
+                           (unsigned long long)pci_resource_len(pdev, rc));
 
        info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 
                pdev->subsystem_vendor, pdev->subsystem_device);
 
-       if (pci_enable_device(pdev))
-               goto abort_free_ctlr;
-       
-       init_MUTEX(&ctrl->crit_sect);
+       mutex_init(&ctrl->crit_sect);
+       mutex_init(&ctrl->ctrl_lock);
+
        /* setup wait queue */
        init_waitqueue_head(&ctrl->queue);
 
        /* find the IRQ */
        php_ctlr->irq = dev->irq;
-       dbg("HPC interrupt = %d\n", php_ctlr->irq);
 
        /* Save interrupt callback info */
-       php_ctlr->attention_button_callback = attention_button_callback;
-       php_ctlr->switch_change_callback = switch_change_callback;
-       php_ctlr->presence_change_callback = presence_change_callback;
-       php_ctlr->power_fault_callback = power_fault_callback;
+       php_ctlr->attention_button_callback = pciehp_handle_attention_button;
+       php_ctlr->switch_change_callback = pciehp_handle_switch_change;
+       php_ctlr->presence_change_callback = pciehp_handle_presence_change;
+       php_ctlr->power_fault_callback = pciehp_handle_power_fault;
        php_ctlr->callback_instance_id = instance_id;
 
        /* return PCI Controller Info */
@@ -1387,15 +1434,12 @@ int pcie_init(struct controller * ctrl,
                err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s : Mask HPIE hp_register_write_word SLOT_CTRL %x\n", __FUNCTION__, temp_word);
 
        rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
        if (rc) {
                err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: Mask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base)
-               , slot_status);
 
        temp_word = 0x1F; /* Clear all events */
        rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
@@ -1403,7 +1447,6 @@ int pcie_init(struct controller * ctrl,
                err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word);
 
        if (pciehp_poll_mode)  {/* Install interrupt polling code */
                /* Install and start the interrupt polling timer */
@@ -1411,7 +1454,7 @@ int pcie_init(struct controller * ctrl,
                start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
        } else {
                /* Installs the interrupt handler */
-               rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+               rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, 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) {
                        err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
@@ -1419,13 +1462,14 @@ int pcie_init(struct controller * ctrl,
                }
        }
 
+       dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
+               PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
+
        rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
        if (rc) {
                err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort_free_irq;
        }
-       dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
-       dbg("%s: slot_cap %x\n", __FUNCTION__, slot_cap);
 
        intr_enable = intr_enable | PRSN_DETECT_ENABLE;
 
@@ -1445,31 +1489,35 @@ int pcie_init(struct controller * ctrl,
        } else {
                temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
        }
-       dbg("%s: temp_word %x\n", __FUNCTION__, temp_word);
 
        /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
        rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
        if (rc) {
                err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort_free_irq;
        }
-       dbg("%s : Unmask HPIE hp_register_write_word SLOT_CTRL with %x\n", __FUNCTION__, temp_word);
        rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
        if (rc) {
                err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort_disable_intr;
        }
-       dbg("%s: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, 
-               SLOT_STATUS(ctrl->cap_base), slot_status);
        
        temp_word =  0x1F; /* Clear all events */
        rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
        if (rc) {
                err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
-               goto abort_free_ctlr;
+               goto abort_disable_intr;
        }
-       dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), temp_word);
        
+       if (pciehp_force) {
+               dbg("Bypassing BIOS check for pciehp use on %s\n",
+                               pci_name(ctrl->pci_dev));
+       } else {
+               rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
+               if (rc)
+                       goto abort_disable_intr;
+       }
+
        /*  Add this HPC instance into the HPC list */
        spin_lock(&list_lock);
        if (php_ctlr_list_head == 0) {
@@ -1494,6 +1542,21 @@ int pcie_init(struct controller * ctrl,
        return 0;
 
        /* We end up here for the many possible ways to fail this API.  */
+abort_disable_intr:
+       rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+       if (!rc) {
+               temp_word &= ~(intr_enable | HP_INTR_ENABLE);
+               rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+       }
+       if (rc)
+               err("%s : disabling interrupts failed\n", __FUNCTION__);
+
+abort_free_irq:
+       if (pciehp_poll_mode)
+               del_timer_sync(&php_ctlr->int_poll_timer);
+       else
+               free_irq(php_ctlr->irq, ctrl);
+
 abort_free_ctlr:
        pcie_cap_base = saved_cap_base;
        kfree(php_ctlr);