Commit 50b52fde authored by Rajat Jain's avatar Rajat Jain Committed by Bjorn Helgaas

PCI: pciehp: Add hotplug_lock to serialize hotplug events

Today it is there is no protection around pciehp_enable_slot() and
pciehp_disable_slot() to ensure that they complete before another
hot-plug operation can be done on that particular slot.

This patch introduces the slot->hotplug_lock to ensure that any hotplug
operations (add / remove) complete before another hotplug event can begin
processing on that particular slot.
Signed-off-by: default avatarRajat Jain <rajatxjain@gmail.com>
Signed-off-by: default avatarRajat Jain <rajatjain@juniper.net>
Signed-off-by: default avatarGuenter Roeck <groeck@juniper.net>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent c4f2f5e4
...@@ -76,6 +76,7 @@ struct slot { ...@@ -76,6 +76,7 @@ struct slot {
struct hotplug_slot *hotplug_slot; struct hotplug_slot *hotplug_slot;
struct delayed_work work; /* work for button event */ struct delayed_work work; /* work for button event */
struct mutex lock; struct mutex lock;
struct mutex hotplug_lock;
struct workqueue_struct *wq; struct workqueue_struct *wq;
}; };
......
...@@ -283,8 +283,11 @@ static int pciehp_probe(struct pcie_device *dev) ...@@ -283,8 +283,11 @@ static int pciehp_probe(struct pcie_device *dev)
slot = ctrl->slot; slot = ctrl->slot;
pciehp_get_adapter_status(slot, &occupied); pciehp_get_adapter_status(slot, &occupied);
pciehp_get_power_status(slot, &poweron); pciehp_get_power_status(slot, &poweron);
if (occupied && pciehp_force) if (occupied && pciehp_force) {
mutex_lock(&slot->hotplug_lock);
pciehp_enable_slot(slot); pciehp_enable_slot(slot);
mutex_unlock(&slot->hotplug_lock);
}
/* If empty slot's power status is on, turn power off */ /* If empty slot's power status is on, turn power off */
if (!occupied && poweron && POWER_CTRL(ctrl)) if (!occupied && poweron && POWER_CTRL(ctrl))
pciehp_power_off_slot(slot); pciehp_power_off_slot(slot);
...@@ -328,10 +331,12 @@ static int pciehp_resume (struct pcie_device *dev) ...@@ -328,10 +331,12 @@ static int pciehp_resume (struct pcie_device *dev)
/* Check if slot is occupied */ /* Check if slot is occupied */
pciehp_get_adapter_status(slot, &status); pciehp_get_adapter_status(slot, &status);
mutex_lock(&slot->hotplug_lock);
if (status) if (status)
pciehp_enable_slot(slot); pciehp_enable_slot(slot);
else else
pciehp_disable_slot(slot); pciehp_disable_slot(slot);
mutex_unlock(&slot->hotplug_lock);
return 0; return 0;
} }
#endif /* PM */ #endif /* PM */
......
...@@ -293,6 +293,7 @@ static void pciehp_power_thread(struct work_struct *work) ...@@ -293,6 +293,7 @@ static void pciehp_power_thread(struct work_struct *work)
struct power_work_info *info = struct power_work_info *info =
container_of(work, struct power_work_info, work); container_of(work, struct power_work_info, work);
struct slot *p_slot = info->p_slot; struct slot *p_slot = info->p_slot;
int ret;
switch (info->req) { switch (info->req) {
case DISABLE_REQ: case DISABLE_REQ:
...@@ -300,7 +301,9 @@ static void pciehp_power_thread(struct work_struct *work) ...@@ -300,7 +301,9 @@ static void pciehp_power_thread(struct work_struct *work)
"Disabling domain:bus:device=%04x:%02x:00\n", "Disabling domain:bus:device=%04x:%02x:00\n",
pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
p_slot->ctrl->pcie->port->subordinate->number); p_slot->ctrl->pcie->port->subordinate->number);
mutex_lock(&p_slot->hotplug_lock);
pciehp_disable_slot(p_slot); pciehp_disable_slot(p_slot);
mutex_unlock(&p_slot->hotplug_lock);
mutex_lock(&p_slot->lock); mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE; p_slot->state = STATIC_STATE;
mutex_unlock(&p_slot->lock); mutex_unlock(&p_slot->lock);
...@@ -310,7 +313,10 @@ static void pciehp_power_thread(struct work_struct *work) ...@@ -310,7 +313,10 @@ static void pciehp_power_thread(struct work_struct *work)
"Enabling domain:bus:device=%04x:%02x:00\n", "Enabling domain:bus:device=%04x:%02x:00\n",
pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
p_slot->ctrl->pcie->port->subordinate->number); p_slot->ctrl->pcie->port->subordinate->number);
if (pciehp_enable_slot(p_slot)) mutex_lock(&p_slot->hotplug_lock);
ret = pciehp_enable_slot(p_slot);
mutex_unlock(&p_slot->hotplug_lock);
if (ret)
pciehp_green_led_off(p_slot); pciehp_green_led_off(p_slot);
mutex_lock(&p_slot->lock); mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE; p_slot->state = STATIC_STATE;
...@@ -546,6 +552,9 @@ static void interrupt_event_handler(struct work_struct *work) ...@@ -546,6 +552,9 @@ static void interrupt_event_handler(struct work_struct *work)
kfree(info); kfree(info);
} }
/*
* Note: This function must be called with slot->hotplug_lock held
*/
int pciehp_enable_slot(struct slot *p_slot) int pciehp_enable_slot(struct slot *p_slot)
{ {
u8 getstatus = 0; u8 getstatus = 0;
...@@ -584,7 +593,9 @@ int pciehp_enable_slot(struct slot *p_slot) ...@@ -584,7 +593,9 @@ int pciehp_enable_slot(struct slot *p_slot)
return rc; return rc;
} }
/*
* Note: This function must be called with slot->hotplug_lock held
*/
int pciehp_disable_slot(struct slot *p_slot) int pciehp_disable_slot(struct slot *p_slot)
{ {
u8 getstatus = 0; u8 getstatus = 0;
...@@ -617,7 +628,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot) ...@@ -617,7 +628,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
case STATIC_STATE: case STATIC_STATE:
p_slot->state = POWERON_STATE; p_slot->state = POWERON_STATE;
mutex_unlock(&p_slot->lock); mutex_unlock(&p_slot->lock);
mutex_lock(&p_slot->hotplug_lock);
retval = pciehp_enable_slot(p_slot); retval = pciehp_enable_slot(p_slot);
mutex_unlock(&p_slot->hotplug_lock);
mutex_lock(&p_slot->lock); mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE; p_slot->state = STATIC_STATE;
break; break;
......
...@@ -686,6 +686,7 @@ static int pcie_init_slot(struct controller *ctrl) ...@@ -686,6 +686,7 @@ static int pcie_init_slot(struct controller *ctrl)
slot->ctrl = ctrl; slot->ctrl = ctrl;
mutex_init(&slot->lock); mutex_init(&slot->lock);
mutex_init(&slot->hotplug_lock);
INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
ctrl->slot = slot; ctrl->slot = slot;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment