blob: 3732fbb2e02e91b2d66ae02b7524f9fc52b3ba35 [file] [log] [blame] [edit]
// SPDX-License-Identifier: GPL-2.0
/*
* Implements methods common to the family of EdgeTPUs for mobile devices to retrieve host side
* debug dump segments and report them to SSCD.
*
* Copyright (C) 2021 Google, Inc.
*/
#include <linux/mutex.h>
#include <linux/platform_data/sscoredump.h>
#include <linux/rbtree.h>
#include <linux/slab.h>
#include "edgetpu-device-group.h"
#include "edgetpu-mailbox.h"
#include "mobile-debug-dump.h"
#include "edgetpu-debug-dump.c"
struct mobile_sscd_mappings_dump *
mobile_sscd_collect_mappings_segment(struct edgetpu_device_group **groups, size_t num_groups,
struct sscd_segment *sscd_seg)
{
struct mobile_sscd_mappings_dump *mappings_dump;
struct edgetpu_mapping_root *mappings;
struct rb_node *node;
void *resized_arr;
size_t idx = 0, mappings_num = 0, new_size = 0;
mappings_dump = kmalloc(sizeof(struct mobile_sscd_mappings_dump), GFP_KERNEL);
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);
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]->host_mappings;
for (node = rb_first(&mappings->rb); node; node = rb_next(node)) {
struct edgetpu_mapping *map =
container_of(node, struct edgetpu_mapping, node);
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_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 =
container_of(node, struct edgetpu_mapping, node);
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_num++;
}
mutex_unlock(&groups[idx]->lock);
}
sscd_seg->addr = mappings_dump;
sscd_seg->size = new_size;
sscd_seg->vaddr = mappings_dump;
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)
{
struct edgetpu_kci *kci;
size_t idx;
u16 num_queues = 0;
// 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;
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;
sscd_seg_arr[num_queues].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;
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;
sscd_seg_arr[num_queues].vaddr =
(void *)groups[idx]->vii.resp_queue_mem.vaddr;
num_queues++;
}
mutex_unlock(&groups[idx]->lock);
}
// 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);
sscd_seg_arr[num_queues].paddr = (void *)kci->cmd_queue_mem.tpu_addr;
sscd_seg_arr[num_queues].vaddr = (void *)kci->cmd_queue_mem.vaddr;
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].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;
}