mirror of https://github.com/Desuuuu/klipper.git
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 <kevin@koconnor.net>
This commit is contained in:
parent
c1bd628ce5
commit
e8356afa26
|
@ -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;
|
||||
|
|
|
@ -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, ...);
|
||||
|
|
|
@ -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 $@"
|
||||
|
|
|
@ -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
|
||||
|
|
106
src/pru/main.c
106
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();
|
||||
|
|
155
src/pru/pru0.c
155
src/pru/pru0.c
|
@ -4,6 +4,7 @@
|
|||
//
|
||||
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||
|
||||
#include <setjmp.h> // setjmp
|
||||
#include <stdint.h> // uint32_t
|
||||
#include <string.h> // memset
|
||||
#include <pru/io.h> // write_r31
|
||||
|
@ -14,8 +15,13 @@
|
|||
#include <pru_virtio_ids.h> // VIRTIO_ID_RPMSG
|
||||
#include <rsc_types.h> // 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; i<SHARED_MEM->command_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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue