mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-02-24 01:20:54 +07:00
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>
This commit is contained in:
parent
49ed2b4963
commit
dd5619cb44
@ -92,6 +92,7 @@ struct php_ctlr_state_s {
|
|||||||
struct controller {
|
struct controller {
|
||||||
struct controller *next;
|
struct controller *next;
|
||||||
struct mutex crit_sect; /* critical section mutex */
|
struct mutex crit_sect; /* critical section mutex */
|
||||||
|
struct mutex ctrl_lock; /* controller lock */
|
||||||
struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
|
struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
|
||||||
int num_slots; /* Number of slots on ctlr */
|
int num_slots; /* Number of slots on ctlr */
|
||||||
int slot_num_inc; /* 1 or -1 */
|
int slot_num_inc; /* 1 or -1 */
|
||||||
|
@ -448,7 +448,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
|
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
|
||||||
|
|
||||||
@ -456,7 +456,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
|
|||||||
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
|
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
|
||||||
if (rc) {
|
if (rc) {
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
goto err_out_free_ctrl_slot;
|
goto err_out_free_ctrl_slot;
|
||||||
} else
|
} else
|
||||||
/* Wait for the command to complete */
|
/* Wait for the command to complete */
|
||||||
@ -464,7 +464,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -234,13 +234,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
|
|||||||
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
|
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
|
||||||
{
|
{
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
|
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
|
||||||
if (POWER_CTRL(ctrl->ctrlcap)) {
|
if (POWER_CTRL(ctrl->ctrlcap)) {
|
||||||
if (pslot->hpc_ops->power_off_slot(pslot)) {
|
if (pslot->hpc_ops->power_off_slot(pslot)) {
|
||||||
err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
|
err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wait_for_ctrl_irq (ctrl);
|
wait_for_ctrl_irq (ctrl);
|
||||||
@ -254,14 +254,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
|
|||||||
if (ATTN_LED(ctrl->ctrlcap)) {
|
if (ATTN_LED(ctrl->ctrlcap)) {
|
||||||
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
|
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
|
||||||
err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
|
err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wait_for_ctrl_irq (ctrl);
|
wait_for_ctrl_irq (ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -284,13 +284,13 @@ static int board_added(struct slot *p_slot)
|
|||||||
ctrl->slot_device_offset, hp_slot);
|
ctrl->slot_device_offset, hp_slot);
|
||||||
|
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
if (POWER_CTRL(ctrl->ctrlcap)) {
|
if (POWER_CTRL(ctrl->ctrlcap)) {
|
||||||
/* Power on slot */
|
/* Power on slot */
|
||||||
rc = p_slot->hpc_ops->power_on_slot(p_slot);
|
rc = p_slot->hpc_ops->power_on_slot(p_slot);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,7 +306,7 @@ static int board_added(struct slot *p_slot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
/* Wait for ~1 second */
|
/* Wait for ~1 second */
|
||||||
wait_for_ctrl_irq (ctrl);
|
wait_for_ctrl_irq (ctrl);
|
||||||
@ -340,7 +340,7 @@ static int board_added(struct slot *p_slot)
|
|||||||
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
|
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
|
||||||
if (PWR_LED(ctrl->ctrlcap)) {
|
if (PWR_LED(ctrl->ctrlcap)) {
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
p_slot->hpc_ops->green_led_on(p_slot);
|
p_slot->hpc_ops->green_led_on(p_slot);
|
||||||
|
|
||||||
@ -348,7 +348,7 @@ static int board_added(struct slot *p_slot)
|
|||||||
wait_for_ctrl_irq (ctrl);
|
wait_for_ctrl_irq (ctrl);
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -380,14 +380,14 @@ static int remove_board(struct slot *p_slot)
|
|||||||
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
|
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
|
||||||
|
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
if (POWER_CTRL(ctrl->ctrlcap)) {
|
if (POWER_CTRL(ctrl->ctrlcap)) {
|
||||||
/* power off slot */
|
/* power off slot */
|
||||||
rc = p_slot->hpc_ops->power_off_slot(p_slot);
|
rc = p_slot->hpc_ops->power_off_slot(p_slot);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
|
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
/* Wait for the command to complete */
|
/* Wait for the command to complete */
|
||||||
@ -403,7 +403,7 @@ static int remove_board(struct slot *p_slot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -450,7 +450,7 @@ static void pciehp_pushbutton_thread(unsigned long slot)
|
|||||||
|
|
||||||
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
|
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&p_slot->ctrl->crit_sect);
|
mutex_lock(&p_slot->ctrl->ctrl_lock);
|
||||||
|
|
||||||
p_slot->hpc_ops->green_led_off(p_slot);
|
p_slot->hpc_ops->green_led_off(p_slot);
|
||||||
|
|
||||||
@ -458,7 +458,7 @@ static void pciehp_pushbutton_thread(unsigned long slot)
|
|||||||
wait_for_ctrl_irq (p_slot->ctrl);
|
wait_for_ctrl_irq (p_slot->ctrl);
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&p_slot->ctrl->crit_sect);
|
mutex_unlock(&p_slot->ctrl->ctrl_lock);
|
||||||
}
|
}
|
||||||
p_slot->state = STATIC_STATE;
|
p_slot->state = STATIC_STATE;
|
||||||
}
|
}
|
||||||
@ -500,7 +500,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
|
|||||||
|
|
||||||
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
|
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&p_slot->ctrl->crit_sect);
|
mutex_lock(&p_slot->ctrl->ctrl_lock);
|
||||||
|
|
||||||
p_slot->hpc_ops->green_led_off(p_slot);
|
p_slot->hpc_ops->green_led_off(p_slot);
|
||||||
|
|
||||||
@ -508,7 +508,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
|
|||||||
wait_for_ctrl_irq (p_slot->ctrl);
|
wait_for_ctrl_irq (p_slot->ctrl);
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&p_slot->ctrl->crit_sect);
|
mutex_unlock(&p_slot->ctrl->ctrl_lock);
|
||||||
}
|
}
|
||||||
p_slot->state = STATIC_STATE;
|
p_slot->state = STATIC_STATE;
|
||||||
}
|
}
|
||||||
@ -621,7 +621,7 @@ static void interrupt_event_handler(struct controller *ctrl)
|
|||||||
switch (p_slot->state) {
|
switch (p_slot->state) {
|
||||||
case BLINKINGOFF_STATE:
|
case BLINKINGOFF_STATE:
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
if (PWR_LED(ctrl->ctrlcap)) {
|
if (PWR_LED(ctrl->ctrlcap)) {
|
||||||
p_slot->hpc_ops->green_led_on(p_slot);
|
p_slot->hpc_ops->green_led_on(p_slot);
|
||||||
@ -635,11 +635,11 @@ static void interrupt_event_handler(struct controller *ctrl)
|
|||||||
wait_for_ctrl_irq (ctrl);
|
wait_for_ctrl_irq (ctrl);
|
||||||
}
|
}
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
break;
|
break;
|
||||||
case BLINKINGON_STATE:
|
case BLINKINGON_STATE:
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
if (PWR_LED(ctrl->ctrlcap)) {
|
if (PWR_LED(ctrl->ctrlcap)) {
|
||||||
p_slot->hpc_ops->green_led_off(p_slot);
|
p_slot->hpc_ops->green_led_off(p_slot);
|
||||||
@ -652,7 +652,7 @@ static void interrupt_event_handler(struct controller *ctrl)
|
|||||||
wait_for_ctrl_irq (ctrl);
|
wait_for_ctrl_irq (ctrl);
|
||||||
}
|
}
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -681,7 +681,7 @@ static void interrupt_event_handler(struct controller *ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
/* blink green LED and turn off amber */
|
/* blink green LED and turn off amber */
|
||||||
if (PWR_LED(ctrl->ctrlcap)) {
|
if (PWR_LED(ctrl->ctrlcap)) {
|
||||||
@ -698,7 +698,7 @@ static void interrupt_event_handler(struct controller *ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
init_timer(&p_slot->task_event);
|
init_timer(&p_slot->task_event);
|
||||||
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
|
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
|
||||||
@ -713,7 +713,7 @@ static void interrupt_event_handler(struct controller *ctrl)
|
|||||||
if (POWER_CTRL(ctrl->ctrlcap)) {
|
if (POWER_CTRL(ctrl->ctrlcap)) {
|
||||||
dbg("power fault\n");
|
dbg("power fault\n");
|
||||||
/* Wait for exclusive access to hardware */
|
/* Wait for exclusive access to hardware */
|
||||||
mutex_lock(&ctrl->crit_sect);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
if (ATTN_LED(ctrl->ctrlcap)) {
|
if (ATTN_LED(ctrl->ctrlcap)) {
|
||||||
p_slot->hpc_ops->set_attention_status(p_slot, 1);
|
p_slot->hpc_ops->set_attention_status(p_slot, 1);
|
||||||
@ -726,7 +726,7 @@ static void interrupt_event_handler(struct controller *ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Done with exclusive hardware access */
|
/* Done with exclusive hardware access */
|
||||||
mutex_unlock(&ctrl->crit_sect);
|
mutex_unlock(&ctrl->ctrl_lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/***********SURPRISE REMOVAL********************/
|
/***********SURPRISE REMOVAL********************/
|
||||||
@ -789,7 +789,6 @@ int pciehp_enable_slot(struct slot *p_slot)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&p_slot->ctrl->crit_sect);
|
|
||||||
|
|
||||||
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
|
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
|
||||||
|
|
||||||
@ -801,6 +800,7 @@ int pciehp_enable_slot(struct slot *p_slot)
|
|||||||
if (p_slot)
|
if (p_slot)
|
||||||
update_slot_info(p_slot);
|
update_slot_info(p_slot);
|
||||||
|
|
||||||
|
mutex_unlock(&p_slot->ctrl->crit_sect);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,10 +846,10 @@ int pciehp_disable_slot(struct slot *p_slot)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&p_slot->ctrl->crit_sect);
|
|
||||||
|
|
||||||
ret = remove_board(p_slot);
|
ret = remove_board(p_slot);
|
||||||
update_slot_info(p_slot);
|
update_slot_info(p_slot);
|
||||||
|
|
||||||
|
mutex_unlock(&p_slot->ctrl->crit_sect);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1402,6 +1402,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
|
|||||||
pdev->subsystem_vendor, pdev->subsystem_device);
|
pdev->subsystem_vendor, pdev->subsystem_device);
|
||||||
|
|
||||||
mutex_init(&ctrl->crit_sect);
|
mutex_init(&ctrl->crit_sect);
|
||||||
|
mutex_init(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
/* setup wait queue */
|
/* setup wait queue */
|
||||||
init_waitqueue_head(&ctrl->queue);
|
init_waitqueue_head(&ctrl->queue);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user