blob: 3836e85a2959cf9e0df47b4297281ccbd950323d [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Module that defines structures and functions to retrieve debug dump segments
* from edgetpu firmware.
*
* Copyright (C) 2020 Google, Inc.
*/
#include <linux/workqueue.h>
#include "edgetpu-config.h"
#include "edgetpu-debug-dump.h"
#include "edgetpu-device-group.h"
#include "edgetpu-iremap-pool.h"
#include "edgetpu-kci.h"
int edgetpu_get_debug_dump(struct edgetpu_dev *etdev, u64 type)
{
int ret;
struct edgetpu_debug_dump_setup *dump_setup;
if (!etdev->debug_dump_mem.vaddr) {
etdev_err(etdev, "Debug dump not allocated");
return -EINVAL;
}
dump_setup =
(struct edgetpu_debug_dump_setup *)etdev->debug_dump_mem.vaddr;
dump_setup->type = type;
/* Signal the type of dump and buffer address to firmware */
ret = edgetpu_kci_get_debug_dump(etdev->kci,
etdev->debug_dump_mem.tpu_addr,
etdev->debug_dump_mem.size);
etdev_dbg(etdev, "Sent debug dump request, tpu addr: %llx",
(u64)etdev->debug_dump_mem.tpu_addr);
if (ret)
etdev_err(etdev, "KCI dump info req failed: %d", ret);
return ret;
}
static void edgetpu_reset_debug_dump(struct edgetpu_dev *etdev)
{
memset(etdev->debug_dump_mem.vaddr, 0, etdev->debug_dump_mem.size);
}
static void edgetpu_debug_dump_work(struct work_struct *work)
{
struct edgetpu_dev *etdev;
struct edgetpu_debug_dump_setup *dump_setup;
struct edgetpu_debug_dump *debug_dump;
int ret;
u64 dump_reason;
etdev = container_of(work, struct edgetpu_dev, debug_dump_work);
dump_setup =
(struct edgetpu_debug_dump_setup *)etdev->debug_dump_mem.vaddr;
debug_dump = (struct edgetpu_debug_dump *)(dump_setup + 1);
if (!etdev->debug_dump_handlers) {
etdev_err(etdev, "Failed to generate coredump as handler is NULL");
edgetpu_reset_debug_dump(etdev);
return;
}
dump_reason = debug_dump->dump_reason;
if (dump_reason >= DUMP_REASON_NUM ||
!etdev->debug_dump_handlers[dump_reason]) {
etdev_err(etdev,
"Failed to generate coredump as handler is NULL for dump request reason: %#llx",
dump_reason);
edgetpu_reset_debug_dump(etdev);
return;
}
ret = etdev->debug_dump_handlers[dump_reason]((void *)etdev, (void *)dump_setup);
if (ret)
etdev_err(etdev, "Failed to generate coredump: %d\n", ret);
edgetpu_reset_debug_dump(etdev);
}
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");
return;
}
dump_setup =
(struct edgetpu_debug_dump_setup *)etdev->debug_dump_mem.vaddr;
debug_dump = (struct edgetpu_debug_dump *)(dump_setup + 1);
if (!debug_dump->host_dump_available_to_read)
return;
debug_dump->host_dump_available_to_read = false;
if (!etdev->debug_dump_work.func)
INIT_WORK(&etdev->debug_dump_work, edgetpu_debug_dump_work);
schedule_work(&etdev->debug_dump_work);
}