Files
CoolPi-Armbian-Rockchip-RK3…/drivers/gpu/arm/bifrost/csf/mali_kbase_csf_util.c
2025-02-04 12:41:12 -06:00

243 lines
5.9 KiB
C

// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
/*
*
* (C) COPYRIGHT 2023-2024 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)) {
vfree(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 = vscnprintf(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);
}