summaryrefslogtreecommitdiff
path: root/gxp-firmware.c
diff options
context:
space:
mode:
Diffstat (limited to 'gxp-firmware.c')
-rw-r--r--gxp-firmware.c432
1 files changed, 304 insertions, 128 deletions
diff --git a/gxp-firmware.c b/gxp-firmware.c
index eb31f23..fcf6a6f 100644
--- a/gxp-firmware.c
+++ b/gxp-firmware.c
@@ -17,6 +17,8 @@
#include <linux/types.h>
#include "gxp-bpm.h"
+#include "gxp-config.h"
+#include "gxp-core-telemetry.h"
#include "gxp-debug-dump.h"
#include "gxp-doorbell.h"
#include "gxp-firmware.h"
@@ -26,11 +28,11 @@
#include "gxp-mailbox.h"
#include "gxp-notification.h"
#include "gxp-pm.h"
-#include "gxp-telemetry.h"
#include "gxp-vd.h"
-/* Files need to be copied to /lib/firmware */
-#define DSP_FIRMWARE_DEFAULT_PREFIX "gxp_fw_core"
+#if IS_ENABLED(CONFIG_GXP_TEST)
+#include "unittests/factory/fake-gxp-firmware.h"
+#endif
#define FW_HEADER_SIZE (0x1000)
#define FW_IMAGE_TYPE_OFFSET (0x400)
@@ -38,6 +40,9 @@
static int gxp_dsp_fw_auth_disable;
module_param_named(dsp_fw_auth_disable, gxp_dsp_fw_auth_disable, int, 0660);
+static bool gxp_core_boot = true;
+module_param_named(core_boot, gxp_core_boot, bool, 0660);
+
static int
request_dsp_firmware(struct gxp_dev *gxp, char *name_prefix,
const struct firmware *out_firmwares[GXP_NUM_CORES])
@@ -92,59 +97,19 @@ static int elf_load_segments(struct gxp_dev *gxp, const u8 *elf_data,
ehdr = (struct elf32_hdr *)elf_data;
phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
- if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
- (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
- (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
- (ehdr->e_ident[EI_MAG3] != ELFMAG3)) {
- dev_err(gxp->dev, "Cannot load FW! Invalid ELF format.\n");
- return -EINVAL;
- }
-
/* go through the available ELF segments */
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
- u64 da = phdr->p_paddr;
- u32 memsz = phdr->p_memsz;
- u32 filesz = phdr->p_filesz;
- u32 offset = phdr->p_offset;
+ const u64 da = phdr->p_paddr;
+ const u32 memsz = phdr->p_memsz;
+ const u32 filesz = phdr->p_filesz;
void *ptr;
- if (phdr->p_type != PT_LOAD)
- continue;
-
- if (!phdr->p_flags)
- continue;
-
- if (!memsz)
+ if (phdr->p_type != PT_LOAD || !phdr->p_flags || !memsz)
continue;
- if (!((da >= (u32)buffer->daddr) &&
- ((da + memsz) <= ((u32)buffer->daddr +
- (u32)buffer->size)))) {
- /*
- * Some BSS data may be referenced from TCM, and can be
- * skipped while loading
- */
- dev_err(gxp->dev, "Segment out of bounds: da 0x%llx mem 0x%x. Skipping...\n",
- da, memsz);
+ if (!(da >= buffer->daddr &&
+ da + memsz <= buffer->daddr + buffer->size))
continue;
- }
-
- dev_notice(gxp->dev, "phdr: type %d da 0x%llx memsz 0x%x filesz 0x%x\n",
- phdr->p_type, da, memsz, filesz);
-
- if (filesz > memsz) {
- dev_err(gxp->dev, "Bad phdr filesz 0x%x memsz 0x%x\n",
- filesz, memsz);
- ret = -EINVAL;
- break;
- }
-
- if (offset + filesz > size) {
- dev_err(gxp->dev, "Truncated fw: need 0x%x avail 0x%zx\n",
- offset + filesz, size);
- ret = -EINVAL;
- break;
- }
/* grab the kernel address for this device address */
ptr = buffer->vaddr + (da - buffer->daddr);
@@ -169,6 +134,15 @@ static int elf_load_segments(struct gxp_dev *gxp, const u8 *elf_data,
return ret;
}
+static void elf_fetch_entry_point(struct gxp_dev *gxp, const u8 *elf_data,
+ uint core)
+{
+ struct elf32_hdr *ehdr;
+
+ ehdr = (struct elf32_hdr *)elf_data;
+ gxp->firmware_mgr->entry_points[core] = ehdr->e_entry;
+}
+
static int
gxp_firmware_authenticate(struct gxp_dev *gxp,
const struct firmware *firmwares[GXP_NUM_CORES])
@@ -258,6 +232,112 @@ error:
return ret;
}
+static int gxp_firmware_fetch_boundary(struct gxp_dev *gxp, const u8 *elf_data,
+ size_t size,
+ const struct gxp_mapped_resource *buffer,
+ dma_addr_t *boundary_ptr)
+{
+ struct elf32_hdr *ehdr = (struct elf32_hdr *)elf_data;
+ struct elf32_phdr *phdr = (struct elf32_phdr *)(elf_data + ehdr->e_phoff);
+ int i, ret = 0;
+ dma_addr_t boundary = 0;
+
+ if ((ehdr->e_ident[EI_MAG0] != ELFMAG0) ||
+ (ehdr->e_ident[EI_MAG1] != ELFMAG1) ||
+ (ehdr->e_ident[EI_MAG2] != ELFMAG2) ||
+ (ehdr->e_ident[EI_MAG3] != ELFMAG3)) {
+ dev_err(gxp->dev, "Invalid ELF format.");
+ return -EINVAL;
+ }
+
+ /* go through the available ELF segments */
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ const u64 da = phdr->p_paddr;
+ const u32 memsz = phdr->p_memsz;
+ const u32 filesz = phdr->p_filesz;
+ const u32 offset = phdr->p_offset;
+ const u32 p_flags = phdr->p_flags;
+
+ if (phdr->p_type != PT_LOAD || !p_flags || !memsz)
+ continue;
+
+ if (!(da >= buffer->daddr &&
+ da + memsz <= buffer->daddr + buffer->size)) {
+ /*
+ * Some BSS data may be referenced from TCM, and can be
+ * skipped while loading
+ */
+ dev_err(gxp->dev, "Segment out of bounds: da 0x%llx mem 0x%x. Skipping...",
+ da, memsz);
+ continue;
+ }
+
+ dev_info(gxp->dev,
+ "phdr: da %#llx memsz %#x filesz %#x perm %d", da,
+ memsz, filesz, p_flags);
+
+ if (filesz > memsz) {
+ dev_err(gxp->dev, "Bad phdr filesz %#x memsz %#x",
+ filesz, memsz);
+ ret = -EINVAL;
+ break;
+ }
+
+ if (offset + filesz > size) {
+ dev_err(gxp->dev, "Truncated fw: need %#x avail %#zx",
+ offset + filesz, size);
+ ret = -EINVAL;
+ break;
+ }
+ if (p_flags & PF_W) {
+ if (!boundary)
+ boundary = da;
+ } else if (boundary) {
+ dev_err(gxp->dev,
+ "Found RO region after a writable segment");
+ ret = -EINVAL;
+ break;
+ }
+ }
+ /* no boundary has been found - assume the whole image is RO */
+ if (!boundary)
+ boundary = buffer->daddr + buffer->size;
+ if (!ret)
+ *boundary_ptr = boundary;
+
+ return ret;
+}
+
+/*
+ * Sets @rw_boundaries by analyzing LOAD segments in ELF headers.
+ *
+ * Assumes the LOAD segments are arranged with RO first then RW. Returns -EINVAL
+ * if this is not true.
+ */
+static int gxp_firmware_fetch_boundaries(struct gxp_dev *gxp,
+ struct gxp_firmware_manager *mgr)
+{
+ int core, ret;
+
+ for (core = 0; core < GXP_NUM_CORES; core++) {
+ ret = gxp_firmware_fetch_boundary(
+ gxp, mgr->firmwares[core]->data + FW_HEADER_SIZE,
+ mgr->firmwares[core]->size - FW_HEADER_SIZE,
+ &gxp->fwbufs[core], &mgr->rw_boundaries[core]);
+ if (ret) {
+ dev_err(gxp->dev,
+ "failed to fetch boundary of core %d: %d", core,
+ ret);
+ goto error;
+ }
+ }
+ return 0;
+
+error:
+ memset(mgr->rw_boundaries, 0, sizeof(mgr->rw_boundaries));
+ return ret;
+}
+
/* Forward declaration for usage inside gxp_firmware_load(..). */
static void gxp_firmware_unload(struct gxp_dev *gxp, uint core);
@@ -265,39 +345,43 @@ static void gxp_program_reset_vector(struct gxp_dev *gxp, uint core, bool verbos
{
u32 reset_vec;
- reset_vec = gxp_read_32_core(gxp, core,
- GXP_REG_ALT_RESET_VECTOR);
+ reset_vec = gxp_read_32(gxp, GXP_CORE_REG_ALT_RESET_VECTOR(core));
if (verbose)
dev_notice(gxp->dev,
"Current Aurora reset vector for core %u: 0x%x\n",
core, reset_vec);
- gxp_write_32_core(gxp, core, GXP_REG_ALT_RESET_VECTOR,
- gxp->fwbufs[core].daddr);
+ gxp_write_32(gxp, GXP_CORE_REG_ALT_RESET_VECTOR(core),
+ gxp->firmware_mgr->entry_points[core]);
if (verbose)
dev_notice(gxp->dev,
- "New Aurora reset vector for core %u: 0x%llx\n",
- core, gxp->fwbufs[core].daddr);
+ "New Aurora reset vector for core %u: 0x%x\n",
+ core, gxp->firmware_mgr->entry_points[core]);
}
static int gxp_firmware_load(struct gxp_dev *gxp, uint core)
{
+ struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
u32 offset;
void __iomem *core_scratchpad_base;
int ret;
- if (!gxp->firmwares[core])
+ if (!mgr->firmwares[core])
return -ENODEV;
/* Load firmware to System RAM */
ret = elf_load_segments(gxp,
- gxp->firmwares[core]->data + FW_HEADER_SIZE,
- gxp->firmwares[core]->size - FW_HEADER_SIZE,
+ mgr->firmwares[core]->data + FW_HEADER_SIZE,
+ mgr->firmwares[core]->size - FW_HEADER_SIZE,
&gxp->fwbufs[core]);
if (ret) {
dev_err(gxp->dev, "Unable to load elf file\n");
goto out_firmware_unload;
}
+ elf_fetch_entry_point(gxp,
+ mgr->firmwares[core]->data + FW_HEADER_SIZE,
+ core);
+
memset(gxp->fwbufs[core].vaddr + AURORA_SCRATCHPAD_OFF, 0,
AURORA_SCRATCHPAD_LEN);
@@ -326,7 +410,7 @@ out_firmware_unload:
static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
{
u32 offset;
- u32 expected_top_value;
+ u32 __maybe_unused expected_top_value;
void __iomem *core_scratchpad_base;
int ctr;
@@ -334,7 +418,7 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
dev_notice(gxp->dev, "Waiting for core %u to power up...\n", core);
ctr = 1000;
while (ctr) {
- if (gxp_lpm_is_powered(gxp, core))
+ if (gxp_lpm_is_powered(gxp, CORE_TO_PSM(core)))
break;
udelay(1 * GXP_TIME_DELAY_FACTOR);
ctr--;
@@ -359,6 +443,15 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
*/
ctr = 5000;
offset = SCRATCHPAD_MSG_OFFSET(MSG_CORE_ALIVE);
+#if IS_ENABLED(CONFIG_GXP_TEST)
+ fake_gxp_firmware_flush_work_all();
+ /*
+ * As the fake firmware works are flushed, we don't have to busy-wait the response of
+ * the firmware. By setting @ctr to 1, just run the while loop below once for the code
+ * coverage.
+ */
+ ctr = 1;
+#endif
usleep_range(50 * GXP_TIME_DELAY_FACTOR, 60 * GXP_TIME_DELAY_FACTOR);
while (ctr--) {
if (readl(core_scratchpad_base + offset) == Q7_ALIVE_MAGIC)
@@ -437,15 +530,16 @@ static ssize_t load_dsp_firmware_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct gxp_dev *gxp = dev_get_drvdata(dev);
+ struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
ssize_t ret;
- mutex_lock(&gxp->dsp_firmware_lock);
+ mutex_lock(&mgr->dsp_firmware_lock);
ret = scnprintf(buf, PAGE_SIZE, "%s\n",
- gxp->firmware_name ? gxp->firmware_name :
+ mgr->firmware_name ? mgr->firmware_name :
DSP_FIRMWARE_DEFAULT_PREFIX);
- mutex_unlock(&gxp->dsp_firmware_lock);
+ mutex_unlock(&mgr->dsp_firmware_lock);
return ret;
}
@@ -455,6 +549,7 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
const char *buf, size_t count)
{
struct gxp_dev *gxp = dev_get_drvdata(dev);
+ struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
const struct firmware *firmwares[GXP_NUM_CORES];
char *name_buf = NULL;
int ret;
@@ -466,10 +561,10 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
*/
down_read(&gxp->vd_semaphore);
- if (gxp->firmware_running) {
+ if (mgr->firmware_running) {
dev_warn(dev, "Cannot update firmware when any core is running\n");
ret = -EBUSY;
- goto out;
+ goto err_out;
}
name_buf = fw_name_from_attr_buf(buf);
@@ -477,10 +572,10 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
dev_err(gxp->dev, "Invalid firmware prefix requested: %s\n",
buf);
ret = PTR_ERR(name_buf);
- goto out;
+ goto err_out;
}
- mutex_lock(&gxp->dsp_firmware_lock);
+ mutex_lock(&mgr->dsp_firmware_lock);
dev_notice(gxp->dev, "Requesting firmware be reloaded: %s\n", name_buf);
@@ -497,25 +592,32 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
goto err_authenticate_firmware;
for (core = 0; core < GXP_NUM_CORES; core++) {
- if (gxp->firmwares[core])
- release_firmware(gxp->firmwares[core]);
- gxp->firmwares[core] = firmwares[core];
+ if (mgr->firmwares[core])
+ release_firmware(mgr->firmwares[core]);
+ mgr->firmwares[core] = firmwares[core];
}
- kfree(gxp->firmware_name);
- gxp->firmware_name = name_buf;
+ ret = gxp_firmware_fetch_boundaries(gxp, mgr);
+ if (ret)
+ goto err_fetch_boundaries;
- mutex_unlock(&gxp->dsp_firmware_lock);
-out:
+ kfree(mgr->firmware_name);
+ mgr->firmware_name = name_buf;
+
+ mutex_unlock(&mgr->dsp_firmware_lock);
up_read(&gxp->vd_semaphore);
return count;
+err_fetch_boundaries:
+ for (core = 0; core < GXP_NUM_CORES; core++)
+ mgr->firmwares[core] = NULL;
err_authenticate_firmware:
for (core = 0; core < GXP_NUM_CORES; core++)
release_firmware(firmwares[core]);
err_request_firmware:
kfree(name_buf);
- mutex_unlock(&gxp->dsp_firmware_lock);
+ mutex_unlock(&mgr->dsp_firmware_lock);
+err_out:
up_read(&gxp->vd_semaphore);
return ret;
}
@@ -537,6 +639,13 @@ int gxp_fw_init(struct gxp_dev *gxp)
uint core;
struct resource r;
int ret;
+ struct gxp_firmware_manager *mgr;
+
+ mgr = devm_kzalloc(gxp->dev, sizeof(*mgr), GFP_KERNEL);
+ if (!mgr)
+ return -ENOMEM;
+ gxp->firmware_mgr = mgr;
+ mutex_init(&mgr->dsp_firmware_lock);
/* Power on BLK_AUR to read the revision and processor ID registers */
gxp_pm_blk_on(gxp);
@@ -545,7 +654,7 @@ int gxp_fw_init(struct gxp_dev *gxp)
dev_notice(gxp->dev, "Aurora version: 0x%x\n", ver);
for (core = 0; core < GXP_NUM_CORES; core++) {
- proc_id = gxp_read_32_core(gxp, core, GXP_REG_PROCESSOR_ID);
+ proc_id = gxp_read_32(gxp, GXP_CORE_REG_PROCESSOR_ID(core));
dev_notice(gxp->dev, "Aurora core %u processor ID: 0x%x\n",
core, proc_id);
}
@@ -609,7 +718,7 @@ int gxp_fw_init(struct gxp_dev *gxp)
if (ret)
goto out_fw_destroy;
- gxp->firmware_running = 0;
+ mgr->firmware_running = 0;
return 0;
out_fw_destroy:
@@ -620,6 +729,10 @@ out_fw_destroy:
void gxp_fw_destroy(struct gxp_dev *gxp)
{
uint core;
+ struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
+
+ if (IS_GXP_TEST && !mgr)
+ return;
device_remove_group(gxp->dev, &gxp_firmware_attr_group);
@@ -629,54 +742,83 @@ void gxp_fw_destroy(struct gxp_dev *gxp)
gxp->fwbufs[core].vaddr = NULL;
}
- if (gxp->firmwares[core]) {
- release_firmware(gxp->firmwares[core]);
- gxp->firmwares[core] = NULL;
+ if (mgr->firmwares[core]) {
+ release_firmware(mgr->firmwares[core]);
+ mgr->firmwares[core] = NULL;
}
}
- kfree(gxp->firmware_name);
+ kfree(mgr->firmware_name);
}
int gxp_firmware_request_if_needed(struct gxp_dev *gxp)
{
int ret = 0;
uint core;
+ struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
+ char *name = NULL;
- mutex_lock(&gxp->dsp_firmware_lock);
+ mutex_lock(&mgr->dsp_firmware_lock);
- if (gxp->is_firmware_requested)
+ if (mgr->is_firmware_requested)
goto out;
- ret = request_dsp_firmware(gxp, DSP_FIRMWARE_DEFAULT_PREFIX,
- gxp->firmwares);
+ if (mgr->firmware_name == NULL)
+ name = DSP_FIRMWARE_DEFAULT_PREFIX;
+ else
+ name = mgr->firmware_name;
+
+ ret = request_dsp_firmware(gxp, name, mgr->firmwares);
if (ret)
goto out;
- ret = gxp_firmware_authenticate(gxp, gxp->firmwares);
+ ret = gxp_firmware_authenticate(gxp, mgr->firmwares);
if (ret)
goto err_authenticate_firmware;
- gxp->is_firmware_requested = true;
+ ret = gxp_firmware_fetch_boundaries(gxp, mgr);
+ if (ret)
+ goto err_authenticate_firmware;
+
+ mgr->is_firmware_requested = true;
out:
- mutex_unlock(&gxp->dsp_firmware_lock);
+ mutex_unlock(&mgr->dsp_firmware_lock);
return ret;
err_authenticate_firmware:
for (core = 0; core < GXP_NUM_CORES; core++) {
- release_firmware(gxp->firmwares[core]);
- gxp->firmwares[core] = NULL;
+ release_firmware(mgr->firmwares[core]);
+ mgr->firmwares[core] = NULL;
}
- mutex_unlock(&gxp->dsp_firmware_lock);
+ mutex_unlock(&mgr->dsp_firmware_lock);
return ret;
}
+/* TODO(b/253464747): Refactor these interrupts handlers and gxp-doorbell.c. */
+static void enable_core_interrupts(struct gxp_dev *gxp, uint core)
+{
+ /*
+ * GXP_CORE_REG_COMMON_INT_MASK_0 is handled in doorbell module, so we
+ * don't need to enable it here.
+ */
+ gxp_write_32(gxp, GXP_CORE_REG_COMMON_INT_MASK_1(core), 0xffffffff);
+ gxp_write_32(gxp, GXP_CORE_REG_DEDICATED_INT_MASK(core), 0xffffffff);
+}
+
+static void disable_core_interrupts(struct gxp_dev *gxp, uint core)
+{
+ gxp_write_32(gxp, GXP_CORE_REG_COMMON_INT_MASK_0(core), 0);
+ gxp_write_32(gxp, GXP_CORE_REG_COMMON_INT_MASK_1(core), 0);
+ gxp_write_32(gxp, GXP_CORE_REG_DEDICATED_INT_MASK(core), 0);
+}
+
static int gxp_firmware_setup(struct gxp_dev *gxp, uint core)
{
int ret = 0;
+ struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
- if (gxp->firmware_running & BIT(core)) {
+ if (mgr->firmware_running & BIT(core)) {
dev_err(gxp->dev, "Firmware is already running on core %u\n",
core);
return -EBUSY;
@@ -689,15 +831,19 @@ static int gxp_firmware_setup(struct gxp_dev *gxp, uint core)
}
/* Mark this as a cold boot */
- gxp_firmware_set_boot_mode(gxp, core, GXP_BOOT_MODE_REQUEST_COLD_BOOT);
+ if (gxp_core_boot)
+ gxp_firmware_set_boot_mode(gxp, core,
+ GXP_BOOT_MODE_REQUEST_COLD_BOOT);
ret = gxp_firmware_setup_hw_after_block_off(gxp, core,
/*verbose=*/true);
if (ret) {
dev_err(gxp->dev, "Failed to power up core %u\n", core);
gxp_firmware_unload(gxp, core);
+ return ret;
}
+ enable_core_interrupts(gxp, core);
return ret;
}
@@ -721,27 +867,35 @@ static int gxp_firmware_finish_startup(struct gxp_dev *gxp,
struct gxp_virtual_device *vd,
uint virt_core, uint core)
{
- int ret;
struct work_struct *work;
+ struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
+ int ret = 0;
- ret = gxp_firmware_handshake(gxp, core);
- if (ret) {
- dev_err(gxp->dev, "Firmware handshake failed on core %u\n",
- core);
- gxp_pm_core_off(gxp, core);
- goto out_firmware_unload;
- }
+ if (gxp_core_boot) {
+ ret = gxp_firmware_handshake(gxp, core);
+ if (ret) {
+ dev_err(gxp->dev,
+ "Firmware handshake failed on core %u\n", core);
+ goto err_firmware_off;
+ }
- /* Initialize mailbox */
- gxp->mailbox_mgr->mailboxes[core] =
- gxp_mailbox_alloc(gxp->mailbox_mgr, vd, virt_core, core);
- if (IS_ERR(gxp->mailbox_mgr->mailboxes[core])) {
- dev_err(gxp->dev,
- "Unable to allocate mailbox (core=%u, ret=%ld)\n", core,
- PTR_ERR(gxp->mailbox_mgr->mailboxes[core]));
- ret = PTR_ERR(gxp->mailbox_mgr->mailboxes[core]);
- gxp->mailbox_mgr->mailboxes[core] = NULL;
- goto out_firmware_unload;
+ /* Initialize mailbox */
+ if (gxp->mailbox_mgr->allocate_mailbox) {
+ gxp->mailbox_mgr->mailboxes[core] =
+ gxp->mailbox_mgr->allocate_mailbox(
+ gxp->mailbox_mgr, vd, virt_core, core);
+ if (IS_ERR(gxp->mailbox_mgr->mailboxes[core])) {
+ dev_err(gxp->dev,
+ "Unable to allocate mailbox (core=%u, ret=%ld)\n",
+ core,
+ PTR_ERR(gxp->mailbox_mgr
+ ->mailboxes[core]));
+ ret = PTR_ERR(
+ gxp->mailbox_mgr->mailboxes[core]);
+ gxp->mailbox_mgr->mailboxes[core] = NULL;
+ goto err_firmware_off;
+ }
+ }
}
work = gxp_debug_dump_get_notification_handler(gxp, core);
@@ -749,16 +903,18 @@ static int gxp_firmware_finish_startup(struct gxp_dev *gxp,
gxp_notification_register_handler(
gxp, core, HOST_NOTIF_DEBUG_DUMP_READY, work);
- work = gxp_telemetry_get_notification_handler(gxp, core);
+ work = gxp_core_telemetry_get_notification_handler(gxp, core);
if (work)
gxp_notification_register_handler(
- gxp, core, HOST_NOTIF_TELEMETRY_STATUS, work);
+ gxp, core, HOST_NOTIF_CORE_TELEMETRY_STATUS, work);
- gxp->firmware_running |= BIT(core);
+ mgr->firmware_running |= BIT(core);
return ret;
-out_firmware_unload:
+err_firmware_off:
+ if (gxp_core_boot)
+ gxp_pm_core_off(gxp, core);
gxp_firmware_unload(gxp, core);
return ret;
}
@@ -767,22 +923,36 @@ static void gxp_firmware_stop_core(struct gxp_dev *gxp,
struct gxp_virtual_device *vd,
uint virt_core, uint core)
{
- if (!(gxp->firmware_running & BIT(core)))
+ struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
+
+ if (!(mgr->firmware_running & BIT(core)))
dev_err(gxp->dev, "Firmware is not running on core %u\n", core);
- gxp->firmware_running &= ~BIT(core);
+ mgr->firmware_running &= ~BIT(core);
gxp_notification_unregister_handler(gxp, core,
HOST_NOTIF_DEBUG_DUMP_READY);
gxp_notification_unregister_handler(gxp, core,
- HOST_NOTIF_TELEMETRY_STATUS);
+ HOST_NOTIF_CORE_TELEMETRY_STATUS);
+
+ if (gxp_core_boot) {
+ if (gxp->mailbox_mgr->release_mailbox) {
+ gxp->mailbox_mgr->release_mailbox(
+ gxp->mailbox_mgr, vd, virt_core,
+ gxp->mailbox_mgr->mailboxes[core]);
+ dev_notice(gxp->dev, "Mailbox %u released\n", core);
+ }
- gxp_mailbox_release(gxp->mailbox_mgr, vd, virt_core,
- gxp->mailbox_mgr->mailboxes[core]);
- dev_notice(gxp->dev, "Mailbox %u released\n", core);
+ if (vd->state == GXP_VD_RUNNING) {
+ /*
+ * Disable interrupts to prevent cores from being woken up
+ * unexpectedly.
+ */
+ disable_core_interrupts(gxp, core);
+ gxp_pm_core_off(gxp, core);
+ }
+ }
- if (vd->state == GXP_VD_RUNNING)
- gxp_pm_core_off(gxp, core);
gxp_firmware_unload(gxp, core);
}
@@ -813,7 +983,8 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
for (core = 0; core < GXP_NUM_CORES; core++) {
if (core_list & BIT(core)) {
if (!(failed_cores & BIT(core))) {
- gxp_pm_core_off(gxp, core);
+ if (gxp_core_boot)
+ gxp_pm_core_off(gxp, core);
gxp_firmware_unload(gxp, core);
}
}
@@ -834,8 +1005,11 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
}
#endif
/* Switch clock mux to the normal state to guarantee LPM works */
- gxp_pm_force_clkmux_normal(gxp);
- gxp_firmware_wakeup_cores(gxp, core_list);
+ if (gxp_core_boot) {
+ gxp_pm_force_clkmux_normal(gxp);
+ gxp_firmware_wakeup_cores(gxp, core_list);
+ }
+
virt_core = 0;
for (core = 0; core < GXP_NUM_CORES; core++) {
if (core_list & BIT(core)) {
@@ -864,7 +1038,8 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
}
}
/* Check if we need to set clock mux to low state as requested */
- gxp_pm_resume_clkmux(gxp);
+ if (gxp_core_boot)
+ gxp_pm_resume_clkmux(gxp);
return ret;
}
@@ -873,7 +1048,8 @@ int gxp_firmware_setup_hw_after_block_off(struct gxp_dev *gxp, uint core,
bool verbose)
{
gxp_program_reset_vector(gxp, core, verbose);
- return gxp_pm_core_on(gxp, core, verbose);
+
+ return gxp_core_boot ? gxp_pm_core_on(gxp, core, verbose) : 0;
}