mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-12 00:00:00 +00:00
qlge: Fix deadlock when cancelling worker.
Removing usage of rtnl_lock() to protect firmware interface registers. These registers are accessed in some worker threads and can create a deadlock if rtnl_lock is taken by upper layers while the worker is still pending. We remove rtnl_lock and use a driver mutex just while mailboxes are accessed. Signed-off-by: Ron Mercer <ron.mercer@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
36eac2130c
commit
4d7b6b5d24
@ -2083,6 +2083,7 @@ struct ql_adapter {
|
|||||||
u32 mailbox_in;
|
u32 mailbox_in;
|
||||||
u32 mailbox_out;
|
u32 mailbox_out;
|
||||||
struct mbox_params idc_mbc;
|
struct mbox_params idc_mbc;
|
||||||
|
struct mutex mpi_mutex;
|
||||||
|
|
||||||
int tx_ring_size;
|
int tx_ring_size;
|
||||||
int rx_ring_size;
|
int rx_ring_size;
|
||||||
|
@ -4629,6 +4629,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
|
|||||||
INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
|
INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
|
||||||
INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
|
INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
|
||||||
init_completion(&qdev->ide_completion);
|
init_completion(&qdev->ide_completion);
|
||||||
|
mutex_init(&qdev->mpi_mutex);
|
||||||
|
|
||||||
if (!cards_found) {
|
if (!cards_found) {
|
||||||
dev_info(&pdev->dev, "%s\n", DRV_STRING);
|
dev_info(&pdev->dev, "%s\n", DRV_STRING);
|
||||||
|
@ -534,6 +534,7 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
|
|||||||
int status;
|
int status;
|
||||||
unsigned long count;
|
unsigned long count;
|
||||||
|
|
||||||
|
mutex_lock(&qdev->mpi_mutex);
|
||||||
|
|
||||||
/* Begin polled mode for MPI */
|
/* Begin polled mode for MPI */
|
||||||
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
|
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
|
||||||
@ -603,6 +604,7 @@ done:
|
|||||||
end:
|
end:
|
||||||
/* End polled mode for MPI */
|
/* End polled mode for MPI */
|
||||||
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
|
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
|
||||||
|
mutex_unlock(&qdev->mpi_mutex);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1099,9 +1101,7 @@ int ql_wait_fifo_empty(struct ql_adapter *qdev)
|
|||||||
static int ql_set_port_cfg(struct ql_adapter *qdev)
|
static int ql_set_port_cfg(struct ql_adapter *qdev)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
rtnl_lock();
|
|
||||||
status = ql_mb_set_port_cfg(qdev);
|
status = ql_mb_set_port_cfg(qdev);
|
||||||
rtnl_unlock();
|
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
status = ql_idc_wait(qdev);
|
status = ql_idc_wait(qdev);
|
||||||
@ -1122,9 +1122,7 @@ void ql_mpi_port_cfg_work(struct work_struct *work)
|
|||||||
container_of(work, struct ql_adapter, mpi_port_cfg_work.work);
|
container_of(work, struct ql_adapter, mpi_port_cfg_work.work);
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
rtnl_lock();
|
|
||||||
status = ql_mb_get_port_cfg(qdev);
|
status = ql_mb_get_port_cfg(qdev);
|
||||||
rtnl_unlock();
|
|
||||||
if (status) {
|
if (status) {
|
||||||
netif_err(qdev, drv, qdev->ndev,
|
netif_err(qdev, drv, qdev->ndev,
|
||||||
"Bug: Failed to get port config data.\n");
|
"Bug: Failed to get port config data.\n");
|
||||||
@ -1167,7 +1165,6 @@ void ql_mpi_idc_work(struct work_struct *work)
|
|||||||
u32 aen;
|
u32 aen;
|
||||||
int timeout;
|
int timeout;
|
||||||
|
|
||||||
rtnl_lock();
|
|
||||||
aen = mbcp->mbox_out[1] >> 16;
|
aen = mbcp->mbox_out[1] >> 16;
|
||||||
timeout = (mbcp->mbox_out[1] >> 8) & 0xf;
|
timeout = (mbcp->mbox_out[1] >> 8) & 0xf;
|
||||||
|
|
||||||
@ -1231,7 +1228,6 @@ void ql_mpi_idc_work(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
rtnl_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ql_mpi_work(struct work_struct *work)
|
void ql_mpi_work(struct work_struct *work)
|
||||||
@ -1242,7 +1238,7 @@ void ql_mpi_work(struct work_struct *work)
|
|||||||
struct mbox_params *mbcp = &mbc;
|
struct mbox_params *mbcp = &mbc;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
rtnl_lock();
|
mutex_lock(&qdev->mpi_mutex);
|
||||||
/* Begin polled mode for MPI */
|
/* Begin polled mode for MPI */
|
||||||
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
|
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
|
||||||
|
|
||||||
@ -1259,7 +1255,7 @@ void ql_mpi_work(struct work_struct *work)
|
|||||||
|
|
||||||
/* End polled mode for MPI */
|
/* End polled mode for MPI */
|
||||||
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
|
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
|
||||||
rtnl_unlock();
|
mutex_unlock(&qdev->mpi_mutex);
|
||||||
ql_enable_completion_interrupt(qdev, 0);
|
ql_enable_completion_interrupt(qdev, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user