243 lines
5.9 KiB
C
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);
|
|
}
|