Skip to content

Commit

Permalink
implement printk daemon for supporting dma
Browse files Browse the repository at this point in the history
  • Loading branch information
shengwen-tw committed Nov 25, 2023
1 parent ed833c9 commit 9f70cb2
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 54 deletions.
61 changes: 11 additions & 50 deletions drivers/serial/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <kernel/mutex.h>
#include <kernel/pipe.h>
#include <kernel/printk.h>
#include <kernel/softirq.h>
#include <kernel/tty.h>
#include <kernel/wait.h>

#include "stm32f4xx.h"
Expand All @@ -21,7 +21,6 @@
#define UART1_ISR_PRIORITY 14

static int uart1_dma_puts(const char *data, size_t size);
ssize_t console_write(const char *buf, size_t size);

ssize_t serial0_read(struct file *filp, char *buf, size_t size, off_t offset);
ssize_t serial0_write(struct file *filp,
Expand All @@ -33,19 +32,13 @@ int serial0_open(struct inode *inode, struct file *file);
void USART1_IRQHandler(void);
void DMA2_Stream7_IRQHandler(void);

void uart1_tx_tasklet_handler(unsigned long data);

uart_dev_t uart1 = {
.rx_fifo = NULL,
.rx_wait_size = 0,
.tx_dma_ready = false,
.tx_state = UART_TX_IDLE,
};

static struct kfifo *uart1_tx_fifo;
static struct tasklet_struct uart1_tx_tasklet;
static LIST_HEAD(uart1_tx_wait_list);

static struct file_operations serial0_file_ops = {
.read = serial0_read,
.write = serial0_write,
Expand Down Expand Up @@ -83,6 +76,9 @@ void uart1_init(uint32_t baudrate)
};
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);
#if (ENABLE_UART1_DMA != 0)
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
#endif
USART_ClearFlag(USART1, USART_FLAG_TC);

/* Initialize interrupt of the UART1 */
Expand Down Expand Up @@ -116,17 +112,9 @@ void tty_init(void)

/* Initialize mutex, kfifo, and tasklet for UART1 tx */
mutex_init(&uart1.tx_mtx);
uart1_tx_fifo = kfifo_alloc(PRINT_SIZE_MAX, UART1_TX_FIFO_SIZE);
tasklet_init(&uart1_tx_tasklet, uart1_tx_tasklet_handler, 0);

/* Initialize UART1 */
uart1_init(115200);

#ifndef BUILD_QEMU
/* Clean screen */
char *cls_str = "\x1b[H\x1b[2J";
console_write(cls_str, strlen(cls_str));
#endif
}

void serial0_init(void)
Expand Down Expand Up @@ -155,28 +143,16 @@ ssize_t serial0_read(struct file *filp, char *buf, size_t size, off_t offset)
}
}

ssize_t console_write(const char *buf, size_t size)
{
kfifo_in(uart1_tx_fifo, buf, size);
tasklet_schedule(&uart1_tx_tasklet);
return size;
}

ssize_t serial0_write(struct file *filp,
const char *buf,
size_t size,
off_t offset)
{
CURRENT_THREAD_INFO(curr_thread);

if (kfifo_avail(uart1_tx_fifo) > 0) {
kfifo_in(uart1_tx_fifo, buf, size);
tasklet_schedule(&uart1_tx_tasklet);
return size;
} else {
prepare_to_wait(&uart1_tx_wait_list, &curr_thread->list, THREAD_WAIT);
return -ERESTARTSYS;
}
#if (ENABLE_UART1_DMA != 0)
return uart1_dma_puts(buf, size);
#else
return uart_puts(USART1, buf, size);
#endif
}

void early_write(char *buf, size_t size)
Expand Down Expand Up @@ -224,6 +200,7 @@ static int uart1_dma_puts(const char *data, size_t size)
/* Wait until DMA completed data transfer */
init_wait(uart1.tx_wait);
prepare_to_wait(&uart1.tx_wq, uart1.tx_wait, THREAD_WAIT);

return -ERESTARTSYS;
}
case UART_TX_DMA_BUSY: {
Expand All @@ -236,6 +213,7 @@ static int uart1_dma_puts(const char *data, size_t size)
}

