Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / pci / hotplug / pciehp_hpc.c
index cb0804b..6c14d9e 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"
-
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/actypes.h>
+#include <linux/pci-acpi.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 */
@@ -109,20 +111,20 @@ enum ctrl_offsets {
 };
 static int pcie_cap_base = 0;          /* Base of the PCI Express capability item structure */ 
 
-#define PCIE_CAP_ID    ( pcie_cap_base + PCIECAPID )
-#define NXT_CAP_PTR    ( pcie_cap_base + NXTCAPPTR )
-#define CAP_REG                ( pcie_cap_base + CAPREG )
-#define DEV_CAP                ( pcie_cap_base + DEVCAP )
-#define DEV_CTRL       ( pcie_cap_base + DEVCTRL )
-#define DEV_STATUS     ( pcie_cap_base + DEVSTATUS )
-#define LNK_CAP                ( pcie_cap_base + LNKCAP )
-#define LNK_CTRL       ( pcie_cap_base + LNKCTRL )
-#define LNK_STATUS     ( pcie_cap_base + LNKSTATUS )
-#define SLOT_CAP       ( pcie_cap_base + SLOTCAP )
-#define SLOT_CTRL      ( pcie_cap_base + SLOTCTRL )
-#define SLOT_STATUS    ( pcie_cap_base + SLOTSTATUS )
-#define ROOT_CTRL      ( pcie_cap_base + ROOTCTRL )
-#define ROOT_STATUS    ( pcie_cap_base + ROOTSTATUS )
+#define PCIE_CAP_ID(cb)        ( cb + PCIECAPID )
+#define NXT_CAP_PTR(cb)        ( cb + NXTCAPPTR )
+#define CAP_REG(cb)    ( cb + CAPREG )
+#define DEV_CAP(cb)    ( cb + DEVCAP )
+#define DEV_CTRL(cb)   ( cb + DEVCTRL )
+#define DEV_STATUS(cb) ( cb + DEVSTATUS )
+#define LNK_CAP(cb)    ( cb + LNKCAP )
+#define LNK_CTRL(cb)   ( cb + LNKCTRL )
+#define LNK_STATUS(cb) ( cb + LNKSTATUS )
+#define SLOT_CAP(cb)   ( cb + SLOTCAP )
+#define SLOT_CTRL(cb)  ( cb + SLOTCTRL )
+#define SLOT_STATUS(cb)        ( cb + SLOTSTATUS )
+#define ROOT_CTRL(cb)  ( cb + ROOTCTRL )
+#define ROOT_STATUS(cb)        ( cb + ROOTSTATUS )
 
 #define hp_register_read_word(pdev, reg , value)               \
        pci_read_config_word(pdev, reg, &value)
@@ -182,7 +184,7 @@ static int pcie_cap_base = 0;               /* Base of the PCI Express capability item struct
 #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
@@ -217,28 +219,11 @@ 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 */
-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; /* 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);
@@ -297,18 +282,16 @@ 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;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+       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__);
                        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 +299,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, cmd | CMD_CMPL_INTR_ENABLE);
+       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;
@@ -342,7 +322,7 @@ static int hpc_check_lnk_status(struct controller *ctrl)
                return -1;
        }
        
-       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status);
 
        if (retval) {
                err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
@@ -376,14 +356,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
                return -1;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       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 %x\n", __FUNCTION__,SLOT_CTRL, slot_ctrl);
+       dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
        atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
 
@@ -423,13 +403,13 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
                return -1;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       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 %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+       dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
        pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
 
@@ -463,7 +443,7 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
                return -1;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+       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__);
@@ -490,7 +470,7 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
                return -1;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+       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__);
@@ -509,7 +489,6 @@ static int hpc_query_power_fault(struct slot * slot)
        u16 slot_status;
        u8 pwr_fault;
        int retval = 0;
-       u8 status;
 
        DBG_ENTER_ROUTINE 
 
@@ -518,18 +497,16 @@ static int hpc_query_power_fault(struct slot * slot)
                return -1;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+       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 +516,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;
@@ -549,13 +527,12 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
                err("%s: Invalid HPC slot number!\n", __FUNCTION__);
                return -1;
        }
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
        if (rc) {
                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 */
@@ -574,8 +551,9 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
                slot_cmd = slot_cmd | HP_INTR_ENABLE; 
 
        pcie_write_cmd(slot, slot_cmd);
