Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Kenji Kaneshige and committed by
Greg Kroah-Hartman
ef3be547 d29aadda

+24 -42
+24 -42
drivers/pci/hotplug/shpchp_ctrl.c
··· 307 307 __FUNCTION__, p_slot->device, 308 308 ctrl->slot_device_offset, hp_slot); 309 309 310 - /* Wait for exclusive access to hardware */ 311 - mutex_lock(&ctrl->crit_sect); 312 - 313 310 /* Power on slot without connecting to bus */ 314 311 rc = p_slot->hpc_ops->power_on_slot(p_slot); 315 312 if (rc) { 316 313 err("%s: Failed to power on slot\n", __FUNCTION__); 317 - /* Done with exclusive hardware access */ 318 - mutex_unlock(&ctrl->crit_sect); 319 314 return -1; 320 315 } 321 316 ··· 320 325 321 326 if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { 322 327 err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); 323 - mutex_unlock(&ctrl->crit_sect); 324 328 return WRONG_BUS_FREQUENCY; 325 329 } 326 330 327 331 /* turn on board, blink green LED, turn off Amber LED */ 328 332 if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { 329 333 err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); 330 - mutex_unlock(&ctrl->crit_sect); 331 334 return rc; 332 335 } 333 336 } ··· 339 346 340 347 if (rc || adapter_speed == PCI_SPEED_UNKNOWN) { 341 348 err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__); 342 - /* Done with exclusive hardware access */ 343 - mutex_unlock(&ctrl->crit_sect); 344 349 return WRONG_BUS_FREQUENCY; 345 350 } 346 351 347 352 rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed); 348 353 if (rc || bus_speed == PCI_SPEED_UNKNOWN) { 349 354 err("%s: Can't get bus operation speed\n", __FUNCTION__); 350 - /* Done with exclusive hardware access */ 351 - mutex_unlock(&ctrl->crit_sect); 352 355 return WRONG_BUS_FREQUENCY; 353 356 } 354 357 ··· 353 364 err("%s: Can't get max bus operation speed\n", __FUNCTION__); 354 365 max_bus_speed = bus_speed; 355 366 } 356 - 357 - /* Done with exclusive hardware access */ 358 - mutex_unlock(&ctrl->crit_sect); 359 367 360 368 if ((rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) { 361 369 err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__); ··· 730 744 int shpchp_enable_slot (struct slot *p_slot) 731 745 { 732 746 u8 getstatus = 0; 733 - int rc; 747 + int rc, retval = -ENODEV; 734 748 735 749 /* Check to see if (latch closed, card present, power off) */ 736 750 mutex_lock(&p_slot->ctrl->crit_sect); 737 751 rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 738 752 if (rc || !getstatus) { 739 753 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); 740 - mutex_unlock(&p_slot->ctrl->crit_sect); 741 - return -ENODEV; 754 + goto out; 742 755 } 743 756 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 744 757 if (rc || getstatus) { 745 758 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); 746 - mutex_unlock(&p_slot->ctrl->crit_sect); 747 - return -ENODEV; 759 + goto out; 748 760 } 749 761 rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 750 762 if (rc || getstatus) { 751 763 info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); 752 - mutex_unlock(&p_slot->ctrl->crit_sect); 753 - return -ENODEV; 764 + goto out; 754 765 } 755 - mutex_unlock(&p_slot->ctrl->crit_sect); 756 766 757 767 p_slot->is_a_board = 1; 758 768 ··· 763 781 && p_slot->ctrl->num_slots == 1) { 764 782 /* handle amd pogo errata; this must be done before enable */ 765 783 amd_pogo_errata_save_misc_reg(p_slot); 766 - rc = board_added(p_slot); 784 + retval = board_added(p_slot); 767 785 /* handle amd pogo errata; this must be done after enable */ 768 786 amd_pogo_errata_restore_misc_reg(p_slot); 769 787 } else 770 - rc = board_added(p_slot); 788 + retval = board_added(p_slot); 771 789 772 - if (rc) { 790 + if (retval) { 773 791 p_slot->hpc_ops->get_adapter_status(p_slot, 774 792 &(p_slot->presence_save)); 775 793 p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 776 794 } 777 795 778 796 update_slot_info(p_slot); 779 - return rc; 797 + out: 798 + mutex_unlock(&p_slot->ctrl->crit_sect); 799 + return retval; 780 800 } 781 801 782 802 783 803 int shpchp_disable_slot (struct slot *p_slot) 784 804 { 785 805 u8 getstatus = 0; 786 - int ret = 0; 806 + int rc, retval = -ENODEV; 787 807 788 808 if (!p_slot->ctrl) 789 809 return -ENODEV; ··· 793 809 /* Check to see if (latch closed, card present, power on) */ 794 810 mutex_lock(&p_slot->ctrl->crit_sect); 795 811 796 - ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 797 - if (ret || !getstatus) { 812 + rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); 813 + if (rc || !getstatus) { 798 814 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); 799 - mutex_unlock(&p_slot->ctrl->crit_sect); 800 - return -ENODEV; 815 + goto out; 801 816 } 802 - ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 803 - if (ret || getstatus) { 817 + rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 818 + if (rc || getstatus) { 804 819 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); 805 - mutex_unlock(&p_slot->ctrl->crit_sect); 806 - return -ENODEV; 820 + goto out; 807 821 } 808 - ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 809 - if (ret || !getstatus) { 822 + rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); 823 + if (rc || !getstatus) { 810 824 info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); 811 - mutex_unlock(&p_slot->ctrl->crit_sect); 812 - return -ENODEV; 825 + goto out; 813 826 } 814 - mutex_unlock(&p_slot->ctrl->crit_sect); 815 827 816 - ret = remove_board(p_slot); 828 + retval = remove_board(p_slot); 817 829 update_slot_info(p_slot); 818 - return ret; 830 + out: 831 + mutex_unlock(&p_slot->ctrl->crit_sect); 832 + return retval; 819 833 } 820 834