diff options
author | Zuma copybara merger <zuma-automerger@google.com> | 2023-03-30 15:16:46 +0000 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-04-23 22:18:16 -0700 |
commit | e302a7688dcaf87fffbdb5bbd263de0bc20bbdd6 (patch) | |
tree | 7c0a575c4f487c11e6ddfeb7a6cc6778190469f5 /drivers/edgetpu/gcip-kernel-driver/include | |
parent | 0a2612e87f00b835d3aaafd2ed232ad9ab770bb4 (diff) | |
download | rio-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.h | 634 |
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__ */ |