/* Notified by the DMA ISR, the data transfer is now complete */
DMA_ITConfig(DMA2_Stream7, DMA_IT_TC, DISABLE);
uart1.tx_state = UART_TX_IDLE;
return size;
}
Expand All @@ -245,23 +223,6 @@ static int uart1_dma_puts(const char *data, size_t size)
}
}

void uart1_tx_tasklet_handler(unsigned long data)
{
char *buf;
size_t size;

kfifo_dma_out_prepare(uart1_tx_fifo, &buf, &size);
uart_puts(USART1, buf, size);
kfifo_dma_out_finish(uart1_tx_fifo);

/* Wake up a write-waiting thread */
wake_up(&uart1_tx_wait_list);

/* Schedule the tasklet again if the fifo is not cleared */
if (!kfifo_is_empty(uart1_tx_fifo))
tasklet_schedule(&uart1_tx_tasklet);
}

void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET) {
Expand Down
1 change: 1 addition & 0 deletions drivers/serial/debug_link.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <kernel/kernel.h>
#include <kernel/pipe.h>
#include <kernel/printk.h>
#include <kernel/tty.h>
#include <kernel/wait.h>

#include "stm32f4xx.h"
Expand Down
1 change: 1 addition & 0 deletions drivers/serial/mavlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <kernel/kernel.h>
#include <kernel/pipe.h>
#include <kernel/printk.h>
#include <kernel/tty.h>
#include <kernel/wait.h>

#include "stm32f4xx.h"
Expand Down
4 changes: 4 additions & 0 deletions include/kernel/printk.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@ void printk(char *format, ...);
*/
void panic(char *format, ...);

void printkd_init(void);
void printkd_start(void);
void printkd(void);

#endif
1 change: 1 addition & 0 deletions kconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define IDLE_STACK_SIZE 2048
#define SOFTIRQD_STACK_SIZE 2048
#define FILESYSD_STACK_SIZE 2048
#define PRINTKD_STACK_SIZE 1024

/* Task */
#define TASK_MAX 64 /* Max number of tasks in the system */
Expand Down
6 changes: 3 additions & 3 deletions kernel/arch/v7m_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,13 @@ void fault_dump(uint32_t fault_type, uint32_t *msp, uint32_t *psp, uint32_t lr)

if (lr == 0xfffffff1 || lr == 0xffffffe1) {
fault_stack = msp;
fault_location = "Fault location: IRQ Handler (sp = msp)\n";
fault_location = "Fault location: IRQ Handler (sp = msp)\n\r";
} else if (lr == 0xfffffff9 || lr == 0xffffffe9) {
fault_stack = msp;
fault_location = "Fault location: Kernel (sp = msp)\n";
fault_location = "Fault location: Kernel (sp = msp)\n\r";
} else if (lr == 0xfffffffd || lr == 0xffffffed) {
fault_stack = psp;
fault_location = "Fault location: Thread (sp = psp)\n";
fault_location = "Fault location: Thread (sp = psp)\n\r";
}

char *fault_type_s = "";
Expand Down
8 changes: 8 additions & 0 deletions kernel/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -2685,6 +2685,11 @@ static void schedule(void)

static void print_platform_info(void)
{
#ifndef BUILD_QEMU
/* Clear screen */
char *cls_str = "\x1b[H\x1b[2J";
console_write("\x1b[H\x1b[2J", strlen(cls_str));
#endif
printk("Tenok RTOS (built time: %s %s)", __TIME__, __DATE__);
printk("Machine model: %s", __BOARD_NAME__);
}
Expand Down Expand Up @@ -2738,6 +2743,7 @@ void init(void)
link_stdin_dev(STDIN_DEV_PATH);
link_stdout_dev(STDOUT_DEV_PATH);
link_stderr_dev(STDERR_DEV_PATH);
printkd_start();
}
preempt_enable();

Expand Down Expand Up @@ -2770,6 +2776,7 @@ void sched_start(void)
slab_init();
heap_init();
tty_init();
printkd_init();
rootfs_init();

