From aa0a1ae020e2d24749e9f8085f12ca6d46899c94 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:11 +0300 Subject: bus: fsl-mc: fix arg in call to dprc_scan_objects() Second parameter of dprc_scan_objects() is a bool not a pointer so change from NULL to false. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-1-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 09c8ab5e0959..ffec838450f3 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -220,7 +220,7 @@ static int scan_fsl_mc_bus(struct device *dev, void *data) root_mc_dev = to_fsl_mc_device(dev); root_mc_bus = to_fsl_mc_bus(root_mc_dev); mutex_lock(&root_mc_bus->scan_mutex); - dprc_scan_objects(root_mc_dev, NULL); + dprc_scan_objects(root_mc_dev, false); mutex_unlock(&root_mc_bus->scan_mutex); exit: -- cgit v1.2.3 From f8cfa9bbab338b64229bffb93fdbb755be9d58d5 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:12 +0300 Subject: bus: fsl-mc: handle DMA config deferral in ACPI case ACPI DMA configure API may return a defer status code, so handle it. On top of this, move the MC firmware resume after the DMA setup is completed to avoid crashing due to DMA setup not being done yet or being deferred. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-2-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index ffec838450f3..ffd7a1ff957a 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1089,17 +1089,6 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) } if (mc->fsl_mc_regs) { - /* - * Some bootloaders pause the MC firmware before booting the - * kernel so that MC will not cause faults as soon as the - * SMMU probes due to the fact that there's no configuration - * in place for MC. - * At this point MC should have all its SMMU setup done so make - * sure it is resumed. - */ - writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & (~GCR1_P1_STOP), - mc->fsl_mc_regs + FSL_MC_GCR1); - if (IS_ENABLED(CONFIG_ACPI) && !dev_of_node(&pdev->dev)) { mc_stream_id = readl(mc->fsl_mc_regs + FSL_MC_FAPR); /* @@ -1113,11 +1102,24 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) error = acpi_dma_configure_id(&pdev->dev, DEV_DMA_COHERENT, &mc_stream_id); + if (error == -EPROBE_DEFER) + return error; if (error) dev_warn(&pdev->dev, "failed to configure dma: %d.\n", error); } + + /* + * Some bootloaders pause the MC firmware before booting the + * kernel so that MC will not cause faults as soon as the + * SMMU probes due to the fact that there's no configuration + * in place for MC. + * At this point MC should have all its SMMU setup done so make + * sure it is resumed. + */ + writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & (~GCR1_P1_STOP), + mc->fsl_mc_regs + FSL_MC_GCR1); } /* -- cgit v1.2.3 From c40cbad63ddcbf47debe350e736e37525a0c336c Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:13 +0300 Subject: bus: fsl-mc: fully resume the firmware The MC firmware has two execution units. Resume them both, as on some Layerscape SoCs not doing so breaks the firmware. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-3-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index ffd7a1ff957a..2341de6bce67 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -63,6 +63,7 @@ struct fsl_mc_addr_translation_range { #define FSL_MC_GCR1 0x0 #define GCR1_P1_STOP BIT(31) +#define GCR1_P2_STOP BIT(30) #define FSL_MC_FAPR 0x28 #define MC_FAPR_PL BIT(18) @@ -1118,7 +1119,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) * At this point MC should have all its SMMU setup done so make * sure it is resumed. */ - writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & (~GCR1_P1_STOP), + writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & + (~(GCR1_P1_STOP | GCR1_P2_STOP)), mc->fsl_mc_regs + FSL_MC_GCR1); } -- cgit v1.2.3 From 3ab520cfc772a63e037b5d433c3976c6426bf080 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:14 +0300 Subject: bus: fsl-mc: add .shutdown() op for the bus driver The fsl-mc bus driver is missing the .shutdown() callback, so add it. The implementation simply calls the .remove() callback. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-4-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 2341de6bce67..efff48b3efa5 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1206,6 +1206,11 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) return 0; } +static void fsl_mc_bus_shutdown(struct platform_device *pdev) +{ + fsl_mc_bus_remove(pdev); +} + static const struct of_device_id fsl_mc_bus_match_table[] = { {.compatible = "fsl,qoriq-mc",}, {}, @@ -1228,6 +1233,7 @@ static struct platform_driver fsl_mc_bus_driver = { }, .probe = fsl_mc_bus_probe, .remove = fsl_mc_bus_remove, + .shutdown = fsl_mc_bus_shutdown, }; static int __init fsl_mc_bus_driver_init(void) -- cgit v1.2.3 From 8c97a4fc1b34856812b6775f1f1d46b3bf59bc9d Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:15 +0300 Subject: bus: fsl-mc: pause the MC firmware before IOMMU setup Add a bus notifier to pause the MC firmware as soon as its device gets discovered. This is needed as the firmware is live thus, as soon as the SMMU gets probed and enabled, it will crash the firmware due to SMMU context faults. The firmware will be resumed at probe time, after the required IOMMU setup was completed. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-5-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 44 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index efff48b3efa5..41861ca5c8f1 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -896,6 +896,8 @@ error_cleanup_dev: } EXPORT_SYMBOL_GPL(fsl_mc_device_add); +static struct notifier_block fsl_mc_nb; + /** * fsl_mc_device_remove - Remove an fsl-mc device from being visible to * Linux @@ -1203,6 +1205,8 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io); mc->root_mc_bus_dev->mc_io = NULL; + bus_unregister_notifier(&fsl_mc_bus_type, &fsl_mc_nb); + return 0; } @@ -1236,6 +1240,44 @@ static struct platform_driver fsl_mc_bus_driver = { .shutdown = fsl_mc_bus_shutdown, }; +static int fsl_mc_bus_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct resource *res; + void __iomem *fsl_mc_regs; + + if (action != BUS_NOTIFY_ADD_DEVICE) + return 0; + + if (!of_match_device(fsl_mc_bus_match_table, dev) && + !acpi_match_device(fsl_mc_bus_acpi_match_table, dev)) + return 0; + + res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 1); + if (!res) + return 0; + + fsl_mc_regs = ioremap(res->start, resource_size(res)); + if (!fsl_mc_regs) + return 0; + + /* + * Make sure that the MC firmware is paused before the IOMMU setup for + * it is done or otherwise the firmware will crash right after the SMMU + * gets probed and enabled. + */ + writel(readl(fsl_mc_regs + FSL_MC_GCR1) | (GCR1_P1_STOP | GCR1_P2_STOP), + fsl_mc_regs + FSL_MC_GCR1); + iounmap(fsl_mc_regs); + + return 0; +} + +static struct notifier_block fsl_mc_nb = { + .notifier_call = fsl_mc_bus_notifier, +}; + static int __init fsl_mc_bus_driver_init(void) { int error; @@ -1260,7 +1302,7 @@ static int __init fsl_mc_bus_driver_init(void) if (error < 0) goto error_cleanup_dprc_driver; - return 0; + return bus_register_notifier(&platform_bus_type, &fsl_mc_nb); error_cleanup_dprc_driver: dprc_driver_exit(); -- cgit v1.2.3 From 39243fc1110caf1e76ea647059e061a021680dfd Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:16 +0300 Subject: bus: fsl-mc: pause the MC firmware when unloading Pause the MC firmware when unloading the driver so that it doesn't crash in certain scenarios, such as kexec. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-6-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 41861ca5c8f1..e5b4830cf3c5 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1207,6 +1207,16 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) bus_unregister_notifier(&fsl_mc_bus_type, &fsl_mc_nb); + if (mc->fsl_mc_regs) { + /* + * Pause the MC firmware so that it doesn't crash in certain + * scenarios, such as kexec. + */ + writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) | + (GCR1_P1_STOP | GCR1_P2_STOP), + mc->fsl_mc_regs + FSL_MC_GCR1); + } + return 0; } -- cgit v1.2.3 From 8567494cebe5c208faa336a8316781d32d4e860f Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:17 +0300 Subject: bus: fsl-mc: rescan devices if endpoint not found If the endpoint of a device is not yet probed on the bus, force a rescan of the devices and retry to get a reference to the endpoint device. If the device is still not found then we assume it's in a different isolation context (container/DPRC) thus unavailable and return a permission error. Signed-off-by: Laurentiu Tudor Signed-off-by: Robert-Ionut Alexa Link: https://lore.kernel.org/r/20210715140718.8513-7-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index e5b4830cf3c5..31595017d207 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -950,10 +950,28 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev) * We know that the device has an endpoint because we verified by * interrogating the firmware. This is the case when the device was not * yet discovered by the fsl-mc bus, thus the lookup returned NULL. - * Differentiate this case by returning EPROBE_DEFER. + * Force a rescan of the devices in this container and retry the lookup. + */ + if (!endpoint) { + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); + + if (mutex_trylock(&mc_bus->scan_mutex)) { + err = dprc_scan_objects(mc_bus_dev, true); + mutex_unlock(&mc_bus->scan_mutex); + } + + if (err < 0) + return ERR_PTR(err); + } + + endpoint = fsl_mc_device_lookup(&endpoint_desc, mc_bus_dev); + /* + * This means that the endpoint might reside in a different isolation + * context (DPRC/container). Not much to do, so return a permssion + * error. */ if (!endpoint) - return ERR_PTR(-EPROBE_DEFER); + return ERR_PTR(-EPERM); return endpoint; } -- cgit v1.2.3 From 8990f96a012f42543005b07d9e482694192e9309 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:18 +0300 Subject: bus: fsl-mc: fix mmio base address for child DPRCs Some versions of the MC firmware wrongly report 0 for register base address of the DPMCP associated with child DPRC objects thus rendering them unusable. This is particularly troublesome in ACPI boot scenarios where the legacy way of extracting this base address from the device tree does not apply. Given that DPMCPs share the same base address, workaround this by using the base address extracted from the root DPRC container. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-8-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c') diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 31595017d207..6273f782d0f2 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -69,6 +69,8 @@ struct fsl_mc_addr_translation_range { #define MC_FAPR_PL BIT(18) #define MC_FAPR_BMT BIT(17) +static phys_addr_t mc_portal_base_phys_addr; + /** * fsl_mc_bus_match - device to driver matching callback * @dev: the fsl-mc device to match against @@ -704,14 +706,30 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, * If base address is in the region_desc use it otherwise * revert to old mechanism */ - if (region_desc.base_address) + if (region_desc.base_address) { regions[i].start = region_desc.base_address + region_desc.base_offset; - else + } else { error = translate_mc_addr(mc_dev, mc_region_type, region_desc.base_offset, ®ions[i].start); + /* + * Some versions of the MC firmware wrongly report + * 0 for register base address of the DPMCP associated + * with child DPRC objects thus rendering them unusable. + * This is particularly troublesome in ACPI boot + * scenarios where the legacy way of extracting this + * base address from the device tree does not apply. + * Given that DPMCPs share the same base address, + * workaround this by using the base address extracted + * from the root DPRC container. + */ + if (is_fsl_mc_bus_dprc(mc_dev) && + regions[i].start == region_desc.base_offset) + regions[i].start += mc_portal_base_phys_addr; + } + if (error < 0) { dev_err(parent_dev, "Invalid MC offset: %#x (for %s.%d\'s region %d)\n", @@ -1150,6 +1168,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mc_portal_phys_addr = plat_res->start; mc_portal_size = resource_size(plat_res); + mc_portal_base_phys_addr = mc_portal_phys_addr & ~0x3ffffff; + error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr, mc_portal_size, NULL, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io); -- cgit v1.2.3