summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurora pro automerger <aurora-pro-automerger@google.com>2022-06-14 13:50:26 -0700
committerJohn Scheible <johnscheible@google.com>2022-06-15 19:51:41 +0000
commit399265ce726dfc7e5b02352fbf17683a4ee15950 (patch)
tree701de08e23d0f3104a3c216a4912140d652f05c6
parentb16f2fa6d4a747b68c8eab8fefb4dd94537d5426 (diff)
downloadgs201-399265ce726dfc7e5b02352fbf17683a4ee15950.tar.gz
[Copybara Auto Merge] Merge branch 'gs201-release' into 'android13-gs-pixel-5.10-tm-d1'android-13.0.0_r0.45android-13.0.0_r0.32android-13.0.0_r0.31android-gs-pantah-5.10-android13-d1
Revert "gxp: authenticate firmware after requesting it" Bug: 235447772 gxp: Add option to disable DSP FW auth Bug: 235135800 gxp: Fix hangs and OOB writes when auth fails Bug: 234947988 gxp: Adjust the per-core FW size from 16MB to 1MB Bug: 228277106 gxp: Add enable_debug_dump argument for insmod Bug: 234529356 gxp: Dynamically allocate memory for debug dump buffer Bug: 234529355 gxp: Trigger debug dump only when firmware is up and running Bug: 233660431 Bug: 233607168 gxp: remove support for unsigned firmware Bug: 220246540 gxp: authenticate firmware after requesting it Bug: 232715929 gxp: Expose additional DVFS states in power APIs Bug: 233929549 GitOrigin-RevId: 99f54518439e715bff19b7b45b9cafe635febb77 Change-Id: Iee1b3c93aad333db2d051017e3509279ceb35f38
-rw-r--r--gxp-debug-dump.c550
-rw-r--r--gxp-debug-dump.h18
-rw-r--r--gxp-debugfs.c5
-rw-r--r--gxp-dma-iommu.c8
-rw-r--r--gxp-firmware-data.c23
-rw-r--r--gxp-firmware.c27
-rw-r--r--gxp-firmware.h4
-rw-r--r--gxp-host-device-structs.h2
-rw-r--r--gxp-internal.h1
-rw-r--r--gxp-iova.h5
-rw-r--r--gxp-platform.c25
-rw-r--r--gxp-pm.c13
-rw-r--r--gxp-pm.h18
-rw-r--r--gxp-vd.c30
-rw-r--r--gxp.h6
15 files changed, 447 insertions, 288 deletions
diff --git a/gxp-debug-dump.c b/gxp-debug-dump.c
index 322e1ca..1165a28 100644
--- a/gxp-debug-dump.c
+++ b/gxp-debug-dump.c
@@ -9,6 +9,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
+#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/workqueue.h>
@@ -18,17 +19,24 @@
#endif
#include "gxp-debug-dump.h"
+#include "gxp-dma.h"
#include "gxp-doorbell.h"
+#include "gxp-firmware.h"
+#include "gxp-host-device-structs.h"
#include "gxp-internal.h"
#include "gxp-lpm.h"
#include "gxp-mapping.h"
+#include "gxp-pm.h"
#include "gxp-vd.h"
+#include "gxp-wakelock.h"
#define SSCD_MSG_LENGTH 64
#define SYNC_BARRIER_BLOCK 0x00100000
#define SYNC_BARRIER_BASE(_x_) ((_x_) << 12)
+#define DEBUG_DUMP_MEMORY_SIZE 0x400000 /* size in bytes */
+
/* Enum indicating the debug dump request reason. */
enum gxp_debug_dump_init_type {
DEBUG_DUMP_FW_INIT,
@@ -40,6 +48,10 @@ enum gxp_common_segments_idx {
GXP_LPM_REGISTERS_IDX
};
+/* Whether or not the debug dump subsystem should be enabled. */
+static int gxp_debug_dump_enable;
+module_param_named(debug_dump_enable, gxp_debug_dump_enable, int, 0660);
+
static void gxp_debug_dump_cache_invalidate(struct gxp_dev *gxp)
{
/* Debug dump carveout is currently coherent. NO-OP. */
@@ -242,12 +254,27 @@ gxp_get_lpm_registers(struct gxp_dev *gxp, struct gxp_seg_header *seg_header,
dev_dbg(gxp->dev, "Done getting LPM registers\n");
}
-static void gxp_get_common_dump(struct gxp_dev *gxp)
+/*
+ * Caller must make sure that gxp->debug_dump_mgr->common_dump is not NULL.
+ */
+static int gxp_get_common_dump(struct gxp_dev *gxp)
{
struct gxp_common_dump *common_dump = gxp->debug_dump_mgr->common_dump;
struct gxp_seg_header *common_seg_header = common_dump->seg_header;
struct gxp_common_dump_data *common_dump_data =
&common_dump->common_dump_data;
+ int ret;
+
+ /* Power on BLK_AUR to read the common registers */
+ ret = gxp_wakelock_acquire(gxp);
+ if (ret) {
+ dev_err(gxp->dev,
+ "Failed to acquire wakelock for getting common dump\n");
+ return ret;
+ }
+ gxp_pm_update_requested_power_states(gxp, AUR_OFF, true, AUR_UUD, false,
+ AUR_MEM_UNDEFINED,
+ AUR_MEM_UNDEFINED);
gxp_get_common_registers(gxp,
&common_seg_header[GXP_COMMON_REGISTERS_IDX],
@@ -255,12 +282,19 @@ static void gxp_get_common_dump(struct gxp_dev *gxp)
gxp_get_lpm_registers(gxp, &common_seg_header[GXP_LPM_REGISTERS_IDX],
&common_dump_data->lpm_regs);
+ gxp_wakelock_release(gxp);
+ gxp_pm_update_requested_power_states(gxp, AUR_UUD, false, AUR_OFF, true,
+ AUR_MEM_UNDEFINED,
+ AUR_MEM_UNDEFINED);
+
dev_dbg(gxp->dev, "Segment Header for Common Segment\n");
dev_dbg(gxp->dev, "Name: %s, Size: 0x%0x bytes, Valid :%0x\n",
common_seg_header->name, common_seg_header->size,
common_seg_header->valid);
dev_dbg(gxp->dev, "Register aurora_revision: 0x%0x\n",
common_dump_data->common_regs.aurora_revision);
+
+ return ret;
}
#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
@@ -281,173 +315,39 @@ static void gxp_send_to_sscd(struct gxp_dev *gxp, void *segs, int seg_cnt,
dev_err(gxp->dev, "Unable to send the report to SSCD daemon\n");
return;
}
-
- /*
- * This delay is needed to ensure there's sufficient time
- * in between sscd_report() being called, as the file name of
- * the core dump files generated by the SSCD daemon includes a
- * time format with a seconds precision.
- */
- msleep(1000);
-}
-#endif
-
-static void gxp_handle_debug_dump(struct gxp_dev *gxp, uint32_t core_id)
-{
- struct gxp_core_dump_header *core_dump_header;
- struct gxp_core_header *core_header;
- struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
- struct gxp_core_dump *core_dump = mgr->core_dump;
- struct gxp_common_dump *common_dump = mgr->common_dump;
- int i;
-#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
- int seg_idx = 0;
- void *data_addr;
- char sscd_msg[SSCD_MSG_LENGTH];
-
- /* Common */
- data_addr = &common_dump->common_dump_data.common_regs;
- for (i = 0; i < GXP_NUM_COMMON_SEGMENTS; i++) {
- mgr->segs[core_id][seg_idx].addr = data_addr;
- mgr->segs[core_id][seg_idx].size =
- common_dump->seg_header[i].size;
- data_addr += mgr->segs[core_id][seg_idx].size;
- seg_idx++;
- }
-#endif
-
- /* Core */
- core_dump_header = &core_dump->core_dump_header[core_id];
- core_header = &core_dump_header->core_header;
- if (!core_header->dump_available) {
- dev_err(gxp->dev,
- "Core dump should have been available\n");
- return;
- }
-#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
- /* Core Header */
- mgr->segs[core_id][seg_idx].addr = core_header;
- mgr->segs[core_id][seg_idx].size = sizeof(struct gxp_core_header);
- seg_idx++;
-
- data_addr = &core_dump->dump_data[core_id *
- core_header->core_dump_size /
- sizeof(u32)];
-
- for (i = 0; i < GXP_NUM_CORE_SEGMENTS - 1; i++) {
- mgr->segs[core_id][seg_idx].addr = data_addr;
- mgr->segs[core_id][seg_idx].size = 0;
- if (core_dump_header->seg_header[i].valid) {
- mgr->segs[core_id][seg_idx].size =
- core_dump_header->seg_header[i].size;
- }
-
- data_addr += core_dump_header->seg_header[i].size;
- seg_idx++;
- }
-
- dev_dbg(gxp->dev, "Passing dump data to SSCD daemon\n");
- snprintf(sscd_msg, SSCD_MSG_LENGTH - 1,
- "gxp debug dump - dump data (core %0x)", core_id);
- gxp_send_to_sscd(gxp, mgr->segs[core_id], seg_idx, sscd_msg);
-#endif
- /* This bit signals that core dump has been processed */
- core_header->dump_available = 0;
-
- for (i = 0; i < GXP_NUM_COMMON_SEGMENTS; i++)
- common_dump->seg_header[i].valid = 0;
-
- for (i = 0; i < GXP_NUM_CORE_SEGMENTS; i++)
- core_dump_header->seg_header[i].valid = 0;
-}
-
-static void gxp_free_segments(struct gxp_dev *gxp)
-{
-#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
- int core_id;
-
- for (core_id = 0; core_id < GXP_NUM_CORES; core_id++)
- kfree(gxp->debug_dump_mgr->segs[core_id]);
-#endif
- kfree(gxp->debug_dump_mgr->common_dump);
-}
-
-#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
-static int gxp_get_mapping_count(struct gxp_dev *gxp, int core_id)
-{
- struct gxp_core_dump *core_dump = gxp->debug_dump_mgr->core_dump;
- struct gxp_core_header *core_header =
- &core_dump->core_dump_header[core_id].core_header;
- int i, count = 0;
-
- for (i = 0; i < GXP_NUM_BUFFER_MAPPINGS; i++) {
- if (core_header->user_bufs[i].size != 0)
- count++;
- }
-
- return count;
-}
-#endif
-
-static int gxp_init_segments(struct gxp_dev *gxp)
-{
-#if !IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
- return 0;
-#else
- struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
- /*
- * segs_num include the common segments, core segments for each core,
- * core header for each core
- */
- int segs_min_num = GXP_NUM_COMMON_SEGMENTS + GXP_NUM_CORE_SEGMENTS + 1;
- int segs_num;
- int core_id = 0;
-
- for (core_id = 0; core_id < GXP_NUM_CORES; core_id++) {
- segs_num = segs_min_num + gxp_get_mapping_count(gxp, core_id);
- mgr->segs[core_id] = kmalloc_array(segs_num,
- sizeof(struct sscd_segment),
- GFP_KERNEL);
- if (!mgr->segs[core_id])
- goto err_out;
- }
-
- mgr->common_dump = kmalloc(sizeof(*mgr->common_dump), GFP_KERNEL);
- if (!mgr->common_dump)
- goto err_out;
-
- return 0;
-err_out:
- gxp_free_segments(gxp);
-
- return -ENOMEM;
-#endif
}
/*
* `user_bufs` is an input buffer containing up to GXP_NUM_BUFFER_MAPPINGS
* virtual addresses
*/
-#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
-static void gxp_add_user_buffer_to_segments(struct gxp_dev *gxp,
- struct gxp_core_header *core_header,
- int core_id, int seg_idx,
- void *user_bufs[])
+static int gxp_add_user_buffer_to_segments(struct gxp_dev *gxp,
+ struct gxp_core_header *core_header,
+ int core_id, int seg_idx,
+ void *user_bufs[])
{
struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
struct gxp_user_buffer user_buf;
int i;
- for (i = 0; i < GXP_NUM_BUFFER_MAPPINGS ; i++) {
+ for (i = 0; i < GXP_NUM_BUFFER_MAPPINGS; i++) {
user_buf = core_header->user_bufs[i];
if (user_buf.size == 0)
continue;
+ if (seg_idx >= GXP_NUM_SEGMENTS_PER_CORE)
+ return -EFAULT;
+
mgr->segs[core_id][seg_idx].addr = user_bufs[i];
mgr->segs[core_id][seg_idx].size = user_buf.size;
seg_idx++;
}
+
+ return 0;
}
+/*
+ * Caller must have locked `gxp->vd_semaphore` for reading.
+ */
static void gxp_user_buffers_vunmap(struct gxp_dev *gxp,
struct gxp_core_header *core_header)
{
@@ -456,12 +356,18 @@ static void gxp_user_buffers_vunmap(struct gxp_dev *gxp,
int i;
struct gxp_mapping *mapping;
- down_read(&gxp->vd_semaphore);
+ lockdep_assert_held(&gxp->vd_semaphore);
+ /*
+ * TODO (b/234172464): When implementing per-core debug dump locks,
+ * down_read(&gxp->vd_semaphore) must be re-added before accessing
+ * gxp->core_to_vd[], and up_read(&gxp->vd_semaphore) must be re-added
+ * after.
+ */
vd = gxp->core_to_vd[core_header->core_id];
if (!vd) {
dev_err(gxp->dev, "Virtual device is not available for vunmap\n");
- goto out;
+ return;
}
for (i = 0; i < GXP_NUM_BUFFER_MAPPINGS; i++) {
@@ -481,24 +387,30 @@ static void gxp_user_buffers_vunmap(struct gxp_dev *gxp,
gxp_mapping_vunmap(mapping);
gxp_mapping_put(mapping);
}
-
-out:
- up_read(&gxp->vd_semaphore);
}
+/*
+ * Caller must have locked `gxp->vd_semaphore` for reading.
+ */
static int gxp_user_buffers_vmap(struct gxp_dev *gxp,
struct gxp_core_header *core_header,
void *user_buf_vaddrs[])
{
struct gxp_virtual_device *vd;
- struct gxp_user_buffer user_buf;
+ struct gxp_user_buffer *user_buf;
int i, cnt = 0;
dma_addr_t daddr;
struct gxp_mapping *mapping;
void *vaddr;
- down_read(&gxp->vd_semaphore);
+ lockdep_assert_held(&gxp->vd_semaphore);
+ /*
+ * TODO (b/234172464): When implementing per-core debug dump locks,
+ * down_read(&gxp->vd_semaphore) must be re-added before accessing
+ * gxp->core_to_vd[], and up_read(&gxp->vd_semaphore) must be re-added
+ * after.
+ */
vd = gxp->core_to_vd[core_header->core_id];
if (!vd) {
dev_err(gxp->dev, "Virtual device is not available for vmap\n");
@@ -506,15 +418,15 @@ static int gxp_user_buffers_vmap(struct gxp_dev *gxp,
}
for (i = 0; i < GXP_NUM_BUFFER_MAPPINGS; i++) {
- user_buf = core_header->user_bufs[i];
- if (user_buf.size == 0)
+ user_buf = &core_header->user_bufs[i];
+ if (user_buf->size == 0)
continue;
/* Get mapping */
- daddr = (dma_addr_t)user_buf.device_addr;
+ daddr = (dma_addr_t)user_buf->device_addr;
mapping = gxp_vd_mapping_search_in_range(vd, daddr);
if (!mapping) {
- user_buf.size = 0;
+ user_buf->size = 0;
continue;
}
@@ -529,7 +441,6 @@ static int gxp_user_buffers_vmap(struct gxp_dev *gxp,
gxp_mapping_put(mapping);
if (IS_ERR(vaddr)) {
- up_read(&gxp->vd_semaphore);
gxp_user_buffers_vunmap(gxp, core_header);
return 0;
}
@@ -538,99 +449,264 @@ static int gxp_user_buffers_vmap(struct gxp_dev *gxp,
user_buf_vaddrs[i] =
vaddr + daddr -
(mapping->device_address & ~(PAGE_SIZE - 1));
+
+ /* Check that the entire user buffer is mapped */
+ if ((user_buf_vaddrs[i] + user_buf->size) >
+ (vaddr + mapping->size)) {
+ gxp_user_buffers_vunmap(gxp, core_header);
+ return 0;
+ }
+
cnt++;
}
out:
- up_read(&gxp->vd_semaphore);
-
return cnt;
}
#endif
-static void gxp_handle_dram_dump(struct gxp_dev *gxp, uint32_t core_id)
+static void gxp_invalidate_segments(struct gxp_dev *gxp, uint32_t core_id)
+{
+ int i;
+ struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
+ struct gxp_core_dump *core_dump;
+ struct gxp_common_dump *common_dump;
+ struct gxp_core_dump_header *core_dump_header;
+
+ core_dump = mgr->core_dump;
+ common_dump = mgr->common_dump;
+ if (!core_dump || !common_dump) {
+ dev_dbg(gxp->dev,
+ "Failed to get core_dump or common_dump for invalidating segments\n");
+ return;
+ }
+
+ core_dump_header = &core_dump->core_dump_header[core_id];
+ if (!core_dump_header) {
+ dev_dbg(gxp->dev,
+ "Failed to get core_dump_header for invalidating segments\n");
+ return;
+ }
+
+ for (i = 0; i < GXP_NUM_COMMON_SEGMENTS; i++)
+ common_dump->seg_header[i].valid = 0;
+
+ for (i = 0; i < GXP_NUM_CORE_SEGMENTS; i++)
+ core_dump_header->seg_header[i].valid = 0;
+
+ for (i = 0; i < GXP_NUM_BUFFER_MAPPINGS; i++)
+ core_dump_header->core_header.user_bufs[i].size = 0;
+
+ core_dump_header->core_header.dump_available = 0;
+}
+
+/*
+ * Caller must make sure that gxp->debug_dump_mgr->common_dump and
+ * gxp->debug_dump_mgr->core_dump are not NULL.
+ */
+static int gxp_handle_debug_dump(struct gxp_dev *gxp, uint32_t core_id)
{
struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
+ struct gxp_core_dump *core_dump = mgr->core_dump;
struct gxp_core_dump_header *core_dump_header =
- &mgr->core_dump->core_dump_header[core_id];
- struct gxp_seg_header *dram_seg_header =
- &core_dump_header->seg_header[GXP_CORE_DRAM_SEGMENT_IDX];
-#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+ &core_dump->core_dump_header[core_id];
struct gxp_core_header *core_header = &core_dump_header->core_header;
- struct sscd_segment *sscd_seg =
- &mgr->segs[core_id][GXP_DEBUG_DUMP_DRAM_SEGMENT_IDX];
+ int ret = 0;
+#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+ struct gxp_common_dump *common_dump = mgr->common_dump;
+ int i;
+ int seg_idx = 0;
+ void *data_addr;
char sscd_msg[SSCD_MSG_LENGTH];
void *user_buf_vaddrs[GXP_NUM_BUFFER_MAPPINGS];
int user_buf_cnt;
+#endif
- sscd_seg->addr = gxp->fwbufs[core_id].vaddr;
- sscd_seg->size = gxp->fwbufs[core_id].size;
+ /* Core */
+ if (!core_header->dump_available) {
+ dev_err(gxp->dev, "Core dump should have been available\n");
+ ret = -EINVAL;
+ goto out;
+ }
+#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+ /* Common */
+ data_addr = &common_dump->common_dump_data.common_regs;
+ for (i = 0; i < GXP_NUM_COMMON_SEGMENTS; i++) {
+ if (seg_idx >= GXP_NUM_SEGMENTS_PER_CORE) {
+ ret = -EFAULT;
+ goto out_efault;
+ }
+ mgr->segs[core_id][seg_idx].addr = data_addr;
+ mgr->segs[core_id][seg_idx].size =
+ common_dump->seg_header[i].size;
+ data_addr += mgr->segs[core_id][seg_idx].size;
+ seg_idx++;
+ }
+
+ /* Core Header */
+ if (seg_idx >= GXP_NUM_SEGMENTS_PER_CORE) {
+ ret = -EFAULT;
+ goto out_efault;
+ }
+ mgr->segs[core_id][seg_idx].addr = core_header;
+ mgr->segs[core_id][seg_idx].size = sizeof(struct gxp_core_header);
+ seg_idx++;
+
+ data_addr = &core_dump->dump_data[core_id *
+ core_header->core_dump_size /
+ sizeof(u32)];
+
+ for (i = 0; i < GXP_NUM_CORE_SEGMENTS - 1; i++) {
+ if (seg_idx >= GXP_NUM_SEGMENTS_PER_CORE) {
+ ret = -EFAULT;
+ goto out_efault;
+ }
+ mgr->segs[core_id][seg_idx].addr = data_addr;
+ mgr->segs[core_id][seg_idx].size = 0;
+ if (core_dump_header->seg_header[i].valid) {
+ mgr->segs[core_id][seg_idx].size =
+ core_dump_header->seg_header[i].size;
+ }
+
+ data_addr += core_dump_header->seg_header[i].size;
+ seg_idx++;
+ }
+
+ /* DRAM */
+ if (seg_idx >= GXP_NUM_SEGMENTS_PER_CORE) {
+ ret = -EFAULT;
+ goto out_efault;
+ }
+ mgr->segs[core_id][seg_idx].addr = gxp->fwbufs[core_id].vaddr;
+ mgr->segs[core_id][seg_idx].size = gxp->fwbufs[core_id].size;
+ seg_idx++;
+
+ /* User Buffers */
user_buf_cnt = gxp_user_buffers_vmap(gxp, core_header, user_buf_vaddrs);
if (user_buf_cnt > 0) {
- gxp_add_user_buffer_to_segments(
- gxp, core_header, core_id,
- GXP_DEBUG_DUMP_DRAM_SEGMENT_IDX + 1, user_buf_vaddrs);
+ if (gxp_add_user_buffer_to_segments(gxp, core_header, core_id,
+ seg_idx, user_buf_vaddrs)) {
+ gxp_user_buffers_vunmap(gxp, core_header);
+ ret = -EFAULT;
+ goto out_efault;
+ }
}
- dev_dbg(gxp->dev, "Passing dram data to SSCD daemon\n");
- snprintf(sscd_msg, SSCD_MSG_LENGTH - 1,
- "gxp debug dump - dram data (core %0x)", core_id);
- gxp_send_to_sscd(gxp, sscd_seg, user_buf_cnt + 1, sscd_msg);
+out_efault:
+ if (ret) {
+ dev_err(gxp->dev,
+ "seg_idx %x is larger than the size of the array\n",
+ seg_idx);
+ } else {
+ dev_dbg(gxp->dev, "Passing dump data to SSCD daemon\n");
+ snprintf(sscd_msg, SSCD_MSG_LENGTH - 1,
+ "gxp debug dump (core %0x)", core_id);
+ gxp_send_to_sscd(gxp, mgr->segs[core_id],
+ seg_idx + user_buf_cnt, sscd_msg);
- gxp_user_buffers_vunmap(gxp, core_header);
+ gxp_user_buffers_vunmap(gxp, core_header);
+ }
#endif
- dram_seg_header->valid = 1;
+
+out:
+ gxp_invalidate_segments(gxp, core_id);
+
+ return ret;
}
-static bool gxp_is_segment_valid(struct gxp_dev *gxp, uint32_t core_id,
- int seg_idx)
+static int gxp_init_segments(struct gxp_dev *gxp)
{
- struct gxp_core_dump *core_dump;
- struct gxp_core_dump_header *core_dump_header;
- struct gxp_seg_header *seg_header;
+#if !IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+ return 0;
+#else
+ struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
- core_dump = gxp->debug_dump_mgr->core_dump;
- core_dump_header = &core_dump->core_dump_header[core_id];
- seg_header = &core_dump_header->seg_header[seg_idx];
+ mgr->common_dump = kzalloc(sizeof(*mgr->common_dump), GFP_KERNEL);
+ if (!mgr->common_dump)
+ return -ENOMEM;
- return seg_header->valid;
+ return 0;
+#endif
}
+/*
+ * Caller must have locked `gxp->debug_dump_mgr->debug_dump_lock` before calling
+ * `gxp_generate_coredump`.
+ */
static int gxp_generate_coredump(struct gxp_dev *gxp, uint32_t core_id)
{
- if (!gxp->debug_dump_mgr->core_dump) {
- dev_err(gxp->dev, "Core dump not allocated\n");
+ int ret = 0;
+
+ if (!gxp->debug_dump_mgr->core_dump ||
+ !gxp->debug_dump_mgr->common_dump) {
+ dev_err(gxp->dev, "Memory is not allocated for debug dump\n");
return -EINVAL;
}
gxp_debug_dump_cache_invalidate(gxp);
- mutex_lock(&gxp->debug_dump_mgr->debug_dump_lock);
-
- if (!gxp_is_segment_valid(gxp, core_id, GXP_CORE_DRAM_SEGMENT_IDX)) {
- gxp_handle_dram_dump(gxp, core_id);
- } else {
- gxp_get_common_dump(gxp);
- gxp_handle_debug_dump(gxp, core_id);
- }
+ ret = gxp_get_common_dump(gxp);
+ if (ret)
+ goto out;
- mutex_unlock(&gxp->debug_dump_mgr->debug_dump_lock);
+ ret = gxp_handle_debug_dump(gxp, core_id);
+ if (ret)
+ goto out;
+out:
gxp_debug_dump_cache_flush(gxp);
- return 0;
+ return ret;
}
-void gxp_debug_dump_process_dump(struct work_struct *work)
+static void gxp_debug_dump_process_dump(struct work_struct *work)
{
struct gxp_debug_dump_work *debug_dump_work =
container_of(work, struct gxp_debug_dump_work, work);
uint core_id = debug_dump_work->core_id;
struct gxp_dev *gxp = debug_dump_work->gxp;
+ u32 boot_mode;
+ bool gxp_generate_coredump_called = false;
+
+ mutex_lock(&gxp->debug_dump_mgr->debug_dump_lock);
+
+ /*
+ * Lock the VD semaphore to ensure no suspend/resume/start/stop requests
+ * can be made on core `core_id` while generating debug dump.
+ * However, since VD semaphore is used by other VDs as well, it can
+ * potentially block device creation and destruction for other cores.
+ * TODO (b/234172464): Implement per-core debug dump locks and
+ * lock/unlock vd_semaphore before/after accessing gxp->core_to_vd[].
+ */
+ down_read(&gxp->vd_semaphore);
+
+ boot_mode = gxp_firmware_get_boot_mode(gxp, core_id);
+
+ if (gxp_is_fw_running(gxp, core_id) &&
+ (boot_mode == GXP_BOOT_MODE_STATUS_COLD_BOOT_COMPLETED ||
+ boot_mode == GXP_BOOT_MODE_STATUS_RESUME_COMPLETED)) {
+ gxp_generate_coredump_called = true;
+ if (gxp_generate_coredump(gxp, core_id))
+ dev_err(gxp->dev, "Failed to generate coredump\n");
+ }
+
+ /* Invalidate segments to prepare for the next debug dump trigger */
+ gxp_invalidate_segments(gxp, core_id);
+
+ up_read(&gxp->vd_semaphore);
+
+ /*
+ * This delay is needed to ensure there's sufficient time
+ * in between sscd_report() being called, as the file name of
+ * the core dump files generated by the SSCD daemon includes a
+ * time format with a seconds precision.
+ */
+ if (gxp_generate_coredump_called)
+ msleep(1000);
- gxp_generate_coredump(gxp, core_id);
+ mutex_unlock(&gxp->debug_dump_mgr->debug_dump_lock);
}
struct work_struct *gxp_debug_dump_get_notification_handler(struct gxp_dev *gxp,
@@ -638,18 +714,27 @@ struct work_struct *gxp_debug_dump_get_notification_handler(struct gxp_dev *gxp,
{
struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
- if (!mgr)
+ if (!gxp_debug_dump_is_enabled())
return NULL;
+ if (!mgr->buf.vaddr) {
+ dev_err(gxp->dev,
+ "Debug dump must be initialized before %s is called\n",
+ __func__);
+ return NULL;
+ }
+
return &mgr->debug_dump_works[core].work;
}
int gxp_debug_dump_init(struct gxp_dev *gxp, void *sscd_dev, void *sscd_pdata)
{
- struct resource r;
struct gxp_debug_dump_manager *mgr;
- struct gxp_core_dump_header *core_dump_header;
- int core, i;
+ int core;
+
+ /* Don't initialize the debug dump subsystem unless it's enabled. */
+ if (!gxp_debug_dump_enable)
+ return 0;
mgr = devm_kzalloc(gxp->dev, sizeof(*mgr), GFP_KERNEL);
if (!mgr)
@@ -657,45 +742,27 @@ int gxp_debug_dump_init(struct gxp_dev *gxp, void *sscd_dev, void *sscd_pdata)
gxp->debug_dump_mgr = mgr;
mgr->gxp = gxp;
- /* Find and map the memory reserved for the debug dump */
- if (gxp_acquire_rmem_resource(gxp, &r, "gxp-debug-dump-region")) {
- dev_err(gxp->dev,
- "Unable to acquire debug dump reserved memory\n");
- return -ENODEV;
- }
- gxp->coredumpbuf.paddr = r.start;
- gxp->coredumpbuf.size = resource_size(&r);
- /*
- * TODO (b/193069216) allocate a dynamic buffer and let
- * `gxp_dma_map_resources()` map it to the expected paddr
- */
- /*
- * TODO (b/200169232) Using memremap until devm_memremap is added to
- * the GKI ABI
- */
- gxp->coredumpbuf.vaddr = memremap(gxp->coredumpbuf.paddr,
- gxp->coredumpbuf.size, MEMREMAP_WC);
- if (IS_ERR(gxp->coredumpbuf.vaddr)) {
- dev_err(gxp->dev, "Failed to map core dump\n");
+ mgr->buf.vaddr =
+ gxp_dma_alloc_coherent(gxp, NULL, 0, DEBUG_DUMP_MEMORY_SIZE,
+ &mgr->buf.daddr, GFP_KERNEL, 0);
+ if (!mgr->buf.vaddr) {
+ dev_err(gxp->dev, "Failed to allocate memory for debug dump\n");
return -ENODEV;
}
- mgr->core_dump = (struct gxp_core_dump *)gxp->coredumpbuf.vaddr;
+ mgr->buf.size = DEBUG_DUMP_MEMORY_SIZE;
+
+ mgr->core_dump = (struct gxp_core_dump *)mgr->buf.vaddr;
+
+ gxp_init_segments(gxp);
for (core = 0; core < GXP_NUM_CORES; core++) {
- core_dump_header = &mgr->core_dump->core_dump_header[core];
- core_dump_header->core_header.dump_available = 0;
- for (i = 0; i < GXP_NUM_CORE_SEGMENTS; i++)
- core_dump_header->seg_header[i].valid = 0;
- for (i = 0; i < GXP_NUM_BUFFER_MAPPINGS; i++)
- core_dump_header->core_header.user_bufs[i].size = 0;
+ gxp_invalidate_segments(gxp, core);
mgr->debug_dump_works[core].gxp = gxp;
mgr->debug_dump_works[core].core_id = core;
INIT_WORK(&mgr->debug_dump_works[core].work,
gxp_debug_dump_process_dump);
}
- gxp_init_segments(gxp);
-
/* No need for a DMA handle since the carveout is coherent */
mgr->debug_dump_dma_handle = 0;
mgr->sscd_dev = sscd_dev;
@@ -714,11 +781,16 @@ void gxp_debug_dump_exit(struct gxp_dev *gxp)
return;
}
- gxp_free_segments(gxp);
- /* TODO (b/200169232) Remove this once we're using devm_memremap */
- memunmap(gxp->coredumpbuf.vaddr);
+ kfree(gxp->debug_dump_mgr->common_dump);
+ gxp_dma_free_coherent(gxp, NULL, 0, DEBUG_DUMP_MEMORY_SIZE,
+ mgr->buf.vaddr, mgr->buf.daddr);
mutex_destroy(&mgr->debug_dump_lock);
devm_kfree(mgr->gxp->dev, mgr);
gxp->debug_dump_mgr = NULL;
}
+
+bool gxp_debug_dump_is_enabled(void)
+{
+ return gxp_debug_dump_enable;
+}
diff --git a/gxp-debug-dump.h b/gxp-debug-dump.h
index 9d80564..1b1fda0 100644
--- a/gxp-debug-dump.h
+++ b/gxp-debug-dump.h
@@ -19,12 +19,11 @@
#define GXP_NUM_COMMON_SEGMENTS 2
#define GXP_NUM_CORE_SEGMENTS 8
-#define GXP_CORE_DRAM_SEGMENT_IDX 7
#define GXP_NUM_BUFFER_MAPPINGS 32
-#define GXP_DEBUG_DUMP_CORE_SEGMENT_IDX_START (GXP_NUM_COMMON_SEGMENTS + 1)
-#define GXP_DEBUG_DUMP_DRAM_SEGMENT_IDX \
- (GXP_DEBUG_DUMP_CORE_SEGMENT_IDX_START + GXP_CORE_DRAM_SEGMENT_IDX)
#define GXP_SEG_HEADER_NAME_LENGTH 32
+#define GXP_NUM_SEGMENTS_PER_CORE \
+ (GXP_NUM_COMMON_SEGMENTS + GXP_NUM_CORE_SEGMENTS + \
+ GXP_NUM_BUFFER_MAPPINGS + 1)
#define GXP_Q7_ICACHE_SIZE 131072 /* I-cache size in bytes */
#define GXP_Q7_ICACHE_LINESIZE 64 /* I-cache line size in bytes */
@@ -173,8 +172,15 @@ struct gxp_debug_dump_work {
uint core_id;
};
+struct gxp_debug_dump_buffer {
+ void *vaddr;
+ dma_addr_t daddr;
+ u32 size;
+};
+
struct gxp_debug_dump_manager {
struct gxp_dev *gxp;
+ struct gxp_debug_dump_buffer buf;
struct gxp_debug_dump_work debug_dump_works[GXP_NUM_CORES];
struct gxp_core_dump *core_dump; /* start of the core dump */
struct gxp_common_dump *common_dump;
@@ -187,14 +193,14 @@ struct gxp_debug_dump_manager {
*/
struct mutex debug_dump_lock;
#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
- struct sscd_segment *segs[GXP_NUM_CORES];
+ struct sscd_segment segs[GXP_NUM_CORES][GXP_NUM_SEGMENTS_PER_CORE];
#endif
};
int gxp_debug_dump_init(struct gxp_dev *gxp, void *sscd_dev, void *sscd_pdata);
void gxp_debug_dump_exit(struct gxp_dev *gxp);
-void gxp_debug_dump_process_dump(struct work_struct *work);
struct work_struct *gxp_debug_dump_get_notification_handler(struct gxp_dev *gxp,
uint core);
+bool gxp_debug_dump_is_enabled(void);
#endif /* __GXP_DEBUG_DUMP_H__ */
diff --git a/gxp-debugfs.c b/gxp-debugfs.c
index 8853c3b..a04a3f2 100644
--- a/gxp-debugfs.c
+++ b/gxp-debugfs.c
@@ -280,6 +280,11 @@ static int gxp_debugfs_coredump(void *data, u64 val)
struct gxp_dev *gxp = (struct gxp_dev *)data;
int core;
+ if (!gxp_debug_dump_is_enabled()) {
+ dev_err(gxp->dev, "Debug dump functionality is disabled\n");
+ return -EINVAL;
+ }
+
down_read(&gxp->vd_semaphore);
for (core = 0; core < GXP_NUM_CORES; core++) {
diff --git a/gxp-dma-iommu.c b/gxp-dma-iommu.c
index 3e0fc6c..9f388c0 100644
--- a/gxp-dma-iommu.c
+++ b/gxp-dma-iommu.c
@@ -250,7 +250,6 @@ void gxp_dma_init_default_resources(struct gxp_dev *gxp)
gxp->fwbufs[core].daddr = GXP_IOVA_FIRMWARE(core);
}
gxp->regs.daddr = GXP_IOVA_AURORA_TOP;
- gxp->coredumpbuf.daddr = GXP_IOVA_CORE_DUMP;
gxp->fwdatabuf.daddr = GXP_IOVA_FW_DATA;
}
@@ -309,11 +308,6 @@ int gxp_dma_map_core_resources(struct gxp_dev *gxp,
IOMMU_READ | IOMMU_WRITE);
if (ret)
goto err;
- ret = iommu_map(vd->core_domains[virt_core], gxp->coredumpbuf.daddr,
- gxp->coredumpbuf.paddr, gxp->coredumpbuf.size,
- IOMMU_READ | IOMMU_WRITE);
- if (ret)
- goto err;
ret = iommu_map(vd->core_domains[virt_core], gxp->fwdatabuf.daddr,
gxp->fwdatabuf.paddr, gxp->fwdatabuf.size,
IOMMU_READ | IOMMU_WRITE);
@@ -355,8 +349,6 @@ void gxp_dma_unmap_core_resources(struct gxp_dev *gxp,
}
iommu_unmap(vd->core_domains[virt_core], gxp->fwdatabuf.daddr,
gxp->fwdatabuf.size);
- iommu_unmap(vd->core_domains[virt_core], gxp->coredumpbuf.daddr,
- gxp->coredumpbuf.size);
/*
* TODO(b/202213606): A core should only have access to the FW
* of other cores if they're in the same VD, and have the FW
diff --git a/gxp-firmware-data.c b/gxp-firmware-data.c
index ea00dd9..d93881e 100644
--- a/gxp-firmware-data.c
+++ b/gxp-firmware-data.c
@@ -9,6 +9,7 @@
#include <linux/dma-mapping.h>
#include <linux/genalloc.h>
+#include "gxp-debug-dump.h"
#include "gxp-firmware-data.h"
#include "gxp-host-device-structs.h"
#include "gxp-internal.h"
@@ -87,6 +88,7 @@ struct gxp_fw_data_manager {
struct fw_memory sys_desc_mem;
struct fw_memory wdog_mem;
struct fw_memory telemetry_mem;
+ struct fw_memory debug_dump_mem;
};
/* A container holding information for a single GXP application. */
@@ -284,6 +286,23 @@ static struct fw_memory init_telemetry(struct gxp_fw_data_manager *mgr)
return mem;
}
+static struct fw_memory init_debug_dump(struct gxp_dev *gxp)
+{
+ struct fw_memory mem;
+
+ if (gxp->debug_dump_mgr) {
+ mem.host_addr = gxp->debug_dump_mgr->buf.vaddr;
+ mem.device_addr = gxp->debug_dump_mgr->buf.daddr;
+ mem.sz = gxp->debug_dump_mgr->buf.size;
+ } else {
+ mem.host_addr = 0;
+ mem.device_addr = 0;
+ mem.sz = 0;
+ }
+
+ return mem;
+}
+
static struct fw_memory init_app_user_memory(struct app_metadata *app,
int memory_size)
{
@@ -572,6 +591,10 @@ int gxp_fw_data_init(struct gxp_dev *gxp)
mgr->telemetry_mem = init_telemetry(mgr);
mgr->system_desc->telemetry_dev_addr = mgr->telemetry_mem.device_addr;
+ /* Set the debug dump region parameters if available */
+ mgr->debug_dump_mem = init_debug_dump(gxp);
+ mgr->system_desc->debug_dump_dev_addr = mgr->debug_dump_mem.device_addr;
+
return res;
err:
diff --git a/gxp-firmware.c b/gxp-firmware.c
index 15497cf..4e207b9 100644
--- a/gxp-firmware.c
+++ b/gxp-firmware.c
@@ -12,6 +12,7 @@
#include <linux/gsa/gsa_image_auth.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -34,6 +35,9 @@
#define FW_HEADER_SIZE (0x1000)
#define FW_IMAGE_TYPE_OFFSET (0x400)
+static int gxp_dsp_fw_auth_disable;
+module_param_named(dsp_fw_auth_disable, gxp_dsp_fw_auth_disable, int, 0660);
+
static int
request_dsp_firmware(struct gxp_dev *gxp, char *name_prefix,
const struct firmware *out_firmwares[GXP_NUM_CORES])
@@ -115,7 +119,7 @@ static int elf_load_segments(struct gxp_dev *gxp, const u8 *elf_data,
if (!((da >= (u32)buffer->daddr) &&
((da + memsz) <= ((u32)buffer->daddr +
- (u32)buffer->size - 1)))) {
+ (u32)buffer->size)))) {
/*
* Some BSS data may be referenced from TCM, and can be
* skipped while loading
@@ -165,15 +169,6 @@ static int elf_load_segments(struct gxp_dev *gxp, const u8 *elf_data,
return ret;
}
-/* TODO (b/220246540): remove after unsigned firmware support is phased out */
-static bool gxp_firmware_image_is_signed(const u8 *data)
-{
- return data[FW_IMAGE_TYPE_OFFSET + 0] == 'D' &&
- data[FW_IMAGE_TYPE_OFFSET + 1] == 'S' &&
- data[FW_IMAGE_TYPE_OFFSET + 2] == 'P' &&
- data[FW_IMAGE_TYPE_OFFSET + 3] == 'F';
-}
-
static int
gxp_firmware_load_authenticated(struct gxp_dev *gxp, const struct firmware *fw,
const struct gxp_mapped_resource *buffer)
@@ -184,10 +179,11 @@ gxp_firmware_load_authenticated(struct gxp_dev *gxp, const struct firmware *fw,
dma_addr_t header_dma_addr;
int ret;
- /* TODO (b/220246540): remove after unsigned firmware support is phased out */
- if (!gxp_firmware_image_is_signed(data)) {
- dev_info(gxp->dev, "Loading unsigned firmware\n");
- return elf_load_segments(gxp, data, size, buffer);
+ if (gxp_dsp_fw_auth_disable) {
+ dev_warn(gxp->dev,
+ "DSP FW authentication disabled, skipping\n");
+ return elf_load_segments(gxp, data + FW_HEADER_SIZE,
+ size - FW_HEADER_SIZE, buffer);
}
if (!gxp->gsa_dev) {
@@ -272,6 +268,9 @@ static int gxp_firmware_load(struct gxp_dev *gxp, uint core)
void __iomem *core_scratchpad_base;
int ret;
+ if (!gxp->firmwares[core])
+ return -ENODEV;
+
/* Authenticate and load firmware to System RAM */
ret = gxp_firmware_load_authenticated(gxp, gxp->firmwares[core],
&gxp->fwbufs[core]);
diff --git a/gxp-firmware.h b/gxp-firmware.h
index 4834e87..835f8c9 100644
--- a/gxp-firmware.h
+++ b/gxp-firmware.h
@@ -13,8 +13,8 @@
#if !IS_ENABLED(CONFIG_GXP_TEST)
-#define AURORA_SCRATCHPAD_OFF 0x00F00000 /* Last 1M of ELF load region */
-#define AURORA_SCRATCHPAD_LEN 0x00100000 /* 1M */
+#define AURORA_SCRATCHPAD_OFF 0x000FF000 /* Last 4KB of ELF load region */
+#define AURORA_SCRATCHPAD_LEN 0x00001000 /* 4KB */
#else /* CONFIG_GXP_TEST */
/* Firmware memory is shrunk in unit tests. */
diff --git a/gxp-host-device-structs.h b/gxp-host-device-structs.h
index 57dc673..8e4723c 100644
--- a/gxp-host-device-structs.h
+++ b/gxp-host-device-structs.h
@@ -265,6 +265,8 @@ struct gxp_system_descriptor {
uint32_t watchdog_dev_addr;
/* A device address for the telemetry descriptor */
uint32_t telemetry_dev_addr;
+ /* A device address for the common debug dump region */
+ uint32_t debug_dump_dev_addr;
};
/* A structure describing the metadata belonging to a specific application. */
diff --git a/gxp-internal.h b/gxp-internal.h
index e456668..82e5303 100644
--- a/gxp-internal.h
+++ b/gxp-internal.h
@@ -63,7 +63,6 @@ struct gxp_dev {
struct gxp_mapped_resource mbx[GXP_NUM_CORES]; /* mailbox CSRs */
struct gxp_mapped_resource fwbufs[GXP_NUM_CORES]; /* FW carveout */
struct gxp_mapped_resource fwdatabuf; /* Shared FW data carveout */
- struct gxp_mapped_resource coredumpbuf; /* core dump carveout */
struct gxp_mapped_resource cmu; /* CMU CSRs */
struct gxp_mailbox_manager *mailbox_mgr;
struct gxp_power_manager *power_mgr;
diff --git a/gxp-iova.h b/gxp-iova.h
index e8a445f..8b7de59 100644
--- a/gxp-iova.h
+++ b/gxp-iova.h
@@ -11,9 +11,8 @@
#define GXP_IOVA_MAILBOX(_x_) (0x18390000 + (_x_) * 0x00020000)
#define GXP_IOVA_EXT_TPU_MBX (0x1CEC0000)
#define GXP_IOVA_AURORA_TOP (0x25C00000)
-#define GXP_IOVA_CORE_DUMP (0xF1C00000)
-#define GXP_IOVA_FIRMWARE(_x_) (0xFA000000 + (_x_) * 0x01000000)
-#define GXP_IOVA_FW_DATA (0xFE000000)
+#define GXP_IOVA_FIRMWARE(_x_) (0xFA000000 + (_x_) * 0x0100000)
+#define GXP_IOVA_FW_DATA (0xFA400000)
#define GXP_IOVA_TPU_MBX_BUFFER(_x_) (0xFE100000 + (_x_) * 0x00040000)
#endif /* __GXP_IOVAS_H__ */
diff --git a/gxp-platform.c b/gxp-platform.c
index 46fb5bb..dca51a7 100644
--- a/gxp-platform.c
+++ b/gxp-platform.c
@@ -132,8 +132,9 @@ static struct platform_device gxp_sscd_dev = {
#endif // CONFIG_SUBSYSTEM_COREDUMP
/* Mapping from GXP_POWER_STATE_* to enum aur_power_state in gxp-pm.h */
-static const uint aur_state_array[GXP_POWER_STATE_READY + 1] = {
- AUR_OFF, AUR_UUD, AUR_SUD, AUR_UD, AUR_NOM, AUR_READY
+static const uint aur_state_array[GXP_NUM_POWER_STATES] = {
+ AUR_OFF, AUR_UUD, AUR_SUD, AUR_UD, AUR_NOM,
+ AUR_READY, AUR_UUD_PLUS, AUR_SUD_PLUS, AUR_UD_PLUS
};
/* Mapping from MEMORY_POWER_STATE_* to enum aur_memory_power_state in gxp-pm.h */
static const uint aur_memory_state_array[MEMORY_POWER_STATE_MAX + 1] = {
@@ -487,7 +488,7 @@ static int gxp_mailbox_command(struct gxp_client *client,
return -EINVAL;
}
if (ibuf.gxp_power_state < GXP_POWER_STATE_OFF ||
- ibuf.gxp_power_state > GXP_POWER_STATE_READY) {
+ ibuf.gxp_power_state >= GXP_NUM_POWER_STATES) {
dev_err(gxp->dev, "Requested power state is invalid\n");
return -EINVAL;
}
@@ -1240,7 +1241,7 @@ static int gxp_acquire_wake_lock_compat(
return -EINVAL;
}
if (ibuf.gxp_power_state < GXP_POWER_STATE_OFF ||
- ibuf.gxp_power_state > GXP_POWER_STATE_READY) {
+ ibuf.gxp_power_state >= GXP_NUM_POWER_STATES) {
dev_err(gxp->dev, "Requested power state is invalid\n");
return -EINVAL;
}
@@ -1371,7 +1372,7 @@ static int gxp_acquire_wake_lock(struct gxp_client *client,
return -EINVAL;
}
if (ibuf.gxp_power_state < GXP_POWER_STATE_OFF ||
- ibuf.gxp_power_state > GXP_POWER_STATE_READY) {
+ ibuf.gxp_power_state >= GXP_NUM_POWER_STATES) {
dev_err(gxp->dev, "Requested power state is invalid\n");
return -EINVAL;
}
@@ -1775,6 +1776,11 @@ static int gxp_trigger_debug_dump(struct gxp_client *client,
if (!uid_eq(current_euid(), GLOBAL_ROOT_UID))
return -EPERM;
+ if (!gxp_debug_dump_is_enabled()) {
+ dev_err(gxp->dev, "Debug dump functionality is disabled\n");
+ return -EINVAL;
+ }
+
if (copy_from_user(&core_bits, argp, sizeof(core_bits)))
return -EFAULT;
@@ -2260,8 +2266,10 @@ static int __init gxp_platform_init(void)
{
#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
/* Registers SSCD platform device */
- if (platform_device_register(&gxp_sscd_dev))
- pr_err("Unable to register SSCD platform device\n");
+ if (gxp_debug_dump_is_enabled()) {
+ if (platform_device_register(&gxp_sscd_dev))
+ pr_err("Unable to register SSCD platform device\n");
+ }
#endif
return platform_driver_register(&gxp_platform_driver);
}
@@ -2270,7 +2278,8 @@ static void __exit gxp_platform_exit(void)
{
platform_driver_unregister(&gxp_platform_driver);
#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
- platform_device_unregister(&gxp_sscd_dev);
+ if (gxp_debug_dump_is_enabled())
+ platform_device_unregister(&gxp_sscd_dev);
#endif
}
diff --git a/gxp-pm.c b/gxp-pm.c
index 8b35939..2a7a4ab 100644
--- a/gxp-pm.c
+++ b/gxp-pm.c
@@ -23,9 +23,10 @@
* The order of this array decides the voting priority, should be increasing in
* frequencies.
*/
-static const enum aur_power_state aur_state_array[] = { AUR_OFF, AUR_READY,
- AUR_UUD, AUR_SUD,
- AUR_UD, AUR_NOM };
+static const enum aur_power_state aur_state_array[] = {
+ AUR_OFF, AUR_READY, AUR_UUD, AUR_UUD_PLUS, AUR_SUD,
+ AUR_SUD_PLUS, AUR_UD, AUR_UD_PLUS, AUR_NOM
+};
static const uint aur_memory_state_array[] = {
AUR_MEM_UNDEFINED, AUR_MEM_MIN, AUR_MEM_VERY_LOW, AUR_MEM_LOW,
AUR_MEM_HIGH, AUR_MEM_VERY_HIGH, AUR_MEM_MAX
@@ -724,10 +725,16 @@ void gxp_pm_set_thermal_limit(struct gxp_dev *gxp, unsigned long thermal_limit)
if (thermal_limit >= aur_power_state2rate[AUR_NOM]) {
dev_warn(gxp->dev, "Thermal limit on DVFS removed\n");
+ } else if (thermal_limit >= aur_power_state2rate[AUR_UD_PLUS]) {
+ dev_warn(gxp->dev, "Thermals limited to UD+\n");
} else if (thermal_limit >= aur_power_state2rate[AUR_UD]) {
dev_warn(gxp->dev, "Thermals limited to UD\n");
+ } else if (thermal_limit >= aur_power_state2rate[AUR_SUD_PLUS]) {
+ dev_warn(gxp->dev, "Thermals limited to SUD+\n");
} else if (thermal_limit >= aur_power_state2rate[AUR_SUD]) {
dev_warn(gxp->dev, "Thermal limited to SUD\n");
+ } else if (thermal_limit >= aur_power_state2rate[AUR_UUD_PLUS]) {
+ dev_warn(gxp->dev, "Thermals limited to UUD+\n");
} else if (thermal_limit >= aur_power_state2rate[AUR_UUD]) {
dev_warn(gxp->dev, "Thermal limited to UUD\n");
} else if (thermal_limit >= aur_power_state2rate[AUR_READY]) {
diff --git a/gxp-pm.h b/gxp-pm.h
index 28a455d..cd285c8 100644
--- a/gxp-pm.h
+++ b/gxp-pm.h
@@ -12,8 +12,17 @@
#include "gxp-internal.h"
#define AUR_DVFS_MIN_RATE 178000
-static const uint aur_power_state2rate[] = { 0, 178000, 373000,
- 750000, 1160000, 178000 };
+static const uint aur_power_state2rate[] = {
+ 0, /* AUR_OFF */
+ 178000, /* AUR_UUD */
+ 373000, /* AUR_SUD */
+ 750000, /* AUR_UD */
+ 1160000, /* AUR_NOM */
+ 178000, /* AUR_READY */
+ 268000, /* AUR_UUD_PLUS */
+ 560000, /* AUR_SUD_PLUS */
+ 975000, /* AUR_UD_PLUS */
+};
enum aur_power_state {
AUR_OFF = 0,
@@ -22,6 +31,9 @@ enum aur_power_state {
AUR_UD = 3,
AUR_NOM = 4,
AUR_READY = 5,
+ AUR_UUD_PLUS = 6,
+ AUR_SUD_PLUS = 7,
+ AUR_UD_PLUS = 8,
};
enum aur_memory_power_state {
@@ -49,7 +61,7 @@ enum aur_power_cmu_mux_state {
* aur_memory_power_state, not necessarily the state with the maximum power
* level.
*/
-#define AUR_MAX_ALLOW_STATE AUR_READY
+#define AUR_MAX_ALLOW_STATE AUR_UD_PLUS
#define AUR_MAX_ALLOW_MEMORY_STATE AUR_MEM_MAX
/*
diff --git a/gxp-vd.c b/gxp-vd.c
index ef83615..ad08207 100644
--- a/gxp-vd.c
+++ b/gxp-vd.c
@@ -8,6 +8,7 @@
#include <linux/bitops.h>
#include <linux/slab.h>
+#include "gxp-debug-dump.h"
#include "gxp-dma.h"
#include "gxp-domain-pool.h"
#include "gxp-firmware.h"
@@ -200,6 +201,31 @@ static void unmap_telemetry_buffers(struct gxp_dev *gxp,
->buffer_daddrs[core]);
}
+static void map_debug_dump_buffer(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint virt_core,
+ uint core)
+{
+ if (!gxp->debug_dump_mgr)
+ return;
+
+ gxp_dma_map_allocated_coherent_buffer(
+ gxp, gxp->debug_dump_mgr->buf.vaddr, vd, BIT(virt_core),
+ gxp->debug_dump_mgr->buf.size, gxp->debug_dump_mgr->buf.daddr,
+ 0);
+}
+
+static void unmap_debug_dump_buffer(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd,
+ uint virt_core, uint core)
+{
+ if (!gxp->debug_dump_mgr)
+ return;
+
+ gxp_dma_unmap_allocated_coherent_buffer(
+ gxp, vd, BIT(virt_core), gxp->debug_dump_mgr->buf.size,
+ gxp->debug_dump_mgr->buf.daddr);
+}
+
/* Caller must hold gxp->vd_semaphore for writing */
int gxp_vd_start(struct gxp_virtual_device *vd)
{
@@ -237,6 +263,7 @@ int gxp_vd_start(struct gxp_virtual_device *vd)
gxp_dma_domain_attach_device(gxp, vd, virt_core, core);
gxp_dma_map_core_resources(gxp, vd, virt_core, core);
map_telemetry_buffers(gxp, vd, virt_core, core);
+ map_debug_dump_buffer(gxp, vd, virt_core, core);
ret = gxp_firmware_run(gxp, vd, virt_core, core);
if (ret) {
dev_err(gxp->dev, "Failed to run firmware on core %u\n",
@@ -246,6 +273,8 @@ int gxp_vd_start(struct gxp_virtual_device *vd)
* had their firmware start successfully, so we
* need to clean up `core` here.
*/
+ unmap_debug_dump_buffer(gxp, vd, virt_core,
+ core);
unmap_telemetry_buffers(gxp, vd, virt_core,
core);
gxp_dma_unmap_core_resources(gxp, vd, virt_core,
@@ -306,6 +335,7 @@ void gxp_vd_stop(struct gxp_virtual_device *vd)
for (core = 0; core < GXP_NUM_CORES; core++) {
if (gxp->core_to_vd[core] == vd) {
gxp_firmware_stop(gxp, vd, virt_core, core);
+ unmap_debug_dump_buffer(gxp, vd, virt_core, core);
unmap_telemetry_buffers(gxp, vd, virt_core, core);
gxp_dma_unmap_core_resources(gxp, vd, virt_core, core);
if (vd->state == GXP_VD_RUNNING)
diff --git a/gxp.h b/gxp.h
index 847c414..0582236 100644
--- a/gxp.h
+++ b/gxp.h
@@ -12,7 +12,7 @@
/* Interface Version */
#define GXP_INTERFACE_VERSION_MAJOR 1
-#define GXP_INTERFACE_VERSION_MINOR 2
+#define GXP_INTERFACE_VERSION_MINOR 3
#define GXP_INTERFACE_VERSION_BUILD 0
/*
@@ -126,6 +126,10 @@ struct gxp_virtual_device_ioctl {
#define GXP_POWER_STATE_UD 3
#define GXP_POWER_STATE_NOM 4
#define GXP_POWER_STATE_READY 5
+#define GXP_POWER_STATE_UUD_PLUS 6
+#define GXP_POWER_STATE_SUD_PLUS 7
+#define GXP_POWER_STATE_UD_PLUS 8
+#define GXP_NUM_POWER_STATES (GXP_POWER_STATE_UD_PLUS + 1)
/*
* Memory interface power state values for use as `memory_power_state` in