diff options
author | Rajat Jain <rajatxjain@gmail.com> | 2014-02-04 21:31:11 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-02-11 18:13:16 -0500 |
commit | 50b52fdee050745935d92e7026373edea2647e60 (patch) | |
tree | 0739f5a0135b070c7626542ffd593074341d950b /drivers/pci | |
parent | c4f2f5e4981073a5aa0739f93b6733060cd37648 (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.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 7 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 17 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 1 |
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 | */ | ||
549 | int pciehp_enable_slot(struct slot *p_slot) | 558 | int 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 | */ | ||
588 | int pciehp_disable_slot(struct slot *p_slot) | 599 | int 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; |