aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorRajat Jain <rajatxjain@gmail.com>2014-02-04 21:31:11 -0500
committerBjorn Helgaas <bhelgaas@google.com>2014-02-11 18:13:16 -0500
commit50b52fdee050745935d92e7026373edea2647e60 (patch)
tree0739f5a0135b070c7626542ffd593074341d950b /drivers/pci
parentc4f2f5e4981073a5aa0739f93b6733060cd37648 (diff)
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>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/hotplug/pciehp.h1
-rw-r--r--drivers/pci/hotplug/pciehp_core.c7
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c17
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c1
4 files changed, 23 insertions, 3 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index d8d033619a77..8a66866b8cf1 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -76,6 +76,7 @@ struct slot {
76 struct hotplug_slot *hotplug_slot; 76 struct hotplug_slot *hotplug_slot;
77 struct delayed_work work; /* work for button event */ 77 struct delayed_work work; /* work for button event */
78 struct mutex lock; 78 struct mutex lock;
79 struct mutex hotplug_lock;
79 struct workqueue_struct *wq; 80 struct workqueue_struct *wq;
80}; 81};
81 82
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 53b58debc288..23b4bde8aad3 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -283,8 +283,11 @@ static int pciehp_probe(struct pcie_device *dev)
283 slot = ctrl->slot; 283 slot = ctrl->slot;
284 pciehp_get_adapter_status(slot, &occupied); 284 pciehp_get_adapter_status(slot, &occupied);
285 pciehp_get_power_status(slot, &poweron); 285 pciehp_get_power_status(slot, &poweron);
286 if (occupied && pciehp_force) 286 if (occupied && pciehp_force) {
287 mutex_lock(&slot->hotplug_lock);
287 pciehp_enable_slot(slot); 288 pciehp_enable_slot(slot);
289 mutex_unlock(&slot->hotplug_lock);
290 }
288 /* If empty slot's power status is on, turn power off */ 291 /* If empty slot's power status is on, turn power off */
289 if (!occupied && poweron && POWER_CTRL(ctrl)) 292 if (!occupied && poweron && POWER_CTRL(ctrl))
290 pciehp_power_off_slot(slot); 293 pciehp_power_off_slot(slot);
@@ -328,10 +331,12 @@ static int pciehp_resume (struct pcie_device *dev)
328 331
329 /* Check if slot is occupied */ 332 /* Check if slot is occupied */
330 pciehp_get_adapter_status(slot, &status); 333 pciehp_get_adapter_status(slot, &status);
334 mutex_lock(&slot->hotplug_lock);
331 if (status) 335 if (status)
332 pciehp_enable_slot(slot); 336 pciehp_enable_slot(slot);
333 else 337 else
334 pciehp_disable_slot(slot); 338 pciehp_disable_slot(slot);
339 mutex_unlock(&slot->hotplug_lock);
335 return 0; 340 return 0;
336} 341}
337#endif /* PM */ 342#endif /* PM */
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 3e40ec0f7da1..fec99a164d93 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -293,6 +293,7 @@ static void pciehp_power_thread(struct work_struct *work)
293 struct power_work_info *info = 293 struct power_work_info *info =
294 container_of(work, struct power_work_info, work); 294 container_of(work, struct power_work_info, work);
295 struct slot *p_slot = info->p_slot; 295 struct slot *p_slot = info->p_slot;
296 int ret;
296 297
297 switch (info->req) { 298 switch (info->req) {
298 case DISABLE_REQ: 299 case DISABLE_REQ:
@@ -300,7 +301,9 @@ static void pciehp_power_thread(struct work_struct *work)
300 "Disabling domain:bus:device=%04x:%02x:00\n", 301 "Disabling domain:bus:device=%04x:%02x:00\n",
301 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), 302 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
302 p_slot->ctrl->pcie->port->subordinate->number); 303 p_slot->ctrl->pcie->port->subordinate->number);
304 mutex_lock(&p_slot->hotplug_lock);
303 pciehp_disable_slot(p_slot); 305 pciehp_disable_slot(p_slot);
306 mutex_unlock(&p_slot->hotplug_lock);
304 mutex_lock(&p_slot->lock); 307 mutex_lock(&p_slot->lock);
305 p_slot->state = STATIC_STATE; 308 p_slot->state = STATIC_STATE;
306 mutex_unlock(&p_slot->lock); 309 mutex_unlock(&p_slot->lock);
@@ -310,7 +313,10 @@ static void pciehp_power_thread(struct work_struct *work)
310 "Enabling domain:bus:device=%04x:%02x:00\n", 313 "Enabling domain:bus:device=%04x:%02x:00\n",
311 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate), 314 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
312 p_slot->ctrl->pcie->port->subordinate->number); 315 p_slot->ctrl->pcie->port->subordinate->number);
313 if (pciehp_enable_slot(p_slot)) 316 mutex_lock(&p_slot->hotplug_lock);
317 ret = pciehp_enable_slot(p_slot);
318 mutex_unlock(&p_slot->hotplug_lock);
319 if (ret)
314 pciehp_green_led_off(p_slot); 320 pciehp_green_led_off(p_slot);
315 mutex_lock(&p_slot->lock); 321 mutex_lock(&p_slot->lock);
316 p_slot->state = STATIC_STATE; 322 p_slot->state = STATIC_STATE;
@@ -546,6 +552,9 @@ static void interrupt_event_handler(struct work_struct *work)
546 kfree(info); 552 kfree(info);
547} 553}
548 554
555/*
556 * Note: This function must be called with slot->hotplug_lock held
557 */
549int pciehp_enable_slot(struct slot *p_slot) 558int pciehp_enable_slot(struct slot *p_slot)
550{ 559{
551 u8 getstatus = 0; 560 u8 getstatus = 0;
@@ -584,7 +593,9 @@ int pciehp_enable_slot(struct slot *p_slot)
584 return rc; 593 return rc;
585} 594}
586 595
587 596/*
597 * Note: This function must be called with slot->hotplug_lock held
598 */
588int pciehp_disable_slot(struct slot *p_slot) 599int pciehp_disable_slot(struct slot *p_slot)
589{ 600{
590 u8 getstatus = 0; 601 u8 getstatus = 0;
@@ -617,7 +628,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
617 case STATIC_STATE: 628 case STATIC_STATE:
618 p_slot->state = POWERON_STATE; 629 p_slot->state = POWERON_STATE;
619 mutex_unlock(&p_slot->lock); 630 mutex_unlock(&p_slot->lock);
631 mutex_lock(&p_slot->hotplug_lock);
620 retval = pciehp_enable_slot(p_slot); 632 retval = pciehp_enable_slot(p_slot);
633 mutex_unlock(&p_slot->hotplug_lock);
621 mutex_lock(&p_slot->lock); 634 mutex_lock(&p_slot->lock);
622 p_slot->state = STATIC_STATE; 635 p_slot->state = STATIC_STATE;
623 break; 636 break;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 6433e73aa2df..da4b0204b4f7 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -686,6 +686,7 @@ static int pcie_init_slot(struct controller *ctrl)
686 686
687 slot->ctrl = ctrl; 687 slot->ctrl = ctrl;
688 mutex_init(&slot->lock); 688 mutex_init(&slot->lock);
689 mutex_init(&slot->hotplug_lock);
689 INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work); 690 INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
690 ctrl->slot = slot; 691 ctrl->slot = slot;
691 return 0; 692 return 0;