summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuma copybara merger <zuma-automerger@google.com>2023-06-01 19:35:23 +0800
committerDavid Chiang <davidchiang@google.com>2023-06-10 02:58:55 +0000
commitb136a231d24aa456d94e87fda93f4ba8c02d1a8d (patch)
tree6b2a2bcc31d5726ea73c60d1353ba47af12e9515
parent8b939d935ca255d445f37054c6b0a054e2121497 (diff)
downloadrio-b136a231d24aa456d94e87fda93f4ba8c02d1a8d.tar.gz
[Copybara Auto Merge] Merge branch zuma into android14-gs-pixel-5.15
gcip: check block power state before fetching resp Bug: 283659596 gcip: Set .is_block_off to gcip_mailbox Bug: 283659596 (repeat) gcip: Add gcip_pm_put_async gcip: iommu: legacy mode do not double map for default domain gcip: keep track of whether a gdomain is for the default domain gcip: Add .is_block_off to gcip_{kci,mailbox} Bug: 283659596 (repeat) gcip: Add gcip_pm_put_async gcip: include: keep track of whether a gdomain is for the default domain edgetpu: Set .is_block_off for gcip_kci Bug: 283659596 (repeat) edgetpu: Move pmu_status to edgetpu_dev Bug: 283659596 (repeat) edgetpu: hold mmap_lock around pin_user_pages mmap_lock must be held around call to pin_user_pages to protect against concurrent address space modifications. Bug: 283787360 (cherry picked from commit 38761382e80a3446ded8e60e121d5357bdceb8be) (cherry picked from commit 97d6d45f552d5ee711c15b5085b2af5e726a17ec) edgetpu: remove code for no KCI data structure edgetpu: debug prints for iommu mapping calls edgetpu: Use gcip_iommu_domain_pool_enable_best_fit_algo Bug: 275112261 edgetpu: Remove the edgetpu_mmu_tpu_map interface edgetpu: Use per-domain IOVA for coherent buffers Bug: 275112261 (repeat) edgetpu: Add edgetpu_mmu_(un)map_sgt() Bug: 275112261 (repeat) edgetpu: Use per-domain IOVA for dma-bufs Bug: 275112261 (repeat) edgetpu: Adopt gcip-iommu with split IOVA-space Bug: 275112261 (repeat) edgetpu: Store a pointer to the default domain Bug: 275112261 (repeat) edgetpu: Remove dead mmu_alloc/reserve/free code gcip: Call iova_domain_init_rcaches on kernel >= 5.18 Bug: 284584586 edgetpu: usage-stats remove unnecessary out of memory log Signed-off-by: Zuma copybara merger <zuma-automerger@google.com> GitOrigin-RevId: d679cc93e4dec8214959ee855a00ba301d178555 Change-Id: Id5ec8ac4ee4dd44c36dcf08cad9b7b56a61e0d30
-rw-r--r--drivers/edgetpu/edgetpu-core.c59
-rw-r--r--drivers/edgetpu/edgetpu-device-group.c2
-rw-r--r--drivers/edgetpu/edgetpu-dmabuf.c167
-rw-r--r--drivers/edgetpu/edgetpu-google-iommu.c449
-rw-r--r--drivers/edgetpu/edgetpu-internal.h12
-rw-r--r--drivers/edgetpu/edgetpu-iremap-pool.h2
-rw-r--r--drivers/edgetpu/edgetpu-kci.c39
-rw-r--r--drivers/edgetpu/edgetpu-mmu.h122
-rw-r--r--drivers/edgetpu/edgetpu-mobile-platform.c17
-rw-r--r--drivers/edgetpu/edgetpu-mobile-platform.h2
-rw-r--r--drivers/edgetpu/edgetpu-usage-stats.c4
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-iommu.c27
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-kci.c10
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c8
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-pm.c19
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-iommu.h5
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-kci.h5
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h5
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-pm.h8
-rw-r--r--drivers/edgetpu/mobile-soc-gsx01.c2
-rw-r--r--drivers/edgetpu/rio-pm.c5
21 files changed, 373 insertions, 596 deletions
diff --git a/drivers/edgetpu/edgetpu-core.c b/drivers/edgetpu/edgetpu-core.c
index 18bffa2..d34c951 100644
--- a/drivers/edgetpu/edgetpu-core.c
+++ b/drivers/edgetpu/edgetpu-core.c
@@ -656,29 +656,72 @@ int edgetpu_alloc_coherent(struct edgetpu_dev *etdev, size_t size,
enum edgetpu_context_id context_id)
{
const u32 flags = EDGETPU_MMU_CC_ACCESS | EDGETPU_MMU_HOST | EDGETPU_MMU_COHERENT;
+ int ret;
mem->vaddr = dma_alloc_coherent(etdev->dev, size, &mem->dma_addr,
GFP_KERNEL);
if (!mem->vaddr)
return -ENOMEM;
+
edgetpu_x86_coherent_mem_init(mem);
- mem->tpu_addr =
- edgetpu_mmu_tpu_map(etdev, mem->dma_addr, size,
- DMA_BIDIRECTIONAL, context_id, flags);
- if (!mem->tpu_addr) {
- dma_free_coherent(etdev->dev, size, mem->vaddr, mem->dma_addr);
- mem->vaddr = NULL;
- return -EINVAL;
+
+ /* If this context's mappings reside in the default domain, we're done */
+ if (edgetpu_mmu_is_context_using_default_domain(etdev, context_id)) {
+ mem->tpu_addr = mem->dma_addr;
+ mem->size = size;
+ return 0;
+ }
+
+ /*
+ * dma_get_sgtable may not always be available, and coherent buffers are always physically
+ * contiguous, so create a 1-entry sgt by hand.
+ */
+ mem->client_sgt = kzalloc(sizeof(*mem->client_sgt), GFP_KERNEL);
+ if (!mem->client_sgt) {
+ ret = -ENOMEM;
+ goto err_free_coherent;
}
+ mem->client_sgt->sgl = kzalloc(sizeof(*mem->client_sgt->sgl), GFP_KERNEL);
+ if (!mem->client_sgt->sgl) {
+ ret = -ENOMEM;
+ goto err_free_sgt;
+ }
+ mem->client_sgt->nents = 1;
+ mem->client_sgt->orig_nents = 1;
+ sg_set_page(mem->client_sgt->sgl, virt_to_page(mem->vaddr), PAGE_ALIGN(size), 0);
+
+ ret = edgetpu_mmu_map_sgt(etdev, mem->client_sgt, context_id, DMA_BIDIRECTIONAL, 0, flags);
+ if (!ret) {
+ etdev_err(etdev, "Failed to map coherent buffer to context %#X\n", context_id);
+ ret = -EIO;
+ goto err_free_sgl;
+ }
+
+ mem->tpu_addr = sg_dma_address(mem->client_sgt->sgl);
mem->size = size;
return 0;
+
+err_free_sgl:
+ kfree(mem->client_sgt->sgl);
+err_free_sgt:
+ kfree(mem->client_sgt);
+ mem->client_sgt = NULL;
+err_free_coherent:
+ dma_free_coherent(etdev->dev, size, mem->vaddr, mem->dma_addr);
+ mem->vaddr = NULL;
+ return ret;
}
void edgetpu_free_coherent(struct edgetpu_dev *etdev,
struct edgetpu_coherent_mem *mem,
enum edgetpu_context_id context_id)
{
- edgetpu_mmu_tpu_unmap(etdev, mem->tpu_addr, mem->size, context_id);
+ if (!edgetpu_mmu_is_context_using_default_domain(etdev, context_id)) {
+ edgetpu_mmu_unmap_sgt(etdev, mem->client_sgt, context_id, DMA_BIDIRECTIONAL,
+ /*dma_attrs=*/0, /*mmu_flags=*/0);
+ kfree(mem->client_sgt->sgl);
+ kfree(mem->client_sgt);
+ }
edgetpu_x86_coherent_mem_set_wb(mem);
dma_free_coherent(etdev->dev, mem->size, mem->vaddr, mem->dma_addr);
mem->vaddr = NULL;
diff --git a/drivers/edgetpu/edgetpu-device-group.c b/drivers/edgetpu/edgetpu-device-group.c
index cb7d9d9..3e94dcd 100644
--- a/drivers/edgetpu/edgetpu-device-group.c
+++ b/drivers/edgetpu/edgetpu-device-group.c
@@ -730,8 +730,10 @@ static struct page **edgetpu_pin_user_pages(struct edgetpu_device_group *group,
kvfree(pages);
return ERR_PTR(-ENOMEM);
}
+ mmap_read_lock(current->mm);
ret = pin_user_pages(host_addr & PAGE_MASK, num_pages, foll_flags,
pages, vmas);
+ mmap_read_unlock(current->mm);
kvfree(vmas);
if (ret < 0) {
etdev_dbg(etdev, "pin_user_pages failed %u:%pK-%u: %d",
diff --git a/drivers/edgetpu/edgetpu-dmabuf.c b/drivers/edgetpu/edgetpu-dmabuf.c
index 4ca8c40..b1b549a 100644
--- a/drivers/edgetpu/edgetpu-dmabuf.c
+++ b/drivers/edgetpu/edgetpu-dmabuf.c
@@ -33,20 +33,6 @@
#define to_etfence(gfence) container_of(gfence, struct edgetpu_dma_fence, gfence)
/*
- * Records objects for mapping a dma-buf to an edgetpu_dev.
- */
-struct dmabuf_map_entry {
- struct dma_buf_attachment *attachment;
- /* SG table returned by dma_buf_map_attachment() */
- struct sg_table *sgt;
- /*
- * The SG table that shrunk and condensed from @sgt with region [0, size), where @size is
- * the size field in edgetpu_dmabuf_map which owns this entry.
- */
- struct sg_table shrunk_sgt;
-};
-
-/*
* Records the mapping and other fields needed for mapping a dma-buf to a device
* group.
*/
@@ -55,7 +41,9 @@ struct edgetpu_dmabuf_map {
u64 size; /* size of this mapping in bytes */
u32 mmu_flags;
struct dma_buf *dmabuf;
- struct dmabuf_map_entry *map_entry;
+ struct dma_buf_attachment *attachment;
+ /* SG table returned by dma_buf_map_attachment(). Records default domain mapping. */
+ struct sg_table *dma_sgt;
};
/*
@@ -74,27 +62,17 @@ struct edgetpu_dma_fence {
static const struct dma_fence_ops edgetpu_dma_fence_ops;
/*
- * Maps @dmap->map_entry.
+ * Maps @dmap->map into its owning device group's context.
*
* Caller holds @group->lock.
*/
-static int etdev_map_dmabuf(struct edgetpu_dev *etdev,
- struct edgetpu_dmabuf_map *dmap,
- tpu_addr_t *tpu_addr_p)
+static int etdev_map_dmabuf(struct edgetpu_dev *etdev, struct edgetpu_dmabuf_map *dmap)
{
struct edgetpu_device_group *group = dmap->map.priv;
const enum edgetpu_context_id ctx_id =
edgetpu_group_context_id_locked(group);
- struct dmabuf_map_entry *entry = dmap->map_entry;
- tpu_addr_t tpu_addr;
-
- tpu_addr = edgetpu_mmu_tpu_map_sgt(etdev, &entry->shrunk_sgt,
- dmap->map.dir,
- ctx_id, dmap->mmu_flags);
- if (!tpu_addr)
- return -ENOSPC;
- *tpu_addr_p = tpu_addr;
- return 0;
+
+ return edgetpu_mmu_map(etdev, &dmap->map, ctx_id, dmap->mmu_flags);
}
/*
@@ -102,16 +80,13 @@ static int etdev_map_dmabuf(struct edgetpu_dev *etdev,
*
* Caller holds @group->lock.
*/
-static void etdev_unmap_dmabuf(struct edgetpu_dev *etdev,
- struct edgetpu_dmabuf_map *dmap,
- tpu_addr_t tpu_addr)
+static void etdev_unmap_dmabuf(struct edgetpu_dev *etdev, struct edgetpu_dmabuf_map *dmap)
{
struct edgetpu_device_group *group = dmap->map.priv;
const enum edgetpu_context_id ctx_id =
edgetpu_group_context_id_locked(group);
- struct dmabuf_map_entry *entry = dmap->map_entry;
- edgetpu_mmu_tpu_unmap_sgt(etdev, tpu_addr, &entry->shrunk_sgt, ctx_id);
+ edgetpu_mmu_unmap(etdev, &dmap->map, ctx_id);
}
/*
@@ -126,26 +101,22 @@ static void dmabuf_map_callback_release(struct edgetpu_mapping *map)
container_of(map, struct edgetpu_dmabuf_map, map);
struct edgetpu_device_group *group = map->priv;
const enum dma_data_direction dir = map->dir;
- struct dmabuf_map_entry *entry = dmap->map_entry;
- tpu_addr_t tpu_addr = map->device_address;
-
- if (tpu_addr)
- etdev_unmap_dmabuf(group->etdev, dmap, tpu_addr);
- sg_free_table(&entry->shrunk_sgt);
- if (entry->sgt)
- dma_buf_unmap_attachment(entry->attachment, entry->sgt, dir);
- if (entry->attachment)
- dma_buf_detach(dmap->dmabuf, entry->attachment);
+
+ if (dmap->map.device_address)
+ etdev_unmap_dmabuf(group->etdev, dmap);
+ sg_free_table(&dmap->map.sgt);
+ if (dmap->dma_sgt)
+ dma_buf_unmap_attachment(dmap->attachment, dmap->dma_sgt, dir);
+ if (dmap->attachment)
+ dma_buf_detach(dmap->dmabuf, dmap->attachment);
dma_buf_put(dmap->dmabuf);
edgetpu_device_group_put(group);
- kfree(dmap->map_entry);
kfree(dmap);
}
-static void entry_show_dma_addrs(struct dmabuf_map_entry *entry,
- struct seq_file *s)
+static void entry_show_dma_addrs(struct edgetpu_dmabuf_map *dmap, struct seq_file *s)
{
- struct sg_table *sgt = &entry->shrunk_sgt;
+ struct sg_table *sgt = &dmap->map.sgt;
if (sgt->nents == 1) {
seq_printf(s, "%pad\n", &sg_dma_address(sgt->sgl));
@@ -164,18 +135,16 @@ static void entry_show_dma_addrs(struct dmabuf_map_entry *entry,
}
}
-static void dmabuf_map_callback_show(struct edgetpu_mapping *map,
- struct seq_file *s)
+static void dmabuf_map_callback_show(struct edgetpu_mapping *map, struct seq_file *s)
{
struct edgetpu_dmabuf_map *dmap =
container_of(map, struct edgetpu_dmabuf_map, map);
- seq_printf(s, " <%s> iova=%#llx pages=%llu %s",
- dmap->dmabuf->exp_name, map->device_address,
- DIV_ROUND_UP(dmap->size, PAGE_SIZE),
- edgetpu_dma_dir_rw_s(map->dir));
+ seq_printf(s, " <%s> iova=%#llx (default=%#llx) pages=%llu %s", dmap->dmabuf->exp_name,
+ map->device_address, sg_dma_address(dmap->dma_sgt->sgl),
+ DIV_ROUND_UP(dmap->size, PAGE_SIZE), edgetpu_dma_dir_rw_s(map->dir));
seq_puts(s, " dma=");
- entry_show_dma_addrs(dmap->map_entry, s);
+ entry_show_dma_addrs(dmap, s);
}
/*
@@ -193,9 +162,6 @@ alloc_dmabuf_map(struct edgetpu_device_group *group, edgetpu_map_flag_t flags)
if (!dmap)
return NULL;
- dmap->map_entry = kzalloc(sizeof(*dmap->map_entry), GFP_KERNEL);
- if (!dmap->map_entry)
- goto err_free;
dmap->mmu_flags = map_to_mmu_flags(flags) | EDGETPU_MMU_DMABUF;
map = &dmap->map;
map->flags = flags;
@@ -204,11 +170,6 @@ alloc_dmabuf_map(struct edgetpu_device_group *group, edgetpu_map_flag_t flags)
map->show = dmabuf_map_callback_show;
map->priv = edgetpu_device_group_get(group);
return dmap;
-
-err_free:
- kfree(dmap->map_entry);
- kfree(dmap);
- return NULL;
}
/*
@@ -257,64 +218,14 @@ static int dup_sgt_in_region(struct sg_table *sgt, u64 size, struct sg_table *ou
}
/*
- * Copy the DMA addresses and lengths in region [0, @size) from
- * @sgt to @out.
- *
- * The DMA addresses will be condensed when possible.
- */
-static void shrink_sgt_dma_in_region(struct sg_table *sgt, u64 size, struct sg_table *out)
-{
- u64 cur_offset = 0;
- struct scatterlist *sg, *prv_sg = NULL, *cur_sg;
-
- cur_sg = out->sgl;
- out->nents = 0;
- for (sg = sgt->sgl; sg;
- cur_offset += sg_dma_len(sg), sg = sg_next(sg)) {
- u64 remain_size = size - cur_offset;
- dma_addr_t dma;
- size_t len;
-
- dma = sg_dma_address(sg);
- len = sg_dma_len(sg);
- if (remain_size < sg_dma_len(sg))
- len -= sg_dma_len(sg) - remain_size;
- if (prv_sg &&
- sg_dma_address(prv_sg) + sg_dma_len(prv_sg) == dma) {
- /* merge to previous sg */
- sg_dma_len(prv_sg) += len;
- } else {
- sg_dma_address(cur_sg) = dma;
- sg_dma_len(cur_sg) = len;
- prv_sg = cur_sg;
- cur_sg = sg_next(cur_sg);
- out->nents++;
- }
- if (remain_size <= sg_dma_len(sg))
- break;
- }
-}
-
-static int entry_set_shrunk_sgt(struct dmabuf_map_entry *entry, u64 size)
-{
- int ret;
-
- ret = dup_sgt_in_region(entry->sgt, size, &entry->shrunk_sgt);
- if (ret)
- return ret;
- shrink_sgt_dma_in_region(entry->sgt, size, &entry->shrunk_sgt);
- return 0;
-}
-
-/*
* Performs dma_buf_attach + dma_buf_map_attachment of @dmabuf to @etdev, and
- * sets @entry per the attaching result.
+ * sets @dmap per the attaching result.
*
- * Fields of @entry will be set on success.
+ * Fields of @dmap will be set on success.
*/
-static int etdev_attach_dmabuf_to_entry(struct edgetpu_dev *etdev, struct dma_buf *dmabuf,
- struct dmabuf_map_entry *entry, u64 size,
- enum dma_data_direction dir)
+static int etdev_attach_dmabuf_to_mapping(struct edgetpu_dev *etdev, struct dma_buf *dmabuf,
+ struct edgetpu_dmabuf_map *dmap, u64 size,
+ enum dma_data_direction dir)
{
struct dma_buf_attachment *attachment;
struct sg_table *sgt;
@@ -328,9 +239,9 @@ static int etdev_attach_dmabuf_to_entry(struct edgetpu_dev *etdev, struct dma_bu
ret = PTR_ERR(sgt);
goto err_detach;
}
- entry->attachment = attachment;
- entry->sgt = sgt;
- ret = entry_set_shrunk_sgt(entry, size);
+ dmap->attachment = attachment;
+ dmap->dma_sgt = sgt;
+ ret = dup_sgt_in_region(dmap->dma_sgt, size, &dmap->map.sgt);
if (ret)
goto err_unmap;
@@ -340,8 +251,8 @@ err_unmap:
dma_buf_unmap_attachment(attachment, sgt, dir);
err_detach:
dma_buf_detach(dmabuf, attachment);
- entry->sgt = NULL;
- entry->attachment = NULL;
+ dmap->dma_sgt = NULL;
+ dmap->attachment = NULL;
return ret;
}
@@ -354,7 +265,6 @@ int edgetpu_map_dmabuf(struct edgetpu_device_group *group,
u64 size;
const enum dma_data_direction dir = map_flag_to_host_dma_dir(flags);
struct edgetpu_dmabuf_map *dmap;
- tpu_addr_t tpu_addr;
if (!valid_dma_direction(dir)) {
etdev_dbg(group->etdev, "%s: invalid direction %d\n", __func__, dir);
@@ -385,35 +295,32 @@ int edgetpu_map_dmabuf(struct edgetpu_device_group *group,
get_dma_buf(dmabuf);
dmap->dmabuf = dmabuf;
dmap->map.map_size = dmap->size = size = dmabuf->size;
- ret = etdev_attach_dmabuf_to_entry(group->etdev, dmabuf,
- dmap->map_entry, size, dir);
+ ret = etdev_attach_dmabuf_to_mapping(group->etdev, dmabuf, dmap, size, dir);
if (ret) {
etdev_dbg(group->etdev,
"%s: etdev_attach_dmabuf_to_entry returns %d\n",
__func__, ret);
goto err_release_map;
}
- ret = etdev_map_dmabuf(group->etdev, dmap, &tpu_addr);
+ ret = etdev_map_dmabuf(group->etdev, dmap);
if (ret) {
etdev_dbg(group->etdev,
"%s: etdev_map_dmabuf returns %d\n",
__func__, ret);
goto err_release_map;
}
- dmap->map.device_address = tpu_addr;
ret = edgetpu_mapping_add(&group->dmabuf_mappings, &dmap->map);
if (ret) {
etdev_dbg(group->etdev, "%s: edgetpu_mapping_add returns %d\n",
__func__, ret);
goto err_release_map;
}
- arg->device_address = tpu_addr;
+ arg->device_address = dmap->map.device_address;
mutex_unlock(&group->lock);
dma_buf_put(dmabuf);
return 0;
err_release_map:
- /* also releases map_entry if set */
dmabuf_map_callback_release(&dmap->map);
err_unlock_group:
mutex_unlock(&group->lock);
diff --git a/drivers/edgetpu/edgetpu-google-iommu.c b/drivers/edgetpu/edgetpu-google-iommu.c
index 1aee8df..1bc4a4e 100644
--- a/drivers/edgetpu/edgetpu-google-iommu.c
+++ b/drivers/edgetpu/edgetpu-google-iommu.c
@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/types.h>
-#include <gcip/gcip-domain-pool.h>
+#include <gcip/gcip-iommu.h>
#include "edgetpu-config.h"
#include "edgetpu-internal.h"
@@ -30,7 +30,12 @@ struct edgetpu_iommu {
* IOMMU domains currently attached.
* NULL for a slot that doesn't have an attached domain.
*/
- struct iommu_domain *domains[EDGETPU_NCONTEXTS];
+ struct gcip_iommu_domain *gdomains[EDGETPU_NCONTEXTS];
+ /*
+ * Pointer to the default domain. `domains[0]` will always point to `default_domain`, if
+ * initialization of this structure is successful.
+ */
+ struct gcip_iommu_domain *default_gdomain;
/*
* Records IDs for all domains currently allocated, to support IOMMU (un)mapping
* when the domain is not attached.
@@ -44,14 +49,7 @@ struct edgetpu_iommu {
* required.
* The implementation will fall back to dynamically allocated domains otherwise.
*/
- struct gcip_domain_pool domain_pool;
-
-};
-
-struct edgetpu_iommu_map_params {
- int prot;
- size_t size;
- struct iommu_domain *domain;
+ struct gcip_iommu_domain_pool domain_pool;
};
/*
@@ -64,29 +62,26 @@ static uint context_id_to_pasid(enum edgetpu_context_id context_id)
return (uint)context_id;
}
-static struct iommu_domain *get_domain_by_token(struct edgetpu_iommu *etiommu,
- int token)
+static struct gcip_iommu_domain *get_domain_by_token(struct edgetpu_iommu *etiommu, int token)
{
- struct iommu_domain *domain;
+ struct gcip_iommu_domain *gdomain;
mutex_lock(&etiommu->pool_lock);
- domain = idr_find(&etiommu->domain_id_pool, token);
+ gdomain = idr_find(&etiommu->domain_id_pool, token);
mutex_unlock(&etiommu->pool_lock);
- return domain;
+ return gdomain;
}
-static struct iommu_domain *
-get_domain_by_context_id(struct edgetpu_dev *etdev,
- enum edgetpu_context_id ctx_id)
+static struct gcip_iommu_domain *get_domain_by_context_id(struct edgetpu_dev *etdev,
+ enum edgetpu_context_id ctx_id)
{
- struct iommu_domain *domain = NULL;
- struct device *dev = etdev->dev;
+ struct gcip_iommu_domain *gdomain = NULL;
struct edgetpu_iommu *etiommu = etdev->mmu_cookie;
uint pasid;
/* always return the default domain when AUX is not supported */
if (!etiommu->aux_enabled)
- return iommu_get_domain_for_dev(dev);
+ return etiommu->default_gdomain;
if (ctx_id == EDGETPU_CONTEXT_INVALID)
return NULL;
if (ctx_id & EDGETPU_CONTEXT_DOMAIN_TOKEN)
@@ -94,12 +89,20 @@ get_domain_by_context_id(struct edgetpu_dev *etdev,
etiommu, ctx_id ^ EDGETPU_CONTEXT_DOMAIN_TOKEN);
pasid = context_id_to_pasid(ctx_id);
if (pasid < EDGETPU_NCONTEXTS)
- domain = etiommu->domains[pasid];
+ gdomain = etiommu->gdomains[pasid];
/* Fall back to default domain. */
- if (!domain)
- domain = iommu_get_domain_for_dev(dev);
- return domain;
+ if (!gdomain)
+ gdomain = etiommu->default_gdomain;
+ return gdomain;
+}
+
+bool edgetpu_mmu_is_context_using_default_domain(struct edgetpu_dev *etdev,
+ enum edgetpu_context_id ctx_id)
+{
+ struct edgetpu_iommu *etiommu = etdev->mmu_cookie;
+
+ return get_domain_by_context_id(etdev, ctx_id) == etiommu->default_gdomain;
}
static int edgetpu_iommu_dev_fault_handler(struct iommu_fault *fault,
@@ -143,10 +146,10 @@ static int edgetpu_unregister_iommu_device_fault_handler(struct edgetpu_dev *etd
/* A callback for idr_for_each to release the domains */
static int edgetpu_idr_free_domain_callback(int id, void *p, void *data)
{
- struct iommu_domain *domain = p;
+ struct gcip_iommu_domain *gdomain = p;
struct edgetpu_iommu *etiommu = data;
- gcip_domain_pool_free(&etiommu->domain_pool, domain);
+ gcip_iommu_domain_pool_free_domain(&etiommu->domain_pool, gdomain);
return 0;
}
@@ -154,8 +157,7 @@ static int edgetpu_iommu_fault_handler(struct iommu_domain *domain,
struct device *dev, unsigned long iova,
int flags, void *token)
{
- struct edgetpu_iommu_domain *etdomain =
- (struct edgetpu_iommu_domain *)token;
+ struct edgetpu_iommu_domain *etdomain = (struct edgetpu_iommu_domain *)token;
dev_dbg(dev, "IOMMU fault on address %08lX. PASID = %u flags = %08X",
iova, etdomain->pasid, flags);
@@ -164,13 +166,12 @@ static int edgetpu_iommu_fault_handler(struct iommu_domain *domain,
}
static void edgetpu_init_etdomain(struct edgetpu_iommu_domain *etdomain,
- struct iommu_domain *domain,
- int token)
+ struct gcip_iommu_domain *gdomain, int token)
{
- etdomain->iommu_domain = domain;
+ etdomain->gdomain = gdomain;
etdomain->pasid = IOMMU_PASID_INVALID;
etdomain->token = token;
- iommu_set_fault_handler(domain, edgetpu_iommu_fault_handler, etdomain);
+ iommu_set_fault_handler(gdomain->domain, edgetpu_iommu_fault_handler, etdomain);
}
/*
@@ -180,13 +181,13 @@ static void edgetpu_init_etdomain(struct edgetpu_iommu_domain *etdomain,
static int check_default_domain(struct edgetpu_dev *etdev,
struct edgetpu_iommu *etiommu)
{
- struct iommu_domain *domain;
+ struct gcip_iommu_domain *gdomain;
int ret;
uint pasid;
- domain = iommu_get_domain_for_dev(etdev->dev);
+ gdomain = gcip_iommu_get_domain_for_dev(etdev->dev);
/* if default domain exists then we are done */
- if (domain) {
+ if (gdomain) {
etiommu->context_0_default = true;
goto out;
}
@@ -195,28 +196,29 @@ static int check_default_domain(struct edgetpu_dev *etdev,
if (!etiommu->aux_enabled)
return -EINVAL;
- domain = gcip_domain_pool_alloc(&etiommu->domain_pool);
- if (!domain) {
+ gdomain = gcip_iommu_domain_pool_alloc_domain(&etiommu->domain_pool);
+ if (!gdomain) {
etdev_warn(etdev, "iommu domain alloc failed");
return -EINVAL;
}
- ret = iommu_aux_attach_device(domain, etdev->dev);
+ ret = iommu_aux_attach_device(gdomain->domain, etdev->dev);
if (ret) {
etdev_warn(etdev, "Attach IOMMU aux failed: %d", ret);
- gcip_domain_pool_free(&etiommu->domain_pool, domain);
+ gcip_iommu_domain_pool_free_domain(&etiommu->domain_pool, gdomain);
return ret;
}
- pasid = iommu_aux_get_pasid(domain, etdev->dev);
+ pasid = iommu_aux_get_pasid(gdomain->domain, etdev->dev);
/* the default domain must have pasid = 0 */
if (pasid != 0) {
etdev_warn(etdev, "Invalid PASID %d returned from iommu\n",
pasid);
- iommu_aux_detach_device(domain, etdev->dev);
- gcip_domain_pool_free(&etiommu->domain_pool, domain);
+ iommu_aux_detach_device(gdomain->domain, etdev->dev);
+ gcip_iommu_domain_pool_free_domain(&etiommu->domain_pool, gdomain);
return -EINVAL;
}
out:
- etiommu->domains[0] = domain;
+ etiommu->default_gdomain = gdomain;
+ etiommu->gdomains[0] = gdomain;
return 0;
}
@@ -229,8 +231,19 @@ int edgetpu_mmu_attach(struct edgetpu_dev *etdev, void *mmu_info)
etiommu = kzalloc(sizeof(*etiommu), GFP_KERNEL);
if (!etiommu)
return -ENOMEM;
- ret = gcip_domain_pool_init(etdev->dev, &etiommu->domain_pool,
- EDGETPU_NUM_PREALLOCATED_DOMAINS);
+ /*
+ * Specify `base_addr` and `iova_space_size` as 0 so the gcip_iommu_domain_pool will obtain
+ * the values from the device tree.
+ */
+ ret = gcip_iommu_domain_pool_init(&etiommu->domain_pool, etdev->dev, 0, 0, SZ_4K,
+ EDGETPU_NUM_PREALLOCATED_DOMAINS,
+ GCIP_IOMMU_DOMAIN_TYPE_IOVAD);
+ if (ret) {
+ etdev_err(etdev, "Unable create domain pool (%d)\n", ret);
+ goto err_free_etiommu;
+ }
+ gcip_iommu_domain_pool_enable_best_fit_algo(&etiommu->domain_pool);
+
idr_init(&etiommu->domain_id_pool);
mutex_init(&etiommu->pool_lock);
etiommu->iommu_group = iommu_group_get(etdev->dev);
@@ -246,7 +259,7 @@ int edgetpu_mmu_attach(struct edgetpu_dev *etdev, void *mmu_info)
etiommu->aux_enabled = true;
ret = check_default_domain(etdev, etiommu);
if (ret)
- goto err_free;
+ goto err_destroy_pool;
ret = edgetpu_register_iommu_device_fault_handler(etdev);
if (ret)
@@ -257,7 +270,9 @@ int edgetpu_mmu_attach(struct edgetpu_dev *etdev, void *mmu_info)
etdev->mmu_cookie = etiommu;
return 0;
-err_free:
+err_destroy_pool:
+ gcip_iommu_domain_pool_destroy(&etiommu->domain_pool);
+err_free_etiommu:
kfree(etiommu);
return ret;
}
@@ -277,117 +292,104 @@ void edgetpu_mmu_detach(struct edgetpu_dev *etdev)
ret);
for (i = etiommu->context_0_default ? 1 : 0; i < EDGETPU_NCONTEXTS;
i++) {
- if (etiommu->domains[i])
- iommu_aux_detach_device(etiommu->domains[i],
- etdev->dev);
+ if (etiommu->gdomains[i])
+ iommu_aux_detach_device(etiommu->gdomains[i]->domain, etdev->dev);
}
if (etiommu->iommu_group)
iommu_group_put(etiommu->iommu_group);
/* free the domain if the context 0 domain is not default */
- if (!etiommu->context_0_default && etiommu->domains[0])
- gcip_domain_pool_free(&etiommu->domain_pool, etiommu->domains[0]);
+ if (!etiommu->context_0_default && etiommu->gdomains[0])
+ gcip_iommu_domain_pool_free_domain(&etiommu->domain_pool, etiommu->gdomains[0]);
idr_for_each(&etiommu->domain_id_pool, edgetpu_idr_free_domain_callback,
etiommu);
idr_destroy(&etiommu->domain_id_pool);
- gcip_domain_pool_destroy(&etiommu->domain_pool);
+ gcip_iommu_domain_pool_destroy(&etiommu->domain_pool);
kfree(etiommu);
etdev->mmu_cookie = NULL;
}
-static int get_iommu_map_params(struct edgetpu_dev *etdev,
- struct edgetpu_mapping *map,
- enum edgetpu_context_id context_id,
- struct edgetpu_iommu_map_params *params, u32 mmu_flags)
+int edgetpu_mmu_map(struct edgetpu_dev *etdev, struct edgetpu_mapping *map,
+ enum edgetpu_context_id context_id, u32 mmu_flags)
{
- struct edgetpu_iommu *etiommu = etdev->mmu_cookie;
- size_t size = 0;
- int prot = mmu_flag_to_iommu_prot(mmu_flags, etdev->dev, map->dir);
- struct iommu_domain *domain;
- int i;
- struct scatterlist *sg;
+ int ret;
- if (!etiommu)
+ ret = edgetpu_mmu_map_sgt(etdev, &map->sgt, context_id, map->dir, map->dma_attrs,
+ mmu_flags);
+ if (!ret)
return -EINVAL;
- domain = get_domain_by_context_id(etdev, context_id);
- if (!domain) {
- etdev_err(etdev, "Unable to find an iommu domain\n");
- return -ENODEV;
- }
-
- for_each_sg(map->sgt.sgl, sg, map->sgt.orig_nents, i)
- size += sg->length;
-
- prot |= IOMMU_PBHA_PROT(EDGEPTU_MAP_PBHA_VALUE(map->flags));
- params->prot = prot;
- params->size = size;
- params->domain = domain;
+ map->sgt.nents = ret;
+ map->device_address = sg_dma_address(map->sgt.sgl);
+ etdev_dbg(etdev, "%s: ctx=%x iova=%#llx dma=%#llx size=%#x flags=%#x\n",
+ __func__, context_id, map->device_address, (u64)sg_dma_address(map->sgt.sgl),
+ sg_dma_len(map->sgt.sgl), mmu_flags);
return 0;
}
-int edgetpu_mmu_map(struct edgetpu_dev *etdev, struct edgetpu_mapping *map,
- enum edgetpu_context_id context_id, u32 mmu_flags)
+void edgetpu_mmu_unmap(struct edgetpu_dev *etdev, struct edgetpu_mapping *map,
+ enum edgetpu_context_id context_id)
{
+ edgetpu_mmu_unmap_sgt(etdev, &map->sgt, context_id, map->dir, map->dma_attrs, 0);
+}
+
+int edgetpu_mmu_map_sgt(struct edgetpu_dev *etdev, struct sg_table *sgt,
+ enum edgetpu_context_id context_id, enum dma_data_direction dir,
+ unsigned long dma_attrs, u32 mmu_flags)
+
+{
+ struct gcip_iommu_domain *gdomain;
+ u64 gcip_map_flags =
+ GCIP_MAP_FLAGS_DMA_DIRECTION_TO_FLAGS(dir) |
+ GCIP_MAP_FLAGS_DMA_COHERENT_TO_FLAGS((mmu_flags & EDGETPU_MMU_COHERENT) != 0) |
+ GCIP_MAP_FLAGS_DMA_ATTR_TO_FLAGS(dma_attrs);
int ret;
- unsigned long iova;
- struct edgetpu_iommu_map_params params;
- struct iommu_domain *default_domain =
- iommu_get_domain_for_dev(etdev->dev);
- ret = get_iommu_map_params(etdev, map, context_id, &params, mmu_flags);
- if (ret)
- return ret;
+ gdomain = get_domain_by_context_id(etdev, context_id);
+ if (!gdomain) {
+ etdev_err(etdev, "Unable to find an iommu_domain for context_id %#x\n", context_id);
+ return 0;
+ }
- ret = dma_map_sg_attrs(etdev->dev, map->sgt.sgl, map->sgt.nents, map->dir, map->dma_attrs);
+ ret = gcip_iommu_domain_map_sg(gdomain, sgt->sgl, sgt->nents, gcip_map_flags);
if (!ret)
- return -EINVAL;
- map->sgt.nents = ret;
- iova = sg_dma_address(map->sgt.sgl);
+ return 0;
- /*
- * All mappings get added to the default domain by the call to
- * dma_map_sg above.
- * Per-context mappings are mirrored to their specific domains here
- */
- if (params.domain != default_domain) {
- ssize_t mapped = (ssize_t)iommu_map_sg(params.domain, iova, map->sgt.sgl,
- map->sgt.orig_nents, params.prot);
-
- /* iommu_map_sg returns 0 on failure before 5.15, returns -errno afterwards */
- if (mapped <= 0) {
- /* Undo the mapping in the default domain */
- dma_unmap_sg_attrs(etdev->dev, map->sgt.sgl, map->sgt.orig_nents, map->dir,
- DMA_ATTR_SKIP_CPU_SYNC);
- return mapped == 0 ? -ENOMEM : (int)mapped;
- }
- }
+ /* TODO(b/281157263): Remove once gcip-iommu checks DMA_ATTR_SKIP_CPU_SYNC */
+ if (!(dma_attrs & DMA_ATTR_SKIP_CPU_SYNC))
+ dma_sync_sg_for_device(etdev->dev, sgt->sgl, sgt->orig_nents, dir);
- map->device_address = iova;
- return 0;
+ etdev_dbg(etdev, "%s: ctx=%x iova=%#llx size=%#x flags=%#llx\n",
+ __func__, context_id, (u64)sg_dma_address(sgt->sgl), sg_dma_len(sgt->sgl),
+ gcip_map_flags);
+ return ret;
}
-void edgetpu_mmu_unmap(struct edgetpu_dev *etdev, struct edgetpu_mapping *map,
- enum edgetpu_context_id context_id)
+void edgetpu_mmu_unmap_sgt(struct edgetpu_dev *etdev, struct sg_table *sgt,
+ enum edgetpu_context_id context_id, enum dma_data_direction dir,
+ unsigned long dma_attrs, u32 mmu_flags)
{
- int ret;
- struct edgetpu_iommu_map_params params;
- struct iommu_domain *default_domain =
- iommu_get_domain_for_dev(etdev->dev);
-
- ret = get_iommu_map_params(etdev, map, context_id, &params, 0);
- if (!ret && params.domain != default_domain) {
- /*
- * If this is a per-context mapping, it was mirrored in the
- * per-context domain. Undo that mapping first.
- */
- iommu_unmap(params.domain, map->device_address, params.size);
+ struct gcip_iommu_domain *gdomain;
+ u64 gcip_map_flags =
+ GCIP_MAP_FLAGS_DMA_DIRECTION_TO_FLAGS(dir) |
+ GCIP_MAP_FLAGS_DMA_COHERENT_TO_FLAGS((mmu_flags & EDGETPU_MMU_COHERENT) != 0) |
+ GCIP_MAP_FLAGS_DMA_ATTR_TO_FLAGS(dma_attrs);
+
+ gdomain = get_domain_by_context_id(etdev, context_id);
+ if (!gdomain) {
+ etdev_err(etdev, "Unable to find an iommu_domain\n");
+ return;
}
- /* Undo the mapping in the default domain */
- dma_unmap_sg_attrs(etdev->dev, map->sgt.sgl, map->sgt.orig_nents, map->dir, map->dma_attrs);
+ /* TODO(b/281157263): Remove once gcip-iommu checks DMA_ATTR_SKIP_CPU_SYNC */
+ if (!(dma_attrs & DMA_ATTR_SKIP_CPU_SYNC))
+ dma_sync_sg_for_cpu(etdev->dev, sgt->sgl, sgt->orig_nents, dir);
+
+ gcip_iommu_domain_unmap_sg(gdomain, sgt->sgl, sgt->orig_nents, gcip_map_flags);
+ etdev_dbg(etdev, "%s: ctx=%x iova=%#llx size=%#x\n",
+ __func__, context_id, (u64)sg_dma_address(sgt->sgl), sg_dma_len(sgt->sgl));
}
int edgetpu_mmu_map_iova_sgt(struct edgetpu_dev *etdev, tpu_addr_t iova,
@@ -408,6 +410,8 @@ int edgetpu_mmu_map_iova_sgt(struct edgetpu_dev *etdev, tpu_addr_t iova,
goto error;
iova += sg->length;
}
+ etdev_dbg(etdev, "%s: ctx=%x iova=%#llx dma=%#llx size=%#llx dir=%d\n",
+ __func__, context_id, iova, (u64)sg_dma_address(sgt->sgl), orig_iova - iova, dir);
return 0;
error:
@@ -428,167 +432,34 @@ void edgetpu_mmu_unmap_iova_sgt_attrs(struct edgetpu_dev *etdev,
for_each_sg(sgt->sgl, sg, sgt->orig_nents, i)
size += sg->length;
+ etdev_dbg(etdev, "%s: ctx=%x iova=%#llx size=%#zx\n", __func__, context_id, iova, size);
edgetpu_mmu_remove_translation(etdev, iova, size, context_id);
}
-tpu_addr_t edgetpu_mmu_alloc(struct edgetpu_dev *etdev, size_t size,
- u32 mmu_flags)
-{
- return 0;
-}
-
-void edgetpu_mmu_reserve(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr,
- size_t size)
-{
-}
-
-void edgetpu_mmu_free(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr,
- size_t size)
-{
-}
-
int edgetpu_mmu_add_translation(struct edgetpu_dev *etdev, unsigned long iova,
phys_addr_t paddr, size_t size, int prot,
enum edgetpu_context_id context_id)
{
- struct iommu_domain *domain;
+ struct gcip_iommu_domain *gdomain;
- domain = get_domain_by_context_id(etdev, context_id);
- if (!domain)
+ etdev_dbg(etdev, "%s: ctx=%x iova=%#lx paddr=%pap size=%#zx prot=%#x\n",
+ __func__, context_id, iova, &paddr, size, prot);
+ gdomain = get_domain_by_context_id(etdev, context_id);
+ if (!gdomain)
return -ENODEV;
- return iommu_map(domain, iova, paddr, size, prot);
+ return iommu_map(gdomain->domain, iova, paddr, size, prot);
}
void edgetpu_mmu_remove_translation(struct edgetpu_dev *etdev,
unsigned long iova, size_t size,
enum edgetpu_context_id context_id)
{
- struct iommu_domain *domain;
+ struct gcip_iommu_domain *gdomain;
- domain = get_domain_by_context_id(etdev, context_id);
- if (domain)
- iommu_unmap(domain, iova, size);
-}
-
-/*
- * This function assumes [@down_addr, @down_addr + size) is mapped to
- * [phys_addr, phys_addr + size). This is true if @down_addr was mapped by
- * dma_alloc_* series, and may not be true when mapped by dma_map_sg*.
- */
-tpu_addr_t edgetpu_mmu_tpu_map(struct edgetpu_dev *etdev, dma_addr_t down_addr,
- size_t size, enum dma_data_direction dir,
- enum edgetpu_context_id context_id,
- u32 mmu_flags)
-{
- struct iommu_domain *domain;
- struct iommu_domain *default_domain =
- iommu_get_domain_for_dev(etdev->dev);
- phys_addr_t paddr;
- int prot = mmu_flag_to_iommu_prot(mmu_flags, etdev->dev, dir);
-
- domain = get_domain_by_context_id(etdev, context_id);
- /*
- * Either we don't have per-context domains or this mapping
- * belongs to the default context, in which case we don't need
- * to do anything
- */
- if (!domain || domain == default_domain)
- return down_addr;
- paddr = iommu_iova_to_phys(default_domain, down_addr);
- if (!paddr)
- return 0;
- /* Map the address to the context-specific domain */
- if (iommu_map(domain, down_addr, paddr, size, prot))
- return 0;
-
- /* Return downstream IOMMU DMA address as TPU address. */
- return down_addr;
-}
-
-void edgetpu_mmu_tpu_unmap(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr,
- size_t size, enum edgetpu_context_id context_id)
-{
- struct iommu_domain *domain;
- struct iommu_domain *default_domain =
- iommu_get_domain_for_dev(etdev->dev);
-
- domain = get_domain_by_context_id(etdev, context_id);
- /*
- * Either we don't have per-context domains or this mapping
- * belongs to the default context, in which case we don't need
- * to do anything
- */
- if (!domain || domain == default_domain)
- return;
- /* Unmap the address from the context-specific domain */
- iommu_unmap(domain, tpu_addr, size);
-}
-
-tpu_addr_t edgetpu_mmu_tpu_map_sgt(struct edgetpu_dev *etdev,
- struct sg_table *sgt, enum dma_data_direction dir,
- enum edgetpu_context_id context_id,
- u32 mmu_flags)
-{
- struct iommu_domain *domain;
- struct iommu_domain *default_domain =
- iommu_get_domain_for_dev(etdev->dev);
- phys_addr_t paddr;
- dma_addr_t iova, cur_iova;
- size_t size;
- int prot = mmu_flag_to_iommu_prot(mmu_flags, etdev->dev, dir);
- struct scatterlist *sg;
- int ret;
- int i;
-
- /*
- * We cannot map the SG to a single TPU VA if the table contains more
- * than one DMA address.
- */
- if (sgt->nents != 1)
- return 0;
- iova = sg_dma_address(sgt->sgl);
- domain = get_domain_by_context_id(etdev, context_id);
- /*
- * Either we don't have per-context domains or this mapping
- * belongs to the default context, in which case we don't need
- * to do anything.
- */
- if (!domain || domain == default_domain)
- return iova;
- cur_iova = iova;
- for_each_sg(sgt->sgl, sg, sgt->orig_nents, i) {
- /* ignore sg->offset */
- paddr = page_to_phys(sg_page(sg));
- size = sg->length + sg->offset;
- ret = iommu_map(domain, cur_iova, paddr, size, prot);
- if (ret)
- goto rollback;
- cur_iova += size;
- }
-
- return iova;
-rollback:
- iommu_unmap(domain, iova, cur_iova - iova);
- etdev_err(etdev, "TPU map sgt failed: %d", ret);
- return 0;
-}
-
-void edgetpu_mmu_tpu_unmap_sgt(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr,
- struct sg_table *sgt,
- enum edgetpu_context_id context_id)
-{
- struct iommu_domain *domain;
- struct iommu_domain *default_domain =
- iommu_get_domain_for_dev(etdev->dev);
-
- domain = get_domain_by_context_id(etdev, context_id);
- if (!domain || domain == default_domain)
- return;
- /*
- * We have checked sgt->nents == 1 on map, sg_dma_len(sgt->sgl) should
- * equal the total size.
- */
- iommu_unmap(domain, tpu_addr, sg_dma_len(sgt->sgl));
+ etdev_dbg(etdev, "%s: ctx=%x iova=%#lx size=%#zx\n", __func__, context_id, iova, size);
+ gdomain = get_domain_by_context_id(etdev, context_id);
+ if (gdomain)
+ iommu_unmap(gdomain->domain, iova, size);
}
/* to be returned when domain aux is not supported */
@@ -601,35 +472,35 @@ struct edgetpu_iommu_domain *edgetpu_mmu_alloc_domain(struct edgetpu_dev *etdev)
{
struct edgetpu_iommu_domain *etdomain;
struct edgetpu_iommu *etiommu = etdev->mmu_cookie;
- struct iommu_domain *domain;
+ struct gcip_iommu_domain *gdomain;
int token;
if (!etiommu->aux_enabled)
return &invalid_etdomain;
- domain = gcip_domain_pool_alloc(&etiommu->domain_pool);
- if (!domain) {
+ gdomain = gcip_iommu_domain_pool_alloc_domain(&etiommu->domain_pool);
+ if (!gdomain) {
etdev_warn(etdev, "iommu domain allocation failed");
return NULL;
}
etdomain = kzalloc(sizeof(*etdomain), GFP_KERNEL);
if (!etdomain) {
- gcip_domain_pool_free(&etiommu->domain_pool, domain);
+ gcip_iommu_domain_pool_free_domain(&etiommu->domain_pool, gdomain);
return NULL;
}
mutex_lock(&etiommu->pool_lock);
- token = idr_alloc(&etiommu->domain_id_pool, domain, 0,
- EDGETPU_DOMAIN_TOKEN_END, GFP_KERNEL);
+ token = idr_alloc(&etiommu->domain_id_pool, gdomain, 0, EDGETPU_DOMAIN_TOKEN_END,
+ GFP_KERNEL);
mutex_unlock(&etiommu->pool_lock);
if (token < 0) {
etdev_warn(etdev, "alloc iommu domain token failed: %d", token);
kfree(etdomain);
- gcip_domain_pool_free(&etiommu->domain_pool, domain);
+ gcip_iommu_domain_pool_free_domain(&etiommu->domain_pool, gdomain);
return NULL;
}
- edgetpu_init_etdomain(etdomain, domain, token);
+ edgetpu_init_etdomain(etdomain, gdomain, token);
return etdomain;
}
@@ -647,7 +518,7 @@ void edgetpu_mmu_free_domain(struct edgetpu_dev *etdev,
mutex_lock(&etiommu->pool_lock);
idr_remove(&etiommu->domain_id_pool, etdomain->token);
mutex_unlock(&etiommu->pool_lock);
- gcip_domain_pool_free(&etiommu->domain_pool, etdomain->iommu_domain);
+ gcip_iommu_domain_pool_free_domain(&etiommu->domain_pool, etdomain->gdomain);
kfree(etdomain);
}
@@ -655,7 +526,7 @@ int edgetpu_mmu_attach_domain(struct edgetpu_dev *etdev,
struct edgetpu_iommu_domain *etdomain)
{
struct edgetpu_iommu *etiommu = etdev->mmu_cookie;
- struct iommu_domain *domain;
+ struct gcip_iommu_domain *gdomain;
int ret;
uint pasid;
@@ -664,13 +535,13 @@ int edgetpu_mmu_attach_domain(struct edgetpu_dev *etdev,
return 0;
if (etdomain->pasid != IOMMU_PASID_INVALID)
return -EINVAL;
- domain = etdomain->iommu_domain;
- ret = iommu_aux_attach_device(domain, etdev->dev);
+ gdomain = etdomain->gdomain;
+ ret = iommu_aux_attach_device(gdomain->domain, etdev->dev);
if (ret) {
etdev_warn(etdev, "Attach IOMMU aux failed: %d", ret);
return ret;
}
- pasid = iommu_aux_get_pasid(domain, etdev->dev);
+ pasid = iommu_aux_get_pasid(gdomain->domain, etdev->dev);
if (pasid <= 0 || pasid >= EDGETPU_NCONTEXTS) {
etdev_warn(etdev, "Invalid PASID %d returned from iommu",
pasid);
@@ -678,15 +549,15 @@ int edgetpu_mmu_attach_domain(struct edgetpu_dev *etdev,
goto err_detach;
}
/* the IOMMU driver returned a duplicate PASID */
- if (etiommu->domains[pasid]) {
+ if (etiommu->gdomains[pasid]) {
ret = -EBUSY;
goto err_detach;
}
- etiommu->domains[pasid] = domain;
+ etiommu->gdomains[pasid] = gdomain;
etdomain->pasid = pasid;
return 0;
err_detach:
- iommu_aux_detach_device(domain, etdev->dev);
+ iommu_aux_detach_device(gdomain->domain, etdev->dev);
return ret;
}
@@ -700,7 +571,7 @@ void edgetpu_mmu_detach_domain(struct edgetpu_dev *etdev,
return;
if (pasid <= 0 || pasid >= EDGETPU_NCONTEXTS)
return;
- etiommu->domains[pasid] = NULL;
+ etiommu->gdomains[pasid] = NULL;
etdomain->pasid = IOMMU_PASID_INVALID;
- iommu_aux_detach_device(etdomain->iommu_domain, etdev->dev);
+ iommu_aux_detach_device(etdomain->gdomain->domain, etdev->dev);
}
diff --git a/drivers/edgetpu/edgetpu-internal.h b/drivers/edgetpu/edgetpu-internal.h
index 17dc48c..e4f17bd 100644
--- a/drivers/edgetpu/edgetpu-internal.h
+++ b/drivers/edgetpu/edgetpu-internal.h
@@ -73,14 +73,19 @@ typedef u64 tpu_addr_t;
struct edgetpu_coherent_mem {
void *vaddr; /* kernel VA, no allocation if NULL */
- dma_addr_t dma_addr; /* DMA handle for downstream IOMMU, if any */
- tpu_addr_t tpu_addr; /* DMA handle for TPU internal IOMMU, if any */
+ dma_addr_t dma_addr; /* IOVA for default domain, returned by dma_alloc_coherent */
+ tpu_addr_t tpu_addr; /*
+ * IOVA for the domain of the context the memory was requested for.
+ * Equal to dma_addr if requested for EDGETPU_CONTEXT_KCI.
+ */
u64 host_addr; /* address mapped on host for debugging */
u64 phys_addr; /* physical address, if available */
size_t size;
#ifdef CONFIG_X86
bool is_set_uc; /* memory has been marked uncached on X86 */
#endif
+ /* SGT used to map the coherent memory into the destination context. */
+ struct sg_table *client_sgt;
};
struct edgetpu_device_group;
@@ -233,6 +238,9 @@ struct edgetpu_dev {
/* debug dump handlers */
edgetpu_debug_dump_handlers *debug_dump_handlers;
struct work_struct debug_dump_work;
+
+ /* PMU status base address for block status, maybe NULL */
+ void __iomem *pmu_status;
};
struct edgetpu_dev_iface {
diff --git a/drivers/edgetpu/edgetpu-iremap-pool.h b/drivers/edgetpu/edgetpu-iremap-pool.h
index 4024b86..55e6277 100644
--- a/drivers/edgetpu/edgetpu-iremap-pool.h
+++ b/drivers/edgetpu/edgetpu-iremap-pool.h
@@ -27,7 +27,7 @@ void edgetpu_iremap_pool_destroy(struct edgetpu_dev *etdev);
/*
* Attempt to allocate memory in the instruction remap pool if the device
* has one.
- * Fall back to dma_alloc_coherent and edgetpu_mmu_tpu_map otherwise.
+ * Fall back to dma_alloc_coherent and edgetpu_mmu_map_sgt otherwise.
*/
int edgetpu_iremap_alloc(struct edgetpu_dev *etdev, size_t size,
struct edgetpu_coherent_mem *mem,
diff --git a/drivers/edgetpu/edgetpu-kci.c b/drivers/edgetpu/edgetpu-kci.c
index 7a90346..27d0a3f 100644
--- a/drivers/edgetpu/edgetpu-kci.c
+++ b/drivers/edgetpu/edgetpu-kci.c
@@ -10,6 +10,7 @@
#include <linux/circ_buf.h>
#include <linux/device.h>
#include <linux/errno.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -187,6 +188,13 @@ static inline void edgetpu_kci_trigger_doorbell(struct gcip_kci *kci,
EDGETPU_MAILBOX_CMD_QUEUE_WRITE(mailbox, doorbell_set, 1);
}
+static inline bool edgetpu_kci_is_block_off(struct gcip_kci *kci)
+{
+ struct edgetpu_mailbox *mailbox = gcip_kci_get_data(kci);
+
+ return mailbox->etdev->pmu_status ? !readl(mailbox->etdev->pmu_status) : false;
+}
+
static const struct gcip_kci_ops kci_ops = {
.get_cmd_queue_head = edgetpu_kci_get_cmd_queue_head,
.get_cmd_queue_tail = edgetpu_kci_get_cmd_queue_tail,
@@ -198,6 +206,7 @@ static const struct gcip_kci_ops kci_ops = {
.trigger_doorbell = edgetpu_kci_trigger_doorbell,
.reverse_kci_handle_response = edgetpu_reverse_kci_handle_response,
.update_usage = edgetpu_kci_update_usage_wrapper,
+ .is_block_off = edgetpu_kci_is_block_off,
};
int edgetpu_kci_init(struct edgetpu_mailbox_manager *mgr, struct edgetpu_kci *etkci)
@@ -537,9 +546,6 @@ void edgetpu_kci_mappings_show(struct edgetpu_dev *etdev, struct seq_file *s)
struct edgetpu_coherent_mem *cmd_queue_mem = &etkci->cmd_queue_mem;
struct edgetpu_coherent_mem *resp_queue_mem = &etkci->resp_queue_mem;
- if (!etkci || !etkci->mailbox)
- return;
-
seq_printf(s, "kci context mbox %u:\n", EDGETPU_CONTEXT_KCI);
seq_printf(s, " %#llx %lu cmdq - %pad\n", cmd_queue_mem->tpu_addr,
DIV_ROUND_UP(QUEUE_SIZE * gcip_kci_queue_element_size(GCIP_MAILBOX_CMD_QUEUE),
@@ -559,9 +565,6 @@ int edgetpu_kci_shutdown(struct edgetpu_kci *etkci)
.code = GCIP_KCI_CODE_SHUTDOWN,
};
- if (!etkci || !etkci->kci)
- return -ENODEV;
-
return gcip_kci_send_cmd(etkci->kci, &cmd);
}
@@ -577,9 +580,6 @@ int edgetpu_kci_get_debug_dump(struct edgetpu_kci *etkci, tpu_addr_t tpu_addr, s
},
};
- if (!etkci || !etkci->kci)
- return -ENODEV;
-
return gcip_kci_send_cmd(etkci->kci, &cmd);
}
@@ -598,9 +598,6 @@ int edgetpu_kci_open_device(struct edgetpu_kci *etkci, u32 mailbox_map, u32 clie
},
};
- if (!etkci || !etkci->kci)
- return -ENODEV;
-
RETURN_ERRNO_IF_ETDEV_NOT_GOOD(etkci, "open device");
if (vcid < 0)
return gcip_kci_send_cmd(etkci->kci, &cmd);
@@ -617,9 +614,6 @@ int edgetpu_kci_close_device(struct edgetpu_kci *etkci, u32 mailbox_map)
},
};
- if (!etkci || !etkci->kci)
- return -ENODEV;
-
RETURN_ERRNO_IF_ETDEV_NOT_GOOD(etkci, "close device");
return gcip_kci_send_cmd(etkci->kci, &cmd);
@@ -634,9 +628,6 @@ int edgetpu_kci_notify_throttling(struct edgetpu_dev *etdev, u32 level)
},
};
- if (!etdev->etkci)
- return -ENODEV;
-
return gcip_kci_send_cmd(etdev->etkci->kci, &cmd);
}
@@ -649,9 +640,6 @@ int edgetpu_kci_block_bus_speed_control(struct edgetpu_dev *etdev, bool block)
},
};
- if (!etdev->etkci)
- return -ENODEV;
-
return gcip_kci_send_cmd(etdev->etkci->kci, &cmd);
}
@@ -667,9 +655,6 @@ int edgetpu_kci_firmware_tracing_level(void *data, unsigned long level, unsigned
struct gcip_kci_response_element resp;
int ret;
- if (!etdev->etkci)
- return -ENODEV;
-
ret = gcip_kci_send_cmd_return_resp(etdev->etkci->kci, &cmd, &resp);
if (ret == GCIP_KCI_ERROR_OK)
*active_level = resp.retval;
@@ -696,9 +681,6 @@ int edgetpu_kci_set_device_properties(struct edgetpu_kci *etkci, struct edgetpu_
};
int ret = 0;
- if (!etkci || !etkci->kci)
- return -ENODEV;
-
mutex_lock(&dev_prop->lock);
if (!dev_prop->initialized)
goto out;
@@ -718,8 +700,5 @@ int edgetpu_kci_resp_rkci_ack(struct edgetpu_dev *etdev, struct gcip_kci_respons
.code = GCIP_KCI_CODE_RKCI_ACK,
};
- if (!etdev->etkci)
- return -ENODEV;
-
return gcip_kci_send_cmd(etdev->etkci->kci, &cmd);
}
diff --git a/drivers/edgetpu/edgetpu-mmu.h b/drivers/edgetpu/edgetpu-mmu.h
index bff24c6..912aa03 100644
--- a/drivers/edgetpu/edgetpu-mmu.h
+++ b/drivers/edgetpu/edgetpu-mmu.h
@@ -13,6 +13,8 @@
#include <linux/scatterlist.h>
#include <linux/version.h>
+#include <gcip/gcip-iommu.h>
+
#include "edgetpu-internal.h"
#include "edgetpu.h"
@@ -39,7 +41,7 @@ struct edgetpu_iommu_domain {
* edgetpu_mmu_detach_domain().
*/
uint pasid;
- struct iommu_domain *iommu_domain;
+ struct gcip_iommu_domain *gdomain;
/*
* A token set by edgetpu_mmu_alloc_domain(). See the description of
* edgetpu_mmu_add_translation() about @context_id for more details.
@@ -114,6 +116,13 @@ int edgetpu_mmu_map(struct edgetpu_dev *dev, struct edgetpu_mapping *map,
void edgetpu_mmu_unmap(struct edgetpu_dev *dev, struct edgetpu_mapping *map,
enum edgetpu_context_id context_id);
+int edgetpu_mmu_map_sgt(struct edgetpu_dev *etdev, struct sg_table *sgt,
+ enum edgetpu_context_id context_id, enum dma_data_direction dir,
+ unsigned long dma_attrs, u32 mmu_flags);
+void edgetpu_mmu_unmap_sgt(struct edgetpu_dev *etdev, struct sg_table *sgt,
+ enum edgetpu_context_id context_id, enum dma_data_direction dir,
+ unsigned long dma_attrs, u32 mmu_flags);
+
/**
* Maps TPU IOVA @iova to @sgt.
* @sgt: the sg table presents the list of pages.
@@ -121,9 +130,6 @@ void edgetpu_mmu_unmap(struct edgetpu_dev *dev, struct edgetpu_mapping *map,
* Description: Request TPU to map @iova to the pages presented by @sgt.
*
* Returns 0 on success, -errno on error.
- *
- * Note: Caller should use edgetpu_mmu_reserve() before calling this method if
- * the target @iova isn't acquired from edgetpu_mmu_alloc(@etdev).
*/
int edgetpu_mmu_map_iova_sgt(struct edgetpu_dev *etdev, tpu_addr_t iova,
struct sg_table *sgt, enum dma_data_direction dir,
@@ -137,36 +143,6 @@ void edgetpu_mmu_unmap_iova_sgt_attrs(struct edgetpu_dev *etdev,
edgetpu_mmu_unmap_iova_sgt_attrs(e, i, s, d, c, 0)
/**
- * Allocates an IOVA in the internal MMU.
- * @size: size needed to be allocated in bytes.
- *
- * Description: Allocates a TPU address to be mapped via
- * edgetpu_mmu_add_translation().
- *
- * If the chip doesn't have an internal MMU then return zero.
- *
- * Returns zero on error.
- */
-tpu_addr_t edgetpu_mmu_alloc(struct edgetpu_dev *etdev, size_t size,
- u32 mmu_flags);
-/**
- * Marks the IOVA region [@tpu_addr, @tpu_addr + @size) as reserved.
- *
- * Description: Use this function to mark the region as reserved and prevents
- * it from being allocated by edgetpu_mmu_alloc().
- *
- * Use edgetpu_mmu_free() to release the reserved area.
- */
-void edgetpu_mmu_reserve(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr,
- size_t size);
-/*
- * Free the IOVA allocated by edgetpu_mmu_alloc() or reserved by
- * edgetpu_mmu_reserve().
- */
-void edgetpu_mmu_free(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr,
- size_t size);
-
-/**
* Add an IOVA translation to the chip MMU/IOMMU.
* @iova: I/O virtual address (TPU VA) to map to paddr.
* @paddr: Physical/next-stage target address to which iova is to be mapped.
@@ -178,10 +154,6 @@ void edgetpu_mmu_free(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr,
* paddr can be considered a physical address from the TPU's viewpoint, but
* may actually be another IOVA for another IOMMU downstream of the chip MMU.
*
- * Note: for chipsets with edgetpu_mmu_alloc() support, @iova passed to this
- * function must be either allocated from edgetpu_mmu_alloc() or reserved by
- * edgetpu_mmu_reserve().
- *
* For chipsets with IOMMU AUX domain support, @context_id can be used to
* specify a detached IOMMU domain by value
* (EDGETPU_CONTEXT_DOMAIN_TOKEN | @token), where @token is the one returned by
@@ -197,67 +169,6 @@ void edgetpu_mmu_remove_translation(struct edgetpu_dev *etdev,
unsigned long iova, size_t size,
enum edgetpu_context_id context_id);
-/**
- * Add a TPU mapping for a local DMA mapping
- * @down_addr: DMA (or physical) addr of memory downstream from TPU
- * @size: size of memory area in bytes
- * @dir: DMA direction of mapping
- * @context_id: context ID for the mapping
- * @mmu_flags: the flag or'ed with EDGETPU_MMU_* macros
- *
- * Description: For chips with internal MMUs, add the required internal MMU
- * mapping for the TPU to access @down_addr, the DMA or physical address of the
- * buffer as returned by the Linux DMA API when the DMA mapping was created.
- * This can be used with, for example, buffers allocated using
- * dma_alloc_coherent(), which are mapped appropriately for any downstream IOMMU
- * and must be mapped to the TPU internal MMU as well.
- *
- * For a chip that doesn't have an internal MMU but has the IOMMU domain AUX
- * feature, perform the necessary mapping to @context_id and return the
- * downstream DMA address.
- *
- * Returns zero on error.
- */
-tpu_addr_t edgetpu_mmu_tpu_map(struct edgetpu_dev *etdev, dma_addr_t down_addr,
- size_t size, enum dma_data_direction dir,
- enum edgetpu_context_id context_id,
- u32 mmu_flags);
-
-/* Unmap a TPU mapping created by edgetpu_mmu_tpu_map */
-void edgetpu_mmu_tpu_unmap(struct edgetpu_dev *etdev,
- tpu_addr_t tpu_addr, size_t size,
- enum edgetpu_context_id context_id);
-
-/**
- * Add a TPU mapping towards an SG table.
- * @sgt: An SG table that is already mapped to @etdev->dev, i.e. dma_map_sg*
- * has been called.
- * @dir: DMA direction of mapping
- * @context_id: context ID for the mapping
- * @mmu_flags: the flag or'ed with EDGETPU_MMU_* macros
- *
- * Description: For chips with internal MMUs, add the required internal MMU
- * mapping for the TPU to access the DMA addresses of @sgt.
- *
- * For a chip that doesn't have an internal MMU but has the IOMMU domain AUX
- * feature, perform the necessary mapping to @context_id and return the
- * downstream DMA address.
- *
- * Caller ensures the SG table has DMA addresses as compact as possible, that is
- * if @sgt->nents is greater than 1 then the DMA addresses are not continuous.
- *
- * Returns zero on error.
- */
-tpu_addr_t edgetpu_mmu_tpu_map_sgt(struct edgetpu_dev *etdev,
- struct sg_table *sgt,
- enum dma_data_direction dir,
- enum edgetpu_context_id context_id,
- u32 mmu_flags);
-/* Unmap a TPU mapping created by edgetpu_mmu_tpu_map_sgt */
-void edgetpu_mmu_tpu_unmap_sgt(struct edgetpu_dev *etdev, tpu_addr_t tpu_addr,
- struct sg_table *sgt,
- enum edgetpu_context_id context_id);
-
/*
* Allocates a IOMMU domain.
*
@@ -292,4 +203,17 @@ int edgetpu_mmu_attach_domain(struct edgetpu_dev *etdev,
void edgetpu_mmu_detach_domain(struct edgetpu_dev *etdev,
struct edgetpu_iommu_domain *etdomain);
+/* TODO(b/281459896) Make domain comparisons internal to edgetpu-mmu.h */
+/*
+ * Returns whether mappings for a given context exist in the default domain.
+ *
+ * If a context represented by @ctx_id has been assigned the default IOMMU domain, either uniquely,
+ * or because AUX domains are not supported, this function returns true.
+ *
+ * This can be used to determine if a buffer which is already mapped for the default domain (such as
+ * coherent buffers or dma-bufs) needs to be remapped for specifically for the context.
+ */
+bool edgetpu_mmu_is_context_using_default_domain(struct edgetpu_dev *etdev,
+ enum edgetpu_context_id ctx_id);
+
#endif /* __EDGETPU_MMU_H__ */
diff --git a/drivers/edgetpu/edgetpu-mobile-platform.c b/drivers/edgetpu/edgetpu-mobile-platform.c
index db66dab..b2a10f9 100644
--- a/drivers/edgetpu/edgetpu-mobile-platform.c
+++ b/drivers/edgetpu/edgetpu-mobile-platform.c
@@ -16,10 +16,6 @@
#include <gcip/gcip-pm.h>
#include <gcip/gcip-iommu.h>
-#if HAS_IOVAD_BEST_FIT_ALGO
-#include <linux/dma-iommu.h>
-#endif
-
#include "edgetpu-config.h"
#include "edgetpu-dmabuf.h"
#include "edgetpu-internal.h"
@@ -229,16 +225,15 @@ void edgetpu_chip_remove_mmu(struct edgetpu_dev *etdev)
edgetpu_mmu_detach(etdev);
}
-static void edgetpu_platform_parse_pmu(struct edgetpu_mobile_platform_dev *etmdev)
+static void edgetpu_platform_parse_pmu(struct edgetpu_dev *etdev)
{
- struct edgetpu_dev *etdev = &etmdev->edgetpu_dev;
struct device *dev = etdev->dev;
u32 reg;
if (of_find_property(dev->of_node, "pmu-status-base", NULL) &&
!of_property_read_u32_index(dev->of_node, "pmu-status-base", 0, &reg)) {
- etmdev->pmu_status = devm_ioremap(dev, reg, 0x4);
- if (!etmdev->pmu_status)
+ etdev->pmu_status = devm_ioremap(dev, reg, 0x4);
+ if (!etdev->pmu_status)
etdev_err(etdev, "Using ACPM for blk status query\n");
} else {
etdev_warn(etdev, "Failed to find PMU register base\n");
@@ -354,10 +349,6 @@ static int edgetpu_mobile_platform_probe(struct platform_device *pdev,
goto out_cleanup_fw;
}
-#if HAS_IOVAD_BEST_FIT_ALGO
- iommu_dma_enable_best_fit_algo(dev);
-#endif
-
INIT_LIST_HEAD(&etmdev->fw_ctx_list);
mutex_init(&etmdev->fw_ctx_list_lock);
@@ -365,7 +356,7 @@ static int edgetpu_mobile_platform_probe(struct platform_device *pdev,
* Parses PMU before edgetpu_device_add so edgetpu_chip_pm_create can know whether to set
* the is_block_down op.
*/
- edgetpu_platform_parse_pmu(etmdev);
+ edgetpu_platform_parse_pmu(etdev);
ret = edgetpu_device_add(etdev, &regs, iface_params, ARRAY_SIZE(iface_params));
if (ret) {
diff --git a/drivers/edgetpu/edgetpu-mobile-platform.h b/drivers/edgetpu/edgetpu-mobile-platform.h
index e89e0f0..147723c 100644
--- a/drivers/edgetpu/edgetpu-mobile-platform.h
+++ b/drivers/edgetpu/edgetpu-mobile-platform.h
@@ -102,8 +102,6 @@ struct edgetpu_mobile_platform_dev {
int n_irq;
/* Array of IRQ numbers */
int *irq;
- /* PMU status base address for block status, maybe NULL */
- void __iomem *pmu_status;
/* callbacks for chip-dependent implementations */
diff --git a/drivers/edgetpu/edgetpu-usage-stats.c b/drivers/edgetpu/edgetpu-usage-stats.c
index 16e6892..506a5fd 100644
--- a/drivers/edgetpu/edgetpu-usage-stats.c
+++ b/drivers/edgetpu/edgetpu-usage-stats.c
@@ -236,10 +236,8 @@ void edgetpu_usage_stats_init(struct edgetpu_dev *etdev)
int ret;
ustats = devm_kzalloc(etdev->dev, sizeof(*etdev->usage_stats), GFP_KERNEL);
- if (!ustats) {
- etdev_warn(etdev, "failed to allocate memory for usage stats\n");
+ if (!ustats)
return;
- }
args.version = EDGETPU_USAGE_METRIC_VERSION;
args.dev = etdev->dev;
diff --git a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-iommu.c b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-iommu.c
index 75509cd..50170c6 100644
--- a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-iommu.c
+++ b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-iommu.c
@@ -85,7 +85,11 @@ static int iovad_initialize_domain(struct gcip_iommu_domain *domain)
init_iova_domain(&domain->iova_space.iovad, dpool->granule,
max_t(unsigned long, 1, dpool->base_daddr >> ilog2(dpool->granule)));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
+ return iova_domain_init_rcaches(&domain->iova_space.iovad);
+#else
return 0;
+#endif
}
static void iovad_finalize_domain(struct gcip_iommu_domain *domain)
@@ -204,12 +208,14 @@ static ssize_t dma_iommu_map_sg(struct gcip_iommu_domain *domain, struct scatter
if (!nents_mapped)
return 0;
- iova = sg_dma_address(sgl);
+ if (!domain->default_domain) {
+ iova = sg_dma_address(sgl);
- ret = (ssize_t)iommu_map_sg(domain->domain, iova, sgl, nents, prot);
- if (ret <= 0) {
- dma_unmap_sg_attrs(domain->dev, sgl, nents, dir, attrs);
- return 0;
+ ret = (ssize_t)iommu_map_sg(domain->domain, iova, sgl, nents, prot);
+ if (ret <= 0) {
+ dma_unmap_sg_attrs(domain->dev, sgl, nents, dir, attrs);
+ return 0;
+ }
}
return nents_mapped;
@@ -222,11 +228,13 @@ static void dma_iommu_unmap_sg(struct gcip_iommu_domain *domain, struct scatterl
size_t size = 0;
int i;
- for_each_sg (sgl, sg, nents, i)
- size += sg_dma_len(sg);
+ if (!domain->default_domain) {
+ for_each_sg (sgl, sg, nents, i)
+ size += sg_dma_len(sg);
- if (!iommu_unmap(domain->domain, sg_dma_address(sgl), size))
- dev_warn(domain->dev, "Failed to unmap sg");
+ if (!iommu_unmap(domain->domain, sg_dma_address(sgl), size))
+ dev_warn(domain->dev, "Failed to unmap sg");
+ }
dma_unmap_sg_attrs(domain->dev, sgl, nents, dir, attrs);
}
@@ -443,6 +451,7 @@ struct gcip_iommu_domain *gcip_iommu_get_domain_for_dev(struct device *dev)
gdomain->dev = dev;
gdomain->legacy_mode = true;
+ gdomain->default_domain = true;
return gdomain;
}
diff --git a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-kci.c b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-kci.c
index 417b078..dd8174c 100644
--- a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-kci.c
+++ b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-kci.c
@@ -242,6 +242,13 @@ static bool gcip_kci_before_handle_resp(struct gcip_mailbox *mailbox, const void
return true;
}
+static inline bool gcip_kci_is_block_off(struct gcip_mailbox *mailbox)
+{
+ struct gcip_kci *kci = gcip_mailbox_get_data(mailbox);
+
+ return kci->ops->is_block_off ? kci->ops->is_block_off(kci) : false;
+}
+
static const struct gcip_mailbox_ops gcip_mailbox_ops = {
.get_cmd_queue_head = gcip_kci_get_cmd_queue_head,
.get_cmd_queue_tail = gcip_kci_get_cmd_queue_tail,
@@ -265,6 +272,7 @@ static const struct gcip_mailbox_ops gcip_mailbox_ops = {
.after_enqueue_cmd = gcip_kci_after_enqueue_cmd,
.after_fetch_resps = gcip_kci_after_fetch_resps,
.before_handle_resp = gcip_kci_before_handle_resp,
+ .is_block_off = gcip_kci_is_block_off,
};
/*
@@ -357,7 +365,7 @@ static int gcip_reverse_kci_remove_resp(struct gcip_reverse_kci *rkci,
* Prevents the compiler from discarding and reloading its cached value additionally forces
* the CPU to order against subsequent memory references.
* Shamelessly stolen from:
- * https://www.kernel.org/doc/html/latest/core-api/circular-buffers.html
+ * [REDACTED]
*/
head = smp_load_acquire(&rkci->head);
tail = rkci->tail;
diff --git a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c
index 4571aa9..afa67c8 100644
--- a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c
+++ b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-mailbox.c
@@ -48,6 +48,8 @@
#define RELEASE_WAIT_LIST_LOCK(irqrestore, flags) \
mailbox->ops->release_wait_list_lock(mailbox, irqrestore, flags)
+#define IS_BLOCK_OFF() (mailbox->ops->is_block_off ? mailbox->ops->is_block_off(mailbox) : false)
+
struct gcip_mailbox_wait_list_elem {
struct list_head list;
struct gcip_mailbox_async_resp *async_resp;
@@ -331,8 +333,8 @@ static void *gcip_mailbox_fetch_responses(struct gcip_mailbox *mailbox, u32 *tot
void *prev_ptr = NULL; /* Temporary pointer to realloc ret. */
bool atomic = false;
- /* Someone is working on consuming - we can leave early. */
- if (!ACQUIRE_RESP_QUEUE_LOCK(true, &atomic))
+ /* The block is off or someone is working on consuming - we can leave early. */
+ if (IS_BLOCK_OFF() || !ACQUIRE_RESP_QUEUE_LOCK(true, &atomic))
goto out;
head = GET_RESP_QUEUE_HEAD();
@@ -396,7 +398,7 @@ static int gcip_mailbox_fetch_one_response(struct gcip_mailbox *mailbox, void *r
u32 tail;
bool atomic;
- if (!ACQUIRE_RESP_QUEUE_LOCK(true, &atomic))
+ if (IS_BLOCK_OFF() || !ACQUIRE_RESP_QUEUE_LOCK(true, &atomic))
return 0;
head = GET_RESP_QUEUE_HEAD();
diff --git a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-pm.c b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-pm.c
index b9907a1..50bc74b 100644
--- a/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-pm.c
+++ b/drivers/edgetpu/gcip-kernel-driver/drivers/gcip/gcip-pm.c
@@ -52,6 +52,14 @@ static void gcip_pm_async_power_down_work(struct work_struct *work)
mutex_unlock(&pm->lock);
}
+/* Worker for async gcip_pm_put(). */
+static void gcip_pm_async_put_work(struct work_struct *work)
+{
+ struct gcip_pm *pm = container_of(work, struct gcip_pm, put_async_work);
+
+ gcip_pm_put(pm);
+}
+
struct gcip_pm *gcip_pm_create(const struct gcip_pm_args *args)
{
struct gcip_pm *pm;
@@ -73,6 +81,7 @@ struct gcip_pm *gcip_pm_create(const struct gcip_pm_args *args)
mutex_init(&pm->lock);
INIT_DELAYED_WORK(&pm->power_down_work, gcip_pm_async_power_down_work);
+ INIT_WORK(&pm->put_async_work, gcip_pm_async_put_work);
if (pm->after_create) {
ret = pm->after_create(pm->data);
@@ -186,6 +195,16 @@ unlock:
mutex_unlock(&pm->lock);
}
+void gcip_pm_put_async(struct gcip_pm *pm)
+{
+ schedule_work(&pm->put_async_work);
+}
+
+void gcip_pm_flush_put_work(struct gcip_pm *pm)
+{
+ flush_work(&pm->put_async_work);
+}
+
int gcip_pm_get_count(struct gcip_pm *pm)
{
if (!pm)
diff --git a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-iommu.h b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-iommu.h
index 1797f94..34f6efa 100644
--- a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-iommu.h
+++ b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-iommu.h
@@ -104,6 +104,7 @@ struct gcip_iommu_domain {
struct gcip_iommu_domain_pool *domain_pool;
struct iommu_domain *domain;
bool legacy_mode;
+ bool default_domain;
union {
struct iova_domain iovad;
struct gcip_mem_pool mem_pool;
@@ -238,13 +239,13 @@ static inline bool gcip_iommu_domain_is_legacy_mode(struct gcip_iommu_domain *do
* 00 = DMA_BIDIRECTIONAL (host/device can write buffer)
* 01 = DMA_TO_DEVICE (host can write buffer)
* 10 = DMA_FROM_DEVICE (device can write buffer)
- * (See https://docs.kernel.org/core-api/dma-api-howto.html#dma-direction)
+ * (See [REDACTED]
* [2:2] - Coherent Mapping:
* 0 = Create non-coherent mappings of the buffer.
* 1 = Create coherent mappings of the buffer.
* [12:3] - DMA_ATTR:
* Not used in the non-legacy mode.
- * (See https://www.kernel.org/doc/Documentation/core-api/dma-attributes.rst)
+ * (See [REDACTED]
* [63:13] - RESERVED
* Set RESERVED bits to 0 to ensure backwards compatibility.
*
diff --git a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-kci.h b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-kci.h
index 1cfc82e..74670de 100644
--- a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-kci.h
+++ b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-kci.h
@@ -233,6 +233,11 @@ struct gcip_kci_ops {
* Context: normal.
*/
int (*update_usage)(struct gcip_kci *kci);
+ /*
+ * Checks if the block is off.
+ * Context: in_interrupt().
+ */
+ bool (*is_block_off)(struct gcip_kci *kci);
};
struct gcip_kci {
diff --git a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h
index af48ba6..b16c15f 100644
--- a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h
+++ b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-mailbox.h
@@ -344,6 +344,11 @@ struct gcip_mailbox_ops {
* Context: normal and in_interrupt().
*/
void (*release_awaiter_data)(void *data);
+ /*
+ * Checks if the block is off.
+ * Context: in_interrupt()
+ */
+ bool (*is_block_off)(struct gcip_mailbox *mailbox);
};
struct gcip_mailbox {
diff --git a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-pm.h b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-pm.h
index 1e6ce05..7e3a3e4 100644
--- a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-pm.h
+++ b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-pm.h
@@ -23,6 +23,8 @@ struct gcip_pm {
int count;
/* Flag indicating a deferred power down is pending. Protected by @lock */
bool power_down_pending;
+ /* The worker to asynchronously call gcip_pm_put(). */
+ struct work_struct put_async_work;
/* Callbacks. See struct gcip_pm_args. */
void *data;
@@ -99,6 +101,12 @@ int gcip_pm_get(struct gcip_pm *pm);
*/
void gcip_pm_put(struct gcip_pm *pm);
+/* Schedules an asynchronous job to execute gcip_pm_put(). */
+void gcip_pm_put_async(struct gcip_pm *pm);
+
+/* Flushes the pending pm_put work if any. */
+void gcip_pm_flush_put_work(struct gcip_pm *pm);
+
/* Gets the power up counter. Note that this is checked without PM lock. */
int gcip_pm_get_count(struct gcip_pm *pm);
diff --git a/drivers/edgetpu/mobile-soc-gsx01.c b/drivers/edgetpu/mobile-soc-gsx01.c
index b903ba1..d247c06 100644
--- a/drivers/edgetpu/mobile-soc-gsx01.c
+++ b/drivers/edgetpu/mobile-soc-gsx01.c
@@ -323,7 +323,7 @@ long edgetpu_soc_pm_get_rate(struct edgetpu_dev *etdev, int flags)
/*
* Below values must match the CMU PLL (pll_con3_pll_tpu) values in the spec and firmware.
- * See https://drive.google.com/file/d/16S9yxmGwkOltdO2w4dC8tpAt99chn-aq/view and
+ * See [REDACTED] and
* power_manager.cc for more details.
*/
switch (TO_PLL_DIV_M(pll_con3)) {
diff --git a/drivers/edgetpu/rio-pm.c b/drivers/edgetpu/rio-pm.c
index ac771ec..c50949a 100644
--- a/drivers/edgetpu/rio-pm.c
+++ b/drivers/edgetpu/rio-pm.c
@@ -144,14 +144,13 @@ static int rio_lpm_up(struct edgetpu_dev *etdev)
static bool rio_is_block_down(struct edgetpu_dev *etdev)
{
- struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(etdev);
int timeout_cnt = 0;
int curr_state;
do {
/* Delay 20us per retry till blk shutdown finished */
usleep_range(SHUTDOWN_DELAY_US_MIN, SHUTDOWN_DELAY_US_MAX);
- curr_state = readl(etmdev->pmu_status);
+ curr_state = readl(etdev->pmu_status);
if (!curr_state)
return true;
timeout_cnt++;
@@ -173,7 +172,7 @@ int edgetpu_chip_pm_create(struct edgetpu_dev *etdev)
platform_pwr->lpm_up = rio_lpm_up;
platform_pwr->lpm_down = rio_lpm_down;
- if (etmdev->pmu_status)
+ if (etdev->pmu_status)
platform_pwr->is_block_down = rio_is_block_down;
platform_pwr->post_fw_start = rio_post_fw_start;