diff options
author | Whi copybara merger <whitechapel-automerger@google.com> | 2021-12-23 17:43:18 +0800 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2022-01-06 09:11:15 -0800 |
commit | c8f1888c32b8a3d7ae00f47ae80b986ac7eda678 (patch) | |
tree | 546bcc554776b7e503d828b201ea461aea806c53 | |
parent | b61360624793a3b4898bf74cbc053c2422826366 (diff) | |
download | janeiro-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.c | 39 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-dmabuf.c | 2 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-fs.c | 109 | ||||
-rw-r--r-- | drivers/edgetpu/edgetpu-mailbox.c | 57 | ||||
-rw-r--r-- | drivers/edgetpu/mobile-debug-dump.c | 45 | ||||
-rw-r--r-- | drivers/edgetpu/mobile-debug-dump.h | 1 |
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; }; |