diff --git a/drivers/console/ipm_console_receiver.c b/drivers/console/ipm_console_receiver.c index e2056b7a127cd..cd1b1dffe2410 100644 --- a/drivers/console/ipm_console_receiver.c +++ b/drivers/console/ipm_console_receiver.c @@ -15,16 +15,19 @@ #include #include #include +#include static void ipm_console_thread(void *arg1, void *arg2, void *arg3) { u8_t size32; u16_t type; - int ret, key; + int ret; + k_spinlock_key_t key; struct device *d; const struct ipm_console_receiver_config_info *config_info; struct ipm_console_receiver_runtime_data *driver_data; - int pos; + int pos, end; + atomic_t *target; d = (struct device *)arg1; driver_data = d->driver_data; @@ -32,13 +35,16 @@ static void ipm_console_thread(void *arg1, void *arg2, void *arg3) ARG_UNUSED(arg2); size32 = 0U; pos = 0; + target = config_info->print_num; while (1) { k_sem_take(&driver_data->sem, K_FOREVER); + key = k_spin_lock(&driver_data->rb_spinlock); ret = ring_buf_item_get(&driver_data->rb, &type, (u8_t *)&config_info->line_buf[pos], NULL, &size32); + k_spin_unlock(&driver_data->rb_spinlock, key); if (ret) { /* Shouldn't ever happen... */ printk("ipm console ring buffer error: %d\n", ret); @@ -46,10 +52,12 @@ static void ipm_console_thread(void *arg1, void *arg2, void *arg3) continue; } + end = 0; if (config_info->line_buf[pos] == '\n' || pos == config_info->lb_size - 2) { if (pos != config_info->lb_size - 2) { config_info->line_buf[pos] = '\0'; + end = 1; } else { config_info->line_buf[pos + 1] = '\0'; } @@ -61,26 +69,14 @@ static void ipm_console_thread(void *arg1, void *arg2, void *arg3) printf("%s: '%s'\n", d->config->name, config_info->line_buf); } + if (end == 1) { + atomic_dec(target); + } pos = 0; } else { ++pos; } - /* ISR may have disabled the channel due to full buffer at - * some point. If that happened and there is now room, - * re-enable it. - * - * Lock interrupts to avoid pathological scenario where - * the buffer fills up in between enabling the channel and - * clearing the channel_disabled flag. - */ - if (driver_data->channel_disabled && - ring_buf_space_get(&driver_data->rb)) { - key = irq_lock(); - ipm_set_enabled(driver_data->ipm_device, 1); - driver_data->channel_disabled = 0; - irq_unlock(key); - } } } @@ -90,27 +86,20 @@ static void ipm_console_receive_callback(void *context, u32_t id, struct device *d; struct ipm_console_receiver_runtime_data *driver_data; int ret; + k_spinlock_key_t key; ARG_UNUSED(data); d = context; driver_data = d->driver_data; + key = k_spin_lock(&driver_data->rb_spinlock); /* Should always be at least one free buffer slot */ ret = ring_buf_item_put(&driver_data->rb, 0, id, NULL, 0); + k_spin_unlock(&driver_data->rb_spinlock, key); __ASSERT(ret == 0, "Failed to insert data into ring buffer"); k_sem_give(&driver_data->sem); - /* If the buffer is now full, disable future interrupts for this channel - * until the thread has a chance to consume characters. - * - * This works without losing data if the sending side tries to send - * more characters because the sending side is making an ipm_send() - * call with the wait flag enabled. It blocks until the receiver side - * re-enables the channel and consumes the data. - */ - if (ring_buf_space_get(&driver_data->rb) == 0) { - ipm_set_enabled(driver_data->ipm_device, 0); - driver_data->channel_disabled = 1; + while (ring_buf_space_get(&driver_data->rb) == 0) { } } diff --git a/include/drivers/console/ipm_console.h b/include/drivers/console/ipm_console.h index 11782cb34c443..a468c403ec4a2 100644 --- a/include/drivers/console/ipm_console.h +++ b/include/drivers/console/ipm_console.h @@ -12,6 +12,8 @@ #include #include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -61,6 +63,8 @@ struct ipm_console_receiver_config_info { * IPM_CONSOLE_STDOUT or IPM_CONSOLE_PRINTK */ unsigned int flags; + + atomic_t *print_num; }; struct ipm_console_receiver_runtime_data { @@ -80,6 +84,11 @@ struct ipm_console_receiver_runtime_data { /** Receiver worker thread */ struct k_thread rx_thread; + + /** + * Ring buffer spinlock + */ + struct k_spinlock rb_spinlock; }; struct ipm_console_sender_config_info { diff --git a/include/ring_buffer.h b/include/ring_buffer.h index 351a1922d73c3..417ecae1ed361 100644 --- a/include/ring_buffer.h +++ b/include/ring_buffer.h @@ -25,8 +25,8 @@ extern "C" { * @brief A structure to represent a ring buffer */ struct ring_buf { - u32_t head; /**< Index in buf for the head element */ - u32_t tail; /**< Index in buf for the tail element */ + volatile u32_t head; /**< Index in buf for the head element */ + volatile u32_t tail; /**< Index in buf for the tail element */ union ring_buf_misc { struct ring_buf_misc_item_mode { u32_t dropped_put_count; /**< Running tally of the @@ -39,7 +39,7 @@ struct ring_buf { u32_t tmp_head; } byte_mode; } misc; - u32_t size; /**< Size of buf in 32-bit chunks */ + volatile u32_t size; /**< Size of buf in 32-bit chunks */ union ring_buf_buffer { u32_t *buf32; /**< Memory region for stored entries */ diff --git a/tests/drivers/ipm/src/ipm_dummy.c b/tests/drivers/ipm/src/ipm_dummy.c index 256295468adf2..5812d90b2cf48 100644 --- a/tests/drivers/ipm/src/ipm_dummy.c +++ b/tests/drivers/ipm/src/ipm_dummy.c @@ -69,13 +69,8 @@ static int ipm_dummy_send(struct device *d, int wait, u32_t id, driver_data->regs.id = id; driver_data->regs.busy = 1U; - irq_offload(ipm_dummy_isr, d); + ipm_dummy_isr(d); - if (wait) { - while (driver_data->regs.busy) { - /* busy-wait */ - } - } return 0; } diff --git a/tests/drivers/ipm/src/main.c b/tests/drivers/ipm/src/main.c index 8fcfd0dc4c2da..b305c066f989a 100644 --- a/tests/drivers/ipm/src/main.c +++ b/tests/drivers/ipm/src/main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "ipm_dummy.h" @@ -54,6 +55,7 @@ DEVICE_INIT(ipm_console_send0, "ipm_send0", ipm_console_sender_init, static u32_t ring_buf_data[RING_BUF_SIZE32]; static K_THREAD_STACK_DEFINE(thread_stack, IPM_CONSOLE_STACK_SIZE); static char line_buf[LINE_BUF_SIZE]; +static atomic_t target; /* Dump incoming messages to printk() */ static struct ipm_console_receiver_config_info receiver_config = { @@ -63,7 +65,8 @@ static struct ipm_console_receiver_config_info receiver_config = { .rb_size32 = RING_BUF_SIZE32, .line_buf = line_buf, .lb_size = LINE_BUF_SIZE, - .flags = DEST + .flags = DEST, + .print_num = &target }; struct ipm_console_receiver_runtime_data receiver_data; @@ -78,16 +81,19 @@ void main(void) int rv, i; struct device *ipm; + target = 0; TC_START("Test IPM"); ipm = device_get_binding("ipm_dummy0"); /* Try sending a raw string to the IPM device to show that the * receiver works */ + atomic_inc(&target); for (i = 0; i < strlen(thestr); i++) { ipm_send(ipm, 1, thestr[i], NULL, 0); } + atomic_inc(&target); /* Now do this through printf() to exercise the sender */ printf("Lorem ipsum dolor sit amet, consectetur adipiscing elit, " "sed do eiusmod tempor incididunt ut labore et dolore magna " @@ -102,6 +108,9 @@ void main(void) * automation purposes? */ + while (atomic_get(&target) != 0) { + } + rv = TC_PASS; TC_END_RESULT(rv); TC_END_REPORT(rv); diff --git a/tests/drivers/ipm/testcase.yaml b/tests/drivers/ipm/testcase.yaml index 469feaf29cfff..0095e7c8ea42f 100644 --- a/tests/drivers/ipm/testcase.yaml +++ b/tests/drivers/ipm/testcase.yaml @@ -2,5 +2,4 @@ tests: peripheral.mailbox: filter: not CONFIG_SOC_QUARK_SE_C1000_SS arch_exclude: posix xtensa - platform_exclude: qemu_x86_64 # see issue #12478 tags: drivers ipc