-       dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, 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 +565,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 ;
@@ -598,20 +577,20 @@ static void hpc_set_green_led_on(struct slot *slot)
                return ;
        }
 
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
        if (rc) {
                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; 
 
        pcie_write_cmd(slot, slot_cmd);
 
-       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, 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 +601,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 ;
@@ -633,21 +613,21 @@ static void hpc_set_green_led_off(struct slot *slot)
                return ;
        }
 
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
        if (rc) {
                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;
 
        if (!pciehp_poll_mode)
                slot_cmd = slot_cmd | HP_INTR_ENABLE; 
        pcie_write_cmd(slot, slot_cmd);
-       dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL, 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 +638,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 ;
@@ -669,13 +650,12 @@ static void hpc_set_green_led_blink(struct slot *slot)
                return ;
        }
 
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
        if (rc) {
                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;
 
@@ -683,7 +663,8 @@ static void hpc_set_green_led_blink(struct slot *slot)
                slot_cmd = slot_cmd | HP_INTR_ENABLE; 
        pcie_write_cmd(slot, slot_cmd);
 
-       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       DBG_LEAVE_ROUTINE
        return;
 }
 
@@ -691,8 +672,7 @@ int pcie_get_ctlr_slot_config(struct controller *ctrl,
        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;
@@ -708,7 +688,7 @@ int pcie_get_ctlr_slot_config(struct controller *ctrl,
        *first_device_num = 0;
        *num_ctlr_slots = 1; 
 
-       rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap);
+       rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
 
        if (rc) {
                err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
@@ -716,8 +696,9 @@ int pcie_get_ctlr_slot_config(struct controller *ctrl,
        }
        
        *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 +722,8 @@ 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) 
@@ -773,12 +756,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__);
@@ -791,19 +773,30 @@ static int hpc_power_on_slot(struct slot * slot)
                return -1;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       /* 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);
 
        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);
 
@@ -811,7 +804,7 @@ static int hpc_power_on_slot(struct slot * slot)
                err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
                return -1;
        }
-       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 
        DBG_LEAVE_ROUTINE
 
@@ -827,7 +820,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__);
@@ -840,19 +832,27 @@ static int hpc_power_off_slot(struct slot * slot)
                err("%s: Invalid HPC slot number!\n", __FUNCTION__);
                return -1;
        }
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       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 %x\n", __FUNCTION__, SLOT_CTRL, 
-               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);
 
@@ -860,7 +860,7 @@ static int hpc_power_off_slot(struct slot * slot)
                err("%s: Write command failed!\n", __FUNCTION__);
                return -1;
        }
-       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL, slot_cmd);
+       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
 
        DBG_LEAVE_ROUTINE
 
@@ -898,7 +898,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
                return IRQ_NONE;
        }
 
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+       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;
@@ -916,24 +916,22 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
        dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
        /* Mask Hot-plug Interrupt Enable */
        if (!pciehp_poll_mode) {
-               rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+               rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
                if (rc) {
                        err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                        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;
 
-               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
                if (rc) {
                        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, slot_status);
+               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;
@@ -942,19 +940,17 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
                
                /* Clear command complete interrupt caused by this write */
                temp_word = 0x1f;
-               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+               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__);
                        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);
        }
 
@@ -973,40 +969,37 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
 
        /* Clear all events after serving them */
        temp_word = 0x1F;
-       rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+       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__);
                return IRQ_NONE;
        }
        /* Unmask Hot-plug Interrupt Enable */
        if (!pciehp_poll_mode) {
-               rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, temp_word);
+               rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
                if (rc) {
                        err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                        return IRQ_NONE;
                }
 
                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, temp_word);
+               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
                if (rc) {
                        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, slot_status);
+               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;
-               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+               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__);
                        return IRQ_NONE;
@@ -1017,7 +1010,7 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-static int hpc_get_max_lnk_speed (struct slot *slot, enum pcie_link_speed *value)
+static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 {
        struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
        enum pcie_link_speed lnk_speed;
@@ -1036,7 +1029,7 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pcie_link_speed *value
                return -1;
        }
 
-       retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap);
+       retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
 
        if (retval) {
                err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
@@ -1077,7 +1070,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
                return -1;
        }
 
-       retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP, lnk_cap);
+       retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
 
        if (retval) {
                err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
@@ -1120,7 +1113,7 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
        return retval;
 }
 
-static int hpc_get_cur_lnk_speed (struct slot *slot, enum pcie_link_speed *value)
+static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 {
        struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
        enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
@@ -1139,7 +1132,7 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pcie_link_speed *value
                return -1;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
 
        if (retval) {
                err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
@@ -1180,7 +1173,7 @@ static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value
                return -1;
        }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS, lnk_status);
