mcb-pci driver is allocating the memory region for the "chameleon table"
with a fixed size of 0x200. This region is only use to do a initial
parsing to discover the devices implemented as IP Cores.
If the "chameleon table" is actually smalled than 0x200 and the first
device offset happen to be within 0x200, a memory overlapping can ocurr.
Here an extract of the memory overlapping when registering a 16z125 IP Core:
[ 31.016972] 8250_men_mcb mcb0-16z125-0:0:0: can't request region for resource [mem 0xa8200100-0xa820010f]
[ 31.016994] 8250_men_mcb: probe of mcb0-16z125-0:0:0 failed with error -16
[ 31.017010] 8250_men_mcb mcb0-16z125-1:0:0: can't request region for resource [mem 0xa8200110-0xa820011f]
And here, the memory allocated for the chameleon table parsing:
user@host:$ sudo /proc/iomem
...
a8200000-a82001ff : mcb_pci
...
This patch solves this problem by dropping/reallocating the memory region of the
"chamelon table" with the actual size once it has been parsed.
This patch is based on linux-next (next-20230323)
Changes for V3:
* handle return value if no chameleon cells found.
* remove stray newline.
* reword typo in PATCH 1 commit message.
Changes for V2:
* make parsing function return the size of "chameleon table".
* reallocate instead of not requesting the memory region.
Javier Rodriguez (3):
mcb: Return actual parsed size when reading chameleon table
mcb-pci: Reallocate memory region to avoid memory overlapping
mcb-lpc: Reallocate memory region to avoid memory overlapping
drivers/mcb/mcb-lpc.c | 35 +++++++++++++++++++++++++++++++----
drivers/mcb/mcb-parse.c | 15 ++++++++++-----
drivers/mcb/mcb-pci.c | 27 +++++++++++++++++++++++++--
3 files changed, 66 insertions(+), 11 deletions(-)
--
2.34.1
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 <[email protected]>
Signed-off-by: Jorge Sanjuan Garcia <[email protected]>
Signed-off-by: Javier Rodriguez <[email protected]>
---
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 dc88232d9af8..53d9202ff9a7 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);
--
2.34.1
mcb-lpc 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 <[email protected]>
Signed-off-by: Jorge Sanjuan Garcia <[email protected]>
Signed-off-by: Javier Rodriguez <[email protected]>
---
drivers/mcb/mcb-lpc.c | 35 +++++++++++++++++++++++++++++++----
1 file changed, 31 insertions(+), 4 deletions(-)
diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c
index 53decd89876e..a851e0236464 100644
--- a/drivers/mcb/mcb-lpc.c
+++ b/drivers/mcb/mcb-lpc.c
@@ -23,7 +23,7 @@ static int mcb_lpc_probe(struct platform_device *pdev)
{
struct resource *res;
struct priv *priv;
- int ret = 0;
+ int ret = 0, table_size;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -58,16 +58,43 @@ static int mcb_lpc_probe(struct platform_device *pdev)
ret = chameleon_parse_cells(priv->bus, priv->mem->start, priv->base);
if (ret < 0) {
- mcb_release_bus(priv->bus);
- return ret;
+ 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->mem->start, resource_size(priv->mem));
+
+ /* Then, allocate it again with the actual chameleon table size */
+ res = devm_request_mem_region(&pdev->dev, priv->mem->start,
+ 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->mem->start, table_size);
+ if (!priv->base) {
+ dev_err(&pdev->dev, "Cannot ioremap\n");
+ ret = -ENOMEM;
+ goto out_mcb_bus;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ }
mcb_bus_add_devices(priv->bus);
return 0;
+out_mcb_bus:
+ mcb_release_bus(priv->bus);
+ return ret;
}
static int mcb_lpc_remove(struct platform_device *pdev)
--
2.34.1
Pushed to mcb-for-next.
Thanks,
Johannes