From e8356afa26dc4d04361b3b66c728ae1ecd17b4e3 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Thu, 29 Jun 2017 18:14:39 -0400 Subject: [PATCH] pru: Rework command processing so that most of it is done on pru0 Change the command dispatch and response generation so that most of the work is done on pru0 instead of pru1. This allows more code to fit into the limited space on pru1. Signed-off-by: Kevin O'Connor --- src/command.c | 20 ++---- src/command.h | 15 +++++ src/pru/Makefile | 17 +++-- src/pru/internal.h | 10 ++- src/pru/main.c | 106 +++++++++++++++---------------- src/pru/pru0.c | 155 +++++++++++++++++++++++++++++++++++++++------ 6 files changed, 222 insertions(+), 101 deletions(-) diff --git a/src/command.c b/src/command.c index af84539f..53263a8f 100644 --- a/src/command.c +++ b/src/command.c @@ -13,19 +13,6 @@ #include "command.h" // output_P #include "sched.h" // DECL_TASK -#define MESSAGE_MIN 5 -#define MESSAGE_MAX 64 -#define MESSAGE_HEADER_SIZE 2 -#define MESSAGE_TRAILER_SIZE 3 -#define MESSAGE_POS_LEN 0 -#define MESSAGE_POS_SEQ 1 -#define MESSAGE_TRAILER_CRC 3 -#define MESSAGE_TRAILER_SYNC 1 -#define MESSAGE_PAYLOAD_MAX (MESSAGE_MAX - MESSAGE_MIN) -#define MESSAGE_SEQ_MASK 0x0f -#define MESSAGE_DEST 0x10 -#define MESSAGE_SYNC 0x7E - static uint8_t next_sequence = MESSAGE_DEST; @@ -68,8 +55,9 @@ parse_int(char **pp) } // Parse an incoming command into 'args' -static char * -parsef(char *p, char *maxend, const struct command_parser *cp, uint32_t *args) +char * +command_parsef(char *p, char *maxend + , const struct command_parser *cp, uint32_t *args) { uint8_t num_params = READP(cp->num_params); const uint8_t *param_types = READP(cp->param_types); @@ -301,7 +289,7 @@ command_dispatch(char *buf, uint8_t msglen) uint8_t cmdid = *p++; const struct command_parser *cp = command_lookup_parser(cmdid); uint32_t args[READP(cp->num_args)]; - p = parsef(p, msgend, cp, args); + p = command_parsef(p, msgend, cp, args); if (sched_is_shutdown() && !(READP(cp->flags) & HF_IN_SHUTDOWN)) { sched_report_shutdown(); continue; diff --git a/src/command.h b/src/command.h index 148f47be..91d7cd80 100644 --- a/src/command.h +++ b/src/command.h @@ -33,6 +33,19 @@ #define try_shutdown(msg) \ sched_try_shutdown(_DECL_STATIC_STR(msg)) +#define MESSAGE_MIN 5 +#define MESSAGE_MAX 64 +#define MESSAGE_HEADER_SIZE 2 +#define MESSAGE_TRAILER_SIZE 3 +#define MESSAGE_POS_LEN 0 +#define MESSAGE_POS_SEQ 1 +#define MESSAGE_TRAILER_CRC 3 +#define MESSAGE_TRAILER_SYNC 1 +#define MESSAGE_PAYLOAD_MAX (MESSAGE_MAX - MESSAGE_MIN) +#define MESSAGE_SEQ_MASK 0x0f +#define MESSAGE_DEST 0x10 +#define MESSAGE_SYNC 0x7E + struct command_encoder { uint8_t msg_id, max_size, num_params; const uint8_t *param_types; @@ -48,6 +61,8 @@ enum { }; // command.c +char *command_parsef(char *p, char *maxend + , const struct command_parser *cp, uint32_t *args); uint8_t command_encodef(char *buf, uint8_t buf_len , const struct command_encoder *ce, va_list args); void command_sendf(const struct command_encoder *ce, ...); diff --git a/src/pru/Makefile b/src/pru/Makefile index 5f5739b4..a5dfaeb8 100644 --- a/src/pru/Makefile +++ b/src/pru/Makefile @@ -6,28 +6,27 @@ CROSS_PREFIX=pru- dirs-y += src/pru src/generic dirs-y += lib/pru_rpmsg -CFLAGS += -Os -mmcu=am335x.pru1 +CFLAGS += -minrt -mmcu=am335x.pru1 CFLAGS += -Ilib/pru_rpmsg/include -Ilib/pru_rpmsg/include/am335x CFLAGS_klipper.elf := $(filter-out -mmcu=%, $(CFLAGS)) CFLAGS_klipper.elf += -Wl,-r -nostdlib -Wl,-T,src/pru/pru.lds -CFLAGS_pru0.elf := $(filter-out -mmcu=%, $(CFLAGS)) -minrt -mmcu=am335x.pru0 -CFLAGS_pru1.elf := $(CFLAGS) -minrt +CFLAGS_pru0.elf := $(filter-out -mmcu=%, $(CFLAGS)) -mmcu=am335x.pru0 +CFLAGS_pru1.elf := $(CFLAGS) # Add source files -src-y := $(filter-out debugcmds.c, $(src-y)) -src-y += pru/main.c pru/gpio.c -src-y += generic/crc16_ccitt.c generic/timer_irq.c +src-y += pru/main.c pru/gpio.c generic/timer_irq.c -pru0-y := pru/pru0.c +pru0-y := pru/pru0.c generic/crc16_ccitt.c command.c pru0-y += ../lib/pru_rpmsg/pru_rpmsg.c ../lib/pru_rpmsg/pru_virtqueue.c -# Build the additional PRU0 binary +# Build the PRU binaries target-y += $(OUT)pru0.elf $(OUT)pru1.elf $(OUT)pru0.elf: $(patsubst %.c, $(OUT)src/%.o,$(pru0-y)) @echo " Linking $@" - $(Q)$(CC) $(CFLAGS_pru0.elf) $^ -o $@ + $(Q)$(CC) $(CFLAGS_klipper.elf) $^ -o $(OUT)pru0.o + $(Q)$(CC) $(CFLAGS_pru0.elf) $(OUT)pru0.o -o $@ $(OUT)pru1.elf: $(OUT)klipper.elf @echo " Linking $@" diff --git a/src/pru/internal.h b/src/pru/internal.h index 109dd3a2..1a2983d2 100644 --- a/src/pru/internal.h +++ b/src/pru/internal.h @@ -19,16 +19,22 @@ #define R31_WRITE_IRQ_SELECT (1<<5) #define R31_WRITE_IRQ_OFFSET 16 +#define ALT_PRU_PTR(ptr) ((typeof(ptr))((uint32_t)(ptr) ^ 0x2000)) + // Layout of shared memory struct shared_mem { uint32_t signal; - uint32_t read_pos, read_count; - char read_data[512]; + const struct command_parser *next_command; + uint32_t next_command_args[16]; uint32_t send_push_pos, send_pop_pos; struct { uint32_t count; char data[64]; } send_data[4]; + const struct command_parser *command_index; + uint32_t command_index_size; + const struct command_parser *shutdown_handler; + char read_data[512]; }; #define SIGNAL_PRU0_WAITING 0xefefefef diff --git a/src/pru/main.c b/src/pru/main.c index d906b1ad..ea0ec602 100644 --- a/src/pru/main.c +++ b/src/pru/main.c @@ -99,74 +99,69 @@ DECL_INIT(timer_init); * Console IO ****************************************************************/ -// Return a buffer (and length) containing any incoming messages -static char * -console_get_input(uint8_t *plen) -{ - uint32_t read_count = readl(&SHARED_MEM->read_count); - if (read_count > 64) - read_count = 64; - *plen = read_count; - return SHARED_MEM->read_data; -} - -// Remove from the receive buffer the given number of bytes -static void -console_pop_input(uint8_t len) -{ - writel(&SHARED_MEM->read_count, 0); -} - // Process any incoming commands void console_task(void) { - uint8_t buf_len, pop_count; - char *buf = console_get_input(&buf_len); - int8_t ret = command_find_block(buf, buf_len, &pop_count); - if (ret) - command_dispatch(buf, pop_count); - console_pop_input(pop_count); + const struct command_parser *cp = SHARED_MEM->next_command; + if (!cp) + return; + barrier(); + + if (sched_is_shutdown() && !(cp->flags & HF_IN_SHUTDOWN)) { + sched_report_shutdown(); + } else { + void (*func)(uint32_t*) = cp->func; + func(SHARED_MEM->next_command_args); + } + + writel(&SHARED_MEM->next_command, 0); } DECL_TASK(console_task); -// Return an output buffer that the caller may fill with transmit messages -static char * -console_get_output(uint8_t len) -{ - if (len > sizeof(SHARED_MEM->send_data[0].data)) - return NULL; - uint32_t send_push_pos = SHARED_MEM->send_push_pos; - if (readl(&SHARED_MEM->send_data[send_push_pos].count)) - // Queue full - return NULL; - return SHARED_MEM->send_data[send_push_pos].data; -} - -// Accept the given number of bytes added to the transmit buffer -static void -console_push_output(uint8_t len) -{ - uint32_t send_push_pos = SHARED_MEM->send_push_pos; - writel(&SHARED_MEM->send_data[send_push_pos].count, len); - write_r31(R31_WRITE_IRQ_SELECT | (KICK_PRU0_EVENT - R31_WRITE_IRQ_OFFSET)); - SHARED_MEM->send_push_pos = ( - (send_push_pos + 1) % ARRAY_SIZE(SHARED_MEM->send_data)); -} - // Encode and transmit a "response" message void console_sendf(const struct command_encoder *ce, va_list args) { - uint8_t buf_len = ce->max_size; - char *buf = console_get_output(buf_len); - if (!buf) + // Verify space for message + uint32_t max_size = ce->max_size; + if (max_size > sizeof(SHARED_MEM->send_data[0].data)) return; - uint8_t msglen = command_encodef(buf, buf_len, ce, args); - command_add_frame(buf, msglen); - console_push_output(msglen); + uint32_t send_push_pos = SHARED_MEM->send_push_pos; + if (readl(&SHARED_MEM->send_data[send_push_pos].count)) + // Queue full + return; + + // Generate message + char *buf = SHARED_MEM->send_data[send_push_pos].data; + uint32_t msglen = command_encodef(buf, max_size, ce, args); + + // Signal PRU0 to transmit message + writel(&SHARED_MEM->send_data[send_push_pos].count, msglen); + write_r31(R31_WRITE_IRQ_SELECT | (KICK_PRU0_EVENT - R31_WRITE_IRQ_OFFSET)); + SHARED_MEM->send_push_pos = ( + (send_push_pos + 1) % ARRAY_SIZE(SHARED_MEM->send_data)); } +void +console_shutdown(void) +{ + writel(&SHARED_MEM->next_command, 0); +} +DECL_SHUTDOWN(console_shutdown); + +// Handle shutdown request from PRU0 +static void +shutdown_handler(uint32_t *args) +{ + shutdown("Request from PRU0"); +} + +// Empty message (for ack/nak transmission) +const struct command_parser shutdown_request = { + .func = shutdown_handler, +}; + /**************************************************************** * Allocator @@ -234,6 +229,9 @@ main(void) // Wait for PRU0 to initialize while (readl(&SHARED_MEM->signal) != SIGNAL_PRU0_WAITING) ; + SHARED_MEM->command_index = command_index; + SHARED_MEM->command_index_size = command_index_size; + SHARED_MEM->shutdown_handler = &shutdown_request; writel(&SHARED_MEM->signal, SIGNAL_PRU1_READY); sched_main(); diff --git a/src/pru/pru0.c b/src/pru/pru0.c index 424ba5c6..6ea42287 100644 --- a/src/pru/pru0.c +++ b/src/pru/pru0.c @@ -4,6 +4,7 @@ // // This file may be distributed under the terms of the GNU GPLv3 license. +#include // setjmp #include // uint32_t #include // memset #include // write_r31 @@ -14,8 +15,13 @@ #include // VIRTIO_ID_RPMSG #include // resource_table #include "board/io.h" // readl +#include "command.h" // command_add_frame #include "compiler.h" // __section #include "internal.h" // SHARED_MEM +#include "sched.h" // sched_shutdown + +struct pru_rpmsg_transport transport; +static uint16_t transport_dst; /**************************************************************** @@ -26,10 +32,9 @@ #define CHAN_DESC "Channel 30" #define CHAN_PORT 30 -static uint16_t transport_dst; - +// Check if there is data to be sent from PRU1 to the host static void -check_can_send(struct pru_rpmsg_transport *transport) +check_can_send(void) { for (;;) { uint32_t send_pop_pos = SHARED_MEM->send_pop_pos; @@ -37,8 +42,9 @@ check_can_send(struct pru_rpmsg_transport *transport) if (!count) // Queue empty break; + command_add_frame(SHARED_MEM->send_data[send_pop_pos].data, count); pru_rpmsg_send( - transport, CHAN_PORT, transport_dst + &transport, CHAN_PORT, transport_dst , &SHARED_MEM->send_data[send_pop_pos].data, count); writel(&SHARED_MEM->send_data[send_pop_pos].count, 0); SHARED_MEM->send_pop_pos = ( @@ -46,34 +52,135 @@ check_can_send(struct pru_rpmsg_transport *transport) } } +// Wait for PRU1 to finish processing a command static void -check_can_read(struct pru_rpmsg_transport *transport) +wait_pru1_command(void) { - if (readl(&SHARED_MEM->read_count)) - // main processing pru is busy - return; - uint16_t dst, len; - int16_t ret = pru_rpmsg_receive( - transport, &transport_dst, &dst, SHARED_MEM->read_data, &len); - if (ret || !len) - return; - SHARED_MEM->read_pos = 0; - writel(&SHARED_MEM->read_count, len); + while (readl(&SHARED_MEM->next_command)) + check_can_send(); + check_can_send(); +} + +// Signal PRU1 that a new command is ready +static void +send_pru1_command(const struct command_parser *cp) +{ + barrier(); + SHARED_MEM->next_command = cp; + barrier(); write_r31(R31_WRITE_IRQ_SELECT | (KICK_PRU1_EVENT - R31_WRITE_IRQ_OFFSET)); } +// Instruct PRU1 to shutdown static void -process_io(struct pru_rpmsg_transport *transport) +send_pru1_shutdown(void) +{ + wait_pru1_command(); + send_pru1_command(SHARED_MEM->shutdown_handler); + wait_pru1_command(); +} + +// Dispatch all the commands in a message block +static void +do_dispatch(char *buf, uint32_t msglen) +{ + char *p = &buf[MESSAGE_HEADER_SIZE]; + char *msgend = &buf[msglen-MESSAGE_TRAILER_SIZE]; + while (p < msgend) { + // Parse command + uint8_t cmdid = *p++; + const struct command_parser *cp = &SHARED_MEM->command_index[cmdid]; + if (!cmdid || cmdid >= SHARED_MEM->command_index_size + || cp->num_args > ARRAY_SIZE(SHARED_MEM->next_command_args)) { + send_pru1_shutdown(); + return; + } + p = command_parsef(p, msgend, cp, SHARED_MEM->next_command_args); + + send_pru1_command(ALT_PRU_PTR(cp)); + wait_pru1_command(); + } +} + +// See if there are commands from the host ready to be processed +static void +check_can_read(void) +{ + // Read data + uint16_t dst, len; + char *p = SHARED_MEM->read_data; + int16_t ret = pru_rpmsg_receive(&transport, &transport_dst, &dst, p, &len); + if (ret) + return; + + // Parse data into message blocks + for (;;) { + uint8_t pop_count, msglen = len > 64 ? 64 : len; + int8_t ret = command_find_block(p, msglen, &pop_count); + if (!ret) + break; + if (ret > 0) + do_dispatch(p, pop_count); + p += pop_count; + len -= pop_count; + } +} + +// Main processing loop +static void +process_io(void) { for (;;) { if (!(read_r31() & (1 << (WAKE_PRU0_IRQ + R31_IRQ_OFFSET)))) continue; CT_INTC.SECR0 = (1 << KICK_PRU0_FROM_ARM_EVENT) | (1 << KICK_PRU0_EVENT); - check_can_send(transport); - check_can_read(transport); + check_can_send(); + check_can_read(); } } +// Startup initialization +static void +setup_io(void) +{ + // Fixup pointers in command_parsers + SHARED_MEM->command_index = ALT_PRU_PTR(SHARED_MEM->command_index); + struct command_parser *p = (void*)SHARED_MEM->command_index; + int i; + for (i=0; icommand_index_size; i++, p++) + if (p->param_types) + p->param_types = ALT_PRU_PTR(p->param_types); +} + + +/**************************************************************** + * Compatibility wrappers + ****************************************************************/ + +// shutdown() compatibility code +uint8_t ctr_lookup_static_string(const char *str) +{ + return 0; +} + +static jmp_buf shutdown_jmp; + +// Handle shutdown() +void +sched_shutdown(uint_fast8_t reason) +{ + longjmp(shutdown_jmp, 1); +} + +// Generate messages - only used for ack/nak messages +void +console_sendf(const struct command_encoder *ce, va_list args) +{ + char buf[MESSAGE_MIN]; + command_add_frame(buf, sizeof(buf)); + pru_rpmsg_send(&transport, CHAN_PORT, transport_dst, buf, sizeof(buf)); +} + /**************************************************************** * Peripheral reset @@ -241,7 +348,6 @@ main(void) ; /* Initialize the RPMsg transport structure */ - struct pru_rpmsg_transport transport; pru_rpmsg_init(&transport, &resourceTable.rpmsg_vring0, &resourceTable.rpmsg_vring1, @@ -265,5 +371,14 @@ main(void) ; writel(&SHARED_MEM->signal, 0); - process_io(&transport); + // Setup incoming message parser + setup_io(); + + // Support shutdown + int ret = setjmp(shutdown_jmp); + if (ret) + send_pru1_shutdown(); + + // Main loop + process_io(); }