summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWhi copybara merger <whitechapel-automerger@google.com>2021-12-23 17:43:18 +0800
committerCopybara-Service <copybara-worker@google.com>2022-01-06 09:11:15 -0800
commitc8f1888c32b8a3d7ae00f47ae80b986ac7eda678 (patch)
tree546bcc554776b7e503d828b201ea461aea806c53
parentb61360624793a3b4898bf74cbc053c2422826366 (diff)
downloadjaneiro-c8f1888c32b8a3d7ae00f47ae80b986ac7eda678.tar.gz
[Copybara Auto Merge] Merge branch 'pro' into android13-gs-pixel-5.10
edgetpu: dbg dump debugFS return EOPNOTSUPP edgetpu: dbg dump handle recoverable fault edgetpu: fix wakelock order to avoid lock inversion Bug: 197788097 edgetpu: power up TPU before sending dbg dump KCI edgetpu: add debugfs for getting dbg dump Bug: 207607509 edgetpu: map_size instead of alloc_size on dump Bug: 210563422 edgetpu: fix UAF on dumping group mappings Bug: 210549145 edgetpu: dmabuf fix potential UAF Bug: 210571509 GitOrigin-RevId: 2aabb111da6de45d4ba20dabfd15c8c05843348f Change-Id: I2145f3ef7839120eb9746a1543cab7245e8335f2
-rw-r--r--drivers/edgetpu/edgetpu-debug-dump.c39
-rw-r--r--drivers/edgetpu/edgetpu-dmabuf.c2
-rw-r--r--drivers/edgetpu/edgetpu-fs.c109
-rw-r--r--drivers/edgetpu/edgetpu-mailbox.c57
-rw-r--r--drivers/edgetpu/mobile-debug-dump.c45
-rw-r--r--drivers/edgetpu/mobile-debug-dump.h1
6 files changed, 155 insertions, 98 deletions
diff --git a/drivers/edgetpu/edgetpu-debug-dump.c b/drivers/edgetpu/edgetpu-debug-dump.c
index 3836e85..4539e87 100644
--- a/drivers/edgetpu/edgetpu-debug-dump.c
+++ b/drivers/edgetpu/edgetpu-debug-dump.c
@@ -3,8 +3,10 @@
* Module that defines structures and functions to retrieve debug dump segments
* from edgetpu firmware.
*
- * Copyright (C) 2020 Google, Inc.
+ * Copyright (C) 2020-2021 Google LLC
*/
+
+#include <linux/debugfs.h>
#include <linux/workqueue.h>
#include "edgetpu-config.h"
@@ -12,6 +14,36 @@
#include "edgetpu-device-group.h"
#include "edgetpu-iremap-pool.h"
#include "edgetpu-kci.h"
+#include "edgetpu-pm.h"
+
+static int edgetpu_get_debug_dump_set(void *data, u64 val)
+{
+ struct edgetpu_dev *etdev = data;
+ int ret = edgetpu_pm_get(etdev->pm);
+
+ if (ret)
+ return ret;
+ ret = edgetpu_get_debug_dump(etdev, val);
+ if (ret > 0) {
+ etdev_warn(etdev, "FW refused debug dump request: %d", ret);
+ ret = -EOPNOTSUPP;
+ }
+ edgetpu_pm_put(etdev->pm);
+ return ret;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_get_debug_dump, NULL, edgetpu_get_debug_dump_set, "%llu\n");
+
+/*
+ * Creates debugFS entries for interacting with debug dump functions.
+ *
+ * This is expected to be called by edgetpu_debug_dump_init().
+ */
+static inline void edgetpu_setup_debug_dump_fs(struct edgetpu_dev *etdev)
+{
+ /* forwards write requests to edgetpu_get_debug_dump() */
+ debugfs_create_file("get_debug_dump", 0220, etdev->d_entry, etdev, &fops_get_debug_dump);
+}
int edgetpu_get_debug_dump(struct edgetpu_dev *etdev, u64 type)
{
@@ -23,6 +55,10 @@ int edgetpu_get_debug_dump(struct edgetpu_dev *etdev, u64 type)
return -EINVAL;
}
+ if (!edgetpu_pm_get_if_powered(etdev->pm)) {
+ etdev_warn(etdev, "Device not powered, skip debug dump");
+ return -ENODEV;
+ }
dump_setup =
(struct edgetpu_debug_dump_setup *)etdev->debug_dump_mem.vaddr;
dump_setup->type = type;
@@ -35,6 +71,7 @@ int edgetpu_get_debug_dump(struct edgetpu_dev *etdev, u64 type)
if (ret)
etdev_err(etdev, "KCI dump info req failed: %d", ret);
+ edgetpu_pm_put(etdev->pm);
return ret;
}
diff --git a/drivers/edgetpu/edgetpu-dmabuf.c b/drivers/edgetpu/edgetpu-dmabuf.c
index f98aafe..276da72 100644
--- a/drivers/edgetpu/edgetpu-dmabuf.c
+++ b/drivers/edgetpu/edgetpu-dmabuf.c
@@ -723,7 +723,7 @@ int edgetpu_map_dmabuf(struct edgetpu_device_group *group,
__func__, ret);
goto err_release_map;
}
- arg->device_address = dmap->map.device_address;
+ arg->device_address = tpu_addr;
mutex_unlock(&group->lock);
dma_buf_put(dmabuf);
return 0;
diff --git a/drivers/edgetpu/edgetpu-fs.c b/drivers/edgetpu/edgetpu-fs.c
index 599a6a7..32b8fde 100644
--- a/drivers/edgetpu/edgetpu-fs.c
+++ b/drivers/edgetpu/edgetpu-fs.c
@@ -111,8 +111,8 @@ static int edgetpu_fs_release(struct inode *inode, struct file *file)
return 0;
etdev = client->etdev;
+ LOCK(client);
wakelock_count = edgetpu_wakelock_lock(client->wakelock);
- mutex_lock(&client->group_lock);
/*
* @wakelock_count = 0 means the device might be powered off. And for group with a
* non-detachable mailbox, its mailbox is removed when the group is released, in such case
@@ -130,8 +130,8 @@ static int edgetpu_fs_release(struct inode *inode, struct file *file)
/* failed to power on - prevent group releasing from accessing the device */
client->group->dev_inaccessible = true;
}
- mutex_unlock(&client->group_lock);
edgetpu_wakelock_unlock(client->wakelock);
+ UNLOCK(client);
edgetpu_client_remove(client);
@@ -222,32 +222,29 @@ static int edgetpu_ioctl_unset_perdie_eventfd(struct edgetpu_client *client,
static int edgetpu_ioctl_finalize_group(struct edgetpu_client *client)
{
struct edgetpu_device_group *group;
- int ret = -EINVAL, wakelock_count;
+ int ret = -EINVAL;
- /*
- * Hold the wakelock since we need to decide whether VII should be
- * initialized during finalization.
- */
- wakelock_count = edgetpu_wakelock_lock(client->wakelock);
LOCK(client);
group = client->group;
if (!group || !edgetpu_device_group_is_leader(group, client))
goto out_unlock;
/* Finalization has to be performed with device on. */
- if (!wakelock_count) {
- ret = edgetpu_pm_get(client->etdev->pm);
- if (ret) {
- etdev_err(client->etdev, "%s: pm_get failed (%d)",
- __func__, ret);
- goto out_unlock;
- }
+ ret = edgetpu_pm_get(client->etdev->pm);
+ if (ret) {
+ etdev_err(client->etdev, "%s: pm_get failed (%d)",
+ __func__, ret);
+ goto out_unlock;
}
+ /*
+ * Hold the wakelock since we need to decide whether VII should be
+ * initialized during finalization.
+ */
+ edgetpu_wakelock_lock(client->wakelock);
ret = edgetpu_device_group_finalize(group);
- if (!wakelock_count)
- edgetpu_pm_put(client->etdev->pm);
+ edgetpu_wakelock_unlock(client->wakelock);
+ edgetpu_pm_put(client->etdev->pm);
out_unlock:
UNLOCK(client);
- edgetpu_wakelock_unlock(client->wakelock);
return ret;
}
@@ -562,21 +559,22 @@ static int edgetpu_ioctl_release_wakelock(struct edgetpu_client *client)
{
int count;
+ LOCK(client);
edgetpu_wakelock_lock(client->wakelock);
/* when NO_WAKELOCK: count should be 1 so here is a no-op */
count = edgetpu_wakelock_release(client->wakelock);
if (count < 0) {
edgetpu_wakelock_unlock(client->wakelock);
+ UNLOCK(client);
return count;
}
if (!count) {
- mutex_lock(&client->group_lock);
if (client->group)
edgetpu_group_close_and_detach_mailbox(client->group);
- mutex_unlock(&client->group_lock);
edgetpu_pm_put(client->etdev->pm);
}
edgetpu_wakelock_unlock(client->wakelock);
+ UNLOCK(client);
etdev_dbg(client->etdev, "%s: wakelock req count = %u", __func__,
count);
return 0;
@@ -588,50 +586,49 @@ static int edgetpu_ioctl_acquire_wakelock(struct edgetpu_client *client)
int ret;
struct edgetpu_thermal *thermal = client->etdev->thermal;
+ LOCK(client);
+ edgetpu_thermal_lock(thermal);
+ if (edgetpu_thermal_is_suspended(thermal)) {
+ /* TPU is thermal suspended, so fail acquiring wakelock */
+ ret = -EAGAIN;
+ etdev_warn_ratelimited(client->etdev,
+ "wakelock acquire rejected due to thermal suspend");
+ edgetpu_thermal_unlock(thermal);
+ goto error_unlock;
+ } else {
+ ret = edgetpu_pm_get(client->etdev->pm);
+ edgetpu_thermal_unlock(thermal);
+ if (ret) {
+ etdev_warn(client->etdev, "%s: pm_get failed (%d)",
+ __func__, ret);
+ goto error_unlock;
+ }
+ }
edgetpu_wakelock_lock(client->wakelock);
/* when NO_WAKELOCK: count should be 1 so here is a no-op */
count = edgetpu_wakelock_acquire(client->wakelock);
if (count < 0) {
- edgetpu_wakelock_unlock(client->wakelock);
- return count;
+ edgetpu_pm_put(client->etdev->pm);
+ ret = count;
+ goto error_unlock;
}
- if (!count) {
- edgetpu_thermal_lock(thermal);
- if (edgetpu_thermal_is_suspended(thermal)) {
- /* TPU is thermal suspended, so fail acquiring wakelock */
- ret = -EAGAIN;
- etdev_warn_ratelimited(client->etdev,
- "wakelock acquire rejected due to thermal suspend");
- edgetpu_thermal_unlock(thermal);
- goto error_release;
- } else {
- ret = edgetpu_pm_get(client->etdev->pm);
- edgetpu_thermal_unlock(thermal);
- }
- if (ret) {
- etdev_warn(client->etdev, "%s: pm_get failed (%d)",
- __func__, ret);
- goto error_release;
- }
- mutex_lock(&client->group_lock);
- if (client->group)
- ret = edgetpu_group_attach_and_open_mailbox(
- client->group);
- mutex_unlock(&client->group_lock);
- if (ret) {
- etdev_warn(client->etdev,
- "failed to attach mailbox: %d", ret);
- edgetpu_pm_put(client->etdev->pm);
- goto error_release;
- }
+ if (!count && client->group)
+ ret = edgetpu_group_attach_and_open_mailbox(client->group);
+ if (ret) {
+ etdev_warn(client->etdev,
+ "failed to attach mailbox: %d", ret);
+ edgetpu_pm_put(client->etdev->pm);
+ edgetpu_wakelock_release(client->wakelock);
+ edgetpu_wakelock_unlock(client->wakelock);
+ goto error_unlock;
}
edgetpu_wakelock_unlock(client->wakelock);
+ UNLOCK(client);
etdev_dbg(client->etdev, "%s: wakelock req count = %u", __func__,
count + 1);
return 0;
-error_release:
- edgetpu_wakelock_release(client->wakelock);
- edgetpu_wakelock_unlock(client->wakelock);
+error_unlock:
+ UNLOCK(client);
etdev_err(client->etdev, "PID: %d failed to acquire wakelock", client->pid);
return ret;
}
@@ -683,10 +680,10 @@ static int edgetpu_ioctl_get_fatal_errors(struct edgetpu_client *client,
u32 fatal_errors = 0;
int ret = 0;
- mutex_lock(&client->group_lock);
+ LOCK(client);
if (client->group)
fatal_errors = edgetpu_group_get_fatal_errors(client->group);
- mutex_unlock(&client->group_lock);
+ UNLOCK(client);
if (copy_to_user(argp, &fatal_errors, sizeof(fatal_errors)))
ret = -EFAULT;
return ret;
diff --git a/drivers/edgetpu/edgetpu-mailbox.c b/drivers/edgetpu/edgetpu-mailbox.c
index a950e2c..03a958b 100644
--- a/drivers/edgetpu/edgetpu-mailbox.c
+++ b/drivers/edgetpu/edgetpu-mailbox.c
@@ -986,6 +986,13 @@ static int edgetpu_mailbox_external_alloc_enable(struct edgetpu_client *client,
group = edgetpu_device_group_get(client->group);
mutex_unlock(&client->group_lock);
+ if (!edgetpu_wakelock_lock(client->wakelock)) {
+ etdev_err(client->etdev, "Enabling external mailbox needs wakelock acquired\n");
+ edgetpu_wakelock_unlock(client->wakelock);
+ edgetpu_device_group_put(client->group);
+ return -EAGAIN;
+ }
+
mutex_lock(&group->lock);
if (!edgetpu_device_group_is_finalized(group)) {
ret = -EINVAL;
@@ -1028,6 +1035,10 @@ static int edgetpu_mailbox_external_alloc_enable(struct edgetpu_client *client,
}
unlock:
mutex_unlock(&group->lock);
+ if (!ret)
+ edgetpu_wakelock_inc_event_locked(client->wakelock,
+ EDGETPU_WAKELOCK_EVENT_EXT_MAILBOX);
+ edgetpu_wakelock_unlock(client->wakelock);
edgetpu_device_group_put(group);
return ret;
}
@@ -1044,9 +1055,17 @@ static int edgetpu_mailbox_external_disable_free(struct edgetpu_client *client)
group = edgetpu_device_group_get(client->group);
mutex_unlock(&client->group_lock);
+ if (!edgetpu_wakelock_lock(client->wakelock)) {
+ etdev_err(client->etdev, "Disabling external mailbox needs wakelock acquired\n");
+ edgetpu_wakelock_unlock(client->wakelock);
+ edgetpu_device_group_put(client->group);
+ return -EAGAIN;
+ }
mutex_lock(&group->lock);
edgetpu_mailbox_external_disable_free_locked(group);
mutex_unlock(&group->lock);
+ edgetpu_wakelock_dec_event_locked(client->wakelock, EDGETPU_WAKELOCK_EVENT_EXT_MAILBOX);
+ edgetpu_wakelock_unlock(client->wakelock);
edgetpu_device_group_put(group);
return 0;
}
@@ -1073,8 +1092,7 @@ void edgetpu_mailbox_external_disable_free_locked(struct edgetpu_device_group *g
edgetpu_mailbox_external_free(group);
}
-int edgetpu_mailbox_enable_ext(struct edgetpu_client *client, int mailbox_id,
- struct edgetpu_external_mailbox_req *ext_mailbox_req)
+static int edgetpu_mailbox_external_enable_by_id(struct edgetpu_client *client, int mailbox_id)
{
int ret;
@@ -1085,24 +1103,19 @@ int edgetpu_mailbox_enable_ext(struct edgetpu_client *client, int mailbox_id,
return -EAGAIN;
}
- if (mailbox_id == EDGETPU_MAILBOX_ID_USE_ASSOC) {
- ret = edgetpu_mailbox_external_alloc_enable(client, ext_mailbox_req);
- goto out;
- }
etdev_dbg(client->etdev, "Enabling mailbox: %d\n", mailbox_id);
ret = edgetpu_mailbox_activate(client->etdev, mailbox_id, -1, false);
if (ret)
etdev_err(client->etdev, "Activate mailbox %d failed: %d", mailbox_id, ret);
-out:
- if (!ret)
+ else
edgetpu_wakelock_inc_event_locked(client->wakelock,
EDGETPU_WAKELOCK_EVENT_EXT_MAILBOX);
edgetpu_wakelock_unlock(client->wakelock);
return ret;
}
-int edgetpu_mailbox_disable_ext(struct edgetpu_client *client, int mailbox_id)
+static int edgetpu_mailbox_external_disable_by_id(struct edgetpu_client *client, int mailbox_id)
{
int ret = 0;
@@ -1118,21 +1131,31 @@ int edgetpu_mailbox_disable_ext(struct edgetpu_client *client, int mailbox_id)
return -EAGAIN;
}
- if (mailbox_id == EDGETPU_MAILBOX_ID_USE_ASSOC) {
- ret = edgetpu_mailbox_external_disable_free(client);
- goto out;
- }
etdev_dbg(client->etdev, "Disabling mailbox: %d\n", mailbox_id);
edgetpu_mailbox_deactivate(client->etdev, mailbox_id);
-out:
- if (!ret)
- edgetpu_wakelock_dec_event_locked(client->wakelock,
- EDGETPU_WAKELOCK_EVENT_EXT_MAILBOX);
+ edgetpu_wakelock_dec_event_locked(client->wakelock, EDGETPU_WAKELOCK_EVENT_EXT_MAILBOX);
edgetpu_wakelock_unlock(client->wakelock);
return ret;
}
+int edgetpu_mailbox_enable_ext(struct edgetpu_client *client, int mailbox_id,
+ struct edgetpu_external_mailbox_req *ext_mailbox_req)
+{
+ if (mailbox_id == EDGETPU_MAILBOX_ID_USE_ASSOC)
+ return edgetpu_mailbox_external_alloc_enable(client, ext_mailbox_req);
+ else
+ return edgetpu_mailbox_external_enable_by_id(client, mailbox_id);
+}
+
+int edgetpu_mailbox_disable_ext(struct edgetpu_client *client, int mailbox_id)
+{
+ if (mailbox_id == EDGETPU_MAILBOX_ID_USE_ASSOC)
+ return edgetpu_mailbox_external_disable_free(client);
+ else
+ return edgetpu_mailbox_external_disable_by_id(client, mailbox_id);
+}
+
int edgetpu_mailbox_activate(struct edgetpu_dev *etdev, u32 mailbox_id, s16 vcid, bool first_open)
{
struct edgetpu_handshake *eh = &etdev->mailbox_manager->open_devices;
diff --git a/drivers/edgetpu/mobile-debug-dump.c b/drivers/edgetpu/mobile-debug-dump.c
index e0c9493..3bb7b3b 100644
--- a/drivers/edgetpu/mobile-debug-dump.c
+++ b/drivers/edgetpu/mobile-debug-dump.c
@@ -34,7 +34,8 @@ static struct platform_device sscd_dev;
*
* Returns the pointer to the first element of the mappings dump array. The allocated array should
* be freed by the caller after the sscd segment is reported.
- * Returns NULL in case of failure.
+ * Returns a negative errno in case of failure.
+ * Returns NULL when there is no mapping allocated in groups.
*/
static struct mobile_sscd_mappings_dump *
mobile_sscd_collect_mappings_segment(struct edgetpu_device_group **groups, size_t num_groups,
@@ -44,19 +45,24 @@ mobile_sscd_collect_mappings_segment(struct edgetpu_device_group **groups, size_
struct edgetpu_mapping_root *mappings;
struct rb_node *node;
void *resized_arr;
- size_t idx = 0, mappings_num = 0, new_size = 0;
+ size_t idx = 0, mappings_num = 0, new_size = 0, count;
- mappings_dump = kmalloc(sizeof(struct mobile_sscd_mappings_dump), GFP_KERNEL);
+ mappings_dump = NULL;
for (idx = 0; idx < num_groups; idx++) {
mutex_lock(&groups[idx]->lock);
- new_size +=
- groups[idx]->host_mappings.count * sizeof(struct mobile_sscd_mappings_dump);
+ count = groups[idx]->host_mappings.count + groups[idx]->dmabuf_mappings.count;
+ if (count == 0) {
+ mutex_unlock(&groups[idx]->lock);
+ continue;
+ }
+ new_size += count * sizeof(*mappings_dump);
resized_arr = krealloc(mappings_dump, new_size, GFP_KERNEL);
if (!resized_arr) {
kfree(mappings_dump);
mutex_unlock(&groups[idx]->lock);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
+ mappings_dump = resized_arr;
mappings = &groups[idx]->host_mappings;
for (node = rb_first(&mappings->rb); node; node = rb_next(node)) {
@@ -65,19 +71,9 @@ mobile_sscd_collect_mappings_segment(struct edgetpu_device_group **groups, size_
mappings_dump[mappings_num].host_address = map->host_address;
mappings_dump[mappings_num].device_address = map->device_address;
- mappings_dump[mappings_num].alloc_iova = map->alloc_iova;
- mappings_dump[mappings_num].size = (u64)map->alloc_size;
+ mappings_dump[mappings_num].size = (u64)map->map_size;
mappings_num++;
}
- new_size += groups[idx]->dmabuf_mappings.count *
- sizeof(struct mobile_sscd_mappings_dump);
- resized_arr = krealloc(mappings_dump, new_size, GFP_KERNEL);
- if (!resized_arr) {
- kfree(mappings_dump);
- mutex_unlock(&groups[idx]->lock);
- return NULL;
- }
-
mappings = &groups[idx]->dmabuf_mappings;
for (node = rb_first(&mappings->rb); node; node = rb_next(node)) {
struct edgetpu_mapping *map =
@@ -85,8 +81,7 @@ mobile_sscd_collect_mappings_segment(struct edgetpu_device_group **groups, size_
mappings_dump[mappings_num].host_address = map->host_address;
mappings_dump[mappings_num].device_address = map->device_address;
- mappings_dump[mappings_num].alloc_iova = map->alloc_iova;
- mappings_dump[mappings_num].size = (u64)map->alloc_size;
+ mappings_dump[mappings_num].size = (u64)map->map_size;
mappings_num++;
}
mutex_unlock(&groups[idx]->lock);
@@ -243,11 +238,15 @@ static int mobile_sscd_generate_coredump(void *p_etdev, void *p_dump_setup)
if (num_groups) {
mappings_dump = mobile_sscd_collect_mappings_segment(groups, num_groups, &segs[i]);
- if (!mappings_dump) {
- ret = -ENOMEM;
+ if (IS_ERR(mappings_dump)) {
+ ret = PTR_ERR(mappings_dump);
goto out_sscd_generate_coredump;
}
- i++;
+ /* increase @i if mappings present */
+ if (mappings_dump)
+ i++;
+ else
+ sscd_dump_segments_num--;
}
num_queues = mobile_sscd_collect_cmd_resp_queues(etdev, groups, num_groups, &segs[i]);
@@ -320,9 +319,11 @@ int edgetpu_debug_dump_init(struct edgetpu_dev *etdev)
if (!etdev->debug_dump_handlers)
return -ENOMEM;
etdev->debug_dump_handlers[DUMP_REASON_REQ_BY_USER] = mobile_sscd_generate_coredump;
+ etdev->debug_dump_handlers[DUMP_REASON_RECOVERABLE_FAULT] = mobile_sscd_generate_coredump;
pdev->sscd_info.pdata = &sscd_pdata;
pdev->sscd_info.dev = &sscd_dev;
+ edgetpu_setup_debug_dump_fs(etdev);
return ret;
out_unregister_platform:
platform_device_unregister(&sscd_dev);
diff --git a/drivers/edgetpu/mobile-debug-dump.h b/drivers/edgetpu/mobile-debug-dump.h
index f433a99..0ebd5f2 100644
--- a/drivers/edgetpu/mobile-debug-dump.h
+++ b/drivers/edgetpu/mobile-debug-dump.h
@@ -19,7 +19,6 @@ struct mobile_sscd_info {
struct mobile_sscd_mappings_dump {
u64 host_address;
u64 device_address;
- u64 alloc_iova;
u64 size;
};