summaryrefslogtreecommitdiff
path: root/gxp-firmware.c
diff options
context:
space:
mode:
Diffstat (limited to 'gxp-firmware.c')
-rw-r--r--gxp-firmware.c590
1 files changed, 322 insertions, 268 deletions
diff --git a/gxp-firmware.c b/gxp-firmware.c
index fcf6a6f..32d5dc3 100644
--- a/gxp-firmware.c
+++ b/gxp-firmware.c
@@ -16,11 +16,16 @@
#include <linux/slab.h>
#include <linux/types.h>
+#include <gcip/gcip-alloc-helper.h>
+#include <gcip/gcip-common-image-header.h>
+#include <gcip/gcip-image-config.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-data.h"
#include "gxp-firmware.h"
#include "gxp-host-device-structs.h"
#include "gxp-internal.h"
@@ -34,15 +39,47 @@
#include "unittests/factory/fake-gxp-firmware.h"
#endif
-#define FW_HEADER_SIZE (0x1000)
-#define FW_IMAGE_TYPE_OFFSET (0x400)
+#define FW_HEADER_SIZE GCIP_FW_HEADER_SIZE
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;
+bool gxp_core_boot = true;
module_param_named(core_boot, gxp_core_boot, bool, 0660);
+/*
+ * Fetches and records image config of the first firmware.
+ */
+static void gxp_firmware_get_image_config(struct gxp_dev *gxp,
+ struct gxp_firmware_manager *mgr)
+{
+ struct gcip_common_image_header *hdr =
+ (struct gcip_common_image_header *)mgr->firmwares[0]->data;
+ struct gcip_image_config *cfg;
+
+ if (unlikely(mgr->firmwares[0]->size < FW_HEADER_SIZE))
+ return;
+ cfg = get_image_config_from_hdr(hdr);
+ if (cfg)
+ mgr->img_cfg = *cfg;
+ else
+ dev_warn(gxp->dev,
+ "Firmware doesn't have a valid image config");
+}
+
+/*
+ * Call this function when mgr->firmwares have been populated.
+ * This function sets is_firmware_requested to true.
+ *
+ * Caller holds mgr->dsp_firmware_lock.
+ */
+static void gxp_firmware_has_requested(struct gxp_dev *gxp,
+ struct gxp_firmware_manager *mgr)
+{
+ gxp_firmware_get_image_config(gxp, mgr);
+ mgr->is_firmware_requested = true;
+}
+
static int
request_dsp_firmware(struct gxp_dev *gxp, char *name_prefix,
const struct firmware *out_firmwares[GXP_NUM_CORES])
@@ -97,25 +134,67 @@ 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, "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;
void *ptr;
- if (phdr->p_type != PT_LOAD || !phdr->p_flags || !memsz)
+ if (phdr->p_type != PT_LOAD)
+ continue;
+
+ if (!phdr->p_flags)
+ continue;
+
+ if (!memsz)
continue;
if (!(da >= buffer->daddr &&
- da + memsz <= buffer->daddr + buffer->size))
+ 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 %#llx mem %#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;
+ }
/* grab the kernel address for this device address */
ptr = buffer->vaddr + (da - buffer->daddr);
if (!ptr) {
- dev_err(gxp->dev, "Bad phdr: da 0x%llx mem 0x%x\n",
- da, memsz);
+ dev_err(gxp->dev, "Bad phdr: da %#llx mem %#x", da,
+ memsz);
ret = -EINVAL;
break;
}
@@ -232,137 +311,91 @@ 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);
-static void gxp_program_reset_vector(struct gxp_dev *gxp, uint core, bool verbose)
+static void gxp_program_reset_vector(struct gxp_dev *gxp, uint core,
+ uint phys_core, bool verbose)
{
u32 reset_vec;
- reset_vec = gxp_read_32(gxp, GXP_CORE_REG_ALT_RESET_VECTOR(core));
+ reset_vec = gxp_read_32(gxp, GXP_CORE_REG_ALT_RESET_VECTOR(phys_core));
if (verbose)
dev_notice(gxp->dev,
"Current Aurora reset vector for core %u: 0x%x\n",
- core, reset_vec);
- gxp_write_32(gxp, GXP_CORE_REG_ALT_RESET_VECTOR(core),
+ phys_core, reset_vec);
+ gxp_write_32(gxp, GXP_CORE_REG_ALT_RESET_VECTOR(phys_core),
gxp->firmware_mgr->entry_points[core]);
if (verbose)
dev_notice(gxp->dev,
"New Aurora reset vector for core %u: 0x%x\n",
- core, gxp->firmware_mgr->entry_points[core]);
+ phys_core, gxp->firmware_mgr->entry_points[core]);
}
-static int gxp_firmware_load(struct gxp_dev *gxp, uint core)
+static void *get_scratchpad_base(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core)
+{
+ void *mem;
+ size_t rw_size;
+
+ if (vd && gxp_fw_data_use_per_vd_config(vd))
+ return vd->core_cfg.vaddr +
+ (vd->core_cfg.size / GXP_NUM_CORES) * core;
+
+ if (!vd || !vd->rwdata_sgt[core])
+ return gxp->fwbufs[core].vaddr + AURORA_SCRATCHPAD_OFF;
+
+ /* Return the last AURORA_SCRATCHPAD_LEN of rwdata_sgt. */
+ mem = gcip_noncontiguous_sgt_to_mem(vd->rwdata_sgt[core]);
+ rw_size = gxp->fwbufs[core].size - vd->fw_ro_size;
+ return mem + rw_size - AURORA_SCRATCHPAD_LEN;
+}
+
+/* TODO(b/265562894): remove scratchpad region support */
+static void flush_scratchpad_region(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core)
+{
+ if (!vd || gxp_fw_data_use_per_vd_config(vd) || !vd->rwdata_sgt[core])
+ return;
+ dma_sync_sg_for_device(gxp->dev, vd->rwdata_sgt[core]->sgl,
+ vd->rwdata_sgt[core]->orig_nents,
+ DMA_BIDIRECTIONAL);
+}
+
+static void invalidate_scratchpad_region(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd,
+ uint core)
+{
+ if (!vd || gxp_fw_data_use_per_vd_config(vd) || !vd->rwdata_sgt[core])
+ return;
+ dma_sync_sg_for_cpu(gxp->dev, vd->rwdata_sgt[core]->sgl,
+ vd->rwdata_sgt[core]->orig_nents,
+ DMA_BIDIRECTIONAL);
+}
+
+static void reset_core_config_region(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core)
+{
+ struct gxp_host_control_region *core_cfg;
+
+ core_cfg = get_scratchpad_base(gxp, vd, core);
+ if (gxp_fw_data_use_per_vd_config(vd)) {
+ core_cfg->core_alive_magic = 0;
+ core_cfg->top_access_ok = 0;
+ core_cfg->boot_status = GXP_BOOT_STATUS_NONE;
+ gxp_firmware_set_boot_mode(gxp, vd, core,
+ GXP_BOOT_MODE_COLD_BOOT);
+ } else {
+ memset(core_cfg, 0, AURORA_SCRATCHPAD_LEN);
+ gxp_firmware_set_boot_mode(gxp, vd, core,
+ GXP_BOOT_MODE_REQUEST_COLD_BOOT);
+ }
+}
+
+static int gxp_firmware_load(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
+ uint core)
{
struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
- u32 offset;
- void __iomem *core_scratchpad_base;
int ret;
if (!mgr->firmwares[core])
@@ -382,24 +415,11 @@ static int gxp_firmware_load(struct gxp_dev *gxp, uint core)
mgr->firmwares[core]->data + FW_HEADER_SIZE,
core);
- memset(gxp->fwbufs[core].vaddr + AURORA_SCRATCHPAD_OFF, 0,
- AURORA_SCRATCHPAD_LEN);
-
- core_scratchpad_base = gxp->fwbufs[core].vaddr + AURORA_SCRATCHPAD_OFF;
- offset = SCRATCHPAD_MSG_OFFSET(MSG_CORE_ALIVE);
- writel(0, core_scratchpad_base + offset);
- offset = SCRATCHPAD_MSG_OFFSET(MSG_TOP_ACCESS_OK);
- writel(0, core_scratchpad_base + offset);
-
/* TODO(b/188970444): Cleanup logging of addresses */
dev_notice(gxp->dev,
"ELF loaded at virtual: %pK and physical: 0x%llx\n",
gxp->fwbufs[core].vaddr, gxp->fwbufs[core].paddr);
- /* Configure bus performance monitors */
- gxp_bpm_configure(gxp, core, INST_BPM_OFFSET, BPM_EVENT_READ_XFER);
- gxp_bpm_configure(gxp, core, DATA_BPM_OFFSET, BPM_EVENT_WRITE_XFER);
-
return 0;
out_firmware_unload:
@@ -407,18 +427,20 @@ out_firmware_unload:
return ret;
}
-static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
+static int gxp_firmware_handshake(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core,
+ uint phys_core)
{
- u32 offset;
u32 __maybe_unused expected_top_value;
- void __iomem *core_scratchpad_base;
+ /* Prevent the read loop below from being optimized. */
+ volatile struct gxp_host_control_region *core_cfg;
int ctr;
/* Wait for core to come up */
- dev_notice(gxp->dev, "Waiting for core %u to power up...\n", core);
+ dev_notice(gxp->dev, "Waiting for core %u to power up...\n", phys_core);
ctr = 1000;
while (ctr) {
- if (gxp_lpm_is_powered(gxp, CORE_TO_PSM(core)))
+ if (gxp_lpm_is_powered(gxp, CORE_TO_PSM(phys_core)))
break;
udelay(1 * GXP_TIME_DELAY_FACTOR);
ctr--;
@@ -432,9 +454,9 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
/* Wait for 500ms. Then check if Q7 core is alive */
dev_notice(gxp->dev, "Waiting for core %u to respond...\n",
- core);
+ phys_core);
- core_scratchpad_base = gxp->fwbufs[core].vaddr + AURORA_SCRATCHPAD_OFF;
+ core_cfg = get_scratchpad_base(gxp, vd, core);
/*
* Currently, the hello_world FW writes a magic number
@@ -442,7 +464,6 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
* space as an alive message
*/
ctr = 5000;
- offset = SCRATCHPAD_MSG_OFFSET(MSG_CORE_ALIVE);
#if IS_ENABLED(CONFIG_GXP_TEST)
fake_gxp_firmware_flush_work_all();
/*
@@ -454,16 +475,18 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
#endif
usleep_range(50 * GXP_TIME_DELAY_FACTOR, 60 * GXP_TIME_DELAY_FACTOR);
while (ctr--) {
- if (readl(core_scratchpad_base + offset) == Q7_ALIVE_MAGIC)
+ invalidate_scratchpad_region(gxp, vd, core);
+ if (core_cfg->core_alive_magic == Q7_ALIVE_MAGIC)
break;
usleep_range(1 * GXP_TIME_DELAY_FACTOR,
10 * GXP_TIME_DELAY_FACTOR);
}
- if (readl(core_scratchpad_base + offset) != Q7_ALIVE_MAGIC) {
- dev_err(gxp->dev, "Core %u did not respond!\n", core);
+ invalidate_scratchpad_region(gxp, vd, core);
+ if (core_cfg->core_alive_magic != Q7_ALIVE_MAGIC) {
+ dev_err(gxp->dev, "Core %u did not respond!\n", phys_core);
return -EIO;
}
- dev_notice(gxp->dev, "Core %u is alive!\n", core);
+ dev_notice(gxp->dev, "Core %u is alive!\n", phys_core);
#if !IS_ENABLED(CONFIG_GXP_GEM5)
/*
@@ -477,26 +500,27 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
* handshakes in Gem5.
*/
ctr = 1000;
- offset = SCRATCHPAD_MSG_OFFSET(MSG_TOP_ACCESS_OK);
- expected_top_value = BIT(CORE_WAKEUP_DOORBELL(core));
+ expected_top_value = BIT(CORE_WAKEUP_DOORBELL(phys_core));
while (ctr--) {
- if (readl(core_scratchpad_base + offset) == expected_top_value)
+ invalidate_scratchpad_region(gxp, vd, core);
+ if (core_cfg->top_access_ok == expected_top_value)
break;
udelay(1 * GXP_TIME_DELAY_FACTOR);
}
- if (readl(core_scratchpad_base + offset) != expected_top_value) {
- dev_err(gxp->dev, "TOP access from core %u failed!\n", core);
+ if (core_cfg->top_access_ok != expected_top_value) {
+ dev_err(gxp->dev, "TOP access from core %u failed!\n", phys_core);
return -EIO;
}
- dev_notice(gxp->dev, "TOP access from core %u successful!\n", core);
+ dev_notice(gxp->dev, "TOP access from core %u successful!\n", phys_core);
#endif
/* Stop bus performance monitors */
- gxp_bpm_stop(gxp, core);
+ gxp_bpm_stop(gxp, phys_core);
dev_notice(gxp->dev, "Core%u Instruction read transactions: 0x%x\n",
- core, gxp_bpm_read_counter(gxp, core, INST_BPM_OFFSET));
- dev_notice(gxp->dev, "Core%u Data write transactions: 0x%x\n", core,
- gxp_bpm_read_counter(gxp, core, DATA_BPM_OFFSET));
+ core, gxp_bpm_read_counter(gxp, phys_core, INST_BPM_OFFSET));
+ dev_notice(gxp->dev, "Core%u Data write transactions: 0x%x\n",
+ phys_core,
+ gxp_bpm_read_counter(gxp, phys_core, DATA_BPM_OFFSET));
return 0;
}
@@ -597,20 +621,14 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
mgr->firmwares[core] = firmwares[core];
}
- ret = gxp_firmware_fetch_boundaries(gxp, mgr);
- if (ret)
- goto err_fetch_boundaries;
-
kfree(mgr->firmware_name);
mgr->firmware_name = name_buf;
+ gxp_firmware_has_requested(gxp, mgr);
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]);
@@ -776,11 +794,7 @@ int gxp_firmware_request_if_needed(struct gxp_dev *gxp)
if (ret)
goto err_authenticate_firmware;
- ret = gxp_firmware_fetch_boundaries(gxp, mgr);
- if (ret)
- goto err_authenticate_firmware;
-
- mgr->is_firmware_requested = true;
+ gxp_firmware_has_requested(gxp, mgr);
out:
mutex_unlock(&mgr->dsp_firmware_lock);
@@ -813,37 +827,49 @@ static void disable_core_interrupts(struct gxp_dev *gxp, uint core)
gxp_write_32(gxp, GXP_CORE_REG_DEDICATED_INT_MASK(core), 0);
}
-static int gxp_firmware_setup(struct gxp_dev *gxp, uint core)
+static inline uint select_core(struct gxp_virtual_device *vd, uint virt_core,
+ uint phys_core)
+{
+ return gxp_fw_data_use_per_vd_config(vd) ? virt_core : phys_core;
+}
+
+static int gxp_firmware_setup(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core,
+ uint phys_core)
{
int ret = 0;
struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
- if (mgr->firmware_running & BIT(core)) {
+ if (gxp_core_boot && mgr->firmware_running & BIT(phys_core)) {
dev_err(gxp->dev, "Firmware is already running on core %u\n",
- core);
+ phys_core);
return -EBUSY;
}
- ret = gxp_firmware_load(gxp, core);
+ ret = gxp_firmware_load(gxp, vd, core);
if (ret) {
- dev_err(gxp->dev, "Failed to load firmware on core %u\n", core);
+ dev_err(gxp->dev, "Failed to load firmware on core %u\n",
+ phys_core);
return ret;
}
+ /* Configure bus performance monitors */
+ gxp_bpm_configure(gxp, phys_core, INST_BPM_OFFSET, BPM_EVENT_READ_XFER);
+ gxp_bpm_configure(gxp, phys_core, DATA_BPM_OFFSET, BPM_EVENT_WRITE_XFER);
/* Mark this as a 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;
+ if (gxp_core_boot) {
+ reset_core_config_region(gxp, vd, core);
+ ret = gxp_firmware_setup_hw_after_block_off(gxp, core,
+ phys_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);
+ enable_core_interrupts(gxp, phys_core);
return ret;
}
@@ -865,82 +891,85 @@ static void gxp_firmware_wakeup_cores(struct gxp_dev *gxp, uint core_list)
static int gxp_firmware_finish_startup(struct gxp_dev *gxp,
struct gxp_virtual_device *vd,
- uint virt_core, uint core)
+ uint virt_core, uint phys_core)
{
struct work_struct *work;
struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
int ret = 0;
+ uint core = select_core(vd, virt_core, phys_core);
if (gxp_core_boot) {
- ret = gxp_firmware_handshake(gxp, core);
+ ret = gxp_firmware_handshake(gxp, vd, core, phys_core);
if (ret) {
dev_err(gxp->dev,
- "Firmware handshake failed on core %u\n", core);
+ "Firmware handshake failed on core %u\n",
+ phys_core);
goto err_firmware_off;
}
/* Initialize mailbox */
if (gxp->mailbox_mgr->allocate_mailbox) {
- gxp->mailbox_mgr->mailboxes[core] =
+ gxp->mailbox_mgr->mailboxes[phys_core] =
gxp->mailbox_mgr->allocate_mailbox(
- gxp->mailbox_mgr, vd, virt_core, core);
- if (IS_ERR(gxp->mailbox_mgr->mailboxes[core])) {
+ gxp->mailbox_mgr, vd, virt_core, phys_core);
+ if (IS_ERR(gxp->mailbox_mgr->mailboxes[phys_core])) {
dev_err(gxp->dev,
"Unable to allocate mailbox (core=%u, ret=%ld)\n",
- core,
+ phys_core,
PTR_ERR(gxp->mailbox_mgr
- ->mailboxes[core]));
+ ->mailboxes[phys_core]));
ret = PTR_ERR(
- gxp->mailbox_mgr->mailboxes[core]);
- gxp->mailbox_mgr->mailboxes[core] = NULL;
+ gxp->mailbox_mgr->mailboxes[phys_core]);
+ gxp->mailbox_mgr->mailboxes[phys_core] = NULL;
goto err_firmware_off;
}
}
+ mgr->firmware_running |= BIT(phys_core);
}
- work = gxp_debug_dump_get_notification_handler(gxp, core);
+ work = gxp_debug_dump_get_notification_handler(gxp, phys_core);
if (work)
gxp_notification_register_handler(
- gxp, core, HOST_NOTIF_DEBUG_DUMP_READY, work);
+ gxp, phys_core, HOST_NOTIF_DEBUG_DUMP_READY, work);
- work = gxp_core_telemetry_get_notification_handler(gxp, core);
+ work = gxp_core_telemetry_get_notification_handler(gxp, phys_core);
if (work)
gxp_notification_register_handler(
- gxp, core, HOST_NOTIF_CORE_TELEMETRY_STATUS, work);
-
- mgr->firmware_running |= BIT(core);
+ gxp, phys_core, HOST_NOTIF_CORE_TELEMETRY_STATUS, work);
return ret;
err_firmware_off:
if (gxp_core_boot)
- gxp_pm_core_off(gxp, core);
+ gxp_pm_core_off(gxp, phys_core);
gxp_firmware_unload(gxp, core);
return ret;
}
static void gxp_firmware_stop_core(struct gxp_dev *gxp,
struct gxp_virtual_device *vd,
- uint virt_core, uint core)
+ uint virt_core, uint phys_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);
+ if (gxp_core_boot && !(mgr->firmware_running & BIT(phys_core)))
+ dev_err(gxp->dev, "Firmware is not running on core %u\n",
+ phys_core);
- mgr->firmware_running &= ~BIT(core);
+ mgr->firmware_running &= ~BIT(phys_core);
- gxp_notification_unregister_handler(gxp, core,
+ gxp_notification_unregister_handler(gxp, phys_core,
HOST_NOTIF_DEBUG_DUMP_READY);
- gxp_notification_unregister_handler(gxp, core,
+ gxp_notification_unregister_handler(gxp, phys_core,
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_mgr->mailboxes[phys_core]);
+ dev_notice(gxp->dev, "Mailbox %u released\n",
+ phys_core);
}
if (vd->state == GXP_VD_RUNNING) {
@@ -948,46 +977,55 @@ static void gxp_firmware_stop_core(struct gxp_dev *gxp,
* Disable interrupts to prevent cores from being woken up
* unexpectedly.
*/
- disable_core_interrupts(gxp, core);
- gxp_pm_core_off(gxp, core);
+ disable_core_interrupts(gxp, phys_core);
+ gxp_pm_core_off(gxp, phys_core);
}
}
- gxp_firmware_unload(gxp, core);
+ gxp_firmware_unload(gxp, select_core(vd, virt_core, phys_core));
}
int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
uint core_list)
{
int ret;
- uint core, virt_core;
+ uint phys_core, virt_core;
uint failed_cores = 0;
int failed_ret;
- for (core = 0; core < GXP_NUM_CORES; core++) {
- if (core_list & BIT(core)) {
- ret = gxp_firmware_setup(gxp, core);
- if (ret) {
- failed_cores |= BIT(core);
- failed_ret = ret;
- dev_err(gxp->dev, "Failed to run firmware on core %u\n",
- core);
- }
+ virt_core = 0;
+ for (phys_core = 0; phys_core < GXP_NUM_CORES; phys_core++) {
+ uint core = select_core(vd, virt_core, phys_core);
+
+ if (!(core_list & BIT(phys_core)))
+ continue;
+
+ ret = gxp_firmware_setup(gxp, vd, core, phys_core);
+ if (ret) {
+ failed_cores |= BIT(phys_core);
+ failed_ret = ret;
+ dev_err(gxp->dev, "Failed to run firmware on core %u\n",
+ phys_core);
}
+ virt_core++;
}
if (failed_cores != 0) {
/*
* Shut down the cores which call `gxp_firmware_setup`
* successfully
*/
- for (core = 0; core < GXP_NUM_CORES; core++) {
- if (core_list & BIT(core)) {
- if (!(failed_cores & BIT(core))) {
- if (gxp_core_boot)
- gxp_pm_core_off(gxp, core);
- gxp_firmware_unload(gxp, core);
- }
+ virt_core = 0;
+ for (phys_core = 0; phys_core < GXP_NUM_CORES; phys_core++) {
+ uint core = select_core(vd, virt_core, phys_core);
+
+ if (!(core_list & BIT(phys_core)))
+ continue;
+ if (!(failed_cores & BIT(phys_core))) {
+ if (gxp_core_boot)
+ gxp_pm_core_off(gxp, phys_core);
+ gxp_firmware_unload(gxp, core);
}
+ virt_core++;
}
return failed_ret;
}
@@ -997,11 +1035,11 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
* gxp_doorbell_enable_for_core here to set GXP_REG_COMMON_INT_MASK_0
* first to enable the firmware handshakes.
*/
- for (core = 0; core < GXP_NUM_CORES; core++) {
- if (!(core_list & BIT(core)))
+ for (phys_core = 0; phys_core < GXP_NUM_CORES; phys_core++) {
+ if (!(core_list & BIT(phys_core)))
continue;
- gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(core),
- core);
+ gxp_doorbell_enable_for_core(
+ gxp, CORE_WAKEUP_DOORBELL(phys_core), phys_core);
}
#endif
/* Switch clock mux to the normal state to guarantee LPM works */
@@ -1011,30 +1049,28 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
}
virt_core = 0;
- for (core = 0; core < GXP_NUM_CORES; core++) {
- if (core_list & BIT(core)) {
- ret = gxp_firmware_finish_startup(gxp, vd, virt_core,
- core);
- if (ret) {
- failed_cores |= BIT(core);
- dev_err(gxp->dev,
- "Failed to run firmware on core %u\n",
- core);
- }
- virt_core++;
+ for (phys_core = 0; phys_core < GXP_NUM_CORES; phys_core++) {
+ if (!(core_list & BIT(phys_core)))
+ continue;
+ ret = gxp_firmware_finish_startup(gxp, vd, virt_core,
+ phys_core);
+ if (ret) {
+ failed_cores |= BIT(phys_core);
+ dev_err(gxp->dev, "Failed to run firmware on core %u\n",
+ phys_core);
}
+ virt_core++;
}
if (failed_cores != 0) {
virt_core = 0;
- for (core = 0; core < GXP_NUM_CORES; core++) {
- if (core_list & BIT(core)) {
- if (!(failed_cores & BIT(core))) {
- gxp_firmware_stop_core(gxp, vd,
- virt_core, core);
- }
- virt_core++;
- }
+ for (phys_core = 0; phys_core < GXP_NUM_CORES; phys_core++) {
+ if (!(core_list & BIT(phys_core)))
+ continue;
+ if (!(failed_cores & BIT(phys_core)))
+ gxp_firmware_stop_core(gxp, vd, virt_core,
+ phys_core);
+ virt_core++;
}
}
/* Check if we need to set clock mux to low state as requested */
@@ -1045,14 +1081,12 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
}
int gxp_firmware_setup_hw_after_block_off(struct gxp_dev *gxp, uint core,
- bool verbose)
+ uint phys_core, bool verbose)
{
- gxp_program_reset_vector(gxp, core, verbose);
-
- return gxp_core_boot ? gxp_pm_core_on(gxp, core, verbose) : 0;
+ gxp_program_reset_vector(gxp, core, phys_core, verbose);
+ return gxp_pm_core_on(gxp, phys_core, verbose);
}
-
void gxp_firmware_stop(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
uint core_list)
{
@@ -1066,30 +1100,50 @@ void gxp_firmware_stop(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
}
}
-void gxp_firmware_set_boot_mode(struct gxp_dev *gxp, uint core, u32 mode)
+void gxp_firmware_set_boot_mode(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core,
+ u32 mode)
{
- void __iomem *boot_mode_addr;
+ struct gxp_host_control_region *core_cfg;
/* Callers shouldn't call the function under this condition. */
if (!gxp->fwbufs[core].vaddr)
return;
- boot_mode_addr = gxp->fwbufs[core].vaddr + AURORA_SCRATCHPAD_OFF +
- SCRATCHPAD_MSG_OFFSET(MSG_BOOT_MODE);
-
- writel(mode, boot_mode_addr);
+ core_cfg = get_scratchpad_base(gxp, vd, core);
+ core_cfg->boot_mode = mode;
+ flush_scratchpad_region(gxp, vd, core);
}
-u32 gxp_firmware_get_boot_mode(struct gxp_dev *gxp, uint core)
+u32 gxp_firmware_get_boot_mode(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core)
{
- void __iomem *boot_mode_addr;
+ struct gxp_host_control_region *core_cfg;
/* Callers shouldn't call the function under this condition. */
if (!gxp->fwbufs[core].vaddr)
return 0;
- boot_mode_addr = gxp->fwbufs[core].vaddr + AURORA_SCRATCHPAD_OFF +
- SCRATCHPAD_MSG_OFFSET(MSG_BOOT_MODE);
+ core_cfg = get_scratchpad_base(gxp, vd, core);
+ invalidate_scratchpad_region(gxp, vd, core);
+ return core_cfg->boot_mode;
+}
+
+void gxp_firmware_set_boot_status(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core,
+ u32 status)
+{
+ struct gxp_host_control_region *core_cfg;
+
+ core_cfg = get_scratchpad_base(gxp, vd, core);
+ core_cfg->boot_status = status;
+}
+
+u32 gxp_firmware_get_boot_status(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd, uint core)
+{
+ struct gxp_host_control_region *core_cfg;
- return readl(boot_mode_addr);
+ core_cfg = get_scratchpad_base(gxp, vd, core);
+ return core_cfg->boot_status;
}