summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWhi copybara merger <whitechapel-automerger@google.com>2022-01-05 11:12:10 -0800
committerCopybara-Service <copybara-worker@google.com>2022-01-18 08:39:31 -0800
commit718b9717ccc1305f3d95b767f28e539c0c084313 (patch)
tree449095e0a90d76d9b4cbca0f29e93c242040e9e9
parent5017274660264e2910eadd6b573e2e87e3c6e009 (diff)
downloadabrolhos-718b9717ccc1305f3d95b767f28e539c0c084313.tar.gz
[Copybara Auto Merge] Merge branch 'whitechapel' into android-gs-pixel-5.10
edgetpu: Remove dbg dump error msg to avoid flooding logs. 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 edgetpu: notify MCP-wide thermal shutdown via kworker Bug: 207807085 Bug: 174552882 edgetpu: expand mobile debug dump support Bug: 207459857 edgetpu: mobile: share debug dump handlers Bug: 207459857 edgetpu: abrolhos: init sscd_dev in dbg dump init Bug: 208359418 edgetpu: expand EXT_MAILBOX support Bug: 204795149 GitOrigin-RevId: ccd0602e3352e9c241ebccfffa5a7d1322e43050 Change-Id: I72fe4428080e6f8e80ac09828e7fc8e330c91c66
-rw-r--r--drivers/edgetpu/abrolhos-debug-dump.c207
-rw-r--r--drivers/edgetpu/abrolhos-device.c84
-rw-r--r--drivers/edgetpu/abrolhos-platform.h3
-rw-r--r--drivers/edgetpu/abrolhos/config-mailbox.h6
-rw-r--r--drivers/edgetpu/edgetpu-debug-dump.c43
-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/edgetpu-mcp.h7
-rw-r--r--drivers/edgetpu/edgetpu-mobile-platform.c80
-rw-r--r--drivers/edgetpu/edgetpu-mobile-platform.h3
-rw-r--r--drivers/edgetpu/mobile-debug-dump.c277
-rw-r--r--drivers/edgetpu/mobile-debug-dump.h27
13 files changed, 473 insertions, 432 deletions
diff --git a/drivers/edgetpu/abrolhos-debug-dump.c b/drivers/edgetpu/abrolhos-debug-dump.c
index a56808c..92c3e1a 100644
--- a/drivers/edgetpu/abrolhos-debug-dump.c
+++ b/drivers/edgetpu/abrolhos-debug-dump.c
@@ -1,216 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
-/*
- * Implements chip specific details of debug dump memory initialization and SSCD registration.
- *
- * Copyright (C) 2021 Google, Inc.
- */
#if IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP) || IS_ENABLED(CONFIG_EDGETPU_TEST)
-#include <linux/platform_device.h>
-
-#include "abrolhos-platform.h"
-
#include "mobile-debug-dump.c"
-static void sscd_release(struct device *dev)
-{
- pr_debug(DRIVER_NAME " release\n");
-}
-static struct sscd_platform_data sscd_pdata;
-static struct platform_device sscd_dev = {
- .name = DRIVER_NAME,
- .driver_override = SSCD_NAME,
- .id = -1,
- .dev = {
- .platform_data = &sscd_pdata,
- .release = sscd_release,
- },
-};
-
-static int abrolhos_sscd_generate_coredump(void *p_etdev, void *p_dump_setup)
-{
- struct edgetpu_dev *etdev;
- struct edgetpu_debug_dump_setup *dump_setup;
- struct abrolhos_platform_dev *pdev;
- struct sscd_platform_data *pdata;
- struct platform_device *sscd_dev;
- struct sscd_segment *segs;
- struct edgetpu_debug_dump *debug_dump;
- struct edgetpu_crash_reason *crash_reason;
- struct edgetpu_dump_segment *dump_seg;
- struct edgetpu_device_group *group;
- struct edgetpu_device_group **groups;
- struct edgetpu_list_group *g;
- struct mobile_sscd_mappings_dump *mappings_dump = NULL;
- char crash_info[128];
- int sscd_dump_segments_num;
- int i, ret;
- size_t num_groups = 0, num_queues = 0;
- u64 offset;
-
- if (!p_etdev || !p_dump_setup)
- return -EINVAL;
-
- etdev = (struct edgetpu_dev *)p_etdev;
- dump_setup = (struct edgetpu_debug_dump_setup *)p_dump_setup;
- pdev = to_abrolhos_dev(etdev);
- pdata = (struct sscd_platform_data *)pdev->sscd_info.pdata;
- sscd_dev = (struct platform_device *)pdev->sscd_info.dev;
- if (!pdata->sscd_report) {
- etdev_err(etdev, "failed to generate coredump");
- return -ENOENT;
- }
-
- debug_dump = (struct edgetpu_debug_dump *)(dump_setup + 1);
-
- /* Populate crash reason */
- crash_reason = (struct edgetpu_crash_reason *)((u8 *)dump_setup +
- debug_dump->crash_reason_offset);
- scnprintf(crash_info, sizeof(crash_info),
- "[edgetpu_coredump] error code: %#llx", crash_reason->code);
-
- mutex_lock(&etdev->groups_lock);
- groups = kmalloc_array(etdev->n_groups, sizeof(*groups), GFP_KERNEL);
- if (!groups) {
- mutex_unlock(&etdev->groups_lock);
- return -ENOMEM;
- }
-
- etdev_for_each_group(etdev, g, group) {
- if (edgetpu_device_group_is_disbanded(group))
- continue;
- groups[num_groups++] = edgetpu_device_group_get(group);
- }
- mutex_unlock(&etdev->groups_lock);
-
- /* Allocate memory for dump segments */
- sscd_dump_segments_num = debug_dump->dump_segments_num;
- sscd_dump_segments_num += 2 * num_groups; /* VII cmd and resp queues */
- sscd_dump_segments_num += num_groups ? 1 : 0; /* Mappings info */
- sscd_dump_segments_num += 2; /* KCI cmd and resp queues */
-
- segs = kmalloc_array(sscd_dump_segments_num,
- sizeof(struct sscd_segment),
- GFP_KERNEL);
- if (!segs) {
- ret = -ENOMEM;
- goto out_sscd_generate_coredump;
- }
-
- /* Populate sscd segments */
- dump_seg = (struct edgetpu_dump_segment *)((u8 *)dump_setup +
- debug_dump->dump_segments_offset);
- offset = debug_dump->dump_segments_offset;
- for (i = 0; i < debug_dump->dump_segments_num; i++) {
- segs[i].addr = dump_seg;
- segs[i].size = sizeof(struct edgetpu_dump_segment) + dump_seg->size;
- segs[i].paddr = (void *)(etdev->debug_dump_mem.tpu_addr +
- offset);
- segs[i].vaddr = (void *)(etdev->debug_dump_mem.vaddr +
- offset);
- offset += sizeof(struct edgetpu_dump_segment) + dump_seg->size;
- dump_seg = (struct edgetpu_dump_segment *)
- ((u8 *)dump_setup + ALIGN(offset, sizeof(uint64_t)));
- }
-
- if (num_groups) {
- mappings_dump = mobile_sscd_collect_mappings_segment(groups, num_groups, &segs[i]);
- if (!mappings_dump) {
- ret = -ENOMEM;
- goto out_sscd_generate_coredump;
- }
- i++;
- }
-
- num_queues = mobile_sscd_collect_cmd_resp_queues(etdev, groups, num_groups, &segs[i]);
-
- /* Adjust num of segments as some groups may have a detached mailbox */
- sscd_dump_segments_num -= (2 * num_groups + 2); /* Subtract number of VII and KCI queues
- * according to num_groups.
- */
- sscd_dump_segments_num += num_queues; /* Add actual number of valid VII and KCI queues */
-
- /* Pass dump data to SSCD daemon */
- etdev_dbg(etdev, "report: %d segments", sscd_dump_segments_num);
- ret = pdata->sscd_report(sscd_dev, segs, sscd_dump_segments_num,
- SSCD_FLAGS_ELFARM64HDR, crash_info);
-out_sscd_generate_coredump:
- for (i = 0; i < num_groups; i++)
- edgetpu_device_group_put(groups[i]);
- kfree(mappings_dump);
- kfree(segs);
- kfree(groups);
-
- return ret;
-}
-
-int edgetpu_debug_dump_init(struct edgetpu_dev *etdev)
-{
- size_t size;
- int ret;
- struct edgetpu_debug_dump_setup *dump_setup;
- struct abrolhos_platform_dev *pdev;
-
- pdev = to_abrolhos_dev(etdev);
-
- size = EDGETPU_DEBUG_DUMP_MEM_SIZE;
-
- /* Register SSCD platform device */
- ret = platform_device_register(&sscd_dev);
- if (ret) {
- etdev_err(etdev, "SSCD platform device registration failed: %d", ret);
- return ret;
- }
- /*
- * Allocate a buffer for various dump segments
- */
- ret = edgetpu_alloc_coherent(etdev, size, &etdev->debug_dump_mem,
- EDGETPU_CONTEXT_KCI);
- if (ret) {
- etdev_err(etdev, "Debug dump seg alloc failed");
- etdev->debug_dump_mem.vaddr = NULL;
- goto out_unregister_platform;
- }
- dump_setup =
- (struct edgetpu_debug_dump_setup *)etdev->debug_dump_mem.vaddr;
- memset(dump_setup, 0, size);
- dump_setup->dump_mem_size = size;
-
- /*
- * Allocate memory for debug dump handlers
- */
- etdev->debug_dump_handlers = kcalloc(DUMP_REASON_NUM,
- sizeof(*etdev->debug_dump_handlers),
- GFP_KERNEL);
- if (!etdev->debug_dump_handlers)
- return -ENOMEM;
- etdev->debug_dump_handlers[DUMP_REASON_REQ_BY_USER] =
- abrolhos_sscd_generate_coredump;
-
- pdev->sscd_info.pdata = &sscd_pdata;
- pdev->sscd_info.dev = &sscd_dev;
- return ret;
-out_unregister_platform:
- platform_device_unregister(&sscd_dev);
- return ret;
-}
-
-void edgetpu_debug_dump_exit(struct edgetpu_dev *etdev)
-{
- if (!etdev->debug_dump_mem.vaddr) {
- etdev_dbg(etdev, "Debug dump not allocated");
- return;
- }
- /*
- * Free the memory assigned for debug dump
- */
- edgetpu_free_coherent(etdev, &etdev->debug_dump_mem,
- EDGETPU_CONTEXT_KCI);
- kfree(etdev->debug_dump_handlers);
- platform_device_unregister(&sscd_dev);
-}
-
#else /* IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP) || IS_ENABLED(CONFIG_EDGETPU_TEST) */
#include "edgetpu-debug-dump.c"
diff --git a/drivers/edgetpu/abrolhos-device.c b/drivers/edgetpu/abrolhos-device.c
index df23c42..67feb70 100644
--- a/drivers/edgetpu/abrolhos-device.c
+++ b/drivers/edgetpu/abrolhos-device.c
@@ -105,87 +105,3 @@ void edgetpu_chip_handle_reverse_kci(struct edgetpu_dev *etdev,
break;
}
}
-
-static int abrolhos_check_ext_mailbox_args(const char *func,
- struct edgetpu_dev *etdev,
- struct edgetpu_ext_mailbox_ioctl *args)
-{
- if (args->type != EDGETPU_EXT_MAILBOX_TYPE_TZ) {
- etdev_err(etdev, "%s: Invalid type %d != %d\n", func,
- args->type, EDGETPU_EXT_MAILBOX_TYPE_TZ);
- return -EINVAL;
- }
- if (args->count != 1) {
- etdev_err(etdev, "%s: Invalid mailbox count: %d != 1\n", func,
- args->count);
- return -EINVAL;
- }
- return 0;
-}
-
-int edgetpu_chip_acquire_ext_mailbox(struct edgetpu_client *client,
- struct edgetpu_ext_mailbox_ioctl *args)
-{
- struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(client->etdev);
- int ret;
-
- ret = abrolhos_check_ext_mailbox_args(__func__, client->etdev,
- args);
- if (ret)
- return ret;
-
- mutex_lock(&etmdev->tz_mailbox_lock);
- if (etmdev->secure_client) {
- etdev_err(client->etdev,
- "TZ mailbox already in use by PID %d\n",
- etmdev->secure_client->pid);
- mutex_unlock(&etmdev->tz_mailbox_lock);
- return -EBUSY;
- }
- ret = edgetpu_mailbox_enable_ext(client, ABROLHOS_TZ_MAILBOX_ID, NULL);
- if (!ret)
- etmdev->secure_client = client;
- mutex_unlock(&etmdev->tz_mailbox_lock);
- return ret;
-}
-
-int edgetpu_chip_release_ext_mailbox(struct edgetpu_client *client,
- struct edgetpu_ext_mailbox_ioctl *args)
-{
- struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(client->etdev);
- int ret = 0;
-
- ret = abrolhos_check_ext_mailbox_args(__func__, client->etdev,
- args);
- if (ret)
- return ret;
-
- mutex_lock(&etmdev->tz_mailbox_lock);
- if (!etmdev->secure_client) {
- etdev_warn(client->etdev, "TZ mailbox already released\n");
- mutex_unlock(&etmdev->tz_mailbox_lock);
- return 0;
- }
- if (etmdev->secure_client != client) {
- etdev_err(client->etdev,
- "TZ mailbox owned by different client\n");
- mutex_unlock(&etmdev->tz_mailbox_lock);
- return -EBUSY;
- }
- etmdev->secure_client = NULL;
- ret = edgetpu_mailbox_disable_ext(client, ABROLHOS_TZ_MAILBOX_ID);
- mutex_unlock(&etmdev->tz_mailbox_lock);
- return ret;
-}
-
-void edgetpu_chip_client_remove(struct edgetpu_client *client)
-{
- struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(client->etdev);
-
- mutex_lock(&etmdev->tz_mailbox_lock);
- if (etmdev->secure_client == client) {
- etmdev->secure_client = NULL;
- edgetpu_mailbox_disable_ext(client, ABROLHOS_TZ_MAILBOX_ID);
- }
- mutex_unlock(&etmdev->tz_mailbox_lock);
-}
diff --git a/drivers/edgetpu/abrolhos-platform.h b/drivers/edgetpu/abrolhos-platform.h
index 7ed88ed..4372f30 100644
--- a/drivers/edgetpu/abrolhos-platform.h
+++ b/drivers/edgetpu/abrolhos-platform.h
@@ -10,15 +10,12 @@
#include "edgetpu-internal.h"
#include "edgetpu-mobile-platform.h"
-#include "mobile-debug-dump.h"
#define to_abrolhos_dev(etdev) \
container_of((to_mobile_dev(etdev)), struct abrolhos_platform_dev, mobile_dev)
struct abrolhos_platform_dev {
struct edgetpu_mobile_platform_dev mobile_dev;
- /* subsystem coredump info struct */
- struct mobile_sscd_info sscd_info;
};
#endif /* __ABROLHOS_PLATFORM_H__ */
diff --git a/drivers/edgetpu/abrolhos/config-mailbox.h b/drivers/edgetpu/abrolhos/config-mailbox.h
index efbd169..b5a6c88 100644
--- a/drivers/edgetpu/abrolhos/config-mailbox.h
+++ b/drivers/edgetpu/abrolhos/config-mailbox.h
@@ -15,7 +15,11 @@
#define EDGETPU_NUM_P2P_MAILBOXES 0
#define EDGETPU_NUM_EXT_MAILBOXES 0
-#define ABROLHOS_TZ_MAILBOX_ID 8
+/*
+ * The TZ mailbox is not managed by the kernel, but we still need to tell firmware to enable it,
+ * so it's index is placed after the kernel managed mailboxes.
+ */
+#define EDGETPU_TZ_MAILBOX_ID 8
#define ABROLHOS_CSR_MBOX2_CONTEXT_ENABLE 0xe0000
#define ABROLHOS_CSR_MBOX2_CMD_QUEUE_DOORBELL_SET 0xe1000
diff --git a/drivers/edgetpu/edgetpu-debug-dump.c b/drivers/edgetpu/edgetpu-debug-dump.c
index 3836e85..ab5f9e3 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;
}
@@ -83,10 +120,8 @@ void edgetpu_debug_dump_resp_handler(struct edgetpu_dev *etdev)
struct edgetpu_debug_dump_setup *dump_setup;
struct edgetpu_debug_dump *debug_dump;
- if (!etdev->debug_dump_mem.vaddr) {
- etdev_err(etdev, "Debug dump memory not allocated");
+ if (!etdev->debug_dump_mem.vaddr)
return;
- }
dump_setup =
(struct edgetpu_debug_dump_setup *)etdev->debug_dump_mem.vaddr;
debug_dump = (struct edgetpu_debug_dump *)(dump_setup + 1);
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/edgetpu-mcp.h b/drivers/edgetpu/edgetpu-mcp.h
index 4530d79..4d762c4 100644
--- a/drivers/edgetpu/edgetpu-mcp.h
+++ b/drivers/edgetpu/edgetpu-mcp.h
@@ -9,7 +9,9 @@
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/spinlock.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
#include "edgetpu-config.h"
#include "edgetpu-internal.h"
@@ -38,6 +40,11 @@ struct edgetpu_mcp {
* One should check with !IS_ERR_OR_NULL(etdevs[i]) before accessing.
*/
struct edgetpu_dev **etdevs;
+
+ /* MCP-wide fatal errors pending runtime notification */
+ uint errors_pending_mask;
+ spinlock_t errors_pending_lock;
+ struct work_struct errors_pending_work; /* for notify via kworker */
};
#ifdef EDGETPU_HAS_MCP
diff --git a/drivers/edgetpu/edgetpu-mobile-platform.c b/drivers/edgetpu/edgetpu-mobile-platform.c
index ffa8928..4e9cac0 100644
--- a/drivers/edgetpu/edgetpu-mobile-platform.c
+++ b/drivers/edgetpu/edgetpu-mobile-platform.c
@@ -125,6 +125,86 @@ static void edgetpu_platform_cleanup_fw_region(struct edgetpu_mobile_platform_de
etmdev->shared_mem_vaddr = NULL;
}
+static int mobile_check_ext_mailbox_args(const char *func, struct edgetpu_dev *etdev,
+ struct edgetpu_ext_mailbox_ioctl *args)
+{
+ if (args->type != EDGETPU_EXT_MAILBOX_TYPE_TZ) {
+ etdev_err(etdev, "%s: Invalid type %d != %d\n", func, args->type,
+ EDGETPU_EXT_MAILBOX_TYPE_TZ);
+ return -EINVAL;
+ }
+ if (args->count != 1) {
+ etdev_err(etdev, "%s: Invalid mailbox count: %d != 1\n", func, args->count);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int edgetpu_chip_acquire_ext_mailbox(struct edgetpu_client *client,
+ struct edgetpu_ext_mailbox_ioctl *args)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(client->etdev);
+ int ret;
+
+ ret = mobile_check_ext_mailbox_args(__func__, client->etdev, args);
+ if (ret)
+ return ret;
+
+ mutex_lock(&etmdev->tz_mailbox_lock);
+ if (etmdev->secure_client) {
+ etdev_err(client->etdev, "TZ mailbox already in use by PID %d\n",
+ etmdev->secure_client->pid);
+ mutex_unlock(&etmdev->tz_mailbox_lock);
+ return -EBUSY;
+ }
+ ret = edgetpu_mailbox_enable_ext(client, EDGETPU_TZ_MAILBOX_ID, NULL);
+ if (!ret)
+ etmdev->secure_client = client;
+ mutex_unlock(&etmdev->tz_mailbox_lock);
+ return ret;
+}
+
+int edgetpu_chip_release_ext_mailbox(struct edgetpu_client *client,
+ struct edgetpu_ext_mailbox_ioctl *args)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(client->etdev);
+ int ret = 0;
+
+ ret = mobile_check_ext_mailbox_args(__func__, client->etdev,
+ args);
+ if (ret)
+ return ret;
+
+ mutex_lock(&etmdev->tz_mailbox_lock);
+ if (!etmdev->secure_client) {
+ etdev_warn(client->etdev, "TZ mailbox already released\n");
+ mutex_unlock(&etmdev->tz_mailbox_lock);
+ return 0;
+ }
+ if (etmdev->secure_client != client) {
+ etdev_err(client->etdev,
+ "TZ mailbox owned by different client\n");
+ mutex_unlock(&etmdev->tz_mailbox_lock);
+ return -EBUSY;
+ }
+ etmdev->secure_client = NULL;
+ ret = edgetpu_mailbox_disable_ext(client, EDGETPU_TZ_MAILBOX_ID);
+ mutex_unlock(&etmdev->tz_mailbox_lock);
+ return ret;
+}
+
+void edgetpu_chip_client_remove(struct edgetpu_client *client)
+{
+ struct edgetpu_mobile_platform_dev *etmdev = to_mobile_dev(client->etdev);
+
+ mutex_lock(&etmdev->tz_mailbox_lock);
+ if (etmdev->secure_client == client) {
+ etmdev->secure_client = NULL;
+ edgetpu_mailbox_disable_ext(client, EDGETPU_TZ_MAILBOX_ID);
+ }
+ mutex_unlock(&etmdev->tz_mailbox_lock);
+}
+
int edgetpu_chip_setup_mmu(struct edgetpu_dev *etdev)
{
int ret;
diff --git a/drivers/edgetpu/edgetpu-mobile-platform.h b/drivers/edgetpu/edgetpu-mobile-platform.h
index 65184ae..9d41571 100644
--- a/drivers/edgetpu/edgetpu-mobile-platform.h
+++ b/drivers/edgetpu/edgetpu-mobile-platform.h
@@ -22,6 +22,7 @@
#include "edgetpu-config.h"
#include "edgetpu-internal.h"
+#include "mobile-debug-dump.h"
#define to_mobile_dev(etdev) container_of(etdev, struct edgetpu_mobile_platform_dev, edgetpu_dev)
@@ -93,6 +94,8 @@ struct edgetpu_mobile_platform_dev {
#if IS_ENABLED(CONFIG_GOOGLE_BCL)
struct bcl_device *bcl_dev;
#endif
+ /* subsystem coredump info struct */
+ struct mobile_sscd_info sscd_info;
/* Protects TZ Mailbox client pointer */
struct mutex tz_mailbox_lock;
/* TZ mailbox client */
diff --git a/drivers/edgetpu/mobile-debug-dump.c b/drivers/edgetpu/mobile-debug-dump.c
index 3732fbb..3bb7b3b 100644
--- a/drivers/edgetpu/mobile-debug-dump.c
+++ b/drivers/edgetpu/mobile-debug-dump.c
@@ -8,16 +8,36 @@
#include <linux/mutex.h>
#include <linux/platform_data/sscoredump.h>
+#include <linux/platform_device.h>
#include <linux/rbtree.h>
#include <linux/slab.h>
+#include "edgetpu-config.h"
#include "edgetpu-device-group.h"
#include "edgetpu-mailbox.h"
+#include "edgetpu-mobile-platform.h"
#include "mobile-debug-dump.h"
#include "edgetpu-debug-dump.c"
-struct mobile_sscd_mappings_dump *
+static void sscd_release(struct device *dev)
+{
+ pr_debug(DRIVER_NAME " release\n");
+}
+
+static struct sscd_platform_data sscd_pdata;
+static struct platform_device sscd_dev;
+
+/*
+ * Collects the mapping information of all the host mapping and dmabuf mapping buffers of all
+ * @groups as an array of struct mobile_sscd_mappings_dump and populates the @sscd_seg.
+ *
+ * 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 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,
struct sscd_segment *sscd_seg)
{
@@ -25,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)) {
@@ -46,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 =
@@ -66,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);
@@ -80,40 +94,49 @@ mobile_sscd_collect_mappings_segment(struct edgetpu_device_group **groups, size_
return mappings_dump;
}
-size_t mobile_sscd_collect_cmd_resp_queues(struct edgetpu_dev *etdev,
- struct edgetpu_device_group **groups, size_t num_groups,
- struct sscd_segment *sscd_seg_arr)
+/*
+ * Collects the VII cmd and resp queues of all @groups that @etdev belongs to and the KCI cmd and
+ * resp queues and populates them as @sscd_seg_arr elements.
+ *
+ * Returns the total number of queues collected since some queues may have been released for groups
+ * with detached mailboxes. The return value is less than or equal to the total number of queues
+ * expected based on @num_groups i.e. (2 * @num_groups +2).
+ */
+static size_t mobile_sscd_collect_cmd_resp_queues(struct edgetpu_dev *etdev,
+ struct edgetpu_device_group **groups,
+ size_t num_groups,
+ struct sscd_segment *sscd_seg_arr)
{
struct edgetpu_kci *kci;
size_t idx;
u16 num_queues = 0;
- // Collect VII cmd and resp queues
+ /* Collect VII cmd and resp queues */
for (idx = 0; idx < num_groups; idx++) {
mutex_lock(&groups[idx]->lock);
if (!edgetpu_group_mailbox_detached_locked(groups[idx])) {
sscd_seg_arr[num_queues].addr =
- (void *)groups[idx]->vii.cmd_queue_mem.vaddr;
+ (void *)groups[idx]->vii.cmd_queue_mem.vaddr;
sscd_seg_arr[num_queues].size = groups[idx]->vii.cmd_queue_mem.size;
sscd_seg_arr[num_queues].paddr =
- (void *)groups[idx]->vii.cmd_queue_mem.tpu_addr;
+ (void *)groups[idx]->vii.cmd_queue_mem.tpu_addr;
sscd_seg_arr[num_queues].vaddr =
- (void *)groups[idx]->vii.cmd_queue_mem.vaddr;
+ (void *)groups[idx]->vii.cmd_queue_mem.vaddr;
num_queues++;
sscd_seg_arr[num_queues].addr =
- (void *)groups[idx]->vii.resp_queue_mem.vaddr;
+ (void *)groups[idx]->vii.resp_queue_mem.vaddr;
sscd_seg_arr[num_queues].size = groups[idx]->vii.resp_queue_mem.size;
sscd_seg_arr[num_queues].paddr =
- (void *)groups[idx]->vii.resp_queue_mem.tpu_addr;
+ (void *)groups[idx]->vii.resp_queue_mem.tpu_addr;
sscd_seg_arr[num_queues].vaddr =
- (void *)groups[idx]->vii.resp_queue_mem.vaddr;
+ (void *)groups[idx]->vii.resp_queue_mem.vaddr;
num_queues++;
}
mutex_unlock(&groups[idx]->lock);
}
- // Collect KCI cmd and resp queues
+ /* Collect KCI cmd and resp queues */
kci = etdev->kci;
sscd_seg_arr[num_queues].addr = (void *)kci->cmd_queue_mem.vaddr;
sscd_seg_arr[num_queues].size = MAX_QUEUE_SIZE * sizeof(struct edgetpu_command_element);
@@ -122,11 +145,201 @@ size_t mobile_sscd_collect_cmd_resp_queues(struct edgetpu_dev *etdev,
num_queues++;
sscd_seg_arr[num_queues].addr = (void *)kci->resp_queue_mem.vaddr;
- sscd_seg_arr[num_queues].size = MAX_QUEUE_SIZE *
- sizeof(struct edgetpu_kci_response_element);
+ sscd_seg_arr[num_queues].size =
+ MAX_QUEUE_SIZE * sizeof(struct edgetpu_kci_response_element);
sscd_seg_arr[num_queues].paddr = (void *)kci->resp_queue_mem.tpu_addr;
sscd_seg_arr[num_queues].vaddr = (void *)kci->resp_queue_mem.vaddr;
num_queues++;
return num_queues;
}
+
+static int mobile_sscd_generate_coredump(void *p_etdev, void *p_dump_setup)
+{
+ struct edgetpu_dev *etdev;
+ struct edgetpu_debug_dump_setup *dump_setup;
+ struct edgetpu_mobile_platform_dev *pdev;
+ struct sscd_platform_data *pdata;
+ struct platform_device *sscd_dev;
+ struct sscd_segment *segs;
+ struct edgetpu_debug_dump *debug_dump;
+ struct edgetpu_crash_reason *crash_reason;
+ struct edgetpu_dump_segment *dump_seg;
+ struct edgetpu_device_group *group;
+ struct edgetpu_device_group **groups;
+ struct edgetpu_list_group *g;
+ struct mobile_sscd_mappings_dump *mappings_dump = NULL;
+ char crash_info[128];
+ int sscd_dump_segments_num;
+ int i, ret;
+ size_t num_groups = 0, num_queues = 0;
+ u64 offset;
+
+ if (!p_etdev || !p_dump_setup)
+ return -EINVAL;
+
+ etdev = (struct edgetpu_dev *)p_etdev;
+ dump_setup = (struct edgetpu_debug_dump_setup *)p_dump_setup;
+ pdev = to_mobile_dev(etdev);
+ pdata = (struct sscd_platform_data *)pdev->sscd_info.pdata;
+ sscd_dev = (struct platform_device *)pdev->sscd_info.dev;
+ if (!pdata->sscd_report) {
+ etdev_err(etdev, "failed to generate coredump");
+ return -ENOENT;
+ }
+
+ debug_dump = (struct edgetpu_debug_dump *)(dump_setup + 1);
+
+ /* Populate crash reason */
+ crash_reason =
+ (struct edgetpu_crash_reason *)((u8 *)dump_setup + debug_dump->crash_reason_offset);
+ scnprintf(crash_info, sizeof(crash_info), "[edgetpu_coredump] error code: %#llx",
+ crash_reason->code);
+
+ mutex_lock(&etdev->groups_lock);
+ groups = kmalloc_array(etdev->n_groups, sizeof(*groups), GFP_KERNEL);
+ if (!groups) {
+ mutex_unlock(&etdev->groups_lock);
+ return -ENOMEM;
+ }
+
+ etdev_for_each_group(etdev, g, group) {
+ if (edgetpu_device_group_is_disbanded(group))
+ continue;
+ groups[num_groups++] = edgetpu_device_group_get(group);
+ }
+ mutex_unlock(&etdev->groups_lock);
+
+ /* Allocate memory for dump segments */
+ sscd_dump_segments_num = debug_dump->dump_segments_num;
+ sscd_dump_segments_num += 2 * num_groups; /* VII cmd and resp queues */
+ sscd_dump_segments_num += num_groups ? 1 : 0; /* Mappings info */
+ sscd_dump_segments_num += 2; /* KCI cmd and resp queues */
+
+ segs = kmalloc_array(sscd_dump_segments_num, sizeof(struct sscd_segment), GFP_KERNEL);
+ if (!segs) {
+ ret = -ENOMEM;
+ goto out_sscd_generate_coredump;
+ }
+
+ /* Populate sscd segments */
+ dump_seg = (struct edgetpu_dump_segment *)((u8 *)dump_setup +
+ debug_dump->dump_segments_offset);
+ offset = debug_dump->dump_segments_offset;
+ for (i = 0; i < debug_dump->dump_segments_num; i++) {
+ segs[i].addr = dump_seg;
+ segs[i].size = sizeof(struct edgetpu_dump_segment) + dump_seg->size;
+ segs[i].paddr = (void *)(etdev->debug_dump_mem.tpu_addr + offset);
+ segs[i].vaddr = (void *)(etdev->debug_dump_mem.vaddr + offset);
+ offset += sizeof(struct edgetpu_dump_segment) + dump_seg->size;
+ dump_seg = (struct edgetpu_dump_segment *)((u8 *)dump_setup +
+ ALIGN(offset, sizeof(uint64_t)));
+ }
+
+ if (num_groups) {
+ mappings_dump = mobile_sscd_collect_mappings_segment(groups, num_groups, &segs[i]);
+ if (IS_ERR(mappings_dump)) {
+ ret = PTR_ERR(mappings_dump);
+ goto out_sscd_generate_coredump;
+ }
+ /* 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]);
+
+ /*
+ * Adjust num of segments as some groups may have a detached mailbox.
+ * Subtract number of VII and KCI queues according to num_groups.
+ */
+ sscd_dump_segments_num -= (2 * num_groups + 2);
+ sscd_dump_segments_num += num_queues; /* Add actual number of valid VII and KCI queues */
+
+ /* Pass dump data to SSCD daemon */
+ etdev_dbg(etdev, "report: %d segments", sscd_dump_segments_num);
+ ret = pdata->sscd_report(sscd_dev, segs, sscd_dump_segments_num, SSCD_FLAGS_ELFARM64HDR,
+ crash_info);
+out_sscd_generate_coredump:
+ for (i = 0; i < num_groups; i++)
+ edgetpu_device_group_put(groups[i]);
+ kfree(mappings_dump);
+ kfree(segs);
+ kfree(groups);
+
+ return ret;
+}
+
+int edgetpu_debug_dump_init(struct edgetpu_dev *etdev)
+{
+ size_t size;
+ int ret;
+ struct edgetpu_debug_dump_setup *dump_setup;
+ struct edgetpu_mobile_platform_dev *pdev;
+
+ pdev = to_mobile_dev(etdev);
+
+ size = EDGETPU_DEBUG_DUMP_MEM_SIZE;
+
+ sscd_dev = (struct platform_device) {
+ .name = DRIVER_NAME,
+ .driver_override = SSCD_NAME,
+ .id = PLATFORM_DEVID_NONE,
+ .dev = {
+ .platform_data = &sscd_pdata,
+ .release = sscd_release,
+ },
+ };
+ /* Register SSCD platform device */
+ ret = platform_device_register(&sscd_dev);
+ if (ret) {
+ etdev_err(etdev, "SSCD platform device registration failed: %d", ret);
+ return ret;
+ }
+ /*
+ * Allocate a buffer for various dump segments
+ */
+ ret = edgetpu_alloc_coherent(etdev, size, &etdev->debug_dump_mem, EDGETPU_CONTEXT_KCI);
+ if (ret) {
+ etdev_err(etdev, "Debug dump seg alloc failed");
+ etdev->debug_dump_mem.vaddr = NULL;
+ goto out_unregister_platform;
+ }
+ dump_setup = (struct edgetpu_debug_dump_setup *)etdev->debug_dump_mem.vaddr;
+ memset(dump_setup, 0, size);
+ dump_setup->dump_mem_size = size;
+
+ /*
+ * Allocate memory for debug dump handlers
+ */
+ etdev->debug_dump_handlers =
+ kcalloc(DUMP_REASON_NUM, sizeof(*etdev->debug_dump_handlers), GFP_KERNEL);
+ 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);
+ return ret;
+}
+
+void edgetpu_debug_dump_exit(struct edgetpu_dev *etdev)
+{
+ if (!etdev->debug_dump_mem.vaddr) {
+ etdev_dbg(etdev, "Debug dump not allocated");
+ return;
+ }
+ /*
+ * Free the memory assigned for debug dump
+ */
+ edgetpu_free_coherent(etdev, &etdev->debug_dump_mem, EDGETPU_CONTEXT_KCI);
+ kfree(etdev->debug_dump_handlers);
+ platform_device_unregister(&sscd_dev);
+}
diff --git a/drivers/edgetpu/mobile-debug-dump.h b/drivers/edgetpu/mobile-debug-dump.h
index 0a9aef9..0ebd5f2 100644
--- a/drivers/edgetpu/mobile-debug-dump.h
+++ b/drivers/edgetpu/mobile-debug-dump.h
@@ -19,34 +19,7 @@ struct mobile_sscd_info {
struct mobile_sscd_mappings_dump {
u64 host_address;
u64 device_address;
- u64 alloc_iova;
u64 size;
};
-struct sscd_segment;
-
-/*
- * Collects the mapping information of all the host mapping and dmabuf mapping buffers of all
- * @groups as an array of struct mobile_sscd_mappings_dump and populates the @sscd_seg.
- *
- * 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.
- */
-struct mobile_sscd_mappings_dump *
-mobile_sscd_collect_mappings_segment(struct edgetpu_device_group **groups, size_t num_groups,
- struct sscd_segment *sscd_seg);
-
-/*
- * Collects the VII cmd and resp queues of all @groups that @etdev belongs to and the KCI cmd and
- * resp queues and populates them as @sscd_seg_arr elements.
- *
- * Returns the total number of queues collected since some queues may have been released for groups
- * with detached mailboxes. The return value is less than or equal to the total number of queues
- * expected based on @num_groups i.e. (2 * @num_groups +2).
- */
-size_t mobile_sscd_collect_cmd_resp_queues(struct edgetpu_dev *etdev,
- struct edgetpu_device_group **groups, size_t num_groups,
- struct sscd_segment *sscd_seg_arr);
-
#endif /* MOBILE_DEBUG_DUMP_H_ */