blob: 2c89aff007e4b6e0e51e4c5efbc3fa4216031c30 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Edge TPU ML accelerator telemetry: logging and tracing.
*
* Copyright (C) 2019-2020 Google, Inc.
*/
#ifndef __EDGETPU_TELEMETRY_H__
#define __EDGETPU_TELEMETRY_H__
#include <linux/eventfd.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include "edgetpu-internal.h"
#include "edgetpu-kci.h"
/* Log level codes used by edgetpu firmware */
#define EDGETPU_FW_LOG_LEVEL_VERBOSE (2)
#define EDGETPU_FW_LOG_LEVEL_DEBUG (1)
#define EDGETPU_FW_LOG_LEVEL_INFO (0)
#define EDGETPU_FW_LOG_LEVEL_WARN (-1)
#define EDGETPU_FW_LOG_LEVEL_ERROR (-2)
#define EDGETPU_FW_DMESG_LOG_LEVEL (EDGETPU_FW_LOG_LEVEL_ERROR)
/* Buffer size must be a power of 2 */
#define EDGETPU_TELEMETRY_LOG_BUFFER_SIZE (16 * 4096)
#define EDGETPU_TELEMETRY_TRACE_BUFFER_SIZE (64 * 4096)
enum edgetpu_telemetry_state {
EDGETPU_TELEMETRY_DISABLED = 0,
EDGETPU_TELEMETRY_ENABLED = 1,
EDGETPU_TELEMETRY_INVALID = -1,
};
/* To specify the target of operation. */
enum edgetpu_telemetry_type {
EDGETPU_TELEMETRY_LOG = 0,
EDGETPU_TELEMETRY_TRACE = 1,
};
struct edgetpu_telemetry_header {
u32 head;
u32 reserved0[15]; /* Place head and tail into different cache lines */
u32 tail;
u32 entries_dropped; /* Number of entries dropped due to buffer full */
u32 reserved1[14]; /* Pad to 128 bytes in total */
};
struct edgetpu_log_entry_header {
s16 code;
u16 length;
u64 timestamp;
u16 crc16;
} __packed;
struct edgetpu_telemetry {
struct edgetpu_dev *etdev;
/*
* State transitioning is to prevent racing in IRQ handlers. e.g. the
* interrupt comes when the kernel is releasing buffers.
*/
enum edgetpu_telemetry_state state;
spinlock_t state_lock; /* protects state */
struct edgetpu_coherent_mem coherent_mem;
struct edgetpu_telemetry_header *header;
/*
* If coherent_mem buffer is provided by the caller in
* edgetpu_telemetry_init, the caller is responsible for
* releasing/unmapping it.
*/
bool caller_mem;
struct eventfd_ctx *ctx; /* signal this to notify the runtime */
rwlock_t ctx_lock; /* protects ctx */
const char *name; /* for debugging */
bool inited; /* whether telemetry_init() succeeded */
/* Worker for handling data. */
struct work_struct work;
/* Fallback function to call for default log/trace handling. */
void (*fallback_fn)(struct edgetpu_telemetry *tel);
struct mutex mmap_lock; /* protects mmapped_count */
/* number of VMAs that are mapped to this telemetry buffer */
long mmapped_count;
};
struct edgetpu_telemetry_ctx {
struct edgetpu_telemetry log;
struct edgetpu_telemetry trace;
};
/*
* Allocates resources needed for @etdev->telemetry.
*
* Optionally provide arrays of etdev->num_cores coherent_mem buffers for log and trace.
* If any of these are NULL, they will be allocated and freed by telemetry code.
*
* Returns 0 on success, or a negative errno on error.
*/
int edgetpu_telemetry_init(struct edgetpu_dev *etdev,
struct edgetpu_coherent_mem *log_mem,
struct edgetpu_coherent_mem *trace_mem);
/*
* Disable the telemetry if enabled, release resources allocated in init().
*/
void edgetpu_telemetry_exit(struct edgetpu_dev *etdev);
/*
* Sends the KCI commands about telemetry buffers to the device.
*
* Returns the code of KCI response, or a negative errno on error.
*/
int edgetpu_telemetry_kci(struct edgetpu_dev *etdev);
/*
* Sets the eventfd to notify the runtime when an IRQ is sent from the device.
*
* Returns 0 on success, or a negative errno on error.
*/
int edgetpu_telemetry_set_event(struct edgetpu_dev *etdev,
enum edgetpu_telemetry_type type, u32 eventfd);
/* Removes previously set event. */
void edgetpu_telemetry_unset_event(struct edgetpu_dev *etdev,
enum edgetpu_telemetry_type type);
/* Checks telemetries and signals eventfd if needed. */
void edgetpu_telemetry_irq_handler(struct edgetpu_dev *etdev);
/* debugfs mappings dump */
void edgetpu_telemetry_mappings_show(struct edgetpu_dev *etdev,
struct seq_file *s);
/* Map telemetry buffer into user space. */
int edgetpu_mmap_telemetry_buffer(struct edgetpu_dev *etdev, enum edgetpu_telemetry_type type,
struct vm_area_struct *vma, int core_id);
void edgetpu_telemetry_inc_mmap_count(struct edgetpu_dev *etdev, enum edgetpu_telemetry_type type,
int core_id);
void edgetpu_telemetry_dec_mmap_count(struct edgetpu_dev *etdev, enum edgetpu_telemetry_type type,
int core_id);
#endif /* __EDGETPU_TELEMETRY_H__ */