summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurora zuma automerger <aurora-zuma-automerger@google.com>2023-03-09 14:01:01 +0000
committerCopybara-Service <copybara-worker@google.com>2023-03-09 22:31:08 -0800
commit19425405130ee51277b94acf9e5599f00b5c014a (patch)
tree9dc0cde488139285faa80ff8abe9194db691b127
parent7fd75e876ae0bcbd3d47f777b0de8774a165238f (diff)
downloadzuma-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
-rw-r--r--BUILD.bazel2
-rw-r--r--Makefile1
-rw-r--r--callisto-platform.c2
-rw-r--r--callisto-platform.h2
-rw-r--r--callisto/config-pwr-state.h2
-rw-r--r--callisto/config.h2
-rw-r--r--callisto/context.h2
-rw-r--r--callisto/csrs.h2
-rw-r--r--callisto/iova.h2
-rw-r--r--callisto/lpm.h2
-rw-r--r--callisto/mailbox-regs.h2
-rw-r--r--gcip-kernel-driver/drivers/gcip/Makefile4
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-alloc-helper.c2
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-dma-fence.c2
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-domain-pool.c4
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-firmware.c4
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-image-config.c2
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-kci.c2
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-mailbox.c2
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-mem-pool.c27
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-pm.c34
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-telemetry.c3
-rw-r--r--gcip-kernel-driver/drivers/gcip/gcip-thermal.c4
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-alloc-helper.h2
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-common-image-header.h2
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-dma-fence.h2
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-domain-pool.h2
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-firmware.h8
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-image-config.h2
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-kci.h2
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-mailbox.h2
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-mem-pool.h23
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-pm.h38
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-telemetry.h3
-rw-r--r--gcip-kernel-driver/include/gcip/gcip-thermal.h8
-rw-r--r--gsx01-mailbox-driver.c2
-rw-r--r--gxp-common-platform.c21
-rw-r--r--gxp-config.h2
-rw-r--r--gxp-core-telemetry.c2
-rw-r--r--gxp-core-telemetry.h2
-rw-r--r--gxp-dci.c2
-rw-r--r--gxp-dci.h2
-rw-r--r--gxp-debug-dump.c112
-rw-r--r--gxp-debugfs.c5
-rw-r--r--gxp-dma-fence.c2
-rw-r--r--gxp-dma-fence.h2
-rw-r--r--gxp-dma-iommu.c8
-rw-r--r--gxp-firmware-data.c14
-rw-r--r--gxp-firmware-loader.c301
-rw-r--r--gxp-firmware-loader.h85
-rw-r--r--gxp-firmware.c229
-rw-r--r--gxp-firmware.h39
-rw-r--r--gxp-internal.h1
-rw-r--r--gxp-kci.c2
-rw-r--r--gxp-kci.h2
-rw-r--r--gxp-mailbox-regs.h2
-rw-r--r--gxp-mailbox.c2
-rw-r--r--gxp-mcu-firmware.c251
-rw-r--r--gxp-mcu-firmware.h20
-rw-r--r--gxp-mcu-fs.c2
-rw-r--r--gxp-mcu-fs.h2
-rw-r--r--gxp-mcu-platform.c37
-rw-r--r--gxp-mcu-platform.h2
-rw-r--r--gxp-mcu-telemetry.c2
-rw-r--r--gxp-mcu-telemetry.h2
-rw-r--r--gxp-mcu.c2
-rw-r--r--gxp-mcu.h2
-rw-r--r--gxp-ssmt.c2
-rw-r--r--gxp-ssmt.h2
-rw-r--r--gxp-uci.c14
-rw-r--r--gxp-uci.h2
-rw-r--r--gxp-vd.c44
-rw-r--r--include/linux/gsa/gsa_dsp.h71
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")
diff --git a/Makefile b/Makefile
index 472c13e..c6e4d2b 100644
--- a/Makefile
+++ b/Makefile
@@ -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
*
diff --git a/gxp-dci.c b/gxp-dci.c
index 8c0aa2d..82bfc78 100644
--- a/gxp-dci.c
+++ b/gxp-dci.c
@@ -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-dci.h b/gxp-dci.h
index 3f99326..09eaed4 100644
--- a/gxp-dci.h
+++ b/gxp-dci.h
@@ -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
diff --git a/gxp-kci.c b/gxp-kci.c
index 6e19686..46636d4 100644
--- a/gxp-kci.c
+++ b/gxp-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 DSP Kernel driver and MCU firmware.
*
diff --git a/gxp-kci.h b/gxp-kci.h
index ca7c143..cb5e23d 100644
--- a/gxp-kci.h
+++ b/gxp-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 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
*
diff --git a/gxp-mcu.c b/gxp-mcu.c
index 7d6d2c4..4fda8d8 100644
--- a/gxp-mcu.c
+++ b/gxp-mcu.c
@@ -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.
*
diff --git a/gxp-mcu.h b/gxp-mcu.h
index d8c8fbe..3612af9 100644
--- a/gxp-mcu.h
+++ b/gxp-mcu.h
@@ -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.
*
diff --git a/gxp-ssmt.c b/gxp-ssmt.c
index 657f4e8..403da5d 100644
--- a/gxp-ssmt.c
+++ b/gxp-ssmt.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* GXP SSMT driver.
*
diff --git a/gxp-ssmt.h b/gxp-ssmt.h
index b37bb53..b35829d 100644
--- a/gxp-ssmt.h
+++ b/gxp-ssmt.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* GXP SSMT driver.
*
diff --git a/gxp-uci.c b/gxp-uci.c
index e4f81a3..1506e9a 100644
--- a/gxp-uci.c
+++ b/gxp-uci.c
@@ -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);
diff --git a/gxp-uci.h b/gxp-uci.h
index a6c1a92..50d9ce0 100644
--- a/gxp-uci.h
+++ b/gxp-uci.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0 */
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* GXP user command interface.
*
diff --git a/gxp-vd.c b/gxp-vd.c
index 57011ba..115f19e 100644
--- a/gxp-vd.c
+++ b/gxp-vd.c
@@ -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 */