diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2006-01-25 20:00:33 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-23 17:35:11 -0500 |
commit | ef3be54777901e570185089f21fbe4498453f67e (patch) | |
tree | 6b03aacd9c9c99ec2160014e0d64415893f6f9f7 /drivers/pci/hotplug/shpchp_ctrl.c | |
parent | d29aaddab3ef3bdaecf3c9c6d9423f0bf0452ccf (diff) |
[PATCH] shpchp - bugfix: add missing serialization
Current shpchp driver might cause system panic because of lack of
serialization. It can be reproduced very easily by the following
operation.
# cd /sys/bus/pci/slots/<slot#>
# while true; do echo 0 > power ; echo 1 > power ; done &
# while true; do echo 0 > power ; echo 1 > power ; done &
This patch fixes this issue by changing shpchp to get appropreate
semaphore for hot-plug operation.
Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/pci/hotplug/shpchp_ctrl.c')
-rw-r--r-- | drivers/pci/hotplug/shpchp_ctrl.c | 66 |
1 files changed, 24 insertions, 42 deletions
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 802c4c48d186..1a7003d4ba96 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c | |||
@@ -307,15 +307,10 @@ static int board_added(struct slot *p_slot) | |||
307 | __FUNCTION__, p_slot->device, | 307 | __FUNCTION__, p_slot->device, |
308 | ctrl->slot_device_offset, hp_slot); | 308 | ctrl->slot_device_offset, hp_slot); |
309 | 309 | ||
310 | /* Wait for exclusive access to hardware */ | ||
311 | mutex_lock(&ctrl->crit_sect); | ||
312 | |||
313 | /* Power on slot without connecting to bus */ | 310 | /* Power on slot without connecting to bus */ |
314 | rc = p_slot->hpc_ops->power_on_slot(p_slot); | 311 | rc = p_slot->hpc_ops->power_on_slot(p_slot); |
315 | if (rc) { | 312 | if (rc) { |
316 | err("%s: Failed to power on slot\n", __FUNCTION__); | 313 | err("%s: Failed to power on slot\n", __FUNCTION__); |
317 | /* Done with exclusive hardware access */ | ||
318 | mutex_unlock(&ctrl->crit_sect); | ||
319 | return -1; | 314 | return -1; |
320 | } | 315 | } |
321 | 316 | ||
@@ -325,14 +320,12 @@ static int board_added(struct slot *p_slot) | |||
325 | 320 | ||
326 | if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { | 321 | if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { |
327 | err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); | 322 | err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); |
328 | mutex_unlock(&ctrl->crit_sect); | ||
329 | return WRONG_BUS_FREQUENCY; | 323 | return WRONG_BUS_FREQUENCY; |
330 | } | 324 | } |
331 | 325 | ||
332 | /* turn on board, blink green LED, turn off Amber LED */ | 326 | /* turn on board, blink green LED, turn off Amber LED */ |
333 | if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { | 327 | if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { |
334 | err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); | 328 | err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); |
335 | mutex_unlock(&ctrl->crit_sect); | ||
336 | return rc; | 329 | return rc; |
337 | } | 330 | } |
338 | } | 331 | } |
@@ -346,16 +339,12 @@ static int board_added(struct slot *p_slot) | |||
346 | 339 | ||
347 | if (rc || adapter_speed == PCI_SPEED_UNKNOWN) { | 340 | if (rc || adapter_speed == PCI_SPEED_UNKNOWN) { |
348 | err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__); | 341 | err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__); |
349 | /* Done with exclusive hardware access */ | ||
350 | mutex_unlock(&ctrl->crit_sect); | ||
351 | return WRONG_BUS_FREQUENCY; | 342 | return WRONG_BUS_FREQUENCY; |
352 | } | 343 | } |
353 | 344 | ||
354 | rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed); | 345 | rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed); |
355 | if (rc || bus_speed == PCI_SPEED_UNKNOWN) { | 346 | if (rc || bus_speed == PCI_SPEED_UNKNOWN) { |
356 | err("%s: Can't get bus operation speed\n", __FUNCTION__); | 347 | err("%s: Can't get bus operation speed\n", __FUNCTION__); |
357 | /* Done with exclusive hardware access */ | ||
358 | mutex_unlock(&ctrl->crit_sect); | ||
359 | return WRONG_BUS_FREQUENCY; | 348 | return WRONG_BUS_FREQUENCY; |
360 | } | 349 | } |
361 | 350 | ||
@@ -365,9 +354,6 @@ static int board_added(struct slot *p_slot) | |||
365 | max_bus_speed = bus_speed; | 354 | max_bus_speed = bus_speed; |
366 | } | 355 | } |
367 | 356 | ||
368 | /* Done with exclusive hardware access */ | ||
369 | mutex_unlock(&ctrl->crit_sect); | ||
370 | |||
371 | if ((rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) { | 357 | if ((rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) { |
372 | err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__); | 358 | err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__); |
373 | pi = 1; | 359 | pi = 1; |
@@ -744,29 +730,25 @@ static void interrupt_event_handler(struct controller *ctrl) | |||
744 | int shpchp_enable_slot (struct slot *p_slot) | 730 | int shpchp_enable_slot (struct slot *p_slot) |
745 | { | 731 | { |
746 | u8 getstatus = 0; | 732 | u8 getstatus = 0; |
747 | int rc; | 733 | int rc, retval = -ENODEV; |
748 | 734 | ||
749 | /* Check to see if (latch closed, card present, power off) */ | 735 | /* Check to see if (latch closed, card present, power off) */ |
750 | mutex_lock(&p_slot->ctrl->crit_sect); | 736 | mutex_lock(&p_slot->ctrl->crit_sect); |
751 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 737 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
752 | if (rc || !getstatus) { | 738 | if (rc || !getstatus) { |
753 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); | 739 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); |
754 | mutex_unlock(&p_slot->ctrl->crit_sect); | 740 | goto out; |
755 | return -ENODEV; | ||
756 | } | 741 | } |
757 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 742 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
758 | if (rc || getstatus) { | 743 | if (rc || getstatus) { |
759 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); | 744 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); |
760 | mutex_unlock(&p_slot->ctrl->crit_sect); | 745 | goto out; |
761 | return -ENODEV; | ||
762 | } | 746 | } |
763 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 747 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
764 | if (rc || getstatus) { | 748 | if (rc || getstatus) { |
765 | info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); | 749 | info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); |
766 | mutex_unlock(&p_slot->ctrl->crit_sect); | 750 | goto out; |
767 | return -ENODEV; | ||
768 | } | 751 | } |
769 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
770 | 752 | ||
771 | p_slot->is_a_board = 1; | 753 | p_slot->is_a_board = 1; |
772 | 754 | ||
@@ -781,27 +763,29 @@ int shpchp_enable_slot (struct slot *p_slot) | |||
781 | && p_slot->ctrl->num_slots == 1) { | 763 | && p_slot->ctrl->num_slots == 1) { |
782 | /* handle amd pogo errata; this must be done before enable */ | 764 | /* handle amd pogo errata; this must be done before enable */ |
783 | amd_pogo_errata_save_misc_reg(p_slot); | 765 | amd_pogo_errata_save_misc_reg(p_slot); |
784 | rc = board_added(p_slot); | 766 | retval = board_added(p_slot); |
785 | /* handle amd pogo errata; this must be done after enable */ | 767 | /* handle amd pogo errata; this must be done after enable */ |
786 | amd_pogo_errata_restore_misc_reg(p_slot); | 768 | amd_pogo_errata_restore_misc_reg(p_slot); |
787 | } else | 769 | } else |
788 | rc = board_added(p_slot); | 770 | retval = board_added(p_slot); |
789 | 771 | ||
790 | if (rc) { | 772 | if (retval) { |
791 | p_slot->hpc_ops->get_adapter_status(p_slot, | 773 | p_slot->hpc_ops->get_adapter_status(p_slot, |
792 | &(p_slot->presence_save)); | 774 | &(p_slot->presence_save)); |
793 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 775 | p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
794 | } | 776 | } |
795 | 777 | ||
796 | update_slot_info(p_slot); | 778 | update_slot_info(p_slot); |
797 | return rc; | 779 | out: |
780 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
781 | return retval; | ||
798 | } | 782 | } |
799 | 783 | ||
800 | 784 | ||
801 | int shpchp_disable_slot (struct slot *p_slot) | 785 | int shpchp_disable_slot (struct slot *p_slot) |
802 | { | 786 | { |
803 | u8 getstatus = 0; | 787 | u8 getstatus = 0; |
804 | int ret = 0; | 788 | int rc, retval = -ENODEV; |
805 | 789 | ||
806 | if (!p_slot->ctrl) | 790 | if (!p_slot->ctrl) |
807 | return -ENODEV; | 791 | return -ENODEV; |
@@ -809,28 +793,26 @@ int shpchp_disable_slot (struct slot *p_slot) | |||
809 | /* Check to see if (latch closed, card present, power on) */ | 793 | /* Check to see if (latch closed, card present, power on) */ |
810 | mutex_lock(&p_slot->ctrl->crit_sect); | 794 | mutex_lock(&p_slot->ctrl->crit_sect); |
811 | 795 | ||
812 | ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); | 796 | rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); |
813 | if (ret || !getstatus) { | 797 | if (rc || !getstatus) { |
814 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); | 798 | info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); |
815 | mutex_unlock(&p_slot->ctrl->crit_sect); | 799 | goto out; |
816 | return -ENODEV; | ||
817 | } | 800 | } |
818 | ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); | 801 | rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); |
819 | if (ret || getstatus) { | 802 | if (rc || getstatus) { |
820 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); | 803 | info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); |
821 | mutex_unlock(&p_slot->ctrl->crit_sect); | 804 | goto out; |
822 | return -ENODEV; | ||
823 | } | 805 | } |
824 | ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); | 806 | rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); |
825 | if (ret || !getstatus) { | 807 | if (rc || !getstatus) { |
826 | info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); | 808 | info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); |
827 | mutex_unlock(&p_slot->ctrl->crit_sect); | 809 | goto out; |
828 | return -ENODEV; | ||
829 | } | 810 | } |
830 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
831 | 811 | ||
832 | ret = remove_board(p_slot); | 812 | retval = remove_board(p_slot); |
833 | update_slot_info(p_slot); | 813 | update_slot_info(p_slot); |
834 | return ret; | 814 | out: |
815 | mutex_unlock(&p_slot->ctrl->crit_sect); | ||
816 | return retval; | ||
835 | } | 817 | } |
836 | 818 | ||