Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

remoteproc: imx_dsp_rproc: Fix multiple start/stop operations

After commit 67a7bc7f0358 ("remoteproc: Use of reserved_mem_region_*
functions for "memory-region"") following commands with
imx-dsp-rproc started to fail:

$ echo zephyr.elf > /sys/class/remoteproc/remoteproc0/firmware
$ echo start > /sys/class/remoteproc/remoteproc0/state
$ echo stop > /sys/class/remoteproc/remoteproc0/state
$ echo start > /sys/class/remoteproc/remoteproc0/state #! This fails
-sh: echo: write error: Device or resource busy

This happens because aforementioned commit replaced devm_ioremap_wc with
devm_ioremap_resource_wc which will "reserve" the memory region with the
first start and then will fail at the second start if the memory
region is already reserved.

Even partially reverting the faulty commit won't fix the
underlying issue because we map the address in prepare() but we never
unmap it at unprepare(), so we will keep leaking memory regions.

So, lets use alloc() and release() callbacks for memory carveout
handling. This will nicely map() the memory region at prepare() time
and unmap() it at unprepare().

Fixes: 67a7bc7f0358 ("remoteproc: Use of_reserved_mem_region_* functions for "memory-region"")
Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Link: https://lore.kernel.org/r/20251210154906.99210-1-daniel.baluta@nxp.com
Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>

authored by

Daniel Baluta and committed by
Mathieu Poirier
a84a1e21 93f51b91

+33 -17
+33 -17
drivers/remoteproc/imx_dsp_rproc.c
··· 644 644 mbox_free_channel(priv->rxdb_ch); 645 645 } 646 646 647 + static int imx_dsp_rproc_mem_alloc(struct rproc *rproc, 648 + struct rproc_mem_entry *mem) 649 + { 650 + struct device *dev = rproc->dev.parent; 651 + void *va; 652 + 653 + va = ioremap_wc(mem->dma, mem->len); 654 + if (!va) { 655 + dev_err(dev, "Unable to map memory region: %pa+%zx\n", 656 + &mem->dma, mem->len); 657 + return -ENOMEM; 658 + } 659 + 660 + mem->va = va; 661 + 662 + return 0; 663 + } 664 + 665 + static int imx_dsp_rproc_mem_release(struct rproc *rproc, 666 + struct rproc_mem_entry *mem) 667 + { 668 + iounmap(mem->va); 669 + 670 + return 0; 671 + } 672 + 647 673 /** 648 674 * imx_dsp_rproc_add_carveout() - request mailbox channels 649 675 * @priv: private data pointer ··· 685 659 struct device *dev = rproc->dev.parent; 686 660 struct device_node *np = dev->of_node; 687 661 struct rproc_mem_entry *mem; 688 - void __iomem *cpu_addr; 689 662 int a, i = 0; 690 663 u64 da; 691 664 ··· 698 673 if (imx_dsp_rproc_sys_to_da(priv, att->sa, att->size, &da)) 699 674 return -EINVAL; 700 675 701 - cpu_addr = devm_ioremap_wc(dev, att->sa, att->size); 702 - if (!cpu_addr) { 703 - dev_err(dev, "failed to map memory %p\n", &att->sa); 704 - return -ENOMEM; 705 - } 706 - 707 676 /* Register memory region */ 708 - mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)att->sa, 709 - att->size, da, NULL, NULL, "dsp_mem"); 677 + mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)att->sa, 678 + att->size, da, imx_dsp_rproc_mem_alloc, 679 + imx_dsp_rproc_mem_release, "dsp_mem"); 710 680 711 681 if (mem) 712 682 rproc_coredump_add_segment(rproc, da, att->size); ··· 729 709 if (imx_dsp_rproc_sys_to_da(priv, res.start, resource_size(&res), &da)) 730 710 return -EINVAL; 731 711 732 - cpu_addr = devm_ioremap_resource_wc(dev, &res); 733 - if (IS_ERR(cpu_addr)) { 734 - dev_err(dev, "failed to map memory %pR\n", &res); 735 - return PTR_ERR(cpu_addr); 736 - } 737 - 738 712 /* Register memory region */ 739 - mem = rproc_mem_entry_init(dev, (void __force *)cpu_addr, (dma_addr_t)res.start, 740 - resource_size(&res), da, NULL, NULL, 713 + mem = rproc_mem_entry_init(dev, NULL, (dma_addr_t)res.start, 714 + resource_size(&res), da, 715 + imx_dsp_rproc_mem_alloc, 716 + imx_dsp_rproc_mem_release, 741 717 "%.*s", strchrnul(res.name, '@') - res.name, res.name); 742 718 if (!mem) 743 719 return -ENOMEM;