habanalabs: prevent host crash during suspend/resume

This patch fixes the implementation of suspend/resume of the device so that
upon resume of the device, the host won't crash due to PCI completion
timeout.

Upon suspend, the device is being reset due to PERST. Therefore, upon
resume, the driver must initialize the PCI controller as if the driver was
loaded. If the controller is not initialized and the device tries to
access the device through the PCI bars, the host will crash with PCI
completion timeout error.

Signed-off-by: Oded Gabbay <oded.gabbay@gmail.com>
This commit is contained in:
Oded Gabbay 2019-03-03 22:29:20 +02:00
parent cbaa99ed1b
commit 7cb5101ee0
2 changed files with 43 additions and 66 deletions

View File

@ -416,6 +416,27 @@ int hl_device_suspend(struct hl_device *hdev)
pci_save_state(hdev->pdev);
/* Block future CS/VM/JOB completion operations */
rc = atomic_cmpxchg(&hdev->in_reset, 0, 1);
if (rc) {
dev_err(hdev->dev, "Can't suspend while in reset\n");
return -EIO;
}
/* This blocks all other stuff that is not blocked by in_reset */
hdev->disabled = true;
/*
* Flush anyone that is inside the critical section of enqueue
* jobs to the H/W
*/
hdev->asic_funcs->hw_queues_lock(hdev);
hdev->asic_funcs->hw_queues_unlock(hdev);
/* Flush processes that are sending message to CPU */
mutex_lock(&hdev->send_cpu_message_lock);
mutex_unlock(&hdev->send_cpu_message_lock);
rc = hdev->asic_funcs->suspend(hdev);
if (rc)
dev_err(hdev->dev,
@ -443,21 +464,38 @@ int hl_device_resume(struct hl_device *hdev)
pci_set_power_state(hdev->pdev, PCI_D0);
pci_restore_state(hdev->pdev);
rc = pci_enable_device(hdev->pdev);
rc = pci_enable_device_mem(hdev->pdev);
if (rc) {
dev_err(hdev->dev,
"Failed to enable PCI device in resume\n");
return rc;
}
pci_set_master(hdev->pdev);
rc = hdev->asic_funcs->resume(hdev);
if (rc) {
dev_err(hdev->dev,
"Failed to enable PCI access from device CPU\n");
return rc;
dev_err(hdev->dev, "Failed to resume device after suspend\n");
goto disable_device;
}
hdev->disabled = false;
atomic_set(&hdev->in_reset, 0);
rc = hl_device_reset(hdev, true, false);
if (rc) {
dev_err(hdev->dev, "Failed to reset device during resume\n");
goto disable_device;
}
return 0;
disable_device:
pci_clear_master(hdev->pdev);
pci_disable_device(hdev->pdev);
return rc;
}
static void hl_device_hard_reset_pending(struct work_struct *work)

View File

@ -1201,15 +1201,6 @@ static int goya_stop_external_queues(struct hl_device *hdev)
return retval;
}
static void goya_resume_external_queues(struct hl_device *hdev)
{
WREG32(mmDMA_QM_0_GLBL_CFG1, 0);
WREG32(mmDMA_QM_1_GLBL_CFG1, 0);
WREG32(mmDMA_QM_2_GLBL_CFG1, 0);
WREG32(mmDMA_QM_3_GLBL_CFG1, 0);
WREG32(mmDMA_QM_4_GLBL_CFG1, 0);
}
/*
* goya_init_cpu_queues - Initialize PQ/CQ/EQ of CPU
*
@ -2178,36 +2169,6 @@ static int goya_stop_internal_queues(struct hl_device *hdev)
return retval;
}
static void goya_resume_internal_queues(struct hl_device *hdev)
{
WREG32(mmMME_QM_GLBL_CFG1, 0);
WREG32(mmMME_CMDQ_GLBL_CFG1, 0);
WREG32(mmTPC0_QM_GLBL_CFG1, 0);
WREG32(mmTPC0_CMDQ_GLBL_CFG1, 0);
WREG32(mmTPC1_QM_GLBL_CFG1, 0);
WREG32(mmTPC1_CMDQ_GLBL_CFG1, 0);
WREG32(mmTPC2_QM_GLBL_CFG1, 0);
WREG32(mmTPC2_CMDQ_GLBL_CFG1, 0);
WREG32(mmTPC3_QM_GLBL_CFG1, 0);
WREG32(mmTPC3_CMDQ_GLBL_CFG1, 0);
WREG32(mmTPC4_QM_GLBL_CFG1, 0);
WREG32(mmTPC4_CMDQ_GLBL_CFG1, 0);
WREG32(mmTPC5_QM_GLBL_CFG1, 0);
WREG32(mmTPC5_CMDQ_GLBL_CFG1, 0);
WREG32(mmTPC6_QM_GLBL_CFG1, 0);
WREG32(mmTPC6_CMDQ_GLBL_CFG1, 0);
WREG32(mmTPC7_QM_GLBL_CFG1, 0);
WREG32(mmTPC7_CMDQ_GLBL_CFG1, 0);
}
static void goya_dma_stall(struct hl_device *hdev)
{
WREG32(mmDMA_QM_0_GLBL_CFG1, 1 << DMA_QM_0_GLBL_CFG1_DMA_STOP_SHIFT);
@ -2905,20 +2866,6 @@ int goya_suspend(struct hl_device *hdev)
{
int rc;
rc = goya_stop_internal_queues(hdev);
if (rc) {
dev_err(hdev->dev, "failed to stop internal queues\n");
return rc;
}
rc = goya_stop_external_queues(hdev);
if (rc) {
dev_err(hdev->dev, "failed to stop external queues\n");
return rc;
}
rc = goya_send_pci_access_msg(hdev, ARMCP_PACKET_DISABLE_PCI_ACCESS);
if (rc)
dev_err(hdev->dev, "Failed to disable PCI access from CPU\n");
@ -2928,15 +2875,7 @@ int goya_suspend(struct hl_device *hdev)
int goya_resume(struct hl_device *hdev)
{
int rc;
goya_resume_external_queues(hdev);
goya_resume_internal_queues(hdev);
rc = goya_send_pci_access_msg(hdev, ARMCP_PACKET_ENABLE_PCI_ACCESS);
if (rc)
dev_err(hdev->dev, "Failed to enable PCI access from CPU\n");
return rc;
return goya_init_iatu(hdev);
}
static int goya_cb_mmap(struct hl_device *hdev, struct vm_area_struct *vma,