summaryrefslogtreecommitdiff
path: root/gxp-firmware.c
diff options
context:
space:
mode:
authorAurora pro automerger <aurora-pro-automerger@google.com>2022-07-19 08:41:41 +0000
committerJohn Scheible <johnscheible@google.com>2022-07-25 18:55:04 +0000
commit51345064a78c4fbee30e5c331a41c0dfab852fa0 (patch)
treec49363432f8d27d687608f9475be184f10b28ac2 /gxp-firmware.c
parent965bb96998a383ae25c88da8c095f375bfb5e240 (diff)
downloadgs201-51345064a78c4fbee30e5c331a41c0dfab852fa0.tar.gz
[Copybara Auto Merge] Merge branch 'gs201-release' into 'android13-gs-pixel-5.10-tm-qpr1'
Revert "gxp: avoid holding semaphore during mmap" Revert "gxp: Disable telemetry before free" gxp: fix deadlock on power states queue full Bug: 236087752 gxp: warn deprecate pwr states only once Bug: 237337595 gxp: don't modify clkmux state during core booting Bug: 238960149 gxp: increase the waiting time for cores booting Bug: 237378056 gxp: Disable telemetry before free Bug: 235771175 gxp: avoid holding semaphore during mmap Bug: 232183143 gxp: parallelize the firmware startup process Bug: 207036666 gxp: hold mmap lock around call to find_extend_vma Bug: 237404338 gxp: Fix bug when clearing FW buffers on auth fail Bug: 237789581 gxp: deprecate NON_AGGRESSOR / add LOW_FREQ_CLKMUX Bug: 237337595 (repeat) Bug: 237378056 (repeat) GitOrigin-RevId: 75508d46deac85970c4d556770c105eaa4f2a2e8 Change-Id: Id50f1b68834e687178d66e0d239d1be42e0e2152
Diffstat (limited to 'gxp-firmware.c')
-rw-r--r--gxp-firmware.c199
1 files changed, 144 insertions, 55 deletions
diff --git a/gxp-firmware.c b/gxp-firmware.c
index 29b00e7..d9e6cc6 100644
--- a/gxp-firmware.c
+++ b/gxp-firmware.c
@@ -239,6 +239,7 @@ gxp_firmware_authenticate(struct gxp_dev *gxp,
if (ret) {
dev_err(gxp->dev, "GSA authentication failed: %d\n",
ret);
+ memset_io(buffer->vaddr, 0, buffer->size);
goto error;
}
}
@@ -250,14 +251,10 @@ error:
* Zero out firmware buffers if we got a authentication failure on any
* core.
*/
- for (core -= 1; core >= 0; core--)
- /*
- * TODO(b/237789581) Only the image which failed auth is being
- * zeroed out here. This is benign since the other buffers will
- * be zeroed-out next call, but should still be fixed.
- * The fix is ready upstream and will be in the next release.
- */
+ for (core -= 1; core >= 0; core--) {
+ buffer = &gxp->fwbufs[core];
memset_io(buffer->vaddr, 0, buffer->size);
+ }
return ret;
}
@@ -333,14 +330,6 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
void __iomem *core_scratchpad_base;
int ctr;
- /* Raise wakeup doorbell */
- dev_notice(gxp->dev, "Raising doorbell %d interrupt\n",
- CORE_WAKEUP_DOORBELL(core));
-#ifndef CONFIG_GXP_GEM5
- gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(core), core);
-#endif
- gxp_doorbell_set(gxp, CORE_WAKEUP_DOORBELL(core));
-
/* Wait for core to come up */
dev_notice(gxp->dev, "Waiting for core %u to power up...\n", core);
ctr = 1000;
@@ -370,7 +359,7 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
*/
ctr = 5000;
offset = SCRATCHPAD_MSG_OFFSET(MSG_CORE_ALIVE);
- usleep_range(500 * GXP_TIME_DELAY_FACTOR, 1000 * GXP_TIME_DELAY_FACTOR);
+ usleep_range(50 * GXP_TIME_DELAY_FACTOR, 60 * GXP_TIME_DELAY_FACTOR);
while (ctr--) {
if (readl(core_scratchpad_base + offset) == Q7_ALIVE_MAGIC)
break;
@@ -385,15 +374,14 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
#ifndef CONFIG_GXP_GEM5
/*
- * Currently, the hello_world FW reads the INT_MASK0 register
- * (written by the driver) to validate TOP access. The value
- * read is echoed back by the FW to offset MSG_TOP_ACCESS_OK in
- * the scratchpad space, which must be compared to the value
- * written in the INT_MASK0 register by the driver for
- * confirmation.
+ * FW reads the INT_MASK0 register (written by the driver) to
+ * validate TOP access. The value read is echoed back by the FW to
+ * offset MSG_TOP_ACCESS_OK in the scratchpad space, which must be
+ * compared to the value written in the INT_MASK0 register by the
+ * driver for confirmation.
* On Gem5, FW will start early when lpm is up. This behavior will
- * affect the order of reading/writing INT_MASK0, so ignore this
- * handshaking in Gem5.
+ * affect the order of reading/writing INT_MASK0, so ignore these
+ * handshakes in Gem5.
*/
ctr = 1000;
offset = SCRATCHPAD_MSG_OFFSET(MSG_TOP_ACCESS_OK);
@@ -684,11 +672,9 @@ err_authenticate_firmware:
return ret;
}
-int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
- uint virt_core, uint core)
+static int gxp_firmware_setup(struct gxp_dev *gxp, uint core)
{
int ret = 0;
- struct work_struct *work;
if (gxp->firmware_running & BIT(core)) {
dev_err(gxp->dev, "Firmware is already running on core %u\n",
@@ -705,35 +691,46 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
/* Mark this as a cold boot */
gxp_firmware_set_boot_mode(gxp, core, GXP_BOOT_MODE_REQUEST_COLD_BOOT);
-#ifdef CONFIG_GXP_GEM5
- /*
- * GEM5 starts firmware after LPM is programmed, so we need to call
- * gxp_doorbell_enable_for_core() here to set GXP_REG_COMMON_INT_MASK_0
- * first to enable the firmware hadnshaking.
- */
- gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(core), core);
-#endif
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);
- goto out_firmware_unload;
+ gxp_firmware_unload(gxp, core);
+ }
+
+ return ret;
+}
+
+static void gxp_firmware_wakeup_cores(struct gxp_dev *gxp, uint core_list)
+{
+ uint core;
+
+ /* Raise wakeup doorbell */
+ for (core = 0; core < GXP_NUM_CORES; core++) {
+ if (!(core_list & BIT(core)))
+ continue;
+#ifndef CONFIG_GXP_GEM5
+ gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(core),
+ core);
+#endif
+ gxp_doorbell_set(gxp, CORE_WAKEUP_DOORBELL(core));
}
+}
+
+static int gxp_firmware_finish_startup(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd,
+ uint virt_core, uint core)
+{
+ int ret = 0;
+ struct work_struct *work;
- /* Switch PLL_CON0_NOC_USER MUX to the normal state to guarantee LPM works */
- gxp_pm_force_cmu_noc_user_mux_normal(gxp);
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_check_noc_user_mux;
+ goto out_firmware_unload;
}
- /*
- * Check if we need to set PLL_CON0_NOC_USER MUX to low state for
- * AUR_READY requested state.
- */
- gxp_pm_check_cmu_noc_user_mux(gxp);
/* Initialize mailbox */
gxp->mailbox_mgr->mailboxes[core] =
@@ -761,22 +758,14 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
return ret;
-out_check_noc_user_mux:
- gxp_pm_check_cmu_noc_user_mux(gxp);
out_firmware_unload:
gxp_firmware_unload(gxp, core);
return ret;
}
-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);
-}
-
-void gxp_firmware_stop(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
- uint virt_core, uint core)
+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)))
dev_err(gxp->dev, "Firmware is not running on core %u\n", core);
@@ -797,6 +786,106 @@ void gxp_firmware_stop(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
gxp_firmware_unload(gxp, core);
}
+int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
+ uint core_list)
+{
+ int ret;
+ uint core, virt_core;
+ uint failed_cores = 0;
+
+ 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);
+ dev_err(gxp->dev, "Failed to run firmware on core %u\n",
+ 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))) {
+ gxp_pm_core_off(gxp, core);
+ gxp_firmware_unload(gxp, core);
+ }
+ }
+ }
+ goto out;
+ }
+#ifdef CONFIG_GXP_GEM5
+ /*
+ * GEM5 starts firmware after LPM is programmed, so we need to call
+ * 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)))
+ continue;
+ gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(core),
+ core);
+ }
+#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);
+ 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++;
+ }
+ }
+
+ if (failed_cores != 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);
+ }
+ }
+ }
+ }
+ /* Check if we need to set clock mux to low state as requested */
+ gxp_pm_resume_clkmux(gxp);
+out:
+ return ret;
+}
+
+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);
+}
+
+
+void gxp_firmware_stop(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
+ uint core_list)
+{
+ uint core, virt_core = 0;
+
+ for (core = 0; core < GXP_NUM_CORES; core++) {
+ if (core_list & BIT(core)) {
+ gxp_firmware_stop_core(gxp, vd, virt_core, core);
+ virt_core++;
+ }
+ }
+}
+
void gxp_firmware_set_boot_mode(struct gxp_dev *gxp, uint core, u32 mode)
{
void __iomem *boot_mode_addr;