summaryrefslogtreecommitdiff
path: root/gxp-firmware.c
diff options
context:
space:
mode:
authorAurora pro automerger <aurora-pro-automerger@google.com>2023-03-14 02:07:34 +0000
committerCopybara-Service <copybara-worker@google.com>2023-03-28 22:19:52 -0700
commitec2e64f0bb54d942059d75ccc7c4ab6daa775f78 (patch)
treece23e15e88a8c51e74a637916f0404087ac5459b /gxp-firmware.c
parent0ffef44f5b07977a5608985c66e7eeaadc29b426 (diff)
downloadgs201-ec2e64f0bb54d942059d75ccc7c4ab6daa775f78.tar.gz
gxp: fix compiler warning in gxp-thermal gxp: move fw_rw_section into if-guard gxp: fix memory leak with invalid telemetry type Bug: 273254318 gxp: remove unneeded checks in vd.c gxp: skip configuring when missing VD config gxp: remove unused host-dev structs Bug: 265748027 gxp: remove unused range-alloc module gxp: entirely remove app_metadata Bug: 265748027 (repeat) gxp: remove legacy firmware data init Bug: 265748027 (repeat) gxp: remove legacy telemetry descriptor Bug: 265748027 (repeat) gxp: move system cfg population to device probe Bug: 265748027 (repeat) gxp: add gxp_fw_data_system_cfg Bug: 265748027 (repeat) gxp: add gxp_fw_data_resource Bug: 265748027 (repeat) gxp: bump version 1.11 Bugs: gxp: fix panic on buffer flushing Bug: 268389591 gxp: Do not put core in reset if already in ACG Bug: 272664140 gxp: add cached core telemetry desc Bug: 265748027 (repeat) gxp: Adpot GCIP thermal Bug: 264729080 Bug: 213272324 gxp: remove core_boot parameter Bug: 251612313 gxp: use GPL-2.0-only license Bug: 271797962 gxp: authenticates firmware through GSA Bug: 260533620 gxp: Enable debug dump for imageconfig 2. Bug: 271371895 gxp: Add size check while loading image to memory Bug: 265105909 gxp: refactor MCU firmware life cycle Bug: 233159020 gxp: Create a function for gxp_core_boot Bug: 271716712 gxp: Increase UCI command timeout to 2 seconds Bug: 271622596 gxp: remove checks of data_mgr gxp: skip mapping core resources in MCU mode gxp: add gxp_firmware_loader module gxp: log a warning on failing to map CMU reg gxp: disable out-dated auth mechanism in MCU mode Bug: 260533620 (repeat) gxp: refactor core firmware loading gxp: stop mapping core->TPU queues gxp: get core_count by counting bits Bug: 270097855 gxp: set SSMT to bypass in both mode Bug: 269855604 gxp: Skip gxp_vd_block_unready if gxp_vd_block_ready was not executed Bug: 268427254 gcip: Make gcip_pm_{get_count,is_powered} lockless Bug: 271756295 gcip: generalize mem_pool gcip: utilize mock files on unittests Bug: 272216562 gcip: use GPL-2.0-only license Bug: 271797962 (repeat) gcip: Remove gcip_pm_put_async Bug: 271756295 (repeat) gcip: Only call .power_up if needed gcip: Print GCIP_FW_LOG_LEVEL_FATAL as error message Bug: 271596603 gcip: Postfix gcip_firmware_tracing_restore gcip: fix undefined variable on !THERMAL gcip: always return NULL on domain alloc error gcip: Add gcip_thermal_destroy Bug; 264729080 (repeat) gcip: Add thermal votes Bug: 271194361 Bug: 264729080 (repeat) gcip: Cleanup abandoned domains on domain-pool destroy gcip: Prefix MAX_NUM_THERMAL_STATES Bug: 264729080 (repeat) gcip: Add const to thermal_cooling_device_ops Bug: 264729080 (repeat) gcip: Add thermal support Bug: 264729080 (repeat) gcip: remove redundant else in pm.c GCIP_MAIN_REV_ID: a5b6843ab58f30d6ce086016214cbf56a46610a8 gcip: Add gcip_pm_lock Bug: 264729080 (repeat) gcip: Make gcip_pm_{get_count,is_powered} lockless Bug: 271756295 (repeat) gcip: generalize mem_pool gcip: use GPL-2.0-only license Bug: 271797962 (repeat) gcip: Remove gcip_pm_put_async Bug: 271756295 (repeat) gcip: Add gcip_pm_trylock Bug: 271756295 (repeat) gcip: Add level -3 (FATAL) for firmware log Bug: 271596603 (repeat) gcip: Update outdated comments gcip: Postfix gcip_firmware_tracing_restore gcip: Add gcip_thermal_destroy Bug: 264729080 (repeat) gcip: Add thermal votes Bug: 271194361 (repeat) Bug: 264729080 (repeat) gcip: Add missing includes to gcip-domain-pool.h gcip: Add list of dynamic domains to domain-pool gcip: Prefix MAX_NUM_THERMAL_STATES Bug: 264729080 (repeat) gcip: add watchdog timeout crash type Bug:255416846 gcip: Add thermal header Bug: 264729080 (repeat) GCIP_HEADERS_REV_ID: 126a2bd1e5ac72231c88425fbddb4b9fe2fd85b1 GitOrigin-RevId: 03d9970af576cb6267f25715de67d4ffd3e2934c Change-Id: Ia0e7a0d8113d209e0bb57e160bc3f2d89b1d4c5e
Diffstat (limited to 'gxp-firmware.c')
-rw-r--r--gxp-firmware.c289
1 files changed, 113 insertions, 176 deletions
diff --git a/gxp-firmware.c b/gxp-firmware.c
index b0453d5..d532fdf 100644
--- a/gxp-firmware.c
+++ b/gxp-firmware.c
@@ -26,6 +26,7 @@
#include "gxp-debug-dump.h"
#include "gxp-doorbell.h"
#include "gxp-firmware-data.h"
+#include "gxp-firmware-loader.h"
#include "gxp-firmware.h"
#include "gxp-host-device-structs.h"
#include "gxp-internal.h"
@@ -44,42 +45,6 @@
static int gxp_dsp_fw_auth_disable;
module_param_named(dsp_fw_auth_disable, gxp_dsp_fw_auth_disable, int, 0660);
-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])
@@ -117,8 +82,10 @@ request_dsp_firmware(struct gxp_dev *gxp, char *name_prefix,
return ret;
err:
- for (core -= 1; core >= 0; core--)
+ for (core -= 1; core >= 0; core--) {
release_firmware(out_firmwares[core]);
+ out_firmwares[core] = NULL;
+ }
kfree(name_buf);
return ret;
}
@@ -238,6 +205,9 @@ gxp_firmware_authenticate(struct gxp_dev *gxp,
return 0;
}
+ if (!gxp_is_direct_mode(gxp))
+ return 0;
+
for (core = 0; core < GXP_NUM_CORES; core++) {
data = firmwares[core]->data;
size = firmwares[core]->size;
@@ -302,9 +272,6 @@ error:
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,
uint phys_core, bool verbose)
{
@@ -383,40 +350,6 @@ static void reset_core_config_region(struct gxp_dev *gxp,
}
}
-static int gxp_firmware_load(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
- uint core)
-{
- struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
- int ret;
-
- if (!mgr->firmwares[core])
- return -ENODEV;
- if (mgr->loaded[core])
- return 0;
-
- /* Load firmware to System RAM */
- ret = elf_load_segments(gxp,
- 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;
- }
-
- /* TODO(b/188970444): Cleanup logging of addresses */
- dev_notice(gxp->dev,
- "ELF loaded at virtual: %pK and physical: %#llx\n",
- gxp->fwbufs[core].vaddr, gxp->fwbufs[core].paddr);
- mgr->loaded[core] = true;
-
- return 0;
-
-out_firmware_unload:
- gxp_firmware_unload(gxp, core);
- return ret;
-}
-
static int gxp_firmware_handshake(struct gxp_dev *gxp,
struct gxp_virtual_device *vd, uint core,
uint phys_core)
@@ -515,9 +448,64 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp,
return 0;
}
-static void gxp_firmware_unload(struct gxp_dev *gxp, uint core)
+static int
+gxp_firmware_load_into_memories(struct gxp_dev *gxp,
+ const struct firmware *firmwares[GXP_NUM_CORES])
+{
+ int core;
+ int ret;
+
+ for (core = 0; core < GXP_NUM_CORES; core++) {
+ /* Load firmware to System RAM */
+ if (FW_HEADER_SIZE > firmwares[core]->size) {
+ dev_err(gxp->dev,
+ "Invalid Core %u firmware Image size (%d > %zu)\n",
+ core, FW_HEADER_SIZE, firmwares[core]->size);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if ((firmwares[core]->size - FW_HEADER_SIZE) >
+ gxp->fwbufs[core].size) {
+ dev_err(gxp->dev,
+ "Core %u firmware image does not fit (%zu > %llu)\n",
+ core, firmwares[core]->size - FW_HEADER_SIZE,
+ gxp->fwbufs[core].size);
+ ret = -EINVAL;
+ goto error;
+ }
+ memcpy_toio(gxp->fwbufs[core].vaddr,
+ firmwares[core]->data + FW_HEADER_SIZE,
+ firmwares[core]->size - FW_HEADER_SIZE);
+ }
+ return 0;
+error:
+ /* Zero out firmware buffers if we got invalid size on any core. */
+ for (core -= 1; core >= 0; core--)
+ memset_io(gxp->fwbufs[core].vaddr, 0, gxp->fwbufs[core].size);
+ return ret;
+}
+
+int gxp_firmware_rearrange_elf(struct gxp_dev *gxp,
+ const struct firmware *firmwares[GXP_NUM_CORES])
{
- /* NO-OP for now. */
+ int ret = 0;
+ uint core;
+
+ for (core = 0; core < GXP_NUM_CORES; core++) {
+ /* Re-arrange ELF firmware in System RAM */
+ ret = elf_load_segments(gxp,
+ firmwares[core]->data + FW_HEADER_SIZE,
+ firmwares[core]->size - FW_HEADER_SIZE,
+ &gxp->fwbufs[core]);
+ if (ret) {
+ dev_err(gxp->dev,
+ "Failed to parse ELF firmware on core %u\n",
+ core);
+ return ret;
+ }
+ }
+ return ret;
}
/* Helper function to parse name written to sysfs "load_dsp_firmware" node */
@@ -544,17 +532,11 @@ 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;
+ char *firmware_name = gxp_firmware_loader_get_core_fw_name(gxp);
- mutex_lock(&mgr->dsp_firmware_lock);
-
- ret = scnprintf(buf, PAGE_SIZE, "%s\n",
- mgr->firmware_name ? mgr->firmware_name :
- DSP_FIRMWARE_DEFAULT_PREFIX);
-
- mutex_unlock(&mgr->dsp_firmware_lock);
-
+ ret = scnprintf(buf, PAGE_SIZE, "%s\n", firmware_name);
+ kfree(firmware_name);
return ret;
}
@@ -564,10 +546,8 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
{
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;
- int core;
/*
* Lock the VD semaphore to ensure no core is executing the firmware
@@ -589,43 +569,28 @@ static ssize_t load_dsp_firmware_store(struct device *dev,
goto err_out;
}
- mutex_lock(&mgr->dsp_firmware_lock);
-
dev_notice(gxp->dev, "Requesting firmware be reloaded: %s\n", name_buf);
- ret = request_dsp_firmware(gxp, name_buf, firmwares);
+ /*
+ * It's possible a race condition bug here that someone opens a gxp
+ * device and loads the firmware between below unload/load functions in
+ * another thread, but this interface is only for developer debugging.
+ * We don't insist on preventing the race condition bug.
+ */
+ gxp_firmware_loader_unload(gxp);
+ gxp_firmware_loader_set_core_fw_name(gxp, name_buf);
+ ret = gxp_firmware_loader_load_if_needed(gxp);
if (ret) {
- dev_err(gxp->dev,
- "Failed to request firmwares with names \"%sX\" (ret=%d)\n",
- name_buf, ret);
- goto err_request_firmware;
+ dev_err(gxp->dev, "Failed to load core firmware: %s\n", name_buf);
+ goto err_firmware_load;
}
- ret = gxp_firmware_authenticate(gxp, firmwares);
- if (ret)
- goto err_authenticate_firmware;
-
- for (core = 0; core < GXP_NUM_CORES; core++) {
- if (mgr->firmwares[core])
- release_firmware(mgr->firmwares[core]);
- mgr->firmwares[core] = firmwares[core];
- mgr->loaded[core] = false;
- }
-
- kfree(mgr->firmware_name);
- mgr->firmware_name = name_buf;
- gxp_firmware_has_requested(gxp, mgr);
-
- mutex_unlock(&mgr->dsp_firmware_lock);
+ kfree(name_buf);
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:
+err_firmware_load:
kfree(name_buf);
- mutex_unlock(&mgr->dsp_firmware_lock);
err_out:
up_read(&gxp->vd_semaphore);
return ret;
@@ -654,7 +619,6 @@ int gxp_fw_init(struct gxp_dev *gxp)
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);
@@ -750,53 +714,34 @@ void gxp_fw_destroy(struct gxp_dev *gxp)
memunmap(gxp->fwbufs[core].vaddr);
gxp->fwbufs[core].vaddr = NULL;
}
-
- if (mgr->firmwares[core]) {
- release_firmware(mgr->firmwares[core]);
- mgr->firmwares[core] = NULL;
- }
}
-
- kfree(mgr->firmware_name);
}
-int gxp_firmware_request_if_needed(struct gxp_dev *gxp)
+int gxp_firmware_load_core_firmware(
+ struct gxp_dev *gxp, char *name_prefix,
+ const struct firmware *core_firmware[GXP_NUM_CORES])
{
- int ret = 0;
uint core;
- struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
- char *name = NULL;
-
- mutex_lock(&mgr->dsp_firmware_lock);
-
- if (mgr->is_firmware_requested)
- goto out;
-
- if (mgr->firmware_name == NULL)
- name = DSP_FIRMWARE_DEFAULT_PREFIX;
- else
- name = mgr->firmware_name;
+ int ret;
- ret = request_dsp_firmware(gxp, name, mgr->firmwares);
+ if (name_prefix == NULL)
+ name_prefix = DSP_FIRMWARE_DEFAULT_PREFIX;
+ ret = request_dsp_firmware(gxp, name_prefix, core_firmware);
if (ret)
- goto out;
-
- ret = gxp_firmware_authenticate(gxp, mgr->firmwares);
+ return ret;
+ ret = gxp_firmware_load_into_memories(gxp, core_firmware);
if (ret)
- goto err_authenticate_firmware;
-
- gxp_firmware_has_requested(gxp, mgr);
-
-out:
- mutex_unlock(&mgr->dsp_firmware_lock);
- return ret;
+ goto error;
+ ret = gxp_firmware_authenticate(gxp, core_firmware);
+ if (ret)
+ goto error;
-err_authenticate_firmware:
+ return 0;
+error:
for (core = 0; core < GXP_NUM_CORES; core++) {
- release_firmware(mgr->firmwares[core]);
- mgr->firmwares[core] = NULL;
+ release_firmware(core_firmware[core]);
+ core_firmware[core] = NULL;
}
- mutex_unlock(&mgr->dsp_firmware_lock);
return ret;
}
@@ -811,7 +756,7 @@ static void enable_core_interrupts(struct gxp_dev *gxp, uint core)
gxp_write_32(gxp, GXP_CORE_REG_DEDICATED_INT_MASK(core), 0xffffffff);
}
-static void disable_core_interrupts(struct gxp_dev *gxp, uint core)
+void gxp_firmware_disable_ext_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);
@@ -831,31 +776,24 @@ static int gxp_firmware_setup(struct gxp_dev *gxp,
int ret = 0;
struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
- if (gxp_core_boot && mgr->firmware_running & BIT(phys_core)) {
+ if (gxp_core_boot(gxp) && mgr->firmware_running & BIT(phys_core)) {
dev_err(gxp->dev, "Firmware is already running on core %u\n",
phys_core);
return -EBUSY;
}
- ret = gxp_firmware_load(gxp, vd, core);
- if (ret) {
- 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) {
+ if (gxp_core_boot(gxp)) {
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, phys_core);
@@ -889,7 +827,7 @@ static int gxp_firmware_finish_startup(struct gxp_dev *gxp,
int ret = 0;
uint core = select_core(vd, virt_core, phys_core);
- if (gxp_core_boot) {
+ if (gxp_core_boot(gxp)) {
ret = gxp_firmware_handshake(gxp, vd, core, phys_core);
if (ret) {
dev_err(gxp->dev,
@@ -931,9 +869,8 @@ static int gxp_firmware_finish_startup(struct gxp_dev *gxp,
return ret;
err_firmware_off:
- if (gxp_core_boot)
+ if (gxp_core_boot(gxp))
gxp_pm_core_off(gxp, phys_core);
- gxp_firmware_unload(gxp, core);
return ret;
}
@@ -943,7 +880,7 @@ static void gxp_firmware_stop_core(struct gxp_dev *gxp,
{
struct gxp_firmware_manager *mgr = gxp->firmware_mgr;
- if (gxp_core_boot && !(mgr->firmware_running & BIT(phys_core)))
+ if (gxp_core_boot(gxp) && !(mgr->firmware_running & BIT(phys_core)))
dev_err(gxp->dev, "Firmware is not running on core %u\n",
phys_core);
@@ -954,7 +891,7 @@ static void gxp_firmware_stop_core(struct gxp_dev *gxp,
gxp_notification_unregister_handler(gxp, phys_core,
HOST_NOTIF_CORE_TELEMETRY_STATUS);
- if (gxp_core_boot) {
+ if (gxp_core_boot(gxp)) {
if (gxp->mailbox_mgr->release_mailbox) {
gxp->mailbox_mgr->release_mailbox(
gxp->mailbox_mgr, vd, virt_core,
@@ -968,12 +905,10 @@ static void gxp_firmware_stop_core(struct gxp_dev *gxp,
* Disable interrupts to prevent cores from being woken up
* unexpectedly.
*/
- disable_core_interrupts(gxp, phys_core);
+ gxp_firmware_disable_ext_interrupts(gxp, phys_core);
gxp_pm_core_off(gxp, phys_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,
@@ -1007,14 +942,11 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd,
*/
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)
+ if (gxp_core_boot(gxp))
gxp_pm_core_off(gxp, phys_core);
- gxp_firmware_unload(gxp, core);
}
virt_core++;
}
@@ -1034,7 +966,7 @@ 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 */
- if (gxp_core_boot) {
+ if (gxp_core_boot(gxp)) {
gxp_pm_force_clkmux_normal(gxp);
gxp_firmware_wakeup_cores(gxp, core_list);
}
@@ -1065,7 +997,7 @@ 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 */
- if (gxp_core_boot)
+ if (gxp_core_boot(gxp))
gxp_pm_resume_clkmux(gxp);
return ret;
@@ -1138,3 +1070,8 @@ u32 gxp_firmware_get_boot_status(struct gxp_dev *gxp,
core_cfg = get_scratchpad_base(gxp, vd, core);
return core_cfg->boot_status;
}
+
+bool gxp_core_boot(struct gxp_dev *gxp)
+{
+ return gxp_is_direct_mode(gxp);
+}