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

drm/imagination: Move ELF fw utils to common file

Currently only MIPS firmware processors use ELF-formatted firmware. When
adding support for RISC-V firmware processors, it will be useful to have
ELF handling functions ready to go.

Reviewed-by: Frank Binns <frank.binns@imgtec.com>
Link: https://lore.kernel.org/r/20250410-sets-bxs-4-64-patch-v1-v6-13-eda620c5865f@imgtec.com
Signed-off-by: Matt Coster <matt.coster@imgtec.com>

+74 -56
+1
drivers/gpu/drm/imagination/Makefile
··· 14 14 pvr_fw_mips.o \ 15 15 pvr_fw_startstop.o \ 16 16 pvr_fw_trace.o \ 17 + pvr_fw_util.o \ 17 18 pvr_gem.o \ 18 19 pvr_hwrt.o \ 19 20 pvr_job.o \
+5
drivers/gpu/drm/imagination/pvr_fw.h
··· 478 478 pvr_fw_object_get_fw_addr_offset(fw_obj, 0, fw_addr_out); 479 479 } 480 480 481 + /* Util functions defined in pvr_fw_util.c. These are intended for use in pvr_fw_<arch>.c files. */ 482 + int 483 + pvr_fw_process_elf_command_stream(struct pvr_device *pvr_dev, const u8 *fw, u8 *fw_code_ptr, 484 + u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr); 485 + 481 486 #endif /* PVR_FW_H */
+2 -56
drivers/gpu/drm/imagination/pvr_fw_mips.c
··· 8 8 #include "pvr_rogue_mips.h" 9 9 #include "pvr_vm_mips.h" 10 10 11 - #include <linux/elf.h> 12 11 #include <linux/err.h> 13 12 #include <linux/types.h> 14 13 15 14 #define ROGUE_FW_HEAP_MIPS_BASE 0xC0000000 16 15 #define ROGUE_FW_HEAP_MIPS_SHIFT 24 /* 16 MB */ 17 16 #define ROGUE_FW_HEAP_MIPS_RESERVED_SIZE SZ_1M 18 - 19 - /** 20 - * process_elf_command_stream() - Process ELF firmware image and populate 21 - * firmware sections 22 - * @pvr_dev: Device pointer. 23 - * @fw: Pointer to firmware image. 24 - * @fw_code_ptr: Pointer to FW code section. 25 - * @fw_data_ptr: Pointer to FW data section. 26 - * @fw_core_code_ptr: Pointer to FW coremem code section. 27 - * @fw_core_data_ptr: Pointer to FW coremem data section. 28 - * 29 - * Returns : 30 - * * 0 on success, or 31 - * * -EINVAL on any error in ELF command stream. 32 - */ 33 - static int 34 - process_elf_command_stream(struct pvr_device *pvr_dev, const u8 *fw, u8 *fw_code_ptr, 35 - u8 *fw_data_ptr, u8 *fw_core_code_ptr, u8 *fw_core_data_ptr) 36 - { 37 - struct elf32_hdr *header = (struct elf32_hdr *)fw; 38 - struct elf32_phdr *program_header = (struct elf32_phdr *)(fw + header->e_phoff); 39 - struct drm_device *drm_dev = from_pvr_device(pvr_dev); 40 - int err; 41 - 42 - for (u32 entry = 0; entry < header->e_phnum; entry++, program_header++) { 43 - void *write_addr; 44 - 45 - /* Only consider loadable entries in the ELF segment table */ 46 - if (program_header->p_type != PT_LOAD) 47 - continue; 48 - 49 - err = pvr_fw_find_mmu_segment(pvr_dev, program_header->p_vaddr, 50 - program_header->p_memsz, fw_code_ptr, fw_data_ptr, 51 - fw_core_code_ptr, fw_core_data_ptr, &write_addr); 52 - if (err) { 53 - drm_err(drm_dev, 54 - "Addr 0x%x (size: %d) not found in any firmware segment", 55 - program_header->p_vaddr, program_header->p_memsz); 56 - return err; 57 - } 58 - 59 - /* Write to FW allocation only if available */ 60 - if (write_addr) { 61 - memcpy(write_addr, fw + program_header->p_offset, 62 - program_header->p_filesz); 63 - 64 - memset((u8 *)write_addr + program_header->p_filesz, 0, 65 - program_header->p_memsz - program_header->p_filesz); 66 - } 67 - } 68 - 69 - return 0; 70 - } 71 17 72 18 static int 73 19 pvr_mips_init(struct pvr_device *pvr_dev) ··· 44 98 dma_addr_t dma_addr; 45 99 int err; 46 100 47 - err = process_elf_command_stream(pvr_dev, fw, fw_code_ptr, fw_data_ptr, fw_core_code_ptr, 48 - fw_core_data_ptr); 101 + err = pvr_fw_process_elf_command_stream(pvr_dev, fw, fw_code_ptr, fw_data_ptr, 102 + fw_core_code_ptr, fw_core_data_ptr); 49 103 if (err) 50 104 return err; 51 105
+66
drivers/gpu/drm/imagination/pvr_fw_util.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only OR MIT 2 + /* Copyright (c) 2024 Imagination Technologies Ltd. */ 3 + 4 + #include "pvr_device.h" 5 + #include "pvr_fw.h" 6 + 7 + #include <drm/drm_device.h> 8 + #include <drm/drm_print.h> 9 + 10 + #include <linux/elf.h> 11 + #include <linux/string.h> 12 + #include <linux/types.h> 13 + 14 + /** 15 + * pvr_fw_process_elf_command_stream() - Process ELF firmware image and populate 16 + * firmware sections 17 + * @pvr_dev: Device pointer. 18 + * @fw: Pointer to firmware image. 19 + * @fw_code_ptr: Pointer to FW code section. 20 + * @fw_data_ptr: Pointer to FW data section. 21 + * @fw_core_code_ptr: Pointer to FW coremem code section. 22 + * @fw_core_data_ptr: Pointer to FW coremem data section. 23 + * 24 + * Returns : 25 + * * 0 on success, or 26 + * * -EINVAL on any error in ELF command stream. 27 + */ 28 + int 29 + pvr_fw_process_elf_command_stream(struct pvr_device *pvr_dev, const u8 *fw, 30 + u8 *fw_code_ptr, u8 *fw_data_ptr, 31 + u8 *fw_core_code_ptr, u8 *fw_core_data_ptr) 32 + { 33 + struct elf32_hdr *header = (struct elf32_hdr *)fw; 34 + struct elf32_phdr *program_header = (struct elf32_phdr *)(fw + header->e_phoff); 35 + struct drm_device *drm_dev = from_pvr_device(pvr_dev); 36 + int err; 37 + 38 + for (u32 entry = 0; entry < header->e_phnum; entry++, program_header++) { 39 + void *write_addr; 40 + 41 + /* Only consider loadable entries in the ELF segment table */ 42 + if (program_header->p_type != PT_LOAD) 43 + continue; 44 + 45 + err = pvr_fw_find_mmu_segment(pvr_dev, program_header->p_vaddr, 46 + program_header->p_memsz, fw_code_ptr, fw_data_ptr, 47 + fw_core_code_ptr, fw_core_data_ptr, &write_addr); 48 + if (err) { 49 + drm_err(drm_dev, 50 + "Addr 0x%x (size: %d) not found in any firmware segment", 51 + program_header->p_vaddr, program_header->p_memsz); 52 + return err; 53 + } 54 + 55 + /* Write to FW allocation only if available */ 56 + if (write_addr) { 57 + memcpy(write_addr, fw + program_header->p_offset, 58 + program_header->p_filesz); 59 + 60 + memset((u8 *)write_addr + program_header->p_filesz, 0, 61 + program_header->p_memsz - program_header->p_filesz); 62 + } 63 + } 64 + 65 + return 0; 66 + }