summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurora pro automerger <aurora-pro-automerger@google.com>2022-06-24 21:21:54 -0700
committerJohn Scheible <johnscheible@google.com>2022-07-01 10:40:42 -0700
commit965bb96998a383ae25c88da8c095f375bfb5e240 (patch)
tree89c7b620d34ae9ec212eed398802e299cc4ac32f
parent9931f3a1a4c9019850edc316c6d54e14f3ff961e (diff)
downloadgs201-965bb96998a383ae25c88da8c095f375bfb5e240.tar.gz
[Copybara Auto Merge] Merge branch 'gs201-release' into 'android13-gs-pixel-5.10-tm-qpr1'
DSP Release 6/29 RC02. Release info: 237573765 gxp: Don't change doorbell mask for running cores Bug: 235447772 Revert "Revert "gxp: authenticate firmware after requesting it"" Bug: 235447772 (repeat) GitOrigin-RevId: f2c9f0833dbd0168186fd618863d7ee57edeaafa Change-Id: I2892b1a032ced0641b0418c0ae2107db135caffc
-rw-r--r--gxp-doorbell.c12
-rw-r--r--gxp-doorbell.h38
-rw-r--r--gxp-firmware-data.c16
-rw-r--r--gxp-firmware.c192
-rw-r--r--gxp-lpm.c8
-rw-r--r--gxp-lpm.h2
6 files changed, 176 insertions, 92 deletions
diff --git a/gxp-doorbell.c b/gxp-doorbell.c
index 40e956b..0fc6389 100644
--- a/gxp-doorbell.c
+++ b/gxp-doorbell.c
@@ -13,19 +13,11 @@
#define GXP_DOORBELL_STRIDE (GXP_REG_DOORBELL_1_STATUS \
- GXP_REG_DOORBELL_0_STATUS)
-void gxp_doorbell_set_listening_core(struct gxp_dev *gxp, u32 doorbell_num,
- uint core)
+void gxp_doorbell_enable_for_core(struct gxp_dev *gxp, u32 doorbell_num,
+ uint core)
{
- uint i;
u32 val;
- /* Disable DOORBELL_NUM on all cores */
- for (i = 0; i < GXP_NUM_CORES; i++) {
- val = gxp_read_32_core(gxp, i, GXP_REG_COMMON_INT_MASK_0);
- val &= ~BIT(doorbell_num);
- gxp_write_32_core(gxp, i, GXP_REG_COMMON_INT_MASK_0, val);
- }
-
/* Enable DOORBELL_NUM on requested core */
val = gxp_read_32_core(gxp, core, GXP_REG_COMMON_INT_MASK_0);
val |= BIT(doorbell_num);
diff --git a/gxp-doorbell.h b/gxp-doorbell.h
index c8592fa..d2f167b 100644
--- a/gxp-doorbell.h
+++ b/gxp-doorbell.h
@@ -9,10 +9,44 @@
#include "gxp-internal.h"
-void gxp_doorbell_set_listening_core(struct gxp_dev *gxp, u32 doorbell_num,
- uint core);
+/**
+ * gxp_doorbell_enable_for_core() - Enable a core to receive interrupts from
+ * the specified doorbell
+ * @gxp: The GXP device to enable the doorbell for
+ * @doorbell_num: The index of the doorbell to enable
+ * @core: The core which will receive interrupts from the enabled doorbell
+ *
+ * This function can only be called before firmware is running on @core or as
+ * part of halting firmware on it. Firmware may read or modify which doorbells
+ * it is listening to and accesses are not synchronized between the driver and
+ * firmware.
+ */
+void gxp_doorbell_enable_for_core(struct gxp_dev *gxp, u32 doorbell_num,
+ uint core);
+
+/**
+ * gxp_doorbell_set() - Ring the specified doorbell
+ * @gxp: The GXP device to ring the doorbell for
+ * @doorbell_num: The index of the doorbell to ring
+ *
+ * Any cores this doorbell is enabled for willexecute their handler.
+ */
void gxp_doorbell_set(struct gxp_dev *gxp, u32 doorbell_num);
+
+/**
+ * gxp_doorbell_clear() - Clear the specified doorbell's interrupt
+ * @gxp: The GXP device to clear the doorbell for
+ * @doorbell_num: The index of the doorbell to clear
+ */
void gxp_doorbell_clear(struct gxp_dev *gxp, u32 doorbell_num);
+
+/**
+ * gxp_doorbell_status() - Returns whether the specified doorbell is rung
+ * @gxp: The GXP device containing the doorbell
+ * @doorbell_num: The index of the doorbell to check
+ *
+ * Return: The status register of the doorbell, 1 for rung, 0 for cleared
+ */
u32 gxp_doorbell_status(struct gxp_dev *gxp, u32 doorbell_num);
#endif /* __GXP_DOORBELL_H__ */
diff --git a/gxp-firmware-data.c b/gxp-firmware-data.c
index d93881e..d1def41 100644
--- a/gxp-firmware-data.c
+++ b/gxp-firmware-data.c
@@ -26,7 +26,7 @@
#define FW_DATA_DEBUG_PATTERN 0x66
/* IDs for dedicated doorbells used by some system components */
-#define DOORBELL_ID_CORE_WAKEUP 0
+#define DOORBELL_ID_CORE_WAKEUP(__core__) (0 + __core__)
/* IDs for dedicated sync barriers used by some system components */
#define SYNC_BARRIER_ID_UART 1
@@ -70,7 +70,7 @@ struct gxp_fw_data_manager {
/* Doorbells allocator and reserved doorbell IDs */
struct range_alloc *doorbell_allocator;
- int cores_wakeup_doorbell;
+ int core_wakeup_doorbells[GXP_NUM_CORES];
int semaphore_doorbells[GXP_NUM_CORES];
/* Sync barriers allocator and reserved sync barrier IDs */
@@ -510,11 +510,13 @@ int gxp_fw_data_init(struct gxp_dev *gxp)
/* Allocate doorbells */
/* Pinned: Cores wakeup doorbell */
- mgr->cores_wakeup_doorbell = DOORBELL_ID_CORE_WAKEUP;
- res = range_alloc_get(mgr->doorbell_allocator,
- mgr->cores_wakeup_doorbell);
- if (res)
- goto err;
+ for (i = 0; i < GXP_NUM_CORES; i++) {
+ mgr->core_wakeup_doorbells[i] = DOORBELL_ID_CORE_WAKEUP(i);
+ res = range_alloc_get(mgr->doorbell_allocator,
+ mgr->core_wakeup_doorbells[i]);
+ if (res)
+ goto err;
+ }
/* Semaphores operation doorbells */
for (i = 0; i < GXP_NUM_CORES; i++) {
diff --git a/gxp-firmware.c b/gxp-firmware.c
index 4e207b9..29b00e7 100644
--- a/gxp-firmware.c
+++ b/gxp-firmware.c
@@ -170,74 +170,94 @@ static int elf_load_segments(struct gxp_dev *gxp, const u8 *elf_data,
}
static int
-gxp_firmware_load_authenticated(struct gxp_dev *gxp, const struct firmware *fw,
- const struct gxp_mapped_resource *buffer)
+gxp_firmware_authenticate(struct gxp_dev *gxp,
+ const struct firmware *firmwares[GXP_NUM_CORES])
{
- const u8 *data = fw->data;
- size_t size = fw->size;
+ const u8 *data;
+ size_t size;
void *header_vaddr;
+ struct gxp_mapped_resource *buffer;
dma_addr_t header_dma_addr;
+ int core;
int ret;
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);
+ return 0;
}
if (!gxp->gsa_dev) {
dev_warn(
gxp->dev,
"No GSA device available, skipping firmware authentication\n");
- return elf_load_segments(gxp, data + FW_HEADER_SIZE,
- size - FW_HEADER_SIZE, buffer);
+ return 0;
}
- if ((size - FW_HEADER_SIZE) > buffer->size) {
- dev_err(gxp->dev, "Firmware image does not fit (%zu > %llu)\n",
- size - FW_HEADER_SIZE, buffer->size);
- return -EINVAL;
- }
+ for (core = 0; core < GXP_NUM_CORES; core++) {
+ data = firmwares[core]->data;
+ size = firmwares[core]->size;
+ buffer = &gxp->fwbufs[core];
- dev_dbg(gxp->dev, "Authenticating firmware\n");
+ if ((size - FW_HEADER_SIZE) > buffer->size) {
+ dev_err(gxp->dev,
+ "Firmware image does not fit (%zu > %llu)\n",
+ size - FW_HEADER_SIZE, buffer->size);
+ ret = -EINVAL;
+ goto error;
+ }
- /* Allocate coherent memory for the image header */
- header_vaddr = dma_alloc_coherent(gxp->gsa_dev, FW_HEADER_SIZE,
- &header_dma_addr, GFP_KERNEL);
- if (!header_vaddr) {
- dev_err(gxp->dev,
- "Failed to allocate coherent memory for header\n");
- return -ENOMEM;
- }
+ dev_dbg(gxp->dev, "Authenticating firmware of core%u\n", core);
- /* Copy the header to GSA coherent memory */
- memcpy(header_vaddr, data, FW_HEADER_SIZE);
+ /* Allocate coherent memory for the image header */
+ header_vaddr = dma_alloc_coherent(gxp->gsa_dev, FW_HEADER_SIZE,
+ &header_dma_addr, GFP_KERNEL);
+ if (!header_vaddr) {
+ dev_err(gxp->dev,
+ "Failed to allocate coherent memory for header\n");
+ ret = -ENOMEM;
+ goto error;
+ }
- /* Copy the firmware image to the carveout location, skipping the header */
- memcpy_toio(buffer->vaddr, data + FW_HEADER_SIZE,
- size - FW_HEADER_SIZE);
+ /* Copy the header to GSA coherent memory */
+ memcpy(header_vaddr, data, FW_HEADER_SIZE);
- dev_dbg(gxp->dev,
- "Requesting GSA authentication. meta = %pad payload = %pap",
- &header_dma_addr, &buffer->paddr);
+ /* Copy the firmware image to the carveout location, skipping the header */
+ memcpy_toio(buffer->vaddr, data + FW_HEADER_SIZE,
+ size - FW_HEADER_SIZE);
- ret = gsa_authenticate_image(gxp->gsa_dev, header_dma_addr,
- buffer->paddr);
- if (ret) {
- dev_err(gxp->dev, "GSA authentication failed: %d\n", ret);
- } else {
dev_dbg(gxp->dev,
- "Authentication succeeded, loading ELF segments\n");
- ret = elf_load_segments(gxp, data + FW_HEADER_SIZE,
- size - FW_HEADER_SIZE, buffer);
- if (ret)
- dev_err(gxp->dev, "ELF parsing failed (%d)\n", ret);
+ "Requesting GSA authentication. meta = %pad payload = %pap",
+ &header_dma_addr, &buffer->paddr);
+
+ ret = gsa_authenticate_image(gxp->gsa_dev, header_dma_addr,
+ buffer->paddr);
+
+ dma_free_coherent(gxp->gsa_dev, FW_HEADER_SIZE, header_vaddr,
+ header_dma_addr);
+
+ if (ret) {
+ dev_err(gxp->dev, "GSA authentication failed: %d\n",
+ ret);
+ goto error;
+ }
}
- dma_free_coherent(gxp->gsa_dev, FW_HEADER_SIZE, header_vaddr,
- header_dma_addr);
+ return 0;
+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.
+ */
+ memset_io(buffer->vaddr, 0, buffer->size);
return ret;
}
@@ -271,9 +291,11 @@ static int gxp_firmware_load(struct gxp_dev *gxp, uint core)
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]);
+ /* Load firmware to System RAM */
+ ret = elf_load_segments(gxp,
+ gxp->firmwares[core]->data + FW_HEADER_SIZE,
+ gxp->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;
@@ -313,11 +335,11 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
/* Raise wakeup doorbell */
dev_notice(gxp->dev, "Raising doorbell %d interrupt\n",
- CORE_WAKEUP_DOORBELL);
+ CORE_WAKEUP_DOORBELL(core));
#ifndef CONFIG_GXP_GEM5
- gxp_doorbell_set_listening_core(gxp, CORE_WAKEUP_DOORBELL, core);
+ gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(core), core);
#endif
- gxp_doorbell_set(gxp, CORE_WAKEUP_DOORBELL);
+ 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);
@@ -375,7 +397,7 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, uint core)
*/
ctr = 1000;
offset = SCRATCHPAD_MSG_OFFSET(MSG_TOP_ACCESS_OK);
- expected_top_value = BIT(0);
+ expected_top_value = BIT(CORE_WAKEUP_DOORBELL(core));
while (ctr--) {
if (readl(core_scratchpad_base + offset) == expected_top_value)
break;
@@ -450,11 +472,24 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
int ret;
int core;
+ /*
+ * Lock the VD semaphore to ensure no core is executing the firmware
+ * while requesting new firmware.
+ */
+ down_read(&gxp->vd_semaphore);
+
+ if (gxp->firmware_running) {
+ dev_warn(dev, "Cannot update firmware when any core is running\n");
+ ret = -EBUSY;
+ goto out;
+ }
+
name_buf = fw_name_from_attr_buf(buf);
if (IS_ERR(name_buf)) {
dev_err(gxp->dev, "Invalid firmware prefix requested: %s\n",
buf);
- return PTR_ERR(name_buf);
+ ret = PTR_ERR(name_buf);
+ goto out;
}
mutex_lock(&gxp->dsp_firmware_lock);
@@ -463,19 +498,15 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
ret = request_dsp_firmware(gxp, name_buf, firmwares);
if (ret) {
- mutex_unlock(&gxp->dsp_firmware_lock);
dev_err(gxp->dev,
"Failed to request firmwares with names \"%sX\" (ret=%d)\n",
name_buf, ret);
- kfree(name_buf);
- return ret;
+ goto err_request_firmware;
}
- /*
- * Lock the VD semaphore to make sure no new firmware is started while
- * changing out the images in `gxp->firmwares`
- */
- down_read(&gxp->vd_semaphore);
+ ret = gxp_firmware_authenticate(gxp, firmwares);
+ if (ret)
+ goto err_authenticate_firmware;
for (core = 0; core < GXP_NUM_CORES; core++) {
if (gxp->firmwares[core])
@@ -486,10 +517,19 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
kfree(gxp->firmware_name);
gxp->firmware_name = name_buf;
- up_read(&gxp->vd_semaphore);
mutex_unlock(&gxp->dsp_firmware_lock);
-
+out:
+ up_read(&gxp->vd_semaphore);
return count;
+
+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);
+ up_read(&gxp->vd_semaphore);
+ return ret;
}
static DEVICE_ATTR_RW(load_dsp_firmware);
@@ -613,18 +653,34 @@ void gxp_fw_destroy(struct gxp_dev *gxp)
int gxp_firmware_request_if_needed(struct gxp_dev *gxp)
{
int ret = 0;
+ uint core;
mutex_lock(&gxp->dsp_firmware_lock);
- if (!gxp->is_firmware_requested) {
- ret = request_dsp_firmware(gxp, DSP_FIRMWARE_DEFAULT_PREFIX,
- gxp->firmwares);
- if (!ret)
- gxp->is_firmware_requested = true;
- }
+ if (gxp->is_firmware_requested)
+ goto out;
+ ret = request_dsp_firmware(gxp, DSP_FIRMWARE_DEFAULT_PREFIX,
+ gxp->firmwares);
+ if (ret)
+ goto out;
+
+ ret = gxp_firmware_authenticate(gxp, gxp->firmwares);
+ if (ret)
+ goto err_authenticate_firmware;
+
+ gxp->is_firmware_requested = true;
+
+out:
mutex_unlock(&gxp->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;
+ }
+ mutex_unlock(&gxp->dsp_firmware_lock);
return ret;
}
@@ -652,10 +708,10 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
#ifdef CONFIG_GXP_GEM5
/*
* GEM5 starts firmware after LPM is programmed, so we need to call
- * gxp_doorbell_set_listening_core here to set GXP_REG_COMMON_INT_MASK_0
+ * gxp_doorbell_enable_for_core() here to set GXP_REG_COMMON_INT_MASK_0
* first to enable the firmware hadnshaking.
*/
- gxp_doorbell_set_listening_core(gxp, CORE_WAKEUP_DOORBELL, core);
+ gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(core), core);
#endif
ret = gxp_firmware_setup_hw_after_block_off(gxp, core,
/*verbose=*/true);
diff --git a/gxp-lpm.c b/gxp-lpm.c
index 33a0a58..1ac8e27 100644
--- a/gxp-lpm.c
+++ b/gxp-lpm.c
@@ -199,7 +199,7 @@ void gxp_lpm_destroy(struct gxp_dev *gxp)
int gxp_lpm_up(struct gxp_dev *gxp, uint core)
{
/* Clear wakeup doorbell */
- gxp_doorbell_clear(gxp, CORE_WAKEUP_DOORBELL);
+ gxp_doorbell_clear(gxp, CORE_WAKEUP_DOORBELL(core));
/* Enable core PSM */
if (psm_enable(gxp, core)) {
@@ -224,8 +224,8 @@ void gxp_lpm_down(struct gxp_dev *gxp, uint core)
gxp_lpm_enable_state(gxp, core, LPM_PG_STATE);
/* Set wakeup doorbell to trigger an automatic transition to PS3 */
- gxp_doorbell_set_listening_core(gxp, CORE_WAKEUP_DOORBELL, core);
- gxp_doorbell_set(gxp, CORE_WAKEUP_DOORBELL);
+ gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(core), core);
+ gxp_doorbell_set(gxp, CORE_WAKEUP_DOORBELL(core));
msleep(25 * GXP_TIME_DELAY_FACTOR);
/*
@@ -233,7 +233,7 @@ void gxp_lpm_down(struct gxp_dev *gxp, uint core)
* the core will not wake unexpectedly.
*/
gxp_write_32_core(gxp, core, GXP_REG_COMMON_INT_MASK_0, 0);
- gxp_doorbell_clear(gxp, CORE_WAKEUP_DOORBELL);
+ gxp_doorbell_clear(gxp, CORE_WAKEUP_DOORBELL(core));
/* Ensure core is in PS3 */
gxp_lpm_set_state(gxp, core, LPM_PG_STATE, /*verbose=*/true);
diff --git a/gxp-lpm.h b/gxp-lpm.h
index 20f48d3..ee1a749 100644
--- a/gxp-lpm.h
+++ b/gxp-lpm.h
@@ -40,7 +40,7 @@ enum lpm_state {
#define LPM_CFG_SW_PS_TARGET_OFFSET 2
-#define CORE_WAKEUP_DOORBELL 0
+#define CORE_WAKEUP_DOORBELL(__core__) (0 + (__core__))
#define AUR_DVFS_DOMAIN 17
#define AUR_DVFS_DEBUG_REQ (1 << 31)