diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 8c51a04..b8983c1 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -58,6 +58,8 @@
  *	used for synchronous writes to the Slot Control register
  * @pending_events: used by the IRQ handler to save events retrieved from the
  *	Slot Status register for later consumption by the IRQ thread
+ * @delayed_events: when we delay an event handling because the slot is being
+ *	removed or rescanned, we use this member to pass the delayed event
  * @notification_enabled: whether the IRQ was requested successfully
  * @power_fault_detected: whether a power fault was detected by the hardware
  *	that has not yet been cleared by the user
@@ -91,6 +93,7 @@ struct controller {
 	wait_queue_head_t queue;
 
 	atomic_t pending_events;		/* event handling */
+	int delayed_events;
 	unsigned int notification_enabled:1;
 	unsigned int power_fault_detected;
 	struct task_struct *poll_thread;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 631ced0..f8b1212 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -141,6 +141,7 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
 {
 	struct controller *ctrl = container_of(work, struct controller,
 					       button_work.work);
+	int events = ctrl->delayed_events;
 
 	mutex_lock(&ctrl->state_lock);
 	switch (ctrl->state) {
@@ -151,6 +152,12 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
 		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
 		break;
 	default:
+		if (events) {
+			atomic_or(events, &ctrl->pending_events);
+			if (!pciehp_poll_mode)
+				irq_wake_thread(ctrl->pcie->irq, ctrl);
+		} else
+			slot_being_removed_rescanned = 0;
 		break;
 	}
 	mutex_unlock(&ctrl->state_lock);
@@ -174,6 +181,7 @@ void pciehp_handle_button_press(struct controller *ctrl)
 		/* blink green LED and turn off amber */
 		pciehp_green_led_blink(ctrl);
 		pciehp_set_attention_status(ctrl, 0);
+		ctrl->delayed_events = 0;
 		schedule_delayed_work(&ctrl->button_work, 5 * HZ);
 		break;
 	case BLINKINGOFF_STATE:
@@ -195,10 +203,12 @@ void pciehp_handle_button_press(struct controller *ctrl)
 		pciehp_set_attention_status(ctrl, 0);
 		ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
 			  slot_name(ctrl));
+		slot_being_removed_rescanned = 0;
 		break;
 	default:
 		ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
 			 slot_name(ctrl), ctrl->state);
+		slot_being_removed_rescanned = 0;
 		break;
 	}
 	mutex_unlock(&ctrl->state_lock);
@@ -217,6 +227,7 @@ void pciehp_handle_disable_request(struct controller *ctrl)
 	mutex_unlock(&ctrl->state_lock);
 
 	ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL);
+	slot_being_removed_rescanned = 0;
 }
 
 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
@@ -254,6 +265,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
 	link_active = pciehp_check_link_active(ctrl);
 	if (!present && !link_active) {
 		mutex_unlock(&ctrl->state_lock);
+		slot_being_removed_rescanned = 0;
 		return;
 	}
 
@@ -276,6 +288,7 @@ void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
 		mutex_unlock(&ctrl->state_lock);
 		break;
 	}
+	slot_being_removed_rescanned = 0;
 }
 
 static int __pciehp_enable_slot(struct controller *ctrl)
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index bd990e3..2db4731 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -631,7 +631,16 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
 	if (events & PCI_EXP_SLTSTA_ABP) {
 		ctrl_info(ctrl, "Slot(%s): Attention button pressed\n",
 			  slot_name(ctrl));
-		pciehp_handle_button_press(ctrl);
+		if (!test_and_set_bit(0, &slot_being_removed_rescanned))
+			pciehp_handle_button_press(ctrl);
+		else {
+			if (ctrl->state == BLINKINGOFF_STATE ||
+			    ctrl->state == BLINKINGON_STATE)
+				pciehp_handle_button_press(ctrl);
+			else
+				ctrl_info(ctrl, "Slot(%s): Slot operation failed because a remove or rescan operation is under processing, please try later!\n",
+					  slot_name(ctrl));
+		}
 	}
 
 	/* Check Power Fault Detected */
@@ -647,10 +656,43 @@ static irqreturn_t pciehp_ist(int irq, void *dev_id)
 	 * or Data Link Layer State Changed events.
 	 */
 	down_read(&ctrl->reset_lock);
-	if (events & DISABLE_SLOT)
-		pciehp_handle_disable_request(ctrl);
-	else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC))
-		pciehp_handle_presence_or_link_change(ctrl, events);
+	if (events & DISABLE_SLOT) {
+		if (!test_and_set_bit(0, &slot_being_removed_rescanned))
+			pciehp_handle_disable_request(ctrl);
+		else {
+			if (ctrl->state == BLINKINGOFF_STATE ||
+			    ctrl->state == BLINKINGON_STATE)
+				pciehp_handle_disable_request(ctrl);
+			/*
+			 * If 'button_work.timer' is pending, delay the work
+			 * will cause BUG_ON() in add_timer().
+			 */
+			else if (!timer_pending(&ctrl->button_work.timer)) {
+
+				ctrl->delayed_events = DISABLE_SLOT;
+				schedule_delayed_work(&ctrl->button_work,
+						      3 * HZ);
+			}
+		}
+	} else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC)) {
+		if (!test_and_set_bit(0, &slot_being_removed_rescanned))
+			pciehp_handle_presence_or_link_change(ctrl, events);
+		else {
+			if (ctrl->state == BLINKINGOFF_STATE ||
+			    ctrl->state == BLINKINGON_STATE)
+				pciehp_handle_presence_or_link_change(ctrl,
+						events);
+			else if (!timer_pending(&ctrl->button_work.timer)) {
+				ctrl_info(ctrl, "Slot(%s): Surprise link down/up in remove or rescan process!\n",
+					  slot_name(ctrl));
+				ctrl->delayed_events = events &
+							(PCI_EXP_SLTSTA_PDC |
+							PCI_EXP_SLTSTA_DLLSC);
+				schedule_delayed_work(&ctrl->button_work,
+						      3 * HZ);
+			}
+		}
+	}
 	up_read(&ctrl->reset_lock);
 
 	pci_config_pm_runtime_put(pdev);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 965c721..8ddfd0d 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -473,11 +473,18 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr,
 {
 	unsigned long val;
 
+	if (test_and_set_bit(0, &slot_being_removed_rescanned)) {
+		pr_info("Slot is being removed or rescanned, please try later!\n");
+		return -EINVAL;
+	}
+
 	if (kstrtoul(buf, 0, &val) < 0)
 		return -EINVAL;
 
 	if (val && device_remove_file_self(dev, attr))
 		pci_stop_and_remove_bus_device_locked(to_pci_dev(dev));
+
+	slot_being_removed_rescanned = 0;
 	return count;
 }
 static struct device_attribute dev_remove_attr = __ATTR_IGNORE_LOCKDEP(remove,
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index e9c6b12..6d15ad0 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -3,6 +3,11 @@
 #include <linux/module.h>
 #include "pci.h"
 
+/*
+ * When a slot is being removed/rescanned, this flag is set.
+ */
+unsigned long slot_being_removed_rescanned;
+
 static void pci_free_resources(struct pci_dev *dev)
 {
 	int i;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 9e700d9..92575ee 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -952,6 +952,9 @@ enum pcie_bus_config_types {
 /* Do NOT directly access these two variables, unless you are arch-specific PCI
  * code, or PCI core code. */
 extern struct list_head pci_root_buses;	/* List of all known PCI buses */
+
+extern unsigned long slot_being_removed_rescanned;
+
 /* Some device drivers need know if PCI is initiated */
 int no_pci_devices(void);
 
