diff options
Diffstat (limited to 'mali_kbase')
-rw-r--r-- | mali_kbase/csf/mali_kbase_csf_cpu_queue_debugfs.c | 3 | ||||
-rw-r--r-- | mali_kbase/csf/mali_kbase_csf_firmware.c | 9 | ||||
-rw-r--r-- | mali_kbase/csf/mali_kbase_csf_firmware.h | 7 | ||||
-rw-r--r-- | mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c | 51 | ||||
-rw-r--r-- | mali_kbase/csf/mali_kbase_csf_firmware_core_dump.h | 59 | ||||
-rw-r--r-- | mali_kbase/platform/pixel/pixel_gpu_dvfs_governor.c | 19 | ||||
-rw-r--r-- | mali_kbase/platform/pixel/pixel_gpu_sscd.c | 98 | ||||
-rw-r--r-- | mali_kbase/platform/pixel/pixel_gpu_sysfs.c | 5 | ||||
-rw-r--r-- | mali_kbase/platform/pixel/pixel_gpu_trace.h | 24 |
9 files changed, 254 insertions, 21 deletions
diff --git a/mali_kbase/csf/mali_kbase_csf_cpu_queue_debugfs.c b/mali_kbase/csf/mali_kbase_csf_cpu_queue_debugfs.c index a319a4a..d783650 100644 --- a/mali_kbase/csf/mali_kbase_csf_cpu_queue_debugfs.c +++ b/mali_kbase/csf/mali_kbase_csf_cpu_queue_debugfs.c @@ -132,6 +132,9 @@ int kbase_csf_cpu_queue_dump(struct kbase_context *kctx, if (!buffer || !alloc_size) return 0; + if (alloc_size > SIZE_MAX - PAGE_SIZE) + return -ENOMEM; + alloc_size = (alloc_size + PAGE_SIZE) & ~(PAGE_SIZE - 1); dump_buffer = kzalloc(alloc_size, GFP_KERNEL); if (!dump_buffer) diff --git a/mali_kbase/csf/mali_kbase_csf_firmware.c b/mali_kbase/csf/mali_kbase_csf_firmware.c index 22f9aeb..bd815c4 100644 --- a/mali_kbase/csf/mali_kbase_csf_firmware.c +++ b/mali_kbase/csf/mali_kbase_csf_firmware.c @@ -110,17 +110,14 @@ MODULE_PARM_DESC(fw_debug, #define TL_METADATA_ENTRY_NAME_OFFSET (0x8) -#define BUILD_INFO_METADATA_SIZE_OFFSET (0x4) -#define BUILD_INFO_GIT_SHA_LEN (40U) -#define BUILD_INFO_GIT_DIRTY_LEN (1U) -#define BUILD_INFO_GIT_SHA_PATTERN "git_sha: " - #define CSF_MAX_FW_STOP_LOOPS (100000) #define CSF_GLB_REQ_CFG_MASK \ (GLB_REQ_CFG_ALLOC_EN_MASK | GLB_REQ_CFG_PROGRESS_TIMER_MASK | \ GLB_REQ_CFG_PWROFF_TIMER_MASK | GLB_REQ_IDLE_ENABLE_MASK) +char fw_git_sha[BUILD_INFO_GIT_SHA_LEN]; + static inline u32 input_page_read(const u32 *const input, const u32 offset) { WARN_ON(offset % sizeof(u32)); @@ -989,6 +986,8 @@ static int parse_build_info_metadata_entry(struct kbase_device *kbdev, } git_sha[i] = '\0'; + memcpy(fw_git_sha, git_sha, BUILD_INFO_GIT_SHA_LEN); + dev_info(kbdev->dev, "Mali firmware git_sha: %s\n", git_sha); } else dev_info(kbdev->dev, "Mali firmware git_sha not found or invalid\n"); diff --git a/mali_kbase/csf/mali_kbase_csf_firmware.h b/mali_kbase/csf/mali_kbase_csf_firmware.h index d8ed8d6..15d7b58 100644 --- a/mali_kbase/csf/mali_kbase_csf_firmware.h +++ b/mali_kbase/csf/mali_kbase_csf_firmware.h @@ -78,6 +78,13 @@ /* MAX_SUPPORTED_STREAMS_PER_GROUP: Maximum CSs per csg. */ #define MAX_SUPPORTED_STREAMS_PER_GROUP 32 +#define BUILD_INFO_METADATA_SIZE_OFFSET (0x4) +#define BUILD_INFO_GIT_SHA_LEN (40U) +#define BUILD_INFO_GIT_DIRTY_LEN (1U) +#define BUILD_INFO_GIT_SHA_PATTERN "git_sha: " + +extern char fw_git_sha[BUILD_INFO_GIT_SHA_LEN]; + struct kbase_device; diff --git a/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c b/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c index 493e1c8..e371db2 100644 --- a/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c +++ b/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c @@ -31,9 +31,6 @@ #include "mali_kbase_csf_firmware_core_dump.h" #include "backend/gpu/mali_kbase_pm_internal.h" -/* Page size in bytes in use by MCU. */ -#define FW_PAGE_SIZE 4096 - /* * FW image header core dump data format supported. * Currently only version 0.1 is supported. @@ -107,15 +104,6 @@ struct elf_prstatus32 { int pr_fpvalid; /* True if math copro being used. */ }; -/** - * struct fw_core_dump_data - Context for seq_file operations used on 'fw_core_dump' - * debugfs file. - * @kbdev: Instance of a GPU platform device that implements a CSF interface. - */ -struct fw_core_dump_data { - struct kbase_device *kbdev; -}; - /* * struct fw_core_dump_seq_off - Iterator for seq_file operations used on 'fw_core_dump' * debugfs file. @@ -405,7 +393,7 @@ static unsigned int fw_core_dump_create_prstatus_note(char *name, struct elf_prs * * 0 - success * * -ENOMEM - not enough memory for allocating ELF32 note */ -static int fw_core_dump_write_elf_header(struct seq_file *m) +int fw_core_dump_write_elf_header(struct seq_file *m) { struct elf32_hdr hdr; struct elf32_phdr phdr; @@ -496,13 +484,48 @@ static int fw_core_dump_write_elf_header(struct seq_file *m) return 0; } +#define MAX_FW_CORE_DUMP_HEADER_SIZE (1 << 14) + +/** + * get_fw_core_dump_size - Get firmware core dump size + * @kbdev: Instance of a GPU platform device that implements a CSF interface. + * + * Return: size on success, -1 otherwise. + */ +size_t get_fw_core_dump_size(struct kbase_device *kbdev) +{ + static char buffer[MAX_FW_CORE_DUMP_HEADER_SIZE]; + size_t size; + struct fw_core_dump_data private = {.kbdev = kbdev}; + struct seq_file m = {.private = &private, .buf = buffer, .size = MAX_FW_CORE_DUMP_HEADER_SIZE}; + struct kbase_csf_firmware_interface *interface; + + fw_core_dump_write_elf_header(&m); + if (unlikely(m.count >= m.size)) { + dev_warn(kbdev->dev, "firmware core dump header may be larger than buffer size"); + return -1; + } + size = m.count; + + list_for_each_entry(interface, &kbdev->csf.firmware_interfaces, node) { + /* Skip memory sections that cannot be read or are protected. */ + if ((interface->flags & CSF_FIRMWARE_ENTRY_PROTECTED) || + (interface->flags & CSF_FIRMWARE_ENTRY_READ) == 0) + continue; + + size += interface->num_pages * FW_PAGE_SIZE; + } + + return size; +} + /** * fw_core_dump_create - Requests firmware to save state for a firmware core dump * @kbdev: Instance of a GPU platform device that implements a CSF interface. * * Return: 0 on success, error code otherwise. */ -static int fw_core_dump_create(struct kbase_device *kbdev) +int fw_core_dump_create(struct kbase_device *kbdev) { int err; diff --git a/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.h b/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.h index 0537dca..940e8af 100644 --- a/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.h +++ b/mali_kbase/csf/mali_kbase_csf_firmware_core_dump.h @@ -27,6 +27,18 @@ struct kbase_device; /** Offset of the last field of core dump entry from the image header */ #define CORE_DUMP_ENTRY_START_ADDR_OFFSET (0x4) +/* Page size in bytes in use by MCU. */ +#define FW_PAGE_SIZE 4096 + +/** + * struct fw_core_dump_data - Context for seq_file operations used on 'fw_core_dump' + * debugfs file. + * @kbdev: Instance of a GPU platform device that implements a CSF interface. + */ +struct fw_core_dump_data { + struct kbase_device *kbdev; +}; + /** * kbase_csf_firmware_core_dump_entry_parse() - Parse a "core dump" entry from * the image header. @@ -62,4 +74,51 @@ int kbase_csf_firmware_core_dump_entry_parse(struct kbase_device *kbdev, const u */ void kbase_csf_firmware_core_dump_init(struct kbase_device *const kbdev); +/** + * get_fw_core_dump_size - Get firmware core dump size + * @kbdev: Instance of a GPU platform device that implements a CSF interface. + * + * Return: size on success, -1 otherwise. + */ +size_t get_fw_core_dump_size(struct kbase_device *kbdev); + +/** + * fw_core_dump_create - Requests firmware to save state for a firmware core dump + * @kbdev: Instance of a GPU platform device that implements a CSF interface. + * + * Return: 0 on success, error code otherwise. + */ +int fw_core_dump_create(struct kbase_device *kbdev); + +/** + * fw_core_dump_write_elf_header - Writes ELF header for the FW core dump + * @m: the seq_file handle + * + * Writes the ELF header of the core dump including program headers for + * memory sections and a note containing the current MCU register + * values. + * + * Excludes memory sections without read access permissions or + * are for protected memory. + * + * The data written is as follows: + * - ELF header + * - ELF PHDRs for memory sections + * - ELF PHDR for program header NOTE + * - ELF PRSTATUS note + * - 0-bytes padding to multiple of ELF_EXEC_PAGESIZE + * + * The actual memory section dumps should follow this (not written + * by this function). + * + * Retrieves the necessary information via the struct + * fw_core_dump_data stored in the private member of the seq_file + * handle. + * + * Return: + * * 0 - success + * * -ENOMEM - not enough memory for allocating ELF32 note + */ +int fw_core_dump_write_elf_header(struct seq_file *m); + #endif /* _KBASE_CSF_FIRMWARE_CORE_DUMP_H_ */ diff --git a/mali_kbase/platform/pixel/pixel_gpu_dvfs_governor.c b/mali_kbase/platform/pixel/pixel_gpu_dvfs_governor.c index a4d4a61..28d4073 100644 --- a/mali_kbase/platform/pixel/pixel_gpu_dvfs_governor.c +++ b/mali_kbase/platform/pixel/pixel_gpu_dvfs_governor.c @@ -7,11 +7,13 @@ /* Mali core includes */ #include <mali_kbase.h> +#include <trace/events/power.h> /* Pixel integration includes */ #include "mali_kbase_config_platform.h" #include "pixel_gpu_control.h" #include "pixel_gpu_dvfs.h" +#include "pixel_gpu_trace.h" /** * gpu_dvfs_governor_basic() - The evaluation function for &GPU_DVFS_GOVERNOR_BASIC. @@ -165,11 +167,24 @@ int gpu_dvfs_governor_get_next_level(struct kbase_device *kbdev, struct gpu_dvfs_utlization *util_stats) { struct pixel_context *pc = kbdev->platform_context; - int level; + int level, ret; lockdep_assert_held(&pc->dvfs.lock); level = governors[pc->dvfs.governor.curr].evaluate(kbdev, util_stats); - return clamp(level, pc->dvfs.level_scaling_max, pc->dvfs.level_scaling_min); + if (level != pc->dvfs.level) { + trace_clock_set_rate("gpu_gov_rec", pc->dvfs.table[level].clk[GPU_DVFS_CLK_SHADERS], + raw_smp_processor_id()); + } + + ret = clamp(level, pc->dvfs.level_scaling_max, pc->dvfs.level_scaling_min); + if (ret != level) { + trace_gpu_gov_rec_violate(pc->dvfs.table[level].clk[GPU_DVFS_CLK_SHADERS], + pc->dvfs.table[ret].clk[GPU_DVFS_CLK_SHADERS], + pc->dvfs.table[pc->dvfs.level_scaling_min].clk[GPU_DVFS_CLK_SHADERS], + pc->dvfs.table[pc->dvfs.level_scaling_max].clk[GPU_DVFS_CLK_SHADERS]); + } + + return ret; } /** diff --git a/mali_kbase/platform/pixel/pixel_gpu_sscd.c b/mali_kbase/platform/pixel/pixel_gpu_sscd.c index 75f3c2a..b48d8c7 100644 --- a/mali_kbase/platform/pixel/pixel_gpu_sscd.c +++ b/mali_kbase/platform/pixel/pixel_gpu_sscd.c @@ -8,7 +8,9 @@ /* Mali core includes */ #include <mali_kbase.h> #include <csf/mali_kbase_csf_trace_buffer.h> +#include <csf/mali_kbase_csf_firmware.h> #include <csf/mali_kbase_csf_firmware_cfg.h> +#include <csf/mali_kbase_csf_firmware_core_dump.h> /* Pixel integration includes */ #include "mali_kbase_config_platform.h" @@ -53,6 +55,7 @@ enum PDC_STATUS = 0x8, KTRACE = 0x9, CONTEXTS = 0xA, + FW_CORE_DUMP = 0xB, NUM_SEGMENTS } sscd_segs; @@ -356,6 +359,88 @@ static int get_and_init_contexts(struct kbase_device *kbdev, } #endif +struct pixel_fw_core_dump { + char magic[4]; + u32 reserved; + char git_sha[BUILD_INFO_GIT_SHA_LEN]; + char core_dump[]; +}; + +static void get_and_init_fw_core_dump(struct kbase_device *kbdev, struct sscd_segment *seg) +{ + const size_t core_dump_size = get_fw_core_dump_size(kbdev); + + int i; + struct pixel_fw_core_dump *fw_core_dump; + struct kbase_csf_firmware_interface *interface; + struct page *page; + u32 *p; + size_t size; + size_t write_size; + + if (core_dump_size == -1) + { + dev_err(kbdev->dev, "pixel: failed to get firmware core dump size"); + } + + seg->size = sizeof(struct pixel_fw_core_dump) + core_dump_size; + seg->addr = kzalloc(seg->size, GFP_KERNEL); + + if (seg->addr == NULL) { + seg->size = 0; + dev_err(kbdev->dev, "pixel: failed to allocate for firmware core dump buffer"); + return; + } + + fw_core_dump = (struct pixel_fw_core_dump *) seg->addr; + + strncpy(fw_core_dump->magic, "fwcd", 4); + memcpy(fw_core_dump->git_sha, fw_git_sha, BUILD_INFO_GIT_SHA_LEN); + + // Dumping ELF header + { + struct fw_core_dump_data private = {.kbdev = kbdev}; + struct seq_file m = {.private = &private, .buf = fw_core_dump->core_dump, .size = core_dump_size}; + fw_core_dump_write_elf_header(&m); + size = m.count; + if (unlikely(m.count >= m.size)) + dev_warn(kbdev->dev, "firmware core dump header may be larger than buffer size"); + } + + // Dumping pages + list_for_each_entry(interface, &kbdev->csf.firmware_interfaces, node) { + /* Skip memory sections that cannot be read or are protected. */ + if ((interface->flags & CSF_FIRMWARE_ENTRY_PROTECTED) || + (interface->flags & CSF_FIRMWARE_ENTRY_READ) == 0) + continue; + + for(i = 0; i < interface->num_pages; i++) + { + page = as_page(interface->phys[i]); + write_size = size < core_dump_size ? min(core_dump_size - size, (size_t) FW_PAGE_SIZE) : 0; + if (write_size) + { + p = kmap_atomic(page); + memcpy(fw_core_dump->core_dump + size, p, write_size); + kunmap_atomic(p); + } + size += FW_PAGE_SIZE; + + if (size < FW_PAGE_SIZE) + break; + } + } + + if (unlikely(size != core_dump_size)) + { + dev_err(kbdev->dev, "firmware core dump size and buffer size are different"); + kfree(seg->addr); + seg->addr = NULL; + seg->size = 0; + } + + return; +} /* * Stub pending FW support */ @@ -493,6 +578,9 @@ void gpu_sscd_dump(struct kbase_device *kbdev, const char* reason) unsigned long flags, current_ts = jiffies; struct pixel_gpu_pdc_status pdc_status; static unsigned long last_hang_sscd_ts; +#if MALI_USE_CSF + int fwcd_err; +#endif if (!strcmp(reason, "GPU hang")) { /* GPU hang - avoid multiple coredumps for the same hang until @@ -515,6 +603,12 @@ void gpu_sscd_dump(struct kbase_device *kbdev, const char* reason) return; } +#if MALI_USE_CSF + fwcd_err = fw_core_dump_create(kbdev); + if (fwcd_err) + dev_err(kbdev->dev, "pixel: failed to create firmware core dump"); +#endif + ec = segments_init(kbdev, segs); if (ec != 0) { dev_err(kbdev->dev, @@ -554,7 +648,11 @@ void gpu_sscd_dump(struct kbase_device *kbdev, const char* reason) dev_err(kbdev->dev, "could not collect active contexts: rc: %i", ec); } + + if (!fwcd_err) + get_and_init_fw_core_dump(kbdev, &segs[FW_CORE_DUMP]); #endif + spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); /* Acquire the pm lock to prevent modifications to the rail state log */ diff --git a/mali_kbase/platform/pixel/pixel_gpu_sysfs.c b/mali_kbase/platform/pixel/pixel_gpu_sysfs.c index c816460..f6164f9 100644 --- a/mali_kbase/platform/pixel/pixel_gpu_sysfs.c +++ b/mali_kbase/platform/pixel/pixel_gpu_sysfs.c @@ -7,6 +7,7 @@ /* Mali core includes */ #include <mali_kbase.h> +#include <trace/events/power.h> /* Pixel integration includes */ #include "mali_kbase_config_platform.h" @@ -445,6 +446,8 @@ static ssize_t hint_max_freq_store(struct device *dev, struct device_attribute * if (level < 0) return -EINVAL; + trace_clock_set_rate("gpu_hint_max", clock, raw_smp_processor_id()); + mutex_lock(&pc->dvfs.lock); gpu_dvfs_update_level_lock(kbdev, GPU_DVFS_LEVEL_LOCK_HINT, -1, level); gpu_dvfs_select_level(kbdev); @@ -489,6 +492,8 @@ static ssize_t hint_min_freq_store(struct device *dev, struct device_attribute * if (level < 0) return -EINVAL; + trace_clock_set_rate("gpu_hint_min", clock, raw_smp_processor_id()); + mutex_lock(&pc->dvfs.lock); gpu_dvfs_update_level_lock(kbdev, GPU_DVFS_LEVEL_LOCK_HINT, level, -1); gpu_dvfs_select_level(kbdev); diff --git a/mali_kbase/platform/pixel/pixel_gpu_trace.h b/mali_kbase/platform/pixel/pixel_gpu_trace.h index 1165e75..6c30f1b 100644 --- a/mali_kbase/platform/pixel/pixel_gpu_trace.h +++ b/mali_kbase/platform/pixel/pixel_gpu_trace.h @@ -45,6 +45,30 @@ TRACE_EVENT(gpu_power_state, ) ); +TRACE_EVENT(gpu_gov_rec_violate, + TP_PROTO(unsigned int recfreq, unsigned int retfreq, + unsigned int minlvfreq, unsigned int maxlvfreq), + TP_ARGS(recfreq, retfreq, minlvfreq, maxlvfreq), + TP_STRUCT__entry( + __field(unsigned int, recfreq) + __field(unsigned int, retfreq) + __field(unsigned int, minlvfreq) + __field(unsigned int, maxlvfreq) + ), + TP_fast_assign( + __entry->recfreq = recfreq; + __entry->retfreq = retfreq; + __entry->minlvfreq = minlvfreq; + __entry->maxlvfreq = maxlvfreq; + ), + TP_printk("rec=%u ret=%u min=%u max=%u", + __entry->recfreq, + __entry->retfreq, + __entry->minlvfreq, + __entry->maxlvfreq + ) +); + #endif /* _TRACE_PIXEL_GPU_H */ /* This part must be outside protection */ |