diff options
author | Aurora pro automerger <aurora-pro-automerger@google.com> | 2022-06-14 13:50:26 -0700 |
---|---|---|
committer | John Scheible <johnscheible@google.com> | 2022-06-15 19:51:41 +0000 |
commit | 399265ce726dfc7e5b02352fbf17683a4ee15950 (patch) | |
tree | 701de08e23d0f3104a3c216a4912140d652f05c6 | |
parent | b16f2fa6d4a747b68c8eab8fefb4dd94537d5426 (diff) | |
download | gs201-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.c | 550 | ||||
-rw-r--r-- | gxp-debug-dump.h | 18 | ||||
-rw-r--r-- | gxp-debugfs.c | 5 | ||||
-rw-r--r-- | gxp-dma-iommu.c | 8 | ||||
-rw-r--r-- | gxp-firmware-data.c | 23 | ||||
-rw-r--r-- | gxp-firmware.c | 27 | ||||
-rw-r--r-- | gxp-firmware.h | 4 | ||||
-rw-r--r-- | gxp-host-device-structs.h | 2 | ||||
-rw-r--r-- | gxp-internal.h | 1 | ||||
-rw-r--r-- | gxp-iova.h | 5 | ||||
-rw-r--r-- | gxp-platform.c | 25 | ||||
-rw-r--r-- | gxp-pm.c | 13 | ||||
-rw-r--r-- | gxp-pm.h | 18 | ||||
-rw-r--r-- | gxp-vd.c | 30 | ||||
-rw-r--r-- | gxp.h | 6 |
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; @@ -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 } @@ -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]) { @@ -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 /* @@ -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) @@ -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 |