From d9f554b62440de542c482fecf9374e8da3ea3602 Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Sun, 3 Jul 2022 12:48:06 +0200 Subject: pci: Add checks to prevent config space overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PCIe config space has address range 0-4095. So do not allow reading from addresses outside of this range. Lot of U-Boot drivers do not expect that passed value is not in this range. PCI DM read function is extended to fill read value to all ones or zeros when it fails as U-Boot callers ignores return value. Calling U-Boot command 'pci display.b 0.0.0 0 0x2000' now stops printing config space at the end (before 0x1000 address). Signed-off-by: Pali Rohár Reviewed-by: Stefan Roese --- drivers/pci/pci-uclass.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 2c85e78a136..16a6a699f92 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -286,6 +286,8 @@ int pci_bus_write_config(struct udevice *bus, pci_dev_t bdf, int offset, ops = pci_get_ops(bus); if (!ops->write_config) return -ENOSYS; + if (offset < 0 || offset >= 4096) + return -EINVAL; return ops->write_config(bus, bdf, offset, value, size); } @@ -364,8 +366,14 @@ int pci_bus_read_config(const struct udevice *bus, pci_dev_t bdf, int offset, struct dm_pci_ops *ops; ops = pci_get_ops(bus); - if (!ops->read_config) + if (!ops->read_config) { + *valuep = pci_conv_32_to_size(~0, offset, size); return -ENOSYS; + } + if (offset < 0 || offset >= 4096) { + *valuep = pci_conv_32_to_size(0, offset, size); + return -EINVAL; + } return ops->read_config(bus, bdf, offset, valuep, size); } -- cgit v1.3.1 From e9ac3a939d4f11e9cdcdcb2bad090f4cb1929a85 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 31 Jul 2022 15:31:31 +0900 Subject: nvme: Do a clean NVMe shutdown The brute-force controller disable method can end up racing controller initialization and causing a crash when we shut down Apple ANS2 NVMe controllers. Do a proper controlled shutdown, which does block until things are quiesced properly. This is nicer in general for all controllers. Signed-off-by: Hector Martin Tested-by: Mark Kettenis (firefly-rk3399) --- drivers/nvme/nvme.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index a305305885e..5fd2fb9ed6a 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -27,9 +27,8 @@ #define IO_TIMEOUT 30 #define MAX_PRP_POOL 512 -static int nvme_wait_ready(struct nvme_dev *dev, bool enabled) +static int nvme_wait_csts(struct nvme_dev *dev, u32 mask, u32 val) { - u32 bit = enabled ? NVME_CSTS_RDY : 0; int timeout; ulong start; @@ -38,7 +37,7 @@ static int nvme_wait_ready(struct nvme_dev *dev, bool enabled) start = get_timer(0); while (get_timer(start) < timeout) { - if ((readl(&dev->bar->csts) & NVME_CSTS_RDY) == bit) + if ((readl(&dev->bar->csts) & mask) == val) return 0; } @@ -295,7 +294,7 @@ static int nvme_enable_ctrl(struct nvme_dev *dev) dev->ctrl_config |= NVME_CC_ENABLE; writel(dev->ctrl_config, &dev->bar->cc); - return nvme_wait_ready(dev, true); + return nvme_wait_csts(dev, NVME_CSTS_RDY, NVME_CSTS_RDY); } static int nvme_disable_ctrl(struct nvme_dev *dev) @@ -304,7 +303,16 @@ static int nvme_disable_ctrl(struct nvme_dev *dev) dev->ctrl_config &= ~NVME_CC_ENABLE; writel(dev->ctrl_config, &dev->bar->cc); - return nvme_wait_ready(dev, false); + return nvme_wait_csts(dev, NVME_CSTS_RDY, 0); +} + +static int nvme_shutdown_ctrl(struct nvme_dev *dev) +{ + dev->ctrl_config &= ~NVME_CC_SHN_MASK; + dev->ctrl_config |= NVME_CC_SHN_NORMAL; + writel(dev->ctrl_config, &dev->bar->cc); + + return nvme_wait_csts(dev, NVME_CSTS_SHST_MASK, NVME_CSTS_SHST_CMPLT); } static void nvme_free_queue(struct nvme_queue *nvmeq) @@ -904,6 +912,13 @@ free_nvme: int nvme_shutdown(struct udevice *udev) { struct nvme_dev *ndev = dev_get_priv(udev); + int ret; + + ret = nvme_shutdown_ctrl(ndev); + if (ret < 0) { + printf("Error: %s: Shutdown timed out!\n", udev->name); + return ret; + } return nvme_disable_ctrl(ndev); } -- cgit v1.3.1