summaryrefslogtreecommitdiff
path: root/mali_kbase
diff options
context:
space:
mode:
Diffstat (limited to 'mali_kbase')
-rw-r--r--mali_kbase/csf/mali_kbase_csf_cpu_queue_debugfs.c3
-rw-r--r--mali_kbase/csf/mali_kbase_csf_firmware.c9
-rw-r--r--mali_kbase/csf/mali_kbase_csf_firmware.h7
-rw-r--r--mali_kbase/csf/mali_kbase_csf_firmware_core_dump.c51
-rw-r--r--mali_kbase/csf/mali_kbase_csf_firmware_core_dump.h59
-rw-r--r--mali_kbase/platform/pixel/pixel_gpu_dvfs_governor.c19
-rw-r--r--mali_kbase/platform/pixel/pixel_gpu_sscd.c98
-rw-r--r--mali_kbase/platform/pixel/pixel_gpu_sysfs.c5
-rw-r--r--mali_kbase/platform/pixel/pixel_gpu_trace.h24
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 */