diff options
author | Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> | 2006-01-26 10:00:33 +0900 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-23 14:35:11 -0800 |
commit | ef3be54777901e570185089f21fbe4498453f67e (patch) | |
tree | 6b03aacd9c9c99ec2160014e0d64415893f6f9f7 /drivers/pci | |
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')
-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 802c4c48d18..1a7003d4ba9 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) __FUNCTION__, p_slot->device, ctrl->slot_device_offset, hp_slot); - /* Wait for exclusive access to hardware */ - mutex_lock(&ctrl->crit_sect); - /* Power on slot without connecting to bus */ rc = p_slot->hpc_ops->power_on_slot(p_slot); if (rc) { err("%s: Failed to power on slot\n", __FUNCTION__); - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); return -1; } @@ -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))) { err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->crit_sect); return WRONG_BUS_FREQUENCY; } /* turn on board, blink green LED, turn off Amber LED */ if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) { err("%s: Issue of Slot Enable command failed\n", __FUNCTION__); - mutex_unlock(&ctrl->crit_sect); return rc; } } @@ -346,16 +339,12 @@ static int board_added(struct slot *p_slot) if (rc || adapter_speed == PCI_SPEED_UNKNOWN) { 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; } rc = p_slot->hpc_ops->get_cur_bus_speed(p_slot, &bus_speed); if (rc || bus_speed == PCI_SPEED_UNKNOWN) { err("%s: Can't get bus operation speed\n", __FUNCTION__); - /* Done with exclusive hardware access */ - mutex_unlock(&ctrl->crit_sect); return WRONG_BUS_FREQUENCY; } @@ -365,9 +354,6 @@ static int board_added(struct slot *p_slot) 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))) { err("%s: Can't get controller programming interface, set it to 1\n", __FUNCTION__); pi = 1; @@ -744,29 +730,25 @@ static void interrupt_event_handler(struct controller *ctrl) int shpchp_enable_slot (struct slot *p_slot) { u8 getstatus = 0; - int rc; + int rc, retval = -ENODEV; /* Check to see if (latch closed, card present, power off) */ mutex_lock(&p_slot->ctrl->crit_sect); rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (rc || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); - mutex_unlock(&p_slot->ctrl->crit_sect); - return -ENODEV; + goto out; } rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); - mutex_unlock(&p_slot->ctrl->crit_sect); - return -ENODEV; + goto out; } rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); - mutex_unlock(&p_slot->ctrl->crit_sect); - return -ENODEV; + goto out; } - mutex_unlock(&p_slot->ctrl->crit_sect); p_slot->is_a_board = 1; @@ -781,27 +763,29 @@ int shpchp_enable_slot (struct slot *p_slot) && p_slot->ctrl->num_slots == 1) { /* handle amd pogo errata; this must be done before enable */ 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 */ amd_pogo_errata_restore_misc_reg(p_slot); } 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->presence_save)); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); } 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) { u8 getstatus = 0; - int ret = 0; + int rc, retval = -ENODEV; if (!p_slot->ctrl) return -ENODEV; @@ -809,28 +793,26 @@ int shpchp_disable_slot (struct slot *p_slot) /* Check to see if (latch closed, card present, power on) */ mutex_lock(&p_slot->ctrl->crit_sect); - ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); - if (ret || !getstatus) { + rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); + if (rc || !getstatus) { info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); - mutex_unlock(&p_slot->ctrl->crit_sect); - return -ENODEV; + goto out; } - ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); - if (ret || getstatus) { + rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); + if (rc || getstatus) { info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); - mutex_unlock(&p_slot->ctrl->crit_sect); - return -ENODEV; + goto out; } - ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); - if (ret || !getstatus) { + rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); + if (rc || !getstatus) { info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); - mutex_unlock(&p_slot->ctrl->crit_sect); - return -ENODEV; + goto out; } - mutex_unlock(&p_slot->ctrl->crit_sect); - ret = remove_board(p_slot); + retval = remove_board(p_slot); update_slot_info(p_slot); - return ret; + out: + mutex_unlock(&p_slot->ctrl->crit_sect); + return retval; } |