remoteproc/k3-r5: fix unaligned data faults with TCMs during loading
authorSuman Anna <s-anna@ti.com>
Fri, 27 Sep 2019 21:28:56 +0000 (16:28 -0500)
committerSuman Anna <s-anna@ti.com>
Wed, 2 Oct 2019 02:38:15 +0000 (21:38 -0500)
The R5F processors on TI K3 SoCs all have Tightly Coupled Memory (TCM)
and has both the ATCM and two banks of BTCM. The K3 R5F remoteproc driver
leverages the TCMs to perform boot-strapping and support further execution
of code from DDR. These TCMs are currently mapped into the kernel as device
type memory due to the usage of devm_ioremap_resource(). The remoteproc
core ELF loader uses the regular memcpy function for loading program
segments.

The Arm64 architecture causes an alignment fault on any unaligned access
to any type of device memory. The R5F firmwares can have a TCM program
segment unaligned (due to the presence of the unaligned Elf32 header)
and cause issues with the Arm64 memcpy() function. The TCMs are furthermore
designed in general to support RAM-like backing memories.

So, update the TCM mapping logic to instead use the devm_ioremap_wc()
function to map these memory regions as Normal Non-Cached memories, and
thereby fix any potential unaligned data accesses during remoteproc
loading. This also helps with zeroing out the TCMs using memset().

An example crash log looks like below:
  Unable to handle kernel paging request at virtual address ffff0000128c0004
  Mem abort info:
    ESR = 0x96000061
    Exception class = DABT (current EL), IL = 32 bits
    SET = 0, FnV = 0
    EA = 0, S1PTW = 0
  Data abort info:
    ISV = 0, ISS = 0x00000061
    CM = 0, WnR = 1
  swapper pgtable: 64k pages, 48-bit VAs, pgdp = 000000002c996fc5
  [ffff0000128c0004] pgd=00000008fffe0003, pud=00000008fffe0003, pmd=00000008fffd0003, pte=00e8000005c00707
  Internal error: Oops: 96000061 [#1] PREEMPT SMP
  Modules linked in: ti_k3_r5_remoteproc virtio_rpmsg_bus remoteproc
  Process kworker/1:2 (pid: 129, stack limit = 0x00000000d72d3758)
  CPU: 1 PID: 129 Comm: kworker/1:2 Not tainted 4.19.73-00042-g9c815c9f00bd #347
  Hardware name: Texas Instruments K3 J721E SoC (DT)
  Workqueue: events request_firmware_work_func
  pstate: 00000005 (nzcv daif -PAN -UAO)
  pc : __memcpy+0x48/0x180
  lr : rproc_elf_load_segments+0x174/0x1c8 [remoteproc]
  sp : ffff00000bbcfc80
  x29: ffff00000bbcfc80 x28: ffff800843a23838
  x27: 0000000000000034 x26: 0000000000000040
  x25: ffff800843a23800 x24: ffff80084a8d2c00
  x23: ffff000012b10000 x22: 0000000000000000
  x21: 0000000000000040 x20: 0000000000000000
  x19: ffff000012ca50c0 x18: 0000000000000000
  x17: 0000000000000000 x16: 0000000000000000
  x15: 0000000000000400 x14: 0000000000000400
  x13: 0000000000000044 x12: 0000000000000000
  x11: 0000000000000001 x10: 0000000000000980
  x9 : ffff00000bbcf860 x8 : ffff8008435609e0
  x7 : ffff800843560240 x6 : ffff0000128c0004
  x5 : ffff80087fae17e8 x4 : 000000000000000c
  x3 : e59ff018e59ff018 x2 : 0000000000000034
  x1 : ffff000012b10040 x0 : ffff0000128c0000
  Call trace:
   __memcpy+0x48/0x180
   rproc_boot+0x404/0x668 [remoteproc]
   rproc_auto_boot_callback+0x18/0x30 [remoteproc]
   request_firmware_work_func+0x48/0x88
   process_one_work+0x1e0/0x318
   worker_thread+0x40/0x428
   kthread+0x124/0x128
   ret_from_fork+0x10/0x18
  Code: b8404423 b80044c3 36180064 f8408423 (f80084c3)
  ---[ end trace cbd6238f81b6eda1 ]---

Fixes: 80d807f572e9 ("remoteproc/k3-r5: add a remoteproc driver for R5F subsystem")
Signed-off-by: Suman Anna <s-anna@ti.com>
drivers/remoteproc/ti_k3_r5_remoteproc.c

index 90bccae7015ba5a0f121e032007241ee9c183b42..429bcb7a2609e8e939f36b2a821102ace4857f11 100644 (file)
@@ -958,11 +958,28 @@ static int k3_r5_core_of_get_internal_memories(struct platform_device *pdev,
        for (i = 0; i < num_mems; i++) {
                res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                                   mem_names[i]);
-               core->mem[i].cpu_addr = devm_ioremap_resource(dev, res);
-               if (IS_ERR(core->mem[i].cpu_addr)) {
-                       dev_err(dev, "failed to parse and map %s memory\n",
+               if (!res) {
+                       dev_err(dev, "found no memory resource for %s\n",
+                               mem_names[i]);
+                       ret = -EINVAL;
+                       goto fail;
+               }
+               if (!devm_request_mem_region(dev, res->start,
+                                            resource_size(res),
+                                            dev_name(dev))) {
+                       dev_err(dev, "could not request %s region for resource\n",
                                mem_names[i]);
+                       ret = -EBUSY;
+                       goto fail;
+               }
+
+               core->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start,
+                                                       resource_size(res));
+               if (IS_ERR(core->mem[i].cpu_addr)) {
+                       dev_err(dev, "failed to map %s memory\n", mem_names[i]);
                        ret = PTR_ERR(core->mem[i].cpu_addr);
+                       devm_release_mem_region(dev, res->start,
+                                               resource_size(res));
                        goto fail;
                }
                core->mem[i].bus_addr = res->start;