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: Rajat Jain <rajatxjain@gmail.com> Signed-off-by: Rajat Jain <rajatjain@juniper.net> Signed-off-by: Guenter Roeck <groeck@juniper.net> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
c4f2f5e498
commit
50b52fdee0
|
@ -76,6 +76,7 @@ struct slot {
|
|||
struct hotplug_slot *hotplug_slot;
|
||||
struct delayed_work work; /* work for button event */
|
||||
struct mutex lock;
|
||||
struct mutex hotplug_lock;
|
||||
struct workqueue_struct *wq;
|
||||
};
|
||||
|
||||
|
|
|
@ -283,8 +283,11 @@ static int pciehp_probe(struct pcie_device *dev)
|
|||
slot = ctrl->slot;
|
||||
pciehp_get_adapter_status(slot, &occupied);
|
||||
pciehp_get_power_status(slot, &poweron);
|
||||
if (occupied && pciehp_force)
|
||||
if (occupied && pciehp_force) {
|
||||
mutex_lock(&slot->hotplug_lock);
|
||||
pciehp_enable_slot(slot);
|
||||
mutex_unlock(&slot->hotplug_lock);
|
||||
}
|
||||
/* If empty slot's power status is on, turn power off */
|
||||
if (!occupied && poweron && POWER_CTRL(ctrl))
|
||||
pciehp_power_off_slot(slot);
|
||||
|
@ -328,10 +331,12 @@ static int pciehp_resume (struct pcie_device *dev)
|
|||
|
||||
/* Check if slot is occupied */
|
||||
pciehp_get_adapter_status(slot, &status);
|
||||
mutex_lock(&slot->hotplug_lock);
|
||||
if (status)
|
||||
pciehp_enable_slot(slot);
|
||||
else
|
||||
pciehp_disable_slot(slot);
|
||||
mutex_unlock(&slot->hotplug_lock);
|
||||
return 0;
|
||||
}
|
||||
#endif /* PM */
|
||||
|
|
|
@ -293,6 +293,7 @@ static void pciehp_power_thread(struct work_struct *work)
|
|||
struct power_work_info *info =
|
||||
container_of(work, struct power_work_info, work);
|
||||
struct slot *p_slot = info->p_slot;
|
||||
int ret;
|
||||
|
||||
switch (info->req) {
|
||||
case DISABLE_REQ:
|
||||
|
@ -300,7 +301,9 @@ static void pciehp_power_thread(struct work_struct *work)
|
|||
"Disabling domain:bus:device=%04x:%02x:00\n",
|
||||
pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
|
||||
p_slot->ctrl->pcie->port->subordinate->number);
|
||||
mutex_lock(&p_slot->hotplug_lock);
|
||||
pciehp_disable_slot(p_slot);
|
||||
mutex_unlock(&p_slot->hotplug_lock);
|
||||
mutex_lock(&p_slot->lock);
|
||||
p_slot->state = STATIC_STATE;
|
||||
mutex_unlock(&p_slot->lock);
|
||||
|
@ -310,7 +313,10 @@ static void pciehp_power_thread(struct work_struct *work)
|
|||
"Enabling domain:bus:device=%04x:%02x:00\n",
|
||||
pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
|
||||
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);
|
||||
mutex_lock(&p_slot->lock);
|
||||
p_slot->state = STATIC_STATE;
|
||||
|
@ -546,6 +552,9 @@ static void interrupt_event_handler(struct work_struct *work)
|
|||
kfree(info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: This function must be called with slot->hotplug_lock held
|
||||
*/
|
||||
int pciehp_enable_slot(struct slot *p_slot)
|
||||
{
|
||||
u8 getstatus = 0;
|
||||
|
@ -584,7 +593,9 @@ int pciehp_enable_slot(struct slot *p_slot)
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Note: This function must be called with slot->hotplug_lock held
|
||||
*/
|
||||
int pciehp_disable_slot(struct slot *p_slot)
|
||||
{
|
||||
u8 getstatus = 0;
|
||||
|
@ -617,7 +628,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
|
|||
case STATIC_STATE:
|
||||
p_slot->state = POWERON_STATE;
|
||||
mutex_unlock(&p_slot->lock);
|
||||
mutex_lock(&p_slot->hotplug_lock);
|
||||
retval = pciehp_enable_slot(p_slot);
|
||||
mutex_unlock(&p_slot->hotplug_lock);
|
||||
mutex_lock(&p_slot->lock);
|
||||
p_slot->state = STATIC_STATE;
|
||||
break;
|
||||
|
|
|
@ -686,6 +686,7 @@ static int pcie_init_slot(struct controller *ctrl)
|
|||
|
||||
slot->ctrl = ctrl;
|
||||
mutex_init(&slot->lock);
|
||||
mutex_init(&slot->hotplug_lock);
|
||||
INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
|
||||
ctrl->slot = slot;
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue