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
4 changed files with 23 additions and 3 deletions
|
@ -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)
|
||||||
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)
|
||||||
|
|
||||||
/* 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)
|
||||||
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)
|
||||||
"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)
|
||||||
"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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue