diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 1ba335d6563a75df82dc10efad8959a055a3acdd..ed42dde5f9ac3fed1b8acf586552b99cf5fbdf98 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -105,6 +105,9 @@ struct slot {
  *	that has not yet been cleared by the user
  * @pending_events: used by the IRQ handler to save events retrieved from the
  *	Slot Status register for later consumption by the IRQ thread
+ * @request_result: result of last user request submitted to the IRQ thread
+ * @requester: wait queue to wake up on completion of user request,
+ *	used for synchronous slot enable/disable request via sysfs
  */
 struct controller {
 	struct mutex ctrl_lock;
@@ -120,6 +123,8 @@ struct controller {
 	unsigned int notification_enabled:1;
 	unsigned int power_fault_detected;
 	atomic_t pending_events;
+	int request_result;
+	wait_queue_head_t requester;
 };
 
 /**
@@ -141,6 +146,17 @@ struct controller {
 #define POWEROFF_STATE			4
 #define ON_STATE			5
 
+/**
+ * DOC: Flags to request an action from the IRQ thread
+ *
+ * These are stored together with events read from the Slot Status register,
+ * hence must be greater than its 16-bit width.
+ *
+ * %DISABLE_SLOT: Disable the slot in response to a user request via sysfs or
+ *	an Attention Button press after the 5 second delay
+ */
+#define DISABLE_SLOT		(1 << 16)
+
 #define ATTN_BUTTN(ctrl)	((ctrl)->slot_cap & PCI_EXP_SLTCAP_ABP)
 #define POWER_CTRL(ctrl)	((ctrl)->slot_cap & PCI_EXP_SLTCAP_PCP)
 #define MRL_SENS(ctrl)		((ctrl)->slot_cap & PCI_EXP_SLTCAP_MRLSP)
@@ -153,7 +169,9 @@ struct controller {
 
 int pciehp_sysfs_enable_slot(struct slot *slot);
 int pciehp_sysfs_disable_slot(struct slot *slot);
+void pciehp_request(struct controller *ctrl, int action);
 void pciehp_handle_button_press(struct slot *slot);
+void pciehp_handle_disable_request(struct slot *slot);
 void pciehp_handle_link_change(struct slot *slot);
 void pciehp_handle_presence_change(struct slot *slot);
 int pciehp_configure_device(struct slot *p_slot);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index cde32e137f6cd11b056c0116b82814513bdecc0c..b11f0db0695f9e58ea97473b022d606ac6b16956 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -240,13 +240,19 @@ static int pciehp_probe(struct pcie_device *dev)
 	}
 
 	/* Check if slot is occupied */
+	mutex_lock(&slot->lock);
 	pciehp_get_adapter_status(slot, &occupied);
 	pciehp_get_power_status(slot, &poweron);
-	if (occupied && pciehp_force)
-		pciehp_enable_slot(slot);
+	if (pciehp_force &&
+	    ((occupied && (slot->state == OFF_STATE ||
+			   slot->state == BLINKINGON_STATE)) ||
+	     (!occupied && (slot->state == ON_STATE ||
+			    slot->state == BLINKINGOFF_STATE))))
+		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
 	/* If empty slot's power status is on, turn power off */
 	if (!occupied && poweron && POWER_CTRL(ctrl))
 		pciehp_power_off_slot(slot);
+	mutex_unlock(&slot->lock);
 
 	return 0;
 
@@ -290,10 +296,14 @@ static int pciehp_resume(struct pcie_device *dev)
 
 	/* Check if slot is occupied */
 	pciehp_get_adapter_status(slot, &status);
-	if (status)
-		pciehp_enable_slot(slot);
-	else
-		pciehp_disable_slot(slot);
+	mutex_lock(&slot->lock);
+	if ((status && (slot->state == OFF_STATE ||
+			slot->state == BLINKINGON_STATE)) ||
+	    (!status && (slot->state == ON_STATE ||
+			 slot->state == BLINKINGOFF_STATE)))
+		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
+	mutex_unlock(&slot->lock);
+
 	return 0;
 }
 #endif /* PM */
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 627e846df8028f73b1fbdadc8dbbbe4e2cad0e61..70bad847a450950bf60c257f89632b2ffb8d035b 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -122,22 +122,26 @@ static void remove_board(struct slot *p_slot)
 	pciehp_green_led_off(p_slot);
 }
 
+void pciehp_request(struct controller *ctrl, int action)
+{
+	atomic_or(action, &ctrl->pending_events);
+	if (!pciehp_poll_mode)
+		irq_wake_thread(ctrl->pcie->irq, ctrl);
+}
+
 void pciehp_queue_pushbutton_work(struct work_struct *work)
 {
 	struct slot *p_slot = container_of(work, struct slot, work.work);
+	struct controller *ctrl = p_slot->ctrl;
 
 	mutex_lock(&p_slot->lock);
 	switch (p_slot->state) {
 	case BLINKINGOFF_STATE:
-		p_slot->state = POWEROFF_STATE;
-		mutex_unlock(&p_slot->lock);
-		pciehp_disable_slot(p_slot);
-		return;
+		pciehp_request(ctrl, DISABLE_SLOT);
+		break;
 	case BLINKINGON_STATE:
-		p_slot->state = POWERON_STATE;
-		mutex_unlock(&p_slot->lock);
-		pciehp_enable_slot(p_slot);
-		return;
+		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
+		break;
 	default:
 		break;
 	}
@@ -186,16 +190,6 @@ void pciehp_handle_button_press(struct slot *p_slot)
 		ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
 			  slot_name(p_slot));
 		break;
-	case POWEROFF_STATE:
-	case POWERON_STATE:
-		/*
-		 * Ignore if the slot is on power-on or power-off state;
-		 * this means that the previous attention button action
-		 * to hot-add or hot-remove is undergoing
-		 */
-		ctrl_info(ctrl, "Slot(%s): Button ignored\n",
-			  slot_name(p_slot));
-		break;
 	default:
 		ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
 			 slot_name(p_slot), p_slot->state);
@@ -204,6 +198,22 @@ void pciehp_handle_button_press(struct slot *p_slot)
 	mutex_unlock(&p_slot->lock);
 }
 
+void pciehp_handle_disable_request(struct slot *slot)
+{
+	struct controller *ctrl = slot->ctrl;
+
+	mutex_lock(&slot->lock);
+	switch (slot->state) {
+	case BLINKINGON_STATE:
+	case BLINKINGOFF_STATE:
+		cancel_delayed_work(&slot->work);
+	}
+	slot->state = POWEROFF_STATE;
+	mutex_unlock(&slot->lock);
+
+	ctrl->request_result = pciehp_disable_slot(slot);
+}
+
 void pciehp_handle_link_change(struct slot *p_slot)
 {
 	struct controller *ctrl = p_slot->ctrl;
@@ -232,32 +242,6 @@ void pciehp_handle_link_change(struct slot *p_slot)
 		}
 		return;
 		break;
-	case POWERON_STATE:
-		if (link_active) {
-			ctrl_info(ctrl, "Slot(%s): Link Up event ignored; already powering on\n",
-				  slot_name(p_slot));
-		} else {
-			p_slot->state = POWEROFF_STATE;
-			mutex_unlock(&p_slot->lock);
-			ctrl_info(ctrl, "Slot(%s): Link Down event queued; currently getting powered on\n",
-				  slot_name(p_slot));
-			pciehp_disable_slot(p_slot);
-			return;
-		}
-		break;
-	case POWEROFF_STATE:
-		if (link_active) {
-			p_slot->state = POWERON_STATE;
-			mutex_unlock(&p_slot->lock);
-			ctrl_info(ctrl, "Slot(%s): Link Up event queued; currently getting powered off\n",
-				  slot_name(p_slot));
-			pciehp_enable_slot(p_slot);
-			return;
-		} else {
-			ctrl_info(ctrl, "Slot(%s): Link Down event ignored; already powering off\n",
-				  slot_name(p_slot));
-		}
-		break;
 	default:
 		ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
 			 slot_name(p_slot), p_slot->state);
@@ -272,6 +256,12 @@ void pciehp_handle_presence_change(struct slot *slot)
 	u8 present;
 
 	mutex_lock(&slot->lock);
+	switch (slot->state) {
+	case BLINKINGON_STATE:
+	case BLINKINGOFF_STATE:
+		cancel_delayed_work(&slot->work);
+	}
+
 	pciehp_get_adapter_status(slot, &present);
 	ctrl_info(ctrl, "Slot(%s): Card %spresent\n", slot_name(slot),
 		  present ? "" : "not ");
@@ -279,7 +269,7 @@ void pciehp_handle_presence_change(struct slot *slot)
 	if (present) {
 		slot->state = POWERON_STATE;
 		mutex_unlock(&slot->lock);
-		pciehp_enable_slot(slot);
+		ctrl->request_result = pciehp_enable_slot(slot);
 	} else {
 		slot->state = POWEROFF_STATE;
 		mutex_unlock(&slot->lock);
@@ -383,11 +373,17 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
 	mutex_lock(&p_slot->lock);
 	switch (p_slot->state) {
 	case BLINKINGON_STATE:
-		cancel_delayed_work(&p_slot->work);
 	case OFF_STATE:
-		p_slot->state = POWERON_STATE;
 		mutex_unlock(&p_slot->lock);
-		return pciehp_enable_slot(p_slot);
+		/*
+		 * The IRQ thread becomes a no-op if the user pulls out the
+		 * card before the thread wakes up, so initialize to -ENODEV.
+		 */
+		ctrl->request_result = -ENODEV;
+		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
+		wait_event(ctrl->requester,
+			   !atomic_read(&ctrl->pending_events));
+		return ctrl->request_result;
 	case POWERON_STATE:
 		ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
 			  slot_name(p_slot));
@@ -415,11 +411,12 @@ int pciehp_sysfs_disable_slot(struct slot *p_slot)
 	mutex_lock(&p_slot->lock);
 	switch (p_slot->state) {
 	case BLINKINGOFF_STATE:
-		cancel_delayed_work(&p_slot->work);
 	case ON_STATE:
-		p_slot->state = POWEROFF_STATE;
 		mutex_unlock(&p_slot->lock);
-		return pciehp_disable_slot(p_slot);
+		pciehp_request(ctrl, DISABLE_SLOT);
+		wait_event(ctrl->requester,
+			   !atomic_read(&ctrl->pending_events));
+		return ctrl->request_result;
 	case POWEROFF_STATE:
 		ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
 			  slot_name(p_slot));
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 9c6a18da1af51c533bf34b7785e72ea10de6c80f..6951a0123e392a6ba1497ac980aa2e96bb67b9fd 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -595,11 +595,16 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
 	}
 
 	/*
+	 * Disable requests have higher priority than Presence Detect Changed
+	 * or Data Link Layer State Changed events.
+	 *
 	 * Check Link Status Changed at higher precedence than Presence
 	 * Detect Changed.  The PDS value may be set to "card present" from
 	 * out-of-band detection, which may be in conflict with a Link Down.
 	 */
-	if (events & PCI_EXP_SLTSTA_DLLSC)
+	if (events & DISABLE_SLOT)
+		pciehp_handle_disable_request(slot);
+	else if (events & PCI_EXP_SLTSTA_DLLSC)
 		pciehp_handle_link_change(slot);
 	else if (events & PCI_EXP_SLTSTA_PDC)
 		pciehp_handle_presence_change(slot);
@@ -612,6 +617,7 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
 		pciehp_green_led_off(slot);
 	}
 
+	wake_up(&ctrl->requester);
 	return IRQ_HANDLED;
 }
 
@@ -625,8 +631,9 @@ static int pciehp_poll(void *data)
 		if (kthread_should_park())
 			kthread_parkme();
 
-		/* poll for interrupt events */
-		while (pciehp_isr(IRQ_NOTCONNECTED, ctrl) == IRQ_WAKE_THREAD)
+		/* poll for interrupt events or user requests */
+		while (pciehp_isr(IRQ_NOTCONNECTED, ctrl) == IRQ_WAKE_THREAD ||
+		       atomic_read(&ctrl->pending_events))
 			pciehp_ist(IRQ_NOTCONNECTED, ctrl);
 
 		if (pciehp_poll_time <= 0 || pciehp_poll_time > 60)
@@ -830,6 +837,7 @@ struct controller *pcie_init(struct pcie_device *dev)
 
 	ctrl->slot_cap = slot_cap;
 	mutex_init(&ctrl->ctrl_lock);
+	init_waitqueue_head(&ctrl->requester);
 	init_waitqueue_head(&ctrl->queue);
 	dbg_ctrl(ctrl);