Commit ef3be547 authored by Kenji Kaneshige's avatar Kenji Kaneshige Committed by Greg Kroah-Hartman

[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: default avatarKenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent d29aadda
...@@ -307,15 +307,10 @@ static int board_added(struct slot *p_slot) ...@@ -307,15 +307,10 @@ static int board_added(struct slot *p_slot)
__FUNCTION__, p_slot->device, __FUNCTION__, p_slot->device,
ctrl->slot_device_offset, hp_slot); ctrl->slot_device_offset, hp_slot);
/* Wait for exclusive access to hardware */
mutex_lock(&ctrl->crit_sect);
/* Power on slot without connecting to bus */ /* Power on slot without connecting to bus */
rc = p_slot->hpc_ops->power_on_slot(p_slot); rc = p_slot->hpc_ops->power_on_slot(p_slot);
if (rc) { if (rc) {
err("%s: Failed to power on slot\n", __FUNCTION__); err("%s: Failed to power on slot\n", __FUNCTION__);
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
return -1; return -1;
} }
...@@ -325,14 +320,12 @@ static int board_added(struct slot *p_slot) ...@@ -325,14 +320,12 @@ static int board_added(struct slot *p_slot)
if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) { if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
mutex_unlock(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY; return WRONG_BUS_FREQUENCY;
} }
/* turn on board, blink green LED, turn off Amber LED */ /* turn on board, blink green LED, turn off Amber LED */
if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
mutex_unlock(&ctrl->crit_sect);
return rc; return rc;
} }
} }
...@@ -346,16 +339,12 @@ static int board_added(struct slot *p_slot) ...@@ -346,16 +339,12 @@ static int board_added(struct slot *p_slot)
if (rc || adapter_speed == PCI_SPEED_UNKNOWN) { if (rc || adapter_speed == PCI_SPEED_UNKNOWN) {
err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__); err("%s: Can't get adapter speed or bus mode mismatch\n", __FUNCTION__);
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY; return WRONG_BUS_FREQUENCY;
} }
rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed); rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed);
if (rc || bus_speed == PCI_SPEED_UNKNOWN) { if (rc || bus_speed == PCI_SPEED_UNKNOWN) {
err("%s: Can't get bus operation speed\n", __FUNCTION__); err("%s: Can't get bus operation speed\n", __FUNCTION__);
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
return WRONG_BUS_FREQUENCY; return WRONG_BUS_FREQUENCY;
} }
...@@ -365,9 +354,6 @@ static int board_added(struct slot *p_slot) ...@@ -365,9 +354,6 @@ static int board_added(struct slot *p_slot)
max_bus_speed = bus_speed; max_bus_speed = bus_speed;
} }
/* Done with exclusive hardware access */
mutex_unlock(&ctrl->crit_sect);
if ((rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) { if ((rc = p_slot->hpc_ops->get_prog_int(p_slot, &pi))) {
err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__); err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__);
pi = 1; pi = 1;
...@@ -744,29 +730,25 @@ static void interrupt_event_handler(struct controller *ctrl) ...@@ -744,29 +730,25 @@ static void interrupt_event_handler(struct controller *ctrl)
int shpchp_enable_slot (struct slot *p_slot) int shpchp_enable_slot (struct slot *p_slot)
{ {
u8 getstatus = 0; u8 getstatus = 0;
int rc; int rc, retval = -ENODEV;
/* Check to see if (latch closed, card present, power off) */ /* Check to see if (latch closed, card present, power off) */
mutex_lock(&p_slot->ctrl->crit_sect); mutex_lock(&p_slot->ctrl->crit_sect);
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) { if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect); goto out;
return -ENODEV;
} }
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) { if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect); goto out;
return -ENODEV;
} }
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) { if (rc || getstatus) {
info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect); goto out;
return -ENODEV;
} }
mutex_unlock(&p_slot->ctrl->crit_sect);
p_slot->is_a_board = 1; p_slot->is_a_board = 1;
...@@ -781,27 +763,29 @@ int shpchp_enable_slot (struct slot *p_slot) ...@@ -781,27 +763,29 @@ int shpchp_enable_slot (struct slot *p_slot)
&& p_slot->ctrl->num_slots == 1) { && p_slot->ctrl->num_slots == 1) {
/* handle amd pogo errata; this must be done before enable */ /* handle amd pogo errata; this must be done before enable */
amd_pogo_errata_save_misc_reg(p_slot); amd_pogo_errata_save_misc_reg(p_slot);
rc = board_added(p_slot); retval = board_added(p_slot);
/* handle amd pogo errata; this must be done after enable */ /* handle amd pogo errata; this must be done after enable */
amd_pogo_errata_restore_misc_reg(p_slot); amd_pogo_errata_restore_misc_reg(p_slot);
} else } else
rc = board_added(p_slot); retval = board_added(p_slot);
if (rc) { if (retval) {
p_slot->hpc_ops->get_adapter_status(p_slot, p_slot->hpc_ops->get_adapter_status(p_slot,
&(p_slot->presence_save)); &(p_slot->presence_save));
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
} }
update_slot_info(p_slot); update_slot_info(p_slot);
return rc; out:
mutex_unlock(&p_slot->ctrl->crit_sect);
return retval;
} }
int shpchp_disable_slot (struct slot *p_slot) int shpchp_disable_slot (struct slot *p_slot)
{ {
u8 getstatus = 0; u8 getstatus = 0;
int ret = 0; int rc, retval = -ENODEV;
if (!p_slot->ctrl) if (!p_slot->ctrl)
return -ENODEV; return -ENODEV;
...@@ -809,28 +793,26 @@ int shpchp_disable_slot (struct slot *p_slot) ...@@ -809,28 +793,26 @@ int shpchp_disable_slot (struct slot *p_slot)
/* Check to see if (latch closed, card present, power on) */ /* Check to see if (latch closed, card present, power on) */
mutex_lock(&p_slot->ctrl->crit_sect); mutex_lock(&p_slot->ctrl->crit_sect);
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) { if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect); goto out;
return -ENODEV;
} }
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) { if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect); goto out;
return -ENODEV;
} }
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) { if (rc || !getstatus) {
info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect); goto out;
return -ENODEV;
} }
mutex_unlock(&p_slot->ctrl->crit_sect);
ret = remove_board(p_slot); retval = remove_board(p_slot);
update_slot_info(p_slot); update_slot_info(p_slot);
return ret; out:
mutex_unlock(&p_slot->ctrl->crit_sect);
return retval;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment