From 2b986700c95cd1d49f982aa17fa9da713c2ecfef Mon Sep 17 00:00:00 2001 From: Nico Huber Date: Thu, 28 Apr 2022 18:27:20 +0200 Subject: libpayload/nvme: Fix error paths of nvme_init() We mustn't try to release resources that we haven't acquired yet. Also, sending commands to the NVMe device is futile if we already timed out. Fixes hangs after a failed init noticed in QEMU and on siemens/chili. Change-Id: Ib83c7785d6e0dc3c44fbd50a30694c74932750d6 Signed-off-by: Nico Huber Reviewed-on: https://review.coreboot.org/c/coreboot/+/63933 Tested-by: build bot (Jenkins) Reviewed-by: Thomas Heijligen Reviewed-by: Angel Pons --- payloads/libpayload/drivers/storage/nvme.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'payloads/libpayload') diff --git a/payloads/libpayload/drivers/storage/nvme.c b/payloads/libpayload/drivers/storage/nvme.c index 8d6f409646..14174cfd83 100644 --- a/payloads/libpayload/drivers/storage/nvme.c +++ b/payloads/libpayload/drivers/storage/nvme.c @@ -341,7 +341,7 @@ static void nvme_init(pcidev_t dev) if (!nvme->prp_list) { printf("NVMe ERROR: Failed to allocate buffer for PRP list\n"); - goto abort; + goto _free_abort; } const uint32_t cc = NVME_CC_EN | NVME_CC_CSS | NVME_CC_MPS | NVME_CC_AMS | NVME_CC_SHN @@ -354,26 +354,26 @@ static void nvme_init(pcidev_t dev) status = read32(nvme->config + 0x1c) & 0x3; if (status == 0x2) { printf("NVMe ERROR: Failed to disable controller. FATAL ERROR\n"); - goto abort; + goto _free_abort; } if (timeout < 0) { printf("NVMe ERROR: Failed to disable controller. Timeout.\n"); - goto abort; + goto _free_abort; } timeout -= 10; mdelay(10); } while (status != 0x0); if (create_admin_queues(nvme)) - goto abort; + goto _free_abort; write32(nvme->config + 0x14, cc); timeout = (read64(nvme->config) >> 24 & 0xff) * 500; do { status = read32(nvme->config + 0x1c) & 0x3; if (status == 0x2) - goto abort; + goto _delete_admin_abort; if (timeout < 0) - goto abort; + goto _delete_admin_abort; timeout -= 10; mdelay(10); } while (status != 0x1); @@ -381,20 +381,21 @@ static void nvme_init(pcidev_t dev) uint16_t command = pci_read_config16(dev, PCI_COMMAND); pci_write_config16(dev, PCI_COMMAND, command | PCI_COMMAND_MASTER); if (create_io_completion_queue(nvme)) - goto abort; + goto _delete_admin_abort; if (create_io_submission_queue(nvme)) - goto abort; + goto _delete_completion_abort; storage_attach_device((storage_dev_t *)nvme); printf("NVMe init done.\n"); return; -abort: - printf("NVMe init failed.\n"); - delete_io_submission_queue(nvme); +_delete_completion_abort: delete_io_completion_queue(nvme); +_delete_admin_abort: delete_admin_queues(nvme); +_free_abort: free(nvme->prp_list); free(nvme); + printf("NVMe init failed.\n"); } void nvme_initialize(struct pci_dev *dev) -- cgit v1.2.3