Files
BPI-CM9-Linux/aml-comp/uboot/bl33/v2023/drivers/amlogic/log/ring_buffer.c
T

470 lines
10 KiB
C

/* * Ring buffer for BL30 log share to kernel
* Copyright (C) 2021-2022 amlogic
*
*/
#include <common.h>
#include <asm/amlogic/arch/cpu_config.h>
#include <asm/amlogic/arch/register.h>
#include "ring_buffer.h"
#define LOCK 1
static int blx_ready;
static struct ring_buffer *g_rb;
/*log message timer*/
#define LOG_MSG_TIMER SYSCTRL_TIMERE
static void Lock_EnterCritical(void)
{
//taskENTER_CRITICAL();
}
static void Lock_ExitCritical(void)
{
//taskEXIT_CRITICAL();
}
static int amp_lock_init(amp_lock *lock)
{
//memset(lock,0,sizeof(amp_lock));
lock->turn = 0;
lock->req[0] = 0;
lock->req[1] = 0;
return 0;
}
int amp_lock_obtain(amp_lock *lock, int self)
{
#if LOCK
int other = 1 - self;
// disable interrupt here
Lock_EnterCritical();
lock->req[self] = 1;
if (lock->req[other]) {
lock->req[self] = 0;
while (lock->turn != self)
;
lock->req[self] = 1;
while (lock->req[other])
;
}
#endif
return 0;
}
int amp_lock_release(amp_lock *lock, int self)
{
#if LOCK
int other = 1 - self;
lock->turn = other;
lock->req[self] = 0;
// enable interrupt here
Lock_ExitCritical();
#endif
return 0;
}
//int lock(void)
//{
// return 0;
//}
//int unlock(void)
//{
// return 0;
//}
static struct ring_buffer *init_ring_buffer(unsigned char *buffer, unsigned int size)
{
struct ring_buffer *b = (struct ring_buffer *)buffer;
if (!b || size < sizeof(struct ring_buffer))
return NULL;
if (b->magic == MAGIC)
return b;
b->magic = MAGIC;
b->inited = UBOOT_LOG_INITFLAG;
b->ver = UBOOT_LOG_VER;
b->size = size - sizeof(struct ring_buffer) + 4;
b->head = 0;
b->tail = 0;
b->len = 0;
b->len_b = 0;
b->mode = 0;
amp_lock_init(&b->lock);
return b;
}
int check_and_get_ring_buffer(unsigned char *buffer, unsigned int size)
{
struct ring_buffer *b = (struct ring_buffer *)buffer;
if (!b || size < sizeof(struct ring_buffer))
return -1;
if (b->magic == MAGIC) {
g_rb = b;
return 0;
}
return -1;
}
/*
* buffer: entire loop buffer start address
* size : loop buffer size
* return: 0: successful, -1: fail
*/
int initial_ring_buffer(unsigned char *buffer, unsigned int size)
{
g_rb = init_ring_buffer(buffer, size);
if (g_rb)
return 0;
return -1;
}
/* __read_ring_buffer
* timer: get time from loop buffer
* msg_state: 0: read a message in progress,
* bit0 is 1: read a mesaage begin
* bit1 is 1: read a message end
*/
static unsigned int __read_ring_buffer(struct ring_buffer *rb, unsigned int *timer,
unsigned char *buffer, unsigned int size, unsigned int *msg_state)
{
unsigned int count, rlen;
unsigned int total_len;
unsigned int msg_header;
unsigned char *p;
static unsigned int *r_message_len;
static unsigned int r_message_len_b;
if (!rb || rb->magic != MAGIC || rb->len == 0)
return 0;
if (!buffer || size == 0 || !timer || !msg_state)
return 0;
*msg_state = READ_MSG_STATE_IN_PROGRESS;
count = 0;
amp_lock_obtain(&rb->lock, ARM_CPU);
/*rb->mode LOG_MESSAGE_READ bit is 0 to read header*/
if ((rb->mode & LOG_MESSAGE_READ) != LOG_MESSAGE_READ) {
total_len = rb->len;
if (total_len >= MESSAGE_MIN_SIZE) {
/* a message format:
* LOG_MESSAGE_HEADER(4bytes) + time(4bytes) + message len(4bytes) + message
* note: message end with '\n'
*/
/*find out a message header*/
msg_header = LOG_MESSAGE_HEADER;
p = (unsigned char *)&msg_header;
do {
if (p[0] != rb->data[rb->head] ||
p[1] != rb->data[rb->head + 1] ||
p[2] != rb->data[rb->head + 2] ||
p[3] != rb->data[rb->head + 3]) {
rb->head++;
rb->head %= rb->size;
rb->len--;
if (rb->len == 0)
goto err;
} else {
rb->head += 4;
rb->head %= rb->size;
rb->len -= 4;
break;
}
} while (1);
/*get time of a message*/
p = (unsigned char *)timer;
rlen = 4;
rb->len -= rlen;
while (rlen--) {
p[count++] = rb->data[rb->head++];
rb->head %= rb->size;
}
/*get a message len */
r_message_len = (unsigned int *)&rb->data[rb->head];
rb->head += 4;
rb->head %= rb->size;
rb->len -= 4;
r_message_len_b = *r_message_len;
/*start to get a message */
rb->mode |= LOG_MESSAGE_READ;
*msg_state |= READ_MSG_STATE_BEGIN;
} else if (total_len == 0) {
goto err;
} // else {
/*it should never be here, if come here, there is an error*/
//}
}
if (!r_message_len) {
/*it should never be here, if come here, there is an error*/
goto err;
}
/*read a message*/
count = 0;
rlen = size < rb->len ? size : rb->len;
rlen = r_message_len_b < rlen ? r_message_len_b : rlen;
rb->len -= rlen;
r_message_len_b -= rlen;
while (rlen--) {
buffer[count++] = rb->data[rb->head++];
rb->head %= rb->size;
}
/*read message finished*/
if (r_message_len_b == 0) {
unsigned int save_head;
save_head = rb->head;
rb->head += (MESSAGE_ALIGN_SIZE - 1);
rb->head = (rb->head >> 2) << 2;
save_head = rb->head - save_head;
rb->head %= rb->size;
rb->len -= save_head;
rb->mode &= ~(LOG_MESSAGE_READ);
r_message_len = NULL;
*msg_state |= READ_MSG_STATE_END; //one message read finished
}
if (rb->len == 0) {
//if read finished, clean LOG_MESSAGE_SECOND_READ flag
rb->mode &= ~(LOG_MESSAGE_SECOND_READ);
}
amp_lock_release(&rb->lock, ARM_CPU);
return count;
err:
amp_lock_release(&rb->lock, ARM_CPU);
return 0;
}
unsigned int read_ring_buffer(unsigned int *timer, unsigned char *buffer,
unsigned int size, unsigned int *msg_state)
{
return __read_ring_buffer(g_rb, timer, buffer, size, msg_state);
}
static void __second_read_ring_buffer_set(struct ring_buffer *rb)
{
amp_lock_obtain(&rb->lock, ARM_CPU);
if (rb->len == 0 && ((rb->mode & LOG_MESSAGE_WRITE) != LOG_MESSAGE_WRITE)) {
rb->len = rb->len_b;
rb->head = 0;
rb->mode |= (LOG_MESSAGE_SECOND_READ);
}
amp_lock_release(&rb->lock, ARM_CPU);
}
void second_read_ring_buffer_set(void)
{
__second_read_ring_buffer_set(g_rb);
}
static unsigned int __write_ring_buffer(struct ring_buffer *rb,
unsigned char *buffer, unsigned int size)
{
unsigned int count, wlen;
unsigned int timer;
unsigned int msg_header;
unsigned char *p;
static unsigned int *message_len;
if (!rb || rb->magic != MAGIC)
return 0;
if (size == 0)
return 0;
count = 0;
amp_lock_obtain(&rb->lock, RISC_V_CPU);
/*rb->mode LOG_MESSAGE_WRITE bit is 0 to write header*/
if ((rb->mode & LOG_MESSAGE_WRITE) != LOG_MESSAGE_WRITE) {
/* a message format:
* LOG_MESSAGE_HEADER(4bytes) + time(4bytes) + message len(4bytes) + message
* note: message end with '\n'
*/
/*write message header to loop buffer, it indicate a message start*/
msg_header = LOG_MESSAGE_HEADER;
p = (unsigned char *)&msg_header;
wlen = 4;
rb->len += wlen;
rb->len_b += wlen;
while (wlen--) {
rb->data[rb->tail++] = p[count++];
rb->tail %= rb->size;
}
/*write time of a message */
/*if LOG_MSG_TIMER is optimized that can not get time, use volatile*/
timer = *(unsigned int *)(unsigned long)LOG_MSG_TIMER;
p = (unsigned char *)&timer;
wlen = 4;
rb->len += wlen;
rb->len_b += wlen;
count = 0;
while (wlen--) {
rb->data[rb->tail++] = p[count++];
rb->tail %= rb->size;
}
/*reserver message len space*/
message_len = (unsigned int *)&rb->data[rb->tail];
*message_len = 0;
rb->tail += 4;
rb->tail %= rb->size;
rb->len += 4;
rb->len_b += 4;
/*write a message until message ends with '\n' in buffer,
*the middle '\n' in the buffer does not act as an end marker
*/
rb->mode |= LOG_MESSAGE_WRITE;
}
if (!message_len) {
/*it should never be here, if come here, it have an error*/
goto err;
}
wlen = size;
rb->len += wlen;
rb->len_b += wlen;
(*message_len) += wlen;
count = 0;
while (wlen--) {
rb->data[rb->tail++] = buffer[count++];
rb->tail %= rb->size;
}
/*'\n' is message end, message size MESSAGE_ALIGN_SIZE size align */
if (buffer[size - 1] == '\n') {
unsigned int save_tail;
save_tail = rb->tail;
rb->tail += (MESSAGE_ALIGN_SIZE - 1);
rb->tail = (rb->tail >> 2) << 2;
save_tail = rb->tail - save_tail;
rb->tail %= rb->size;
rb->len += save_tail;
rb->len_b += save_tail;
rb->mode &= ~(LOG_MESSAGE_WRITE);
message_len = NULL;
}
/* New data will overwrite the old data */
if (rb->len > rb->size) {
rb->head = rb->tail;
rb->len = rb->size;
rb->len_b = rb->size;
}
amp_lock_release(&rb->lock, RISC_V_CPU);
return count;
err:
amp_lock_release(&rb->lock, RISC_V_CPU);
return 0;
}
unsigned int write_ring_buffer(unsigned char *buffer, unsigned int size)
{
if (blx_ready)
return __write_ring_buffer(g_rb, buffer, size);
return 0;
}
static void __reset_ring_buffer(struct ring_buffer *rb)
{
if (!rb || rb->magic != MAGIC)
return;
rb->head = 0;
rb->tail = 0;
rb->len = 0;
rb->len_b = 0;
amp_lock_init(&rb->lock);
}
void reset_ring_buffer(void)
{
__reset_ring_buffer(g_rb);
}
int blx_init_uboot_log(void)
{
blx_ready = 1;
initial_ring_buffer((unsigned char *)UBOOT_LOG_BUF_BASE, UBOOT_LOG_BUF_SIZE);
return 0;
}
void uboot_log_use_new_addr(unsigned long addr, unsigned int size)
{
if (size < UBOOT_LOG_BUF_SIZE) {
/*address space too small*/
return;
}
memcpy((void *)addr, (void *)UBOOT_LOG_BUF_BASE, UBOOT_LOG_BUF_SIZE);
initial_ring_buffer((unsigned char *)addr, UBOOT_LOG_BUF_SIZE);
}
void blx_put_char(unsigned char c)
{
if (blx_ready) {
if (c == '\n') {
unsigned char c_r = '\r';
write_ring_buffer(&c_r, 1);
}
write_ring_buffer(&c, 1);
}
}
//#define DUMP_SAVE_LOG_TEST
#ifdef DUMP_SAVE_LOG_TEST
#include <serial.h>
#include <string.h>
void dump_loop_buf_log(void)
{
unsigned char r_buf[50];
unsigned int timer = 0;
int i;
unsigned int status;
unsigned int count;
blx_ready = 0;
printf("save log temporary addr: 0x%x\n", UBOOT_LOG_BUF_BASE);
printf("save log g_rb addr: 0x%lx\n", (long)g_rb);
printf("save log g_rb->len: 0x%x, g_rb->len_b:0x%x\n", g_rb->len, g_rb->len_b);
printf("save log g_rb->mode: 0x%x,g_rb->head:0x%x,g_rb->tail:0x%x\n",
g_rb->mode, g_rb->head, g_rb->tail);
printf("*dump start:\n");
memset(r_buf, 0, sizeof(r_buf));
for (i = 0; i < 1000; i++) {
memset(r_buf, 0, sizeof(r_buf));
timer = 0;
status = 0;
count = read_ring_buffer(&timer, r_buf, sizeof(r_buf), &status);
printf("dump status: 0x%x, count: 0x%x\n", status, count);
if (count > 0) {
switch (status & 3) {
case 1:
case 3:
printf("dump timer: 0x%x\n", timer);
printf((const char *)r_buf);
break;
case 0:
case 2:
printf((const char *)r_buf);
break;
default:
break;
}
}
}
printf("*dump end\n");
}
#endif