[PATCH] PCI Express Hotplug: clear sticky power-fault bit

Per the PCI Express spec, the power-fault-detected bit in the
slot status register can be set anytime hardware detects a power
fault, regardless of whether the slot has a device populated in
it or not. This bit is sticky and must be explicitly cleared.
This patch is needed to allow hot-add after such a power fault
has been detected.

Signed-off-by: Rajesh Shah <rajesh.shah@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index c42b68d..6a61b9f 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -59,7 +59,6 @@
 	struct slot *next;
 	u8 bus;
 	u8 device;
-	u16 status;
 	u32 number;
 	u8 state;
 	struct timer_list task_event;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 5e582ec..83c4b86 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -207,7 +207,6 @@
 		 * power fault Cleared
 		 */
 		info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
-		p_slot->status = 0x00;
 		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
 	} else {
 		/*
@@ -215,8 +214,6 @@
 		 */
 		info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
 		taskInfo->event_type = INT_POWER_FAULT;
-		/* set power fault status for this board */
-		p_slot->status = 0xFF;
 		info("power fault bit %x set\n", hp_slot);
 	}
 	if (rc)
@@ -317,13 +314,10 @@
 		return rc;
 	}
 
-	dbg("%s: slot status = %x\n", __FUNCTION__, p_slot->status);
-
 	/* Check for a power fault */
-	if (p_slot->status == 0xFF) {
-		/* power fault occurred, but it was benign */
+	if (p_slot->hpc_ops->query_power_fault(p_slot)) {
+		dbg("%s: power fault detected\n", __FUNCTION__);
 		rc = POWER_FAILURE;
-		p_slot->status = 0;
 		goto err_exit;
 	}
 
@@ -334,8 +328,6 @@
 		goto err_exit;
 	}
 
-	p_slot->status = 0;
-
 	/*
 	 * Some PCI Express root ports require fixup after hot-plug operation.
 	 */
@@ -382,9 +374,6 @@
 
 	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
 
-	/* Change status to shutdown */
-	p_slot->status = 0x01;
-
 	/* Wait for exclusive access to hardware */
 	down(&ctrl->crit_sect);
 
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 2387e75..0b8b26b 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -750,7 +750,7 @@
 {
 	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;
 
@@ -767,6 +767,14 @@
 		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) {