diff --git a/benchmark/benchmark.c b/benchmark/benchmark.c index 1eae9056c..92bd24e13 100644 --- a/benchmark/benchmark.c +++ b/benchmark/benchmark.c @@ -3,6 +3,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -15,39 +16,38 @@ #include #include #include +#include + +#define SERIAL_TX_CH 0 + +char *serial_tx_data; +serial_queue_t *serial_tx_queue; +serial_queue_handle_t serial_tx_queue_handle; #define LOG_BUFFER_CAP 7 -/* Notification channels and TCB CAP offsets - ensure these align with .system file! */ -#define START 1 -#define STOP 2 -#define INIT 3 +/* Channel START signal is received on. */ +#define RX_START 1 -#define PD_TOTAL 0 -#define PD_ETH_ID 1 -#define PD_VIRT_RX_ID 2 -#define PD_VIRT_TX_ID 3 -#define PD_COPY_ID 4 -#define PD_COPY1_ID 5 -#define PD_LWIP_ID 6 -#define PD_LWIP1_ID 7 -#define PD_TIMER_ID 8 +/* Channel STOP signal is received on. */ +#define RX_STOP 2 -uintptr_t uart_base; -uintptr_t cyclecounters_vaddr; +/* Channel to transmit START signal. */ +#define TX_START 3 -ccnt_t counter_values[8]; -counter_bitfield_t benchmark_bf; +/* Channel to transmit STOP signal. */ +#define TX_STOP 4 -#define SERIAL_TX_CH 0 +/* Channel to initialise idle thread. */ +#define IDLE_INIT 5 -char *serial_tx_data; -serial_queue_t *serial_tx_queue; -serial_queue_handle_t serial_tx_queue_handle; +/* Identifier used to track utilisation for entire core. */ +#define TOTAL_ID 0 -#ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES -benchmark_track_kernel_entry_t *log_buffer; -#endif +core_config_t core_config; + +ccnt_t counter_values[8]; +counter_bitfield_t benchmark_bf; char *counter_names[] = { "L1 i-cache misses", @@ -67,95 +67,57 @@ event_id_t benchmarking_events[] = { SEL4BENCH_EVENT_BRANCH_MISPREDICT, }; -static void print_pdid_name(uint64_t pd_id) -{ - switch (pd_id) { - case PD_ETH_ID: - sddf_printf(NET_DRIVER_NAME); - break; - case PD_VIRT_RX_ID: - sddf_printf(NET_VIRT_RX_NAME); - break; - case PD_VIRT_TX_ID: - sddf_printf(NET_VIRT_TX_NAME); - break; - case PD_COPY_ID: - sddf_printf(NET_COPY0_NAME); - break; - case PD_COPY1_ID: - sddf_printf(NET_COPY1_NAME); - break; - case PD_LWIP_ID: - sddf_printf(NET_CLI0_NAME); - break; - case PD_LWIP1_ID: - sddf_printf(NET_CLI1_NAME); - break; - case PD_TIMER_ID: - sddf_printf(NET_TIMER_NAME); - break; - default: - sddf_printf("unknown"); - break; - } -} - #ifdef CONFIG_BENCHMARK_TRACK_UTILISATION -static void microkit_benchmark_start(void) +static void benchmark_start_core() { seL4_BenchmarkResetThreadUtilisation(TCB_CAP); - seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + PD_ETH_ID); - seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + PD_VIRT_RX_ID); - seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + PD_VIRT_TX_ID); - seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + PD_COPY_ID); - seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + PD_COPY1_ID); - seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + PD_LWIP_ID); - seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + PD_LWIP1_ID); - seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + PD_TIMER_ID); + for (uint32_t id = 1; id < core_config.max_core_id + 1; id++) { + if (core_config.core_bitmap & (1 << id)) { + seL4_BenchmarkResetThreadUtilisation(BASE_TCB_CAP + id); + } + } seL4_BenchmarkResetLog(); } -static void microkit_benchmark_stop(uint64_t *total, uint64_t *number_schedules, uint64_t *kernel, uint64_t *entries) +static void benchmark_print_IPC_data(uint64_t *buffer, uint32_t id) { - seL4_BenchmarkFinalizeLog(); - seL4_BenchmarkGetThreadUtilisation(TCB_CAP); - uint64_t *buffer = (uint64_t *)&seL4_GetIPCBuffer()->msg[0]; - - *total = buffer[BENCHMARK_TOTAL_UTILISATION]; - *number_schedules = buffer[BENCHMARK_TOTAL_NUMBER_SCHEDULES]; - *kernel = buffer[BENCHMARK_TOTAL_KERNEL_UTILISATION]; - *entries = buffer[BENCHMARK_TOTAL_NUMBER_KERNEL_ENTRIES]; -} - -static void microkit_benchmark_stop_tcb(uint64_t pd_id, uint64_t *total, uint64_t *number_schedules, uint64_t *kernel, - uint64_t *entries) -{ - seL4_BenchmarkGetThreadUtilisation(BASE_TCB_CAP + pd_id); - uint64_t *buffer = (uint64_t *)&seL4_GetIPCBuffer()->msg[0]; - - *total = buffer[BENCHMARK_TCB_UTILISATION]; - *number_schedules = buffer[BENCHMARK_TCB_NUMBER_SCHEDULES]; - *kernel = buffer[BENCHMARK_TCB_KERNEL_UTILISATION]; - *entries = buffer[BENCHMARK_TCB_NUMBER_KERNEL_ENTRIES]; + uint64_t total, number_schedules, kernel, entries; + if (id == TOTAL_ID) { + total = buffer[BENCHMARK_TOTAL_UTILISATION]; + number_schedules = buffer[BENCHMARK_TOTAL_NUMBER_SCHEDULES]; + kernel = buffer[BENCHMARK_TOTAL_KERNEL_UTILISATION]; + entries = buffer[BENCHMARK_TOTAL_NUMBER_KERNEL_ENTRIES]; + sddf_printf("Total utilisation details: \n"); + } else { + total = buffer[BENCHMARK_TCB_UTILISATION]; + number_schedules = buffer[BENCHMARK_TCB_NUMBER_SCHEDULES]; + kernel = buffer[BENCHMARK_TCB_KERNEL_UTILISATION]; + entries = buffer[BENCHMARK_TCB_NUMBER_KERNEL_ENTRIES]; + sddf_printf("Utilisation details for PD: %s (%x)\n", pd_id_to_name(id), id); + } + sddf_printf("{\nKernelUtilisation: %lx\nKernelEntries: " + "%lx\nNumberSchedules: %lx\nTotalUtilisation: %lx\n}\n", + kernel, entries, number_schedules, total); } -static void print_benchmark_details(uint64_t pd_id, uint64_t kernel_util, uint64_t kernel_entries, - uint64_t number_schedules, uint64_t total_util) +static void benchmark_stop_core() { - if (pd_id == PD_TOTAL) { - sddf_printf("Total utilisation details: \n"); - } else { - sddf_printf("Utilisation details for PD: "); - print_pdid_name(pd_id); - sddf_printf(" (%lx)\n", pd_id); + seL4_BenchmarkFinalizeLog(); + seL4_BenchmarkGetThreadUtilisation(TCB_CAP); + benchmark_print_IPC_data((uint64_t *)&seL4_GetIPCBuffer()->msg[0], TOTAL_ID); + for (uint32_t id = 1; id < core_config.max_core_id + 1; id++) { + if (core_config.core_bitmap & (1 << id)) { + seL4_BenchmarkGetThreadUtilisation(BASE_TCB_CAP + id); + benchmark_print_IPC_data((uint64_t *)&seL4_GetIPCBuffer()->msg[0], id); + } } - sddf_printf("{\nKernelUtilisation: %lx\nKernelEntries: %lx\nNumberSchedules: %lx\nTotalUtilisation: %lx\n}\n", - kernel_util, kernel_entries, number_schedules, total_util); } #endif #ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES -static inline void seL4_BenchmarkTrackDumpSummary(benchmark_track_kernel_entry_t *logBuffer, uint64_t logSize) +benchmark_track_kernel_entry_t *log_buffer; + +static inline void seL4_BenchmarkTrackDumpSummary(uint64_t logSize) { seL4_Word index = 0; seL4_Word syscall_entries = 0; @@ -166,19 +128,19 @@ static inline void seL4_BenchmarkTrackDumpSummary(benchmark_track_kernel_entry_t seL4_Word debug_fault = 0; seL4_Word other = 0; - while (logBuffer[index].start_time != 0 && index < logSize) { - if (logBuffer[index].entry.path == Entry_Syscall) { - if (logBuffer[index].entry.is_fastpath) { + while (log_buffer[index].start_time != 0 && index < logSize) { + if (log_buffer[index].entry.path == Entry_Syscall) { + if (log_buffer[index].entry.is_fastpath) { fastpaths++; } syscall_entries++; - } else if (logBuffer[index].entry.path == Entry_Interrupt) { + } else if (log_buffer[index].entry.path == Entry_Interrupt) { interrupt_entries++; - } else if (logBuffer[index].entry.path == Entry_UserLevelFault) { + } else if (log_buffer[index].entry.path == Entry_UserLevelFault) { userlevelfault_entries++; - } else if (logBuffer[index].entry.path == Entry_VMFault) { + } else if (log_buffer[index].entry.path == Entry_VMFault) { vmfault_entries++; - } else if (logBuffer[index].entry.path == Entry_DebugFault) { + } else if (log_buffer[index].entry.path == Entry_DebugFault) { debug_fault++; } else { other++; @@ -187,12 +149,13 @@ static inline void seL4_BenchmarkTrackDumpSummary(benchmark_track_kernel_entry_t index++; } - sddf_printf("Number of system call invocations %llx and fastpaths %llx\n", syscall_entries, fastpaths); - sddf_printf("Number of interrupt invocations %llx\n", interrupt_entries); - sddf_printf("Number of user-level faults %llx\n", userlevelfault_entries); - sddf_printf("Number of VM faults %llx\n", vmfault_entries); - sddf_printf("Number of debug faults %llx\n", debug_fault); - sddf_printf("Number of others %llx\n", other); + sddf_printf("System call invocations %lx", syscall_entries); + sddf_printf("Fastpaths %lx\n", fastpaths); + sddf_printf("Interrupt invocations %lx\n", interrupt_entries); + sddf_printf("User-level faults %lx\n", userlevelfault_entries); + sddf_printf("VM faults %lx\n", vmfault_entries); + sddf_printf("Debug faults %lx\n", debug_fault); + sddf_printf("Others %lx\n", other); } #endif @@ -200,28 +163,30 @@ static inline void seL4_BenchmarkTrackDumpSummary(benchmark_track_kernel_entry_t void notified(microkit_channel ch) { switch (ch) { - case START: + case RX_START: #ifdef MICROKIT_CONFIG_benchmark sel4bench_reset_counters(); THREAD_MEMORY_RELEASE(); sel4bench_start_counters(benchmark_bf); #ifdef CONFIG_BENCHMARK_TRACK_UTILISATION - microkit_benchmark_start(); + benchmark_start_core(); #endif #ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES seL4_BenchmarkResetLog(); #endif #endif - + if (!core_config.last_core) + microkit_notify(TX_START); break; - case STOP: + + case RX_STOP: #ifdef MICROKIT_CONFIG_benchmark sel4bench_get_counters(benchmark_bf, &counter_values[0]); sel4bench_stop_counters(benchmark_bf); - sddf_printf("{\n"); + sddf_printf("{CORE %u: \n", core_config.core_value); for (int i = 0; i < ARRAY_SIZE(benchmarking_events); i++) { sddf_printf("%s: %lX\n", counter_names[i], counter_values[i]); } @@ -229,63 +194,42 @@ void notified(microkit_channel ch) #endif #ifdef CONFIG_BENCHMARK_TRACK_UTILISATION - uint64_t total; - uint64_t kernel; - uint64_t entries; - uint64_t number_schedules; - microkit_benchmark_stop(&total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_TOTAL, kernel, entries, number_schedules, total); - - microkit_benchmark_stop_tcb(PD_ETH_ID, &total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_ETH_ID, kernel, entries, number_schedules, total); - - microkit_benchmark_stop_tcb(PD_VIRT_RX_ID, &total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_VIRT_RX_ID, kernel, entries, number_schedules, total); - - microkit_benchmark_stop_tcb(PD_VIRT_TX_ID, &total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_VIRT_TX_ID, kernel, entries, number_schedules, total); - - microkit_benchmark_stop_tcb(PD_COPY_ID, &total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_COPY_ID, kernel, entries, number_schedules, total); - - microkit_benchmark_stop_tcb(PD_COPY1_ID, &total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_COPY1_ID, kernel, entries, number_schedules, total); - - microkit_benchmark_stop_tcb(PD_LWIP_ID, &total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_LWIP_ID, kernel, entries, number_schedules, total); - - microkit_benchmark_stop_tcb(PD_LWIP1_ID, &total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_LWIP1_ID, kernel, entries, number_schedules, total); - - microkit_benchmark_stop_tcb(PD_TIMER_ID, &total, &number_schedules, &kernel, &entries); - print_benchmark_details(PD_TIMER_ID, kernel, entries, number_schedules, total); + benchmark_stop_core(); #endif #ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES - entries = seL4_BenchmarkFinalizeLog(); - sddf_printf("KernelEntries: %llx\n", entries); - seL4_BenchmarkTrackDumpSummary(log_buffer, entries); + uint64_t log_size = seL4_BenchmarkFinalizeLog(); + sddf_printf("KernelEntries: %lx\n", log_size); + seL4_BenchmarkTrackDumpSummary(log_size); #endif - + THREAD_MEMORY_RELEASE(); + if (!core_config.last_core) + microkit_notify(TX_STOP); break; + case SERIAL_TX_CH: // Nothing to do break; + default: - sddf_printf("Bench thread notified on unexpected channel\n"); + sddf_printf("BENCH|LOG: Bench thread notified on unexpected channel\n"); } } void init(void) { - serial_cli_queue_init_sys(microkit_name, NULL, NULL, NULL, &serial_tx_queue_handle, serial_tx_queue, serial_tx_data); + uint32_t serial_tx_data_capacity; + serial_cli_data_capacity(microkit_name, NULL, &serial_tx_data_capacity); + serial_queue_init(&serial_tx_queue_handle, serial_tx_queue, serial_tx_data_capacity, serial_tx_data); serial_putchar_init(SERIAL_TX_CH, &serial_tx_queue_handle); + + bench_core_config_info(microkit_name, &core_config); + #ifdef MICROKIT_CONFIG_benchmark sel4bench_init(); - seL4_Word n_counters = sel4bench_get_num_counters(); + seL4_Word n_counters = sel4bench_get_num_counters(); counter_bitfield_t mask = 0; - for (seL4_Word counter = 0; counter < n_counters; counter++) { if (counter >= ARRAY_SIZE(benchmarking_events)) { break; @@ -301,28 +245,26 @@ void init(void) sddf_dprintf("BENCH|LOG: Bench running in debug mode, no access to counters\n"); #endif - /* Notify the idle thread that the sel4bench library is initialised. */ - microkit_notify(INIT); + microkit_notify(IDLE_INIT); #ifdef CONFIG_BENCHMARK_TRACK_KERNEL_ENTRIES int res_buf = seL4_BenchmarkSetLogBuffer(LOG_BUFFER_CAP); if (res_buf) { - sddf_printf("Could not set log buffer: %llx\n", res_buf); + sddf_printf("BENCH|ERROR: Could not set log buffer: %d\n", res_buf); } else { - sddf_printf("Log buffer set\n"); + sddf_printf("BENCH|LOG: Log buffer set\n"); } #endif } seL4_Bool fault(microkit_child id, microkit_msginfo msginfo, microkit_msginfo *reply_msginfo) { - sddf_printf("BENCH|LOG: Faulting PD "); - print_pdid_name(id); - sddf_printf(" (%x)\n", id); + sddf_printf("BENCH|LOG: Faulting PD %s (%x)\n", pd_id_to_name(id), id); seL4_UserContext regs; seL4_TCB_ReadRegisters(BASE_TCB_CAP + id, false, 0, sizeof(seL4_UserContext) / sizeof(seL4_Word), ®s); - sddf_printf("Registers: \npc : %lx\nspsr : %lx\nx0 : %lx\nx1 : %lx\nx2 : %lx\nx3 : %lx\nx4 : %lx\nx5 : %lx\nx6 : %lx\nx7 : %lx\n", + sddf_printf("Registers: \npc : %lx\nspsr : %lx\nx0 : %lx\nx1 : %lx\n" + "x2 : %lx\nx3 : %lx\nx4 : %lx\nx5 : %lx\nx6 : %lx\nx7 : %lx\n", regs.pc, regs.spsr, regs.x0, regs.x1, regs.x2, regs.x3, regs.x4, regs.x5, regs.x6, regs.x7); switch (microkit_msginfo_get_label(msginfo)) { @@ -353,4 +295,4 @@ seL4_Bool fault(microkit_child id, microkit_msginfo msginfo, microkit_msginfo *r } return seL4_False; -} \ No newline at end of file +} diff --git a/benchmark/idle.c b/benchmark/idle.c index ad30f4180..7907e0c3f 100644 --- a/benchmark/idle.c +++ b/benchmark/idle.c @@ -13,7 +13,6 @@ #define INIT 3 #define MAGIC_CYCLES 150 -uintptr_t cyclecounters_vaddr; struct bench *b; void count_idle(void) @@ -48,6 +47,5 @@ void notified(microkit_channel ch) void init(void) { - b = (void *)cyclecounters_vaddr; return; -} \ No newline at end of file +} diff --git a/drivers/network/imx/ethernet.c b/drivers/network/imx/ethernet.c index 7609daaec..3b5aeec7b 100644 --- a/drivers/network/imx/ethernet.c +++ b/drivers/network/imx/ethernet.c @@ -42,10 +42,11 @@ struct descriptor { /* HW ring buffer data type */ typedef struct { - unsigned int tail; /* index to insert at */ - unsigned int head; /* index to remove from */ + uint32_t tail; /* index to insert at */ + uint32_t head; /* index to remove from */ + uint32_t capacity; /* capacity of the ring */ + volatile struct descriptor *descr; /* buffer descriptor array */ net_buff_desc_t descr_mdata[MAX_COUNT]; /* associated meta data array */ - volatile struct descriptor *descr; /* buffer descripter array */ } hw_ring_t; hw_ring_t rx; /* Rx NIC ring */ @@ -58,14 +59,14 @@ net_queue_handle_t tx_queue; volatile struct enet_regs *eth; -static inline bool hw_ring_full(hw_ring_t *ring, size_t ring_capacity) +static inline bool hw_ring_full(hw_ring_t *ring) { - return !((ring->tail - ring->head + 1) % ring_capacity); + return ring->tail - ring->head == ring->capacity; } -static inline bool hw_ring_empty(hw_ring_t *ring, size_t ring_capacity) +static inline bool hw_ring_empty(hw_ring_t *ring) { - return !((ring->tail - ring->head) % ring_capacity); + return ring->tail - ring->head == 0; } static void update_ring_slot(hw_ring_t *ring, unsigned int idx, uintptr_t phys, @@ -78,7 +79,7 @@ static void update_ring_slot(hw_ring_t *ring, unsigned int idx, uintptr_t phys, /* Ensure all writes to the descriptor complete, before we set the flags * that makes hardware aware of this slot. */ - __sync_synchronize(); + THREAD_MEMORY_RELEASE(); d->stat = stat; } @@ -86,30 +87,31 @@ static void rx_provide(void) { bool reprocess = true; while (reprocess) { - while (!hw_ring_full(&rx, RX_COUNT) && !net_queue_empty_free(&rx_queue)) { + while (!hw_ring_full(&rx) && !net_queue_empty_free(&rx_queue)) { net_buff_desc_t buffer; int err = net_dequeue_free(&rx_queue, &buffer); assert(!err); + uint32_t idx = rx.tail % rx.capacity; uint16_t stat = RXD_EMPTY; - if (rx.tail + 1 == RX_COUNT) { + if (idx + 1 == rx.capacity) { stat |= WRAP; } - rx.descr_mdata[rx.tail] = buffer; - update_ring_slot(&rx, rx.tail, buffer.io_or_offset, 0, stat); - rx.tail = (rx.tail + 1) % RX_COUNT; + rx.descr_mdata[idx] = buffer; + update_ring_slot(&rx, idx, buffer.io_or_offset, 0, stat); + rx.tail++; eth->rdar = RDAR_RDAR; } /* Only request a notification from virtualiser if HW ring not full */ - if (!hw_ring_full(&rx, RX_COUNT)) { + if (!hw_ring_full(&rx)) { net_request_signal_free(&rx_queue); } else { net_cancel_signal_free(&rx_queue); } reprocess = false; - if (!net_queue_empty_free(&rx_queue) && !hw_ring_full(&rx, RX_COUNT)) { + if (!net_queue_empty_free(&rx_queue) && !hw_ring_full(&rx)) { net_cancel_signal_free(&rx_queue); reprocess = true; } @@ -119,20 +121,23 @@ static void rx_provide(void) static void rx_return(void) { bool packets_transferred = false; - while (!hw_ring_empty(&rx, RX_COUNT)) { + while (!hw_ring_empty(&rx)) { /* If buffer slot is still empty, we have processed all packets the device has filled */ - volatile struct descriptor *d = &(rx.descr[rx.head]); + uint32_t idx = rx.head % rx.capacity; + volatile struct descriptor *d = &(rx.descr[idx]); if (d->stat & RXD_EMPTY) { break; } - net_buff_desc_t buffer = rx.descr_mdata[rx.head]; + THREAD_MEMORY_ACQUIRE(); + + net_buff_desc_t buffer = rx.descr_mdata[idx]; buffer.len = d->len; int err = net_enqueue_active(&rx_queue, buffer); assert(!err); packets_transferred = true; - rx.head = (rx.head + 1) % RX_COUNT; + rx.head++; } if (packets_transferred && net_require_signal_active(&rx_queue)) { @@ -145,26 +150,26 @@ static void tx_provide(void) { bool reprocess = true; while (reprocess) { - while (!(hw_ring_full(&tx, TX_COUNT)) && !net_queue_empty_active(&tx_queue)) { + while (!(hw_ring_full(&tx)) && !net_queue_empty_active(&tx_queue)) { net_buff_desc_t buffer; int err = net_dequeue_active(&tx_queue, &buffer); assert(!err); + uint32_t idx = tx.tail % tx.capacity; uint16_t stat = TXD_READY | TXD_ADDCRC | TXD_LAST; - if (tx.tail + 1 == TX_COUNT) { + if (idx + 1 == tx.capacity) { stat |= WRAP; } - tx.descr_mdata[tx.tail] = buffer; - update_ring_slot(&tx, tx.tail, buffer.io_or_offset, buffer.len, stat); - - tx.tail = (tx.tail + 1) % TX_COUNT; + tx.descr_mdata[idx] = buffer; + update_ring_slot(&tx, idx, buffer.io_or_offset, buffer.len, stat); + tx.tail++; eth->tdar = TDAR_TDAR; } net_request_signal_active(&tx_queue); reprocess = false; - if (!hw_ring_full(&tx, TX_COUNT) && !net_queue_empty_active(&tx_queue)) { + if (!hw_ring_full(&tx) && !net_queue_empty_active(&tx_queue)) { net_cancel_signal_active(&tx_queue); reprocess = true; } @@ -174,21 +179,23 @@ static void tx_provide(void) static void tx_return(void) { bool enqueued = false; - while (!hw_ring_empty(&tx, TX_COUNT)) { + while (!hw_ring_empty(&tx)) { /* Ensure that this buffer has been sent by the device */ - volatile struct descriptor *d = &(tx.descr[tx.head]); + uint32_t idx = tx.head % tx.capacity; + volatile struct descriptor *d = &(tx.descr[idx]); if (d->stat & TXD_READY) { break; } - net_buff_desc_t buffer = tx.descr_mdata[tx.head]; - buffer.len = 0; - - tx.head = (tx.head + 1) % TX_COUNT; + THREAD_MEMORY_ACQUIRE(); + net_buff_desc_t buffer = tx.descr_mdata[idx]; + buffer.len = 0; int err = net_enqueue_free(&tx_queue, buffer); assert(!err); + enqueued = true; + tx.head++; } if (enqueued && net_require_signal_free(&tx_queue)) { @@ -225,7 +232,9 @@ static void eth_setup(void) uint32_t h = eth->paur; /* Set up HW rings */ + rx.capacity = RX_COUNT; rx.descr = (volatile struct descriptor *)hw_ring_buffer_vaddr; + tx.capacity = TX_COUNT; tx.descr = (volatile struct descriptor *)(hw_ring_buffer_vaddr + (sizeof(struct descriptor) * RX_COUNT)); /* Perform reset */ @@ -269,14 +278,13 @@ static void eth_setup(void) eth->tipg = TIPG; /* Transmit FIFO Watermark register - store and forward */ eth->tfwr = STRFWD; - /* clear rx store and forward. This must be done for hardware csums*/ + /* clear rx store and forward. This must be done for hardware csums */ eth->rsfl = 0; /* Do not forward frames with errors + check the csum */ eth->racc = RACC_LINEDIS | RACC_IPDIS | RACC_PRODIS; /* Add the checksum for known IP protocols */ eth->tacc = TACC_PROCHK | TACC_IPCHK; - /* Set RDSR */ eth->rdsr = hw_ring_buffer_paddr; eth->tdsr = hw_ring_buffer_paddr + (sizeof(struct descriptor) * RX_COUNT); diff --git a/drivers/network/meson/ethernet.c b/drivers/network/meson/ethernet.c index 6eb8999b9..75120651e 100644 --- a/drivers/network/meson/ethernet.c +++ b/drivers/network/meson/ethernet.c @@ -44,10 +44,11 @@ _Static_assert((RX_COUNT + TX_COUNT) * sizeof(struct descriptor) <= NET_HW_REGIO "Expect rx+tx buffers to fit in single 2MB page"); typedef struct { - unsigned int tail; /* index to insert at */ - unsigned int head; /* index to remove from */ + uint32_t tail; /* index to insert at */ + uint32_t head; /* index to remove from */ + uint32_t capacity; /* capacity of the ring */ + volatile struct descriptor *descr; /* buffer descriptor array */ net_buff_desc_t descr_mdata[MAX_COUNT]; /* associated meta data array */ - volatile struct descriptor *descr; /* buffer descripter array */ } hw_ring_t; hw_ring_t rx; @@ -59,14 +60,14 @@ net_queue_handle_t tx_queue; volatile struct eth_mac_regs *eth_mac; volatile struct eth_dma_regs *eth_dma; -static inline bool hw_ring_full(hw_ring_t *ring, size_t ring_capacity) +static inline bool hw_ring_full(hw_ring_t *ring) { - return !((ring->tail + 2 - ring->head) % ring_capacity); + return ring->tail - ring->head == ring->capacity; } -static inline bool hw_ring_empty(hw_ring_t *ring, size_t ring_capacity) +static inline bool hw_ring_empty(hw_ring_t *ring) { - return !((ring->tail - ring->head) % ring_capacity); + return ring->tail - ring->head == 0; } static void update_ring_slot(hw_ring_t *ring, unsigned int idx, uint32_t status, @@ -87,27 +88,28 @@ static void rx_provide() { bool reprocess = true; while (reprocess) { - while (!hw_ring_full(&rx, RX_COUNT) && !net_queue_empty_free(&rx_queue)) { + while (!hw_ring_full(&rx) && !net_queue_empty_free(&rx_queue)) { net_buff_desc_t buffer; int err = net_dequeue_free(&rx_queue, &buffer); assert(!err); + uint32_t idx = rx.tail % rx.capacity; uint32_t cntl = (MAX_RX_FRAME_SZ << DESC_RXCTRL_SIZE1SHFT) & DESC_RXCTRL_SIZE1MASK; - if (rx.tail + 1 == RX_COUNT) { + if (idx + 1 == rx.capacity) { cntl |= DESC_RXCTRL_RXRINGEND; } - rx.descr_mdata[rx.tail] = buffer; - update_ring_slot(&rx, rx.tail, DESC_RXSTS_OWNBYDMA, cntl, buffer.io_or_offset, 0); + rx.descr_mdata[idx] = buffer; + update_ring_slot(&rx, idx, DESC_RXSTS_OWNBYDMA, cntl, buffer.io_or_offset, 0); eth_dma->rxpolldemand = POLL_DATA; - rx.tail = (rx.tail + 1) % RX_COUNT; + rx.tail++; } net_request_signal_free(&rx_queue); reprocess = false; - if (!net_queue_empty_free(&rx_queue) && !hw_ring_full(&rx, RX_COUNT)) { + if (!net_queue_empty_free(&rx_queue) && !hw_ring_full(&rx)) { net_cancel_signal_free(&rx_queue); reprocess = true; } @@ -117,33 +119,36 @@ static void rx_provide() static void rx_return(void) { bool packets_transferred = false; - while (!hw_ring_empty(&rx, RX_COUNT)) { + while (!hw_ring_empty(&rx)) { /* If buffer slot is still empty, we have processed all packets the device has filled */ - volatile struct descriptor *d = &(rx.descr[rx.head]); + uint32_t idx = rx.head % rx.capacity; + volatile struct descriptor *d = &(rx.descr[idx]); if (d->status & DESC_RXSTS_OWNBYDMA) { break; } - net_buff_desc_t buffer = rx.descr_mdata[rx.head]; + THREAD_MEMORY_ACQUIRE(); + net_buff_desc_t buffer = rx.descr_mdata[idx]; if (d->status & DESC_RXSTS_ERROR) { sddf_dprintf("ETH|ERROR: RX descriptor returned with error status %x\n", d->status); + idx = rx.tail % rx.capacity; uint32_t cntl = (MAX_RX_FRAME_SZ << DESC_RXCTRL_SIZE1SHFT) & DESC_RXCTRL_SIZE1MASK; - if (rx.tail + 1 == RX_COUNT) { + if (idx + 1 == rx.capacity) { cntl |= DESC_RXCTRL_RXRINGEND; } - rx.descr_mdata[rx.tail] = buffer; - update_ring_slot(&rx, rx.tail, DESC_RXSTS_OWNBYDMA, cntl, buffer.io_or_offset, 0); + rx.descr_mdata[idx] = buffer; + update_ring_slot(&rx, idx, DESC_RXSTS_OWNBYDMA, cntl, buffer.io_or_offset, 0); eth_dma->rxpolldemand = POLL_DATA; - rx.tail = (rx.tail + 1) % RX_COUNT; + rx.tail++; } else { buffer.len = (d->status & DESC_RXSTS_LENMSK) >> DESC_RXSTS_LENSHFT; int err = net_enqueue_active(&rx_queue, buffer); assert(!err); packets_transferred = true; } - rx.head = (rx.head + 1) % RX_COUNT; + rx.head++; } if (packets_transferred && net_require_signal_active(&rx_queue)) { @@ -156,26 +161,27 @@ static void tx_provide(void) { bool reprocess = true; while (reprocess) { - while (!(hw_ring_full(&tx, TX_COUNT)) && !net_queue_empty_active(&tx_queue)) { + while (!(hw_ring_full(&tx)) && !net_queue_empty_active(&tx_queue)) { net_buff_desc_t buffer; int err = net_dequeue_active(&tx_queue, &buffer); assert(!err); + uint32_t idx = tx.tail % tx.capacity; uint32_t cntl = (((uint32_t) buffer.len) << DESC_TXCTRL_SIZE1SHFT) & DESC_TXCTRL_SIZE1MASK; cntl |= DESC_TXCTRL_TXLAST | DESC_TXCTRL_TXFIRST | DESC_TXCTRL_TXINT; - if (tx.tail + 1 == TX_COUNT) { + if (idx + 1 == tx.capacity) { cntl |= DESC_TXCTRL_TXRINGEND; } - tx.descr_mdata[tx.tail] = buffer; - update_ring_slot(&tx, tx.tail, DESC_TXSTS_OWNBYDMA, cntl, buffer.io_or_offset, 0); + tx.descr_mdata[idx] = buffer; + update_ring_slot(&tx, idx, DESC_TXSTS_OWNBYDMA, cntl, buffer.io_or_offset, 0); - tx.tail = (tx.tail + 1) % TX_COUNT; + tx.tail++; } net_request_signal_active(&tx_queue); reprocess = false; - if (!hw_ring_full(&tx, TX_COUNT) && !net_queue_empty_active(&tx_queue)) { + if (!hw_ring_full(&tx) && !net_queue_empty_active(&tx_queue)) { net_cancel_signal_active(&tx_queue); reprocess = true; } @@ -186,19 +192,21 @@ static void tx_provide(void) static void tx_return(void) { bool enqueued = false; - while (!hw_ring_empty(&tx, TX_COUNT)) { + while (!hw_ring_empty(&tx)) { /* Ensure that this buffer has been sent by the device */ - volatile struct descriptor *d = &(tx.descr[tx.head]); + uint32_t idx = tx.head % tx.capacity; + volatile struct descriptor *d = &(tx.descr[idx]); if (d->status & DESC_TXSTS_OWNBYDMA) { break; } - net_buff_desc_t buffer = tx.descr_mdata[tx.head]; + THREAD_MEMORY_ACQUIRE(); + net_buff_desc_t buffer = tx.descr_mdata[idx]; int err = net_enqueue_free(&tx_queue, buffer); assert(!err); enqueued = true; - tx.head = (tx.head + 1) % TX_COUNT; + tx.head++; } if (enqueued && net_require_signal_free(&tx_queue)) { @@ -238,7 +246,9 @@ static void eth_setup(void) assert((hw_ring_buffer_paddr & 0xFFFFFFFF) == hw_ring_buffer_paddr); + rx.capacity = RX_COUNT; rx.descr = (volatile struct descriptor *)hw_ring_buffer_vaddr; + tx.capacity = TX_COUNT; tx.descr = (volatile struct descriptor *)(hw_ring_buffer_vaddr + (sizeof(struct descriptor) * RX_COUNT)); /* Perform reset */ diff --git a/examples/echo_server/Makefile b/examples/echo_server/Makefile index e7376ac71..432702ca8 100644 --- a/examples/echo_server/Makefile +++ b/examples/echo_server/Makefile @@ -24,11 +24,23 @@ ifeq ($(strip $(MICROKIT_BOARD)), odroidc4) export UART_DRIV_DIR := meson export TIMER_DRV_DIR := meson export CPU := cortex-a55 +else ifeq ($(strip $(MICROKIT_BOARD)), odroidc4_4_cores) + export DRIV_DIR := meson + export UART_DRIV_DIR := meson + export TIMER_DRV_DIR := meson + export CPU := cortex-a55 + export CONFIG_INCLUDE_SMP := _smp else ifneq ($(filter $(strip $(MICROKIT_BOARD)),imx8mm_evk imx8mp_evk maaxboard),) export DRIV_DIR := imx export UART_DRIV_DIR := imx export TIMER_DRV_DIR := imx export CPU := cortex-a53 +else ifeq ($(strip $(MICROKIT_BOARD)), imx8mm_evk_4_cores) + export DRIV_DIR := imx + export UART_DRIV_DIR := imx + export TIMER_DRV_DIR := imx + export CPU := cortex-a53 + export CONFIG_INCLUDE_SMP := _smp else ifeq ($(strip $(MICROKIT_BOARD)), qemu_virt_aarch64) export DRIV_DIR := virtio export UART_DRIV_DIR := arm diff --git a/examples/echo_server/board/imx8mm_evk/echo_server.system b/examples/echo_server/board/imx8mm_evk/echo_server.system index 264e4e867..8972117a6 100644 --- a/examples/echo_server/board/imx8mm_evk/echo_server.system +++ b/examples/echo_server/board/imx8mm_evk/echo_server.system @@ -60,10 +60,10 @@ - + - + @@ -177,7 +177,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -264,17 +264,17 @@ - + - + - + diff --git a/examples/echo_server/board/imx8mm_evk_4_cores/echo_server.system b/examples/echo_server/board/imx8mm_evk_4_cores/echo_server.system new file mode 100644 index 000000000..ab03df33c --- /dev/null +++ b/examples/echo_server/board/imx8mm_evk_4_cores/echo_server.system @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ethernet interrupt --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/echo_server/board/imx8mp_evk/echo_server.system b/examples/echo_server/board/imx8mp_evk/echo_server.system index 264e4e867..8972117a6 100644 --- a/examples/echo_server/board/imx8mp_evk/echo_server.system +++ b/examples/echo_server/board/imx8mp_evk/echo_server.system @@ -60,10 +60,10 @@ - + - + @@ -177,7 +177,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -264,17 +264,17 @@ - + - + - + diff --git a/examples/echo_server/board/maaxboard/echo_server.system b/examples/echo_server/board/maaxboard/echo_server.system index 05e1d7684..acdf5ed7f 100644 --- a/examples/echo_server/board/maaxboard/echo_server.system +++ b/examples/echo_server/board/maaxboard/echo_server.system @@ -60,10 +60,10 @@ - + - + @@ -177,7 +177,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -264,17 +264,17 @@ - + - + - + diff --git a/examples/echo_server/board/odroidc4/echo_server.system b/examples/echo_server/board/odroidc4/echo_server.system index 74998d981..d0cb78834 100644 --- a/examples/echo_server/board/odroidc4/echo_server.system +++ b/examples/echo_server/board/odroidc4/echo_server.system @@ -60,10 +60,10 @@ - + - + @@ -177,7 +177,7 @@ - + @@ -219,7 +219,7 @@ - + @@ -264,17 +264,17 @@ - + - + - + diff --git a/examples/echo_server/board/odroidc4_4_cores/echo_server.system b/examples/echo_server/board/odroidc4_4_cores/echo_server.system new file mode 100644 index 000000000..5636da798 --- /dev/null +++ b/examples/echo_server/board/odroidc4_4_cores/echo_server.system @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ethernet interrupt --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/echo_server/board/qemu_virt_aarch64/echo_server.system b/examples/echo_server/board/qemu_virt_aarch64/echo_server.system index 1cacbb3c9..c2cb5a834 100644 --- a/examples/echo_server/board/qemu_virt_aarch64/echo_server.system +++ b/examples/echo_server/board/qemu_virt_aarch64/echo_server.system @@ -59,10 +59,10 @@ - + - + @@ -176,7 +176,7 @@ - + @@ -217,7 +217,7 @@ - + @@ -262,17 +262,17 @@ - + - + - + diff --git a/examples/echo_server/echo.mk b/examples/echo_server/echo.mk index bf5e3a67c..fa9add691 100644 --- a/examples/echo_server/echo.mk +++ b/examples/echo_server/echo.mk @@ -7,19 +7,24 @@ QEMU := qemu-system-aarch64 MICROKIT_TOOL ?= $(MICROKIT_SDK)/bin/microkit -ECHO_SERVER:=${SDDF}/examples/echo_server -LWIPDIR:=network/ipstacks/lwip/src +BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) +ECHO_SERVER:=$(SDDF)/examples/echo_server + BENCHMARK:=$(SDDF)/benchmark -UTIL:=$(SDDF)/util +CORE_CONFIG_INCLUDE:=$(ECHO_SERVER)/include/core_config$(CONFIG_INCLUDE_SMP) + +LWIPDIR:=network/ipstacks/lwip/src +NETWORK_COMPONENTS:=$(SDDF)/network/components ETHERNET_DRIVER:=$(SDDF)/drivers/network/$(DRIV_DIR) -ETHERNET_CONFIG_INCLUDE:=${ECHO_SERVER}/include/ethernet_config +ETHERNET_CONFIG_INCLUDE:=$(ECHO_SERVER)/include/ethernet_config + SERIAL_COMPONENTS := $(SDDF)/serial/components UART_DRIVER := $(SDDF)/drivers/serial/$(UART_DRIV_DIR) -SERIAL_CONFIG_INCLUDE:=${ECHO_SERVER}/include/serial_config +SERIAL_CONFIG_INCLUDE:=$(ECHO_SERVER)/include/serial_config$(CONFIG_INCLUDE_SMP) + TIMER_DRIVER:=$(SDDF)/drivers/timer/$(TIMER_DRV_DIR) -NETWORK_COMPONENTS:=$(SDDF)/network/components +UTIL:=$(SDDF)/util -BOARD_DIR := $(MICROKIT_SDK)/board/$(MICROKIT_BOARD)/$(MICROKIT_CONFIG) SYSTEM_FILE := ${ECHO_SERVER}/board/$(MICROKIT_BOARD)/echo_server.system IMAGE_FILE := loader.img REPORT_FILE := report.txt @@ -37,11 +42,12 @@ CFLAGS := -mcpu=$(CPU) \ -DMICROKIT_CONFIG_$(MICROKIT_CONFIG) \ -I$(BOARD_DIR)/include \ -I$(SDDF)/include \ - -I${ECHO_INCLUDE}/lwip \ - -I${ETHERNET_CONFIG_INCLUDE} \ + -I$(ECHO_INCLUDE)/lwip \ + -I$(CORE_CONFIG_INCLUDE) \ + -I$(ETHERNET_CONFIG_INCLUDE) \ -I$(SERIAL_CONFIG_INCLUDE) \ - -I${SDDF}/$(LWIPDIR)/include \ - -I${SDDF}/$(LWIPDIR)/include/ipv4 \ + -I$(SDDF)/$(LWIPDIR)/include \ + -I$(SDDF)/$(LWIPDIR)/include/ipv4 \ -MD \ -MP diff --git a/examples/echo_server/include/core_config/core_config.h b/examples/echo_server/include/core_config/core_config.h new file mode 100644 index 000000000..5f3748b08 --- /dev/null +++ b/examples/echo_server/include/core_config/core_config.h @@ -0,0 +1,97 @@ +/* + * Copyright 2024, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +/* Total number of cores on the board. */ +#define MAX_CORES 4 + +/* Total number of PDs being tracked during the benchmark. */ +#define NUM_PDS_TO_TRACK 8 + +/* The core of the benchmark PD which is last in the notification chain. + The benchmark PD on this core receives START and STOP notifications, + but does not send them. */ +#define LAST_CORE 0 + +typedef struct { + uint16_t pd_id; /* ID of the PD. */ + uint16_t pd_core; /* Core of the PD. */ + char *pd_name; /* Name of the PD. */ +} pd_core_info_t; + +pd_core_info_t pd_core_info[NUM_PDS_TO_TRACK] = { + { 1, 0, NET_DRIVER_NAME }, /* Ethernet driver. */ + { 2, 0, NET_VIRT_RX_NAME }, /* Rx virtualiser. */ + { 3, 0, NET_VIRT_TX_NAME }, /* Tx virtualiser. */ + { 4, 0, NET_COPY0_NAME }, /* Copy component 0. */ + { 5, 0, NET_COPY1_NAME }, /* Copy component 1. */ + { 6, 0, NET_CLI0_NAME }, /* LWIP client 0. */ + { 7, 0, NET_CLI1_NAME }, /* LWIP client 1. */ + { 8, 0, NET_TIMER_NAME } /* Timer driver. */ +}; + +typedef struct { + uint64_t core_bitmap; /* Bitmap of client IDs on this core. */ + uint32_t core_value; /* Core of this benchmark process. */ + uint32_t max_core_id; /* Maximum ID of client on this core. */ + bool last_core; /* Whether this bench process is the last in the notification chain. */ +} core_config_t; + +static void bench_core_config_info(char *pd_name, core_config_t *core_config) +{ + core_config->max_core_id = 0; + core_config->last_core = false; + + if (!sddf_strcmp(pd_name, "bench0")) { + core_config->core_value = 0; + } else if (!sddf_strcmp(pd_name, "bench1")) { + core_config->core_value = 1; + } else if (!sddf_strcmp(pd_name, "bench2")) { + core_config->core_value = 2; + } else if (!sddf_strcmp(pd_name, "bench3")) { + core_config->core_value = 3; + } else { + return; + } + + if (core_config->core_value == LAST_CORE) { + core_config->last_core = true; + } + + for (uint16_t i = 0; i < NUM_PDS_TO_TRACK; i++) { + if (pd_core_info[i].pd_core == core_config->core_value) { + core_config->core_bitmap |= (1 << pd_core_info[i].pd_id); + if (pd_core_info[i].pd_id > core_config->max_core_id) { + core_config->max_core_id = pd_core_info[i].pd_id; + } + } + } +} + +static uint16_t bench_active_cores() +{ + uint16_t active_cores = 0; + for (uint16_t i = 0; i < NUM_PDS_TO_TRACK; i++) { + active_cores |= (1 << pd_core_info[i].pd_core); + } + + return active_cores; +} + +static char *pd_id_to_name(uint16_t pd_id) +{ + for (uint16_t i = 0; i < NUM_PDS_TO_TRACK; i++) { + if (pd_core_info[i].pd_id == pd_id) { + return pd_core_info[i].pd_name; + } + } + + return NULL; +} diff --git a/examples/echo_server/include/core_config_smp/core_config.h b/examples/echo_server/include/core_config_smp/core_config.h new file mode 100644 index 000000000..de28138bc --- /dev/null +++ b/examples/echo_server/include/core_config_smp/core_config.h @@ -0,0 +1,97 @@ +/* + * Copyright 2024, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +/* Total number of cores on the board. */ +#define MAX_CORES 4 + +/* Total number of PDs being tracked during the benchmark. */ +#define NUM_PDS_TO_TRACK 8 + +/* The core of the benchmark PD which is last in the notification chain. + The benchmark PD on this core receives START and STOP notifications, + but does not send them. */ +#define LAST_CORE 1 + +typedef struct { + uint16_t pd_id; /* ID of the PD. */ + uint16_t pd_core; /* Core of the PD. */ + char *pd_name; /* Name of the PD. */ +} pd_core_info_t; + +pd_core_info_t pd_core_info[NUM_PDS_TO_TRACK] = { + { 1, 0, NET_DRIVER_NAME }, /* Ethernet driver. */ + { 2, 1, NET_VIRT_RX_NAME }, /* Rx virtualiser. */ + { 3, 0, NET_VIRT_TX_NAME }, /* Tx virtualiser. */ + { 4, 1, NET_COPY0_NAME }, /* Copy component 0. */ + { 5, 1, NET_COPY1_NAME }, /* Copy component 1. */ + { 6, 1, NET_CLI0_NAME }, /* LWIP client 0. */ + { 7, 1, NET_CLI1_NAME }, /* LWIP client 1. */ + { 8, 1, NET_TIMER_NAME } /* Timer driver. */ +}; + +typedef struct { + uint64_t core_bitmap; /* Bitmap of client IDs on this core. */ + uint32_t core_value; /* Core of this benchmark process. */ + uint32_t max_core_id; /* Maximum ID of client on this core. */ + bool last_core; /* Whether this bench process is the last in the notification chain. */ +} core_config_t; + +static void bench_core_config_info(char *pd_name, core_config_t *core_config) +{ + core_config->max_core_id = 0; + core_config->last_core = false; + + if (!sddf_strcmp(pd_name, "bench0")) { + core_config->core_value = 0; + } else if (!sddf_strcmp(pd_name, "bench1")) { + core_config->core_value = 1; + } else if (!sddf_strcmp(pd_name, "bench2")) { + core_config->core_value = 2; + } else if (!sddf_strcmp(pd_name, "bench3")) { + core_config->core_value = 3; + } else { + return; + } + + if (core_config->core_value == LAST_CORE) { + core_config->last_core = true; + } + + for (uint16_t i = 0; i < NUM_PDS_TO_TRACK; i++) { + if (pd_core_info[i].pd_core == core_config->core_value) { + core_config->core_bitmap |= (1 << pd_core_info[i].pd_id); + if (pd_core_info[i].pd_id > core_config->max_core_id) { + core_config->max_core_id = pd_core_info[i].pd_id; + } + } + } +} + +static uint16_t bench_active_cores() +{ + uint16_t active_cores = 0; + for (uint16_t i = 0; i < NUM_PDS_TO_TRACK; i++) { + active_cores |= (1 << pd_core_info[i].pd_core); + } + + return active_cores; +} + +static char *pd_id_to_name(uint16_t pd_id) +{ + for (uint16_t i = 0; i < NUM_PDS_TO_TRACK; i++) { + if (pd_core_info[i].pd_id == pd_id) { + return pd_core_info[i].pd_name; + } + } + + return NULL; +} diff --git a/examples/echo_server/include/serial_config/serial_config.h b/examples/echo_server/include/serial_config/serial_config.h index cd0e744a0..d49d7c424 100644 --- a/examples/echo_server/include/serial_config/serial_config.h +++ b/examples/echo_server/include/serial_config/serial_config.h @@ -11,7 +11,7 @@ #include /* Number of clients that can be connected to the serial server. */ -#define SERIAL_NUM_CLIENTS 3 +#define NUM_SERIAL_CLIENTS 3 /* Only support transmission and not receive. */ #define SERIAL_TX_ONLY 1 @@ -30,7 +30,7 @@ #define SERIAL_CLI0_NAME "client0" #define SERIAL_CLI1_NAME "client1" -#define SERIAL_CLI2_NAME "bench" +#define SERIAL_CLI2_NAME "bench0" #define SERIAL_VIRT_TX_NAME "serial_virt_tx" #define SERIAL_QUEUE_SIZE 0x1000 @@ -41,47 +41,63 @@ #define SERIAL_TX_DATA_REGION_CAPACITY_CLI1 SERIAL_DATA_REGION_CAPACITY #define SERIAL_TX_DATA_REGION_CAPACITY_CLI2 SERIAL_DATA_REGION_CAPACITY +/* To avoid deadlocks caused when the virtualiser adds colour codes to the + start and end of strings, driver data region must be larger than any + client data region. */ #define SERIAL_MAX_CLIENT_TX_DATA_CAPACITY MAX(SERIAL_TX_DATA_REGION_CAPACITY_CLI2, MAX(SERIAL_TX_DATA_REGION_CAPACITY_CLI0, SERIAL_TX_DATA_REGION_CAPACITY_CLI1)) #if SERIAL_WITH_COLOUR _Static_assert(SERIAL_TX_DATA_REGION_CAPACITY_DRIV > SERIAL_MAX_CLIENT_TX_DATA_CAPACITY, "Driver TX data region must be larger than all client data regions in SERIAL_WITH_COLOUR mode."); #endif +/* Ensure the entire data region can be assigned a unique index by a 32 bit + unsigned. */ #define SERIAL_MAX_DATA_CAPACITY MAX(SERIAL_TX_DATA_REGION_CAPACITY_DRIV, SERIAL_MAX_CLIENT_TX_DATA_CAPACITY) _Static_assert(SERIAL_MAX_DATA_CAPACITY < UINT32_MAX, "Data regions must be smaller than UINT32 max to correctly use queue data structure."); -static inline void serial_cli_queue_init_sys(char *pd_name, serial_queue_handle_t *rx_queue_handle, - serial_queue_t *rx_queue, - char *rx_data, serial_queue_handle_t *tx_queue_handle, serial_queue_t *tx_queue, char *tx_data) +static inline void serial_cli_data_capacity(char *pd_name, uint32_t *rx_data_capacity, uint32_t *tx_data_capacity) { if (!sddf_strcmp(pd_name, SERIAL_CLI0_NAME)) { - serial_queue_init(tx_queue_handle, tx_queue, SERIAL_TX_DATA_REGION_CAPACITY_CLI0, tx_data); + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI0; } else if (!sddf_strcmp(pd_name, SERIAL_CLI1_NAME)) { - serial_queue_init(tx_queue_handle, tx_queue, SERIAL_TX_DATA_REGION_CAPACITY_CLI1, tx_data); + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI1; } else if (!sddf_strcmp(pd_name, SERIAL_CLI2_NAME)) { - serial_queue_init(tx_queue_handle, tx_queue, SERIAL_TX_DATA_REGION_CAPACITY_CLI2, tx_data); + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI2; } } -static inline void serial_virt_queue_init_sys(char *pd_name, serial_queue_handle_t *cli_queue_handle, - serial_queue_t *cli_queue, char *cli_data) +typedef struct serial_queue_info { + serial_queue_t *cli_queue; + char *cli_data; + uint32_t capacity; +} serial_queue_info_t; + +static inline void serial_virt_queue_info(char *pd_name, serial_queue_t *cli_queue, char *cli_data, + serial_queue_info_t ret[NUM_SERIAL_CLIENTS]) { if (!sddf_strcmp(pd_name, SERIAL_VIRT_TX_NAME)) { - serial_queue_init(cli_queue_handle, cli_queue, SERIAL_TX_DATA_REGION_CAPACITY_CLI0, cli_data); - serial_queue_init(&cli_queue_handle[1], (serial_queue_t *)((uintptr_t)cli_queue + SERIAL_QUEUE_SIZE), - SERIAL_TX_DATA_REGION_CAPACITY_CLI1, cli_data + SERIAL_TX_DATA_REGION_CAPACITY_CLI0); - serial_queue_init(&cli_queue_handle[2], (serial_queue_t *)((uintptr_t)cli_queue + 2 * SERIAL_QUEUE_SIZE), - SERIAL_TX_DATA_REGION_CAPACITY_CLI2, - cli_data + SERIAL_TX_DATA_REGION_CAPACITY_CLI0 + SERIAL_TX_DATA_REGION_CAPACITY_CLI1); + ret[0] = (serial_queue_info_t) { .cli_queue = cli_queue, + .cli_data = cli_data, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI0 }; + ret[1] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[0].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[0].cli_data + ret[0].capacity, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI1 }; + ret[2] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[1].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[1].cli_data + ret[1].capacity, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI2 }; } } #if SERIAL_WITH_COLOUR -static inline void serial_channel_names_init(char **client_names) +static inline void serial_channel_names_init(char *pd_name, char *client_names[NUM_SERIAL_CLIENTS]) { - client_names[0] = SERIAL_CLI0_NAME; - client_names[1] = SERIAL_CLI1_NAME; - client_names[2] = SERIAL_CLI2_NAME; + if (!sddf_strcmp(pd_name, SERIAL_VIRT_TX_NAME)) { + client_names[0] = SERIAL_CLI0_NAME; + client_names[1] = SERIAL_CLI1_NAME; + client_names[2] = SERIAL_CLI2_NAME; + } } #endif diff --git a/examples/echo_server/include/serial_config_smp/serial_config.h b/examples/echo_server/include/serial_config_smp/serial_config.h new file mode 100644 index 000000000..98df83bfd --- /dev/null +++ b/examples/echo_server/include/serial_config_smp/serial_config.h @@ -0,0 +1,130 @@ +/* + * Copyright 2024, UNSW + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +/* Number of clients that can be connected to the serial server. */ +#define NUM_SERIAL_CLIENTS 6 + +/* Only support transmission and not receive. */ +#define SERIAL_TX_ONLY 1 + +/* Associate a colour with each client's output. */ +#define SERIAL_WITH_COLOUR 1 + +/* Control character to switch input stream - ctrl \. To input character input twice. */ +#define SERIAL_SWITCH_CHAR 28 + +/* Control character to terminate client number input. */ +#define SERIAL_TERMINATE_NUM '\r' + +/* Default baud rate of the uart device */ +#define UART_DEFAULT_BAUD 115200 + +#define SERIAL_CLI0_NAME "client0" +#define SERIAL_CLI1_NAME "client1" +#define SERIAL_CLI2_NAME "bench0" +#define SERIAL_CLI3_NAME "bench1" +#define SERIAL_CLI4_NAME "bench2" +#define SERIAL_CLI5_NAME "bench3" +#define SERIAL_VIRT_TX_NAME "serial_virt_tx" + +#define SERIAL_QUEUE_SIZE 0x1000 +#define SERIAL_DATA_REGION_CAPACITY 0x2000 + +#define SERIAL_TX_DATA_REGION_CAPACITY_DRIV (2 * SERIAL_DATA_REGION_CAPACITY) +#define SERIAL_TX_DATA_REGION_CAPACITY_CLI0 SERIAL_DATA_REGION_CAPACITY +#define SERIAL_TX_DATA_REGION_CAPACITY_CLI1 SERIAL_DATA_REGION_CAPACITY +#define SERIAL_TX_DATA_REGION_CAPACITY_CLI2 SERIAL_DATA_REGION_CAPACITY +#define SERIAL_TX_DATA_REGION_CAPACITY_CLI3 SERIAL_DATA_REGION_CAPACITY +#define SERIAL_TX_DATA_REGION_CAPACITY_CLI4 SERIAL_DATA_REGION_CAPACITY +#define SERIAL_TX_DATA_REGION_CAPACITY_CLI5 SERIAL_DATA_REGION_CAPACITY + +/* To avoid deadlocks caused when the virtualiser adds colour codes to the + start and end of strings, driver data region must be larger than any + client data region. */ +#define SERIAL_MAX_CLIENT_TX_DATA_CAPACITY SERIAL_DATA_REGION_CAPACITY +#if SERIAL_WITH_COLOUR +_Static_assert(SERIAL_TX_DATA_REGION_CAPACITY_DRIV > SERIAL_MAX_CLIENT_TX_DATA_CAPACITY, + "Driver TX data region must be larger than all client data regions in SERIAL_WITH_COLOUR mode."); +#endif + +/* Ensure the entire data region can be assigned a unique index by a 32 bit + unsigned. */ +#define SERIAL_MAX_DATA_CAPACITY MAX(SERIAL_TX_DATA_REGION_CAPACITY_DRIV, SERIAL_MAX_CLIENT_TX_DATA_CAPACITY) +_Static_assert(SERIAL_MAX_DATA_CAPACITY < UINT32_MAX, + "Data regions must be smaller than UINT32 max to correctly use queue data structure."); + +static inline void serial_cli_data_capacity(char *pd_name, uint32_t *rx_data_capacity, uint32_t *tx_data_capacity) +{ + if (!sddf_strcmp(pd_name, SERIAL_CLI0_NAME)) { + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI0; + } else if (!sddf_strcmp(pd_name, SERIAL_CLI1_NAME)) { + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI1; + } else if (!sddf_strcmp(pd_name, SERIAL_CLI2_NAME)) { + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI2; + } else if (!sddf_strcmp(pd_name, SERIAL_CLI3_NAME)) { + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI3; + } else if (!sddf_strcmp(pd_name, SERIAL_CLI4_NAME)) { + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI4; + } else if (!sddf_strcmp(pd_name, SERIAL_CLI5_NAME)) { + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI5; + } +} + +typedef struct serial_queue_info { + serial_queue_t *cli_queue; + char *cli_data; + uint32_t capacity; +} serial_queue_info_t; + +static inline void serial_virt_queue_info(char *pd_name, serial_queue_t *cli_queue, char *cli_data, + serial_queue_info_t ret[NUM_SERIAL_CLIENTS]) +{ + if (!sddf_strcmp(pd_name, SERIAL_VIRT_TX_NAME)) { + ret[0] = (serial_queue_info_t) { .cli_queue = cli_queue, + .cli_data = cli_data, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI0 }; + ret[1] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[0].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[0].cli_data + ret[0].capacity, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI1 }; + ret[2] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[1].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[1].cli_data + ret[1].capacity, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI2 }; + ret[3] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[2].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[2].cli_data + ret[2].capacity, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI3 }; + ret[4] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[3].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[3].cli_data + ret[3].capacity, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI4 }; + ret[5] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[4].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[4].cli_data + ret[4].capacity, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI5 }; + } +} + +#if SERIAL_WITH_COLOUR +static inline void serial_channel_names_init(char *pd_name, char *client_names[NUM_SERIAL_CLIENTS]) +{ + if (!sddf_strcmp(pd_name, SERIAL_VIRT_TX_NAME)) { + client_names[0] = SERIAL_CLI0_NAME; + client_names[1] = SERIAL_CLI1_NAME; + client_names[2] = SERIAL_CLI2_NAME; + client_names[3] = SERIAL_CLI3_NAME; + client_names[4] = SERIAL_CLI4_NAME; + client_names[5] = SERIAL_CLI5_NAME; + } +} +#endif diff --git a/examples/echo_server/lwip.c b/examples/echo_server/lwip.c index 54bfe0b29..119369a7b 100644 --- a/examples/echo_server/lwip.c +++ b/examples/echo_server/lwip.c @@ -286,13 +286,15 @@ static void netif_status_callback(struct netif *netif) void init(void) { - serial_cli_queue_init_sys(microkit_name, NULL, NULL, NULL, &serial_tx_queue_handle, serial_tx_queue, serial_tx_data); + uint32_t serial_tx_data_capacity; + serial_cli_data_capacity(microkit_name, NULL, &serial_tx_data_capacity); + serial_queue_init(&serial_tx_queue_handle, serial_tx_queue, serial_tx_data_capacity, serial_tx_data); serial_putchar_init(SERIAL_TX_CH, &serial_tx_queue_handle); - size_t rx_capacity, tx_capacity; - net_cli_queue_capacity(microkit_name, &rx_capacity, &tx_capacity); - net_queue_init(&state.rx_queue, rx_free, rx_active, rx_capacity); - net_queue_init(&state.tx_queue, tx_free, tx_active, tx_capacity); + size_t net_rx_capacity, net_tx_capacity; + net_cli_queue_capacity(microkit_name, &net_rx_capacity, &net_tx_capacity); + net_queue_init(&state.rx_queue, rx_free, rx_active, net_rx_capacity); + net_queue_init(&state.tx_queue, tx_free, tx_active, net_tx_capacity); net_buffers_init(&state.tx_queue, 0); lwip_init(); diff --git a/examples/echo_server/utilization_socket.c b/examples/echo_server/utilization_socket.c index c69dde1b0..64c9ded72 100644 --- a/examples/echo_server/utilization_socket.c +++ b/examples/echo_server/utilization_socket.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "echo.h" @@ -21,8 +22,6 @@ #define MAX_PACKET_SIZE 0x1000 -uintptr_t cyclecounters_vaddr; - /* This file implements a TCP based utilization measurment process that starts * and stops utilization measurements based on a client's requests. * The protocol used to communicate is as follows: @@ -74,14 +73,16 @@ static struct tcp_pcb *utiliz_socket; "Content-length: "STR(x)"\n"\ ","STR(y)","STR(z) +uintptr_t idle_ccounts_vaddr; -struct bench *bench; +#define IDLE_CCOUNTS_SIZE 0x1000 -uint64_t start; -uint64_t idle_ccount_start; +uint16_t active_cores; -char data_packet_str[MAX_PACKET_SIZE]; +uint64_t core_ccount_start[MAX_CORES]; +uint64_t idle_ccount_start[MAX_CORES]; +char data_packet_str[MAX_PACKET_SIZE]; static inline void my_reverse(char s[]) { @@ -139,8 +140,13 @@ static err_t utilization_recv_callback(void *arg, struct tcp_pcb *pcb, struct pb } else if (msg_match(data_packet_str, START)) { sddf_printf("%s measurement starting... \n", microkit_name); if (!strcmp(microkit_name, "client0")) { - start = __atomic_load_n(&bench->ts, __ATOMIC_RELAXED); - idle_ccount_start = __atomic_load_n(&bench->ccount, __ATOMIC_RELAXED); + for (int i = 0; i < MAX_CORES; i++) { + if (active_cores & (1 << i)) { + struct bench *core_ccounts = (struct bench *)(idle_ccounts_vaddr + IDLE_CCOUNTS_SIZE * i); + core_ccount_start[i] = __atomic_load_n(&core_ccounts->ts, __ATOMIC_RELAXED); + idle_ccount_start[i] = __atomic_load_n(&core_ccounts->ccount, __ATOMIC_RELAXED); + } + } microkit_notify(START_PMU); } } else if (msg_match(data_packet_str, STOP)) { @@ -149,8 +155,13 @@ static err_t utilization_recv_callback(void *arg, struct tcp_pcb *pcb, struct pb uint64_t total = 0, idle = 0; if (!strcmp(microkit_name, "client0")) { - total = __atomic_load_n(&bench->ts, __ATOMIC_RELAXED) - start; - idle = __atomic_load_n(&bench->ccount, __ATOMIC_RELAXED) - idle_ccount_start; + for (int i = 0; i < MAX_CORES; i++) { + if (active_cores & (1 << i)) { + struct bench *core_ccounts = (struct bench *)(idle_ccounts_vaddr + IDLE_CCOUNTS_SIZE * i); + total += __atomic_load_n(&core_ccounts->ts, __ATOMIC_RELAXED) - core_ccount_start[i]; + idle += __atomic_load_n(&core_ccounts->ccount, __ATOMIC_RELAXED) - idle_ccount_start[i]; + } + } } char tbuf[21]; @@ -199,7 +210,8 @@ static err_t utilization_accept_callback(void *arg, struct tcp_pcb *newpcb, err_ int setup_utilization_socket(void) { - bench = (void *)cyclecounters_vaddr; + active_cores = bench_active_cores(); + utiliz_socket = tcp_new_ip_type(IPADDR_TYPE_V4); if (utiliz_socket == NULL) { sddf_dprintf("Failed to open a socket for listening!\n"); @@ -220,4 +232,4 @@ int setup_utilization_socket(void) tcp_accept(utiliz_socket, utilization_accept_callback); return 0; -} \ No newline at end of file +} diff --git a/examples/serial/README.md b/examples/serial/README.md index 027a1e10c..b11db6471 100644 --- a/examples/serial/README.md +++ b/examples/serial/README.md @@ -86,7 +86,7 @@ system file including client names and queue sizes, as well as updated initialis for clients and virtualisers. * **Makefile** You must include directories for **SERIAL_COMPONENTS**, the **UART_DRIVER** and your -**SERIAL_CONFIG_INCLUDE**. You must also supply **SERIAL_NUM_CLIENTS**. You must add the uart +**SERIAL_CONFIG_INCLUDE**. You must also supply **NUM_SERIAL_CLIENTS**. You must add the uart driver, transmit virtualiser and optionally the receive virtualiser to your image list. You must add your serial include directory to your cflags, and finally you must include the uart driver and serial_components make files. For each component you wish to have access to the serial @@ -117,4 +117,4 @@ completed, and waits for input. When a character is received, each client will r character using `sddf_putchar_unbuffered` which flushes the character to the device immediately. Every tenth character each client will print a string containing their name using `sddf_printf` which calls the serial `_sddf_putchar`, flushing characters to the device only when a `\n` is -encountered. \ No newline at end of file +encountered. diff --git a/examples/serial/include/serial_config/serial_config.h b/examples/serial/include/serial_config/serial_config.h index eeb1f8a7b..77cabf5b4 100644 --- a/examples/serial/include/serial_config/serial_config.h +++ b/examples/serial/include/serial_config/serial_config.h @@ -10,7 +10,8 @@ #include #include -#define SERIAL_NUM_CLIENTS 2 +/* Number of clients that can be connected to the serial server. */ +#define NUM_SERIAL_CLIENTS 2 /* Only support transmission and not receive. */ #define SERIAL_TX_ONLY 0 @@ -47,49 +48,68 @@ #define SERIAL_RX_DATA_REGION_CAPACITY_CLI0 SERIAL_DATA_REGION_CAPACITY #define SERIAL_RX_DATA_REGION_CAPACITY_CLI1 SERIAL_DATA_REGION_CAPACITY +/* To avoid deadlocks caused when the virtualiser adds colour codes to the + start and end of strings, driver data region must be larger than any + client data region. */ #define SERIAL_MAX_CLIENT_TX_DATA_CAPACITY MAX(SERIAL_TX_DATA_REGION_CAPACITY_CLI0, SERIAL_TX_DATA_REGION_CAPACITY_CLI1) #if SERIAL_WITH_COLOUR _Static_assert(SERIAL_TX_DATA_REGION_CAPACITY_DRIV > SERIAL_MAX_CLIENT_TX_DATA_CAPACITY, "Driver TX data region must be larger than all client data regions in SERIAL_WITH_COLOUR mode."); #endif +/* Ensure the entire data region can be assigned a unique index by a 32 bit + unsigned. */ #define SERIAL_MAX_TX_DATA_CAPACITY MAX(SERIAL_TX_DATA_REGION_CAPACITY_DRIV, SERIAL_MAX_CLIENT_TX_DATA_CAPACITY) #define SERIAL_MAX_RX_DATA_CAPACITY MAX(SERIAL_RX_DATA_REGION_CAPACITY_DRIV, MAX(SERIAL_RX_DATA_REGION_CAPACITY_CLI0, SERIAL_RX_DATA_REGION_CAPACITY_CLI1)) #define SERIAL_MAX_DATA_CAPACITY MAX(SERIAL_MAX_TX_DATA_CAPACITY, SERIAL_MAX_RX_DATA_CAPACITY) _Static_assert(SERIAL_MAX_DATA_CAPACITY < UINT32_MAX, "Data regions must be smaller than UINT32 max to correctly use queue data structure."); -static inline void serial_cli_queue_init_sys(char *pd_name, serial_queue_handle_t *rx_queue_handle, - serial_queue_t *rx_queue, - char *rx_data, serial_queue_handle_t *tx_queue_handle, serial_queue_t *tx_queue, char *tx_data) +static inline void serial_cli_data_capacity(char *pd_name, uint32_t *rx_data_capacity, uint32_t *tx_data_capacity) { if (!sddf_strcmp(pd_name, SERIAL_CLI0_NAME)) { - serial_queue_init(rx_queue_handle, rx_queue, SERIAL_RX_DATA_REGION_CAPACITY_CLI0, rx_data); - serial_queue_init(tx_queue_handle, tx_queue, SERIAL_TX_DATA_REGION_CAPACITY_CLI0, tx_data); + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI0; + *rx_data_capacity = SERIAL_RX_DATA_REGION_CAPACITY_CLI0; } else if (!sddf_strcmp(pd_name, SERIAL_CLI1_NAME)) { - serial_queue_init(rx_queue_handle, rx_queue, SERIAL_RX_DATA_REGION_CAPACITY_CLI1, rx_data); - serial_queue_init(tx_queue_handle, tx_queue, SERIAL_TX_DATA_REGION_CAPACITY_CLI1, tx_data); + *tx_data_capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI1; + *rx_data_capacity = SERIAL_RX_DATA_REGION_CAPACITY_CLI1; } } -static inline void serial_virt_queue_init_sys(char *pd_name, serial_queue_handle_t *cli_queue_handle, - serial_queue_t *cli_queue, char *cli_data) +typedef struct serial_queue_info { + serial_queue_t *cli_queue; + char *cli_data; + uint32_t capacity; +} serial_queue_info_t; + +static inline void serial_virt_queue_info(char *pd_name, serial_queue_t *cli_queue, char *cli_data, + serial_queue_info_t ret[NUM_SERIAL_CLIENTS]) { - if (!sddf_strcmp(pd_name, SERIAL_VIRT_RX_NAME)) { - serial_queue_init(cli_queue_handle, cli_queue, SERIAL_RX_DATA_REGION_CAPACITY_CLI0, cli_data); - serial_queue_init(&cli_queue_handle[1], (serial_queue_t *)((uintptr_t)cli_queue + SERIAL_QUEUE_SIZE), - SERIAL_RX_DATA_REGION_CAPACITY_CLI1, cli_data + SERIAL_RX_DATA_REGION_CAPACITY_CLI0); - } else if (!sddf_strcmp(pd_name, SERIAL_VIRT_TX_NAME)) { - serial_queue_init(cli_queue_handle, cli_queue, SERIAL_TX_DATA_REGION_CAPACITY_CLI0, cli_data); - serial_queue_init(&cli_queue_handle[1], (serial_queue_t *)((uintptr_t)cli_queue + SERIAL_QUEUE_SIZE), - SERIAL_TX_DATA_REGION_CAPACITY_CLI1, cli_data + SERIAL_TX_DATA_REGION_CAPACITY_CLI0); + if (!sddf_strcmp(pd_name, SERIAL_VIRT_TX_NAME)) { + ret[0] = (serial_queue_info_t) { .cli_queue = cli_queue, + .cli_data = cli_data, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI0 }; + ret[1] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[0].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[0].cli_data + ret[0].capacity, + .capacity = SERIAL_TX_DATA_REGION_CAPACITY_CLI1 }; + } else if (!sddf_strcmp(pd_name, SERIAL_VIRT_RX_NAME)) { + ret[0] = (serial_queue_info_t) { .cli_queue = cli_queue, + .cli_data = cli_data, + .capacity = SERIAL_RX_DATA_REGION_CAPACITY_CLI0 }; + ret[1] = + (serial_queue_info_t) { .cli_queue = (serial_queue_t *)((uintptr_t)ret[0].cli_queue + SERIAL_QUEUE_SIZE), + .cli_data = ret[0].cli_data + ret[0].capacity, + .capacity = SERIAL_RX_DATA_REGION_CAPACITY_CLI1 }; } } #if SERIAL_WITH_COLOUR -static inline void serial_channel_names_init(char **client_names) +static inline void serial_channel_names_init(char *pd_name, char *client_names[NUM_SERIAL_CLIENTS]) { - client_names[0] = SERIAL_CLI0_NAME; - client_names[1] = SERIAL_CLI1_NAME; + if (!sddf_strcmp(pd_name, SERIAL_VIRT_TX_NAME)) { + client_names[0] = SERIAL_CLI0_NAME; + client_names[1] = SERIAL_CLI1_NAME; + } } #endif diff --git a/examples/serial/serial_server.c b/examples/serial/serial_server.c index 2a49f2b3d..84d49d35a 100644 --- a/examples/serial/serial_server.c +++ b/examples/serial/serial_server.c @@ -24,7 +24,10 @@ uint32_t local_head; void init(void) { - serial_cli_queue_init_sys(microkit_name, &rx_queue_handle, rx_queue, rx_data, &tx_queue_handle, tx_queue, tx_data); + uint32_t rx_data_capacity, tx_data_capacity; + serial_cli_data_capacity(microkit_name, &rx_data_capacity, &tx_data_capacity); + serial_queue_init(&rx_queue_handle, rx_queue, rx_data_capacity, rx_data); + serial_queue_init(&tx_queue_handle, tx_queue, tx_data_capacity, tx_data); serial_putchar_init(TX_CH, &tx_queue_handle); sddf_printf("Hello world! I am %s.\nPlease give me character!\n", microkit_name); } diff --git a/serial/components/virt_rx.c b/serial/components/virt_rx.c index 4d107d1b5..c103fdc56 100644 --- a/serial/components/virt_rx.c +++ b/serial/components/virt_rx.c @@ -21,7 +21,7 @@ char *rx_data_drv; char *rx_data_cli0; serial_queue_handle_t rx_queue_handle_drv; -serial_queue_handle_t rx_queue_handle_cli[SERIAL_NUM_CLIENTS]; +serial_queue_handle_t rx_queue_handle_cli[NUM_SERIAL_CLIENTS]; #define MAX_CLI_BASE_10 4 typedef enum mode {normal, switched, number} mode_t; @@ -78,7 +78,7 @@ void rx_return(void) default: if (c == SERIAL_TERMINATE_NUM) { int input_number = sddf_atoi(next_client); - if (input_number >= 0 && input_number < SERIAL_NUM_CLIENTS) { + if (input_number >= 0 && input_number < NUM_SERIAL_CLIENTS) { if (transferred && serial_require_producer_signal(&rx_queue_handle_cli[current_client])) { serial_update_visible_tail(&rx_queue_handle_cli[current_client], local_tail); serial_cancel_producer_signal(&rx_queue_handle_cli[current_client]); @@ -129,7 +129,13 @@ void rx_return(void) void init(void) { serial_queue_init(&rx_queue_handle_drv, rx_queue_drv, SERIAL_RX_DATA_REGION_CAPACITY_DRIV, rx_data_drv); - serial_virt_queue_init_sys(microkit_name, rx_queue_handle_cli, rx_queue_cli0, rx_data_cli0); + + serial_queue_info_t queue_info[NUM_SERIAL_CLIENTS] = { 0 }; + serial_virt_queue_info(microkit_name, rx_queue_cli0, rx_data_cli0, queue_info); + for (int i = 0; i < NUM_SERIAL_CLIENTS; i++) { + serial_queue_init(&rx_queue_handle_cli[i], queue_info[i].cli_queue, queue_info[i].capacity, + queue_info[i].cli_data); + } } void notified(microkit_channel ch) diff --git a/serial/components/virt_tx.c b/serial/components/virt_tx.c index b57200771..46b82b062 100644 --- a/serial/components/virt_tx.c +++ b/serial/components/virt_tx.c @@ -41,17 +41,17 @@ const char *colours[] = { #define COLOUR_END "\x1b[0m" #define COLOUR_END_LEN 4 -char *client_names[SERIAL_NUM_CLIENTS]; +char *client_names[NUM_SERIAL_CLIENTS]; #endif serial_queue_handle_t tx_queue_handle_drv; -serial_queue_handle_t tx_queue_handle_cli[SERIAL_NUM_CLIENTS]; +serial_queue_handle_t tx_queue_handle_cli[NUM_SERIAL_CLIENTS]; -#define TX_PENDING_LEN (SERIAL_NUM_CLIENTS + 1) +#define TX_PENDING_LEN (NUM_SERIAL_CLIENTS + 1) typedef struct tx_pending { uint32_t queue[TX_PENDING_LEN]; - bool clients_pending[SERIAL_NUM_CLIENTS]; + bool clients_pending[NUM_SERIAL_CLIENTS]; uint32_t head; uint32_t tail; } tx_pending_t; @@ -71,7 +71,7 @@ static void tx_pending_push(uint32_t client) } /* Ensure the pending queue is not already full */ - assert(tx_pending_length() < SERIAL_NUM_CLIENTS); + assert(tx_pending_length() < NUM_SERIAL_CLIENTS); tx_pending.queue[tx_pending.tail] = client; tx_pending.clients_pending[client] = true; @@ -134,7 +134,7 @@ void tx_return(void) } uint32_t client; - bool notify_client[SERIAL_NUM_CLIENTS] = {false}; + bool notify_client[NUM_SERIAL_CLIENTS] = { false }; bool transferred = false; for (uint32_t req = 0; req < num_pending_tx; req++) { tx_pending_pop(&client); @@ -160,7 +160,7 @@ void tx_return(void) microkit_notify(DRIVER_CH); } - for (uint32_t client = 0; client < SERIAL_NUM_CLIENTS; client++) { + for (uint32_t client = 0; client < NUM_SERIAL_CLIENTS; client++) { if (notify_client[client] && serial_require_consumer_signal(&tx_queue_handle_cli[client])) { serial_cancel_consumer_signal(&tx_queue_handle_cli[client]); microkit_notify(client + CLIENT_OFFSET); @@ -170,7 +170,7 @@ void tx_return(void) void tx_provide(microkit_channel ch) { - if (ch > SERIAL_NUM_CLIENTS) { + if (ch > NUM_SERIAL_CLIENTS) { sddf_dprintf("VIRT_TX|LOG: Received notification from unknown channel %u\n", ch); return; } @@ -204,7 +204,13 @@ void tx_provide(microkit_channel ch) void init(void) { serial_queue_init(&tx_queue_handle_drv, tx_queue_drv, SERIAL_TX_DATA_REGION_CAPACITY_DRIV, tx_data_drv); - serial_virt_queue_init_sys(microkit_name, tx_queue_handle_cli, tx_queue_cli0, tx_data_cli0); + + serial_queue_info_t queue_info[NUM_SERIAL_CLIENTS] = { 0 }; + serial_virt_queue_info(microkit_name, tx_queue_cli0, tx_data_cli0, queue_info); + for (int i = 0; i < NUM_SERIAL_CLIENTS; i++) { + serial_queue_init(&tx_queue_handle_cli[i], queue_info[i].cli_queue, queue_info[i].capacity, + queue_info[i].cli_data); + } #if !SERIAL_TX_ONLY /* Print a deterministic string to allow console input to begin */ @@ -214,8 +220,8 @@ void init(void) #endif #if SERIAL_WITH_COLOUR - serial_channel_names_init(client_names); - for (uint32_t i = 0; i < SERIAL_NUM_CLIENTS; i++) { + serial_channel_names_init(microkit_name, client_names); + for (uint32_t i = 0; i < NUM_SERIAL_CLIENTS; i++) { sddf_dprintf("%s'%s' is client %u%s\n", colours[i % ARRAY_SIZE(colours)], client_names[i], i, COLOUR_END); } #endif