diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2006-09-22 13:17:29 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-10-18 14:36:10 -0400 |
commit | dd5619cb4407e830a8921a93c949be37c81105b5 (patch) | |
tree | f726db26b6019e6f741dfb146e3d37eca9198cf4 | |
parent | 49ed2b4963cd00993eab518b820a6700f94f222d (diff) |
pciehp - add missing locking
This patch fixes the problem that system will panic if multiple power
on/off operations are issued to the same slot in parallel. This
problem can be easily reproduced by commands below.
# while true; do echo 1 > power; echo 0 > power; done &
# while true; do echo 1 > power; echo 0 > power; done &
The cause is lack of locking for enable/disable operations. This patch
fixes this problem.
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/pci/hotplug/pciehp.h | 1 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_core.c | 6 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_ctrl.c | 54 | ||||
-rw-r--r-- | drivers/pci/hotplug/pciehp_hpc.c | 2 |
4 files changed, 33 insertions, 30 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index b71f774aca16..30f021c55fe5 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h | |||
@@ -92,6 +92,7 @@ struct php_ctlr_state_s { | |||
92 | struct controller { | 92 | struct controller { |
93 | struct controller *next; | 93 | struct controller *next; |
94 | struct mutex crit_sect; /* critical section mutex */ | 94 | struct mutex crit_sect; /* critical section mutex */ |
95 | struct mutex ctrl_lock; /* controller lock */ | ||
95 | struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ | 96 | struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */ |
96 | int num_slots; /* Number of slots on ctlr */ | 97 | int num_slots; /* Number of slots on ctlr */ |
97 | int slot_num_inc; /* 1 or -1 */ | 98 | int slot_num_inc; /* 1 or -1 */ |
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index c67b7c3f1ddf..f93e81e2d2c7 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c | |||
@@ -448,7 +448,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
448 | } | 448 | } |
449 | 449 | ||
450 | /* Wait for exclusive access to hardware */ | 450 | /* Wait for exclusive access to hardware */ |
451 | mutex_lock(&ctrl->crit_sect); | 451 | mutex_lock(&ctrl->ctrl_lock); |
452 | 452 | ||
453 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ | 453 | t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */ |
454 | 454 | ||
@@ -456,7 +456,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
456 | rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ | 456 | rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ |
457 | if (rc) { | 457 | if (rc) { |
458 | /* Done with exclusive hardware access */ | 458 | /* Done with exclusive hardware access */ |
459 | mutex_unlock(&ctrl->crit_sect); | 459 | mutex_unlock(&ctrl->ctrl_lock); |
460 | goto err_out_free_ctrl_slot; | 460 | goto err_out_free_ctrl_slot; |
461 | } else | 461 | } else |
462 | /* Wait for the command to complete */ | 462 | /* Wait for the command to complete */ |
@@ -464,7 +464,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ | |||
464 | } | 464 | } |
465 | 465 | ||
466 | /* Done with exclusive hardware access */ | 466 | /* Done with exclusive hardware access */ |
467 | mutex_unlock(&ctrl->crit_sect); | 467 | mutex_unlock(&ctrl->ctrl_lock); |
468 | 468 | ||
469 | return 0; | 469 | return 0; |
470 | 470 | ||
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index f602b042adcf..c206a3d63b63 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c | |||
@@ -234,13 +234,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id) | |||
234 | static void set_slot_off(struct controller *ctrl, struct slot * pslot) | 234 | static void set_slot_off(struct controller *ctrl, struct slot * pslot) |
235 | { | 235 | { |
236 | /* Wait for exclusive access to hardware */ | 236 | /* Wait for exclusive access to hardware */ |
237 | mutex_lock(&ctrl->crit_sect); | 237 | mutex_lock(&ctrl->ctrl_lock); |
238 | 238 | ||
239 | /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ | 239 | /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ |
240 | if (POWER_CTRL(ctrl->ctrlcap)) { | 240 | if (POWER_CTRL(ctrl->ctrlcap)) { |
241 | if (pslot->hpc_ops->power_off_slot(pslot)) { | 241 | if (pslot->hpc_ops->power_off_slot(pslot)) { |
242 | err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); | 242 | err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__); |
243 | mutex_unlock(&ctrl->crit_sect); | 243 | mutex_unlock(&ctrl->ctrl_lock); |
244 | return; | 244 | return; |
245 | } | 245 | } |
246 | wait_for_ctrl_irq (ctrl); | 246 | wait_for_ctrl_irq (ctrl); |
@@ -254,14 +254,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) | |||
254 | if (ATTN_LED(ctrl->ctrlcap)) { | 254 | if (ATTN_LED(ctrl->ctrlcap)) { |
255 | if (pslot->hpc_ops->set_attention_status(pslot, 1)) { | 255 | if (pslot->hpc_ops->set_attention_status(pslot, 1)) { |
256 | err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); | 256 | err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__); |
257 | mutex_unlock(&ctrl->crit_sect); | 257 | mutex_unlock(&ctrl->ctrl_lock); |
258 | return; | 258 | return; |
259 | } | 259 | } |
260 | wait_for_ctrl_irq (ctrl); | 260 | wait_for_ctrl_irq (ctrl); |
261 | } | 261 | } |
262 | 262 | ||
263 | /* Done with exclusive hardware access */ | 263 | /* Done with exclusive hardware access */ |
264 | mutex_unlock(&ctrl->crit_sect); | 264 | mutex_unlock(&ctrl->ctrl_lock); |
265 | } | 265 | } |
266 | 266 | ||
267 | /** | 267 | /** |
@@ -284,13 +284,13 @@ static int board_added(struct slot *p_slot) | |||
284 | ctrl->slot_device_offset, hp_slot); | 284 | ctrl->slot_device_offset, hp_slot); |
285 | 285 | ||
286 | /* Wait for exclusive access to hardware */ | 286 | /* Wait for exclusive access to hardware */ |
287 | mutex_lock(&ctrl->crit_sect); | 287 | mutex_lock(&ctrl->ctrl_lock); |
288 | 288 | ||
289 | if (POWER_CTRL(ctrl->ctrlcap)) { | 289 | if (POWER_CTRL(ctrl->ctrlcap)) { |
290 | /* Power on slot */ | 290 | /* Power on slot */ |
291 | rc = p_slot->hpc_ops->power_on_slot(p_slot); | 291 | rc = p_slot->hpc_ops->power_on_slot(p_slot); |
292 | if (rc) { | 292 | if (rc) { |
293 | mutex_unlock(&ctrl->crit_sect); | 293 | mutex_unlock(&ctrl->ctrl_lock); |
294 | return -1; | 294 | return -1; |
295 | } | 295 | } |
296 | 296 | ||
@@ -306,7 +306,7 @@ static int board_added(struct slot *p_slot) | |||
306 | } | 306 | } |
307 | 307 | ||
308 | /* Done with exclusive hardware access */ | 308 | /* Done with exclusive hardware access */ |
309 | mutex_unlock(&ctrl->crit_sect); | 309 | mutex_unlock(&ctrl->ctrl_lock); |
310 | 310 | ||
311 | /* Wait for ~1 second */ | 311 | /* Wait for ~1 second */ |
312 | wait_for_ctrl_irq (ctrl); | 312 | wait_for_ctrl_irq (ctrl); |
@@ -340,7 +340,7 @@ static int board_added(struct slot *p_slot) | |||
340 | pci_fixup_device(pci_fixup_final, ctrl->pci_dev); | 340 | pci_fixup_device(pci_fixup_final, ctrl->pci_dev); |
341 | if (PWR_LED(ctrl->ctrlcap)) { | 341 | if (PWR_LED(ctrl->ctrlcap)) { |
342 | /* Wait for exclusive access to hardware */ | 342 | /* Wait for exclusive access to hardware */ |
343 | mutex_lock(&ctrl->crit_sect); | 343 | mutex_lock(&ctrl->ctrl_lock); |
344 | 344 | ||
345 | p_slot->hpc_ops->green_led_on(p_slot); | 345 | p_slot->hpc_ops->green_led_on(p_slot); |
346 | 346 | ||
@@ -348,7 +348,7 @@ static int board_added(struct slot *p_slot) | |||
348 | wait_for_ctrl_irq (ctrl); | 348 | wait_for_ctrl_irq (ctrl); |
349 | 349 | ||
350 | /* Done with exclusive hardware access */ | 350 | /* Done with exclusive hardware access */ |
351 | mutex_unlock(&ctrl->crit_sect); | 351 | mutex_unlock(&ctrl->ctrl_lock); |
352 | } | 352 | } |
353 | return 0; | 353 | return 0; |
354 | 354 | ||
@@ -380,14 +380,14 @@ static int remove_board(struct slot *p_slot) | |||
380 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); | 380 | dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); |
381 | 381 | ||
382 | /* Wait for exclusive access to hardware */ | 382 | /* Wait for exclusive access to hardware */ |
383 | mutex_lock(&ctrl->crit_sect); | 383 | mutex_lock(&ctrl->ctrl_lock); |
384 | 384 | ||
385 | if (POWER_CTRL(ctrl->ctrlcap)) { | 385 | if (POWER_CTRL(ctrl->ctrlcap)) { |
386 | /* power off slot */ | 386 | /* power off slot */ |
387 | rc = p_slot->hpc_ops->power_off_slot(p_slot); | 387 | rc = p_slot->hpc_ops->power_off_slot(p_slot); |
388 | if (rc) { | 388 | if (rc) { |
389 | err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); | 389 | err("%s: Issue of Slot Disable command failed\n", __FUNCTION__); |
390 | mutex_unlock(&ctrl->crit_sect); | 390 | mutex_unlock(&ctrl->ctrl_lock); |
391 | return rc; | 391 | return rc; |
392 | } | 392 | } |
393 | /* Wait for the command to complete */ | 393 | /* Wait for the command to complete */ |
@@ -403,7 +403,7 @@ static int remove_board(struct slot *p_slot) | |||
403 | } | 403 | } |
404 | 404 | ||
405 | /* Done with exclusive hardware access */ | 405 | /* Done with exclusive hardware access */ |
406 | mutex_unlock(&ctrl->crit_sect); | 406 | mutex_unlock(&ctrl->ctrl_lock); |
407 | 407 | ||
408 | return 0; | 408 | return 0; |
409 | } | 409 | } |
@@ -450,7 +450,7 @@ static void pciehp_pushbutton_thread(unsigned long slot) | |||
450 | 450 | ||
451 | if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { | 451 | if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { |
452 | /* Wait for exclusive access to hardware */ | 452 | /* Wait for exclusive access to hardware */ |
453 | mutex_lock(&p_slot->ctrl->crit_sect); | 453 | mutex_lock(&p_slot->ctrl->ctrl_lock); |
454 | 454 | ||
455 | p_slot->hpc_ops->green_led_off(p_slot); | 455 | p_slot->hpc_ops->green_led_off(p_slot); |
456 | 456 | ||
@@ -458,7 +458,7 @@ static void pciehp_pushbutton_thread(unsigned long slot) | |||
458 | wait_for_ctrl_irq (p_slot->ctrl); | 458 | wait_for_ctrl_irq (p_slot->ctrl); |
459 | 459 | ||
460 | /* Done with exclusive hardware access */ | 460 | /* Done with exclusive hardware access */ |
461 | mutex_unlock(&p_slot->ctrl->crit_sect); | 461 | mutex_unlock(&p_slot->ctrl->ctrl_lock); |
462 | } | 462 | } |
463 | p_slot->state = STATIC_STATE; | 463 | p_slot->state = STATIC_STATE; |
464 | } | 464 | } |
@@ -500,7 +500,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot) | |||
500 | 500 | ||
501 | if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { | 501 | if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) { |
502 | /* Wait for exclusive access to hardware */ | 502 | /* Wait for exclusive access to hardware */ |
503 | mutex_lock(&p_slot->ctrl->crit_sect); | 503 | mutex_lock(&p_slot->ctrl->ctrl_lock); |
504 | 504 | ||
505 | p_slot->hpc_ops->green_led_off(p_slot); | 505 | p_slot->hpc_ops->green_led_off(p_slot); |
506 | 506 | ||
@@ -508,7 +508,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot) | |||
508 | wait_for_ctrl_irq (p_slot->ctrl); | 508 | wait_for_ctrl_irq (p_slot->ctrl); |
509 | 509 | ||
510 | /* Done with exclusive hardware access */ | 510 | /* Done with exclusive hardware access */ |
511 | mutex_unlock(&p_slot->ctrl->crit_sect); | 511 | mutex_unlock(&p_slot->ctrl->ctrl_lock); |
512 | } | 512 | } |
513 | p_slot->state = STATIC_STATE; | 513 | p_slot->state = STATIC_STATE; |
514 | } | 514 | } |
@@ -621,7 +621,7 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
621 | switch (p_slot->state) { | 621 | switch (p_slot->state) { |
622 | case BLINKINGOFF_STATE: | 622 | case BLINKINGOFF_STATE: |
623 | /* Wait for exclusive access to hardware */ | 623 | /* Wait for exclusive access to hardware */ |
624 | mutex_lock(&ctrl->crit_sect); | 624 | mutex_lock(&ctrl->ctrl_lock); |
625 | 625 | ||
626 | if (PWR_LED(ctrl->ctrlcap)) { | 626 | if (PWR_LED(ctrl->ctrlcap)) { |
627 | p_slot->hpc_ops->green_led_on(p_slot); | 627 | p_slot->hpc_ops->green_led_on(p_slot); |
@@ -635,11 +635,11 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
635 | wait_for_ctrl_irq (ctrl); | 635 | wait_for_ctrl_irq (ctrl); |
636 | } | 636 | } |
637 | /* Done with exclusive hardware access */ | 637 | /* Done with exclusive hardware access */ |
638 | mutex_unlock(&ctrl->crit_sect); | 638 | mutex_unlock(&ctrl->ctrl_lock); |
639 | break; | 639 | break; |
640 | case BLINKINGON_STATE: | 640 | case BLINKINGON_STATE: |
641 | /* Wait for exclusive access to hardware */ | 641 | /* Wait for exclusive access to hardware */ |
642 | mutex_lock(&ctrl->crit_sect); | 642 | mutex_lock(&ctrl->ctrl_lock); |
643 | 643 | ||
644 | if (PWR_LED(ctrl->ctrlcap)) { | 644 | if (PWR_LED(ctrl->ctrlcap)) { |
645 | p_slot->hpc_ops->green_led_off(p_slot); | 645 | p_slot->hpc_ops->green_led_off(p_slot); |
@@ -652,7 +652,7 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
652 | wait_for_ctrl_irq (ctrl); | 652 | wait_for_ctrl_irq (ctrl); |
653 | } | 653 | } |
654 | /* Done with exclusive hardware access */ | 654 | /* Done with exclusive hardware access */ |
655 | mutex_unlock(&ctrl->crit_sect); | 655 | mutex_unlock(&ctrl->ctrl_lock); |
656 | 656 | ||
657 | break; | 657 | break; |
658 | default: | 658 | default: |
@@ -681,7 +681,7 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
681 | } | 681 | } |
682 | 682 | ||
683 | /* Wait for exclusive access to hardware */ | 683 | /* Wait for exclusive access to hardware */ |
684 | mutex_lock(&ctrl->crit_sect); | 684 | mutex_lock(&ctrl->ctrl_lock); |
685 | 685 | ||
686 | /* blink green LED and turn off amber */ | 686 | /* blink green LED and turn off amber */ |
687 | if (PWR_LED(ctrl->ctrlcap)) { | 687 | if (PWR_LED(ctrl->ctrlcap)) { |
@@ -698,7 +698,7 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
698 | } | 698 | } |
699 | 699 | ||
700 | /* Done with exclusive hardware access */ | 700 | /* Done with exclusive hardware access */ |
701 | mutex_unlock(&ctrl->crit_sect); | 701 | mutex_unlock(&ctrl->ctrl_lock); |
702 | 702 | ||
703 | init_timer(&p_slot->task_event); | 703 | init_timer(&p_slot->task_event); |
704 | p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ | 704 | p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */ |
@@ -713,7 +713,7 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
713 | if (POWER_CTRL(ctrl->ctrlcap)) { | 713 | if (POWER_CTRL(ctrl->ctrlcap)) { |
714 | dbg("power fault\n"); | 714 | dbg("power fault\n"); |
715 | /* Wait for exclusive access to hardware */ | 715 | /* Wait for exclusive access to hardware */ |
716 | mutex_lock(&ctrl->crit_sect); | 716 | mutex_lock(&ctrl->ctrl_lock); |
717 | 717 | ||
718 | if (ATTN_LED(ctrl->ctrlcap)) { | 718 | if (ATTN_LED(ctrl->ctrlcap)) { |
719 | p_slot->hpc_ops->set_attention_status(p_slot, 1); | 719 | p_slot->hpc_ops->set_attention_status(p_slot, 1); |
@@ -726,7 +726,7 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
726 | } | 726 | } |
727 | 727 | ||
728 | /* Done with exclusive hardware access */ | 728 | /* Done with exclusive hardware access */ |
729 | mutex_unlock(&ctrl->crit_sect); | 729 | mutex_unlock(&ctrl->ctrl_lock); |
730 | } | 730 | } |
731 | } | 731 | } |
732 | /***********SURPRISE REMOVAL********************/ | 732 | /***********SURPRISE REMOVAL********************/ |
@@ -789,7 +789,6 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
789 | return -EINVAL; | 789 | return -EINVAL; |
790 | } | 790 | } |
791 | } | 791 | } |
792 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
793 | 792 | ||
794 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 793 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
795 | 794 | ||
@@ -801,6 +800,7 @@ int pciehp_enable_slot(struct slot *p_slot) | |||
801 | if (p_slot) | 800 | if (p_slot) |
802 | update_slot_info(p_slot); | 801 | update_slot_info(p_slot); |
803 | 802 | ||
803 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
804 | return rc; | 804 | return rc; |
805 | } | 805 | } |
806 | 806 | ||
@@ -846,10 +846,10 @@ int pciehp_disable_slot(struct slot *p_slot) | |||
846 | } | 846 | } |
847 | } | 847 | } |
848 | 848 | ||
849 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
850 | |||
851 | ret = remove_board(p_slot); | 849 | ret = remove_board(p_slot); |
852 | update_slot_info(p_slot); | 850 | update_slot_info(p_slot); |
851 | |||
852 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
853 | return ret; | 853 | return ret; |
854 | } | 854 | } |
855 | 855 | ||
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 703a64a39fe8..1c551c697c35 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c | |||
@@ -1402,6 +1402,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) | |||
1402 | pdev->subsystem_vendor, pdev->subsystem_device); | 1402 | pdev->subsystem_vendor, pdev->subsystem_device); |
1403 | 1403 | ||
1404 | mutex_init(&ctrl->crit_sect); | 1404 | mutex_init(&ctrl->crit_sect); |
1405 | mutex_init(&ctrl->ctrl_lock); | ||
1406 | |||
1405 | /* setup wait queue */ | 1407 | /* setup wait queue */ |
1406 | init_waitqueue_head(&ctrl->queue); | 1408 | init_waitqueue_head(&ctrl->queue); |
1407 | 1409 | ||