summaryrefslogtreecommitdiff
path: root/drivers/edgetpu/mobile-firmware.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edgetpu/mobile-firmware.c')
-rw-r--r--drivers/edgetpu/mobile-firmware.c69
1 files changed, 55 insertions, 14 deletions
diff --git a/drivers/edgetpu/mobile-firmware.c b/drivers/edgetpu/mobile-firmware.c
index e8f156f..d85b27e 100644
--- a/drivers/edgetpu/mobile-firmware.c
+++ b/drivers/edgetpu/mobile-firmware.c
@@ -13,6 +13,7 @@
#include <linux/string.h>
#include <linux/types.h>
+#include <gcip/gcip-alloc-helper.h>
#include <gcip/gcip-image-config.h>
#include "edgetpu.h"
@@ -34,29 +35,69 @@ static int image_config_map(void *data, dma_addr_t daddr, phys_addr_t paddr, siz
{
struct edgetpu_dev *etdev = data;
struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
- bool ns = !(flags & GCIP_IMAGE_CONFIG_FLAGS_SECURE);
+ struct edgetpu_mobile_fw_ctx *fw_ctx;
+ int ret;
- if (ns) {
- if (paddr + size > etmdev->fw_ctx_size) {
- etdev_err(etdev, "Insufficient firmware context memory");
- return -ENOSPC;
- }
- /*
- * For non-secure mappings the physical addresses in image config are based on the
- * firmware context region.
- */
- paddr += etmdev->fw_ctx_paddr;
+ if (flags & GCIP_IMAGE_CONFIG_FLAGS_SECURE)
+ return edgetpu_mmu_add_translation(etdev, daddr, paddr, size,
+ IOMMU_READ | IOMMU_WRITE, EDGETPU_CONTEXT_KCI);
+
+ fw_ctx = kzalloc(sizeof(*fw_ctx), GFP_KERNEL);
+ if (!fw_ctx)
+ return -ENOMEM;
+
+ fw_ctx->daddr = daddr;
+ fw_ctx->size = size;
+ fw_ctx->sgt = gcip_alloc_noncontiguous(etdev->dev, size, GFP_KERNEL);
+ if (!fw_ctx->sgt) {
+ kfree(fw_ctx);
+ return -ENOMEM;
+ }
+
+ ret = edgetpu_mmu_map_iova_sgt(etdev, daddr, fw_ctx->sgt, DMA_BIDIRECTIONAL, 0,
+ EDGETPU_CONTEXT_KCI);
+ if (ret) {
+ gcip_free_noncontiguous(fw_ctx->sgt);
+ kfree(fw_ctx);
+ return ret;
}
- return edgetpu_mmu_add_translation(etdev, daddr, paddr, size,
- IOMMU_READ | IOMMU_WRITE, EDGETPU_CONTEXT_KCI);
+ mutex_lock(&etmdev->fw_ctx_list_lock);
+ list_add_tail(&fw_ctx->list, &etmdev->fw_ctx_list);
+ mutex_unlock(&etmdev->fw_ctx_list_lock);
+
+ return 0;
}
static void image_config_unmap(void *data, dma_addr_t daddr, size_t size, unsigned int flags)
{
struct edgetpu_dev *etdev = data;
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
+ struct edgetpu_mobile_fw_ctx *fw_ctx = NULL, *cur;
+
+ if (flags & GCIP_IMAGE_CONFIG_FLAGS_SECURE) {
+ edgetpu_mmu_remove_translation(etdev, daddr, size, EDGETPU_CONTEXT_KCI);
+ return;
+ }
- edgetpu_mmu_remove_translation(etdev, daddr, size, EDGETPU_CONTEXT_KCI);
+ mutex_lock(&etmdev->fw_ctx_list_lock);
+ list_for_each_entry(cur, &etmdev->fw_ctx_list, list) {
+ if (cur->daddr == daddr && cur->size == size) {
+ fw_ctx = cur;
+ list_del(&cur->list);
+ break;
+ }
+ }
+ mutex_unlock(&etmdev->fw_ctx_list_lock);
+
+ if (fw_ctx) {
+ edgetpu_mmu_unmap_iova_sgt(etdev, daddr, fw_ctx->sgt, DMA_BIDIRECTIONAL,
+ EDGETPU_CONTEXT_KCI);
+ gcip_free_noncontiguous(fw_ctx->sgt);
+ kfree(fw_ctx);
+ } else {
+ etdev_warn(etdev, "Firmware context region SG table not found.");
+ }
}
static int mobile_firmware_after_create(struct edgetpu_firmware *et_fw)