From: RodrÃguez Barbarin, José Javier JoseJavier.Rodriguez@duagon.com
[ Upstream commit 9be24faadd085c284890c3afcec7a0184642315a ]
mcb-pci requests a fixed-size memory region to parse the chameleon table, however, if the chameleon table is smaller that the allocated region, it could overlap with the IP Cores' memory regions.
After parsing the chameleon table, drop/reallocate the memory region with the actual chameleon table size.
Co-developed-by: Jorge Sanjuan Garcia jorge.sanjuangarcia@duagon.com Signed-off-by: Jorge Sanjuan Garcia jorge.sanjuangarcia@duagon.com Signed-off-by: Javier Rodriguez josejavier.rodriguez@duagon.com Signed-off-by: Johannes Thumshirn jth@kernel.org Link: https://lore.kernel.org/r/20230411083329.4506-3-jth@kernel.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/mcb/mcb-pci.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c index dc88232d9af83..53d9202ff9a7c 100644 --- a/drivers/mcb/mcb-pci.c +++ b/drivers/mcb/mcb-pci.c @@ -31,7 +31,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct resource *res; struct priv *priv; - int ret; + int ret, table_size; unsigned long flags;
priv = devm_kzalloc(&pdev->dev, sizeof(struct priv), GFP_KERNEL); @@ -90,7 +90,30 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret < 0) goto out_mcb_bus;
- dev_dbg(&pdev->dev, "Found %d cells\n", ret); + table_size = ret; + + if (table_size < CHAM_HEADER_SIZE) { + /* Release the previous resources */ + devm_iounmap(&pdev->dev, priv->base); + devm_release_mem_region(&pdev->dev, priv->mapbase, CHAM_HEADER_SIZE); + + /* Then, allocate it again with the actual chameleon table size */ + res = devm_request_mem_region(&pdev->dev, priv->mapbase, + table_size, + KBUILD_MODNAME); + if (!res) { + dev_err(&pdev->dev, "Failed to request PCI memory\n"); + ret = -EBUSY; + goto out_mcb_bus; + } + + priv->base = devm_ioremap(&pdev->dev, priv->mapbase, table_size); + if (!priv->base) { + dev_err(&pdev->dev, "Cannot ioremap\n"); + ret = -ENOMEM; + goto out_mcb_bus; + } + }
mcb_bus_add_devices(priv->bus);