Skip to content

Commit

Permalink
drm/imagination: fix firmware memory leaks
Browse files Browse the repository at this point in the history
commit a5b230e upstream.

Free the memory used to hold the results of firmware image processing
when the module is unloaded.

Fix the related issue of the same memory being leaked if processing
of the firmware image fails during module load.

Ensure all firmware GEM objects are destroyed if firmware image
processing fails.

Fixes memory leaks on powervr module unload detected by Kmemleak:

unreferenced object 0xffff000042e20000 (size 94208):
  comm "modprobe", pid 470, jiffies 4295277154
  hex dump (first 32 bytes):
    02 ae 7f ed bf 45 84 00 3c 5b 1f ed 9f 45 45 05  .....E..<[...EE.
    d5 4f 5d 14 6c 00 3d 23 30 d0 3a 4a 66 0e 48 c8  .O].l.=#0.:Jf.H.
  backtrace (crc dd329dec):
    kmemleak_alloc+0x30/0x40
    ___kmalloc_large_node+0x140/0x188
    __kmalloc_large_node_noprof+0x2c/0x13c
    __kmalloc_noprof+0x48/0x4c0
    pvr_fw_init+0xaa4/0x1f50 [powervr]

unreferenced object 0xffff000042d20000 (size 20480):
  comm "modprobe", pid 470, jiffies 4295277154
  hex dump (first 32 bytes):
    00 00 00 00 00 00 00 00 09 00 00 00 0b 00 00 00  ................
    00 00 00 00 00 00 00 00 07 00 00 00 08 00 00 00  ................
  backtrace (crc 395b02e3):
    kmemleak_alloc+0x30/0x40
    ___kmalloc_large_node+0x140/0x188
    __kmalloc_large_node_noprof+0x2c/0x13c
    __kmalloc_noprof+0x48/0x4c0
    pvr_fw_init+0xb0c/0x1f50 [powervr]

Cc: stable@vger.kernel.org
Fixes: cc1aeed ("drm/imagination: Implement firmware infrastructure and META FW support")
Signed-off-by: Brendan King <brendan.king@imgtec.com>
Reviewed-by: Matt Coster <matt.coster@imgtec.com>
Link: https://lore.kernel.org/r/20250318-ddkopsrc-1339-firmware-related-memory-leak-on-module-unload-v1-1-155337c57bb4@imgtec.com
Signed-off-by: Matt Coster <matt.coster@imgtec.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Brendan King authored and Greg Kroah-Hartman committed Apr 25, 2025
1 parent 6e2c805 commit 490c30f
Showing 1 changed file with 20 additions and 7 deletions.
27 changes: 20 additions & 7 deletions drivers/gpu/drm/imagination/pvr_fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ pvr_fw_process(struct pvr_device *pvr_dev)
fw_mem->core_data, fw_mem->core_code_alloc_size);

if (err)
goto err_free_fw_core_data_obj;
goto err_free_kdata;

memcpy(fw_code_ptr, fw_mem->code, fw_mem->code_alloc_size);
memcpy(fw_data_ptr, fw_mem->data, fw_mem->data_alloc_size);
Expand All @@ -742,18 +742,22 @@ pvr_fw_process(struct pvr_device *pvr_dev)
memcpy(fw_core_data_ptr, fw_mem->core_data, fw_mem->core_data_alloc_size);

/* We're finished with the firmware section memory on the CPU, unmap. */
if (fw_core_data_ptr)
if (fw_core_data_ptr) {
pvr_fw_object_vunmap(fw_mem->core_data_obj);
if (fw_core_code_ptr)
fw_core_data_ptr = NULL;
}
if (fw_core_code_ptr) {
pvr_fw_object_vunmap(fw_mem->core_code_obj);
fw_core_code_ptr = NULL;
}
pvr_fw_object_vunmap(fw_mem->data_obj);
fw_data_ptr = NULL;
pvr_fw_object_vunmap(fw_mem->code_obj);
fw_code_ptr = NULL;

err = pvr_fw_create_fwif_connection_ctl(pvr_dev);
if (err)
goto err_free_fw_core_data_obj;
goto err_free_kdata;

return 0;

Expand All @@ -763,13 +767,16 @@ pvr_fw_process(struct pvr_device *pvr_dev)
kfree(fw_mem->data);
kfree(fw_mem->code);

err_free_fw_core_data_obj:
if (fw_core_data_ptr)
pvr_fw_object_unmap_and_destroy(fw_mem->core_data_obj);
pvr_fw_object_vunmap(fw_mem->core_data_obj);
if (fw_mem->core_data_obj)
pvr_fw_object_destroy(fw_mem->core_data_obj);

err_free_fw_core_code_obj:
if (fw_core_code_ptr)
pvr_fw_object_unmap_and_destroy(fw_mem->core_code_obj);
pvr_fw_object_vunmap(fw_mem->core_code_obj);
if (fw_mem->core_code_obj)
pvr_fw_object_destroy(fw_mem->core_code_obj);

err_free_fw_data_obj:
if (fw_data_ptr)
Expand Down Expand Up @@ -836,6 +843,12 @@ pvr_fw_cleanup(struct pvr_device *pvr_dev)
struct pvr_fw_mem *fw_mem = &pvr_dev->fw_dev.mem;

pvr_fw_fini_fwif_connection_ctl(pvr_dev);

kfree(fw_mem->core_data);
kfree(fw_mem->core_code);
kfree(fw_mem->data);
kfree(fw_mem->code);

if (fw_mem->core_code_obj)
pvr_fw_object_destroy(fw_mem->core_code_obj);
if (fw_mem->core_data_obj)
Expand Down

0 comments on commit 490c30f

Please sign in to comment.