/* Initialize ready lists */
Expand All @@ -2781,6 +2788,7 @@ void sched_start(void)
kthread_create(init, 0, IDLE_STACK_SIZE);
kthread_create(softirqd, KTHREAD_PRI_MAX, SOFTIRQD_STACK_SIZE);
kthread_create(filesysd, KTHREAD_PRI_MAX - 1, FILESYSD_STACK_SIZE);
kthread_create(printkd, KTHREAD_PRI_MAX - 1, PRINTKD_STACK_SIZE);

/* Dequeue thread 0 (Idle) to execute */
running_thread = &threads[0];
Expand Down
112 changes: 112 additions & 0 deletions kernel/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,66 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tenok.h>
#include <unistd.h>

#include <arch/port.h>
#include <common/list.h>
#include <kernel/interrupt.h>
#include <kernel/kernel.h>
#include <kernel/kfifo.h>
#include <kernel/printk.h>
#include <kernel/time.h>
#include <kernel/tty.h>

#include "kconfig.h"

#define PRINTK_QUEUE_SIZE 10

struct printk_data {
struct list_head list;
size_t size;
char data[PRINT_SIZE_MAX];
};

static struct printk_data printk_buf[PRINTK_QUEUE_SIZE];

static LIST_HEAD(printkd_wait);
static LIST_HEAD(printk_free_list);
static LIST_HEAD(printk_wait_list);

static bool stdout_initialized;
static bool printk_is_writing;

ssize_t console_write(const char *buf, size_t size)
{
struct printk_data *entry;

/* Check if the free list still has space */
if (list_empty(&printk_free_list)) {
/* No, overwrite the oldest buffer */
entry = list_first_entry(&printk_wait_list, struct printk_data, list);
/* Move the buffer to the end of the wait queue */
list_del(&entry->list);
list_add(&entry->list, &printk_wait_list);
} else {
/* Yes, take one buffer from the free queue */
entry = list_first_entry(&printk_free_list, struct printk_data, list);
/* Move the buffer to the wait queue */
list_move(&entry->list, &printk_wait_list);
}

/* Copy write message to the prink buffer */
memcpy(entry->data, buf, sizeof(char) * size);
entry->size = size;

/* Wake up the printk daemon */
if (!printk_is_writing)
wake_up_all(&printkd_wait);

return 0;
}

void printk(char *format, ...)
{
va_list args;
Expand Down Expand Up @@ -55,3 +107,63 @@ void panic(char *format, ...)
while (1)
;
}

void printkd_init(void)
{
/* Place all prink buffers to the free queue */
for (int i = 0; i < PRINTK_QUEUE_SIZE; i++)
list_add(&printk_buf[i].list, &printk_free_list);
}

void printkd_start(void)
{
/* Initiate the printk daemon */
stdout_initialized = true;
wake_up_all(&printkd_wait);
}

static void printkd_sleep(void)
{
CURRENT_THREAD_INFO(curr_thread);

preempt_disable();
prepare_to_wait(&printkd_wait, &curr_thread->list, THREAD_WAIT);
jump_to_kernel();
preempt_enable();
}

void printkd(void)
{
setprogname("printk");

struct printk_data *entry;

/* Wait until stdout is ready */
while (!stdout_initialized)
printkd_sleep();

while (1) {
/* Check if there is any printk message to write */
if (list_empty(&printk_wait_list)) {
/* No, suspend the daemon */
printkd_sleep();
} else {
/* Pop one prink data from the wait queue */
preempt_disable();
entry =
list_first_entry(&printk_wait_list, struct printk_data, list);
list_del(&entry->list);
preempt_enable();

/* Write printk message to the serial */
printk_is_writing = true;
write(STDOUT_FILENO, entry->data, entry->size);
printk_is_writing = false;

/* Place the used buffer back to the free queue */
preempt_disable();
list_add(&entry->list, &printk_free_list);
preempt_enable();
}
}
}
3 changes: 2 additions & 1 deletion kernel/softirq.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ void softirqd(void)
softirqd_sleep();
} else {
preempt_disable();

while (1)
;
/* Retrieve the next tasklet */
t = list_first_entry(&tasklet_list, struct tasklet_struct, list);
list_del(&t->list);
Expand Down

0 comments on commit 9f70cb2

Please sign in to comment.