diff options
Diffstat (limited to 'mali_kbase/csf/mali_kbase_csf_util.c')
-rw-r--r-- | mali_kbase/csf/mali_kbase_csf_util.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/mali_kbase/csf/mali_kbase_csf_util.c b/mali_kbase/csf/mali_kbase_csf_util.c new file mode 100644 index 0000000..7dc32a1 --- /dev/null +++ b/mali_kbase/csf/mali_kbase_csf_util.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note +/* + * + * (C) COPYRIGHT 2023 ARM Limited. All rights reserved. + * + * This program is free software and is provided to you under the terms of the + * GNU General Public License version 2 as published by the Free Software + * Foundation, and any use by you of this program is subject to the terms + * of such GNU license. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can access it online at + * http://www.gnu.org/licenses/gpl-2.0.html. + * + */ + +#include "mali_kbase_csf_util.h" +#include <mali_kbase.h> +#include <linux/kfifo.h> +#include <linux/printk.h> +#include <linux/seq_file.h> +#include <linux/version_compat_defs.h> +#include <linux/vmalloc.h> + +#define KBASEP_PRINTER_BUFFER_MAX_SIZE (2 * PAGE_SIZE) + +#define KBASEP_PRINT_FORMAT_BUFFER_MAX_SIZE 256 + +/** + * struct kbasep_printer - Object representing a logical printer device. + * + * @type: The print output type. + * @fifo: address of the fifo to be used. + * @kbdev: The kbase device. + * @file: The seq_file for printing to. This is NULL if printing to dmesg. + */ +struct kbasep_printer { + enum kbasep_printer_type type; + struct kbase_device *kbdev; + struct seq_file *file; + DECLARE_KFIFO_PTR(fifo, char); +}; + +/** + * kbasep_printer_alloc() - Allocate a kbasep_printer instance. + * + * @type: The type of kbasep_printer to be allocated. + * + * Return: The kbasep_printer instance pointer or NULL on error. + */ +static inline struct kbasep_printer *kbasep_printer_alloc(enum kbasep_printer_type type) +{ + struct kbasep_printer *kbpr = NULL; + + if (type == KBASEP_PRINT_TYPE_INVALID || type >= KBASEP_PRINT_TYPE_CNT) { + pr_err("printer type not supported"); + return NULL; + } + + kbpr = vzalloc(sizeof(struct kbasep_printer)); + if (kbpr) { + kbpr->type = type; + kbpr->file = NULL; + } + + return kbpr; +} + +/** + * kbasep_printer_validate() - Validate kbasep_printer instance. + * + * @kbpr: The kbasep_printer instance to be validated. + * + * Return: true if the instance is correctly configured else false. + */ +static inline bool kbasep_printer_validate(const struct kbasep_printer *kbpr) +{ + if (!kbpr || kbpr->type == KBASEP_PRINT_TYPE_INVALID || kbpr->type >= KBASEP_PRINT_TYPE_CNT) + return false; + + switch (kbpr->type) { + case KBASEP_PRINT_TYPE_DEV_INFO: + case KBASEP_PRINT_TYPE_DEV_WARN: + case KBASEP_PRINT_TYPE_DEV_ERR: + if (kbpr->kbdev == NULL || !kfifo_initialized(&kbpr->fifo)) + return false; + break; + case KBASEP_PRINT_TYPE_SEQ_FILE: + if (kbpr->file == NULL) + return false; + break; + default: + return false; + } + + return true; +} + +struct kbasep_printer *kbasep_printer_buffer_init(struct kbase_device *kbdev, + enum kbasep_printer_type type) +{ + struct kbasep_printer *kbpr = NULL; + + if (WARN_ON_ONCE((kbdev == NULL || !(type == KBASEP_PRINT_TYPE_DEV_INFO || + type == KBASEP_PRINT_TYPE_DEV_WARN || + type == KBASEP_PRINT_TYPE_DEV_ERR)))) + return NULL; + + kbpr = kbasep_printer_alloc(type); + + if (kbpr) { + if (kfifo_alloc(&kbpr->fifo, KBASEP_PRINTER_BUFFER_MAX_SIZE, GFP_KERNEL)) { + kfree(kbpr); + return NULL; + } + kbpr->kbdev = kbdev; + } + + return kbpr; +} + +struct kbasep_printer *kbasep_printer_file_init(struct seq_file *file) +{ + struct kbasep_printer *kbpr = NULL; + + if (WARN_ON_ONCE(file == NULL)) + return NULL; + + kbpr = kbasep_printer_alloc(KBASEP_PRINT_TYPE_SEQ_FILE); + + if (kbpr) + kbpr->file = file; + + return kbpr; +} + +void kbasep_printer_term(struct kbasep_printer *kbpr) +{ + if (kbpr) { + if (kfifo_initialized(&kbpr->fifo)) + kfifo_free(&kbpr->fifo); + vfree(kbpr); + } +} + +void kbasep_printer_buffer_flush(struct kbasep_printer *kbpr) +{ + char buffer[KBASEP_PRINT_FORMAT_BUFFER_MAX_SIZE]; + unsigned int i; + + if (WARN_ON_ONCE(!kbasep_printer_validate(kbpr))) + return; + + if (kfifo_is_empty(&kbpr->fifo)) + return; + + while (!kfifo_is_empty(&kbpr->fifo)) { + /* copy elements to fill the local string buffer */ + size_t copied = kfifo_out_peek(&kbpr->fifo, buffer, + KBASEP_PRINT_FORMAT_BUFFER_MAX_SIZE - 1); + buffer[copied] = '\0'; + /* pop all fifo copied elements until the first new-line char or + * the last copied element + */ + for (i = 0; i < copied; i++) { + kfifo_skip(&kbpr->fifo); + if (buffer[i] == '\n') { + buffer[i + 1] = '\0'; + break; + } + } + + switch (kbpr->type) { + case KBASEP_PRINT_TYPE_DEV_INFO: + dev_info(kbpr->kbdev->dev, buffer); + break; + case KBASEP_PRINT_TYPE_DEV_WARN: + dev_warn(kbpr->kbdev->dev, buffer); + break; + case KBASEP_PRINT_TYPE_DEV_ERR: + dev_err(kbpr->kbdev->dev, buffer); + break; + default: + pr_err("printer not supported"); + } + } +} + +void kbasep_puts(struct kbasep_printer *kbpr, const char *str) +{ + int len = 0; + + if (WARN_ON_ONCE(!kbasep_printer_validate(kbpr))) { + pr_warn("%s", str); + return; + } + + switch (kbpr->type) { + case KBASEP_PRINT_TYPE_DEV_INFO: + case KBASEP_PRINT_TYPE_DEV_WARN: + case KBASEP_PRINT_TYPE_DEV_ERR: + len = strlen(str); + if (len <= kfifo_avail(&kbpr->fifo)) + kfifo_in(&kbpr->fifo, str, len); + break; + case KBASEP_PRINT_TYPE_SEQ_FILE: + seq_printf(kbpr->file, str); + break; + default: + pr_err("printer not supported"); + } +} + +__attribute__((format(__printf__, 2, 3))) void kbasep_print(struct kbasep_printer *kbpr, + const char *fmt, ...) +{ + int len = 0; + char buffer[KBASEP_PRINT_FORMAT_BUFFER_MAX_SIZE]; + va_list arglist; + + va_start(arglist, fmt); + len = vsnprintf(buffer, KBASEP_PRINT_FORMAT_BUFFER_MAX_SIZE, fmt, arglist); + if (len <= 0) { + pr_err("message write to the buffer failed"); + goto exit; + } + + if (WARN_ON_ONCE(!kbasep_printer_validate(kbpr))) + pr_warn("%s", buffer); + + if (kbpr->type == KBASEP_PRINT_TYPE_SEQ_FILE) + seq_printf(kbpr->file, buffer); + else if (len <= kfifo_avail(&kbpr->fifo)) + kfifo_in(&kbpr->fifo, buffer, len); +exit: + va_end(arglist); +} |