diff options
author | Aurora zuma automerger <aurora-zuma-automerger@google.com> | 2023-03-09 14:01:01 +0000 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-03-09 22:31:08 -0800 |
commit | 19425405130ee51277b94acf9e5599f00b5c014a (patch) | |
tree | 9dc0cde488139285faa80ff8abe9194db691b127 | |
parent | 7fd75e876ae0bcbd3d47f777b0de8774a165238f (diff) | |
download | zuma-19425405130ee51277b94acf9e5599f00b5c014a.tar.gz |
gxp: [Copybara Auto Merge] Merge branch 'zuma' into 'android14-gs-pixel-5.15'
gcip: Make gcip_pm_{get_count,is_powered} lockless
Bug: 271756295
gcip: generalize mem_pool
GCIP_HEADERS_REV_ID: 5ac83c6a2c630e09be378f657bd8be9bc0523b34
gxp: rollback GPL change for gsa_image_auth
Bug: 271797962
gcip: Make gcip_pm_{get_count,is_powered} lockless
Bug: 271756295 (repeat)
gcip: generalize mem_pool
gcip: utilize mock files on unittests
Bug: 272216562
GCIP_MAIN_REV_ID: a5b6843ab58f30d6ce086016214cbf56a46610a8
gxp: use GPL-2.0-only license
Bug: 271797962 (repeat)
gxp: not program MCU iremap and doobell in TZ priv
Bug: 260533620
gxp: authenticates firmware through GSA
Bug: 260533620 (repeat)
gxp: Enable debug dump for imageconfig 2.
Bug: 271371895
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_MAIN_REV_ID: 210c9f18b07dff1f6eee8deadb571619c9d8d864
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_HEADERS_REV_ID: 97eb89f481a48030259ec90691ff4b5126a463c2
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: minor style fixes
gxp: fix memory leak of eventfd
Bug: 270657146
gxp: remove checks of data_mgr
gxp: skip mapping core resources in MCU mode
gxp: add gxp_firmware_loader module
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_MAIN_REV_ID: 92addd19b0b6f01ca127402d29f862d26895add4
gcip: Add level -3 (FATAL) for firmware log
Bug: 271596603 (repeat)
gcip: Update outdated comments
gcip: Postfix gcip_firmware_tracing_restore
GCIP_HEADERS_REV_ID: 3e296e62e800e70f68fa4bd63504394dce0f2e75
GitOrigin-RevId: b83c2bc8112562304e23fd28c0dbd3c97e076476
Change-Id: I9ebcdf6b813d321ab467a7a23a95e897c504dca0
73 files changed, 979 insertions, 522 deletions
diff --git a/BUILD.bazel b/BUILD.bazel index 09ef4d0..8ee7a98 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: GPL-2.0-only load("//build/kernel/kleaf:kernel.bzl", "kernel_module") @@ -22,6 +22,7 @@ gxp-objs += \ gxp-doorbell.o \ gxp-eventfd.o \ gxp-firmware-data.o \ + gxp-firmware-loader.o \ gxp-firmware.o \ gxp-lpm.o \ gxp-mailbox-manager.o \ diff --git a/callisto-platform.c b/callisto-platform.c index 0d006c2..8ccd526 100644 --- a/callisto-platform.c +++ b/callisto-platform.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Platform device driver for Callisto. * diff --git a/callisto-platform.h b/callisto-platform.h index e7d017e..ea6d3d3 100644 --- a/callisto-platform.h +++ b/callisto-platform.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Platform device driver for Callisto. * diff --git a/callisto/config-pwr-state.h b/callisto/config-pwr-state.h index 5558765..548442f 100644 --- a/callisto/config-pwr-state.h +++ b/callisto/config-pwr-state.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Chip-dependent power configuration and states. * diff --git a/callisto/config.h b/callisto/config.h index 9be1ef5..cc8ffb5 100644 --- a/callisto/config.h +++ b/callisto/config.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Include all configuration files for Callisto. * diff --git a/callisto/context.h b/callisto/context.h index 94f98be..ec0f4f6 100644 --- a/callisto/context.h +++ b/callisto/context.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Callisto context related macros. * diff --git a/callisto/csrs.h b/callisto/csrs.h index f1bfcd1..df58916 100644 --- a/callisto/csrs.h +++ b/callisto/csrs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Callisto CSR definitions. * diff --git a/callisto/iova.h b/callisto/iova.h index 0a81a56..bc55c6c 100644 --- a/callisto/iova.h +++ b/callisto/iova.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP IOVAs. The list of addresses for fixed device-side IOVAs * diff --git a/callisto/lpm.h b/callisto/lpm.h index a2716db..81115d9 100644 --- a/callisto/lpm.h +++ b/callisto/lpm.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Callisto LPM chip-dependent settings. * diff --git a/callisto/mailbox-regs.h b/callisto/mailbox-regs.h index c90bafa..6baefed 100644 --- a/callisto/mailbox-regs.h +++ b/callisto/mailbox-regs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP mailbox registers. * diff --git a/gcip-kernel-driver/drivers/gcip/Makefile b/gcip-kernel-driver/drivers/gcip/Makefile index c47f1c5..7de0874 100644 --- a/gcip-kernel-driver/drivers/gcip/Makefile +++ b/gcip-kernel-driver/drivers/gcip/Makefile @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: GPL-2.0-only # # Makefile for GCIP framework. # @@ -24,6 +24,8 @@ ccflags-y += -I$(CURRENT_DIR)/../../include ifdef CONFIG_GCIP_TEST obj-y += unittests/ +include $(srctree)/drivers/gcip/unittests/Makefile.include +$(call include_test_path, $(gcip-objs)) endif modules modules_install clean: diff --git a/gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c b/gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c index 85af8e5..4008dff 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GCIP helpers for allocating memories. * diff --git a/gcip-kernel-driver/drivers/gcip/gcip-dma-fence.c b/gcip-kernel-driver/drivers/gcip/gcip-dma-fence.c index 4f83670..ca49526 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-dma-fence.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-dma-fence.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GCIP support of DMA fences. * diff --git a/gcip-kernel-driver/drivers/gcip/gcip-domain-pool.c b/gcip-kernel-driver/drivers/gcip/gcip-domain-pool.c index c3c41ea..882aa80 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-domain-pool.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-domain-pool.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GCIP IOMMU domain allocator. * @@ -60,7 +60,7 @@ struct iommu_domain *gcip_domain_pool_alloc(struct gcip_domain_pool *pool) if (!pool->size) { ddomain = vzalloc(sizeof(*ddomain)); if (!ddomain) - return ERR_PTR(-ENOMEM); + return NULL; ddomain->domain = iommu_domain_alloc(pool->dev->bus); if (!ddomain->domain) { diff --git a/gcip-kernel-driver/drivers/gcip/gcip-firmware.c b/gcip-kernel-driver/drivers/gcip/gcip-firmware.c index 1d9392c..52c3940 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-firmware.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-firmware.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GCIP firmware interface. * @@ -136,7 +136,7 @@ void gcip_firmware_tracing_destroy(struct gcip_fw_tracing *fw_tracing) kfree(fw_tracing); } -int gcip_firmware_tracing_restore(struct gcip_fw_tracing *fw_tracing) +int gcip_firmware_tracing_restore_on_powering(struct gcip_fw_tracing *fw_tracing) { int ret = 0; diff --git a/gcip-kernel-driver/drivers/gcip/gcip-image-config.c b/gcip-kernel-driver/drivers/gcip/gcip-image-config.c index 62acd0b..98a3546 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-image-config.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-image-config.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Framework for parsing the firmware image configuration. * diff --git a/gcip-kernel-driver/drivers/gcip/gcip-kci.c b/gcip-kernel-driver/drivers/gcip/gcip-kci.c index 15b2c53..c3da416 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-kci.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-kci.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Kernel Control Interface, implements the protocol between AP kernel and GCIP firmware. * diff --git a/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c b/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c index 334a51d..6d20771 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GCIP Mailbox Interface. * diff --git a/gcip-kernel-driver/drivers/gcip/gcip-mem-pool.c b/gcip-kernel-driver/drivers/gcip/gcip-mem-pool.c index 3e18051..564991b 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-mem-pool.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-mem-pool.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * A simple memory allocator to help allocating reserved memory pools. * @@ -12,21 +12,21 @@ #include <gcip/gcip-mem-pool.h> -int gcip_mem_pool_init(struct gcip_mem_pool *pool, struct device *dev, phys_addr_t base_paddr, +int gcip_mem_pool_init(struct gcip_mem_pool *pool, struct device *dev, unsigned long base_addr, size_t size, size_t granule) { int ret; - if (!base_paddr || granule == 0) + if (!base_addr || granule == 0) return -EINVAL; - if (base_paddr % granule || size % granule) + if (base_addr % granule || size % granule) return -EINVAL; pool->gen_pool = gen_pool_create(ilog2(granule), -1); if (!pool->gen_pool) { dev_err(dev, "gcip memory pool allocate gen_pool failed"); return -ENOMEM; } - ret = gen_pool_add(pool->gen_pool, base_paddr, size, -1); + ret = gen_pool_add(pool->gen_pool, base_addr, size, -1); if (ret) { gen_pool_destroy(pool->gen_pool); pool->gen_pool = NULL; @@ -35,7 +35,7 @@ int gcip_mem_pool_init(struct gcip_mem_pool *pool, struct device *dev, phys_addr } pool->dev = dev; pool->granule = granule; - pool->base_paddr = base_paddr; + pool->base_addr = base_addr; return 0; } @@ -47,23 +47,20 @@ void gcip_mem_pool_exit(struct gcip_mem_pool *pool) pool->gen_pool = NULL; } -phys_addr_t gcip_mem_pool_alloc(struct gcip_mem_pool *pool, size_t size) +unsigned long gcip_mem_pool_alloc(struct gcip_mem_pool *pool, size_t size) { unsigned long addr; - size_t aligned_size = ALIGN(size, pool->granule); - addr = gen_pool_alloc(pool->gen_pool, aligned_size); + addr = gen_pool_alloc(pool->gen_pool, size); if (!addr) return 0; - dev_dbg(pool->dev, "%s @ size = %#zx paddr=%#lx", __func__, size, addr); - return (phys_addr_t)addr; + dev_dbg(pool->dev, "%s @ size = %#zx addr=%#lx", __func__, size, addr); + return addr; } -void gcip_mem_pool_free(struct gcip_mem_pool *pool, phys_addr_t paddr, size_t size) +void gcip_mem_pool_free(struct gcip_mem_pool *pool, unsigned long addr, size_t size) { - unsigned long addr = paddr; - - dev_dbg(pool->dev, "%s @ size = %#zx paddr=%#lx", __func__, size, addr); + dev_dbg(pool->dev, "%s @ size = %#zx addr=%#lx", __func__, size, addr); size = ALIGN(size, pool->granule); gen_pool_free(pool->gen_pool, addr, size); } diff --git a/gcip-kernel-driver/drivers/gcip/gcip-pm.c b/gcip-kernel-driver/drivers/gcip/gcip-pm.c index 54589e0..b9907a1 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-pm.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-pm.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Power management interface for GCIP devices. * @@ -113,8 +113,10 @@ static int gcip_pm_get_locked(struct gcip_pm *pm) gcip_pm_lockdep_assert_held(pm); if (!pm->count) { - pm->power_down_pending = false; - ret = pm->power_up(pm->data); + if (pm->power_down_pending) + pm->power_down_pending = false; + else + ret = pm->power_up(pm->data); } if (!ret) @@ -163,7 +165,7 @@ int gcip_pm_get(struct gcip_pm *pm) return ret; } -static void __gcip_pm_put(struct gcip_pm *pm, bool async) +void gcip_pm_put(struct gcip_pm *pm) { if (!pm) return; @@ -175,10 +177,7 @@ static void __gcip_pm_put(struct gcip_pm *pm, bool async) if (!--pm->count) { pm->power_down_pending = true; - if (async) - schedule_delayed_work(&pm->power_down_work, 0); - else - gcip_pm_try_power_down(pm); + gcip_pm_try_power_down(pm); } dev_dbg(pm->dev, "%s: %d\n", __func__, pm->count); @@ -187,29 +186,12 @@ unlock: mutex_unlock(&pm->lock); } -void gcip_pm_put(struct gcip_pm *pm) -{ - __gcip_pm_put(pm, false); -} - -void gcip_pm_put_async(struct gcip_pm *pm) -{ - __gcip_pm_put(pm, true); -} - int gcip_pm_get_count(struct gcip_pm *pm) { - int count = -EAGAIN; - if (!pm) return 0; - if (mutex_trylock(&pm->lock)) { - count = pm->count; - mutex_unlock(&pm->lock); - } - - return count; + return pm->count; } bool gcip_pm_is_powered(struct gcip_pm *pm) diff --git a/gcip-kernel-driver/drivers/gcip/gcip-telemetry.c b/gcip-kernel-driver/drivers/gcip/gcip-telemetry.c index f557c24..1599889 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-telemetry.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-telemetry.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GCIP telemetry: logging and tracing. * @@ -126,6 +126,7 @@ void gcip_telemetry_fw_log(struct gcip_telemetry *log) case GCIP_FW_LOG_LEVEL_WARN: dev_warn(dev, "%s", buffer); break; + case GCIP_FW_LOG_LEVEL_FATAL: case GCIP_FW_LOG_LEVEL_ERROR: dev_err(dev, "%s", buffer); break; diff --git a/gcip-kernel-driver/drivers/gcip/gcip-thermal.c b/gcip-kernel-driver/drivers/gcip/gcip-thermal.c index 5afa65e..bc06cd5 100644 --- a/gcip-kernel-driver/drivers/gcip/gcip-thermal.c +++ b/gcip-kernel-driver/drivers/gcip/gcip-thermal.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Thermal management support for GCIP devices. * @@ -188,7 +188,7 @@ static void gcip_thermal_update(struct gcip_thermal *thermal) #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0) || IS_ENABLED(CONFIG_ANDROID) thermal_cdev_update(cdev); #elif IS_ENABLED(CONFIG_THERMAL) - dev_err_once(dev, "Thermal update not implemented"); + dev_err_once(thermal->dev, "Thermal update not implemented"); #endif } diff --git a/gcip-kernel-driver/include/gcip/gcip-alloc-helper.h b/gcip-kernel-driver/include/gcip/gcip-alloc-helper.h index 3d2c110..17208bf 100644 --- a/gcip-kernel-driver/include/gcip/gcip-alloc-helper.h +++ b/gcip-kernel-driver/include/gcip/gcip-alloc-helper.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GCIP helpers for allocating memories. * diff --git a/gcip-kernel-driver/include/gcip/gcip-common-image-header.h b/gcip-kernel-driver/include/gcip/gcip-common-image-header.h index d986fbc..b86b430 100644 --- a/gcip-kernel-driver/include/gcip/gcip-common-image-header.h +++ b/gcip-kernel-driver/include/gcip/gcip-common-image-header.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Common authenticated image format for Google SoCs * diff --git a/gcip-kernel-driver/include/gcip/gcip-dma-fence.h b/gcip-kernel-driver/include/gcip/gcip-dma-fence.h index 1d4030a..ad765d2 100644 --- a/gcip-kernel-driver/include/gcip/gcip-dma-fence.h +++ b/gcip-kernel-driver/include/gcip/gcip-dma-fence.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GCIP support of DMA fences. * diff --git a/gcip-kernel-driver/include/gcip/gcip-domain-pool.h b/gcip-kernel-driver/include/gcip/gcip-domain-pool.h index a5441a9..3a6ae4b 100644 --- a/gcip-kernel-driver/include/gcip/gcip-domain-pool.h +++ b/gcip-kernel-driver/include/gcip/gcip-domain-pool.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GCIP IOMMU domain allocator. * diff --git a/gcip-kernel-driver/include/gcip/gcip-firmware.h b/gcip-kernel-driver/include/gcip/gcip-firmware.h index b48317b..52f5d11 100644 --- a/gcip-kernel-driver/include/gcip/gcip-firmware.h +++ b/gcip-kernel-driver/include/gcip/gcip-firmware.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GCIP firmware interface. * @@ -84,7 +84,9 @@ struct gcip_fw_tracing { * Lock to protect the struct members listed below. * * Note that since the request of tracing level adjusting might happen during power state - * transitions, this lock must be acquired after holding the pm lock to avoid deadlock. + * transitions (i.e., another thread calling gcip_firmware_tracing_restore_on_powering() + * with pm lock held), one must either use the non-blocking gcip_pm_get_if_powered() or make + * sure there won't be any new power transition after holding this lock to prevent deadlock. */ struct mutex lock; /* Actual firmware tracing level. */ @@ -127,6 +129,6 @@ void gcip_firmware_tracing_destroy(struct gcip_fw_tracing *fw_tracing); * This function is designed to restore the firmware tracing level during power management calls and * thus it assumes the caller holds the pm lock. */ -int gcip_firmware_tracing_restore(struct gcip_fw_tracing *fw_tracing); +int gcip_firmware_tracing_restore_on_powering(struct gcip_fw_tracing *fw_tracing); #endif /* __GCIP_FIRMWARE_H__ */ diff --git a/gcip-kernel-driver/include/gcip/gcip-image-config.h b/gcip-kernel-driver/include/gcip/gcip-image-config.h index bcc506f..df09d39 100644 --- a/gcip-kernel-driver/include/gcip/gcip-image-config.h +++ b/gcip-kernel-driver/include/gcip/gcip-image-config.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Framework for parsing the firmware image configuration. * diff --git a/gcip-kernel-driver/include/gcip/gcip-kci.h b/gcip-kernel-driver/include/gcip/gcip-kci.h index 03cc078..eb83550 100644 --- a/gcip-kernel-driver/include/gcip/gcip-kci.h +++ b/gcip-kernel-driver/include/gcip/gcip-kci.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Kernel Control Interface, implements the protocol between AP kernel and GCIP firmware. * diff --git a/gcip-kernel-driver/include/gcip/gcip-mailbox.h b/gcip-kernel-driver/include/gcip/gcip-mailbox.h index 649b574..c88d2d7 100644 --- a/gcip-kernel-driver/include/gcip/gcip-mailbox.h +++ b/gcip-kernel-driver/include/gcip/gcip-mailbox.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GCIP Mailbox Interface. * diff --git a/gcip-kernel-driver/include/gcip/gcip-mem-pool.h b/gcip-kernel-driver/include/gcip/gcip-mem-pool.h index c770300..44ea5f5 100644 --- a/gcip-kernel-driver/include/gcip/gcip-mem-pool.h +++ b/gcip-kernel-driver/include/gcip/gcip-mem-pool.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * A simple memory allocator to help allocating reserved memory pools. * @@ -15,7 +15,7 @@ struct gcip_mem_pool { struct device *dev; struct gen_pool *gen_pool; - phys_addr_t base_paddr; + unsigned long base_addr; size_t granule; }; @@ -24,8 +24,7 @@ struct gcip_mem_pool { * * @pool: The memory pool object to be initialized. * @dev: Used for logging only. - * @base_paddr: The base physical address of the pool. Must be greater than 0 and a multiple of - * @granule. + * @base_addr: The base address of the pool. Must be greater than 0 and a multiple of @granule. * @size: The size of the pool. @size should be a multiple of @granule. * @granule: The granule when invoking the allocator. Should be a power of 2. * @@ -33,7 +32,7 @@ struct gcip_mem_pool { * * Call gcip_mem_pool_exit() to release the resources of @pool. */ -int gcip_mem_pool_init(struct gcip_mem_pool *pool, struct device *dev, phys_addr_t base_paddr, +int gcip_mem_pool_init(struct gcip_mem_pool *pool, struct device *dev, unsigned long base_addr, size_t size, size_t granule); /* * Releases resources of @pool. @@ -44,28 +43,28 @@ int gcip_mem_pool_init(struct gcip_mem_pool *pool, struct device *dev, phys_addr void gcip_mem_pool_exit(struct gcip_mem_pool *pool); /* - * Allocates and returns the allocated physical address. + * Allocates and returns the allocated address. * * @size: Size to be allocated. * * Returns the allocated address. Returns 0 on allocation failure. */ -phys_addr_t gcip_mem_pool_alloc(struct gcip_mem_pool *pool, size_t size); +unsigned long gcip_mem_pool_alloc(struct gcip_mem_pool *pool, size_t size); /* * Returns the address previously allocated by gcip_mem_pool_alloc(). * * The size and address must match what previously passed to / returned by gcip_mem_pool_alloc(). */ -void gcip_mem_pool_free(struct gcip_mem_pool *pool, phys_addr_t paddr, size_t size); +void gcip_mem_pool_free(struct gcip_mem_pool *pool, unsigned long addr, size_t size); /* - * Returns the offset between @paddr and @base_paddr passed to gcip_mem_pool_init(). + * Returns the offset between @addr and @base_addr passed to gcip_mem_pool_init(). * - * @paddr must be a value returned by gcip_mem_pool_alloc(). + * @addr must be a value returned by gcip_mem_pool_alloc(). */ -static inline size_t gcip_mem_pool_offset(struct gcip_mem_pool *pool, phys_addr_t paddr) +static inline size_t gcip_mem_pool_offset(struct gcip_mem_pool *pool, unsigned long addr) { - return paddr - pool->base_paddr; + return addr - pool->base_addr; } #endif /* __GCIP_MEM_POOL_H__ */ diff --git a/gcip-kernel-driver/include/gcip/gcip-pm.h b/gcip-kernel-driver/include/gcip/gcip-pm.h index c7673d8..af0fb31 100644 --- a/gcip-kernel-driver/include/gcip/gcip-pm.h +++ b/gcip-kernel-driver/include/gcip/gcip-pm.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Power management support for GCIP devices. * @@ -97,17 +97,10 @@ int gcip_pm_get(struct gcip_pm *pm); */ void gcip_pm_put(struct gcip_pm *pm); -/* - * Same as gcip_pm_put, but the power off will be scheduled later. - * Caller should use this async gcip_pm_put if they're on the power off path to prevent deadlock, - * e.g., a workqueue that will be canceled during power off. - */ -void gcip_pm_put_async(struct gcip_pm *pm); - -/* Gets the power up counter. Retures -EAGAIN if device is in power state transition. */ +/* Gets the power up counter. Note that this is checked without PM lock. */ int gcip_pm_get_count(struct gcip_pm *pm); -/* Checks if device is already on. Retures false if device is off or in power state transition. */ +/* Checks if device is already on. Note that this is checked without PM lock. */ bool gcip_pm_is_powered(struct gcip_pm *pm); /* Shuts down the device if @pm->count equals to 0 or @force is true. */ @@ -122,4 +115,29 @@ static inline void gcip_pm_lockdep_assert_held(struct gcip_pm *pm) lockdep_assert_held(&pm->lock); } +/* + * Lock the PM lock. + * Returns 1 if the lock has been acquired successfully, and 0 on contention. + * Since all the PM requests will be blocked until gcip_pm_unlock is called, one should use the + * gcip_pm_{get,get_if_powered,put} if possible and uses this only if a power state transition can + * not be triggered, e.g., in a workqueue that will be canceled during power off. + */ +static inline int gcip_pm_trylock(struct gcip_pm *pm) +{ + if (!pm) + return 1; + + return mutex_trylock(&pm->lock); +} + +/* Unlock the PM lock. */ +static inline void gcip_pm_unlock(struct gcip_pm *pm) +{ + if (!pm) + return; + + lockdep_assert_held(&pm->lock); + mutex_unlock(&pm->lock); +} + #endif /* __GCIP_PM_H__ */ diff --git a/gcip-kernel-driver/include/gcip/gcip-telemetry.h b/gcip-kernel-driver/include/gcip/gcip-telemetry.h index 4556291..ad26ee9 100644 --- a/gcip-kernel-driver/include/gcip/gcip-telemetry.h +++ b/gcip-kernel-driver/include/gcip/gcip-telemetry.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GCIP telemetry: logging and tracing. * @@ -22,6 +22,7 @@ #define GCIP_FW_LOG_LEVEL_INFO (0) #define GCIP_FW_LOG_LEVEL_WARN (-1) #define GCIP_FW_LOG_LEVEL_ERROR (-2) +#define GCIP_FW_LOG_LEVEL_FATAL (-3) #define GCIP_FW_DMESG_LOG_LEVEL (GCIP_FW_LOG_LEVEL_WARN) diff --git a/gcip-kernel-driver/include/gcip/gcip-thermal.h b/gcip-kernel-driver/include/gcip/gcip-thermal.h index f742705..7c9ebc4 100644 --- a/gcip-kernel-driver/include/gcip/gcip-thermal.h +++ b/gcip-kernel-driver/include/gcip/gcip-thermal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Thermal management support for GCIP devices. * @@ -37,9 +37,9 @@ struct gcip_thermal { * Lock to protect the struct members listed below. * * Note that since the request of thermal state adjusting might happen during power state - * transitions (i.e., another thread calling gcip_thermal_restore() with pm lock held), one - * must either use the non-blocking gcip_pm_get_if_powered() or make sure there won't be any - * new power transition after holding this thermal lock to prevent deadlock. + * transitions (i.e., another thread calling gcip_thermal_restore_on_powering() with pm lock + * held), one must either use the non-blocking gcip_pm_get_if_powered() or make sure there + * won't be any new power transition after holding this thermal lock to prevent deadlock. */ struct mutex lock; unsigned long num_states; diff --git a/gsx01-mailbox-driver.c b/gsx01-mailbox-driver.c index f0090f4..9876998 100644 --- a/gsx01-mailbox-driver.c +++ b/gsx01-mailbox-driver.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GXP hardware-based mailbox csr driver implementation for GSX01. * diff --git a/gxp-common-platform.c b/gxp-common-platform.c index 9a54a6d..694a2a8 100644 --- a/gxp-common-platform.c +++ b/gxp-common-platform.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GXP platform driver utilities. * @@ -37,6 +37,7 @@ #include "gxp-domain-pool.h" #include "gxp-firmware.h" #include "gxp-firmware-data.h" +#include "gxp-firmware-loader.h" #include "gxp-internal.h" #include "gxp-lpm.h" #include "gxp-mailbox.h" @@ -145,13 +146,10 @@ static int gxp_open(struct inode *inode, struct file *file) misc_dev); int ret = 0; - /* If this is the first call to open(), request the firmware files */ - ret = gxp_firmware_request_if_needed(gxp); - if (ret) { - dev_err(gxp->dev, - "Failed to request dsp firmware files (ret=%d)\n", ret); + /* If this is the first call to open(), load the firmware files */ + ret = gxp_firmware_loader_load_if_needed(gxp); + if (ret) return ret; - } client = gxp_client_create(gxp); if (IS_ERR(client)) @@ -2063,6 +2061,12 @@ static int gxp_common_platform_probe(struct platform_device *pdev, struct gxp_de goto err_domain_pool_destroy; } + ret = gxp_firmware_loader_init(gxp); + if (ret) { + dev_err(dev, "Failed to initialize firmware loader (ret=%d)\n", + ret); + goto err_fw_destroy; + } gxp_dma_init_default_resources(gxp); gxp_vd_init(gxp); @@ -2134,6 +2138,8 @@ err_fw_data_destroy: gxp_fw_data_destroy(gxp); err_vd_destroy: gxp_vd_destroy(gxp); + gxp_firmware_loader_destroy(gxp); +err_fw_destroy: gxp_fw_destroy(gxp); err_domain_pool_destroy: gxp_domain_pool_destroy(gxp->domain_pool); @@ -2164,6 +2170,7 @@ static int gxp_common_platform_remove(struct platform_device *pdev) gxp_core_telemetry_exit(gxp); gxp_fw_data_destroy(gxp); gxp_vd_destroy(gxp); + gxp_firmware_loader_destroy(gxp); gxp_fw_destroy(gxp); gxp_domain_pool_destroy(gxp->domain_pool); kfree(gxp->domain_pool); diff --git a/gxp-config.h b/gxp-config.h index 2987a8f..f20d587 100644 --- a/gxp-config.h +++ b/gxp-config.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Include all configuration files for GXP. * diff --git a/gxp-core-telemetry.c b/gxp-core-telemetry.c index bce27c6..2b76ef2 100644 --- a/gxp-core-telemetry.c +++ b/gxp-core-telemetry.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GXP core telemetry support * diff --git a/gxp-core-telemetry.h b/gxp-core-telemetry.h index 9a89c0e..0ceeb60 100644 --- a/gxp-core-telemetry.h +++ b/gxp-core-telemetry.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP core telemetry support * @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Implementation of DCI (Direct Command Interface) using mailbox. * @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Implementation of DCI (Direct Command Interface) using mailbox. * diff --git a/gxp-debug-dump.c b/gxp-debug-dump.c index 94ae78b..9d1ea21 100644 --- a/gxp-debug-dump.c +++ b/gxp-debug-dump.c @@ -19,12 +19,15 @@ #endif #include <gcip/gcip-pm.h> +#include <gcip/gcip-alloc-helper.h> #include "gxp-client.h" #include "gxp-debug-dump.h" #include "gxp-dma.h" #include "gxp-doorbell.h" #include "gxp-firmware.h" +#include "gxp-firmware-data.h" +#include "gxp-firmware-loader.h" #include "gxp-host-device-structs.h" #include "gxp-internal.h" #include "gxp-lpm.h" @@ -39,6 +42,13 @@ #define DEBUG_DUMP_MEMORY_SIZE 0x400000 /* size in bytes */ +/* + * CORE_FIRMWARE_RW_STRIDE & CORE_FIRMWARE_RW_ADDR must match with their + * values defind in core firmware image config. + */ +#define CORE_FIRMWARE_RW_STRIDE 0x200000 /* 2 MB */ +#define CORE_FIRMWARE_RW_ADDR(x) (0xFA400000 + CORE_FIRMWARE_RW_STRIDE * x) + /* Enum indicating the debug dump request reason. */ enum gxp_debug_dump_init_type { DEBUG_DUMP_FW_INIT, DEBUG_DUMP_KERNEL_INIT }; @@ -491,6 +501,60 @@ void gxp_debug_dump_invalidate_segments(struct gxp_dev *gxp, uint32_t core_id) core_dump_header->core_header.dump_available = 0; } +/** + * gxp_map_fw_rw_section() - Maps the fw rw section address and size to be + * sent to sscd module for taking the dump. + * @gxp: The GXP device. + * @vd: vd of the crashed client. + * @core_id: physical core_id of crashed core. + * @seg_idx: Pointer to a index that is keeping track of + * gxp->debug_dump_mgr->segs[] array. + * + * This function parses the ns_regions of the given vd to find + * fw_rw_section details. + * + * Return: + * * 0 - Successfully mapped fw_rw_section data. + * * -EOPNOTSUPP - Operation not supported for invalid image config. + * * -ENXIO - No IOVA found for the fw_rw_section. + */ +static int gxp_map_fw_rw_section(struct gxp_dev *gxp, + struct gxp_virtual_device *vd, + uint32_t core_id, int *seg_idx) +{ + size_t idx; + struct sg_table *sgt; + struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr; + dma_addr_t fw_rw_section_daddr = CORE_FIRMWARE_RW_ADDR(core_id); + const size_t n_reg = ARRAY_SIZE(vd->ns_regions); + + if (!gxp_fw_data_use_per_vd_config(vd)) { + dev_err(gxp->dev, "Unsupported Image config version = %d.", + gxp->fw_loader_mgr->core_img_cfg.config_version); + return -EOPNOTSUPP; + } + + for (idx = 0; idx < n_reg; idx++) { + sgt = vd->ns_regions[idx].sgt; + if (!sgt) + break; + + if (fw_rw_section_daddr != vd->ns_regions[idx].daddr) + continue; + + mgr->segs[core_id][*seg_idx].addr = + gcip_noncontiguous_sgt_to_mem(sgt); + mgr->segs[core_id][*seg_idx].size = gcip_ns_config_to_size( + gxp->fw_loader_mgr->core_img_cfg.ns_iommu_mappings[idx]); + *seg_idx += 1; + return 0; + } + dev_err(gxp->dev, + "fw_rw_section mapping for core %u at iova 0x%llx does not exist", + core_id, fw_rw_section_daddr); + return -ENXIO; +} + /* * Caller must make sure that gxp->debug_dump_mgr->common_dump and * gxp->debug_dump_mgr->core_dump are not NULL. @@ -571,14 +635,16 @@ static int gxp_handle_debug_dump(struct gxp_dev *gxp, ret = -EFAULT; goto out_efault; } - /* - * TODO(b/265105909): Implement the logic for collecting fw rw section - * separately for mcu mode. - */ + /* fw ro section */ mgr->segs[core_id][seg_idx].addr = gxp->fwbufs[core_id].vaddr; - mgr->segs[core_id][seg_idx].size = gxp->fwbufs[core_id].size; + mgr->segs[core_id][seg_idx].size = vd->fw_ro_size; seg_idx++; + /* fw rw section */ + ret = gxp_map_fw_rw_section(gxp, vd, core_id, &seg_idx); + if (ret) + goto out; + /* User Buffers */ user_buf_cnt = gxp_user_buffers_vmap(gxp, vd, core_header, user_buf_vaddrs); @@ -663,23 +729,12 @@ out: static void gxp_generate_debug_dump(struct gxp_dev *gxp, uint core_id, struct gxp_virtual_device *vd) { - u32 boot_mode; - bool gxp_generate_coredump_called = false; - + bool gxp_generate_coredump_called = true; mutex_lock(&gxp->debug_dump_mgr->debug_dump_lock); - /* - * TODO(b/265105909): Checks below to be verified after implementation for - * firmware loading for mcu mode are completed. - */ - boot_mode = gxp_firmware_get_boot_mode(gxp, vd, core_id); - - if (gxp_is_fw_running(gxp, core_id) && - (boot_mode == GXP_BOOT_MODE_STATUS_COLD_BOOT_COMPLETED || - boot_mode == GXP_BOOT_MODE_STATUS_RESUME_COMPLETED)) { - gxp_generate_coredump_called = true; - if (gxp_generate_coredump(gxp, vd, core_id)) - dev_err(gxp->dev, "Failed to generate coredump\n"); + if (gxp_generate_coredump(gxp, vd, core_id)) { + gxp_generate_coredump_called = false; + dev_err(gxp->dev, "Failed to generate the coredump.\n"); } /* Invalidate segments to prepare for the next debug dump trigger */ @@ -706,8 +761,14 @@ static void gxp_debug_dump_process_dump_direct_mode(struct work_struct *work) struct gxp_virtual_device *vd = NULL; down_read(&gxp->vd_semaphore); - if (gxp->core_to_vd[core_id]) + if (gxp->core_to_vd[core_id]) { vd = gxp_vd_get(gxp->core_to_vd[core_id]); + } else { + dev_err(gxp->dev, "debug dump failed for null vd on core %d.", + core_id); + up_read(&gxp->vd_semaphore); + return; + } up_read(&gxp->vd_semaphore); /* @@ -715,15 +776,12 @@ static void gxp_debug_dump_process_dump_direct_mode(struct work_struct *work) * of @vd while generating a debug dump. This will help not to block other virtual devices * proceeding their jobs. */ - if (vd) - mutex_lock(&vd->debug_dump_lock); + mutex_lock(&vd->debug_dump_lock); gxp_generate_debug_dump(gxp, core_id, vd); - if (vd) { - mutex_unlock(&vd->debug_dump_lock); - gxp_vd_put(vd); - } + mutex_unlock(&vd->debug_dump_lock); + gxp_vd_put(vd); } int gxp_debug_dump_process_dump_mcu_mode(struct gxp_dev *gxp, uint core_list, diff --git a/gxp-debugfs.c b/gxp-debugfs.c index a9a2e14..6dacde9 100644 --- a/gxp-debugfs.c +++ b/gxp-debugfs.c @@ -15,6 +15,7 @@ #include "gxp-debugfs.h" #include "gxp-dma.h" #include "gxp-firmware-data.h" +#include "gxp-firmware-loader.h" #include "gxp-firmware.h" #include "gxp-internal.h" #include "gxp-notification.h" @@ -136,9 +137,9 @@ static int gxp_firmware_run_set(void *data, u64 val) uint core; bool acquired_block_wakelock; - ret = gxp_firmware_request_if_needed(gxp); + ret = gxp_firmware_loader_load_if_needed(gxp); if (ret) { - dev_err(gxp->dev, "Unable to request dsp firmware files\n"); + dev_err(gxp->dev, "Unable to load firmware files\n"); return ret; } diff --git a/gxp-dma-fence.c b/gxp-dma-fence.c index 7bcc11b..4733081 100644 --- a/gxp-dma-fence.c +++ b/gxp-dma-fence.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GXP support for DMA fence. * diff --git a/gxp-dma-fence.h b/gxp-dma-fence.h index c7ad95e..38f8cf2 100644 --- a/gxp-dma-fence.h +++ b/gxp-dma-fence.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP support for DMA fence. * diff --git a/gxp-dma-iommu.c b/gxp-dma-iommu.c index 87bb649..ad1111b 100644 --- a/gxp-dma-iommu.c +++ b/gxp-dma-iommu.c @@ -81,7 +81,7 @@ static int gxp_dma_ssmt_program(struct gxp_dev *gxp, uint core; /* Program VID only when cores are managed by us. */ - if (gxp_is_direct_mode(gxp) || gxp_core_boot) { + if (gxp_is_direct_mode(gxp) || gxp_core_boot(gxp)) { pasid = iommu_aux_get_pasid(domain, gxp->dev); for (core = 0; core < GXP_NUM_CORES; core++) if (BIT(core) & core_list) { @@ -322,6 +322,9 @@ int gxp_dma_map_core_resources(struct gxp_dev *gxp, uint i; struct iommu_domain *domain = gdomain->domain; + if (!gxp_is_direct_mode(gxp)) + return 0; + ret = gxp_map_csrs(gxp, domain, &gxp->regs); if (ret) goto err; @@ -376,6 +379,9 @@ void gxp_dma_unmap_core_resources(struct gxp_dev *gxp, uint i; struct iommu_domain *domain = gdomain->domain; + if (!gxp_is_direct_mode(gxp)) + return; + /* Only unmap the TPU mailboxes if they were found on probe */ if (gxp->tpu_dev.mbx_paddr) { for (i = 0; i < GXP_NUM_CORES; i++) { diff --git a/gxp-firmware-data.c b/gxp-firmware-data.c index 4a35ccc..0ba2c7b 100644 --- a/gxp-firmware-data.c +++ b/gxp-firmware-data.c @@ -11,6 +11,7 @@ #include "gxp-debug-dump.h" #include "gxp-firmware-data.h" +#include "gxp-firmware-loader.h" #include "gxp-firmware.h" /* gxp_core_boot */ #include "gxp-host-device-structs.h" #include "gxp-internal.h" @@ -642,7 +643,7 @@ _gxp_fw_data_create_app(struct gxp_dev *gxp, struct gxp_virtual_device *vd) if (!app) return ERR_PTR(-ENOMEM); - if (!gxp_core_boot) { + if (!gxp_core_boot(gxp)) { dev_info(gxp->dev, "Skip setting VD and core CFG"); return app; } @@ -859,9 +860,6 @@ void gxp_fw_data_destroy(struct gxp_dev *gxp) { struct gxp_fw_data_manager *mgr = gxp->data_mgr; - if (!mgr) - return; - mem_alloc_free(mgr->allocator, &mgr->core_telemetry_mem); mem_alloc_free(mgr->allocator, &mgr->wdog_mem); mem_alloc_free(mgr->allocator, &mgr->sys_desc_mem); @@ -876,10 +874,8 @@ void gxp_fw_data_destroy(struct gxp_dev *gxp) mgr->fw_data_virt = NULL; } - if (gxp->data_mgr) { - devm_kfree(gxp->dev, gxp->data_mgr); - gxp->data_mgr = NULL; - } + devm_kfree(gxp->dev, mgr); + gxp->data_mgr = NULL; } int gxp_fw_data_set_core_telemetry_descriptors(struct gxp_dev *gxp, u8 type, @@ -967,7 +963,7 @@ u32 gxp_fw_data_get_core_telemetry_device_status(struct gxp_dev *gxp, uint core, if (core >= GXP_NUM_CORES) return 0; - if (gxp->firmware_mgr->img_cfg.config_version >= + if (gxp->fw_loader_mgr->core_img_cfg.config_version >= FW_DATA_PROTOCOL_PER_VD_CONFIG) { return _gxp_fw_data_get_core_telemetry_device_status(gxp, core, type); diff --git a/gxp-firmware-loader.c b/gxp-firmware-loader.c new file mode 100644 index 0000000..5f64bd4 --- /dev/null +++ b/gxp-firmware-loader.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GXP firmware loading management. + * + * Copyright (C) 2023 Google LLC + */ + +#include <linux/dma-mapping.h> +#include <linux/slab.h> + +#include <gcip/gcip-common-image-header.h> +#include <gcip/gcip-image-config.h> + +#include "gxp-config.h" +#include "gxp-firmware-loader.h" +#include "gxp-firmware.h" +#include "gxp-internal.h" + +#if GXP_HAS_MCU +#include <linux/gsa/gsa_dsp.h> + +#include "gxp-mcu-firmware.h" +#endif + +#if GXP_HAS_MCU +static int gxp_firmware_loader_gsa_auth(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + int ret; + uint core; + dma_addr_t headers_dma_addr; + void *header_vaddr; + const u8 *data; + struct gxp_mcu_firmware *mcu_fw = gxp_mcu_firmware_of(gxp); + + if (!mcu_fw->is_secure) { + dev_warn( + gxp->dev, + "No need to do firmware authentication with non-secure privilege\n"); + return 0; + } + if (!gxp->gsa_dev) { + dev_warn( + gxp->dev, + "No GSA device available, skipping firmware authentication\n"); + return 0; + } + /* Authenticate MCU firmware */ + header_vaddr = dma_alloc_coherent(gxp->gsa_dev, GCIP_FW_HEADER_SIZE, + &headers_dma_addr, GFP_KERNEL); + if (!header_vaddr) { + dev_err(gxp->dev, + "Failed to allocate coherent memory for header\n"); + return -ENOMEM; + } + memcpy(header_vaddr, mgr->mcu_firmware->data, GCIP_FW_HEADER_SIZE); + ret = gsa_load_dsp_fw_image(gxp->gsa_dev, headers_dma_addr, + mcu_fw->image_buf.paddr); + if (ret) { + dev_err(gxp->dev, "MCU fw GSA authentication fails"); + goto err_load_mcu_fw; + } + + for (core = 0; core < GXP_NUM_CORES; core++) { + data = mgr->core_firmware[core]->data; + /* Authenticate core firmware */ + memcpy(header_vaddr, data, GCIP_FW_HEADER_SIZE); + ret = gsa_load_dsp_fw_image(gxp->gsa_dev, headers_dma_addr, + gxp->fwbufs[core].paddr); + if (ret) { + dev_err(gxp->dev, + "Core %u firmware authentication fails", core); + goto err_load_core_fw; + } + } + dma_free_coherent(gxp->gsa_dev, GCIP_FW_HEADER_SIZE, header_vaddr, + headers_dma_addr); + return 0; +err_load_core_fw: + gsa_unload_dsp_fw_image(gxp->gsa_dev); +err_load_mcu_fw: + dma_free_coherent(gxp->gsa_dev, GCIP_FW_HEADER_SIZE, header_vaddr, + headers_dma_addr); + return ret; +} + +static void gxp_firmware_loader_gsa_unload(struct gxp_dev *gxp) +{ + struct gxp_mcu_firmware *mcu_fw = gxp_mcu_firmware_of(gxp); + + if (mcu_fw->is_secure) + gsa_unload_dsp_fw_image(gxp->gsa_dev); +} +#endif /* GXP_HAS_MCU */ + +int gxp_firmware_loader_init(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr; + + mgr = devm_kzalloc(gxp->dev, sizeof(*mgr), GFP_KERNEL); + if (!mgr) + return -ENOMEM; + gxp->fw_loader_mgr = mgr; + mutex_init(&mgr->lock); + return 0; +} + +void gxp_firmware_loader_destroy(struct gxp_dev *gxp) +{ + gxp_firmware_loader_unload(gxp); +} + +void gxp_firmware_loader_set_core_fw_name(struct gxp_dev *gxp, + const char *fw_name) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + + mutex_lock(&mgr->lock); + mgr->core_firmware_name = kstrdup(fw_name, GFP_KERNEL); + mutex_unlock(&mgr->lock); +} + +char *gxp_firmware_loader_get_core_fw_name(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + char *name; + + mutex_lock(&mgr->lock); + if (mgr->core_firmware_name) + name = kstrdup(mgr->core_firmware_name, GFP_KERNEL); + else + name = kstrdup(DSP_FIRMWARE_DEFAULT_PREFIX, GFP_KERNEL); + mutex_unlock(&mgr->lock); + return name; +} + +/* + * Fetches and records image config of the first core firmware. + */ +static void gxp_firmware_loader_get_core_image_config(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + struct gcip_common_image_header *hdr = + (struct gcip_common_image_header *)mgr->core_firmware[0]->data; + struct gcip_image_config *cfg; + + if (unlikely(mgr->core_firmware[0]->size < GCIP_FW_HEADER_SIZE)) + return; + cfg = get_image_config_from_hdr(hdr); + if (cfg) + mgr->core_img_cfg = *cfg; + else + dev_warn(gxp->dev, + "Core 0 Firmware doesn't have a valid image config"); +} + +/* + * Call this function when mgr->core_firmware have been populated. + * This function sets is_loaded to true. + * + */ +static void gxp_firmware_loader_has_loaded(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + + lockdep_assert_held(&mgr->lock); + gxp_firmware_loader_get_core_image_config(gxp); + mgr->is_loaded = true; +} + +static void gxp_firmware_loader_unload_core_firmware(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + uint core; + + lockdep_assert_held(&mgr->lock); + for (core = 0; core < GXP_NUM_CORES; core++) { + if (mgr->core_firmware[core]) { + release_firmware(mgr->core_firmware[core]); + mgr->core_firmware[core] = NULL; + } + } + kfree(mgr->core_firmware_name); + mgr->core_firmware_name = NULL; +} + +#if GXP_HAS_MCU +static void gxp_firmware_loader_unload_mcu_firmware(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + + lockdep_assert_held(&mgr->lock); + if (!gxp_is_direct_mode(gxp)) { + if (mgr->mcu_firmware) { + gxp_mcu_firmware_unload(gxp, mgr->mcu_firmware); + release_firmware(mgr->mcu_firmware); + mgr->mcu_firmware = NULL; + } + kfree(mgr->mcu_firmware_name); + mgr->mcu_firmware_name = NULL; + } +} +#endif /* GXP_HAS_MCU */ + +static int gxp_firmware_loader_load_locked(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + int ret; + + lockdep_assert_held(&mgr->lock); + ret = gxp_firmware_load_core_firmware(gxp, mgr->core_firmware_name, + mgr->core_firmware); + if (ret) + return ret; + +#if GXP_HAS_MCU + if (!gxp_is_direct_mode(gxp)) { + ret = gxp_mcu_firmware_load(gxp, mgr->mcu_firmware_name, + &mgr->mcu_firmware); + if (ret) + goto err_unload_core; + + ret = gxp_firmware_loader_gsa_auth(gxp); + if (ret) + goto err_unload_mcu; + } +#endif + ret = gxp_firmware_rearrange_elf(gxp, mgr->core_firmware); + if (ret) + goto err_unload; + gxp_firmware_loader_has_loaded(gxp); + return 0; + +err_unload: +#if GXP_HAS_MCU + if (!gxp_is_direct_mode(gxp)) + gxp_firmware_loader_gsa_unload(gxp); +err_unload_mcu: + if (!gxp_is_direct_mode(gxp)) + gxp_firmware_loader_unload_mcu_firmware(gxp); +err_unload_core: +#endif + gxp_firmware_loader_unload_core_firmware(gxp); + return ret; +} + +int gxp_firmware_loader_load_if_needed(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + int ret = 0; + + mutex_lock(&mgr->lock); + if (mgr->is_loaded) + goto out; + ret = gxp_firmware_loader_load_locked(gxp); +out: + mutex_unlock(&mgr->lock); + return ret; +} + +void gxp_firmware_loader_unload(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + + mutex_lock(&mgr->lock); + if (mgr->is_loaded) { +#if GXP_HAS_MCU + gxp_firmware_loader_gsa_unload(gxp); + gxp_firmware_loader_unload_mcu_firmware(gxp); +#endif + gxp_firmware_loader_unload_core_firmware(gxp); + } + mgr->is_loaded = false; + mutex_unlock(&mgr->lock); +} + +#if GXP_HAS_MCU +void gxp_firmware_loader_set_mcu_fw_name(struct gxp_dev *gxp, + const char *fw_name) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + + mutex_lock(&mgr->lock); + mgr->mcu_firmware_name = kstrdup(fw_name, GFP_KERNEL); + mutex_unlock(&mgr->lock); +} + +char *gxp_firmware_loader_get_mcu_fw_name(struct gxp_dev *gxp) +{ + struct gxp_firmware_loader_manager *mgr = gxp->fw_loader_mgr; + char *name; + + mutex_lock(&mgr->lock); + if (mgr->mcu_firmware_name) + name = kstrdup(mgr->mcu_firmware_name, GFP_KERNEL); + else + name = kstrdup(GXP_DEFAULT_MCU_FIRMWARE, GFP_KERNEL); + mutex_unlock(&mgr->lock); + return name; +} +#endif /* GXP_HAS_MCU */ diff --git a/gxp-firmware-loader.h b/gxp-firmware-loader.h new file mode 100644 index 0000000..d081af2 --- /dev/null +++ b/gxp-firmware-loader.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * GXP firmware loading management. + * + * Copyright (C) 2023 Google LLC + */ + +#ifndef __GXP_FIRMWARE_LOADER_H_ +#define __GXP_FIRMWARE_LOADER_H_ + +#include <gcip/gcip-image-config.h> + +#include "gxp-config.h" +#include "gxp-internal.h" + +struct gxp_firmware_loader_manager { + const struct firmware *core_firmware[GXP_NUM_CORES]; + char *core_firmware_name; + /* + * Cached core 0 firmware image config, for easier fetching config entries. + * Not a pointer to the firmware buffer because we want to forcely change the + * privilege level to NS. + * Only valid on the firmware loaded. + */ + struct gcip_image_config core_img_cfg; +#if GXP_HAS_MCU + const struct firmware *mcu_firmware; + char *mcu_firmware_name; +#endif + bool is_loaded; + /* Protects above fields */ + struct mutex lock; +}; + +/* + * Initializes the firmware loader subsystem. + */ +int gxp_firmware_loader_init(struct gxp_dev *gxp); + +/* + * Tears down the firmware loader subsystem. + */ +void gxp_firmware_loader_destroy(struct gxp_dev *gxp); + +/* + * Requests and loads all firmware only if firmware is not loaded. + * + * Returns 0 on success, a negative errno on failure. + */ +int gxp_firmware_loader_load_if_needed(struct gxp_dev *gxp); + +/* + * Unloads firmware. + */ +void gxp_firmware_loader_unload(struct gxp_dev *gxp); + +/* + * Returns a copied core firmware name prefix, the caller needs to release it by + * kfree. + */ +char *gxp_firmware_loader_get_core_fw_name(struct gxp_dev *gxp); + +/* + * Set the core firmware name prefix to be requested in + * `gxp_firmware_loader_load_if_needed()`. + * It's safe for caller to release @fw_name after calling this function. + */ +void gxp_firmware_loader_set_core_fw_name(struct gxp_dev *gxp, + const char *fw_name); +/* + * + * Returns a copied MCU firmware name, the caller needs to release it by + * kfree. + */ +char *gxp_firmware_loader_get_mcu_fw_name(struct gxp_dev *gxp); + +/* + * Set the MCU firmware name to be requested in + * `gxp_firmware_loader_load_if_needed()`. + * It's safe for caller to release @fw_name after calling this function. + */ +void gxp_firmware_loader_set_mcu_fw_name(struct gxp_dev *gxp, + const char *fw_name); + +#endif /* __GXP_FIRMWARE_LOADER_H_ */ diff --git a/gxp-firmware.c b/gxp-firmware.c index 804ea1a..2f9a585 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,41 +45,8 @@ 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 bool gxp_core_boot_flag = true; +module_param_named(core_boot, gxp_core_boot_flag, bool, 0660); static int request_dsp_firmware(struct gxp_dev *gxp, char *name_prefix, @@ -117,8 +85,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; } @@ -481,32 +451,56 @@ static int gxp_firmware_handshake(struct gxp_dev *gxp, return 0; } -static void gxp_firmware_load(struct gxp_dev *gxp, - const struct firmware *firmwares[GXP_NUM_CORES]) +static int +gxp_firmware_load_into_memories(struct gxp_dev *gxp, + const struct firmware *firmwares[GXP_NUM_CORES]) { - uint core; + 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; } -static int gxp_firmware_rearrange_elf(struct gxp_dev *gxp) +int gxp_firmware_rearrange_elf(struct gxp_dev *gxp, + const struct firmware *firmwares[GXP_NUM_CORES]) { - struct gxp_firmware_manager *mgr = gxp->firmware_mgr; int ret = 0; uint core; - lockdep_assert_held(&mgr->dsp_firmware_lock); for (core = 0; core < GXP_NUM_CORES; core++) { /* Re-arrange ELF firmware in System RAM */ - ret = elf_load_segments( - gxp, mgr->firmwares[core]->data + FW_HEADER_SIZE, - mgr->firmwares[core]->size - FW_HEADER_SIZE, - &gxp->fwbufs[core]); + 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", @@ -541,17 +535,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; } @@ -561,10 +549,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 @@ -586,50 +572,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; - } - - gxp_firmware_load(gxp, firmwares); - 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]; + dev_err(gxp->dev, "Failed to load core firmware: %s\n", name_buf); + goto err_firmware_load; } - ret = gxp_firmware_rearrange_elf(gxp); - if (ret) - goto err_rearrange_elf; - - 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_rearrange_elf: - 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]); -err_request_firmware: +err_firmware_load: kfree(name_buf); - mutex_unlock(&mgr->dsp_firmware_lock); err_out: up_read(&gxp->vd_semaphore); return ret; @@ -658,7 +622,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); @@ -754,59 +717,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; - - gxp_firmware_load(gxp, mgr->firmwares); - ret = gxp_firmware_authenticate(gxp, mgr->firmwares); + return ret; + ret = gxp_firmware_load_into_memories(gxp, core_firmware); if (ret) - goto err_authenticate_firmware; - - ret = gxp_firmware_rearrange_elf(gxp); + goto error; + ret = gxp_firmware_authenticate(gxp, core_firmware); if (ret) - goto err_rearrange_elf; - - gxp_firmware_has_requested(gxp, mgr); + goto error; -out: - mutex_unlock(&mgr->dsp_firmware_lock); - return ret; - -err_rearrange_elf: -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; } @@ -841,7 +779,7 @@ 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; @@ -852,7 +790,7 @@ static int gxp_firmware_setup(struct gxp_dev *gxp, 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, @@ -892,7 +830,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, @@ -934,7 +872,7 @@ 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); return ret; } @@ -945,7 +883,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); @@ -956,7 +894,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, @@ -1010,7 +948,7 @@ int gxp_firmware_run(struct gxp_dev *gxp, struct gxp_virtual_device *vd, 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); } virt_core++; @@ -1031,7 +969,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); } @@ -1062,7 +1000,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; @@ -1135,3 +1073,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_core_boot_flag; +} diff --git a/gxp-firmware.h b/gxp-firmware.h index 9a02570..6dde831 100644 --- a/gxp-firmware.h +++ b/gxp-firmware.h @@ -43,8 +43,6 @@ #define PRIVATE_FW_DATA_SIZE SZ_2M #define SHARED_FW_DATA_SIZE SZ_1M -extern bool gxp_core_boot; - /* Indexes same as image_config.IommuMappingIdx in the firmware side. */ enum gxp_imgcfg_idx { CORE_CFG_REGION_IDX, @@ -53,20 +51,8 @@ enum gxp_imgcfg_idx { }; struct gxp_firmware_manager { - const struct firmware *firmwares[GXP_NUM_CORES]; - char *firmware_name; - bool is_firmware_requested; - /* Protects `firmwares` and `firmware_name` */ - struct mutex dsp_firmware_lock; /* Firmware status bitmap. Accessors must hold `vd_semaphore`. */ u32 firmware_running; - /* - * Cached image config, for easier fetching config entries. - * Not a pointer to the firmware buffer because we want to forcely change the - * privilege level to NS. - * Only valid on firmware requested. - */ - struct gcip_image_config img_cfg; }; enum aurora_msg { @@ -83,7 +69,7 @@ static inline bool gxp_is_fw_running(struct gxp_dev *gxp, uint core) } /* - * Initializes the firmware loading/unloading subsystem. This includes + * Initializes the core firmware loading/unloading subsystem. This includes * initializing the LPM and obtaining the memory regions needed to load the FW. * The function needs to be called once after a block power up event. */ @@ -96,14 +82,22 @@ int gxp_fw_init(struct gxp_dev *gxp); void gxp_fw_destroy(struct gxp_dev *gxp); /* - * Check if the DSP firmware files have been requested yet, and if not, request - * them. + * Requests and loads core firmware into memories. + * If the loaded firmware is ELF, rearranges it. + * + * Returns 0 on success, a negative errno on failure. + */ +int gxp_firmware_load_core_firmware( + struct gxp_dev *gxp, char *name_prefix, + const struct firmware *core_firmwares[GXP_NUM_CORES]); + +/* + * Rearranges firmware data if the firmware is ELF. * - * Returns 0 if the files have already been requested or were successfully - * requested by this call; Returns an errno if this call attempted to request - * the files and it failed. + * Returns 0 on success, a negative errno on failure. */ -int gxp_firmware_request_if_needed(struct gxp_dev *gxp); +int gxp_firmware_rearrange_elf(struct gxp_dev *gxp, + const struct firmware *firmwares[GXP_NUM_CORES]); /* * Re-program the reset vector and power on the core's LPM if the block had @@ -157,4 +151,7 @@ void gxp_firmware_set_boot_status(struct gxp_dev *gxp, u32 gxp_firmware_get_boot_status(struct gxp_dev *gxp, struct gxp_virtual_device *vd, uint core); +/* Returns whether the core firmware running states are managed by us. */ +bool gxp_core_boot(struct gxp_dev *gxp); + #endif /* __GXP_FIRMWARE_H__ */ diff --git a/gxp-internal.h b/gxp-internal.h index cc6cffe..a0f2f0c 100644 --- a/gxp-internal.h +++ b/gxp-internal.h @@ -83,6 +83,7 @@ struct gxp_dev { struct gxp_mailbox_manager *mailbox_mgr; struct gxp_power_manager *power_mgr; struct gxp_debug_dump_manager *debug_dump_mgr; + struct gxp_firmware_loader_manager *fw_loader_mgr; struct gxp_firmware_manager *firmware_mgr; /* * Lock to ensure only one thread at a time is ever calling @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Kernel Control Interface, implements the protocol between DSP Kernel driver and MCU firmware. * @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Kernel Control Interface, implements the protocol between DSP Kernel driver and MCU firmware. * diff --git a/gxp-mailbox-regs.h b/gxp-mailbox-regs.h index 05fb414..5c518ed 100644 --- a/gxp-mailbox-regs.h +++ b/gxp-mailbox-regs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP mailbox registers. * diff --git a/gxp-mailbox.c b/gxp-mailbox.c index 0e0b365..758b707 100644 --- a/gxp-mailbox.c +++ b/gxp-mailbox.c @@ -33,7 +33,7 @@ #endif /* Timeout of 1s by default */ -int gxp_mbx_timeout = 1000; +int gxp_mbx_timeout = 2000; module_param_named(mbx_timeout, gxp_mbx_timeout, int, 0660); /* diff --git a/gxp-mcu-firmware.c b/gxp-mcu-firmware.c index 898ffd6..56b0550 100644 --- a/gxp-mcu-firmware.c +++ b/gxp-mcu-firmware.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GXP MicroController Unit firmware management. * @@ -7,10 +7,12 @@ #include <linux/device.h> #include <linux/firmware.h> +#include <linux/gsa/gsa_dsp.h> #include <linux/io.h> #include <linux/lockdep.h> #include <linux/mutex.h> #include <linux/resource.h> +#include <linux/slab.h> #include <linux/string.h> #include <gcip/gcip-common-image-header.h> @@ -21,6 +23,7 @@ #include "gxp-config.h" #include "gxp-dma.h" #include "gxp-doorbell.h" +#include "gxp-firmware-loader.h" #include "gxp-internal.h" #include "gxp-kci.h" #include "gxp-lpm.h" @@ -61,84 +64,113 @@ static bool is_signed_firmware(const struct firmware *fw, return true; } -/* - * Loads firmware image to memory. - */ -static int gxp_mcu_firmware_load_locked(struct gxp_mcu_firmware *mcu_fw, - const char *name) +int gxp_mcu_firmware_load(struct gxp_dev *gxp, char *fw_name, + const struct firmware **fw) { int ret; - struct gxp_dev *gxp = mcu_fw->gxp; + struct gxp_mcu_firmware *mcu_fw = gxp_mcu_firmware_of(gxp); struct device *dev = gxp->dev; struct gcip_image_config *imgcfg; - const struct firmware *fw; struct gcip_common_image_header *hdr; size_t offset, size; + bool is_signed; - lockdep_assert_held(&mcu_fw->lock); - ret = request_firmware(&fw, name, dev); + mutex_lock(&mcu_fw->lock); + if (mcu_fw->status == GCIP_FW_LOADING || + mcu_fw->status == GCIP_FW_VALID) { + dev_info(gxp->dev, "MCU firmware is loaded, skip loading"); + goto out; + } + + mcu_fw->status = GCIP_FW_LOADING; + if (fw_name == NULL) + fw_name = GXP_DEFAULT_MCU_FIRMWARE; + dev_info(gxp->dev, "MCU firmware %s loading", fw_name); + + ret = request_firmware(fw, fw_name, dev); if (ret) { - dev_err(dev, "request firmware '%s' failed: %d", name, ret); - return ret; + dev_err(dev, "request firmware '%s' failed: %d", fw_name, ret); + goto err_out; } - hdr = (struct gcip_common_image_header *)fw->data; + hdr = (struct gcip_common_image_header *)(*fw)->data; - mcu_fw->is_signed = is_signed_firmware(fw, hdr); + is_signed = is_signed_firmware(*fw, hdr); - if (mcu_fw->is_signed) { + if (is_signed) { offset = GCIP_FW_HEADER_SIZE; - size = fw->size - GCIP_FW_HEADER_SIZE; + size = (*fw)->size - GCIP_FW_HEADER_SIZE; } else { offset = 0; - size = fw->size; + size = (*fw)->size; } if (size > mcu_fw->image_buf.size) { dev_err(dev, "firmware %s size %#zx exceeds buffer size %#llx", - name, size, mcu_fw->image_buf.size); + fw_name, size, mcu_fw->image_buf.size); ret = -ENOSPC; - goto out_release_firmware; + goto err_release_firmware; } - if (mcu_fw->is_signed) { + if (is_signed) { imgcfg = get_image_config_from_hdr(hdr); if (!imgcfg) { dev_err(dev, "Unsupported image header generation"); ret = -EINVAL; - goto out_release_firmware; + goto err_release_firmware; } ret = gcip_image_config_parse(&mcu_fw->cfg_parser, imgcfg); if (ret) dev_err(dev, "image config parsing failed: %d", ret); - } else + mcu_fw->is_secure = !gcip_image_config_is_ns(imgcfg); + } else { ret = gxp_iommu_map(gxp, gxp_iommu_get_domain_for_dev(gxp), mcu_fw->image_buf.daddr, - mcu_fw->image_buf.paddr, mcu_fw->image_buf.size, + mcu_fw->image_buf.paddr, + mcu_fw->image_buf.size, IOMMU_READ | IOMMU_WRITE); + mcu_fw->is_secure = false; + } if (ret) - goto out_release_firmware; + goto err_release_firmware; - memcpy(mcu_fw->image_buf.vaddr, fw->data + offset, size); + memcpy(mcu_fw->image_buf.vaddr, (*fw)->data + offset, size); +out: + mutex_unlock(&mcu_fw->lock); + return 0; -out_release_firmware: - release_firmware(fw); +err_release_firmware: + release_firmware(*fw); +err_out: + mcu_fw->status = GCIP_FW_INVALID; + mutex_unlock(&mcu_fw->lock); return ret; } -/* - * Reverts gxp_mcu_firmware_load_locked. The firmware must be not running when - * calling this method. - */ -static void gxp_mcu_firmware_unload_locked(struct gxp_mcu_firmware *mcu_fw) +void gxp_mcu_firmware_unload(struct gxp_dev *gxp, const struct firmware *fw) { - lockdep_assert_held(&mcu_fw->lock); - if (mcu_fw->is_signed) + struct gcip_common_image_header *hdr; + struct gxp_mcu_firmware *mcu_fw = gxp_mcu_firmware_of(gxp); + bool is_signed; + + mutex_lock(&mcu_fw->lock); + if (mcu_fw->status == GCIP_FW_INVALID) { + dev_err(mcu_fw->gxp->dev, "Failed to unload MCU firmware"); + mutex_unlock(&mcu_fw->lock); + return; + } + hdr = (struct gcip_common_image_header *)fw->data; + is_signed = is_signed_firmware(fw, hdr); + if (is_signed) gcip_image_config_clear(&mcu_fw->cfg_parser); else - gxp_iommu_unmap(mcu_fw->gxp, gxp_iommu_get_domain_for_dev(mcu_fw->gxp), - mcu_fw->image_buf.daddr, mcu_fw->image_buf.size); + gxp_iommu_unmap(mcu_fw->gxp, + gxp_iommu_get_domain_for_dev(mcu_fw->gxp), + mcu_fw->image_buf.daddr, + mcu_fw->image_buf.size); + mcu_fw->status = GCIP_FW_INVALID; + mutex_unlock(&mcu_fw->lock); } static int gxp_mcu_firmware_handshake(struct gxp_mcu_firmware *mcu_fw) @@ -207,21 +239,15 @@ static void gxp_mcu_firmware_stop_locked(struct gxp_mcu_firmware *mcu_fw) dev_warn(gxp->dev, "MCU PSM transition to PS3 fails, current state: %u\n", gxp_lpm_get_state(gxp, CORE_TO_PSM(GXP_MCU_CORE_ID))); - - gxp_mcu_firmware_unload_locked(mcu_fw); + if (mcu_fw->is_secure) + gsa_send_dsp_cmd(gxp->gsa_dev, GSA_DSP_SHUTDOWN); } -static int gxp_mcu_firmware_power_up(struct gxp_mcu_firmware *mcu_fw, - const char *name) +static int gxp_mcu_firmware_power_up(struct gxp_mcu_firmware *mcu_fw) { struct gxp_dev *gxp = mcu_fw->gxp; int ret; - - /* - * TODO(267723984): call this only if GSA device is not found after the GSA - * firmware hanles this. - */ - program_iremap_csr(gxp, &mcu_fw->image_buf); + int state; gxp_bpm_configure(gxp, GXP_MCU_CORE_ID, INST_BPM_OFFSET, BPM_EVENT_READ_XFER); @@ -229,80 +255,51 @@ static int gxp_mcu_firmware_power_up(struct gxp_mcu_firmware *mcu_fw, ret = gxp_lpm_up(gxp, GXP_MCU_CORE_ID); if (ret) return ret; - /* Raise wakeup doorbell */ - dev_dbg(gxp->dev, "Raising doorbell %d interrupt\n", - CORE_WAKEUP_DOORBELL(GXP_MCU_CORE_ID)); - gxp_doorbell_enable_for_core(gxp, CORE_WAKEUP_DOORBELL(GXP_MCU_CORE_ID), - GXP_MCU_CORE_ID); - gxp_doorbell_set(gxp, CORE_WAKEUP_DOORBELL(GXP_MCU_CORE_ID)); + + if (mcu_fw->is_secure) { + state = gsa_send_dsp_cmd(gxp->gsa_dev, GSA_DSP_START); + if (state != GSA_DSP_STATE_RUNNING) + goto err_lpm_down; + } else { + program_iremap_csr(gxp, &mcu_fw->image_buf); + /* Raise wakeup doorbell */ + dev_dbg(gxp->dev, "Raising doorbell %d interrupt\n", + CORE_WAKEUP_DOORBELL(GXP_MCU_CORE_ID)); + gxp_doorbell_enable_for_core( + gxp, CORE_WAKEUP_DOORBELL(GXP_MCU_CORE_ID), + GXP_MCU_CORE_ID); + gxp_doorbell_set(gxp, CORE_WAKEUP_DOORBELL(GXP_MCU_CORE_ID)); + } ret = gxp_mcu_firmware_handshake(mcu_fw); if (ret) - goto err_lpm_down; - dev_info(gxp->dev, "MCU firmware %s run succeeded", name); + goto err_mcu_shutdown; + dev_info(gxp->dev, "MCU firmware run succeeded"); return ret; +err_mcu_shutdown: + if (mcu_fw->is_secure) + gsa_send_dsp_cmd(gxp->gsa_dev, GSA_DSP_SHUTDOWN); err_lpm_down: gxp_lpm_down(gxp, GXP_MCU_CORE_ID); return ret; } /* - * Runs the firmware without checking current status. - * - * The firmware status would be set as GCIP_FW_LOADING when this function is - * working, and set as GCIP_FW_VALID/INVALID on finished. - * - * @mcu_fw->name will be set to @name if firmware handshake succeeds, set to - * NULL otherwise. - * - * Caller holds firmware lock. + * Caller must hold firmware lock. */ -static int gxp_mcu_firmware_run_locked(struct gxp_mcu_firmware *mcu_fw, - const char *name) +static int gxp_mcu_firmware_run_locked(struct gxp_mcu_firmware *mcu_fw) { int ret; lockdep_assert_held(&mcu_fw->lock); - if (!name) - name = GXP_DEFAULT_MCU_FIRMWARE; - mcu_fw->status = GCIP_FW_LOADING; - - ret = gxp_mcu_firmware_load_locked(mcu_fw, name); - if (ret) - goto err_invalid; - ret = gxp_mcu_firmware_power_up(mcu_fw, name); + ret = gxp_mcu_firmware_power_up(mcu_fw); if (ret) - goto err_unload; + return ret; mcu_fw->status = GCIP_FW_VALID; - mcu_fw->name = name; - return 0; - -err_unload: - gxp_mcu_firmware_unload_locked(mcu_fw); -err_invalid: - mcu_fw->status = GCIP_FW_INVALID; - mcu_fw->name = NULL; - return ret; -} - -static int gxp_mcu_firmware_restart_locked(struct gxp_mcu_firmware *mcu_fw) -{ - struct gxp_dev *gxp = mcu_fw->gxp; - int ret; - - lockdep_assert_held(&mcu_fw->lock); - - ret = gxp_mcu_firmware_power_up(mcu_fw, mcu_fw->name); - if (ret) { - dev_warn(gxp->dev, "Failed to restart, reload MCU fw entirely"); - gxp_mcu_firmware_unload_locked(mcu_fw); - return gxp_mcu_firmware_run_locked(mcu_fw, mcu_fw->name); - } - return 0; } @@ -347,17 +344,11 @@ static ssize_t load_firmware_show(struct device *dev, struct device_attribute *attr, char *buf) { struct gxp_dev *gxp = dev_get_drvdata(dev); - struct gxp_mcu_firmware *mcu_fw = gxp_mcu_firmware_of(gxp); - int ret; - const char *name; + ssize_t ret; + char *firmware_name = gxp_firmware_loader_get_mcu_fw_name(gxp); - mutex_lock(&mcu_fw->lock); - name = mcu_fw->name; - /* name can be NULL when the last MCU firmware run failed */ - if (!name) - name = "[none]"; - ret = scnprintf(buf, PAGE_SIZE, "%s\n", name); - mutex_unlock(&mcu_fw->lock); + ret = scnprintf(buf, PAGE_SIZE, "%s\n", firmware_name); + kfree(firmware_name); return ret; } @@ -366,14 +357,9 @@ static ssize_t load_firmware_store(struct device *dev, const char *buf, size_t count) { struct gxp_dev *gxp = dev_get_drvdata(dev); - struct gxp_mcu_firmware *mcu_fw = gxp_mcu_firmware_of(gxp); int ret; char *name; - const char *last_name; - /* early return without holding a lock when the FW run is ongoing */ - if (mcu_fw->status == GCIP_FW_LOADING) - return -EBUSY; name = fw_name_from_buf(gxp, buf); if (IS_ERR(name)) return PTR_ERR(name); @@ -389,16 +375,20 @@ static ssize_t load_firmware_store(struct device *dev, */ } dev_info(gxp->dev, "loading firmware %s from SysFS", name); - last_name = mcu_fw->name; - mcu_fw->name = name; - ret = gcip_pm_get(gxp->power_mgr->pm); + /* + * 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_mcu_fw_name(gxp, name); + ret = gxp_firmware_loader_load_if_needed(gxp); if (ret) { - dev_err(gxp->dev, "loading firmware %s failed: %d", name, ret); - mcu_fw->name = last_name; - } else { - gcip_pm_put(gxp->power_mgr->pm); + dev_err(gxp->dev, "Failed to load MCU firmware: %s\n", name); + return ret; } - return ret < 0 ? ret : count; + return count; } static DEVICE_ATTR_RW(load_firmware); @@ -424,7 +414,7 @@ static int image_config_map(void *data, dma_addr_t daddr, phys_addr_t paddr, } return gxp_iommu_map(gxp, gxp_iommu_get_domain_for_dev(gxp), daddr, - paddr, size, IOMMU_READ | IOMMU_WRITE); + paddr, size, IOMMU_READ | IOMMU_WRITE); } static void image_config_unmap(void *data, dma_addr_t daddr, size_t size, @@ -457,7 +447,6 @@ int gxp_mcu_firmware_init(struct gxp_dev *gxp, struct gxp_mcu_firmware *mcu_fw) } mcu_fw->gxp = gxp; mcu_fw->status = GCIP_FW_INVALID; - mcu_fw->name = GXP_DEFAULT_MCU_FIRMWARE; mutex_init(&mcu_fw->lock); ret = device_add_group(gxp->dev, &firmware_attr_group); if (ret) @@ -477,16 +466,10 @@ int gxp_mcu_firmware_run(struct gxp_mcu_firmware *mcu_fw) int ret; mutex_lock(&mcu_fw->lock); - /* - * TODO(b/233159020): Currently, the stop function unloads the firmware image and - * we have to reload it by calling the run function. We have implemented the restart - * function for non-GSA environment, but let's enable it by removing " && 0" once we - * refactor the whole logic for supporting the GSA device. - */ - if (mcu_fw->status == GCIP_FW_VALID && 0) - ret = gxp_mcu_firmware_restart_locked(mcu_fw); + if (mcu_fw->status == GCIP_FW_INVALID) + ret = -EINVAL; else - ret = gxp_mcu_firmware_run_locked(mcu_fw, mcu_fw->name); + ret = gxp_mcu_firmware_run_locked(mcu_fw); mutex_unlock(&mcu_fw->lock); return ret; } @@ -587,7 +570,7 @@ void gxp_mcu_firmware_crash_handler(struct gxp_dev *gxp, goto out; } - ret = gxp_mcu_firmware_restart_locked(mcu_fw); + ret = gxp_mcu_firmware_run_locked(mcu_fw); if (ret) dev_err(gxp->dev, "Failed to run MCU firmware (ret=%d)\n", ret); diff --git a/gxp-mcu-firmware.h b/gxp-mcu-firmware.h index 1026988..fb05edb 100644 --- a/gxp-mcu-firmware.h +++ b/gxp-mcu-firmware.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP MicroController Unit firmware management. * @@ -24,8 +24,7 @@ struct gxp_mcu_firmware { enum gcip_fw_status status; struct gcip_fw_info fw_info; struct gcip_image_config_parser cfg_parser; - const char *name; /* the firmware name last loaded */ - bool is_signed; + bool is_secure; }; /* @@ -38,7 +37,7 @@ int gxp_mcu_firmware_init(struct gxp_dev *gxp, struct gxp_mcu_firmware *mcu_fw); void gxp_mcu_firmware_exit(struct gxp_mcu_firmware *mcu_fw); /* - * Loads and runs the MCU firmware. The firmware is ready to serve when this + * Runs the MCU firmware. The firmware is ready to serve when this * call succeeds. * * Returns 0 on success, a negative errno on failure. @@ -51,6 +50,19 @@ int gxp_mcu_firmware_run(struct gxp_mcu_firmware *mcu_fw); void gxp_mcu_firmware_stop(struct gxp_mcu_firmware *mcu_fw); /* + * Loads MCU firmware into memories and parses the image config. + * + * Returns 0 on success, a negative errno on failure. + */ +int gxp_mcu_firmware_load(struct gxp_dev *gxp, char *fw_name, + const struct firmware **fw); + +/* + * Unloads MCU firmware. + */ +void gxp_mcu_firmware_unload(struct gxp_dev *gxp, const struct firmware *fw); + +/* * Returns the pointer of MCU firmware associated with the GXP device object. * * This function is NOT implemented in gxp-mcu-firmware.c. Instead, it shall be diff --git a/gxp-mcu-fs.c b/gxp-mcu-fs.c index f3a59ca..dbad6ca 100644 --- a/gxp-mcu-fs.c +++ b/gxp-mcu-fs.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Common file system operations for devices with MCU support. * diff --git a/gxp-mcu-fs.h b/gxp-mcu-fs.h index 75b55c7..99fe59b 100644 --- a/gxp-mcu-fs.h +++ b/gxp-mcu-fs.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Common file system operations for devices with MCU support. * diff --git a/gxp-mcu-platform.c b/gxp-mcu-platform.c index 5aca0b6..cfbb433 100644 --- a/gxp-mcu-platform.c +++ b/gxp-mcu-platform.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Platform device driver for devices with MCU support. * @@ -127,15 +127,13 @@ static int gxp_mcu_link_offload_vmbox(struct gxp_dev *gxp, ret = gxp_kci_link_unlink_offload_vmbox( kci, vd->client_id, offload_client_id, offload_chip_type, true); - if (ret) { + if (ret) dev_err(gxp->dev, "Failed to link offload VMBox for client %d, offload client %u, offload chip type %d: %d", vd->client_id, offload_client_id, offload_chip_type, ret); - return ret; - } - return 0; + return ret; } static void gxp_mcu_unlink_offload_vmbox(struct gxp_dev *gxp, @@ -277,13 +275,13 @@ static void gxp_mcu_before_unmap_tpu_mbx_queue(struct gxp_dev *gxp, static irqreturn_t mcu_wdg_irq_handler(int irq, void *arg) { - struct gxp_dev *gxp = (struct gxp_dev *)arg; + struct gxp_dev *gxp = arg; u32 wdg_control_val; /* Clear the interrupt and disable the WDG. */ wdg_control_val = gxp_read_32(gxp, GXP_REG_WDOG_CONTROL); - wdg_control_val |= (1 << GXP_WDG_INT_CLEAR_BIT); - wdg_control_val &= ~(1 << GXP_WDG_ENABLE_BIT); + wdg_control_val |= BIT(GXP_WDG_INT_CLEAR_BIT); + wdg_control_val &= ~BIT(GXP_WDG_ENABLE_BIT); gxp_write_32(gxp, GXP_REG_WDOG_CONTROL, wdg_control_val); return IRQ_WAKE_THREAD; @@ -291,7 +289,7 @@ static irqreturn_t mcu_wdg_irq_handler(int irq, void *arg) static irqreturn_t mcu_wdg_threaded_handler(int irq, void *arg) { - struct gxp_dev *gxp = (struct gxp_dev *)arg; + struct gxp_dev *gxp = arg; gxp_mcu_firmware_crash_handler(gxp, GCIP_FW_CRASH_HW_WDG_TIMEOUT); @@ -308,21 +306,16 @@ static int gxp_mcu_register_wdg_irq(struct gxp_dev *gxp) if (!wdg_virq) { dev_warn(dev, "Unable to parse interrupt for HW WDG from the DT"); - } else { - ret = devm_request_threaded_irq(dev, wdg_virq, - mcu_wdg_irq_handler, - mcu_wdg_threaded_handler, - /*flags=*/0, "aurora_mcu_wdg", - (void *)gxp); - if (ret) { - dev_err(dev, - "Unable to register MCU WDG IRQ; error=%d\n", - ret); - return -EINVAL; - } + return 0; } + ret = devm_request_threaded_irq(dev, wdg_virq, mcu_wdg_irq_handler, + mcu_wdg_threaded_handler, + /*flags=*/0, "aurora_mcu_wdg", + (void *)gxp); + if (ret) + dev_err(dev, "Unable to register MCU WDG IRQ: %d\n", ret); - return 0; + return ret; } struct gxp_mcu *gxp_mcu_of(struct gxp_dev *gxp) diff --git a/gxp-mcu-platform.h b/gxp-mcu-platform.h index 6ae923a..e87a36b 100644 --- a/gxp-mcu-platform.h +++ b/gxp-mcu-platform.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Platform device driver for devices with MCU support. * diff --git a/gxp-mcu-telemetry.c b/gxp-mcu-telemetry.c index 6dcdae6..a0aa4c7 100644 --- a/gxp-mcu-telemetry.c +++ b/gxp-mcu-telemetry.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GXP MCU telemetry support * diff --git a/gxp-mcu-telemetry.h b/gxp-mcu-telemetry.h index 4658fee..e092c46 100644 --- a/gxp-mcu-telemetry.h +++ b/gxp-mcu-telemetry.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP MCU telemetry support * @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Structures and helpers for managing GXP MicroController Unit. * @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Structures and helpers for managing GXP MicroController Unit. * @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GXP SSMT driver. * @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP SSMT driver. * @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * GXP user command interface. * @@ -262,10 +262,8 @@ gxp_uci_handle_awaiter_arrived(struct gcip_mailbox *mailbox, list_add_tail(&async_resp->dest_list_entry, async_resp->dest_queue); - if (async_resp->eventfd) { + if (async_resp->eventfd) gxp_eventfd_signal(async_resp->eventfd); - gxp_eventfd_put(async_resp->eventfd); - } wake_up(async_resp->dest_queue_waitq); out: @@ -303,10 +301,8 @@ gxp_uci_handle_awaiter_timedout(struct gcip_mailbox *mailbox, async_resp->dest_queue); spin_unlock_irqrestore(async_resp->queue_lock, flags); - if (async_resp->eventfd) { + if (async_resp->eventfd) gxp_eventfd_signal(async_resp->eventfd); - gxp_eventfd_put(async_resp->eventfd); - } wake_up(async_resp->dest_queue_waitq); } else { @@ -321,6 +317,8 @@ static void gxp_uci_release_awaiter_data(void *data) struct gxp_uci_async_response *async_resp = data; gxp_vd_release_credit(async_resp->vd); + if (async_resp->eventfd) + gxp_eventfd_put(async_resp->eventfd); kfree(async_resp); } @@ -510,6 +508,8 @@ int gxp_uci_send_command(struct gxp_uci *uci, struct gxp_virtual_device *vd, return 0; err_free_resp: + if (async_resp->eventfd) + gxp_eventfd_put(async_resp->eventfd); kfree(async_resp); err_release_credit: gxp_vd_release_credit(vd); @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * GXP user command interface. * @@ -23,8 +23,9 @@ #include "gxp-domain-pool.h" #include "gxp-doorbell.h" #include "gxp-eventfd.h" -#include "gxp-firmware.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" #include "gxp-lpm.h" @@ -314,9 +315,9 @@ static void gxp_vd_imgcfg_unmap(void *data, dma_addr_t daddr, size_t size, unmap_ns_region(vd, daddr); } -static int map_fw_image_config(struct gxp_dev *gxp, - struct gxp_virtual_device *vd, - struct gxp_firmware_manager *fw_mgr) +static int +map_fw_image_config(struct gxp_dev *gxp, struct gxp_virtual_device *vd, + struct gxp_firmware_loader_manager *fw_loader_mgr) { int ret; struct gcip_image_config *cfg; @@ -328,9 +329,9 @@ static int map_fw_image_config(struct gxp_dev *gxp, /* * Allow to skip for test suites need VD but doesn't need the FW module. */ - if (IS_ENABLED(CONFIG_GXP_TEST) && !fw_mgr) + if (IS_ENABLED(CONFIG_GXP_TEST) && !fw_loader_mgr) return 0; - cfg = &fw_mgr->img_cfg; + cfg = &fw_loader_mgr->core_img_cfg; ret = gcip_image_config_parser_init(&vd->cfg_parser, &gxp_vd_imgcfg_ops, gxp->dev, vd); /* parser_init() never fails unless we pass invalid OPs. */ @@ -568,7 +569,7 @@ static int assign_cores(struct gxp_virtual_device *vd) uint core; uint available_cores = 0; - if (!gxp_core_boot) { + if (!gxp_core_boot(gxp)) { /* We don't do core assignment when cores are managed by MCU. */ vd->core_list = BIT(GXP_NUM_CORES) - 1; return 0; @@ -598,7 +599,7 @@ static void unassign_cores(struct gxp_virtual_device *vd) struct gxp_dev *gxp = vd->gxp; uint core; - if (!gxp_core_boot) + if (!gxp_core_boot(gxp)) return; for (core = 0; core < GXP_NUM_CORES; core++) { if (gxp->core_to_vd[core] == vd) @@ -646,7 +647,8 @@ static void set_config_version(struct gxp_dev *gxp, struct gxp_virtual_device *vd) { if (gxp->firmware_mgr && vd->sys_cfg.daddr) - vd->config_version = gxp->firmware_mgr->img_cfg.config_version; + vd->config_version = + gxp->fw_loader_mgr->core_img_cfg.config_version; /* * Let gxp_dma_map_core_resources() map this region only when using the * legacy protocol. @@ -744,19 +746,17 @@ struct gxp_virtual_device *gxp_vd_allocate(struct gxp_dev *gxp, * Here assumes firmware is requested before allocating a VD, which is * true because we request firmware on first GXP device open. */ - err = map_fw_image_config(gxp, vd, gxp->firmware_mgr); + err = map_fw_image_config(gxp, vd, gxp->fw_loader_mgr); if (err) goto error_unassign_cores; set_config_version(gxp, vd); - if (gxp->data_mgr) { - /* After map_fw_image_config because it needs vd->sys_cfg. */ - vd->fw_app = gxp_fw_data_create_app(gxp, vd); - if (IS_ERR(vd->fw_app)) { - err = PTR_ERR(vd->fw_app); - vd->fw_app = NULL; - goto error_unmap_imgcfg; - } + /* After map_fw_image_config because it needs vd->sys_cfg. */ + vd->fw_app = gxp_fw_data_create_app(gxp, vd); + if (IS_ERR(vd->fw_app)) { + err = PTR_ERR(vd->fw_app); + vd->fw_app = NULL; + goto error_unmap_imgcfg; } err = gxp_dma_map_core_resources(gxp, vd->domain, vd->core_list, vd->slice_index); @@ -971,7 +971,7 @@ void gxp_vd_stop(struct gxp_virtual_device *vd) lockdep_assert_held_write(&gxp->vd_semaphore); debug_dump_lock(gxp, vd); - if (gxp_core_boot && + if (gxp_core_boot(gxp) && (vd->state == GXP_VD_OFF || vd->state == GXP_VD_READY || vd->state == GXP_VD_RUNNING) && gxp_pm_get_blk_state(gxp) != AUR_OFF) { @@ -1043,7 +1043,7 @@ void gxp_vd_suspend(struct gxp_virtual_device *vd) u32 boot_state; uint failed_cores = 0; - if (!gxp_is_direct_mode(gxp) && gxp_core_boot) + if (!gxp_is_direct_mode(gxp) && gxp_core_boot(gxp)) return gxp_vd_stop(vd); lockdep_assert_held_write(&gxp->vd_semaphore); debug_dump_lock(gxp, vd); @@ -1055,7 +1055,7 @@ void gxp_vd_suspend(struct gxp_virtual_device *vd) "Attempt to suspend a virtual device twice\n"); goto out; } - if (!gxp_core_boot) { + if (!gxp_core_boot(gxp)) { vd->state = GXP_VD_SUSPENDED; goto out; } @@ -1165,7 +1165,7 @@ int gxp_vd_resume(struct gxp_virtual_device *vd) ret = -EBUSY; goto out; } - if (!gxp_core_boot) { + if (!gxp_core_boot(gxp)) { vd->state = GXP_VD_RUNNING; goto out; } diff --git a/include/linux/gsa/gsa_dsp.h b/include/linux/gsa/gsa_dsp.h new file mode 100644 index 0000000..288adaf --- /dev/null +++ b/include/linux/gsa/gsa_dsp.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Fallback header for systems without GSA support. + * + * Copyright (C) 2023 Google LLC + */ + +#ifndef __LINUX_GSA_DSP_H +#define __LINUX_GSA_DSP_H + +#include <linux/device.h> +#include <linux/types.h> + +static inline int gsa_load_dsp_fw_image(struct device *gsa, dma_addr_t img_meta, + phys_addr_t img_body) +{ + return 0; +} + +static inline int gsa_unload_dsp_fw_image(struct device *gsa) +{ + return 0; +} + +/** + * enum gsa_dsp_state - DSP state + * @GSA_DSP_STATE_INACTIVE: All DSP firmware images are not loaded + * @GSA_DSP_STATE_LOADING: DSP firmware images are loading + * @GSA_DSP_STATE_LOADED: All DSP firmware images are loaded + * @GSA_DSP_STATE_RUNNING: DSP is running + * @GSA_DSP_STATE_SUSPENDED: DSP is suspended + */ +enum gsa_dsp_state { + GSA_DSP_STATE_INACTIVE = 0, + GSA_DSP_STATE_LOADING, + GSA_DSP_STATE_LOADED, + GSA_DSP_STATE_RUNNING, + GSA_DSP_STATE_SUSPENDED, +}; + +/** + * enum gsa_dsp_cmd - DSP management commands + * @GSA_DSP_GET_STATE: return current DSP state + * @GSA_DSP_START: take DSP out of reset and start executing loaded + * firmware + * @GSA_DSP_SUSPEND: put DSP into suspended state + * @GSA_DSP_RESUME: take DSP out of suspended state and resume executing + * @GSA_DSP_SHUTDOWN: reset DSP + */ +enum gsa_dsp_cmd { + GSA_DSP_GET_STATE = 0, + GSA_DSP_START, + GSA_DSP_SUSPEND, + GSA_DSP_RESUME, + GSA_DSP_SHUTDOWN, +}; + +/** + * gsa_send_dsp_cmd() - execute specified DSP management command + * @gsa: pointer to GSA &struct device + * @cmd: &enum gsa_dsp_cmd to execute + * + * Return: new DSP state (&enum gsa_dsp_state) on success, negative error code + * otherwise. + */ +static inline int gsa_send_dsp_cmd(struct device *gsa, enum gsa_dsp_cmd cmd) +{ + return GSA_DSP_STATE_INACTIVE; +} + +#endif /* __LINUX_GSA_DSP_H */ |