+       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
 
        if (retval) {
                err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
@@ -1246,12 +1239,77 @@ static struct hpc_ops pciehp_hpc_ops = {
        .check_lnk_status               = hpc_check_lnk_status,
 };
 
-int pcie_init(struct controller * ctrl,
-       struct pci_dev *pdev,
-       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);
+                       acpi_os_free(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));
+
+       acpi_os_free(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;
@@ -1259,10 +1317,11 @@ 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;
+       struct pci_dev *pdev;
 
        DBG_ENTER_ROUTINE
        
@@ -1275,11 +1334,12 @@ int pcie_init(struct controller * ctrl,
        }
 
        memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
-
+       
+       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;
 
@@ -1288,55 +1348,54 @@ int pcie_init(struct controller * ctrl,
                goto abort_free_ctlr;
        }
 
-       pcie_cap_base = cap_base;
+       ctrl->cap_base = cap_base;
 
        dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
 
-       rc = hp_register_read_word(pdev, CAP_REG, cap_reg);
+       rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg);
        if (rc) {
                err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG, cap_reg);
+       dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg);
 
-       if (((cap_reg & SLOT_IMPL) == 0) || ((cap_reg & DEV_PORT_TYPE) != 0x0040)){
+       if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
+               && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
                dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
 
-       rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP, slot_cap);
+       rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
        if (rc) {
                err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP, slot_cap);
+       dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap);
 
        if (!(slot_cap & HP_CAP)) {
                dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
        /* For debugging purpose */
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS, slot_status);
+       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: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS, slot_status);
+       dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status);
 
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL, slot_ctrl);
+       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
        if (rc) {
                err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL, slot_ctrl);
+       dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
 
        if (first) {
                spin_lock_init(&hpc_event_lock);
                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), pdev->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,
@@ -1345,19 +1404,21 @@ int pcie_init(struct controller * ctrl,
        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);
 
-       init_MUTEX(&ctrl->crit_sect);
+       if (pci_enable_device(pdev))
+               goto abort_free_ctlr;
+       
+       mutex_init(&ctrl->crit_sect);
        /* setup wait queue */
        init_waitqueue_head(&ctrl->queue);
 
        /* find the IRQ */
-       php_ctlr->irq = pdev->irq;
-       dbg("HPC interrupt = %d\n", php_ctlr->irq);
+       php_ctlr->irq = dev->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 */
@@ -1365,36 +1426,33 @@ int pcie_init(struct controller * ctrl,
        php_ctlr->num_slots = 1;
 
        /* Mask Hot-plug Interrupt Enable */
-       rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+       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;
        }
 
-       dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
+       dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
        temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
 
-       rc = hp_register_write_word(pdev, SLOT_CTRL, temp_word);
+       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;
        }
-       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, slot_status);
+       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, slot_status);
 
        temp_word = 0x1F; /* Clear all events */
-       rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+       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;
        }
-       dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, temp_word);
 
        if (pciehp_poll_mode)  {/* Install interrupt polling code */
                /* Install and start the interrupt polling timer */
@@ -1402,16 +1460,6 @@ 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) {
-                       rc = pci_enable_msi(pdev);
-                       if (rc) {
-                               info("Can't get msi for the hotplug controller\n");
-                               info("Use INTx for the hotplug controller\n");
-                               dbg("%s: rc = %x\n", __FUNCTION__, rc);
-                       } 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) {
@@ -1420,15 +1468,25 @@ int pcie_init(struct controller * ctrl,
                }
        }
 
-       rc = hp_register_read_word(pdev, SLOT_CTRL, temp_word);
+       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;
        }
-       dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL, temp_word);
 
-       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; 
 
@@ -1437,31 +1495,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, temp_word);
+       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;
        }
-       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, slot_status);
+       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: Unmask HPIE SLOT_STATUS offset %x reads slot_status %x\n", __FUNCTION__, 
-               SLOT_STATUS, slot_status);
        
        temp_word =  0x1F; /* Clear all events */
-       rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS, temp_word);
+       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;
        }
-       dbg("%s: SLOT_STATUS offset %x writes slot_status %x\n", __FUNCTION__, SLOT_STATUS, 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_free_ctlr;
+       }
+
        /*  Add this HPC instance into the HPC list */
        spin_lock(&list_lock);
        if (php_ctlr_list_head == 0) {