summaryrefslogtreecommitdiff
path: root/drivers/edgetpu/gcip-kernel-driver/include
diff options
context:
space:
mode:
authorZuma copybara merger <zuma-automerger@google.com>2023-03-30 15:16:46 +0000
committerCopybara-Service <copybara-worker@google.com>2023-04-23 22:18:16 -0700
commite302a7688dcaf87fffbdb5bbd263de0bc20bbdd6 (patch)
tree7c0a575c4f487c11e6ddfeb7a6cc6778190469f5 /drivers/edgetpu/gcip-kernel-driver/include
parent0a2612e87f00b835d3aaafd2ed232ad9ab770bb4 (diff)
downloadrio-e302a7688dcaf87fffbdb5bbd263de0bc20bbdd6.tar.gz
[Copybara Auto Merge] Merge branch zuma into android14-gs-pixel-5.15
gcip: introduce gcip_usage_stats_max_watermark Bug: 276474775 gcip: introduce gcip_usage_stats_thread_stats Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_counter Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_component_utilization Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_core_usage Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_dvfs_frequency_info Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_ops Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_{header,metric} Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_attr Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_metric_type Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_max_watermark Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_thread_stats Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_counter Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_component_utilization Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_core_usage Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_dvfs_frequency_info Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_ops Bug: 276474775 (repeat) gcip: implement parsing metrics Bug: 276474775 (repeat) gcip: registers device attributes with default callbacks Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats_attr Bug: 276474775 (repeat) gcip: introduce gcip_usage_stats Bug: 276474775 (repeat) edgetpu: add error log for canceled operation due to fatal error edgetpu: unittests: enable ftrace events to increase the code coverage Bug: 277672895 Signed-off-by: Zuma copybara merger <zuma-automerger@google.com> GitOrigin-RevId: f1f8a0813ff35b8b5804780d1f69596f1746c3be Change-Id: Iadfbe95c38d99feab481ffd7bb6aa97110a78f01
Diffstat (limited to 'drivers/edgetpu/gcip-kernel-driver/include')
-rw-r--r--drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-usage-stats.h634
1 files changed, 634 insertions, 0 deletions
diff --git a/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-usage-stats.h b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-usage-stats.h
new file mode 100644
index 0000000..a20fe33
--- /dev/null
+++ b/drivers/edgetpu/gcip-kernel-driver/include/gcip/gcip-usage-stats.h
@@ -0,0 +1,634 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Interface of managing the usage stats of IPs.
+ *
+ * Copyright (C) 2023 Google LLC
+ */
+
+#ifndef __GCIP_USAGE_STATS_H__
+#define __GCIP_USAGE_STATS_H__
+
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/hashtable.h>
+#include <linux/mutex.h>
+#include <linux/stringify.h>
+#include <linux/types.h>
+
+/* Attribute read/write mode (permissions). */
+#define GCIP_USAGE_STATS_MODE_RO 0444
+#define GCIP_USAGE_STATS_MODE_WO 0200
+#define GCIP_USAGE_STATS_MODE_RW (GCIP_USAGE_STATS_MODE_RO | GCIP_USAGE_STATS_MODE_WO)
+
+/* Macros which generate `struct gcip_usage_stats_attr` instances easily. */
+#define GCIP_USAGE_STATS_ATTR(_metric, _type, _subcomponent, _name, _mode, _show, _store) \
+ struct gcip_usage_stats_attr gcip_usage_stats_attr_##_name = { \
+ .metric = _metric, \
+ .type = _type, \
+ .subcomponent = _subcomponent, \
+ .name = __stringify(_name), \
+ .mode = _mode, \
+ .show = _show, \
+ .store = _store, \
+ }
+
+#define GCIP_USAGE_STATS_ATTR_RW(metric, type, subcomponent, name, show, store) \
+ GCIP_USAGE_STATS_ATTR(metric, type, subcomponent, name, GCIP_USAGE_STATS_MODE_RW, show, \
+ store)
+
+#define GCIP_USAGE_STATS_ATTR_RO(metric, type, subcomponent, name, show) \
+ GCIP_USAGE_STATS_ATTR(metric, type, subcomponent, name, GCIP_USAGE_STATS_MODE_RO, show, \
+ NULL)
+
+#define GCIP_USAGE_STATS_ATTR_WO(metric, type, subcomponent, name, store) \
+ GCIP_USAGE_STATS_ATTR(metric, type, subcomponent, name, GCIP_USAGE_STATS_MODE_WO, NULL, \
+ store)
+
+/*
+ * Set a device attribute to show/store all subcomponents instead of one specific subcomponent.
+ * See @subcomponents field of `struct gcip_usage_stats_attr`.
+ */
+#define GCIP_USAGE_STATS_ATTR_ALL_SUBCOMPONENTS -1
+
+/*
+ * Size of the metric v1 in bytes.
+ *
+ * We decided to use 20 bytes for the V1 metrics. However, from V2, we increased the size of it to
+ * 24 bytes which is the same as `sizeof(struct gcip_usage_stats_metric)` to collect more stats
+ * information. To verify whether the firmware sent valid V1 size metrics, keep it as a macro.
+ */
+#define GCIP_USAGE_STATS_METRIC_SIZE_V1 20
+
+/* Max number of frequencies to support. */
+#define GCIP_USAGE_STATS_MAX_DVFS_FREQ_NUM 10
+
+struct gcip_usage_stats_attr;
+
+typedef ssize_t (*gcip_usage_stats_show_t)(struct device *dev, struct gcip_usage_stats_attr *attr,
+ char *buf, void *data);
+typedef ssize_t (*gcip_usage_stats_store_t)(struct device *dev, struct gcip_usage_stats_attr *attr,
+ const char *buf, size_t count, void *data);
+
+/*
+ * The version of metrics.
+ * The format of header or the size of metrics would be different from the versions. However,
+ * the metric implementation will be shared. See each metric implementation to know which fields
+ * can be accessed according to the versions.
+ */
+enum gcip_usage_stats_version {
+ /*
+ * In V1, the headers must have the format of the `struct gcip_usage_stats_header_v1` and
+ * the size of metrics must be GCIP_USAGE_STATS_METRIC_SIZE_V1.
+ */
+ GCIP_USAGE_STATS_V1 = 1,
+ /*
+ * In V2, the headers must have the format of the `struct gcip_usage_stats_header` and
+ * the size of metrics must be `sizeof(struct gcip_usage_stats_metric)`.
+ */
+ GCIP_USAGE_STATS_V2 = 2,
+ /* Version of metrics must be lower than this. */
+ GCIP_USAGE_STATS_VERSION_UPPER_BOUND,
+};
+
+/* Hash bits which will be used when initializing @ustats->core_usage_htable. */
+#define GCIP_USAGE_STATS_UID_HASH_BITS 3
+
+/* Must be kept in sync with firmware `enum class UsageTrackerMetric::Type`. */
+enum gcip_usage_stats_metric_type {
+ GCIP_USAGE_STATS_METRIC_TYPE_RESERVED,
+ GCIP_USAGE_STATS_METRIC_TYPE_CORE_USAGE,
+ GCIP_USAGE_STATS_METRIC_TYPE_COMPONENT_UTILIZATION,
+ GCIP_USAGE_STATS_METRIC_TYPE_COUNTER,
+ GCIP_USAGE_STATS_METRIC_TYPE_THREAD_STATS,
+ GCIP_USAGE_STATS_METRIC_TYPE_MAX_WATERMARK,
+ GCIP_USAGE_STATS_METRIC_TYPE_DVFS_FREQUENCY_INFO,
+};
+
+/*
+ * Encapsulates core usage information of a specific application.
+ * Must be kept in sync with firmware `struct CoreUsage`.
+ */
+struct gcip_usage_stats_core_usage {
+ /*
+ * The applications global identifier.
+ * This value IS NOT the virtual identifier assigned by the accelerator kernel driver,
+ * this is the user ID of the application assigned by Linux kernel.
+ */
+ int32_t uid;
+ /* The frequency (kHz) represented by this report. */
+ uint32_t operating_point;
+ /* Utilization time in microseconds (us). */
+ uint32_t control_core_duration;
+
+ /* Following fields must not be accessed in lower than V2. */
+
+ /*
+ * The compute core is represented by this metric on DSP.
+ * The TPU does not personalize core usages by DVFS and can expect this value to be 0 at
+ * all times. For DSP the value will be either 0, 1, or 2.
+ */
+ uint8_t core_id;
+ /* Reserved. */
+ uint8_t reserved[3];
+} __packed;
+
+/*
+ * Hash table entry which stores core usage per uid.
+ * It will be added to the hash table of its subcomponent, @ustats->core_usage_htable[], using @uid
+ * as the key and itself as the value.
+ */
+struct gcip_usage_stats_core_usage_uid_entry {
+ int32_t uid;
+ uint64_t time_in_state[GCIP_USAGE_STATS_MAX_DVFS_FREQ_NUM];
+ struct hlist_node node;
+};
+
+/*
+ * An enum to represent the different activity components we can track metrics for.
+ * Must be kept in sync with firmware `enum class Component`.
+ */
+enum gcip_usage_stats_component_utilization_type {
+ /* The entire IP Block. */
+ GCIP_USAGE_STATS_COMPONENT_UTILIZATION_IP,
+ /* A compute core. */
+ GCIP_USAGE_STATS_COMPONENT_UTILIZATION_CORES,
+
+ /* The number of total types. Must be located at the end of this enum. */
+ GCIP_USAGE_STATS_COMPONENT_UTILIZATION_NUM_TYPES,
+};
+
+/*
+ * Encapsulates information about utilization of a component.
+ * Must be kept in sync with firmware `struct ComponentActivity`.
+ */
+struct gcip_usage_stats_component_utilization {
+ /* Type of component. */
+ enum gcip_usage_stats_component_utilization_type component;
+ /*
+ * The percentage of time the component was active over the collection interval.
+ * This value is strictly between 0 and 100.
+ */
+ int32_t utilization;
+
+ /* Following fields must not be accessed in version 1. */
+
+ /* Reserved. */
+ uint32_t reserved[2];
+} __packed;
+
+/*
+ * Defines different counter types we track.
+ * Must be kept in sync with firmware `enum class CounterType`.
+ */
+enum gcip_usage_stats_counter_type {
+ /* Active TPU cycles. */
+ GCIP_USAGE_STATS_COUNTER_TPU_ACTIVIY_CYCLES,
+ /* The number of stalls caused by throttling. */
+ GCIP_USAGE_STATS_COUNTER_TPU_THROTTLE_STALLS,
+ /* Number of TPU inferences / DSP workloads. */
+ GCIP_USAGE_STATS_COUNTER_WORKLOAD,
+ /* Number of TPU offload op invocations. */
+ GCIP_USAGE_STATS_COUNTER_TPU_OP,
+ /* Number of times a TPU op invocation used its cache parameters. */
+ GCIP_USAGE_STATS_COUNTER_PARAM_CACHING_HIT,
+ /* Number of times a TPU op invocation had to cache its parameters. */
+ GCIP_USAGE_STATS_COUNTER_PARAM_CACHING_MISS,
+ /*
+ * Number of times preemptions (either software or hardware) occurred between different
+ * clients.
+ * - Hardware preemption: The preemption which occurs between QoS classes. E.g., Realtime
+ * QoS class has a higher priority than Best-Effort QoS class. In
+ * this case, the current workload will be stopped at the next
+ * scalar fence, saved and will be restored after the new higher
+ * priority workload is completed.
+ * - Software preemption: The preemption which occurs between workloads with the same QoS
+ * class, but different priorities. The on-going workload is allowed
+ * to be completed before the higher priority one begins to execute.
+ * In the case of TPU, one TPU offload operation can be cut into
+ * multiple chunks (workloads) and it allows the higher priority
+ * offload to have the chance to preempt after the current chunk is
+ * processed.
+ */
+ GCIP_USAGE_STATS_COUNTER_CONTEXT_PREEMPTIONS,
+ /* Number of times hardware preemptions occurred. */
+ GCIP_USAGE_STATS_COUNTER_HW_PREEMPTIONS,
+ /*
+ * The total time in microseconds spent saving a hardware context during hardware
+ * preemption.
+ */
+ GCIP_USAGE_STATS_COUNTER_TOTAL_HW_CONTEXT_SAVE_TIME,
+ /* The total time in microseconds spent waiting to hit a scalar fence. */
+ GCIP_USAGE_STATS_COUNTER_TOTAL_SCALAR_FENCE_WAIT_TIME,
+ /* The number of times the Pipeline::Suspend function takes longer than SLA time. */
+ GCIP_USAGE_STATS_COUNTER_NUM_OF_LONG_SUSPENDS,
+ /* The number of times a compute core experienced a context switch. */
+ GCIP_USAGE_STATS_COUNTER_CONTEXT_SWITCHES,
+ /* The number of times a TPU cluster reconfiguration occurred. */
+ GCIP_USAGE_STATS_COUNTER_NUM_OF_RECONFIGURATIONS,
+ /*
+ * The number of times a TPU cluster reconfiguration occurred and was strictly motivated by
+ * a preemption.
+ */
+ GCIP_USAGE_STATS_COUNTER_NUM_OF_RECONFIGURATIONS_BY_PREEMPTION,
+
+ /* The number of total types. Must be located at the end of this enum. */
+ GCIP_USAGE_STATS_COUNTER_NUM_TYPES,
+};
+
+/*
+ * Generic counter. Only reported if it has a value larger than 0.
+ * Must be kept in sync with firmware `struct Counter`.
+ */
+struct gcip_usage_stats_counter {
+ /* What it counts. */
+ enum gcip_usage_stats_counter_type type;
+ /* Accumulated value since last initialization. */
+ uint64_t value;
+
+ /* Following fields must not be accessed in version 1. */
+
+ /* An identifier that personalizes the represented hardware for counters. */
+ uint8_t component_id;
+ /* Reserved. */
+ uint8_t reserved[3];
+} __packed;
+
+/*
+ * An enum to identify the tracked firmware threads.
+ * Must be kept in sync with firmware `enum class UsageTrackerThreadId`.
+ */
+enum gcip_usage_stats_thread_stats_thread_id {
+ /* The entry thread for the firmware. */
+ GCIP_USAGE_STATS_THREAD_MAIN_TASK,
+ /*
+ * The thread that processes commands from the kernel and sends commands reversely in some
+ * cases, e.g., firmware crashes.
+ */
+ GCIP_USAGE_STATS_THREAD_KCI_HANDLER,
+ /* The thread that determines the commanded power state of the system. */
+ GCIP_USAGE_STATS_THREAD_POWER_ADMINISTRATOR,
+ /* The thread responsible for coordinating and dispatching workloads. */
+ GCIP_USAGE_STATS_THREAD_SCHEDULER,
+ /* The thread that handles VII commands from TPU clients. */
+ GCIP_USAGE_STATS_THREAD_VII_HANDLER,
+ /*
+ * The multi-core coordination thread that shares complex assignments with other TPU cores.
+ */
+ GCIP_USAGE_STATS_THREAD_MCP_GRAPH_DRIVER,
+ /* The single-core coordination thread that handles local-only graphs. */
+ GCIP_USAGE_STATS_THREAD_SCP_GRAPH_DRIVER,
+ /* The thread that coordinates the progress of scalar and tile TPU workloads. */
+ GCIP_USAGE_STATS_THREAD_TPU_DRIVER,
+ /* Orchestrates restarting client threads when there is a fatal error in the pipeline. */
+ GCIP_USAGE_STATS_THREAD_RESTART_HANDLER,
+ /* Used for polling some state but not blocking other threads from execution. */
+ GCIP_USAGE_STATS_THREAD_POLL_SERVICE,
+ /* Schedules DMAs on the main DMA engine. */
+ GCIP_USAGE_STATS_THREAD_DMA_DRIVER,
+ /* Used for driving AES DMA for random number generation. */
+ GCIP_USAGE_STATS_THREAD_GRAPH_DMA_DRIVER,
+ /*
+ * The multi-cluster scheduler, this dispatches complex workloads to the major and minor
+ * TPU clusters.
+ */
+ GCIP_USAGE_STATS_THREAD_MC_SCHEDULER,
+ /*
+ * The single-cluster scheduler that dispatches workloads to only a single TPU cluster at
+ * a time.
+ */
+ GCIP_USAGE_STATS_THREAD_SC_SCHEDULER,
+ /*
+ * The thread that dispatches scheduled workloads from the DSP control core directly to the
+ * DSP cores.
+ */
+ GCIP_USAGE_STATS_THREAD_DSP_CORE_MANAGER,
+
+ /* The number of total threads. Must be located at the end of this enum. */
+ GCIP_USAGE_STATS_THREAD_NUM_TYPES,
+};
+
+/*
+ * Statistics related to a single thread in firmware.
+ * Must be kept in sync with firmware `struct ThreadStats`.
+ */
+struct gcip_usage_stats_thread_stats {
+ /* The thread in question. */
+ enum gcip_usage_stats_thread_stats_thread_id thread_id;
+ /* Maximum stack usage (in bytes) since last firmware boot. */
+ uint32_t max_stack_usage_bytes;
+
+ /* Following fields must not be accessed in version 1. */
+
+ /* Reserved. */
+ uint32_t reserved[2];
+} __packed;
+
+/*
+ * Defines different max watermarks we track.
+ * Must be kept in sync with firmware `enum class MaxWatermarkType`.
+ */
+enum gcip_usage_stats_max_watermark_type {
+ /* The number of UCI/VII commands dequeued and not yet responded to. */
+ GCIP_USAGE_STATS_MAX_WATERMARK_OUTSTANDING_CMDS,
+ /* The maximum number of outstanding preempted workloads that must be resumed. */
+ GCIP_USAGE_STATS_MAX_WATERMARK_PREEMPTION_DEPTH,
+ /*
+ * The longest time in microseconds required to save a cluster-context so that another
+ * client can run on the same cluster.
+ */
+ GCIP_USAGE_STATS_MAX_WATERMARK_MAX_HW_CONTEXT_SAVE_TIME,
+ /*
+ * Maximum time in microseconds spent waiting to hit a scalar fence during hardware
+ * preemption.
+ */
+ GCIP_USAGE_STATS_MAX_WATERMARK_MAX_SCALAR_FENCE_WAIT_TIME,
+ /* Maximum time in microseconds spent during the Pipeline::Suspend function. */
+ GCIP_USAGE_STATS_MAX_WATERMARK_MAX_SUSPEND_TIME,
+
+ /* The number of total types. Must be located at the end of this enum. */
+ GCIP_USAGE_STATS_MAX_WATERMARK_NUM_TYPES,
+};
+
+/*
+ * Max watermark. Only reported if it has a value larger than 0.
+ * Must be kept in sync with firmware `struct MaxWatermark`.
+ */
+struct gcip_usage_stats_max_watermark {
+ /* What it counts. */
+ enum gcip_usage_stats_max_watermark_type type;
+ /* Maximum expressed value over the collection interval. */
+ uint64_t value;
+
+ /* Following fields must not be accessed in version 1. */
+
+ /* Reporting component. */
+ uint8_t component_id;
+ /* Reserved. */
+ uint8_t reserved[3];
+} __packed;
+
+/*
+ * Used to report DVFS frequencies supported by the chip.
+ * Must be kept in sync with firmware `struct DvfsFrequencyInfo`.
+ */
+struct gcip_usage_stats_dvfs_frequency_info {
+ /* An actively supported DVFS Frequency (kHz). */
+ uint32_t supported_frequency;
+
+ /* Following fields must not be accessed in lower than V2. */
+
+ /* Reserved. */
+ uint32_t reserved[3];
+} __packed;
+
+/*
+ * Header struct in the v1 metric buffer.
+ * Keep this structure for the compatibility.
+ */
+struct gcip_usage_stats_header_v1 {
+ /* Number of metrics being reported. */
+ uint32_t num_metrics;
+ /* Size of each metric struct. */
+ uint32_t metric_size;
+};
+
+/*
+ * Header struct in the metric buffer.
+ * Must be kept in sync with firmware `struct UsageTrackerHeader`.
+ */
+struct gcip_usage_stats_header {
+ /* Number of bytes in this header. */
+ uint16_t header_bytes;
+ /* Metrics version. */
+ uint16_t version;
+ /* Number of metrics being reported. */
+ uint32_t num_metrics;
+ /* Size of each metric struct. */
+ uint32_t metric_size;
+};
+
+/*
+ * Encapsulates a single metric reported to the kernel driver.
+ * Must be kept in sync with firmware `struct UsageTrackerMetric`.
+ */
+struct gcip_usage_stats_metric {
+ uint32_t type;
+ uint8_t reserved[4];
+ union {
+ struct gcip_usage_stats_core_usage core_usage;
+ struct gcip_usage_stats_component_utilization component_utilization;
+ struct gcip_usage_stats_counter counter;
+ struct gcip_usage_stats_thread_stats thread_stats;
+ struct gcip_usage_stats_max_watermark max_watermark;
+ struct gcip_usage_stats_dvfs_frequency_info dvfs_frequency_info;
+ /* The implementation of each metric must fit to 16 bytes. */
+ uint8_t impl_reserved[16];
+ };
+} __packed;
+
+/* Operators which are needed while processing usage stats data. */
+struct gcip_usage_stats_ops {
+ /*
+ * The callback which sends `GET_USAGE` KCI to get the latest usage stats from the firmware
+ * synchronously and calls `gcip_usage_stats_process_buffer` function to process them.
+ *
+ * This callback is required and will be called when the user tries to read device
+ * statistics.
+ *
+ * Returns KCI response code on success or < 0 on error (typically -ETIMEDOUT).
+ */
+ int (*update_usage_kci)(void *data);
+
+ /*
+ * Returns the number of default DVFS frequencies.
+ * If the firmware has never sent `DVFS_FREQUENCY_INFO` metrics, it will use the default
+ * frequencies which are maintained by the kernel driver.
+ */
+ int (*get_default_dvfs_freqs_num)(void *data);
+
+ /*
+ * Returns the DVFS frequency of @idx.
+ * @idx will not exceed the number of default DVFS frequencies which is returned by the
+ * `get_default_dvfs_freqs_num` operator.
+ */
+ int (*get_default_dvfs_freq)(int idx, void *data);
+};
+
+/* Structure manages the information of usage stats and device attributes. */
+struct gcip_usage_stats {
+ /* The version of metrics. */
+ enum gcip_usage_stats_version version;
+ /* The number of subcomponents. (e.g., TPU: clusters, DSP: cores) */
+ unsigned int subcomponents;
+ /* The device to register attributes. */
+ struct device *dev;
+ /* User-data. */
+ void *data;
+
+ /* Pointer array of attributes which will be registered to the device. */
+ struct attribute **attrs;
+ /* Attribute group which will contain @attrs. */
+ struct attribute_group group;
+
+ /* Operators. */
+ const struct gcip_usage_stats_ops *ops;
+
+ /*
+ * Core usage (per subcomponent).
+ * Stores stats as an UID to `struct gcip_usage_stats_core_usage_uid_entry` hash table.
+ * Declare it as a pointer to an array because we have to dynamically allocate multiple
+ * rows with the fixed column size.
+ * I.e., (@subcomponents (rows) * BIT(GCIP_USAGE_STATS_UID_HASH_BITS) (cols)) 2d array.
+ */
+ struct hlist_head (*core_usage_htable)[BIT(GCIP_USAGE_STATS_UID_HASH_BITS)];
+ /* Component utilization. */
+ int32_t component_utilization[GCIP_USAGE_STATS_COMPONENT_UTILIZATION_NUM_TYPES];
+ /*
+ * Counter (per subcomponents).
+ * Declare it as a pointer to an array because we have to dynamically allocate multiple
+ * rows with the fixed column size.
+ * I.e., (@subcomponents (rows) * GCIP_USAGE_STATS_COUNTER_NUM_TYPES (cols)) 2d array.
+ */
+ int64_t (*counter)[GCIP_USAGE_STATS_COUNTER_NUM_TYPES];
+ /* Thread statistics. */
+ int32_t thread_max_stack_usage[GCIP_USAGE_STATS_THREAD_NUM_TYPES];
+ /*
+ * Max watermark (per subcomponents).
+ * Declare it as a pointer to an array because we have to dynamically allocate multiple
+ * rows with the fixed column size.
+ * I.e., (@subcomponents (rows) * GCIP_USAGE_STATS_MAX_WATERMARK_NUM_TYPES (cols)) 2d
+ * array.
+ */
+ int64_t (*max_watermark)[GCIP_USAGE_STATS_MAX_WATERMARK_NUM_TYPES];
+ /* Protects the statistics above. */
+ struct mutex usage_stats_lock;
+
+ /*
+ * DVFS frequencies that the firmware returns via `DVFS_FREQUENCY_INFO` metric.
+ * If the firmware has sent `DVFS_FREQUENCY_INFO` metric, it will be used instead of
+ * getting the default ones from the kernel driver side via @get_default_dvfs_freq callback
+ * of the `struct gcip_usage_stats_ops`.
+ */
+ uint32_t dvfs_freqs[GCIP_USAGE_STATS_MAX_DVFS_FREQ_NUM];
+ /* The number of DVFS frequencies. */
+ int dvfs_freqs_num;
+ /* Protects DVFS frequencies. */
+ struct mutex dvfs_freqs_lock;
+};
+
+/*
+ * Structure which contains information of an attribute to be registered to the device.
+ * One can directly create an instance, but it is recommneded to use `GCIP_USAGE_STATS_ATTR_*`
+ * macros instead. A pointer array of this attributes must be passed to the @attrs of
+ * `struct gcip_usage_stats_args`.
+ */
+struct gcip_usage_stats_attr {
+ /* The metric to be collected. */
+ enum gcip_usage_stats_metric_type metric;
+ /*
+ * The sub-type of @metric to be collected.
+ * - COMPONENT_UTILIZATION: enum gcip_usage_stats_component_utilization_type
+ * - COUNTER: enum gcip_usage_stats_counter_type
+ * - MAX_WATERMARK: enum gcip_usage_stats_max_watermark_type
+ */
+ unsigned int type;
+ /*
+ * The 0-based index of subcomponent. (Ignored in V1 metrics.)
+ *
+ * One can specify the subcomponent to be read if there are multiple subcomponents.
+ *
+ * If this value is `GCIP_USAGE_STATS_ATTR_ALL_SUBCOMPONENTS`, its show or store function
+ * will involve in all subcomponents. In case of show, it will print statistics of all
+ * subcomponents in an array with whitespace separation. Note that according to the Linux
+ * documentation, one value per one attribute is a rule, but printing multiple same types
+ * in an array is acceptable. Therefore, use this way only when the printing format is
+ * simple. In case of store, it will update statistic values (mostly reset to 0) of all
+ * subcomponents.
+ *
+ * Note: when the metric is `CORE_USAGE`, using `GCIP_USAGE_STATS_ATTR_ALL_SUBCOMPONENTS`
+ * is invalid because its printing format is too complicated to print multiple
+ * subcomponents in one attribute.
+ */
+ int subcomponent;
+ /* The name of the attribute. */
+ const char *name;
+ /* Permission. It must be one of `GCIP_USAGE_STATS_MODE_*`. */
+ umode_t mode;
+ /*
+ * User-defined show callback.
+ *
+ * Mostly, one will set it as NULL to use the GCIP implementation.
+ * See the `gcip_usage_stats_alloc_attrs` function to find which function will be used for
+ * the show function according to the type of metric.
+ *
+ * However, if a customized show function is needed, one can pass its own function to this.
+ *
+ * It will be used only when @mode has the read permission.
+ */
+ gcip_usage_stats_show_t show;
+
+ /*
+ * User-defined store callback.
+ *
+ * Mostly, one will set it as NULL to use the GCIP implementation.
+ * See the `gcip_usage_stats_alloc_attrs` function to find which function will be used for
+ * the store function according to the type of metric.
+ *
+ * However, if a customized store function is needed, one can pass its own function to
+ * this.
+ *
+ * It will be used only when @mode has the write permission.
+ */
+ gcip_usage_stats_store_t store;
+
+ /* Following fields must not be touched by the caller. */
+ struct device_attribute dev_attr;
+ struct gcip_usage_stats *ustats;
+};
+
+/*
+ * Arguments for `gcip_usage_stats_init`.
+ *
+ * `struct gcip_usage_stats` instance will be initialized according to this.
+ */
+struct gcip_usage_stats_args {
+ /* The version of metrics. */
+ enum gcip_usage_stats_version version;
+ /*
+ * The number of subcomponents. (e.g., TPU: clusters, DSP: cores)
+ * Must be bigger than 0.
+ */
+ unsigned int subcomponents;
+ /* The device to register attributes. */
+ struct device *dev;
+ /* User-data. */
+ void *data;
+ /*
+ * Pointer array of attributes.
+ * This must not be freed before the `gcip_usage_stats_exit` is called.
+ */
+ struct gcip_usage_stats_attr **attrs;
+ /* The size of @attrs. */
+ unsigned int num_attrs;
+ /*
+ * Operators.
+ * See `struct gcip_usage_stats_ops` for the details.
+ */
+ const struct gcip_usage_stats_ops *ops;
+};
+
+/*
+ * Initializes @ustats.
+ *
+ * @ustats must be cleaned up with the `gcip_usage_stats_exit` function.
+ */
+int gcip_usage_stats_init(struct gcip_usage_stats *ustats,
+ const struct gcip_usage_stats_args *args);
+
+/* Cleans up @ustats which is initialized by the `gcip_usage_stats_init` function. */
+void gcip_usage_stats_exit(struct gcip_usage_stats *ustats);
+
+/* Processes the buffer which is returned by the firmware via `GET_USAGE` KCI. */
+void gcip_usage_stats_process_buffer(struct gcip_usage_stats *ustats, void *buf);
+
+#endif /* __GCIP_USAGE_STATS_H__ */