summaryrefslogtreecommitdiff
path: root/gxp-firmware.c
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 /gxp-firmware.c
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
Diffstat (limited to 'gxp-firmware.c')
-rw-r--r--gxp-firmware.c192
1 files changed, 124 insertions, 68 deletions
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);